LCOV - code coverage report
Current view: top level - EnergyPlus - WindowManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 51.3 % 4003 2053
Test Date: 2025-05-22 16:09:37 Functions: 82.6 % 46 38

            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 <algorithm>
      50              : #include <cassert>
      51              : #include <cmath>
      52              : #include <memory>
      53              : #include <string>
      54              : 
      55              : // ObjexxFCL Headers
      56              : #include <ObjexxFCL/Array.functions.hh>
      57              : 
      58              : // EnergyPlus Headers
      59              : #include <EnergyPlus/Construction.hh>
      60              : #include <EnergyPlus/ConvectionCoefficients.hh>
      61              : #include <EnergyPlus/CurveManager.hh>
      62              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      63              : #include <EnergyPlus/DataBSDFWindow.hh>
      64              : #include <EnergyPlus/DataEnvironment.hh>
      65              : #include <EnergyPlus/DataHeatBalSurface.hh>
      66              : #include <EnergyPlus/DataHeatBalance.hh>
      67              : #include <EnergyPlus/DataIPShortCuts.hh>
      68              : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
      69              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      70              : #include <EnergyPlus/Material.hh>
      71              : #include <EnergyPlus/Psychrometrics.hh>
      72              : #include <EnergyPlus/UtilityRoutines.hh>
      73              : #include <EnergyPlus/WindowComplexManager.hh>
      74              : #include <EnergyPlus/WindowEquivalentLayer.hh>
      75              : #include <EnergyPlus/WindowManager.hh>
      76              : #include <EnergyPlus/WindowManagerExteriorOptical.hh>
      77              : #include <EnergyPlus/WindowManagerExteriorThermal.hh>
      78              : #include <EnergyPlus/WindowModel.hh>
      79              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      80              : 
      81              : namespace EnergyPlus {
      82              : 
      83              : namespace Window {
      84              : 
      85              :     // MODULE INFORMATION
      86              :     //       AUTHOR         Fred Winkelmann
      87              :     //       DATE WRITTEN   September 1999
      88              :     //       MODIFIED       August 2001 (FW): add window shade thermal calculation;
      89              :     //                                        add window blind optical and thermal model.
      90              :     //                      February 2003 (FW/LKL): Name changed to WindowManager
      91              :     //       RE-ENGINEERED  na
      92              : 
      93              :     // PURPOSE OF THIS MODULE:
      94              :     // Manages the window optical and thermal calculations derived
      95              :     // from WINDOW 4 and WINDOW 5.
      96              : 
      97              :     // METHODOLOGY EMPLOYED:
      98              : 
      99              :     // REFERENCES:
     100              :     // WINDOW 4:
     101              :     // D.Arasteh, M.Reilly and M.Rubin. A versative procedure for
     102              :     // calculating heat transfer through windows. ASHRAE Trans. 1989, Vol. 95, Pt. 2.
     103              : 
     104              :     // E.Finlayson, D.Arasteh, C.Huizenga, M.Rubin, and M.Reilly. WINDOW 4.0:
     105              :     // Documentation of calculation procedures. LBL-33943. July 1993.
     106              : 
     107              :     // WINDOW 5:
     108              :     // ASHRAE Standard 142P (draft 1/13/98): Standard method for determining and expressing
     109              :     // the heat transfer and total optical properties of fenestration products.
     110              : 
     111              :     // Shade and blind thermal model:
     112              :     // ISO/DIS 15099, Thermal Performance of Windows, Doors and Shading Devices,
     113              :     // Detailed Calculations, 1/12/00.
     114              : 
     115              :     // Blind optical model:
     116              :     // H. Simmler, U. Fischer and Frederick Winkelmann, Solar-Thermal Window Blind Model
     117              :     // for DOE-2, Lawrence Berkeley National Laboratory, Jan. 1996.
     118              : 
     119              :     // Using/Aliasing
     120              :     using namespace DataEnvironment;
     121              :     using namespace DataHeatBalance;
     122              :     using namespace DataSurfaces;
     123              : 
     124              :     // SUBROUTINE SPECIFICATIONS FOR MODULE WindowManager:
     125              :     //   Optical Calculation Routines
     126              :     //   Heat Balance Routines
     127              : 
     128          111 :     void InitWindowOpticalCalculations(EnergyPlusData &state)
     129              :     {
     130              :         // SUBROUTINE INFORMATION:
     131              :         //       AUTHOR         Simon Vidanovic
     132              :         //       DATE WRITTEN   September 2016
     133              :         //       MODIFIED       na
     134              :         //       RE-ENGINEERED  na
     135              : 
     136              :         // PURPOSE OF THIS SUBROUTINE:
     137              :         // Manages if optical calculation will be performed with internal or external routines
     138          111 :         auto &s_surf = state.dataSurface;
     139              : 
     140              :         // check and read custom solar and/or visible spectrum data if any
     141          111 :         CheckAndReadCustomSprectrumData(state);
     142              : 
     143              :         // allocate surface level adj ratio data member
     144          111 :         state.dataHeatBalSurf->SurfWinCoeffAdjRatio.dimension(s_surf->TotSurfaces, 1.0);
     145              : 
     146          111 :         if (state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) {
     147            3 :             InitWCE_SimplifiedOpticalData(state);
     148              :         } else {
     149          108 :             InitGlassOpticalCalculations(state);
     150              :         }
     151          111 :     }
     152              : 
     153          110 :     void InitGlassOpticalCalculations(EnergyPlusData &state)
     154              :     {
     155              : 
     156              :         // SUBROUTINE INFORMATION:
     157              :         //       AUTHOR         F. Winkelmann
     158              :         //       DATE WRITTEN   August 1999
     159              :         //       MODIFIED       May 2001 (FW): add window blinds
     160              :         //                      Jan 2002 (FW): add blinds with variable slat angle
     161              :         //                      Jan 2003 (FW): add between-glass shade/blind
     162              :         //                      May 2006 (RR): add exterior window screen
     163              :         //                      Aug 2010 (TH): allow spectral data for between-glass shade/blind
     164              :         //                      Aug 2013 (TH): allow user defined solar and visible spectrum data
     165              :         //       RE-ENGINEERED  na
     166              : 
     167              :         // PURPOSE OF THIS SUBROUTINE:
     168              :         // Manages the calculation of the solar and visible properties of a multi-layer glazing
     169              :         // system from the properties of the individual glazing and shading layers
     170              : 
     171              :         // Using/Aliasing
     172              :         using namespace Vectors;
     173              : 
     174              :         int TotLay;                     // Total solid and gas layers in a window construction
     175              :         int ConstrNumSh;                // Shaded construction number
     176              :         int ShadeLayNum;                // Layer number for shade or blind, if present
     177              :         int ShadeLayPtr;                // Material number for shade or blind
     178              :         bool lquasi;                    // True if one or more glass layers have no spectral data
     179              :         bool AllGlassIsSpectralAverage; // True if all glazing in a construction is spectral average
     180              :         bool IntShade;                  // True if construction has an interior,exterior or between-glass shade
     181              :         bool ExtShade;
     182              :         bool BGShade;
     183              :         bool IntBlind; // True if construction has an interior,exterior or between-glass blind
     184              :         bool ExtBlind;
     185              :         bool BGBlind;
     186              :         bool ExtScreen; // True if construction has an exterior screen
     187              :         bool ScreenOn;  // True if construction has an exterior screen
     188              :         bool BlindOn;   // True if IntBlind, ExtBlind or BGBlind is true
     189              :         bool ShadeOn;   // True if IntShade, ExtShade or BGShade is true
     190              :         int BlNum;      // Blind number
     191              : 
     192          110 :         auto &wm = state.dataWindowManager;
     193          110 :         Array1D<Real64> sabsPhi(nume); // Glazing system absorptance for a glass layer
     194              :         //  and angle of incidence, for each wavelength
     195              :         //   glass layer for an angle of incidence, for each wavelength
     196              :         // Glazing system layer solar absorptance for each glass layer
     197          110 :         Array1D<Real64> solabsDiff(maxGlassLayers);
     198              :         // Glazing system solar absorptance for a layer at each incidence angle
     199              :         std::array<Real64, numPhis> solabsPhiLay;
     200              :         // Glazing system solar transmittance from fit at each incidence angle
     201              :         std::array<Real64, numPhis> tsolPhiFit;
     202              :         // Glazing system visible transmittance from fit at each incidence angle
     203              :         std::array<Real64, numPhis> tvisPhiFit;
     204              :         // Isolated glass solar transmittance for each incidence angle
     205          110 :         Array1D<std::array<Real64, numPhis>> tBareSolPhi(maxGlassLayers);
     206              :         Real64 t1; // = tBareSolPhi(,1)(,2)
     207              :         Real64 t2;
     208              :         // Isolated glass visible transmittance for each incidence angle
     209          110 :         Array1D<std::array<Real64, numPhis>> tBareVisPhi(maxGlassLayers);
     210              :         Real64 t1v; // = tBareVisPhi(,1)(,2)
     211              :         Real64 t2v;
     212              :         // Isolated glass front solar reflectance for each incidence angle
     213          110 :         Array1D<std::array<Real64, numPhis>> rfBareSolPhi(maxGlassLayers);
     214              :         // Isolated glass front visible reflectance for each incidence angle
     215          110 :         Array1D<std::array<Real64, numPhis>> rfBareVisPhi(maxGlassLayers);
     216              :         // Isolated glass back solar reflectance for each incidence angle
     217          110 :         Array1D<std::array<Real64, numPhis>> rbBareSolPhi(maxGlassLayers);
     218              :         // Isolated glass back visible reflectance for each incidence angle
     219          110 :         Array1D<std::array<Real64, numPhis>> rbBareVisPhi(maxGlassLayers);
     220              :         // Isolated glass front solar absorptance for each incidence angle
     221          110 :         Array1D<std::array<Real64, numPhis>> afBareSolPhi(maxGlassLayers);
     222              :         Real64 af1; // = afBareSolPhi(,1)(,2)
     223              :         Real64 af2;
     224              :         Real64 rbmf2; // Isolated glass #2 front beam reflectance
     225              :         // Isolated glass back solar absorptance for each incidence angle
     226          110 :         Array1D<std::array<Real64, numPhis>> abBareSolPhi(maxGlassLayers);
     227              :         // Glazing system solar absorptance for each angle of incidence
     228          110 :         Array1D<std::array<Real64, numPhis>> solabsPhi(maxGlassLayers);
     229              :         // Glazing system back solar absorptance for each angle of incidence
     230          110 :         Array1D<std::array<Real64, numPhis>> solabsBackPhi(maxGlassLayers);
     231              :         // Glazing system interior shade solar absorptance for each angle of incidence
     232              :         std::array<Real64, numPhis> solabsShadePhi;
     233              : 
     234              :         // These need to stay as Array1D for a little longer because changing them spreads into many source files
     235              :         std::array<Real64, numPhis> tsolPhi;  // Glazing system solar transmittance for each angle of incidence
     236              :         std::array<Real64, numPhis> rfsolPhi; // Glazing system solar front reflectance for each angle of incidence
     237              :         std::array<Real64, numPhis> rbsolPhi; // Glazing system solar back reflectance for each angle of incidence
     238              :         std::array<Real64, numPhis> tvisPhi;  // Glazing system visible transmittance for each angle of incidence
     239              :         std::array<Real64, numPhis> rfvisPhi; // Glazing system visible front reflectance for each angle of incidence
     240              :         std::array<Real64, numPhis> rbvisPhi; // Glazing system visible back reflectance for each angle of incidence
     241              : 
     242              :         Real64 ab1; // = abBareSolPhi(,1)(,2)
     243              :         Real64 ab2;
     244              :         Real64 td1; // Isolated glass diffuse solar transmittance
     245              :         Real64 td2;
     246              :         Real64 td3;
     247              :         Real64 td1v; // Isolated glass diffuse visible transmittance
     248              :         Real64 td2v;
     249              :         Real64 td3v;
     250              :         Real64 rf1; // Isolated glass diffuse solar front reflectance
     251              :         Real64 rf2;
     252              :         Real64 rf3;
     253              :         Real64 rf1v; // Isolated glass diffuse visible front reflectance
     254              :         Real64 rf2v;
     255              :         Real64 rf3v;
     256              :         Real64 rb1; // Isolated glass diffuse solar back reflectance
     257              :         Real64 rb2;
     258              :         Real64 rb3;
     259              :         Real64 rb1v; // Isolated glass diffuse visible back reflectance
     260              :         Real64 rb2v;
     261              :         Real64 rb3v;
     262              :         Real64 afd1; // Isolated glass diffuse solar front absorptance
     263              :         Real64 afd2;
     264              :         Real64 afd3;
     265              :         Real64 abd1; // Isolated glass diffuse solar back absorptance
     266              :         Real64 abd2;
     267              :         Real64 abd3;
     268              :         Real64 TauShIR;  // IR transmittance of isolated shade
     269              :         Real64 EpsShIR;  // IR absorptance of isolated shade
     270              :         Real64 RhoShIR;  // IR reflectance of isolated shade
     271              :         Real64 EpsGlIR;  // IR absorptance of front or back of isolated glass
     272              :         Real64 RhoGlIR;  // IR reflectance of inside face of inside glass
     273              :         int NGlass;      // Number of glass layers in a construction
     274              :         int LayPtr;      // Material number corresponding to LayNum
     275              :         Real64 tsolDiff; // Glazing system diffuse solar transmittance
     276              :         Real64 tvisDiff; // Glazing system diffuse visible transmittance
     277              :         int IGlassBack;  // Glass layer number counted from back of window
     278              :         Real64 ShadeAbs; // Solar absorptance of isolated shade
     279              :         Real64 ash;      // = ShadeAbs
     280              :         Real64 afsh;     // Diffuse solar front absorptance of isolated blind
     281              :         Real64 afshGnd;  // Ground and sky diffuse solar front absorptance of isolated blind
     282              :         Real64 afshSky;
     283              :         Real64 absh;          // Diffuse solar back absorptance of isolated blind
     284              :         Real64 ShadeTrans;    // Solar transmittance of isolated shade/blind
     285              :         Real64 ShadeTransGnd; // Diffuse-diffuse transmittance of isolated vertical blind with
     286              :         // horizontal slats for isotropic ground solar
     287              :         Real64 ShadeTransSky; // Diffuse-diffuse transmittance of isolated vertical blind with
     288              :         // horizontal slats for isotropic sky solar
     289              :         Real64 tsh;    // = ShadeTrans
     290              :         Real64 tshGnd; // = ShadeTransGnd,ShadeTransSky
     291              :         Real64 tshSky;
     292              :         Real64 tsh2;         // = tsh**2
     293              :         Real64 ShadeRefl;    // Solar reflectance of isolated shade
     294              :         Real64 ShadeReflGnd; // Front blind reflectance for ground diffuse solar
     295              :         Real64 ShadeReflSky; // Front blind reflectance for sky diffuse solar
     296              :         Real64 rsh;          // = ShadeRefl
     297              :         Real64 rfsh;         // Diffuse solar front reflectance of isolated blind
     298              :         Real64 rfshGnd;      // Ground and sky diffuse solar front reflectance of isolated blind
     299              :         Real64 rfshSky;
     300              :         Real64 rbsh;            // Diffuse solar back reflectance of isolated blind
     301              :         Real64 ShadeReflFac;    // Shade/blind solar reflection factor
     302              :         Real64 ShadeTransVis;   // Visible transmittance of isolated shade/blind
     303              :         Real64 tshv;            // = ShadeTransVis
     304              :         Real64 tshv2;           // = tshv**2
     305              :         Real64 ShadeReflVis;    // Visible reflectance of isolated shade
     306              :         Real64 rshv;            // = ShadeReflVis
     307              :         Real64 rfshv;           // Diffuse visible front reflectance of isolated blind
     308              :         Real64 rbshv;           // Diffuse visible back reflectance of isolated blind
     309              :         Real64 ShadeReflFacVis; // Shade/blind visible reflection factor
     310          110 :         int SpecDataNum = 0;    // Spectral data set number
     311              :         int numptDAT;           // Number of wavelengths in a spectral data set
     312              :         bool StormWinConst;     // True if a construction with a storm window
     313              :         bool Triangle;          // True if window is triangular
     314              :         bool Rectangle;         // True if window is rectangular
     315          110 :         Vector3<Real64> W1;     // Window vertices (m)
     316          110 :         Vector3<Real64> W2;
     317          110 :         Vector3<Real64> W3;
     318          110 :         Vector3<Real64> W21; // W1-W2, W3-W2, resp. (m)
     319          110 :         Vector3<Real64> W23;
     320              : 
     321              :         // Spectral data wavelengths for each glass layer in a glazing system
     322          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> wlt = {0.0};
     323              : 
     324              :         // Following data, Spectral data for each layer for each wavelength in wlt
     325          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> t = {0.0};     // normal transmittance
     326          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rff = {0.0};   // normal front reflectance
     327          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbb = {0.0};   // normal back reflectance
     328          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tPhi = {0.0};  // transmittance at angle of incidence
     329          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfPhi = {0.0}; // front reflectance at angle of incidence
     330          110 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbPhi = {0.0}; // back reflectance at angle of incidence
     331              : 
     332              :         // Number of spectral data wavelengths for each layer; =2 if no spectra data for a layer
     333          110 :         std::array<int, maxGlassLayers> numpt = {0};
     334              : 
     335          110 :         auto &s_mat = state.dataMaterial;
     336          110 :         auto &s_surf = state.dataSurface;
     337              : 
     338          110 :         W5InitGlassParameters(state);
     339              : 
     340              :         // Calculate optical properties of blind-type layers entered with MATERIAL:WindowBlind
     341          110 :         if (s_mat->NumBlinds > 0) CalcWindowBlindProperties(state);
     342              : 
     343              :         // Initialize SurfaceScreen structure
     344          110 :         if (s_mat->NumScreens > 0) CalcWindowScreenProperties(state);
     345              : 
     346              :         // Get glazing system optical properties of constructions with glass or glass plus
     347              :         //   shade, screen or blind
     348              :         // Loop over constructions and find those that are glazing constructions
     349          433 :         for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
     350          323 :             auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
     351          330 :             if (!thisConstruct.TypeIsWindow) continue;
     352           42 :             if (thisConstruct.WindowTypeBSDF) continue; // Skip Complex Fenestrations, they have separate
     353           41 :             if (thisConstruct.WindowTypeEQL) continue;  // skip Equivalent Layer Fenestration
     354              :             // handling of optical properties
     355              : 
     356              :             // When pulling in develop, the following block appears to have been modified in develop,
     357              :             //  but removed entirely in this branch.  I'm going to leave it commented.
     358              :             // Pre-calculate constants
     359              :             // for (int IPhi = 1; IPhi <= 10; ++IPhi) {
     360              :             //    CosPhiIndepVar(IPhi) = std::cos((IPhi - 1) * 10.0 * Constant::DegToRad);
     361              :             //}
     362              : 
     363           35 :             TotLay = thisConstruct.TotLayers;
     364              : 
     365           35 :             auto const *mat = s_mat->materials(thisConstruct.LayerPoint(1));
     366              : 
     367              :             // First layer must be glass, shade, screen or blind to be a glazing construction
     368           35 :             if (mat->group != Material::Group::Glass && mat->group != Material::Group::Shade && mat->group != Material::Group::Screen &&
     369           12 :                 mat->group != Material::Group::Blind && mat->group != Material::Group::GlassSimple)
     370            0 :                 continue;
     371              : 
     372           35 :             ShadeLayNum = 0;
     373           35 :             ExtShade = false;
     374           35 :             IntShade = false;
     375           35 :             BGShade = false;
     376           35 :             ExtBlind = false;
     377           35 :             IntBlind = false;
     378           35 :             BGBlind = false;
     379           35 :             ExtScreen = false;
     380           35 :             StormWinConst = false;
     381           35 :             wm->lSimpleGlazingSystem = false;
     382              : 
     383           35 :             if (mat->group == Material::Group::GlassSimple) {
     384           12 :                 auto const *matWin = dynamic_cast<Material::MaterialGlass const *>(mat);
     385           12 :                 assert(matWin != nullptr);
     386              : 
     387              :                 // what if outside layer is shade, blind, or screen?
     388           12 :                 wm->lSimpleGlazingSystem = true;
     389           12 :                 wm->SimpleGlazingSHGC = matWin->SimpleWindowSHGC;
     390           12 :                 wm->SimpleGlazingU = matWin->SimpleWindowUfactor;
     391              :             }
     392              : 
     393           35 :             if (has_prefix(thisConstruct.Name, "BARECONSTRUCTIONWITHSTORMWIN") || has_prefix(thisConstruct.Name, "SHADEDCONSTRUCTIONWITHSTORMWIN"))
     394            0 :                 StormWinConst = true;
     395              : 
     396              :             // Get layer number of shade/blind
     397           35 :             if (mat->group == Material::Group::Shade) {
     398            0 :                 ExtShade = true;
     399            0 :                 ShadeLayNum = 1;
     400           35 :             } else if (s_mat->materials(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Shade) {
     401            0 :                 IntShade = true;
     402            0 :                 ShadeLayNum = TotLay;
     403           35 :             } else if (thisConstruct.TotLayers == 5) {
     404            0 :                 if (s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Shade) {
     405            0 :                     BGShade = true;
     406            0 :                     ShadeLayNum = 3;
     407              :                 }
     408           35 :             } else if (thisConstruct.TotLayers == 7) {
     409            0 :                 if (s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Shade) {
     410            0 :                     BGShade = true;
     411            0 :                     ShadeLayNum = 5;
     412              :                 }
     413              :             }
     414              : 
     415           35 :             if (mat->group == Material::Group::Blind) {
     416            0 :                 ExtBlind = true;
     417            0 :                 ShadeLayNum = 1;
     418            0 :                 BlNum = thisConstruct.LayerPoint(ShadeLayNum);
     419           35 :             } else if (s_mat->materials(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Blind) {
     420            1 :                 IntBlind = true;
     421            1 :                 ShadeLayNum = TotLay;
     422            1 :                 BlNum = thisConstruct.LayerPoint(ShadeLayNum);
     423           34 :             } else if (thisConstruct.TotLayers == 5) {
     424            0 :                 if (s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Blind) {
     425            0 :                     BGBlind = true;
     426            0 :                     ShadeLayNum = 3;
     427            0 :                     BlNum = thisConstruct.LayerPoint(ShadeLayNum);
     428              :                 }
     429           34 :             } else if (thisConstruct.TotLayers == 7) {
     430            0 :                 if (s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Blind) {
     431            0 :                     BGBlind = true;
     432            0 :                     ShadeLayNum = 5;
     433            0 :                     BlNum = thisConstruct.LayerPoint(ShadeLayNum);
     434              :                 }
     435              :             }
     436              : 
     437           35 :             if (mat->group == Material::Group::Screen) {
     438            0 :                 ShadeLayNum = 1;
     439            0 :                 ExtScreen = true;
     440              :             }
     441              : 
     442           35 :             ScreenOn = ExtScreen;
     443           35 :             BlindOn = IntBlind || ExtBlind || BGBlind;
     444           35 :             ShadeOn = IntShade || ExtShade || BGShade;
     445           35 :             wm->BGFlag = BGBlind || BGShade;
     446              : 
     447              :             // For construction with interior or exterior shade, get shade thermal absorptance (emissivity)
     448              :             // (accounting for inter-reflection with glazing) and correct the inside glass InsideAbsorpThermal
     449              :             // for presence of interior shade. Assumes inner and outer glass layers have zero thermal transmittance.
     450              : 
     451           35 :             if (IntShade || ExtShade || ExtScreen) {
     452            0 :                 ShadeLayPtr = thisConstruct.LayerPoint(ShadeLayNum);
     453            0 :                 auto const *matShade = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(ShadeLayPtr));
     454            0 :                 assert(matShade != nullptr);
     455            0 :                 if (ExtScreen) {
     456            0 :                     auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
     457            0 :                     assert(matScreen != nullptr);
     458            0 :                     TauShIR = matScreen->DfTrans;
     459              :                 } else {
     460            0 :                     TauShIR = matShade->TransThermal;
     461              :                 }
     462            0 :                 EpsShIR = matShade->AbsorpThermal;
     463            0 :                 RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
     464            0 :                 if (ExtShade || ExtScreen) { // Exterior shade or screen
     465            0 :                     EpsGlIR = s_mat->materials(thisConstruct.LayerPoint(2))->AbsorpThermalFront;
     466              :                 } else { // Interior shade
     467            0 :                     EpsGlIR = s_mat->materials(thisConstruct.LayerPoint(TotLay - 1))->AbsorpThermalBack;
     468              :                 }
     469            0 :                 RhoGlIR = max(0.0, 1.0 - EpsGlIR);
     470            0 :                 thisConstruct.ShadeAbsorpThermal = EpsShIR * (1.0 + TauShIR * RhoGlIR / (1.0 - RhoShIR * RhoGlIR));
     471            0 :                 if (IntShade) thisConstruct.InsideAbsorpThermal *= TauShIR / (1.0 - RhoShIR * RhoGlIR);
     472              :             }
     473              : 
     474              :             // From the individual glass layer properties, get the glazing system optical properties
     475              :             // for BARE GLASS (i.e., interior, exterior or between-glass shade or blind, or exterior screen, if present, not in place).
     476              :             // Get one set of system properties for solar incident on front of
     477              :             // window and a second set for solar incident on back of window. (The back-incident
     478              :             // properties are used with interior short-wave radiation striking the window from inside.)
     479              : 
     480              :             // After the front and back system optical properties are calculated for bare glass,
     481              :             // a correction is made for the effect of a shade, screen or blind if one of these
     482              :             // is present in the construction.
     483              : 
     484           35 :             NGlass = thisConstruct.TotGlassLayers;
     485              : 
     486              :             //--------------------------------------------------------------------------------------------
     487              :             // Front calculation (solar incident from outside of room); bare glass portion of construction
     488              :             //--------------------------------------------------------------------------------------------
     489              : 
     490           35 :             lquasi = false;
     491           35 :             AllGlassIsSpectralAverage = true;
     492           35 :             wm->LayerNum = {0};
     493              : 
     494              :             // Loop over glass layers in the construction
     495           80 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     496           45 :                 int LayNum = 1 + 2 * (IGlass - 1);
     497           45 :                 if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + 2 * (IGlass - 1);
     498           45 :                 if (BGShade || BGBlind) {
     499            0 :                     LayNum = 1;
     500            0 :                     if (NGlass == 2) {
     501            0 :                         if (IGlass == 2) LayNum = 5;
     502              :                     } else { // NGlass = 3
     503            0 :                         if (IGlass == 2) LayNum = 3;
     504            0 :                         if (IGlass == 3) LayNum = 7;
     505              :                     }
     506              :                 }
     507              : 
     508           45 :                 wm->LayerNum[IGlass - 1] = LayNum;
     509           45 :                 LayPtr = thisConstruct.LayerPoint(LayNum);
     510           45 :                 auto *matGlass = dynamic_cast<Material::MaterialGlass *>(s_mat->materials(LayPtr));
     511           45 :                 assert(matGlass != nullptr);
     512           45 :                 SpecDataNum = matGlass->GlassSpectralDataPtr;
     513           45 :                 if (SpecDataNum != 0) {
     514            4 :                     if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
     515              : 
     516            4 :                     auto const &specData = s_mat->SpectralData(SpecDataNum);
     517              :                     // Get the spectral data for the transmittance, front reflectance and
     518              :                     // back reflectance (all at normal incidence) for this layer.
     519              :                     // In this case, "front" means incident from the outside and "back"
     520              :                     // means incident from the inside.
     521            4 :                     numptDAT = specData.NumOfWavelengths;
     522            4 :                     numpt[IGlass - 1] = numptDAT;
     523              : 
     524         1072 :                     for (int ILam = 1; ILam <= numptDAT; ++ILam) {
     525         1068 :                         wlt[IGlass - 1][ILam - 1] = specData.WaveLength(ILam);
     526         1068 :                         t[IGlass - 1][ILam - 1] = specData.Trans(ILam);
     527         1068 :                         if ((IGlass == 1 || (IGlass == 2 && StormWinConst)) && (!wm->BGFlag))
     528          441 :                             t[IGlass - 1][ILam - 1] *= matGlass->GlassTransDirtFactor;
     529         1068 :                         rff[IGlass - 1][ILam - 1] = specData.ReflFront(ILam);
     530         1068 :                         rbb[IGlass - 1][ILam - 1] = specData.ReflBack(ILam);
     531              :                     }
     532              : 
     533              :                     // If there is spectral data for between-glass shades or blinds, calc the average spectral properties for use.
     534            4 :                     if (wm->BGFlag) {
     535              :                         // Add warning message for the glazing defined with full spectral data.
     536            0 :                         ShowWarningError(
     537              :                             state,
     538            0 :                             format(
     539              :                                 "Window glazing material \"{}\" was defined with full spectral data and has been converted to average spectral data",
     540            0 :                                 matGlass->Name));
     541            0 :                         ShowContinueError(
     542              :                             state,
     543            0 :                             format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
     544            0 :                         ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
     545            0 :                         ShowContinueError(state,
     546              :                                           "If this material is also used in other window constructions  without between-glass shades or blinds,");
     547            0 :                         ShowContinueError(state,
     548              :                                           "then make a duplicate material (with new name) if you want to model those windows  (and reference the new "
     549              :                                           "material) using the full spectral data.");
     550              :                         // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
     551              :                         //  assuming wlt same as wle
     552            0 :                         wm->tmpTrans = solarSpectrumAverage(state, t[0]);
     553            0 :                         wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
     554            0 :                         wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
     555              : 
     556              :                         // visible properties
     557            0 :                         wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
     558            0 :                         wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
     559            0 :                         wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
     560              : 
     561              :                         // set this material to average spectral data
     562            0 :                         matGlass->GlassSpectralDataPtr = 0;
     563            0 :                         matGlass->Trans = wm->tmpTrans;
     564            0 :                         matGlass->TransVis = wm->tmpTransVis;
     565            0 :                         matGlass->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
     566            0 :                         matGlass->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
     567            0 :                         matGlass->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
     568            0 :                         matGlass->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
     569            0 :                         SpecDataNum = 0;
     570              :                     }
     571              :                 }
     572              : 
     573              :                 // No spectral data for this layer; use spectral average values
     574           45 :                 if (SpecDataNum == 0 && matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
     575           39 :                     lquasi = true;
     576           39 :                     numpt[IGlass - 1] = 2;
     577           39 :                     t[IGlass - 1][0] = matGlass->Trans;
     578           39 :                     if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][0] *= matGlass->GlassTransDirtFactor;
     579           39 :                     t[IGlass - 1][1] = matGlass->TransVis;
     580           39 :                     if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][1] *= matGlass->GlassTransDirtFactor;
     581           39 :                     rff[IGlass - 1][0] = matGlass->ReflectSolBeamFront;
     582           39 :                     rbb[IGlass - 1][0] = matGlass->ReflectSolBeamBack;
     583           39 :                     rff[IGlass - 1][1] = matGlass->ReflectVisBeamFront;
     584           39 :                     rbb[IGlass - 1][1] = matGlass->ReflectVisBeamBack;
     585              :                 }
     586              : 
     587           45 :                 if (matGlass->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
     588            2 :                     if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
     589            2 :                     numptDAT = wm->wle.size();
     590            2 :                     numpt[IGlass - 1] = numptDAT;
     591            2 :                     if (wm->BGFlag) {
     592              :                         // 5/16/2012 CR 8793. Add warning message for the glazing defined with full spectral data.
     593            0 :                         ShowWarningError(state,
     594            0 :                                          format("Window glazing material \"{}\" was defined with full spectral and angular data and has been "
     595              :                                                 "converted to average spectral data",
     596            0 :                                                 matGlass->Name));
     597            0 :                         ShowContinueError(
     598              :                             state,
     599            0 :                             format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
     600            0 :                         ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
     601            0 :                         ShowContinueError(state,
     602              :                                           "If this material is also used in other window constructions  without between-glass shades or blinds,");
     603            0 :                         ShowContinueError(state,
     604              :                                           "then make a duplicate material (with new name) if you want to model those windows  (and reference the new "
     605              :                                           "material) using the full spectral data.");
     606              :                         // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
     607              :                         //  assuming wlt same as wle
     608            0 :                         for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
     609            0 :                             Real64 lam = wm->wle[ILam - 1];
     610            0 :                             wlt[IGlass - 1][ILam - 1] = lam;
     611            0 :                             t[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, 0.0, lam);
     612            0 :                             rff[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, 0.0, lam);
     613            0 :                             rbb[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, 0.0, lam);
     614              :                         }
     615            0 :                         wm->tmpTrans = solarSpectrumAverage(state, t[0]);
     616            0 :                         wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
     617            0 :                         wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
     618              : 
     619              :                         // visible properties
     620            0 :                         wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
     621            0 :                         wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
     622            0 :                         wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
     623              : 
     624              :                         // set this material to average spectral data
     625            0 :                         matGlass->windowOpticalData = Window::OpticalDataModel::SpectralAverage;
     626            0 :                         matGlass->Trans = wm->tmpTrans;
     627            0 :                         matGlass->TransVis = wm->tmpTransVis;
     628            0 :                         matGlass->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
     629            0 :                         matGlass->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
     630            0 :                         matGlass->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
     631            0 :                         matGlass->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
     632            0 :                         SpecDataNum = 0;
     633              :                     }
     634              :                 }
     635              :             } // End of loop over glass layers in the construction for front calculation
     636              : 
     637              :             // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
     638              :             // Get glass layer properties, then glazing system properties (which include the
     639              :             // effect of inter-reflection among glass layers) at each incidence angle.
     640              : 
     641              :             // <<<<<<< HEAD
     642              :             // This was not a clear merge conflict, so I'm just taking the branch code and we'll see.
     643              :             std::array<Real64, numPhis> cosPhisLocal;
     644              :             // =======
     645              :             //  for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
     646              :             //      // 10 degree increment for incident angle is only value for a construction without a layer = SpectralAndAngle
     647              :             //      Phi = double(IPhi - 1) * 10.0;
     648              :             //      CosPhi = std::cos(Phi * Constant::DegToRad);
     649              :             //      if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
     650              :             // >>>>>>> origin/develop
     651              : 
     652          385 :             for (int iPhi = 0; iPhi < numPhis; ++iPhi)
     653          350 :                 cosPhisLocal[iPhi] = std::cos((double)iPhi * dPhiDeg * Constant::DegToRad);
     654              : 
     655          385 :             for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
     656              :                 // For each wavelength, get glass layer properties at this angle of incidence
     657              :                 // from properties at normal incidence
     658          800 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     659          450 :                     LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
     660          450 :                     auto *matGlass = dynamic_cast<Material::MaterialGlass *>(s_mat->materials(LayPtr));
     661          450 :                     assert(matGlass != nullptr);
     662          450 :                     if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
     663        11890 :                         for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
     664        11460 :                             TransAndReflAtPhi(cosPhisLocal[iPhi],
     665        11460 :                                               t[IGlass - 1][ILam - 1],
     666        11460 :                                               rff[IGlass - 1][ILam - 1],
     667        11460 :                                               rbb[IGlass - 1][ILam - 1],
     668        11460 :                                               tPhi[IGlass - 1][ILam - 1],
     669        11460 :                                               rfPhi[IGlass - 1][ILam - 1],
     670        11460 :                                               rbPhi[IGlass - 1][ILam - 1],
     671        11460 :                                               wm->lSimpleGlazingSystem,
     672        11460 :                                               wm->SimpleGlazingSHGC,
     673        11460 :                                               wm->SimpleGlazingU);
     674              :                         }
     675              :                     } else {
     676         4320 :                         for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
     677         2140 :                             Real64 lam = wm->wle[ILam - 1];
     678         2140 :                             wlt[IGlass - 1][ILam - 1] = lam;
     679         2140 :                             tPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, iPhi * dPhiDeg, lam);
     680         2140 :                             rfPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, iPhi * dPhiDeg, lam);
     681         2140 :                             rbPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, iPhi * dPhiDeg, lam);
     682              :                         }
     683              :                     }
     684              :                     // For use with between-glass shade/blind, save angular properties of isolated glass
     685              :                     // for case that all glass layers were input with spectral-average properties
     686              :                     //  only used by between-glass shades or blinds
     687          450 :                     if (AllGlassIsSpectralAverage) {
     688          390 :                         tBareSolPhi(IGlass)[iPhi] = tPhi[IGlass - 1][0];
     689          390 :                         tBareVisPhi(IGlass)[iPhi] = tPhi[IGlass - 1][1];
     690          390 :                         rfBareSolPhi(IGlass)[iPhi] = rfPhi[IGlass - 1][0];
     691          390 :                         rfBareVisPhi(IGlass)[iPhi] = rfPhi[IGlass - 1][1];
     692          390 :                         rbBareSolPhi(IGlass)[iPhi] = rbPhi[IGlass - 1][0];
     693          390 :                         rbBareVisPhi(IGlass)[iPhi] = rbPhi[IGlass - 1][1];
     694          390 :                         afBareSolPhi(IGlass)[iPhi] = max(0.0, 1.0 - (tBareSolPhi(IGlass)[iPhi] + rfBareSolPhi(IGlass)[iPhi]));
     695          390 :                         abBareSolPhi(IGlass)[iPhi] = max(0.0, 1.0 - (tBareSolPhi(IGlass)[iPhi] + rbBareSolPhi(IGlass)[iPhi]));
     696              :                     }
     697              :                 }
     698              : 
     699              :                 // For each wavelength in the solar spectrum, calculate system properties
     700              :                 // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence.
     701              :                 // In the following the argument "1" indicates that spectral average solar values
     702              :                 // should be used for layers without spectral data.
     703              : 
     704          350 :                 std::array<Real64, nume> stPhi = {0.0};  // Glazing system transmittance at angle of incidence for each wavelength in wle
     705          350 :                 std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
     706          350 :                 std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelength in wle
     707              :                 // For each layer, glazing system absorptance at angle of incidence
     708          350 :                 Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
     709              : 
     710          350 :                 SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
     711              : 
     712              :                 // Get solar properties of system by integrating over solar irradiance spectrum.
     713              :                 // For now it is assumed that the exterior and interior irradiance spectra are the same.
     714          350 :                 tsolPhi[iPhi] = solarSpectrumAverage(state, stPhi);
     715          350 :                 rfsolPhi[iPhi] = solarSpectrumAverage(state, srfPhi);
     716          350 :                 rbsolPhi[iPhi] = solarSpectrumAverage(state, srbPhi);
     717              : 
     718          800 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     719        48600 :                     for (int ILam = 1; ILam <= nume; ++ILam) {
     720        48150 :                         sabsPhi(ILam) = saPhi(IGlass, ILam);
     721              :                     }
     722          450 :                     solabsPhi(IGlass)[iPhi] = solarSpectrumAverage(state, sabsPhi);
     723              :                 }
     724              : 
     725              :                 // Get visible properties of system by integrating over solar irradiance
     726              :                 // spectrum weighted by photopic response.
     727              :                 // Need to redo the calculation of system spectral properties here only if
     728              :                 // one or more glass layers have no spectral data (lquasi = .TRUE.); in this
     729              :                 // case the spectral average visible properties will be used for the layers
     730              :                 // without spectral data, as indicated by the argument "2".
     731              : 
     732          350 :                 if (lquasi) SystemSpectralPropertiesAtPhi(state, 2, NGlass, 0.37, 0.78, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
     733          350 :                 tvisPhi[iPhi] = visibleSpectrumAverage(state, stPhi);
     734          350 :                 rfvisPhi[iPhi] = visibleSpectrumAverage(state, srfPhi);
     735          350 :                 rbvisPhi[iPhi] = visibleSpectrumAverage(state, srbPhi);
     736              : 
     737          350 :             } // End of loop over incidence angles for front calculation
     738              : 
     739              :             //  only used by between-glass shades or blinds
     740           35 :             if (AllGlassIsSpectralAverage) {
     741           71 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     742           39 :                     W5LsqFit(cosPhisLocal, tBareSolPhi(IGlass), thisConstruct.tBareSolCoef(IGlass));
     743           39 :                     W5LsqFit(cosPhisLocal, tBareVisPhi(IGlass), thisConstruct.tBareVisCoef(IGlass));
     744           39 :                     W5LsqFit(cosPhisLocal, rfBareSolPhi(IGlass), thisConstruct.rfBareSolCoef(IGlass));
     745           39 :                     W5LsqFit(cosPhisLocal, rfBareVisPhi(IGlass), thisConstruct.rfBareVisCoef(IGlass));
     746           39 :                     W5LsqFit(cosPhisLocal, rbBareSolPhi(IGlass), thisConstruct.rbBareSolCoef(IGlass));
     747           39 :                     W5LsqFit(cosPhisLocal, rbBareVisPhi(IGlass), thisConstruct.rbBareVisCoef(IGlass));
     748           39 :                     W5LsqFit(cosPhisLocal, afBareSolPhi(IGlass), thisConstruct.afBareSolCoef(IGlass));
     749           39 :                     W5LsqFit(cosPhisLocal, abBareSolPhi(IGlass), thisConstruct.abBareSolCoef(IGlass));
     750              :                 }
     751              :             }
     752              : 
     753           35 :             thisConstruct.ReflectSolDiffFront = DiffuseAverage(rfsolPhi);
     754           35 :             thisConstruct.ReflectSolDiffBack = DiffuseAverage(rbsolPhi);
     755           35 :             thisConstruct.ReflectVisDiffFront = DiffuseAverage(rfvisPhi);
     756           35 :             thisConstruct.ReflectVisDiffBack = DiffuseAverage(rbvisPhi);
     757              : 
     758           35 :             tsolDiff = DiffuseAverage(tsolPhi);
     759           35 :             tvisDiff = DiffuseAverage(tvisPhi);
     760           35 :             thisConstruct.TransDiff = tsolDiff;
     761           35 :             thisConstruct.TransDiffVis = tvisDiff;
     762           80 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     763           45 :                 solabsPhiLay = solabsPhi(IGlass); // Is this a deep copy?
     764           45 :                 solabsDiff(IGlass) = DiffuseAverage(solabsPhiLay);
     765           45 :                 thisConstruct.AbsDiff(IGlass) = solabsDiff(IGlass);
     766              : 
     767              :                 // For use with between-glass shade/blind, get diffuse properties of isolated glass for case when
     768              :                 // all glass layers were input with spectral-average properties
     769              :                 //  only used by between-glass shades or blinds
     770           45 :                 if (AllGlassIsSpectralAverage) {
     771           39 :                     thisConstruct.tBareSolDiff(IGlass) = DiffuseAverage(tBareSolPhi(IGlass));
     772           39 :                     thisConstruct.tBareVisDiff(IGlass) = DiffuseAverage(tBareVisPhi(IGlass));
     773           39 :                     thisConstruct.rfBareSolDiff(IGlass) = DiffuseAverage(rfBareSolPhi(IGlass));
     774           39 :                     thisConstruct.rfBareVisDiff(IGlass) = DiffuseAverage(rfBareVisPhi(IGlass));
     775           39 :                     thisConstruct.rbBareSolDiff(IGlass) = DiffuseAverage(rbBareSolPhi(IGlass));
     776           39 :                     thisConstruct.rbBareVisDiff(IGlass) = DiffuseAverage(rbBareVisPhi(IGlass));
     777           39 :                     thisConstruct.afBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rfBareSolDiff(IGlass)));
     778           39 :                     thisConstruct.abBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rbBareSolDiff(IGlass)));
     779              :                 }
     780              :             }
     781              : 
     782              :             //------------------------------------------------------------------------------------------
     783              :             // Back calculation (solar incident from inside of room); bare glass portion of construction
     784              :             //------------------------------------------------------------------------------------------
     785              : 
     786           35 :             lquasi = false;
     787           35 :             wm->LayerNum = {0};
     788              : 
     789              :             // Loop over glass layers in the construction.
     790           80 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     791           45 :                 int LayNum = 1 + (NGlass - IGlass) * 2;
     792           45 :                 if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + (NGlass - IGlass) * 2;
     793           45 :                 if (BGShade || BGBlind) {
     794            0 :                     if (NGlass == 2) {
     795            0 :                         if (IGlass == 1) LayNum = 5;
     796            0 :                         if (IGlass == 2) LayNum = 1;
     797              :                     } else { // NGlass = 3
     798            0 :                         if (IGlass == 1) LayNum = 7;
     799            0 :                         if (IGlass == 2) LayNum = 3;
     800            0 :                         if (IGlass == 3) LayNum = 1;
     801              :                     }
     802              :                 }
     803           45 :                 wm->LayerNum[IGlass - 1] = LayNum;
     804           45 :                 LayPtr = thisConstruct.LayerPoint(LayNum);
     805           45 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(s_mat->materials(LayPtr));
     806           45 :                 assert(matGlass != nullptr);
     807              : 
     808           45 :                 if (matGlass->GlassSpectralDataPtr != 0) {
     809            4 :                     auto const &specData = s_mat->SpectralData(matGlass->GlassSpectralDataPtr);
     810              :                     // Get the spectral data for the transmittance, front reflectance and
     811              :                     // back reflectance (all at normal incidence) for this layer.
     812              :                     // In this case, "front" means incident from the inside and "back"
     813              :                     // means incident from the outside.
     814              : 
     815            4 :                     numptDAT = specData.NumOfWavelengths;
     816            4 :                     numpt[IGlass - 1] = numptDAT;
     817              : 
     818         1072 :                     for (int ILam = 1; ILam <= numptDAT; ++ILam) {
     819         1068 :                         wlt[IGlass - 1][ILam - 1] = specData.WaveLength(ILam);
     820         1068 :                         t[IGlass - 1][ILam - 1] = specData.Trans(ILam);
     821         1068 :                         if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][ILam - 1] *= matGlass->GlassTransDirtFactor;
     822         1068 :                         rff[IGlass - 1][ILam - 1] = specData.ReflBack(ILam);
     823         1068 :                         rbb[IGlass - 1][ILam - 1] = specData.ReflFront(ILam);
     824              :                     }
     825              : 
     826              :                     // No spectral data for this layer; use spectral average values
     827           41 :                 } else if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
     828           39 :                     lquasi = true;
     829           39 :                     numpt[IGlass - 1] = 2;
     830           39 :                     t[IGlass - 1][0] = matGlass->Trans;
     831           39 :                     if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][0] *= matGlass->GlassTransDirtFactor;
     832           39 :                     t[IGlass - 1][1] = matGlass->TransVis;
     833           39 :                     if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][1] *= matGlass->GlassTransDirtFactor;
     834           39 :                     rff[IGlass - 1][0] = matGlass->ReflectSolBeamBack;
     835           39 :                     rbb[IGlass - 1][0] = matGlass->ReflectSolBeamFront;
     836           39 :                     rff[IGlass - 1][1] = matGlass->ReflectVisBeamBack;
     837           39 :                     rbb[IGlass - 1][1] = matGlass->ReflectVisBeamFront;
     838              : 
     839              :                     // Using SpectralAndAngle here
     840              :                 } else {
     841            2 :                     numptDAT = wm->wle.size();
     842            2 :                     numpt[IGlass - 1] = numptDAT;
     843              :                 }
     844              :             } // End of loop over glass layers in the construction for back calculation
     845              : 
     846              :             // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
     847              :             // Get bare glass layer properties, then glazing system properties at each incidence angle.
     848              :             // The glazing system properties include the effect of inter-reflection among glass layers,
     849              :             // but exclude the effect of a shade or blind if present in the construction.
     850              :             // When a construction has a layer = SpectralAndAngle, the 10 degree increment will be overridden.
     851              : 
     852              :             // another odd merge conflict, I'm just taking the branch code
     853              :             //<<<<<<< HEAD
     854          385 :             for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
     855              :                 //=======
     856              :                 // for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
     857              :                 //    Phi = double(IPhi - 1) * 10.0;
     858              :                 //    CosPhi = std::cos(Phi * Constant::DegToRad);
     859              :                 //    if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
     860              : 
     861              :                 // >>>>>>> origin/develop
     862              :                 // For each wavelength, get glass layer properties at this angle of incidence
     863              :                 // from properties at normal incidence
     864          800 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     865          450 :                     LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
     866          450 :                     auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(s_mat->materials(LayPtr));
     867          450 :                     assert(matGlass != nullptr);
     868          450 :                     if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
     869        11890 :                         for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
     870              : 
     871        11460 :                             TransAndReflAtPhi(cosPhisLocal[iPhi],
     872        11460 :                                               t[IGlass - 1][ILam - 1],
     873        11460 :                                               rff[IGlass - 1][ILam - 1],
     874        11460 :                                               rbb[IGlass - 1][ILam - 1],
     875        11460 :                                               tPhi[IGlass - 1][ILam - 1],
     876        11460 :                                               rfPhi[IGlass - 1][ILam - 1],
     877        11460 :                                               rbPhi[IGlass - 1][ILam - 1],
     878        11460 :                                               wm->lSimpleGlazingSystem,
     879        11460 :                                               wm->SimpleGlazingSHGC,
     880        11460 :                                               wm->SimpleGlazingU);
     881              :                         }
     882              : 
     883              :                     } else {
     884         4320 :                         for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
     885         2140 :                             Real64 lam = wm->wle[ILam - 1];
     886         2140 :                             wlt[IGlass - 1][ILam - 1] = lam;
     887         2140 :                             tPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, iPhi * dPhiDeg, lam);
     888         2140 :                             rfPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, iPhi * dPhiDeg, lam);
     889         2140 :                             rbPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, iPhi * dPhiDeg, lam);
     890              :                         }
     891              :                     }
     892              :                 }
     893              : 
     894              :                 // For each wavelength in the solar spectrum, calculate system properties
     895              :                 // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence
     896          350 :                 std::array<Real64, nume> stPhi = {0.0};  // Glazing system transmittance at angle of incidence for each wavelength in wle
     897          350 :                 std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
     898          350 :                 std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelength in wle
     899              :                 // For each layer, glazing system absorptance at angle of incidence
     900          350 :                 Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
     901              : 
     902          350 :                 SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
     903              : 
     904              :                 // Get back absorptance properties of system by integrating over solar irradiance spectrum.
     905              :                 // For now it is assumed that the exterior and interior irradiance spectra are the same.
     906              : 
     907          800 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     908        48600 :                     for (int j = 1; j <= nume; ++j) {
     909        48150 :                         sabsPhi(j) = saPhi(IGlass, j);
     910              :                     }
     911          450 :                     solabsBackPhi(IGlass)[iPhi] = solarSpectrumAverage(state, sabsPhi);
     912              :                 }
     913              : 
     914          350 :             } // End of loop over incidence angles for back calculation
     915              : 
     916           80 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     917           45 :                 IGlassBack = NGlass - IGlass + 1;
     918           45 :                 thisConstruct.AbsDiffBack(IGlass) = DiffuseAverage(solabsBackPhi(IGlassBack));
     919              :             }
     920              : 
     921              :             //-----------------------------------------------------------------------
     922              :             // Correction for effect of shade, screen or blind if present in the construction
     923              :             //-----------------------------------------------------------------------
     924              : 
     925              :             // For construction with shade, screen or blind, get system shading device absorptance
     926              :             // and correct the system glass layer absorptances for the effect of reflection
     927              :             // and transmission by shade, screen or blind. Get system reflectance (front and back,
     928              :             // solar and visible)
     929           35 :             auto &constr = thisConstruct;
     930              : 
     931              :             // Solar and visible properties of isolated shade or blind
     932              :             // (Note: for shades or screen we go through the following loop over slat angles only once.)
     933              : 
     934           35 :             Real64 const tsolDiff_2(pow_2(tsolDiff));
     935           35 :             Real64 const tvisDiff_2(pow_2(tvisDiff));
     936              : 
     937           35 :             if (IntShade) {
     938            0 :                 auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
     939            0 :                 assert(matSh != nullptr);
     940            0 :                 ShadeAbs = matSh->AbsorpSolar;
     941            0 :                 ShadeTrans = matSh->Trans;
     942            0 :                 ShadeTransVis = matSh->TransVis;
     943            0 :                 ShadeRefl = matSh->ReflectShade;
     944            0 :                 ShadeReflVis = matSh->ReflectShadeVis;
     945            0 :                 rsh = ShadeRefl;
     946            0 :                 rshv = ShadeReflVis;
     947            0 :                 tsh = ShadeTrans;
     948            0 :                 tshv = ShadeTransVis;
     949            0 :                 ash = ShadeAbs;
     950              : 
     951              :                 // Correction factors for inter-reflections between glass and shading device
     952            0 :                 ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffBack);
     953            0 :                 ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffBack);
     954              : 
     955              :                 // Front incident solar, beam, interior shade
     956            0 :                 for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
     957            0 :                     for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     958            0 :                         solabsPhi(IGlass)[iPhi] += tsolPhi[iPhi] * ShadeRefl * ShadeReflFac * constr.AbsDiffBack(IGlass);
     959              :                     }
     960            0 :                     solabsShadePhi[iPhi] = tsolPhi[iPhi] * ShadeReflFac * ShadeAbs;
     961            0 :                     tsolPhi[iPhi] *= ShadeReflFac * ShadeTrans;
     962            0 :                     tvisPhi[iPhi] *= ShadeReflFacVis * ShadeTransVis;
     963              :                 }
     964              : 
     965              :                 // Front incident solar, diffuse, interior shade
     966            0 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     967            0 :                     constr.AbsDiff(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
     968              :                 }
     969              : 
     970            0 :                 constr.AbsDiffShade = tsolDiff * ShadeReflFac * ShadeAbs;
     971            0 :                 constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
     972            0 :                 constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
     973            0 :                 constr.ReflectSolDiffFront += tsolDiff_2 * ShadeRefl * ShadeReflFac;
     974            0 :                 constr.ReflectVisDiffFront += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
     975              : 
     976              :                 // Back incident solar, diffuse, interior shade
     977              : 
     978            0 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     979            0 :                     constr.AbsDiffBack(IGlass) *= ShadeTrans * ShadeReflFac;
     980              :                 }
     981              : 
     982            0 :                 constr.AbsDiffBackShade = ShadeAbs * (1 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffBack);
     983            0 :                 constr.ReflectSolDiffBack = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffBack * ShadeReflFac;
     984            0 :                 constr.ReflectVisDiffBack = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffBack * ShadeReflFacVis;
     985              : 
     986              :                 // Exterior Shade
     987           35 :             } else if (ExtShade) {
     988            0 :                 auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
     989            0 :                 assert(matSh != nullptr);
     990            0 :                 ShadeAbs = matSh->AbsorpSolar;
     991            0 :                 ShadeTrans = matSh->Trans;
     992            0 :                 ShadeTransVis = matSh->TransVis;
     993            0 :                 ShadeRefl = matSh->ReflectShade;
     994            0 :                 ShadeReflVis = matSh->ReflectShadeVis;
     995            0 :                 rsh = ShadeRefl;
     996            0 :                 rshv = ShadeReflVis;
     997            0 :                 tsh = ShadeTrans;
     998            0 :                 tshv = ShadeTransVis;
     999            0 :                 ash = ShadeAbs;
    1000              : 
    1001              :                 // Correction factors for inter-reflections between glass and shading device
    1002            0 :                 ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
    1003            0 :                 ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
    1004              : 
    1005            0 :                 for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
    1006            0 :                     for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1007            0 :                         solabsPhi(IGlass)[iPhi] = ShadeTrans * solabsDiff(IGlass) * ShadeReflFac;
    1008              :                     }
    1009            0 :                     tsolPhi[iPhi] = ShadeTrans * ShadeReflFac * tsolDiff;
    1010            0 :                     tvisPhi[iPhi] = ShadeTransVis * ShadeReflFacVis * tvisDiff;
    1011            0 :                     solabsShadePhi[iPhi] = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
    1012              :                 }
    1013              : 
    1014              :                 // Front incident solar, diffuse, exterior shade/screen/blind
    1015            0 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1016            0 :                     constr.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
    1017              :                 }
    1018              : 
    1019              :                 // Front incident solar, diffuse, exterior shade/screen
    1020            0 :                 constr.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
    1021            0 :                 constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
    1022            0 :                 constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1023            0 :                 constr.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffFront * ShadeReflFac;
    1024            0 :                 constr.ReflectVisDiffFront = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffFront * ShadeReflFacVis;
    1025              : 
    1026              :                 // Back incident solar, diffuse, exterior shade/screen
    1027            0 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1028            0 :                     constr.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
    1029              :                 }
    1030            0 :                 constr.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
    1031            0 :                 constr.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1032            0 :                 constr.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1033              : 
    1034              :                 // Between-glass shade
    1035           35 :             } else if (BGShade) {
    1036            0 :                 auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
    1037            0 :                 assert(matSh != nullptr);
    1038            0 :                 ShadeAbs = matSh->AbsorpSolar;
    1039            0 :                 ShadeTrans = matSh->Trans;
    1040            0 :                 ShadeTransVis = matSh->TransVis;
    1041            0 :                 ShadeRefl = matSh->ReflectShade;
    1042            0 :                 ShadeReflVis = matSh->ReflectShadeVis;
    1043            0 :                 rsh = ShadeRefl;
    1044            0 :                 rshv = ShadeReflVis;
    1045            0 :                 tsh = ShadeTrans;
    1046            0 :                 tshv = ShadeTransVis;
    1047            0 :                 ash = ShadeAbs;
    1048              : 
    1049              :                 // Between-glass shade/blind; assumed to be between glass #2 and glass #3
    1050            0 :                 tsh2 = pow_2(tsh);
    1051            0 :                 tshv2 = pow_2(tshv);
    1052            0 :                 td1 = constr.tBareSolDiff(1);
    1053            0 :                 td2 = constr.tBareSolDiff(2);
    1054            0 :                 td1v = constr.tBareVisDiff(1);
    1055            0 :                 td2v = constr.tBareVisDiff(2);
    1056            0 :                 afd1 = constr.afBareSolDiff(1);
    1057            0 :                 afd2 = constr.afBareSolDiff(2);
    1058            0 :                 abd1 = constr.abBareSolDiff(1);
    1059            0 :                 abd2 = constr.abBareSolDiff(2);
    1060            0 :                 rb1 = constr.rbBareSolDiff(1);
    1061            0 :                 rb2 = constr.rbBareSolDiff(2);
    1062            0 :                 rb1v = constr.rbBareVisDiff(1);
    1063            0 :                 rb2v = constr.rbBareVisDiff(2);
    1064            0 :                 rf1 = constr.rfBareSolDiff(1);
    1065            0 :                 rf2 = constr.rfBareSolDiff(2);
    1066            0 :                 rf1v = constr.rfBareVisDiff(1);
    1067            0 :                 rf2v = constr.rfBareVisDiff(2);
    1068              : 
    1069            0 :                 if (NGlass == 2) {
    1070              : 
    1071              :                     // Front incident solar, beam, between-glass shade, NGlass = 2
    1072              : 
    1073            0 :                     for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
    1074            0 :                         t1 = tBareSolPhi(1)[iPhi];
    1075            0 :                         t1v = tBareVisPhi(1)[iPhi];
    1076            0 :                         af1 = afBareSolPhi(1)[iPhi];
    1077            0 :                         ab1 = abBareSolPhi(1)[iPhi];
    1078            0 :                         tsolPhi[iPhi] = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * td2;
    1079            0 :                         tvisPhi[iPhi] = t1v * (tshv + rshv * rb1v * tshv + tshv * rf2v * rshv) * td2v;
    1080            0 :                         solabsShadePhi[iPhi] = t1 * (ash + rsh * rb1 + tsh * rf2) * ash;
    1081            0 :                         solabsPhi(1)[iPhi] = af1 + t1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * abd1;
    1082            0 :                         solabsPhi(2)[iPhi] = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
    1083              :                     } // End of loop over incidence angles
    1084              : 
    1085              :                     // Front incident solar, diffuse, between-glass shade, NGlass = 2
    1086              : 
    1087            0 :                     constr.TransDiff = td1 * (tsh + rsh * rb1 * tsh + tsh * rb2 * rsh) * td2;
    1088            0 :                     constr.TransDiffVis = td1v * (tshv + rshv * rb1v * tshv + tshv * rb2v * rshv) * td2v;
    1089            0 :                     constr.AbsDiffShade = td1 * (ash + rsh * rb1 * ash + tsh * rf2 * ash);
    1090            0 :                     constr.AbsDiff(1) = afd1 + td1 * (rsh + tsh * rb2 * tsh) * abd1;
    1091            0 :                     constr.AbsDiff(2) = td1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
    1092            0 :                     constr.ReflectSolDiffFront = rf1 + td1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * td1;
    1093            0 :                     constr.ReflectVisDiffFront = rf1v + td1v * (rshv + rshv * rb1v * rshv + tshv * rf2v * tshv) * td1v;
    1094              : 
    1095              :                     // Back incident solar, diffuse, between-glass shade, NGlass = 2
    1096              : 
    1097            0 :                     constr.AbsDiffBackShade = td2 * (ash + rsh * rf2 * ash + tsh * rb1 * ash);
    1098            0 :                     constr.AbsDiffBack(1) = td2 * (tsh + rsh * rf2 * tsh + tsh * rb1 * rsh) * abd1;
    1099            0 :                     constr.AbsDiffBack(2) = abd2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * afd2;
    1100            0 :                     constr.ReflectSolDiffBack = rb2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * td2;
    1101            0 :                     constr.ReflectVisDiffBack = rb2v + td2v * (rshv + rshv * rf2v * rshv + tshv * rb1v * tshv) * td2v;
    1102              : 
    1103            0 :                 } else if (NGlass == 3) {
    1104              : 
    1105            0 :                     td3 = constr.tBareSolDiff(3);
    1106            0 :                     td3v = constr.tBareVisDiff(3);
    1107            0 :                     afd3 = constr.afBareSolDiff(3);
    1108            0 :                     abd3 = constr.abBareSolDiff(3);
    1109            0 :                     rb3 = constr.rbBareSolDiff(3);
    1110            0 :                     rb3v = constr.rbBareVisDiff(3);
    1111            0 :                     rf3 = constr.rfBareSolDiff(3);
    1112            0 :                     rf3v = constr.rfBareVisDiff(3);
    1113              : 
    1114              :                     // Front incident solar, beam, between-glass shade, NGlass = 3
    1115              : 
    1116            0 :                     for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
    1117            0 :                         t1 = tBareSolPhi(1)[iPhi];
    1118            0 :                         t1v = tBareVisPhi(1)[iPhi];
    1119            0 :                         t2 = tBareSolPhi(2)[iPhi];
    1120            0 :                         t2v = tBareVisPhi(2)[iPhi];
    1121            0 :                         af1 = afBareSolPhi(1)[iPhi];
    1122            0 :                         af2 = afBareSolPhi(2)[iPhi];
    1123            0 :                         ab1 = abBareSolPhi(1)[iPhi];
    1124            0 :                         ab2 = abBareSolPhi(2)[iPhi];
    1125            0 :                         rbmf2 = max(0.0, 1.0 - (t2 + af2));
    1126              : 
    1127            0 :                         tsolPhi[iPhi] = t1 * t2 * (tsh + tsh * rf3 * rsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh) * td3;
    1128            0 :                         tvisPhi[iPhi] = t1v * t2v * (tshv + tshv * rf3v * rshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv) * td3v;
    1129            0 :                         solabsShadePhi[iPhi] = t1 * t2 * (1 + rsh * td2 * rb1 * td2 + rsh * rb2) * ash;
    1130            0 :                         solabsPhi(1)[iPhi] = af1 + rbmf2 * ab1 + t1 * t2 * rsh * (1 + rf3 * tsh + rb2 * rsh + td2 * rb1 * td2 * rsh) * td2 * abd1;
    1131            0 :                         solabsPhi(2)[iPhi] = t1 * af2 + t1 * t2 * ((rsh + tsh * rf3 * tsh + rsh * rb2 * rsh) * abd2 + rsh * td2 * rb1 * afd2);
    1132            0 :                         solabsPhi(3)[iPhi] = t1 * t2 * (tsh + rsh * (rb2 * tsh + td2 * rb2 * td2 * tsh + rf3 * rsh)) * afd3;
    1133              :                     } // End of loop over incidence angle
    1134              : 
    1135              :                     // Front incident solar, diffuse, between-glass shade, NGlass = 3
    1136              : 
    1137            0 :                     constr.TransDiff = td1 * td2 * (tsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh + tsh * rf3 * rsh) * td3;
    1138            0 :                     constr.TransDiffVis = td1v * td2v * (tshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv + tshv * rf3v * rshv) * td3v;
    1139            0 :                     constr.AbsDiffShade = td1 * td2 * (ash * (1 + rsh * td2 * rb1 * td2 + rsh * rb2 * ash) + tsh * rf3 * ash);
    1140            0 :                     constr.AbsDiff(1) =
    1141            0 :                         afd1 + td1 * (rf2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh + rsh * td2 * rb1 * td2 * rsh) * td2) * abd1;
    1142            0 :                     constr.AbsDiff(2) = td1 * (afd2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh) * abd2);
    1143            0 :                     constr.AbsDiff(3) = td1 * td2 * (tsh + rsh * rb2 * tsh + rsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rsh) * afd3;
    1144            0 :                     constr.ReflectSolDiffFront =
    1145            0 :                         rf1 + td1 * rf2 * td1 + td1 * td2 * (rsh + tsh * rf3 * tsh + rsh * rb2 * rsh + rsh * td2 * rb1 * td2 * rsh) * td2 * td1;
    1146            0 :                     constr.ReflectVisDiffFront =
    1147            0 :                         rf1v + td1v * rf2v * td1v +
    1148            0 :                         td1v * td2v * (rshv + tshv * rf3v * tshv + rshv * rb2v * rshv + rshv * td2v * rb1v * td2v * rshv) * td2v * td1v;
    1149              : 
    1150              :                     // Back incident solar, diffuse, between-glass shade, NGlass = 3
    1151              : 
    1152            0 :                     constr.AbsDiffBackShade = td3 * ((1 + rsh * rf3) * ash + (tsh * td2 * rb1 * td2 + tsh * rb2) * ash);
    1153            0 :                     constr.AbsDiffBack(1) = td3 * (tsh + rsh * rf3 * tsh + tsh * rb2 * rsh + tsh * td2 * rb1 * td2 * rsh) * td2 * abd1;
    1154            0 :                     constr.AbsDiffBack(2) = td3 * ((tsh + rsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
    1155            0 :                     constr.AbsDiffBack(3) = abd3 + td3 * (rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
    1156            0 :                     constr.ReflectSolDiffBack = rb3 + td3 * (rsh + rsh * rf3 * rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
    1157            0 :                     constr.ReflectVisDiffBack =
    1158            0 :                         rb3v + td3v * (rshv + rshv * rf3 * rshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
    1159              : 
    1160              :                 } // End of check if NGlass = 3
    1161              : 
    1162              :                 // Interior blind
    1163           35 :             } else if (IntBlind) {
    1164            1 :                 auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
    1165              : 
    1166          182 :                 for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
    1167          181 :                     auto const &btar = matBlind->TARs[iSlatAng];
    1168          181 :                     ShadeTrans = btar.Sol.Ft.Df.Tra;
    1169          181 :                     ShadeTransGnd = btar.Sol.Ft.Df.TraGnd;
    1170          181 :                     ShadeTransSky = btar.Sol.Ft.Df.TraSky;
    1171          181 :                     ShadeTransVis = btar.Vis.Ft.Df.Tra;
    1172          181 :                     ShadeAbs = btar.Sol.Ft.Df.Abs;
    1173          181 :                     ShadeRefl = btar.Sol.Ft.Df.Ref;
    1174          181 :                     ShadeReflGnd = btar.Sol.Ft.Df.RefGnd;
    1175          181 :                     ShadeReflSky = btar.Sol.Ft.Df.RefSky;
    1176          181 :                     ShadeReflVis = btar.Vis.Ft.Df.Ref;
    1177              : 
    1178              :                     // Correction factors for inter-reflections between glass and shading device
    1179          181 :                     ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffBack);
    1180          181 :                     ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffBack);
    1181              : 
    1182              :                     // Front incident solar, diffuse, interior blind
    1183          362 :                     for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1184          181 :                         auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
    1185          181 :                         dfAbs.Sol.Ft.Df.Abs = constr.AbsDiff(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * constr.AbsDiffBack(IGlass);
    1186          181 :                         dfAbs.Sol.Ft.Df.AbsGnd = constr.AbsDiff(IGlass) + tsolDiff * ShadeReflGnd * ShadeReflFac * constr.AbsDiffBack(IGlass);
    1187          181 :                         dfAbs.Sol.Ft.Df.AbsSky = constr.AbsDiff(IGlass) + tsolDiff * ShadeReflSky * ShadeReflFac * constr.AbsDiffBack(IGlass);
    1188              :                     }
    1189              : 
    1190          181 :                     auto &cbtar = constr.blindTARs[iSlatAng];
    1191              : 
    1192          181 :                     cbtar.Sol.Ft.Df.Abs = tsolDiff * ShadeReflFac * ShadeAbs;
    1193          181 :                     cbtar.Sol.Ft.Df.AbsGnd = tsolDiff * ShadeReflFac * btar.Sol.Ft.Df.AbsGnd;
    1194          181 :                     cbtar.Sol.Ft.Df.AbsSky = tsolDiff * ShadeReflFac * btar.Sol.Ft.Df.AbsSky;
    1195          181 :                     cbtar.Sol.Ft.Df.Tra = tsolDiff * ShadeReflFac * ShadeTrans;
    1196          181 :                     cbtar.Sol.Ft.Df.TraGnd = tsolDiff * ShadeReflFac * ShadeTransGnd;
    1197          181 :                     cbtar.Sol.Ft.Df.TraSky = tsolDiff * ShadeReflFac * ShadeTransSky;
    1198          181 :                     cbtar.Vis.Ft.Df.Tra = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1199          181 :                     cbtar.Sol.Ft.Df.Ref = constr.ReflectSolDiffFront + tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1200          181 :                     cbtar.Vis.Ft.Df.Ref = constr.ReflectVisDiffFront + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1201              : 
    1202              :                     // Back incident solar, diffuse, interior blind
    1203              : 
    1204          362 :                     for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1205          181 :                         auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
    1206          181 :                         dfAbs.Sol.Bk.Df.Abs = constr.AbsDiffBack(IGlass) * ShadeTrans * ShadeReflFac;
    1207              :                     }
    1208              : 
    1209          181 :                     cbtar.Sol.Bk.Df.Abs = btar.Sol.Bk.Df.Abs + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffBack * ShadeAbs;
    1210          181 :                     cbtar.Sol.Bk.Df.Ref = btar.Sol.Bk.Df.Ref + pow_2(ShadeTrans) * constr.ReflectSolDiffBack * ShadeReflFac;
    1211          181 :                     cbtar.Vis.Bk.Df.Ref = btar.Vis.Bk.Df.Ref + pow_2(ShadeTransVis) * constr.ReflectVisDiffBack * ShadeReflFacVis;
    1212              :                 }
    1213              : 
    1214              :                 // Exterior blind
    1215           34 :             } else if (ExtBlind) {
    1216            0 :                 auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
    1217              : 
    1218            0 :                 for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
    1219            0 :                     auto const &btar = matBlind->TARs[iSlatAng];
    1220            0 :                     ShadeTrans = btar.Sol.Ft.Df.Tra;
    1221            0 :                     ShadeTransGnd = btar.Sol.Ft.Df.TraGnd;
    1222            0 :                     ShadeTransSky = btar.Sol.Ft.Df.TraSky;
    1223            0 :                     ShadeTransVis = btar.Vis.Ft.Df.Tra;
    1224            0 :                     ShadeAbs = btar.Sol.Bk.Df.Abs;
    1225            0 :                     ShadeRefl = btar.Sol.Bk.Df.Ref;
    1226            0 :                     ShadeReflVis = btar.Vis.Bk.Df.Ref;
    1227              : 
    1228              :                     // Correction factors for inter-reflections between glass and shading device
    1229            0 :                     ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
    1230            0 :                     ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
    1231              : 
    1232            0 :                     for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1233            0 :                         auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
    1234            0 :                         dfAbs.Sol.Ft.Df.Abs = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
    1235            0 :                         dfAbs.Sol.Ft.Df.AbsGnd = ShadeTransGnd * ShadeReflFac * solabsDiff(IGlass);
    1236            0 :                         dfAbs.Sol.Ft.Df.AbsSky = ShadeTransSky * ShadeReflFac * solabsDiff(IGlass);
    1237              :                     }
    1238              : 
    1239            0 :                     auto &cbtar = constr.blindTARs[iSlatAng];
    1240            0 :                     cbtar.Sol.Ft.Df.Abs = btar.Sol.Ft.Df.Abs + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
    1241            0 :                     cbtar.Sol.Ft.Df.AbsGnd = btar.Sol.Ft.Df.AbsGnd + ShadeTransGnd * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
    1242            0 :                     cbtar.Sol.Ft.Df.AbsSky = btar.Sol.Ft.Df.AbsSky + ShadeTransSky * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
    1243            0 :                     cbtar.Sol.Ft.Df.Tra = tsolDiff * ShadeReflFac * ShadeTrans;
    1244            0 :                     cbtar.Sol.Ft.Df.TraGnd = tsolDiff * ShadeReflFac * ShadeTransGnd;
    1245            0 :                     cbtar.Sol.Ft.Df.TraSky = tsolDiff * ShadeReflFac * ShadeTransSky;
    1246            0 :                     cbtar.Vis.Ft.Df.Tra = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1247            0 :                     cbtar.Sol.Ft.Df.Ref = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
    1248            0 :                     cbtar.Vis.Ft.Df.Ref = ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
    1249              : 
    1250              :                     // Back incident solar, diffuse, exterior shade/blind
    1251            0 :                     for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1252            0 :                         auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
    1253            0 :                         dfAbs.Sol.Bk.Df.Abs = constr.AbsDiffBack(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
    1254              :                     }
    1255              : 
    1256            0 :                     cbtar.Sol.Bk.Df.Abs = tsolDiff * ShadeReflFac * ShadeAbs;
    1257            0 :                     cbtar.Sol.Bk.Df.Ref = constr.ReflectSolDiffBack + tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1258            0 :                     cbtar.Vis.Bk.Df.Ref = constr.ReflectVisDiffBack + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1259              :                 }
    1260              : 
    1261              :                 // Between-glass blind
    1262           34 :             } else if (BGBlind) {
    1263            0 :                 auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
    1264            0 :                 assert(matBlind != nullptr);
    1265              : 
    1266              :                 // Between-glass shade/blind; assumed to be between glass #2 and glass #3
    1267            0 :                 tsh2 = pow_2(tsh);
    1268            0 :                 tshv2 = pow_2(tshv);
    1269            0 :                 td1 = constr.tBareSolDiff(1);
    1270            0 :                 td2 = constr.tBareSolDiff(2);
    1271            0 :                 td1v = constr.tBareVisDiff(1);
    1272            0 :                 td2v = constr.tBareVisDiff(2);
    1273            0 :                 afd1 = constr.afBareSolDiff(1);
    1274            0 :                 afd2 = constr.afBareSolDiff(2);
    1275            0 :                 abd1 = constr.abBareSolDiff(1);
    1276            0 :                 abd2 = constr.abBareSolDiff(2);
    1277            0 :                 rb1 = constr.rbBareSolDiff(1);
    1278            0 :                 rb2 = constr.rbBareSolDiff(2);
    1279            0 :                 rb1v = constr.rbBareVisDiff(1);
    1280            0 :                 rb2v = constr.rbBareVisDiff(2);
    1281            0 :                 rf1 = constr.rfBareSolDiff(1);
    1282            0 :                 rf2 = constr.rfBareSolDiff(2);
    1283            0 :                 rf1v = constr.rfBareVisDiff(1);
    1284            0 :                 rf2v = constr.rfBareVisDiff(2);
    1285              : 
    1286            0 :                 for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
    1287            0 :                     auto const &btar = matBlind->TARs[iSlatAng];
    1288            0 :                     tsh = btar.Sol.Ft.Df.Tra;
    1289            0 :                     tshGnd = btar.Sol.Ft.Df.TraGnd;
    1290            0 :                     tshSky = btar.Sol.Ft.Df.TraSky;
    1291            0 :                     tshv = btar.Vis.Ft.Df.Tra;
    1292            0 :                     rfsh = btar.Sol.Ft.Df.Ref;
    1293            0 :                     rfshGnd = btar.Sol.Ft.Df.RefGnd;
    1294            0 :                     rfshSky = btar.Sol.Ft.Df.RefSky;
    1295            0 :                     rfshv = btar.Vis.Ft.Df.Ref;
    1296            0 :                     rbsh = btar.Sol.Bk.Df.Ref;
    1297            0 :                     rbshv = btar.Vis.Bk.Df.Ref;
    1298            0 :                     afsh = btar.Sol.Ft.Df.Abs;
    1299            0 :                     afshGnd = btar.Sol.Ft.Df.AbsGnd;
    1300            0 :                     afshSky = btar.Sol.Ft.Df.AbsSky;
    1301            0 :                     absh = btar.Sol.Bk.Df.Abs;
    1302              : 
    1303            0 :                     auto &cbtar = constr.blindTARs[iSlatAng];
    1304            0 :                     if (NGlass == 2) {
    1305              :                         // Front incident solar, diffuse, between-glass blind, NGlass = 2
    1306            0 :                         auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng];
    1307            0 :                         auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng];
    1308            0 :                         dfAbs1.Sol.Ft.Df.Abs = afd1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rb2 * tsh) * abd1;
    1309            0 :                         dfAbs1.Sol.Ft.Df.AbsGnd = afd1 + td1 * (rfshGnd + rfshGnd * rb1 * rfshGnd + tshGnd * rb2 * tsh) * abd1;
    1310            0 :                         dfAbs1.Sol.Ft.Df.AbsSky = afd1 + td1 * (rfshSky + rfshSky * rb1 * rfshSky + tshSky * rb2 * tsh) * abd1;
    1311            0 :                         dfAbs2.Sol.Ft.Df.Abs = td1 * (tsh + rfsh * rb1 * tsh + tsh * rf2 * rbsh) * afd2;
    1312            0 :                         dfAbs2.Sol.Ft.Df.AbsGnd = td1 * (tshGnd + rfshGnd * rb1 * tsh + tshGnd * rf2 * rbsh) * afd2;
    1313            0 :                         dfAbs2.Sol.Ft.Df.AbsSky = td1 * (tshSky + rfshSky * rb1 * tsh + tshSky * rf2 * rbsh) * afd2;
    1314            0 :                         cbtar.Sol.Ft.Df.Abs = td1 * (afsh + rfsh * rb1 * afsh + tsh * rf2 * absh);
    1315            0 :                         cbtar.Sol.Ft.Df.AbsGnd = td1 * (afshGnd + rfsh * rb1 * afsh + tshGnd * rf2 * absh);
    1316            0 :                         cbtar.Sol.Ft.Df.AbsSky = td1 * (afshSky + rfsh * rb1 * afsh + tshSky * rf2 * absh);
    1317            0 :                         cbtar.Sol.Ft.Df.Tra = td1 * (tsh + rfsh * rb1 * tsh + tsh * rb2 * rbsh) * td2;
    1318            0 :                         cbtar.Sol.Ft.Df.TraGnd = td1 * (tshGnd + rfsh * rb1 * tshGnd + tshGnd * rb2 * rbsh) * td2;
    1319            0 :                         cbtar.Sol.Ft.Df.TraSky = td1 * (tshSky + rfsh * rb1 * tshSky + tshSky * rb2 * rbsh) * td2;
    1320            0 :                         cbtar.Vis.Ft.Df.Tra = td1v * (tshv + rfshv * rb1v * tshv + tshv * rb2v * rbshv) * td2v;
    1321            0 :                         cbtar.Sol.Ft.Df.Ref = rf1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rf2 * tsh) * td1;
    1322            0 :                         cbtar.Vis.Ft.Df.Ref = rf1v + td1v * (rfshv + rfshv * rb1v * rfshv + tshv * rf2v * tshv) * td1v;
    1323              : 
    1324              :                         // Back incident solar, diffuse, between-glass blind, NGlass = 2
    1325              : 
    1326            0 :                         dfAbs1.Sol.Bk.Df.Abs = td2 * (tsh + rbsh * rf2 * tsh + tsh * rb1 * rfsh) * abd1;
    1327            0 :                         dfAbs2.Sol.Bk.Df.Abs = abd2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * afd2;
    1328            0 :                         cbtar.Sol.Bk.Df.Abs = td2 * (absh + rbsh * rf2 * absh + tsh * rb1 * afsh);
    1329            0 :                         cbtar.Sol.Bk.Df.Ref = rb2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * td2;
    1330            0 :                         cbtar.Vis.Bk.Df.Ref = rb2v + td2v * (rbshv + rbshv * rf2v * rbshv + tshv * rb1v * tshv) * td2v;
    1331              : 
    1332            0 :                     } else if (NGlass == 3) {
    1333            0 :                         auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng];
    1334            0 :                         auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng];
    1335            0 :                         auto &dfAbs3 = constr.layerSlatBlindDfAbs(3)[iSlatAng];
    1336            0 :                         td3 = constr.tBareSolDiff(3);
    1337            0 :                         td3v = constr.tBareVisDiff(3);
    1338            0 :                         afd3 = constr.afBareSolDiff(3);
    1339            0 :                         abd3 = constr.abBareSolDiff(3);
    1340            0 :                         rb3 = constr.rbBareSolDiff(3);
    1341            0 :                         rb3v = constr.rbBareVisDiff(3);
    1342            0 :                         rf3 = constr.rfBareSolDiff(3);
    1343            0 :                         rf3v = constr.rfBareVisDiff(3);
    1344              : 
    1345              :                         // Front incident solar, diffuse, between-glass blind, NGlass = 3
    1346              : 
    1347            0 :                         dfAbs1.Sol.Ft.Df.Abs =
    1348            0 :                             afd1 + td1 * (rf2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh + rfsh * td2 * rb1 * td2 * rfsh) * td2) * abd1;
    1349            0 :                         dfAbs1.Sol.Ft.Df.AbsGnd =
    1350            0 :                             afd1 +
    1351            0 :                             td1 * (rf2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh + rfshGnd * td2 * rb1 * td2 * rfsh) * td2) * abd1;
    1352            0 :                         dfAbs1.Sol.Ft.Df.AbsSky =
    1353            0 :                             afd1 +
    1354            0 :                             td1 * (rf2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh + rfshSky * td2 * rb1 * td2 * rfsh) * td2) * abd1;
    1355            0 :                         dfAbs2.Sol.Ft.Df.Abs = td1 * (afd2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh) * abd2);
    1356            0 :                         dfAbs2.Sol.Ft.Df.AbsGnd = td1 * (afd2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh) * abd2);
    1357            0 :                         dfAbs2.Sol.Ft.Df.AbsSky = td1 * (afd2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh) * abd2);
    1358            0 :                         dfAbs3.Sol.Ft.Df.Abs = td1 * td2 * (tsh + rfsh * rb2 * tsh + rfsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rbsh) * afd3;
    1359            0 :                         dfAbs3.Sol.Ft.Df.AbsGnd =
    1360            0 :                             td1 * td2 * (tshGnd + rfshGnd * rb2 * tsh + rfshGnd * td2 * rb1 * td2 * tsh + tshGnd * rf3 * rbsh) * afd3;
    1361            0 :                         dfAbs3.Sol.Ft.Df.AbsSky =
    1362            0 :                             td1 * td2 * (tshSky + rfshSky * rb2 * tsh + rfshSky * td2 * rb1 * td2 * tsh + tshSky * rf3 * rbsh) * afd3;
    1363            0 :                         cbtar.Sol.Ft.Df.Abs = td1 * td2 * (afsh * (1 + rfsh * td2 * rb1 * td2) + rfsh * rb2 * afsh + tsh * rf3 * absh);
    1364            0 :                         cbtar.Sol.Ft.Df.AbsGnd = td1 * td2 * (afshGnd + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshGnd * rf3 * absh);
    1365            0 :                         cbtar.Sol.Ft.Df.AbsSky = td1 * td2 * (afshSky + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshSky * rf3 * absh);
    1366            0 :                         cbtar.Sol.Ft.Df.Tra = td1 * td2 * (tsh + rfsh * td2 * rb1 * td2 * tsh + rfsh * rb2 * tsh + tsh * rf3 * rbsh) * td3;
    1367            0 :                         cbtar.Sol.Ft.Df.TraGnd =
    1368            0 :                             td1 * td2 * (tshGnd + rfsh * td2 * rb1 * td2 * tshGnd + rfsh * rb2 * tshGnd + tshGnd * rf3 * rbsh) * td3;
    1369            0 :                         cbtar.Sol.Ft.Df.TraSky =
    1370            0 :                             td1 * td2 * (tshSky + rfsh * td2 * rb1 * td2 * tshSky + rfsh * rb2 * tshSky + tshSky * rf3 * rbsh) * td3;
    1371            0 :                         cbtar.Vis.Ft.Df.Tra =
    1372            0 :                             td1v * td2v * (tshv + rfshv * td2v * rb1v * td2v * tshv + rfshv * rb2v * tshv + tshv * rf3v * rbshv) * td3v;
    1373            0 :                         cbtar.Sol.Ft.Df.Ref = rf1 + td1 * rf2 * td1 +
    1374            0 :                                               td1 * td2 * (rfsh + tsh * rf3 * tsh + rfsh * rb2 * rfsh + rfsh * td2 * rb1 * td2 * rfsh) * td2 * td1;
    1375            0 :                         cbtar.Vis.Ft.Df.Ref =
    1376            0 :                             rf1v + td1v * rf2v * td1v +
    1377            0 :                             td1v * td2v * (rfshv + tshv * rf3v * tshv + rfshv * rb2v * rfshv + rfshv * td2v * rb1v * td2v * rfshv) * td2v * td1v;
    1378              : 
    1379              :                         // Back incident solar, diffuse, between-glass blind, NGlass = 3
    1380              : 
    1381            0 :                         dfAbs1.Sol.Bk.Df.Abs = td3 * (tsh + rbsh * rf3 * tsh + tsh * rb2 * rfsh + tsh * td2 * rb1 * td2 * rfsh) * td2 * abd1;
    1382            0 :                         dfAbs2.Sol.Bk.Df.Abs = td3 * ((tsh + rbsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
    1383            0 :                         dfAbs3.Sol.Bk.Df.Abs = abd3 + td3 * (rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
    1384            0 :                         cbtar.Sol.Bk.Df.Abs = td3 * ((1 + rbsh * rf3) * absh + (tsh * td2 * rb1 * td2 + tsh * rb2) * afsh);
    1385            0 :                         cbtar.Sol.Bk.Df.Ref = rb3 + td3 * (rbsh + rbsh * rf3 * rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
    1386            0 :                         cbtar.Vis.Bk.Df.Ref =
    1387            0 :                             rb3v + td3v * (rbshv + rbshv * rf3v * rbshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
    1388              :                     } // if (NGlass == 3)
    1389              :                 }     // for (iSlatAng)
    1390              : 
    1391              :                 // Exterior screen
    1392           34 :             } else if (ExtScreen) {
    1393              :                 //       diffuse screen properties are calculated during initialization (quarter-hemispherical integration of beam properties)
    1394            0 :                 auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(thisConstruct.LayerPoint(ShadeLayNum)));
    1395            0 :                 assert(matScreen != nullptr);
    1396              : 
    1397            0 :                 ShadeAbs = matScreen->DfAbs;
    1398            0 :                 ShadeTrans = matScreen->DfTrans;
    1399            0 :                 ShadeTransVis = matScreen->DfTransVis;
    1400            0 :                 ShadeRefl = matScreen->DfRef;
    1401            0 :                 ShadeReflVis = matScreen->DfRefVis;
    1402            0 :                 rsh = ShadeRefl;
    1403            0 :                 rshv = ShadeReflVis;
    1404            0 :                 tsh = ShadeTrans;
    1405            0 :                 tshv = ShadeTransVis;
    1406            0 :                 ash = ShadeAbs;
    1407              : 
    1408              :                 // Correction factors for inter-reflections between glass and shading device
    1409            0 :                 ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
    1410            0 :                 ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
    1411              : 
    1412              :                 // Front incident solar, diffuse, exterior shade/screen/blind
    1413            0 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1414            0 :                     constr.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
    1415              :                 }
    1416              : 
    1417              :                 // Front incident solar, diffuse, exterior shade/screen
    1418            0 :                 constr.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
    1419            0 :                 constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
    1420            0 :                 constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1421            0 :                 constr.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffFront * ShadeReflFac;
    1422            0 :                 constr.ReflectVisDiffFront = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffFront * ShadeReflFacVis;
    1423              : 
    1424              :                 // Back incident solar, diffuse, exterior shade/screen
    1425            0 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1426            0 :                     constr.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
    1427              :                 }
    1428            0 :                 constr.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
    1429            0 :                 constr.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1430            0 :                 constr.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1431              :             } // if (ExtScreen)
    1432              : 
    1433              :             // Curve fits to get solar transmittance, reflectance, layer absorptance and
    1434              :             // visible transmittance as polynomials in cosine of incidence angle
    1435              : 
    1436           35 :             if (!BlindOn && !ScreenOn) { // Bare glass or shade on
    1437           34 :                 W5LsqFit(cosPhisLocal, tsolPhi, thisConstruct.TransSolBeamCoef);
    1438           34 :                 W5LsqFit(cosPhisLocal, rfsolPhi, thisConstruct.ReflSolBeamFrontCoef);
    1439           34 :                 W5LsqFit(cosPhisLocal, rbsolPhi, thisConstruct.ReflSolBeamBackCoef);
    1440           34 :                 W5LsqFit(cosPhisLocal, tvisPhi, thisConstruct.TransVisBeamCoef);
    1441              : 
    1442           78 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1443              :                     // Front absorptance coefficients for glass layers
    1444           44 :                     W5LsqFit(cosPhisLocal, solabsPhi(IGlass), thisConstruct.AbsBeamCoef(IGlass));
    1445              : 
    1446              :                     // Back absorptance coefficients for glass layers
    1447           44 :                     IGlassBack = NGlass - IGlass + 1;
    1448           44 :                     W5LsqFit(cosPhisLocal, solabsBackPhi(IGlassBack), thisConstruct.AbsBeamBackCoef(IGlass));
    1449              :                 }
    1450              : 
    1451              :                 // To check goodness of fit //Tuned
    1452              : 
    1453          374 :                 for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
    1454          340 :                     tsolPhiFit[iPhi] = 0.0;
    1455          340 :                     tvisPhiFit[iPhi] = 0.0;
    1456              : 
    1457              :                     //<<<<<<< HEAD
    1458         2380 :                     for (int CoefNum = 0; CoefNum < maxPolyCoef; ++CoefNum) {
    1459         2040 :                         tsolPhiFit[iPhi] += thisConstruct.TransSolBeamCoef[CoefNum] * cosPhisLocal[iPhi];
    1460         2040 :                         tvisPhiFit[iPhi] += thisConstruct.TransVisBeamCoef[CoefNum] * cosPhisLocal[iPhi];
    1461              :                         //=======
    1462              :                         // Phi = double(IPhi - 1) * 10.0;
    1463              :                         // CosPhi = std::cos(Phi * Constant::DegToRad);
    1464              :                         // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
    1465              :                         // Real64 cos_pow(1.0);
    1466              :                         // for (int CoefNum = 1; CoefNum <= 6; ++CoefNum) {
    1467              :                         //     cos_pow *= CosPhi;
    1468              :                         //     tsolPhiFit(IPhi) += thisConstruct.TransSolBeamCoef(CoefNum) * cos_pow;
    1469              :                         //     tvisPhiFit(IPhi) += thisConstruct.TransVisBeamCoef(CoefNum) * cos_pow;
    1470              :                         // >>>>>>> origin/develop
    1471              :                     }
    1472              :                 }
    1473              :             }
    1474              : 
    1475           35 :             if (ShadeOn) W5LsqFit(cosPhisLocal, solabsShadePhi, thisConstruct.AbsBeamShadeCoef);
    1476              : 
    1477              :         } // End of loop over constructions
    1478              : 
    1479              :         // Get effective glass and shade/blind emissivities for windows that have interior blind or
    1480              :         // shade. These are used to calculate zone MRT contribution from window when
    1481              :         // interior blind/shade is deployed.
    1482              : 
    1483              :         // Loop for ordinary windows
    1484          942 :         for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
    1485          832 :             auto const &surf = s_surf->Surface(SurfNum);
    1486          832 :             if (!surf.HeatTransSurf) continue;
    1487          814 :             if (!state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    1488           52 :             if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) continue;       // Irrelevant for Complex Fen
    1489           52 :             if (state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) continue; // not required
    1490              : 
    1491           45 :             ConstrNumSh = surf.activeShadedConstruction;
    1492           45 :             if (ConstrNumSh == 0) continue;
    1493            9 :             TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    1494              : 
    1495            9 :             auto &surfShade = s_surf->surfShades(SurfNum);
    1496              : 
    1497            9 :             auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay));
    1498            9 :             auto const *matFen = dynamic_cast<Material::MaterialFen const *>(mat);
    1499            9 :             assert(matFen != nullptr);
    1500              : 
    1501            9 :             if (mat->group == Material::Group::Shade) {
    1502            0 :                 EpsGlIR = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1))->AbsorpThermalBack;
    1503            0 :                 RhoGlIR = 1 - EpsGlIR;
    1504            0 :                 TauShIR = matFen->TransThermal;
    1505            0 :                 EpsShIR = matFen->AbsorpThermal;
    1506            0 :                 RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
    1507            0 :                 surfShade.effShadeEmi = EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
    1508            0 :                 surfShade.effGlassEmi = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
    1509              : 
    1510            9 :             } else if (mat->group == Material::Group::Blind) {
    1511            8 :                 auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
    1512            8 :                 assert(matBlind != nullptr);
    1513            8 :                 surfShade.glass.epsIR = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1))->AbsorpThermalBack;
    1514            8 :                 surfShade.glass.rhoIR = 1 - surfShade.glass.epsIR;
    1515              : 
    1516              :                 // surfShade.blind has not been initialized yet
    1517            8 :                 surfShade.blind.slatAngDeg = matBlind->SlatAngle;
    1518            8 :                 surfShade.blind.slatAng = surfShade.blind.slatAngDeg * Constant::DegToRad;
    1519              : 
    1520            8 :                 Material::GetSlatIndicesInterpFac(
    1521            8 :                     surfShade.blind.slatAng, surfShade.blind.slatAngIdxLo, surfShade.blind.slatAngIdxHi, surfShade.blind.slatAngInterpFac);
    1522            8 :                 surfShade.blind.TAR.interpSlatAng(
    1523            8 :                     matBlind->TARs[surfShade.blind.slatAngIdxLo], matBlind->TARs[surfShade.blind.slatAngIdxHi], surfShade.blind.slatAngInterpFac);
    1524              : 
    1525            8 :                 TauShIR = surfShade.blind.TAR.IR.Ft.Tra;
    1526            8 :                 EpsShIR = surfShade.blind.TAR.IR.Bk.Emi;
    1527            8 :                 RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
    1528            8 :                 surfShade.effShadeEmi = EpsShIR * (1.0 + surfShade.glass.rhoIR * TauShIR / (1.0 - surfShade.glass.rhoIR * RhoShIR));
    1529            8 :                 surfShade.effGlassEmi = surfShade.glass.epsIR * TauShIR / (1.0 - surfShade.glass.rhoIR * RhoShIR);
    1530              : 
    1531              :             } // End of check if interior shade or interior blind
    1532              :         }     // End of surface loop
    1533              : 
    1534          942 :         for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
    1535          832 :             auto const &surf = s_surf->Surface(SurfNum);
    1536          832 :             if (surf.Construction <= 0) continue;
    1537          816 :             auto const &construct = state.dataConstruction->Construct(surf.Construction);
    1538          816 :             if (!construct.TypeIsWindow) continue;
    1539              : 
    1540              :             // Total thickness of glazing system (used in calculation of inside reveal reflection/absorption
    1541           52 :             s_surf->SurfWinTotGlazingThickness(SurfNum) = 0.0;
    1542          164 :             for (int LayNum = 1; LayNum <= construct.TotLayers; ++LayNum) {
    1543          112 :                 s_surf->SurfWinTotGlazingThickness(SurfNum) += s_mat->materials(construct.LayerPoint(LayNum))->Thickness;
    1544              :             }
    1545              :             // Sine and cosine of azimuth and tilt
    1546              :             //    SurfaceWindow(SurfNum)%SinAzim = Surface(SurfNum)%SinAzim
    1547              :             //    SurfaceWindow(SurfNum)%CosAzim = Surface(SurfNum)%CosAzim
    1548              :             //    SurfaceWindow(SurfNum)%SinTilt = Surface(SurfNum)%SinTilt
    1549              :             //    SurfaceWindow(SurfNum)%CosTilt = Surface(SurfNum)%CosTilt
    1550              :             //    ! Outward normal unit vector (pointing away from room)
    1551              :             //    SurfaceWindow(SurfNum)%OutNormVec(1) = Surface(SurfNum)%OutNormVec(1)
    1552              :             //    SurfaceWindow(SurfNum)%OutNormVec(2) = Surface(SurfNum)%OutNormVec(2)
    1553              :             //    SurfaceWindow(SurfNum)%OutNormVec(3) = Surface(SurfNum)%OutNormVec(3)
    1554              :             //    write(outputfiledebug,*) 'window='//TRIM(surface(SurfNum)%name)
    1555              :             //    write(outputfiledebug,*) '  swindow%outnormvec=',surfacewindow(SurfNum)%outnormvec
    1556              :             //    write(outputfiledebug,*) '  surface%outnormvec=',surface(SurfNum)%outnormvec
    1557              :             // Window center
    1558           52 :             Rectangle = false;
    1559           52 :             Triangle = false;
    1560           52 :             if (surf.Sides == 3) Triangle = true;
    1561           52 :             if (surf.Sides == 4) Rectangle = true;
    1562           52 :             if (Rectangle) {
    1563              :                 // Vertices of window (numbered counter-clockwise starting at upper left as viewed from inside of room).
    1564              :                 // Assumes original vertices are numbered counter-clockwise from upper left as viewed from outside.
    1565           52 :                 W3 = surf.Vertex(2);
    1566           52 :                 W2 = surf.Vertex(3);
    1567           52 :                 W1 = surf.Vertex(4);
    1568            0 :             } else if (Triangle) {
    1569            0 :                 W3 = surf.Vertex(2);
    1570            0 :                 W2 = surf.Vertex(3);
    1571            0 :                 W1 = surf.Vertex(1);
    1572              :             }
    1573           52 :             W21 = W1 - W2;
    1574           52 :             W23 = W3 - W2;
    1575           52 :             if (Rectangle) {
    1576           52 :                 s_surf->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 2.0;
    1577            0 :             } else if (Triangle) {
    1578            0 :                 s_surf->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 3.0;
    1579              :             }
    1580              :         } // End of surface loop
    1581              : 
    1582          110 :         ReportGlass(state);
    1583          110 :     } // InitGlassOpticalCalculations()
    1584              : 
    1585              :     //*****************************************************************************************
    1586              : 
    1587          111 :     void W5InitGlassParameters(EnergyPlusData &state)
    1588              :     {
    1589              :         // Initializes variables used in the window optical and thermal calculation.
    1590              : 
    1591              :         Real64 FrWidth;       // Window frame width {m}
    1592              :         Real64 FrEdgeWidth;   // Frame edge width {m}
    1593              :         Real64 DivWidth;      // Window divider width {m}
    1594              :         Real64 DivEdgeWidth;  // Divider edge width {m}
    1595              :         Real64 GlHeight;      // Height of glazed part of window {m}
    1596              :         Real64 GlWidth;       // Width of glazed part of window {m}
    1597              :         int NumHorDividers;   // Number of horizontal divider elements
    1598              :         int NumVertDividers;  // Number of vertical divider elements
    1599              :         int DifOverrideCount; // Count the number of SolarDiffusing material overrides
    1600              : 
    1601          111 :         auto &s_mat = state.dataMaterial;
    1602          111 :         auto &s_surf = state.dataSurface;
    1603              : 
    1604          435 :         for (auto &constr : state.dataConstruction->Construct) {
    1605          324 :             if (constr.FromWindow5DataFile) continue;
    1606          324 :             if (constr.WindowTypeBSDF) continue;
    1607          323 :             constr.TransDiff = 0.0;
    1608          323 :             constr.TransDiffVis = 0.0;
    1609          323 :             constr.AbsDiffBackShade = 0.0;
    1610          323 :             constr.ShadeAbsorpThermal = 0.0;
    1611          323 :             constr.ReflectSolDiffBack = 0.0;
    1612          323 :             constr.ReflectSolDiffFront = 0.0;
    1613          323 :             constr.ReflectVisDiffFront = 0.0;
    1614              : 
    1615          323 :             std::fill(constr.AbsBeamShadeCoef.begin(), constr.AbsBeamShadeCoef.end(), 0.0);
    1616          323 :             std::fill(constr.TransSolBeamCoef.begin(), constr.TransSolBeamCoef.end(), 0.0);
    1617          323 :             std::fill(constr.ReflSolBeamFrontCoef.begin(), constr.ReflSolBeamFrontCoef.end(), 0.0);
    1618          323 :             std::fill(constr.ReflSolBeamBackCoef.begin(), constr.ReflSolBeamBackCoef.begin(), 0.0);
    1619          323 :             std::fill(constr.TransVisBeamCoef.begin(), constr.TransVisBeamCoef.end(), 0.0);
    1620          323 :             constr.AbsDiff = 0.0;
    1621          323 :             constr.AbsDiffBack = 0.0;
    1622         2512 :             for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
    1623        15323 :                 for (int index = 0; index < maxPolyCoef; ++index) {
    1624        13134 :                     state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamCoef(Layer)[index] = 0.0;
    1625        13134 :                     state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamBackCoef(Layer)[index] = 0.0;
    1626              :                 }
    1627              :             }
    1628              :         }
    1629              : 
    1630              :         // Set some static exterior-window frame and divider SurfaceWindow values
    1631              :         // from values in FrameDivider derived type
    1632          945 :         for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
    1633          834 :             auto const &surf = s_surf->Surface(SurfNum);
    1634          834 :             if (surf.FrameDivider == 0) continue;
    1635              : 
    1636            7 :             auto &surfWin = s_surf->SurfaceWindow(SurfNum);
    1637            7 :             auto const &frdiv = s_surf->FrameDivider(surf.FrameDivider);
    1638              : 
    1639            7 :             FrWidth = frdiv.FrameWidth;
    1640            7 :             GlHeight = surf.Height;
    1641            7 :             GlWidth = surf.Width;
    1642            7 :             NumVertDividers = frdiv.VertDividers;
    1643            7 :             NumHorDividers = frdiv.HorDividers;
    1644            7 :             s_surf->SurfWinFrameConductance(SurfNum) = frdiv.FrameConductance;
    1645            7 :             s_surf->SurfWinFrameSolAbsorp(SurfNum) = frdiv.FrameSolAbsorp;
    1646            7 :             s_surf->SurfWinFrameVisAbsorp(SurfNum) = frdiv.FrameVisAbsorp;
    1647            7 :             s_surf->SurfWinFrameEmis(SurfNum) = frdiv.FrameEmis;
    1648            7 :             s_surf->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) = frdiv.FrEdgeToCenterGlCondRatio;
    1649            7 :             s_surf->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::DividedLite;
    1650            7 :             if (frdiv.DividerType == DataSurfaces::FrameDividerType::Suspended)
    1651            0 :                 s_surf->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::Suspended;
    1652            7 :             DivWidth = frdiv.DividerWidth;
    1653            7 :             s_surf->SurfWinDividerConductance(SurfNum) = frdiv.DividerConductance;
    1654            7 :             s_surf->SurfWinDividerSolAbsorp(SurfNum) = frdiv.DividerSolAbsorp;
    1655            7 :             s_surf->SurfWinDividerVisAbsorp(SurfNum) = frdiv.DividerVisAbsorp;
    1656            7 :             s_surf->SurfWinDividerEmis(SurfNum) = frdiv.DividerEmis;
    1657            7 :             s_surf->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) = frdiv.DivEdgeToCenterGlCondRatio;
    1658              : 
    1659            7 :             s_surf->SurfWinOutsideRevealSolAbs(SurfNum) = frdiv.OutsideRevealSolAbs;
    1660            7 :             s_surf->SurfWinInsideSillDepth(SurfNum) = frdiv.InsideSillDepth;
    1661            7 :             s_surf->SurfWinInsideReveal(SurfNum) = frdiv.InsideReveal;
    1662            7 :             s_surf->SurfWinInsideSillSolAbs(SurfNum) = frdiv.InsideSillSolAbs;
    1663            7 :             s_surf->SurfWinInsideRevealSolAbs(SurfNum) = frdiv.InsideRevealSolAbs;
    1664              : 
    1665            7 :             FrEdgeWidth = frdiv.FrameEdgeWidth;
    1666            7 :             DivEdgeWidth = frdiv.DividerEdgeWidth;
    1667            7 :             s_surf->SurfWinFrameEdgeArea(SurfNum) =
    1668            7 :                 2 * FrEdgeWidth * (GlHeight - FrEdgeWidth - NumHorDividers * DivWidth + GlWidth - FrEdgeWidth - NumVertDividers * DivWidth);
    1669            7 :             s_surf->SurfWinDividerEdgeArea(SurfNum) =
    1670           14 :                 2 * DivEdgeWidth * (NumHorDividers * (GlWidth - 2 * FrEdgeWidth) + NumVertDividers * (GlHeight - 2 * FrEdgeWidth)) -
    1671            7 :                 NumHorDividers * NumVertDividers * (4 * pow_2(DivEdgeWidth) + 4 * FrEdgeWidth * DivWidth);
    1672            7 :             surfWin.centerGlassArea = surf.Area - s_surf->SurfWinFrameEdgeArea(SurfNum) - s_surf->SurfWinDividerEdgeArea(SurfNum);
    1673            7 :             surfWin.edgeGlassCorrFac =
    1674            7 :                 (s_surf->SurfWinFrameEdgeArea(SurfNum) * s_surf->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) +
    1675            7 :                  s_surf->SurfWinDividerEdgeArea(SurfNum) * s_surf->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) + surfWin.centerGlassArea) /
    1676            7 :                 (s_surf->SurfWinFrameEdgeArea(SurfNum) + s_surf->SurfWinDividerEdgeArea(SurfNum) + surfWin.centerGlassArea);
    1677              :         } // for (SurfNum)
    1678              : 
    1679              :         // Set SolarDiffusing to true for exterior windows that have a construction with an innermost diffusing glass layer
    1680          111 :         DifOverrideCount = 0;
    1681          945 :         for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
    1682          834 :             auto const &surf = s_surf->Surface(SurfNum);
    1683          834 :             s_surf->SurfWinSolarDiffusing(SurfNum) = false;
    1684          834 :             if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != ExternalEnvironment || s_surf->SurfWinStormWinConstr(SurfNum) != 0)
    1685          780 :                 continue;
    1686              : 
    1687           54 :             int ConstrNum = surf.Construction;
    1688           54 :             int MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
    1689           54 :             auto const *mat = s_mat->materials(MatNum);
    1690           54 :             if (mat->group != Material::Group::Glass) continue;
    1691              : 
    1692           30 :             if (!dynamic_cast<Material::MaterialGlass const *>(mat)->SolarDiffusing) continue;
    1693              : 
    1694            0 :             if (!surf.HasShadeControl) {
    1695            0 :                 s_surf->SurfWinSolarDiffusing(SurfNum) = true;
    1696              :                 // There is a shading control
    1697            0 :             } else if (s_surf->WindowShadingControl(surf.activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) {
    1698            0 :                 s_surf->SurfWinSolarDiffusing(SurfNum) = true;
    1699              :             } else {
    1700            0 :                 s_surf->SurfWinSolarDiffusing(SurfNum) = false;
    1701            0 :                 ++DifOverrideCount;
    1702            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    1703            0 :                     ShowWarningError(state,
    1704            0 :                                      format("W5InitGlassParameters: Window=\"{}\" has interior material with Solar Diffusing=Yes, but "
    1705              :                                             "existing Window Shading Device sets Diffusing=No.",
    1706            0 :                                             surf.Name));
    1707              :                 }
    1708              :             }
    1709              :         } // for (SurfNum)
    1710              : 
    1711          111 :         if (DifOverrideCount > 0) {
    1712            0 :             if (!state.dataGlobal->DisplayExtraWarnings) {
    1713            0 :                 ShowWarningError(state,
    1714            0 :                                  format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
    1715              :                                         DifOverrideCount));
    1716              :             } else {
    1717            0 :                 ShowMessage(state,
    1718            0 :                             format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
    1719              :                                    DifOverrideCount));
    1720              :             }
    1721              :         }
    1722          111 :     } // W5InitGlassParameters()
    1723              : 
    1724              :     //****************************************************************************
    1725              :     // WINDOW 5 Optical Calculation Subroutines
    1726              :     //****************************************************************************
    1727              : 
    1728         1020 :     void SystemSpectralPropertiesAtPhi(EnergyPlusData &state,
    1729              :                                        int const iquasi,   // When there is no spectral data, this is the wavelength
    1730              :                                        int const ngllayer, // Number of glass layers in construction
    1731              :                                        Real64 const wlbot, // Lowest and highest wavelength considered
    1732              :                                        Real64 const wltop,
    1733              :                                        std::array<int, maxGlassLayers> const &numpt,
    1734              :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &wlt,
    1735              :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &tPhi,
    1736              :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rfPhi,
    1737              :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rbPhi,
    1738              :                                        std::array<Real64, nume> &stPhi,
    1739              :                                        std::array<Real64, nume> &srfPhi,
    1740              :                                        std::array<Real64, nume> &srbPhi,
    1741              :                                        Array2D<Real64> &saPhi)
    1742              :     {
    1743              : 
    1744              :         // SUBROUTINE INFORMATION:
    1745              :         //       AUTHOR         Adapted by F.Winkelmann from WINDOW 5
    1746              :         //                      subroutine opcalc
    1747              :         //       DATE WRITTEN   August 1999
    1748              :         //       MODIFIED       na
    1749              :         //       RE-ENGINEERED  na
    1750              : 
    1751              :         // PURPOSE OF THIS SUBROUTINE:
    1752              :         // For a particular angle of incidence, calculates system properties
    1753              :         // for a multi-layer glazing for each wavelength in the solar spectrum.
    1754              :         // Handles the special case of one or more layers that do not have spectral data.
    1755              : 
    1756              :         // Returns, for a particular angle of incidence:
    1757              :         //   stPhi     transmissivity of system at each wavelength in swl
    1758              :         //   srfPhi    front reflectance of system at each wavelength in swl
    1759              :         //   srbPhi    back reflectance of system at each wavelength in swl
    1760              :         //   sabsPhi   absorptance by layer at each wavelength in swl
    1761              : 
    1762         1020 :         Array1D<Real64> sabsPhi(5); // System solar absorptance in each glass layer for
    1763              :         //   particular angle of incidence
    1764              : 
    1765              :         // transmittance at angle of incidence
    1766         1020 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tadjPhi = {0.0};
    1767              :         // front reflectance at angle of incidence
    1768         1020 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfadjPhi = {0.0};
    1769              :         // back reflectance at angle of incidence
    1770         1020 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbadjPhi = {0.0};
    1771              : 
    1772         1020 :         auto const &wm = state.dataWindowManager;
    1773              :         // For each glass layer find tPhi, rfPhi, and rbPhi at each wavelength
    1774              : 
    1775         2310 :         for (int in = 1; in <= ngllayer; ++in) {
    1776       139320 :             for (int iwl = 1; iwl <= nume; ++iwl) {
    1777       138030 :                 Real64 wl = wm->wle[iwl - 1];
    1778       138030 :                 if (wl < wlbot || wl > wltop) continue;
    1779              :                 // In the following numpt is the number of spectral data points for each layer;
    1780              :                 // numpt = 2 if there is no spectral data for a layer.
    1781       109950 :                 if (numpt[in - 1] <= 2) {
    1782        97110 :                     tadjPhi[in - 1][iwl - 1] = tPhi[in - 1][iquasi - 1];
    1783        97110 :                     rfadjPhi[in - 1][iwl - 1] = rfPhi[in - 1][iquasi - 1];
    1784        97110 :                     rbadjPhi[in - 1][iwl - 1] = rbPhi[in - 1][iquasi - 1];
    1785              :                 } else {
    1786              :                     // Interpolate to get properties at the solar spectrum wavelengths
    1787        12840 :                     tadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], tPhi[in - 1], numpt[in - 1], wl);
    1788        12840 :                     rfadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rfPhi[in - 1], numpt[in - 1], wl);
    1789        12840 :                     rbadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rbPhi[in - 1], numpt[in - 1], wl);
    1790              :                 }
    1791              :             }
    1792              :         }
    1793              : 
    1794              :         // Calculate system properties at each wavelength
    1795       110160 :         for (int j = 1; j <= nume; ++j) {
    1796       109140 :             Real64 wl = wm->wle[j - 1];
    1797       109140 :             if (wl < wlbot || wl > wltop) continue;
    1798              : 
    1799              :             // Set diagonal of matrix for subroutine SystemPropertiesAtLambdaAndPhi
    1800       196050 :             for (int i = 1; i <= ngllayer; ++i) {
    1801       109950 :                 wm->top[i - 1][i - 1] = tadjPhi[i - 1][j - 1];
    1802       109950 :                 wm->rfop[i - 1][i - 1] = rfadjPhi[i - 1][j - 1];
    1803       109950 :                 wm->rbop[i - 1][i - 1] = rbadjPhi[i - 1][j - 1];
    1804              :             }
    1805              : 
    1806              :             // Calculate glazing system properties
    1807        86100 :             if (ngllayer == 1) { // Single-layer system
    1808        62250 :                 stPhi[j - 1] = wm->top[0][0];
    1809        62250 :                 srfPhi[j - 1] = wm->rfop[0][0];
    1810        62250 :                 srbPhi[j - 1] = wm->rbop[0][0];
    1811        62250 :                 sabsPhi(1) = 1.0 - stPhi[j - 1] - srfPhi[j - 1];
    1812              :             } else { // Multilayer system
    1813              :                 // Get glazing system properties stPhi, etc., at this wavelength and incidence angle
    1814        23850 :                 SystemPropertiesAtLambdaAndPhi(state, ngllayer, stPhi[j - 1], srfPhi[j - 1], srbPhi[j - 1], sabsPhi);
    1815              :             }
    1816              : 
    1817       196050 :             for (int i = 1; i <= ngllayer; ++i) {
    1818       109950 :                 saPhi(i, j) = sabsPhi(i);
    1819              :             }
    1820              : 
    1821              :         } // End of wavelength loop
    1822         1020 :     }     // SystemSpectralPropertiesAtPhi()
    1823              : 
    1824              :     //************************************************************************
    1825              : 
    1826        23850 :     void SystemPropertiesAtLambdaAndPhi(EnergyPlusData &state,
    1827              :                                         int const n, // Number of glass layers
    1828              :                                         Real64 &tt,  // System transmittance
    1829              :                                         Real64 &rft, // System front and back reflectance
    1830              :                                         Real64 &rbt,
    1831              :                                         Array1A<Real64> aft // System absorptance of each glass layer
    1832              :     )
    1833              :     {
    1834              : 
    1835              :         // SUBROUTINE INFORMATION:
    1836              :         //       AUTHOR         Adapted by F. Winkelmann from WINDOW 5
    1837              :         //                      subroutine op
    1838              :         //       DATE WRITTEN   August 1999
    1839              :         //       MODIFIED       na
    1840              :         //       RE-ENGINEERED  na
    1841              : 
    1842              :         // PURPOSE OF THIS SUBROUTINE:
    1843              :         // For a given angle of incidence, finds the overall properties of
    1844              :         // of a series of layers at a particular wavelength
    1845              : 
    1846              :         // Argument array dimensioning
    1847        23850 :         aft.dim(5);
    1848              : 
    1849              :         Real64 denom; // Intermediate variables
    1850              :         Real64 denom1;
    1851              :         Real64 denom2;
    1852              :         Real64 t0; // Transmittance, back reflectance and front
    1853              :         Real64 rb0;
    1854              :         Real64 rf0;
    1855              :         //   reflectance variables
    1856              :         Real64 af; // Front and back absorptance variables
    1857              :         Real64 ab;
    1858              : 
    1859        23850 :         auto &wm = state.dataWindowManager;
    1860              :         // Calculate perimeter elements of rt matrix
    1861        47700 :         for (int i = 1; i <= n - 1; ++i) {
    1862        47700 :             for (int j = i + 1; j <= n; ++j) {
    1863        23850 :                 denom = 1.0 - wm->rfop[j - 1][j - 1] * wm->rbop[i - 1][j - 2];
    1864        23850 :                 if (denom == 0.0) {
    1865          148 :                     wm->top[j - 1][i - 1] = 0.0;
    1866          148 :                     wm->rfop[j - 1][i - 1] = 1.0;
    1867          148 :                     wm->rbop[i - 1][j - 1] = 1.0;
    1868              :                 } else {
    1869        23702 :                     wm->top[j - 1][i - 1] = wm->top[j - 2][i - 1] * wm->top[j - 1][j - 1] / denom;
    1870        23702 :                     wm->rfop[j - 1][i - 1] = wm->rfop[j - 2][i - 1] + pow_2(wm->top[j - 2][i - 1]) * wm->rfop[j - 1][j - 1] / denom;
    1871        23702 :                     wm->rbop[i - 1][j - 1] = wm->rbop[j - 1][j - 1] + pow_2(wm->top[j - 1][j - 1]) * wm->rbop[i - 1][j - 2] / denom;
    1872              :                 }
    1873              :             }
    1874              :         }
    1875              :         // System properties: transmittance, front and back reflectance
    1876        23850 :         tt = wm->top[n - 1][0];
    1877        23850 :         rft = wm->rfop[n - 1][0];
    1878        23850 :         rbt = wm->rbop[0][n - 1];
    1879              : 
    1880              :         // Absorptance in each layer
    1881        71550 :         for (int j = 1; j <= n; ++j) {
    1882        47700 :             if (j == 1) {
    1883        23850 :                 t0 = 1.0;
    1884        23850 :                 rb0 = 0.0;
    1885              :             } else {
    1886        23850 :                 t0 = wm->top[j - 2][0];
    1887        23850 :                 rb0 = wm->rbop[0][j - 2];
    1888              :             }
    1889              : 
    1890        47700 :             if (j == n) {
    1891        23850 :                 rf0 = 0.0;
    1892              :             } else {
    1893        23850 :                 rf0 = wm->rfop[n - 1][j];
    1894              :             }
    1895              : 
    1896        47700 :             af = 1.0 - wm->top[j - 1][j - 1] - wm->rfop[j - 1][j - 1];
    1897        47700 :             ab = 1.0 - wm->top[j - 1][j - 1] - wm->rbop[j - 1][j - 1];
    1898        47700 :             denom1 = 1.0 - wm->rfop[n - 1][j - 1] * rb0;
    1899        47700 :             denom2 = 1.0 - wm->rbop[0][j - 1] * rf0;
    1900              : 
    1901        47700 :             if (denom1 == 0.0 || denom2 == 0.0) {
    1902          296 :                 aft(j) = 0.0;
    1903              :             } else {
    1904        47404 :                 aft(j) = (t0 * af) / denom1 + (wm->top[j - 1][0] * rf0 * ab) / denom2;
    1905              :             }
    1906              :         }
    1907        23850 :     } // SystemPropertiesAtLambdaAndPhi()
    1908              : 
    1909         1950 :     Real64 solarSpectrumAverage(EnergyPlusData const &state, gsl::span<Real64 const> p)
    1910              :     {
    1911         1950 :         Real64 num = 0.0;
    1912         1950 :         Real64 denom = 0.0;
    1913         1950 :         auto const &wm = state.dataWindowManager;
    1914              : 
    1915       208650 :         for (int i = 1; i <= nume - 1; ++i) {
    1916       206700 :             Real64 const esol = (wm->wle[i] - wm->wle[i - 1]) * 0.5 * (wm->e[i - 1] + wm->e[i]);
    1917       206700 :             num += 0.5 * (p[i - 1] + p[i]) * esol;
    1918       206700 :             denom += esol;
    1919              :         }
    1920         1950 :         return num / denom; // dangerous, doesn't check for zero denominator
    1921              :     }
    1922              : 
    1923         1050 :     Real64 visibleSpectrumAverage(EnergyPlusData const &state, gsl::span<Real64 const> p)
    1924              :     {
    1925              :         //       AUTHOR         Adapted by F.Winkelmann from WINDOW 5
    1926              :         //                      subroutine w4vis
    1927              :         //       DATE WRITTEN   August 1999
    1928              : 
    1929              :         // Calculates visible average of property p by weighting with solar
    1930              :         // spectral irradiance, e, and photopic response, y30
    1931              : 
    1932         1050 :         Real64 num = 0.0;
    1933         1050 :         Real64 denom = 0.0;
    1934         1050 :         Real64 y30new = 0.0;
    1935         1050 :         Real64 y30ils1 = 0.0;
    1936              : 
    1937         1050 :         auto const &wm = state.dataWindowManager;
    1938              : 
    1939       112350 :         for (int i = 2; i <= nume; ++i) { // Autodesk:BoundsViolation e|wle|p(i-1) @ i=1: Changed start index from 1 to 2: wle
    1940              :             // values prevented this violation from occurring in practice
    1941              :             // Restrict to visible range
    1942       111300 :             if (wm->wle[i - 1] >= 0.37 && wm->wle[i - 1] <= 0.78) {
    1943        36750 :                 y30new = Interpolate(wm->wlt3, wm->y30, numt3, wm->wle[i - 1]);
    1944        36750 :                 Real64 evis = wm->e[i - 2] * 0.5 * (y30new + y30ils1) * (wm->wle[i - 1] - wm->wle[i - 2]);
    1945        36750 :                 num += 0.5 * (p[i - 1] + p[i - 2]) * evis;
    1946        36750 :                 denom += evis;
    1947        36750 :                 y30ils1 = y30new;
    1948              :             }
    1949              :         }
    1950         1050 :         return num / denom; // dangerous, doesn't check for zero denominator
    1951              :     }
    1952              : 
    1953        75270 :     Real64 Interpolate(gsl::span<Real64 const> x, // Array of data points for independent variable
    1954              :                        gsl::span<Real64 const> y, // Array of data points for dependent variable
    1955              :                        int const npts,            // Number of data pairs
    1956              :                        Real64 const xin           // Given value of x
    1957              :     )
    1958              :     {
    1959              : 
    1960              :         // SUBROUTINE INFORMATION:
    1961              :         //       AUTHOR         Adapted by F.Winkelmann from WINDOW 5 subroutine interp
    1962              :         //       DATE WRITTEN   August 1999
    1963              :         //       MODIFIED       na
    1964              :         //       RE-ENGINEERED  na
    1965              : 
    1966              :         // PURPOSE OF THIS SUBROUTINE:
    1967              :         // Linearly interpolates between data points. Outputs yout, interpolated
    1968              :         // value of y corresponding to xin
    1969              : 
    1970      4660920 :         for (int i = 1; i <= npts; ++i) {
    1971      4660680 :             if (xin <= x[i - 1]) {
    1972        75030 :                 if (i - 1 == 0) {
    1973         2460 :                     return y[0];
    1974              :                 } else {
    1975        72570 :                     return y[i - 2] + (y[i - 1] - y[i - 2]) * (xin - x[i - 2]) / (x[i - 1] - x[i - 2]);
    1976              :                 }
    1977              :             }
    1978              :         }
    1979              : 
    1980              :         // Past the end of the array, so return endpoint
    1981          240 :         return y[npts - 1];
    1982              :     }
    1983              : 
    1984              :     //***********************************************************************************
    1985              :     // Window Thermal Calculation Subroutines
    1986              :     //***********************************************************************************
    1987              : 
    1988        88568 :     void CalcWindowHeatBalance(EnergyPlusData &state,
    1989              :                                int const SurfNum,          // Surface number
    1990              :                                Real64 const HextConvCoeff, // Outside air film conductance coefficient
    1991              :                                Real64 &SurfInsideTemp,     // Inside window surface temperature
    1992              :                                Real64 &SurfOutsideTemp     // Outside surface temperature (C)
    1993              :     )
    1994              :     {
    1995              :         // SUBROUTINE INFORMATION:
    1996              :         //       AUTHOR         S. Vidanovic
    1997              :         //       DATE WRITTEN   June 2016
    1998              :         //       MODIFIED       na
    1999              :         //       RE-ENGINEERED  na
    2000              :         //
    2001              :         // PURPOSE OF THIS SUBROUTINE:
    2002              :         // Subroutine to direct whether to use exterior or interior window routines
    2003        88568 :         auto const &wm = state.dataWindowManager;
    2004              : 
    2005        88568 :         if (state.dataGlobal->KickOffSizing || state.dataGlobal->KickOffSimulation) return;
    2006              : 
    2007        88247 :         if (wm->inExtWindowModel->isExternalLibraryModel()) {
    2008            0 :             CalcWindowHeatBalanceExternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
    2009              :         } else {
    2010        88247 :             CalcWindowHeatBalanceInternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
    2011              :         }
    2012              :     }
    2013              : 
    2014        88247 :     void CalcWindowHeatBalanceInternalRoutines(EnergyPlusData &state,
    2015              :                                                int const SurfNum,          // Surface number
    2016              :                                                Real64 const HextConvCoeff, // Outside air film conductance coefficient
    2017              :                                                Real64 &SurfInsideTemp,     // Inside window surface temperature
    2018              :                                                Real64 &SurfOutsideTemp     // Outside surface temperature (C)
    2019              :     )
    2020              :     {
    2021              : 
    2022              :         // SUBROUTINE INFORMATION:
    2023              :         //       AUTHOR         F. Winkelmann
    2024              :         //       DATE WRITTEN   November 1999
    2025              :         //       MODIFIED       FW, July 2000 (call better solution method)
    2026              :         //                      FW, June 2001 (handle window blinds)
    2027              :         //                      FW, Dec  2002 (add between-glass shades and blinds)
    2028              :         //                      FW, Mar  2003 (extend condensation flag to airflow windows)
    2029              :         //                      CC, Jul  2003 (set the reference temperatures for inside surface heat balance
    2030              :         //                                    depending on convection algorithms and/or air models used)
    2031              :         //                      FW, Sep  2003 (increment ZoneWinHeatGain only for exterior windows)
    2032              :         //                      RR, May  2006 (add exterior window screen)
    2033              :         //                      TH, Dec  2008 (add thermochromic windows)
    2034              :         //       RE-ENGINEERED  na
    2035              : 
    2036              :         // PURPOSE OF THIS SUBROUTINE:
    2037              :         // Sets up information needed to calculate the window thermal behavior.
    2038              :         // Calls SolveForWindowTemperatures, which calculates the inside and outside
    2039              :         // face temperature of each glass layer by solving the heat balance
    2040              :         // equations on each face. Also calls CalcWinFrameAndDividerTemps,
    2041              :         // which calculates the outside and inside face temperatures of the
    2042              :         // window frame and divider if either of these are present.
    2043              :         // The resulting inside face temperature of the inner glass pane and the
    2044              :         // inside surface temperatures of frame and divider are used in the zone
    2045              :         // heat balance calculation. The inside face temperature of an interior shade
    2046              :         // or blind, if present, and the natural convection air flow between the
    2047              :         // shade/blind and inside glass face also appear in the zone heat balance calculation.
    2048              :         // The logical variable NRSolution is currently set to false, which means
    2049              :         // that the Newton-Raphson solution method for the glass layer heat balance
    2050              :         // is not used (because it sometimes didn't converge for 3- and 4-pane
    2051              :         // constructions with one or more low-emissivity layers). Instead, a more
    2052              :         // robust solution method is used that successively solves linearized heat
    2053              :         // balance equations until convergence is reached (see SolveForWindowTemperatures).
    2054              :         // CalcWindowHeatBalance is called by CalcHeatBalanceInsideSurface once each
    2055              :         // time step for each window.
    2056              : 
    2057              :         // Using/Aliasing
    2058              :         using namespace DataBSDFWindow;
    2059              : 
    2060              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    2061              :         // (temperature of innermost face) [C]
    2062              : 
    2063              :         int SurfNumAdj; // An interzone surface's number in the adjacent zone
    2064              :         //   (sum of solid layers and gap layers)
    2065              :         int TotGlassLay;          // Total number of glass layers in a construction
    2066              :         int LayPtr;               // Material number for a layer
    2067              :         WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position
    2068              :         // REAL(r64) :: tsky                         ! Sky temperature [K]
    2069              :         int ShadeLayPtr; // Material number corresponding to a shade layer
    2070              :         Real64 dth1;     // Temperature difference across glass layers [K]
    2071              :         Real64 dth2;
    2072              :         Real64 dth3;
    2073              :         Real64 dth4;
    2074              :         Real64 EffShBlEmiss;    // Effective interior shade or blind emissivity
    2075              :         Real64 EffGlEmiss;      // Effective inside glass emissivity when interior shade or blind
    2076              :         Real64 RoomHumRat;      // Room air humidity ratio
    2077              :         Real64 RoomDewPoint;    // Room air dewpoint temperature (C)
    2078              :         Real64 InsideGlassTemp; // Temperature of room side of innermost glass layer (C)
    2079              :         Real64 Tleft;           // For airflow windows, temperature of the glass faces adjacent
    2080              :         Real64 Tright;
    2081              : 
    2082              :         Real64 SrdSurfTempAbs; // Absolute temperature of a surrounding surface
    2083              :         Real64 OutSrdIR;       // LWR from surrounding srfs
    2084              : 
    2085              :         // New variables for thermochromic windows calc
    2086              :         Real64 locTCSpecTemp;  // The temperature corresponding to the specified optical properties of the TC layer
    2087              :         Real64 locTCLayerTemp; // TC layer temperature at each time step. C
    2088              : 
    2089        88247 :         auto &s_mat = state.dataMaterial;
    2090        88247 :         auto &s_surf = state.dataSurface;
    2091        88247 :         auto &wm = state.dataWindowManager;
    2092              : 
    2093              :         Real64 SurfOutsideEmiss; // temporary for result of outside surface emissivity
    2094              :         Real64 Tsout;            // temporary for result of outside surface temp in Kelvin
    2095              : 
    2096              :         // Shorthand references
    2097        88247 :         auto &surf = s_surf->Surface(SurfNum);
    2098        88247 :         auto &surfWin = s_surf->SurfaceWindow(SurfNum);
    2099        88247 :         int ConstrNum = s_surf->SurfActiveConstruction(SurfNum);
    2100        88247 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(surf.Zone);
    2101              : 
    2102        88247 :         if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) {
    2103              : 
    2104            0 :             int temp = 0;
    2105              : 
    2106              :             // Simon: Complex fenestration state works only with tarcog
    2107            0 :             WindowComplexManager::CalcComplexWindowThermal(
    2108              :                 state, SurfNum, temp, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
    2109              : 
    2110            0 :             auto const &constr = state.dataConstruction->Construct(ConstrNum);
    2111            0 :             wm->ngllayer = constr.TotSolidLayers; // Simon: This is necessary to keep for frame calculations
    2112              :             // Simon: need to transfer surface temperatures because of frames calculation
    2113              : 
    2114            0 :             for (int i = 1; i <= 2 * constr.TotSolidLayers; ++i) {
    2115            0 :                 wm->thetas[i - 1] = surfWin.thetaFace[i];
    2116              :             }
    2117            0 :             wm->hcout = HextConvCoeff;
    2118            0 :             wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
    2119            0 :             wm->tin = thisZoneHB.MAT + Constant::Kelvin; // Inside air temperature
    2120              : 
    2121              :             // This is code repeating and it is necessary to calculate report variables.  Do not know
    2122              :             // how to solve this in more elegant way :(
    2123            0 :             if (surf.ExtWind) {                // Window is exposed to wind (and possibly rain)
    2124            0 :                 if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
    2125            0 :                     wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
    2126              :                 } else { // Dry
    2127            0 :                     wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2128              :                 }
    2129              :             } else { // Window not exposed to wind
    2130            0 :                 wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2131              :             }
    2132              : 
    2133            0 :             wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
    2134            0 :             wm->Outir =
    2135            0 :                 surf.ViewFactorSkyIR * (s_surf->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
    2136            0 :                                         (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
    2137            0 :                 surf.ViewFactorGroundIR * wm->Ebout;
    2138              : 
    2139        88247 :         } else if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::EQL) {
    2140              : 
    2141         2352 :             WindowEquivalentLayer::EQLWindowSurfaceHeatBalance(
    2142              :                 state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
    2143         2352 :             wm->hcout = HextConvCoeff;
    2144              :             // Required for report variables calculations.
    2145         2352 :             if (surf.ExtWind) {                // Window is exposed to wind (and possibly rain)
    2146         2352 :                 if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
    2147            0 :                     wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
    2148              :                 } else { // Dry
    2149         2352 :                     wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2150              :                 }
    2151              :             } else { // Window not exposed to wind
    2152            0 :                 wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2153              :             }
    2154              : 
    2155              :         } else { // regular window, not BSDF, not EQL Window
    2156              :             // Added for thermochromic windows
    2157        85895 :             auto const &constr = state.dataConstruction->Construct(ConstrNum);
    2158        85895 :             wm->locTCFlag = (constr.isTCWindow);
    2159              : 
    2160        85895 :             if (wm->locTCFlag) {
    2161            0 :                 locTCSpecTemp = constr.specTemp;
    2162            0 :                 s_surf->SurfWinSpecTemp(SurfNum) = locTCSpecTemp;
    2163              :                 // Check to see whether needs to switch to a new TC window construction
    2164            0 :                 locTCLayerTemp = s_surf->SurfWinTCLayerTemp(SurfNum);
    2165            0 :                 Real64 dT0 = std::abs(locTCLayerTemp - locTCSpecTemp);
    2166            0 :                 if (dT0 >= 1) {
    2167              : 
    2168              :                     // Find the TC construction that is closed to the TCLayerTemp
    2169            0 :                     auto const &constrTCMaster = state.dataConstruction->Construct(constr.TCMasterConstrNum);
    2170              : 
    2171            0 :                     for (int iTCConstr = 1; iTCConstr <= constrTCMaster.numTCChildConstrs; ++iTCConstr) {
    2172            0 :                         Real64 dT1 = std::abs(locTCLayerTemp - constrTCMaster.TCChildConstrs(iTCConstr).specTemp);
    2173              : 
    2174            0 :                         if (dT1 < dT0) {
    2175            0 :                             surf.Construction = s_surf->SurfActiveConstruction(SurfNum) = constrTCMaster.TCChildConstrs(iTCConstr).constrNum;
    2176            0 :                             s_surf->SurfWinSpecTemp(SurfNum) = constrTCMaster.TCChildConstrs(iTCConstr).specTemp;
    2177            0 :                             dT0 = dT1;
    2178              :                         }
    2179              :                     }
    2180              :                 }
    2181              :             }
    2182              :             // end new TC code
    2183              : 
    2184        85895 :             TotGlassLay = constr.TotGlassLayers;
    2185        85895 :             wm->ngllayer = TotGlassLay;
    2186        85895 :             wm->nglface = 2 * wm->ngllayer;
    2187        85895 :             ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    2188        85895 :             wm->tilt = surf.Tilt;
    2189        85895 :             wm->tiltr = wm->tilt * Constant::DegToRad;
    2190        85895 :             SurfNumAdj = surf.ExtBoundCond;
    2191        85895 :             wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum); // Room-side surface convective film conductance
    2192        85895 :             Real64 RefAirTemp = s_surf->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
    2193        85895 :             state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = RefAirTemp;
    2194        85895 :             wm->tin = RefAirTemp + Constant::Kelvin; // Inside air temperature
    2195              : 
    2196              :             // Reset hcin if necessary since too small a value sometimes causes non-convergence
    2197              :             // of window layer heat balance solution.
    2198        85895 :             if (s_surf->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) {
    2199              :                 // may be redundant now, check is also in HeatBalanceConvectionCoeffs.cc
    2200        85895 :                 if (wm->hcin <= state.dataHeatBal->LowHConvLimit) {
    2201              :                     //  hcin = 3.076d0  !BG this is rather high value and abrupt change. changed to set to lower limit
    2202          101 :                     wm->hcin = state.dataHeatBal->LowHConvLimit;
    2203          101 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = wm->hcin; // store for accurate reporting.
    2204              :                 }
    2205              :             }
    2206              : 
    2207              :             // IR incident on window from zone surfaces and high-temp radiant sources
    2208        85895 :             wm->Rmir = s_surf->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
    2209              : 
    2210              :             // Short-wave radiation (from interior and exterior solar and zone lights)
    2211              :             // absorbed at each face. Assumes equal split between faces of short-wave absorbed in glass layer.
    2212              : 
    2213       195987 :             for (int IGlass = 1; IGlass <= TotGlassLay; ++IGlass) {
    2214       110092 :                 wm->AbsRadGlassFace[2 * IGlass - 2] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
    2215       110092 :                 wm->AbsRadGlassFace[2 * IGlass - 1] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
    2216              :             }
    2217              : 
    2218              :             // IR from zone internal gains (lights, equipment and people) absorbed on zone-side face
    2219              :             // (assumes inside glass layer is opaque to IR, so no contribution to other layers)
    2220        85895 :             wm->AbsRadGlassFace[2 * TotGlassLay - 1] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum);
    2221              : 
    2222              :             // Fill the layer properties needed for the thermal calculation.
    2223              :             // For switchable glazing it is assumed that thermal properties, such
    2224              :             // as surface emissivity, are the same for the unswitched and switched state,
    2225              :             // so the thermal properties of the unswitched state are used.
    2226              :             // For windows with a blind or shade it is assumed
    2227              :             // that the blind or shade does not affect the thermal properties of the glazing,
    2228              :             // so the thermal properties of the construction without the blind or shade are used.
    2229              : 
    2230              :             // The layer and face numbering are as follows (for the triple glazing case):
    2231              :             // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
    2232              :             //   layer and 3 is the inside (room-facing) layer;
    2233              :             // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
    2234              :             //   outside (front) face of glass layer 1, face 2 is the inside (back)
    2235              :             //   face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
    2236              :             //   inner face of glass layer 2, etc.
    2237              :             // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
    2238              :             //   and gap layer 2 is between glass layers 2 and 3.
    2239              :             // If an exterior, interior or between-glass blind or shade is in place, 7 and 8
    2240              :             //   are the blind/shade faces, from outside to inside. If an exterior or interior
    2241              :             //   blind/shade is in place, gap layer 3 is between the blind/shade and adjacent
    2242              :             //   glass layer and is assumed to be air.
    2243              :             // Between-glass blind/shade is modeled only for double and triple glazing.
    2244              :             //   For double glazing, gap 1 is between glass 1 and blind/shade and gap 2 is between
    2245              :             //   blind/shade and glass 2.
    2246              :             //   For triple glazing, the blind/shade is assumed to be between the inner two glass
    2247              :             //   layers, i.e., between glass layers 2 and 3. In this case gap 1 is between glass 1
    2248              :             //   and glass 2, gap 2 is between glass 2 and blind/shade, and gap 3 is between
    2249              :             //   blind/shade and glass 3.
    2250              : 
    2251        85895 :             int IConst = surf.Construction;
    2252        85895 :             if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
    2253            0 :                 IConst = s_surf->SurfWinActiveShadedConstruction(SurfNum);
    2254              :             }
    2255        85895 :             int TotLay = state.dataConstruction->Construct(IConst).TotLayers;
    2256        85895 :             int IGlass = 0;
    2257        85895 :             int IGap = 0;
    2258              : 
    2259              :             // Fill window layer properties needed for window layer heat balance calculation
    2260              : 
    2261       220186 :             for (int Lay = 1; Lay <= TotLay; ++Lay) {
    2262       134291 :                 LayPtr = state.dataConstruction->Construct(IConst).LayerPoint(Lay);
    2263       134291 :                 auto const *mat = s_mat->materials(LayPtr);
    2264              : 
    2265       134291 :                 if (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple) {
    2266       110092 :                     ++IGlass;
    2267       110092 :                     auto const *matGlass = dynamic_cast<Material::MaterialFen const *>(mat);
    2268       110092 :                     assert(matGlass != nullptr);
    2269       110092 :                     wm->thick[IGlass - 1] = matGlass->Thickness;
    2270       110092 :                     wm->scon[IGlass - 1] = matGlass->Conductivity / matGlass->Thickness;
    2271       110092 :                     wm->emis[2 * IGlass - 2] = matGlass->AbsorpThermalFront;
    2272       110092 :                     wm->emis[2 * IGlass - 1] = matGlass->AbsorpThermalBack;
    2273       110092 :                     wm->tir[2 * IGlass - 2] = matGlass->TransThermal;
    2274       110092 :                     wm->tir[2 * IGlass - 1] = matGlass->TransThermal;
    2275              : 
    2276       134291 :                 } else if (mat->group == Material::Group::Shade || mat->group == Material::Group::Blind || mat->group == Material::Group::Screen) {
    2277            0 :                     if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag))
    2278            0 :                         ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers);
    2279            0 :                     if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1);
    2280            0 :                     if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    2281            0 :                         ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3);
    2282            0 :                         if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5);
    2283              :                     }
    2284            0 :                     auto const *matShade = dynamic_cast<Material::MaterialFen const *>(s_mat->materials(ShadeLayPtr));
    2285            0 :                     assert(matShade != nullptr);
    2286              : 
    2287            0 :                     if (ANY_SHADE_SCREEN(ShadeFlag)) {
    2288              :                         // Shade or screen on
    2289            0 :                         if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
    2290              :                             // check to make sure the user hasn't messed up the shade control values
    2291            0 :                             if (matShade->group == Material::Group::Blind) {
    2292            0 :                                 ShowSevereError(
    2293              :                                     state,
    2294            0 :                                     format("CalcWindowHeatBalance: ShadeFlag indicates Shade but Blind=\"{}\" is being used.", matShade->Name));
    2295            0 :                                 ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
    2296            0 :                                 ShowFatalError(state, "Preceding condition terminates program.");
    2297              :                             }
    2298              :                         }
    2299            0 :                         wm->thick[TotGlassLay] = matShade->Thickness;
    2300            0 :                         wm->scon[TotGlassLay] = matShade->Conductivity / matShade->Thickness;
    2301              : 
    2302            0 :                         if (ShadeFlag == WinShadingType::ExtScreen) {
    2303            0 :                             auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
    2304            0 :                             assert(matScreen != nullptr);
    2305            0 :                             wm->emis[wm->nglface] = matScreen->AbsorpThermalFront;
    2306            0 :                             wm->tir[wm->nglface] = matScreen->DfTrans;
    2307            0 :                             wm->tir[wm->nglface + 1] = matScreen->DfTrans;
    2308              :                         } else {
    2309            0 :                             wm->emis[wm->nglface] = matShade->AbsorpThermal;
    2310            0 :                             wm->tir[wm->nglface] = matShade->TransThermal;
    2311            0 :                             wm->tir[wm->nglface + 1] = matShade->TransThermal;
    2312              :                         }
    2313            0 :                         wm->emis[wm->nglface + 1] = matShade->AbsorpThermal;
    2314              : 
    2315              :                     } else {
    2316            0 :                         if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
    2317              :                             // check to make sure the user hasn't messed up the shade control values
    2318            0 :                             if (matShade->group == Material::Group::Shade || matShade->group == Material::Group::Screen) {
    2319            0 :                                 ShowSevereError(state,
    2320            0 :                                                 format("CalcWindowHeatBalance: ShadeFlag indicates Blind but Shade/Screen=\"{}\" is being used.",
    2321            0 :                                                        matShade->Name));
    2322            0 :                                 ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
    2323            0 :                                 ShowFatalError(state, "Preceding condition terminates program.");
    2324              :                             }
    2325              :                         }
    2326              : 
    2327              :                         // Blind on
    2328            0 :                         auto &surfShade = s_surf->surfShades(SurfNum);
    2329            0 :                         auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(surfShade.blind.matNum));
    2330            0 :                         assert(matBlind != nullptr);
    2331            0 :                         wm->thick[TotGlassLay] = matBlind->SlatThickness;
    2332            0 :                         wm->scon[TotGlassLay] = matBlind->SlatConductivity / matBlind->SlatThickness;
    2333              : 
    2334            0 :                         wm->emis[wm->nglface] = surfShade.blind.TAR.IR.Ft.Emi;
    2335            0 :                         wm->emis[wm->nglface + 1] = surfShade.blind.TAR.IR.Bk.Emi;
    2336            0 :                         wm->tir[wm->nglface] = surfShade.blind.TAR.IR.Ft.Tra;
    2337            0 :                         wm->tir[wm->nglface + 1] = surfShade.blind.TAR.IR.Bk.Tra;
    2338              :                     }
    2339              : 
    2340        24199 :                 } else if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture) {
    2341        24196 :                     ++IGap;
    2342        24196 :                     auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(LayPtr));
    2343        24196 :                     assert(matGas != nullptr);
    2344        24196 :                     wm->gaps[IGap - 1].width = matGas->Thickness;
    2345        24196 :                     wm->gaps[IGap - 1].numGases = matGas->numGases;
    2346        48392 :                     for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
    2347        24196 :                         wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
    2348        24196 :                         wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
    2349              :                     }
    2350              :                 }
    2351              : 
    2352              :             } // End of loop over glass, gap and blind/shade layers in a window construction
    2353              : 
    2354        85895 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2355              :                 // Interior or exterior blind, shade or screen is on.
    2356              :                 // Fill gap between blind/shade and adjacent glass with air properties.
    2357            0 :                 ++IGap;
    2358            0 :                 wm->gaps[IGap - 1].width = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(ShadeLayPtr))->toGlassDist;
    2359            0 :                 wm->gaps[IGap - 1].numGases = 1;
    2360              : 
    2361            0 :                 wm->gaps[IGap - 1].gases[0] = Material::gases[(int)Material::GasType::Air];
    2362            0 :                 wm->gaps[IGap - 1].gasFracts[0] = 1;
    2363              :             }
    2364              : 
    2365              :             // Exterior convection coefficient, exterior air temperature and IR radiance
    2366              :             // of exterior surround. Depend on whether window is interzone (in an interzone
    2367              :             // wall or exterior (in an exterior wall).
    2368              : 
    2369        85895 :             wm->hcout = HextConvCoeff; // Exterior convection coefficient is passed in from outer routine
    2370              :             // tsky = SkyTemp + TKelvin
    2371              : 
    2372        85895 :             if (SurfNumAdj > 0) { // Interzone window
    2373              : 
    2374            0 :                 RefAirTemp = s_surf->Surface(SurfNumAdj).getInsideAirTemperature(state, SurfNumAdj);
    2375            0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNumAdj) = RefAirTemp;
    2376            0 :                 wm->tout = RefAirTemp + Constant::Kelvin; // outside air temperature
    2377              : 
    2378              :                 // Add long-wave radiation from adjacent zone absorbed by glass layer closest to the adjacent zone.
    2379            0 :                 wm->AbsRadGlassFace[0] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNumAdj);
    2380              : 
    2381              :                 // The IR radiance of this window's "exterior" surround is the IR radiance
    2382              :                 // from surfaces and high-temp radiant sources in the adjacent zone
    2383              : 
    2384            0 :                 wm->Outir = s_surf->SurfWinIRfromParentZone(SurfNumAdj) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNumAdj);
    2385              : 
    2386              :             } else { // Exterior window (Ext BoundCond = 0)
    2387              :                 // Calculate LWR from surrounding surfaces if defined for an exterior window
    2388        85895 :                 OutSrdIR = 0;
    2389        85895 :                 if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
    2390            1 :                     if (s_surf->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
    2391            1 :                         SrdSurfTempAbs = surf.SrdSurfTemp + Constant::Kelvin;
    2392            1 :                         OutSrdIR = Constant::StefanBoltzmann * surf.ViewFactorSrdSurfs * pow_4(SrdSurfTempAbs);
    2393              :                     }
    2394              :                 }
    2395        85895 :                 if (surf.ExtWind) {                // Window is exposed to wind (and possibly rain)
    2396        85895 :                     if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
    2397            0 :                         wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
    2398              :                     } else { // Dry
    2399        85895 :                         wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2400              :                     }
    2401              :                 } else { // Window not exposed to wind
    2402            0 :                     wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2403              :                 }
    2404        85895 :                 wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
    2405        85895 :                 wm->Outir =
    2406        85895 :                     surf.ViewFactorSkyIR * (s_surf->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
    2407        85895 :                                             (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
    2408        85895 :                     surf.ViewFactorGroundIR * wm->Ebout + OutSrdIR;
    2409              :             }
    2410              : 
    2411              :             // Factors used in window layer temperature solution
    2412        85895 :             if (wm->ngllayer >= 2) {
    2413        24197 :                 wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    2414        24197 :                 wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    2415        24197 :                 wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
    2416              :             }
    2417              : 
    2418        85895 :             if (wm->ngllayer >= 3) {
    2419            0 :                 wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    2420            0 :                 wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    2421            0 :                 wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
    2422              :             }
    2423              : 
    2424        85895 :             if (wm->ngllayer == 4) {
    2425            0 :                 wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    2426            0 :                 wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    2427            0 :                 wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
    2428              :             }
    2429              : 
    2430        85895 :             wm->thetas = {0.0};
    2431        85895 :             wm->thetasPrev = {0.0};
    2432              : 
    2433              :             // Calculate window face temperatures
    2434              : 
    2435        85895 :             SolveForWindowTemperatures(state, SurfNum);
    2436              : 
    2437              :             // Temperature difference across glass layers (for debugging)
    2438              : 
    2439        85895 :             dth1 = wm->thetas[1] - wm->thetas[0];
    2440        85895 :             dth2 = wm->thetas[3] - wm->thetas[2];
    2441        85895 :             dth3 = wm->thetas[5] - wm->thetas[4];
    2442        85895 :             dth4 = wm->thetas[7] - wm->thetas[6];
    2443              : 
    2444        85895 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    2445            0 :                 auto const &surfShade = s_surf->surfShades(SurfNum);
    2446            0 :                 SurfInsideTemp = wm->thetas[2 * wm->ngllayer + 1] - Constant::Kelvin;
    2447            0 :                 EffShBlEmiss = surfShade.effShadeEmi;
    2448            0 :                 EffGlEmiss = surfShade.effGlassEmi;
    2449              : 
    2450            0 :                 s_surf->SurfWinEffInsSurfTemp(SurfNum) =
    2451            0 :                     (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin)) /
    2452            0 :                     (EffShBlEmiss + EffGlEmiss);
    2453              :             } else {
    2454        85895 :                 SurfInsideTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
    2455              :             }
    2456        85895 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2457            0 :                 SurfOutsideTemp = wm->thetas[2 * wm->ngllayer] - Constant::Kelvin; // this index looks suspicious (CR 8202)
    2458              :                 // SurfOutsideEmiss = emis(1)  ! this index should be coordinated with previous line
    2459            0 :                 SurfOutsideEmiss = wm->emis[2 * wm->ngllayer]; // fix for CR 8202
    2460              :             } else {
    2461        85895 :                 SurfOutsideEmiss = wm->emis[0];
    2462        85895 :                 SurfOutsideTemp = wm->thetas[0] - Constant::Kelvin;
    2463              :             }
    2464              : 
    2465              :             // Save temperatures for use next time step
    2466              : 
    2467       306079 :             for (int k = 1; k <= wm->nglfacep; ++k) {
    2468       220184 :                 surfWin.thetaFace[k] = wm->thetas[k - 1];
    2469              :             }
    2470              : 
    2471              :             // Added TH 12/23/2008 for thermochromic windows to save the current TC layer temperature
    2472        85895 :             if (wm->locTCFlag) {
    2473            0 :                 s_surf->SurfWinTCLayerTemp(SurfNum) =
    2474            0 :                     (wm->thetas[2 * constr.TCGlassNum - 2] + wm->thetas[2 * constr.TCGlassNum - 1]) / 2 - Constant::Kelvin; // degree C
    2475              :             }
    2476              :         } // regular window, not BSDF, not EQL
    2477              : 
    2478              :         // Set condensation flag to 1 if condensation expected to occur on the innermost glass face,
    2479              :         // or, for airflow windows, on either or the two glass faces in the airflow gap
    2480        88247 :         if (!state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) {
    2481        85895 :             InsideGlassTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
    2482        85895 :             RoomHumRat = thisZoneHB.airHumRat;
    2483        85895 :             RoomDewPoint = Psychrometrics::PsyTdpFnWPb(state, RoomHumRat, state.dataEnvrn->OutBaroPress);
    2484        85895 :             s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 0;
    2485        85895 :             if (InsideGlassTemp < RoomDewPoint) s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
    2486              :             // If airflow window, is there condensation on either glass face of the airflow gap?
    2487        85895 :             if (s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    2488            0 :                 Tleft = wm->thetas[2 * wm->ngllayer - 3] - Constant::Kelvin;
    2489            0 :                 Tright = wm->thetas[2 * wm->ngllayer - 2] - Constant::Kelvin;
    2490            0 :                 if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    2491            0 :                     if (Tleft < RoomDewPoint || Tright < RoomDewPoint) s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
    2492            0 :                 } else if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Outdoor) {
    2493            0 :                     if (Tleft < state.dataEnvrn->OutDewPointTemp || Tright < state.dataEnvrn->OutDewPointTemp)
    2494            0 :                         s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
    2495              :                 }
    2496              :             }
    2497              : 
    2498              :             // Do frame and divider calculation
    2499        85895 :             if (s_surf->SurfWinFrameArea(SurfNum) > 0.0 || s_surf->SurfWinDividerArea(SurfNum) > 0.0)
    2500            9 :                 CalcWinFrameAndDividerTemps(state, SurfNum, wm->tout, wm->tin, wm->hcout, wm->hcin, wm->Outir, ConstrNum);
    2501        85895 :             if (s_surf->SurfWinFrameArea(SurfNum) > 0.0) {
    2502            9 :                 s_surf->SurfWinInsideFrameCondensationFlag(SurfNum) = 0;
    2503            9 :                 if (s_surf->SurfWinFrameTempIn(SurfNum) < RoomDewPoint) s_surf->SurfWinInsideFrameCondensationFlag(SurfNum) = 1;
    2504              :             }
    2505        85895 :             if (s_surf->SurfWinDividerArea(SurfNum) > 0.0) {
    2506            9 :                 s_surf->SurfWinInsideDividerCondensationFlag(SurfNum) = 0;
    2507            9 :                 if (s_surf->SurfWinDividerTempIn(SurfNum) < RoomDewPoint) s_surf->SurfWinInsideDividerCondensationFlag(SurfNum) = 1;
    2508              :             }
    2509              :         }
    2510              :         // update exterior environment surface heat loss reporting
    2511        88247 :         Tsout = SurfOutsideTemp + Constant::Kelvin;
    2512        88247 :         state.dataHeatBalSurf->SurfQdotConvOutPerArea(SurfNum) = -wm->hcout * (Tsout - wm->tout);
    2513              : 
    2514        88247 :         Real64 const Tsout_4(pow_4(Tsout)); // Tuned To reduce pow calls and redundancies
    2515        88247 :         Real64 const Tout_4(pow_4(wm->tout));
    2516        88247 :         Real64 const emiss_sigma_product(SurfOutsideEmiss * Constant::StefanBoltzmann);
    2517        88247 :         Real64 rad_out_lw_srd_per_area = 0;
    2518              : 
    2519        88247 :         if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
    2520            1 :             if (surf.SurfHasSurroundingSurfProperty) {
    2521              :                 // update SurfHSrdSurfExt if the windows has exterior shade or blind
    2522            1 :                 state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) =
    2523            1 :                     Convect::SurroundingSurfacesRadCoeffAverage(state, SurfNum, Tsout, SurfOutsideEmiss);
    2524            1 :                 rad_out_lw_srd_per_area = state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) * (surf.SrdSurfTemp - SurfOutsideTemp);
    2525              :             }
    2526              :         }
    2527              : 
    2528              :         Real64 const rad_out_air_per_area =
    2529        88247 :             -emiss_sigma_product * (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * surf.ViewFactorSkyIR * (Tsout_4 - Tout_4);
    2530        88247 :         Real64 const rad_out_ground_per_area = -emiss_sigma_product * surf.ViewFactorGroundIR * (Tsout_4 - Tout_4);
    2531              :         Real64 const rad_out_sky_per_area =
    2532        88247 :             -emiss_sigma_product * s_surf->SurfAirSkyRadSplit(SurfNum) * surf.ViewFactorSkyIR * (Tsout_4 - pow_4(state.dataEnvrn->SkyTempKelvin));
    2533        88247 :         Real64 const rad_out_per_area = rad_out_air_per_area + rad_out_sky_per_area + rad_out_ground_per_area + rad_out_lw_srd_per_area;
    2534              : 
    2535        88247 :         state.dataHeatBalSurf->SurfHAirExt(SurfNum) = rad_out_air_per_area / (Tsout - wm->tout);
    2536        88247 :         state.dataHeatBalSurf->SurfQRadLWOutSrdSurfs(SurfNum) = rad_out_lw_srd_per_area;
    2537        88247 :         state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(SurfNum) = rad_out_per_area;
    2538        88247 :     } // CalcWindowHeatBalanceInternalRoutines()
    2539              : 
    2540              :     //****************************************************************************
    2541              : 
    2542              :     //****************************************************************************
    2543              : 
    2544          596 :     void GetHeatBalanceEqCoefMatrixSimple(EnergyPlusData &state,
    2545              :                                           int const nglasslayer,     // Number of glass layers
    2546              :                                           Array1D<Real64> const &hr, // Radiative conductance (W/m2-K)
    2547              :                                           Array1A<Real64> &hgap,     // Gap gas conductive conductance (W/m2-K)
    2548              :                                           Array2D<Real64> &Aface,    // Coefficient in equation Aface*thetas = Bface
    2549              :                                           Array1D<Real64> &Bface     // Coefficient in equation Aface*thetas = Bface
    2550              :     )
    2551              :     {
    2552              :         Real64 gr;  // Grashof number of gas in a gap
    2553              :         Real64 con; // Gap gas conductivity
    2554              :         Real64 pr;  // Gap gas Prandtl number
    2555              :         Real64 nu;  // Gap gas Nusselt number
    2556              : 
    2557          596 :         auto const &wm = state.dataWindowManager;
    2558              : 
    2559          596 :         if (nglasslayer == 1) {
    2560          508 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2561          508 :             Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
    2562              : 
    2563          508 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2564          508 :             Aface(2, 1) = -wm->scon[0];
    2565          508 :             Aface(1, 2) = -wm->scon[0];
    2566          508 :             Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
    2567              : 
    2568           88 :         } else if (nglasslayer == 2) {
    2569           88 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2570           88 :             NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2571           88 :             hgap(1) = con / wm->gaps[0].width * nu;
    2572              : 
    2573           88 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2574           88 :             Bface(2) = wm->AbsRadGlassFace[1];
    2575           88 :             Bface(3) = wm->AbsRadGlassFace[2];
    2576           88 :             Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
    2577              : 
    2578           88 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2579           88 :             Aface(2, 1) = -wm->scon[0];
    2580              : 
    2581           88 :             Aface(1, 2) = -wm->scon[0];
    2582           88 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2583           88 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2584              : 
    2585           88 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2586           88 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2587           88 :             Aface(4, 3) = -wm->scon[1];
    2588              : 
    2589           88 :             Aface(3, 4) = -wm->scon[1];
    2590           88 :             Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
    2591              : 
    2592            0 :         } else if (nglasslayer == 3) {
    2593            0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2594            0 :             NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2595            0 :             hgap(1) = con / wm->gaps[0].width * nu;
    2596              : 
    2597            0 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2598            0 :             NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2599            0 :             hgap(2) = con / wm->gaps[1].width * nu;
    2600              : 
    2601            0 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2602            0 :             Bface(2) = wm->AbsRadGlassFace[1];
    2603            0 :             Bface(3) = wm->AbsRadGlassFace[2];
    2604            0 :             Bface(4) = wm->AbsRadGlassFace[3];
    2605            0 :             Bface(5) = wm->AbsRadGlassFace[4];
    2606            0 :             Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
    2607              : 
    2608            0 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2609            0 :             Aface(2, 1) = -wm->scon[0];
    2610              : 
    2611            0 :             Aface(1, 2) = -wm->scon[0];
    2612            0 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2613            0 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2614              : 
    2615            0 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2616            0 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2617            0 :             Aface(4, 3) = -wm->scon[1];
    2618              : 
    2619            0 :             Aface(3, 4) = -wm->scon[1];
    2620            0 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    2621            0 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    2622              : 
    2623            0 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    2624            0 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    2625            0 :             Aface(6, 5) = -wm->scon[2];
    2626              : 
    2627            0 :             Aface(5, 6) = -wm->scon[2];
    2628            0 :             Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
    2629              : 
    2630            0 :         } else if (nglasslayer == 4) {
    2631            0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2632            0 :             NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2633            0 :             hgap(1) = con / wm->gaps[0].width * nu;
    2634              : 
    2635            0 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2636            0 :             NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2637            0 :             hgap(2) = con / wm->gaps[1].width * nu;
    2638              : 
    2639            0 :             WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
    2640            0 :             NusseltNumber(state, 0, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
    2641            0 :             hgap(3) = con / wm->gaps[2].width * nu;
    2642              : 
    2643            0 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2644            0 :             Bface(2) = wm->AbsRadGlassFace[1];
    2645            0 :             Bface(3) = wm->AbsRadGlassFace[2];
    2646            0 :             Bface(4) = wm->AbsRadGlassFace[3];
    2647            0 :             Bface(5) = wm->AbsRadGlassFace[4];
    2648            0 :             Bface(6) = wm->AbsRadGlassFace[5];
    2649            0 :             Bface(7) = wm->AbsRadGlassFace[6];
    2650            0 :             Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
    2651              : 
    2652            0 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2653            0 :             Aface(2, 1) = -wm->scon[0];
    2654              : 
    2655            0 :             Aface(1, 2) = -wm->scon[0];
    2656            0 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2657            0 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2658              : 
    2659            0 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2660            0 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2661            0 :             Aface(4, 3) = -wm->scon[1];
    2662              : 
    2663            0 :             Aface(3, 4) = -wm->scon[1];
    2664            0 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    2665            0 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    2666              : 
    2667            0 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    2668            0 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    2669            0 :             Aface(6, 5) = -wm->scon[2];
    2670              : 
    2671            0 :             Aface(5, 6) = -wm->scon[2];
    2672            0 :             Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
    2673            0 :             Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
    2674              : 
    2675            0 :             Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
    2676            0 :             Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
    2677            0 :             Aface(8, 7) = -wm->scon[3];
    2678              : 
    2679            0 :             Aface(7, 8) = -wm->scon[3];
    2680            0 :             Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
    2681              :         }
    2682          596 :     } // GetHeatBalanceEqCoefMatrixSimple()
    2683              : 
    2684       149363 :     void GetHeatBalanceEqCoefMatrix(EnergyPlusData &state,
    2685              :                                     int const SurfNum,
    2686              :                                     int const nglasslayer,
    2687              :                                     WinShadingType const ShadeFlag,
    2688              :                                     Real64 const sconsh,
    2689              :                                     Real64 const TauShIR,
    2690              :                                     Real64 const EpsShIR1,
    2691              :                                     Real64 const EpsShIR2,
    2692              :                                     Real64 const RhoShIR1,
    2693              :                                     Real64 const RhoShIR2,
    2694              :                                     Real64 const ShGlReflFacIR,
    2695              :                                     Real64 const RhoGlIR1,
    2696              :                                     Real64 const RhoGlIR2,
    2697              :                                     Real64 const hcv,             // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
    2698              :                                     Real64 const TGapNew,         // Current-iteration average air temp in airflow gap (K)
    2699              :                                     Real64 const TAirflowGapNew,  // Average air temp in airflow gap between glass panes (K)
    2700              :                                     Real64 const hcvAirflowGap,   // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
    2701              :                                     Array1A<Real64> const &hcvBG, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
    2702              :                                     Array1A<Real64> const &TGapNewBG,
    2703              :                                     Array1A<Real64> const &AbsRadShadeFace,
    2704              :                                     Array1D<Real64> const &hr,
    2705              :                                     Array2D<Real64> &Aface,
    2706              :                                     Array1D<Real64> &Bface)
    2707              :     {
    2708       149363 :         auto &wm = state.dataWindowManager;
    2709              : 
    2710              :         Real64 gr;  // Grashof number of gas in a gap
    2711              :         Real64 con; // Gap gas conductivity
    2712              :         Real64 pr;  // Gap gas Prandtl number
    2713              :         Real64 nu;  // Gap gas Nusselt number
    2714              : 
    2715              :         Real64 FacRhoIR25;         // Intermediate variable
    2716              :         Real64 FacRhoIR63;         // Intermediate variable
    2717              :         Real64 RhoIRfp;            // Intermediate variable
    2718              :         Real64 RhoIRbp;            // Intermediate variable
    2719              :         Real64 FacRhoIR2fp;        // Intermediate variable
    2720              :         Real64 FacRhoIR3bp;        // Intermediate variable
    2721              :         Real64 FacRhoIR2fpRhoIR63; // Intermediate variable
    2722              :         Real64 FacRhoIR3bpRhoIR25; // Intermediate variable
    2723              :         Real64 FacRhoIR47;         // Intermediate variable
    2724              :         Real64 FacRhoIR85;         // Intermediate variable
    2725              :         Real64 FacRhoIR4fp;        // Intermediate variable
    2726              :         Real64 FacRhoIR5bp;        // Intermediate variable
    2727              :         Real64 FacRhoIR4fpRhoIR85; // Intermediate variable
    2728              :         Real64 FacRhoIR5bpRhoIR47; // Intermediate variable
    2729              : 
    2730       149363 :         Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance (W/m2-K)
    2731              : 
    2732       149363 :         auto &s_surf = state.dataSurface;
    2733              : 
    2734       149363 :         auto const &surfWin = s_surf->SurfaceWindow(SurfNum);
    2735              : 
    2736       149363 :         if (nglasslayer == 1) {
    2737       109093 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2738       109093 :             Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
    2739              : 
    2740       109093 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2741       109093 :             Aface(2, 1) = -wm->scon[0];
    2742       109093 :             Aface(1, 2) = -wm->scon[0];
    2743       109093 :             Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
    2744              : 
    2745       109093 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    2746              :                 // interior shade, single pane
    2747              :                 //            ||   ||
    2748              :                 //  outside  1||2 3||4
    2749              :                 //            ||   ||
    2750              :                 //            gl  bl/sh/sc
    2751            0 :                 Bface(2) = wm->Rmir * wm->emis[1] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[1];
    2752            0 :                 Bface(3) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    2753            0 :                 Bface(4) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    2754              : 
    2755            0 :                 Aface(2, 2) = hr(2) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[0] + hcv;
    2756            0 :                 Aface(3, 2) = -wm->emis[1] * hr(3) / ShGlReflFacIR;
    2757            0 :                 Aface(2, 3) = -hr(2) * EpsShIR1 / ShGlReflFacIR;
    2758            0 :                 Aface(3, 3) = hr(3) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    2759            0 :                 Aface(4, 3) = -sconsh;
    2760            0 :                 Aface(3, 4) = -sconsh;
    2761            0 :                 Aface(4, 4) = hr(4) + sconsh + wm->hcin;
    2762              :             }
    2763              : 
    2764       109093 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2765              :                 // exterior shade, single pane
    2766              :                 //           ||      ||
    2767              :                 //  outside 3||4    1||2
    2768              :                 //           ||      ||
    2769              :                 //        bl/sh/sc   gl
    2770            0 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    2771            0 :                 Bface(3) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    2772            0 :                 Bface(4) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    2773              : 
    2774            0 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    2775            0 :                 Aface(4, 1) = -wm->emis[0] * hr(4) / ShGlReflFacIR;
    2776            0 :                 Aface(3, 3) = hr(3) + sconsh + wm->hcout;
    2777            0 :                 Aface(4, 3) = -sconsh;
    2778            0 :                 Aface(1, 4) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    2779            0 :                 Aface(3, 4) = -sconsh;
    2780            0 :                 Aface(4, 4) = hr(4) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    2781              :             }
    2782              : 
    2783        40270 :         } else if (nglasslayer == 2) {
    2784        40270 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2785        40270 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2786        40270 :             hgap(1) = con / wm->gaps[0].width * nu;
    2787        40270 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    2788            0 :                 wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
    2789            0 :                 hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
    2790              :             }
    2791              : 
    2792        40270 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2793        40270 :             Bface(2) = wm->AbsRadGlassFace[1];
    2794        40270 :             Bface(3) = wm->AbsRadGlassFace[2];
    2795        40270 :             Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
    2796              : 
    2797        40270 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2798        40270 :             Aface(2, 1) = -wm->scon[0];
    2799              : 
    2800        40270 :             Aface(1, 2) = -wm->scon[0];
    2801        40270 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2802        40270 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2803              : 
    2804        40270 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2805        40270 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2806        40270 :             Aface(4, 3) = -wm->scon[1];
    2807              : 
    2808        40270 :             Aface(3, 4) = -wm->scon[1];
    2809        40270 :             Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
    2810              : 
    2811        40270 :             if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    2812            0 :                 Bface(2) = wm->AbsRadGlassFace[1] + hcvAirflowGap * TAirflowGapNew;
    2813            0 :                 Bface(3) = wm->AbsRadGlassFace[2] + hcvAirflowGap * TAirflowGapNew;
    2814            0 :                 Aface(2, 2) = wm->scon[0] + hcvAirflowGap - wm->A23P * hr(2);
    2815            0 :                 Aface(3, 2) = -wm->A32P * hr(3);
    2816            0 :                 Aface(2, 3) = wm->A23P * hr(2);
    2817            0 :                 Aface(3, 3) = hcvAirflowGap + wm->scon[1] + wm->A32P * hr(3);
    2818              :             }
    2819              : 
    2820        40270 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    2821            0 :                 Bface(4) = wm->Rmir * wm->emis[3] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[3];
    2822            0 :                 Bface(5) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    2823            0 :                 Bface(6) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    2824              : 
    2825            0 :                 Aface(4, 4) = hr(4) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[1] + hcv;
    2826            0 :                 Aface(5, 4) = -wm->emis[3] * hr(5) / ShGlReflFacIR;
    2827            0 :                 Aface(4, 5) = -hr(4) * EpsShIR1 / ShGlReflFacIR;
    2828            0 :                 Aface(5, 5) = hr(5) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    2829            0 :                 Aface(6, 5) = -sconsh;
    2830            0 :                 Aface(5, 6) = -sconsh;
    2831            0 :                 Aface(6, 6) = hr(6) + sconsh + wm->hcin;
    2832              :             }
    2833              : 
    2834        40270 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2835            0 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    2836            0 :                 Bface(5) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    2837            0 :                 Bface(6) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    2838              : 
    2839            0 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    2840            0 :                 Aface(6, 1) = -wm->emis[0] * hr(6) / ShGlReflFacIR;
    2841            0 :                 Aface(5, 5) = hr(5) + sconsh + wm->hcout;
    2842            0 :                 Aface(6, 5) = -sconsh;
    2843            0 :                 Aface(1, 6) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    2844            0 :                 Aface(5, 6) = -sconsh;
    2845            0 :                 Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    2846              :             }
    2847              : 
    2848        40270 :             if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    2849            0 :                 Array1D<Real64> RhoIR(6); // Face IR reflectance
    2850              : 
    2851            0 :                 for (int i = 1; i <= 6; ++i) {
    2852            0 :                     RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
    2853              :                 }
    2854            0 :                 FacRhoIR25 = 1.0 - RhoIR(2) * RhoIR(5);
    2855            0 :                 FacRhoIR63 = 1.0 - RhoIR(6) * RhoIR(3);
    2856            0 :                 Real64 const tir_5_squared(pow_2(wm->tir[4]));
    2857            0 :                 RhoIRfp = RhoIR(5) + tir_5_squared * RhoIR(3) / FacRhoIR63;
    2858            0 :                 RhoIRbp = RhoIR(6) + tir_5_squared * RhoIR(2) / FacRhoIR25;
    2859            0 :                 FacRhoIR2fp = 1.0 - RhoIRfp * RhoIR(2);
    2860            0 :                 FacRhoIR3bp = 1.0 - RhoIRbp * RhoIR(3);
    2861            0 :                 FacRhoIR2fpRhoIR63 = FacRhoIR2fp * FacRhoIR63;
    2862            0 :                 FacRhoIR3bpRhoIR25 = FacRhoIR3bp * FacRhoIR25;
    2863            0 :                 Aface(2, 2) = wm->scon[0] + hcvBG(1) + hr(2) * (1 - RhoIRfp * (wm->emis[1] + RhoIR(2))) / FacRhoIR2fp;
    2864            0 :                 Aface(3, 2) = -wm->emis[1] * hr(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
    2865            0 :                 Aface(5, 2) = -wm->emis[1] * hr(5) / FacRhoIR2fp;
    2866            0 :                 Aface(6, 2) = -wm->emis[1] * hr(6) * RhoIR(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
    2867            0 :                 Bface(2) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[1];
    2868            0 :                 Aface(2, 3) = -wm->emis[2] * hr(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
    2869            0 :                 Aface(3, 3) = wm->scon[1] + hcvBG(2) + hr(3) * (1 - RhoIRbp * (wm->emis[2] + RhoIR(3))) / FacRhoIR3bp;
    2870            0 :                 Aface(5, 3) = -wm->emis[2] * hr(5) * RhoIR(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
    2871            0 :                 Aface(6, 3) = -wm->emis[2] * hr(6) / FacRhoIR3bp;
    2872            0 :                 Bface(3) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[2];
    2873            0 :                 Aface(2, 5) = -wm->emis[4] * hr(2) / FacRhoIR2fp;
    2874            0 :                 Aface(3, 5) = -hr(3) * wm->tir[4] * RhoIR(2) * wm->emis[4] / FacRhoIR2fpRhoIR63;
    2875            0 :                 Aface(5, 5) = sconsh + hcvBG(1) + hr(5) * (1 - RhoIR(2) * wm->emis[4] / FacRhoIR2fp);
    2876            0 :                 Aface(6, 5) = -sconsh - hr(6) * RhoIR(2) * wm->tir[4] * RhoIR(3) * wm->emis[4] / FacRhoIR2fpRhoIR63;
    2877            0 :                 Bface(5) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
    2878            0 :                 Aface(2, 6) = -hr(2) * wm->tir[4] * RhoIR(3) * wm->emis[5] / FacRhoIR3bpRhoIR25;
    2879            0 :                 Aface(3, 6) = -wm->emis[5] * hr(3) / FacRhoIR3bp;
    2880            0 :                 Aface(5, 6) = -sconsh - hr(5) * RhoIR(3) * wm->tir[4] * RhoIR(2) * wm->emis[5] / FacRhoIR3bpRhoIR25;
    2881            0 :                 Aface(6, 6) = sconsh + hcvBG(2) + hr(6) * (1 - RhoIR(3) * wm->emis[5] / FacRhoIR3bp);
    2882            0 :                 Bface(6) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
    2883            0 :             }
    2884              : 
    2885            0 :         } else if (nglasslayer == 3) {
    2886            0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2887            0 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2888            0 :             hgap(1) = con / wm->gaps[0].width * nu;
    2889            0 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    2890            0 :                 wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
    2891            0 :                 hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
    2892              :             }
    2893              : 
    2894            0 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2895            0 :             NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2896            0 :             hgap(2) = con / wm->gaps[1].width * nu;
    2897            0 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    2898            0 :                 wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
    2899            0 :                 hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
    2900              :             }
    2901              : 
    2902            0 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2903            0 :             Bface(2) = wm->AbsRadGlassFace[1];
    2904            0 :             Bface(3) = wm->AbsRadGlassFace[2];
    2905            0 :             Bface(4) = wm->AbsRadGlassFace[3];
    2906            0 :             Bface(5) = wm->AbsRadGlassFace[4];
    2907            0 :             Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
    2908              : 
    2909            0 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2910            0 :             Aface(2, 1) = -wm->scon[0];
    2911              : 
    2912            0 :             Aface(1, 2) = -wm->scon[0];
    2913            0 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2914            0 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2915              : 
    2916            0 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2917            0 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2918            0 :             Aface(4, 3) = -wm->scon[1];
    2919              : 
    2920            0 :             Aface(3, 4) = -wm->scon[1];
    2921            0 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    2922            0 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    2923              : 
    2924            0 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    2925            0 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    2926            0 :             Aface(6, 5) = -wm->scon[2];
    2927              : 
    2928            0 :             Aface(5, 6) = -wm->scon[2];
    2929            0 :             Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
    2930              : 
    2931            0 :             if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    2932            0 :                 Bface(4) = wm->AbsRadGlassFace[3] + hcvAirflowGap * TAirflowGapNew;
    2933            0 :                 Bface(5) = wm->AbsRadGlassFace[4] + hcvAirflowGap * TAirflowGapNew;
    2934            0 :                 Aface(4, 4) = wm->scon[1] + hcvAirflowGap - wm->A45P * hr(4);
    2935            0 :                 Aface(5, 4) = -wm->A54P * hr(5);
    2936            0 :                 Aface(4, 5) = wm->A45P * hr(4);
    2937            0 :                 Aface(5, 5) = hcvAirflowGap + wm->scon[2] + wm->A54P * hr(5);
    2938              :             }
    2939              : 
    2940            0 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    2941            0 :                 Bface(6) = wm->Rmir * wm->emis[5] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[5];
    2942            0 :                 Bface(7) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    2943            0 :                 Bface(8) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    2944              : 
    2945            0 :                 Aface(6, 6) = hr(6) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[2] + hcv;
    2946            0 :                 Aface(7, 6) = -wm->emis[5] * hr(7) / ShGlReflFacIR;
    2947            0 :                 Aface(6, 7) = -hr(6) * EpsShIR1 / ShGlReflFacIR;
    2948            0 :                 Aface(7, 7) = hr(7) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    2949            0 :                 Aface(8, 7) = -sconsh;
    2950            0 :                 Aface(7, 8) = -sconsh;
    2951            0 :                 Aface(8, 8) = hr(8) + sconsh + wm->hcin;
    2952            0 :             } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2953            0 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    2954            0 :                 Bface(7) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    2955            0 :                 Bface(8) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    2956              : 
    2957            0 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    2958            0 :                 Aface(8, 1) = -wm->emis[0] * hr(8) / ShGlReflFacIR;
    2959            0 :                 Aface(7, 7) = hr(7) + sconsh + wm->hcout;
    2960            0 :                 Aface(8, 7) = -sconsh;
    2961            0 :                 Aface(1, 8) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    2962            0 :                 Aface(7, 8) = -sconsh;
    2963            0 :                 Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    2964            0 :             } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    2965            0 :                 Array1D<Real64> RhoIR(8); // Face IR reflectance
    2966            0 :                 for (int i = 1; i <= 8; ++i) {
    2967            0 :                     RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
    2968              :                 }
    2969            0 :                 FacRhoIR47 = 1 - RhoIR(4) * RhoIR(7);
    2970            0 :                 FacRhoIR85 = 1 - RhoIR(8) * RhoIR(5);
    2971            0 :                 Real64 const tir_7_squared(pow_2(wm->tir[6]));
    2972            0 :                 RhoIRfp = RhoIR(7) + tir_7_squared * RhoIR(5) / FacRhoIR85;
    2973            0 :                 RhoIRbp = RhoIR(8) + tir_7_squared * RhoIR(4) / FacRhoIR47;
    2974            0 :                 FacRhoIR4fp = 1 - RhoIRfp * RhoIR(4);
    2975            0 :                 FacRhoIR5bp = 1 - RhoIRbp * RhoIR(5);
    2976            0 :                 FacRhoIR4fpRhoIR85 = FacRhoIR4fp * FacRhoIR85;
    2977            0 :                 FacRhoIR5bpRhoIR47 = FacRhoIR5bp * FacRhoIR47;
    2978            0 :                 Aface(4, 4) = wm->scon[1] + hcvBG(1) + hr(4) * (1 - RhoIRfp * (wm->emis[3] + RhoIR(4))) / FacRhoIR4fp;
    2979            0 :                 Aface(5, 4) = -wm->emis[3] * hr(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
    2980            0 :                 Aface(7, 4) = -wm->emis[3] * hr(7) / FacRhoIR4fp;
    2981            0 :                 Aface(8, 4) = -wm->emis[3] * hr(8) * RhoIR(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
    2982            0 :                 Bface(4) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[3];
    2983            0 :                 Aface(4, 5) = -wm->emis[4] * hr(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
    2984            0 :                 Aface(5, 5) = wm->scon[2] + hcvBG(2) + hr(5) * (1 - RhoIRbp * (wm->emis[4] + RhoIR(5))) / FacRhoIR5bp;
    2985            0 :                 Aface(7, 5) = -wm->emis[4] * hr(7) * RhoIR(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
    2986            0 :                 Aface(8, 5) = -wm->emis[4] * hr(8) / FacRhoIR5bp;
    2987            0 :                 Bface(5) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[4];
    2988            0 :                 Aface(4, 7) = -wm->emis[6] * hr(4) / FacRhoIR4fp;
    2989            0 :                 Aface(5, 7) = -hr(5) * wm->tir[6] * RhoIR(4) * wm->emis[6] / FacRhoIR4fpRhoIR85;
    2990            0 :                 Aface(7, 7) = sconsh + hcvBG(1) + hr(7) * (1 - RhoIR(4) * wm->emis[6] / FacRhoIR4fp);
    2991            0 :                 Aface(8, 7) = -sconsh - hr(8) * RhoIR(4) * wm->tir[6] * RhoIR(5) * wm->emis[6] / FacRhoIR4fpRhoIR85;
    2992            0 :                 Bface(7) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
    2993            0 :                 Aface(4, 8) = -hr(4) * wm->tir[6] * RhoIR(5) * wm->emis[7] / FacRhoIR5bpRhoIR47;
    2994            0 :                 Aface(5, 8) = -wm->emis[7] * hr(5) / FacRhoIR5bp;
    2995            0 :                 Aface(7, 8) = -sconsh - hr(7) * RhoIR(5) * wm->tir[6] * RhoIR(4) * wm->emis[7] / FacRhoIR5bpRhoIR47;
    2996            0 :                 Aface(8, 8) = sconsh + hcvBG(2) + hr(8) * (1 - RhoIR(5) * wm->emis[7] / FacRhoIR5bp);
    2997            0 :                 Bface(8) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
    2998            0 :             }
    2999              : 
    3000            0 :         } else if (nglasslayer == 4) {
    3001            0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    3002            0 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    3003            0 :             hgap(1) = con / wm->gaps[0].width * nu;
    3004            0 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3005            0 :                 wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
    3006            0 :                 hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
    3007              :             }
    3008              : 
    3009            0 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    3010            0 :             NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    3011            0 :             hgap(2) = con / wm->gaps[1].width * nu;
    3012            0 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3013            0 :                 wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
    3014            0 :                 hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
    3015              :             }
    3016              : 
    3017            0 :             WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
    3018            0 :             NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
    3019            0 :             hgap(3) = con / wm->gaps[2].width * nu;
    3020            0 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3021            0 :                 wm->hrgap[2] = 0.5 * std::abs(wm->A67) * pow_3(wm->thetas[5] + wm->thetas[6]);
    3022            0 :                 hgap(3) = hgap(3) * surfWin.edgeGlassCorrFac + wm->hrgap[2] * (surfWin.edgeGlassCorrFac - 1.0);
    3023              :             }
    3024            0 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    3025            0 :             Bface(2) = wm->AbsRadGlassFace[1];
    3026            0 :             Bface(3) = wm->AbsRadGlassFace[2];
    3027            0 :             Bface(4) = wm->AbsRadGlassFace[3];
    3028            0 :             Bface(5) = wm->AbsRadGlassFace[4];
    3029            0 :             Bface(6) = wm->AbsRadGlassFace[5];
    3030            0 :             Bface(7) = wm->AbsRadGlassFace[6];
    3031            0 :             Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
    3032              : 
    3033            0 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    3034            0 :             Aface(2, 1) = -wm->scon[0];
    3035              : 
    3036            0 :             Aface(1, 2) = -wm->scon[0];
    3037            0 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    3038            0 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    3039              : 
    3040            0 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    3041            0 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    3042            0 :             Aface(4, 3) = -wm->scon[1];
    3043              : 
    3044            0 :             Aface(3, 4) = -wm->scon[1];
    3045            0 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    3046            0 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    3047              : 
    3048            0 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    3049            0 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    3050            0 :             Aface(6, 5) = -wm->scon[2];
    3051              : 
    3052            0 :             Aface(5, 6) = -wm->scon[2];
    3053            0 :             Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
    3054            0 :             Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
    3055              : 
    3056            0 :             Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
    3057            0 :             Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
    3058            0 :             Aface(8, 7) = -wm->scon[3];
    3059              : 
    3060            0 :             Aface(7, 8) = -wm->scon[3];
    3061            0 :             Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
    3062              : 
    3063            0 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3064            0 :                 Bface(8) = wm->Rmir * wm->emis[7] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[7];
    3065            0 :                 Bface(9) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    3066            0 :                 Bface(10) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    3067              : 
    3068            0 :                 Aface(8, 8) = hr(8) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[3] + hcv;
    3069            0 :                 Aface(9, 8) = -wm->emis[7] * hr(9) / ShGlReflFacIR;
    3070            0 :                 Aface(8, 9) = -hr(8) * EpsShIR1 / ShGlReflFacIR;
    3071            0 :                 Aface(9, 9) = hr(9) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    3072            0 :                 Aface(10, 9) = -sconsh;
    3073            0 :                 Aface(9, 10) = -sconsh;
    3074            0 :                 Aface(10, 10) = hr(10) + sconsh + wm->hcin;
    3075              :             }
    3076              : 
    3077            0 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    3078            0 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    3079            0 :                 Bface(9) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    3080            0 :                 Bface(10) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    3081              : 
    3082            0 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    3083            0 :                 Aface(10, 1) = -wm->emis[0] * hr(10) / ShGlReflFacIR;
    3084            0 :                 Aface(9, 9) = hr(9) + sconsh + wm->hcout;
    3085            0 :                 Aface(10, 9) = -sconsh;
    3086            0 :                 Aface(1, 10) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    3087            0 :                 Aface(9, 10) = -sconsh;
    3088            0 :                 Aface(10, 10) = hr(10) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    3089              :             }
    3090              : 
    3091              :         } else {
    3092            0 :             ShowFatalError(state, format("SolveForWindowTemperatures: Invalid number of Glass Layers={}, up to 4 allowed.", wm->ngllayer));
    3093              :         }
    3094       149363 :     } // GetHeatBalanceEqCoefMatrix()
    3095              : 
    3096        85895 :     void SolveForWindowTemperatures(EnergyPlusData &state, int const SurfNum) // Surface number
    3097              :     {
    3098              : 
    3099              :         // SUBROUTINE INFORMATION:
    3100              :         //       AUTHOR         F. Winkelmann
    3101              :         //       DATE WRITTEN   July 2000
    3102              :         //       MODIFIED       Oct 2000, FW: modify edge-of-glass correction to account
    3103              :         //                       for gap radiative conductance affects
    3104              :         //                      Feb 2001, FW: add interior or exterior shade to layer
    3105              :         //                       heat balance calculation.
    3106              :         //                      Mar 2001, FW: relax error tolerance if MaxIterations reached.
    3107              :         //                      Jun 2001, FW: add interior or exterior blind
    3108              :         //                      Nov 2002, FW: add relaxation on face temperatures
    3109              :         //                       to improve convergence for multipane cases where outer pane
    3110              :         //                       has high solar absorptance: temp --> 0.5*(temp + previous temp);
    3111              :         //                       also, increase MaxIterations from 50 to 100.
    3112              :         //                      Dec 2002, FW: add between-glass shade/blind for double and triple glazing.
    3113              :         //                      Mar 2003, FW: remove redundant relaxation on radiative conductances
    3114              :         //                      Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02 to enhance
    3115              :         //                                    convergence in difficult cases.
    3116              :         //                      June 2003, FW: correct the expression for convective gain to zone air
    3117              :         //                       from airflow windows with airflow destination = InsideAir. Previously
    3118              :         //                       convective gain of air as it passed through gap was used, which is correct
    3119              :         //                       for airflow source = InsideAir but incorrect for airflow source = OutsideAir.
    3120              :         //                       Save SurfaceWindow%TAirflowGapOutlet for use in calculating convective heat
    3121              :         //                       gain to return air when airflow source = InsideAir, destination = ReturnAir.
    3122              :         //                      Dec 2003, FW: enhance converge for difficult cases by increasing relaxation
    3123              :         //                       in layer surface temperatures for iterations > MaxIterations/4
    3124              :         //                      May 2006, RR: add exterior window screen
    3125              :         //                      January 2009, BG: inserted call to recalc inside face convection inside iteration loop
    3126              :         //                        per ISO 15099 Section 8.3.2.2
    3127              :         //       RE-ENGINEERED  na
    3128              : 
    3129              :         // PURPOSE OF THIS SUBROUTINE:
    3130              :         // Evaluates the coefficients Aface and Bface in the system of linear
    3131              :         // algebraic equations
    3132              :         //     Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglfacep, j=1,nglfacep
    3133              :         // where
    3134              :         // nglface  = number of glass faces (= 2 * number of glass layers), or, if shade or blind is present,
    3135              :         // nglgacep = number of glass faces + 2
    3136              :         // thetas(j) = temperature of face j
    3137              :         // If an interior, exterior or between-glass shade or blind, or exterior screen is present
    3138              :         // the face numbering is as follows:
    3139              :         //   1 to 2*nglface are glass faces, from outside to inside;
    3140              :         //   2*nglface+1 and 2*nglface+2 are the shade or blind faces, from outside to inside
    3141              :         // For example, the following diagram shows the face number for an exterior shade, screen or blind
    3142              :         // on double glazing:
    3143              :         //     ||   ||   ||
    3144              :         //    5||6 1||2 3||4
    3145              :         //     ||   ||   ||
    3146              :         // bl/sh/sc gl   gl
    3147              : 
    3148              :         // And for a between-glass shade/blind in triple glazing:
    3149              :         //     ||   ||   ||   ||
    3150              :         //    1||2 3||4 7||8 5||6
    3151              :         //     ||   ||   ||   ||
    3152              :         //     gl   gl  bl/sh gl
    3153              : 
    3154              :         // METHODOLOGY EMPLOYED:
    3155              :         // The Aface and Bface coefficients are determined by the equations for
    3156              :         // heat balance at the glass and shade/blind faces. The system of linear equations is solved
    3157              :         // by LU decomposition.
    3158              : 
    3159        85895 :         constexpr int MaxIterations(100); // Maximum allowed number of iterations (increased 9/01 from 15 to 50,
    3160              :         //   increased 11/02 from 50 to 100)
    3161        85895 :         constexpr Real64 errtemptol(0.02); // Tolerance on errtemp for convergence (increased from 0.01, 3/4/03)
    3162              : 
    3163              :         int ZoneNum; // Zone number corresponding to SurfNum
    3164              :         int d;       // +1 if number of row interchanges is even,
    3165              :         // -1 if odd (in LU decomposition
    3166              : 
    3167        85895 :         auto &wm = state.dataWindowManager;
    3168              : 
    3169        85895 :         int iter = 0;                    // Iteration number
    3170        85895 :         Real64 errtemp = 0.0;            // Absolute value of sum of face temperature differences between iterations, divided by number of faces
    3171        85895 :         Real64 VGap = 0.0;               // Air velocity in gap between glass and shade/blind (m/s)
    3172        85895 :         Real64 VAirflowGap = 0.0;        // Air velocity in airflow gap between glass panes (m/s)
    3173        85895 :         Real64 VGapPrev = 0.0;           // Value of VGap from previous iteration
    3174        85895 :         Real64 TGapNew = 0.0;            // Average air temp in gap between glass and shade/blind (K)
    3175        85895 :         Real64 TAirflowGapNew = 0.0;     // Average air temp in airflow gap between glass panes (K)
    3176        85895 :         Real64 TGapOutlet = 0.0;         // Temperature of air leaving gap between glass and shade/blind (K)
    3177        85895 :         Real64 TAirflowGapOutlet = 0.0;  // Temperature of air leaving airflow gap between glass panes (K)
    3178        85895 :         Real64 TAirflowGapOutletC = 0.0; // Temperature of air leaving airflow gap between glass panes (C)
    3179        85895 :         Real64 hcv = 0.0;                // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
    3180        85895 :         Real64 hcvAirflowGap = 0.0;      // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
    3181        85895 :         Real64 hcvPrev = 0.0;            // Value of hcv from previous iteration
    3182        85895 :         Real64 ConvHeatFlowForced = 0.0; // Convective heat flow from forced airflow gap (W)
    3183        85895 :         Real64 ShGlReflFacIR = 0.0;      // Factor for long-wave inter-reflection between shade/blind and adjacent glass
    3184        85895 :         Real64 RhoGlIR1 = 0.0;           // Long-wave reflectance of glass surface facing shade/blind; 1=exterior shade/blind,
    3185        85895 :         Real64 RhoGlIR2 = 0.0;
    3186              :         //  2=exterior shade/blind
    3187        85895 :         Real64 EpsShIR1 = 0.0; // Long-wave emissivity of shade/blind surface facing glass; 1=interior shade/blind,
    3188        85895 :         Real64 EpsShIR2 = 0.0;
    3189              :         //  2=interior shade/blind
    3190        85895 :         Real64 RhoShIR1 = 0.0; // Long-wave reflectance of shade/blind surface facing glass; 1=interior shade/blind,
    3191        85895 :         Real64 RhoShIR2 = 0.0;
    3192              :         //  2=exterior shade/blind
    3193        85895 :         Real64 TauShIR = 0.0; // Long-wave transmittance of isolated shade/blind
    3194        85895 :         Real64 sconsh = 0.0;  // shade/blind conductance (W/m2-K)
    3195              : 
    3196              :         //  radiation from lights and zone equipment absorbed by faces of shade/blind (W/m2)
    3197        85895 :         Real64 ShadeArea = 0.0; // shade/blind area (m2)
    3198              :         // Real64 CondHeatGainGlass = 0.0; // Conduction through inner glass layer, outside to inside (W)
    3199              :         // Real64 CondHeatGainShade = 0.0; // Conduction through shade/blind, outside to inside (W)
    3200              :         //  shade/blind is present. Zero if shade/blind has zero IR transmittance (W)
    3201              :         // Real64 IncidentSolar = 0.0;         // Solar incident on outside of window (W)
    3202        85895 :         Real64 TotAirflowGap = 0.0;  // Total volumetric airflow through window gap (m3/s)
    3203        85895 :         Real64 CpAirOutlet = 0.0;    // Heat capacity of air from window gap (J/kg-K)
    3204        85895 :         Real64 CpAirZone = 0.0;      // Heat capacity of zone air (J/kg-K)
    3205        85895 :         Real64 InletAirHumRat = 0.0; // Humidity ratio of air from window gap entering fan
    3206              : 
    3207        85895 :         Array1D<Real64> hr = Array1D<Real64>(2 * maxGlassLayers); // Radiative conductance (W/m2-K)
    3208        85895 :         Array1D<Real64> AbsRadShadeFace(2);                       // Solar radiation, short-wave radiation from lights, and long-wave
    3209        85895 :         Array1D<Real64> TGapNewBG(2);                             // For between-glass shade/blind, average gas temp in gaps on either
    3210              :         //  side of shade/blind (K)
    3211        85895 :         Array1D<Real64> hcvBG(2); // For between-glass shade/blind, convection coefficient from gap glass or
    3212              :         //  shade/blind to gap gas on either side of shade/blind (W/m2-K)
    3213              : 
    3214        85895 :         Array2D<Real64> Aface(2 * maxGlassLayers, 2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
    3215        85895 :         Array1D<Real64> Bface(2 * maxGlassLayers);                     // Coefficient in equation Aface*thetas = Bface
    3216        85895 :         Array1D_int indx(2 * maxGlassLayers);                          // Vector of row permutations in LU decomposition
    3217              : 
    3218        85895 :         auto &s_surf = state.dataSurface;
    3219              : 
    3220        85895 :         wm->nglfacep = wm->nglface;
    3221        85895 :         WinShadingType ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    3222        85895 :         ZoneNum = s_surf->Surface(SurfNum).Zone;
    3223        85895 :         AbsRadShadeFace = 0.0;
    3224              : 
    3225        85895 :         if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
    3226            0 :             wm->nglfacep = wm->nglface + 2;
    3227            0 :             AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(state, SurfNum);
    3228            0 :             AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(state, SurfNum);
    3229            0 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsRadShadeFace(2) += s_surf->SurfWinIntLWAbsByShade(SurfNum);
    3230            0 :             sconsh = wm->scon[wm->ngllayer];
    3231            0 :             TauShIR = wm->tir[wm->nglface];
    3232            0 :             EpsShIR1 = wm->emis[wm->nglface];
    3233            0 :             EpsShIR2 = wm->emis[wm->nglface + 1];
    3234            0 :             RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
    3235            0 :             RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
    3236            0 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3237            0 :                 RhoGlIR2 = 1.0 - wm->emis[2 * wm->ngllayer - 1];
    3238            0 :                 ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
    3239            0 :             } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    3240            0 :                 RhoGlIR1 = 1.0 - wm->emis[0];
    3241            0 :                 ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2;
    3242              :             }
    3243              :         } // End of check if shade or blind is on
    3244              : 
    3245              :         // Initialize face temperatures.
    3246              : 
    3247        85895 :         StartingWindowTemps(state, SurfNum, AbsRadShadeFace);
    3248              : 
    3249        85895 :         hcvPrev = 0.0;
    3250        85895 :         VGapPrev = 0.0;
    3251              : 
    3252              :         // Calculate radiative conductances
    3253              : 
    3254        85895 :         errtemp = errtemptol * 2.0;
    3255              : 
    3256       235258 :         while (iter < MaxIterations && errtemp > errtemptol) {
    3257              : 
    3258       528629 :             for (int i = 1; i <= wm->nglfacep; ++i) {
    3259       379266 :                 hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
    3260              :                 // Following line is redundant since thetas is being relaxed;
    3261              :                 // removed by FCW, 3/4/03
    3262              :                 //! fw if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
    3263              :             }
    3264              : 
    3265              :             // call for new interior film coeff (since it is temperature dependent) if using Detailed inside coef model
    3266       149363 :             if (((s_surf->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) &&
    3267       169205 :                  (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo == Convect::HcInt::ASHRAETARP)) ||
    3268        19842 :                 (s_surf->surfIntConv(SurfNum).model == Convect::HcInt::ASHRAETARP)) {
    3269              :                 // coef model is "detailed" and not prescribed by user
    3270              :                 // need to find inside face index, varies with shade/blind etc.
    3271              :                 int InsideFaceIndex; // intermediate variable for index of inside face in thetas
    3272       129521 :                 if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3273            0 :                     InsideFaceIndex = wm->nglfacep;
    3274              :                 } else {
    3275       129521 :                     InsideFaceIndex = wm->nglface;
    3276              :                 }
    3277       129521 :                 Convect::CalcISO15099WindowIntConvCoeff(
    3278       129521 :                     state, SurfNum, wm->thetas[InsideFaceIndex - 1] - Constant::Kelvin, wm->tin - Constant::Kelvin);
    3279       129521 :                 wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
    3280              :             }
    3281              : 
    3282       149363 :             Aface = 0.0;
    3283       149363 :             Bface = 0.0;
    3284              : 
    3285              :             // If interior or exterior shade or blind is present, get heat transfer
    3286              :             // coefficient from glass and shade/blind to gap between glass and shade/blind,
    3287              :             // effective gap air temperature, velocity of air in gap and gap outlet temperature.
    3288              : 
    3289       149363 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3290            0 :                 ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, s_surf->SurfWinConvHeatFlowNatural(SurfNum));
    3291            0 :                 if (iter >= 1) {
    3292            0 :                     hcv = 0.5 * (hcvPrev + hcv);
    3293            0 :                     VGap = 0.5 * (VGapPrev + VGap);
    3294              :                 }
    3295            0 :                 hcvPrev = hcv;
    3296            0 :                 VGapPrev = VGap;
    3297              :             }
    3298              : 
    3299       149363 :             TAirflowGapOutlet = 0.0;
    3300              :             // If between-glass shade or blind is not present and this is an airflow window
    3301              :             // (i.e., with forced airflow in the gap for double glass or in the inner gap for triple glass)
    3302              :             // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and
    3303              :             // convective heat flow from gap.
    3304              : 
    3305       149363 :             if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    3306            0 :                 BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced);
    3307              :             }
    3308              : 
    3309              :             // If between-glass shade or blind is present, get convective heat transfer
    3310              :             // coefficients from glass and shade/blind to the two gaps on either side of the shade/matBlind->
    3311              :             // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the
    3312              :             // convective heat flows from the gaps.
    3313              : 
    3314       149363 :             if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    3315            0 :                 if (s_surf->SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps
    3316            0 :                     BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG);
    3317              :                 } else { // Forced convection in gaps
    3318            0 :                     BetweenGlassShadeForcedFlow(state, SurfNum, iter, VGap, TGapNewBG, TAirflowGapOutlet, hcvBG, ConvHeatFlowForced);
    3319              :                 }
    3320              :             }
    3321              : 
    3322       149363 :             ++iter;
    3323              : 
    3324              :             // Calculations based on number of glass layers
    3325       298726 :             GetHeatBalanceEqCoefMatrix(state,
    3326              :                                        SurfNum,
    3327       149363 :                                        wm->ngllayer,
    3328              :                                        ShadeFlag,
    3329              :                                        sconsh,
    3330              :                                        TauShIR,
    3331              :                                        EpsShIR1,
    3332              :                                        EpsShIR2,
    3333              :                                        RhoShIR1,
    3334              :                                        RhoShIR2,
    3335              :                                        ShGlReflFacIR,
    3336              :                                        RhoGlIR1,
    3337              :                                        RhoGlIR2,
    3338              :                                        hcv,
    3339              :                                        TGapNew,
    3340              :                                        TAirflowGapNew,
    3341              :                                        hcvAirflowGap,
    3342              :                                        hcvBG,
    3343              :                                        TGapNewBG,
    3344              :                                        AbsRadShadeFace,
    3345              :                                        hr,
    3346              :                                        Aface,
    3347              :                                        Bface);
    3348       149363 :             LUdecomposition(state, Aface, wm->nglfacep, indx, d); // Note that these routines change Aface;
    3349       149363 :             LUsolution(state, Aface, wm->nglfacep, indx, Bface);  // face temperatures are returned in Bface
    3350              : 
    3351       528629 :             for (int i = 1; i <= wm->nglfacep; ++i) {
    3352       379266 :                 wm->thetasPrev[i - 1] = wm->thetas[i - 1];
    3353       379266 :                 if (iter < MaxIterations / 4) {
    3354       379266 :                     wm->thetas[i - 1] = 0.5 * wm->thetas[i - 1] + 0.5 * Bface(i);
    3355              :                 } else {
    3356            0 :                     wm->thetas[i - 1] = 0.75 * wm->thetas[i - 1] + 0.25 * Bface(i);
    3357              :                 }
    3358              :             }
    3359              : 
    3360       149363 :             errtemp = 0.0;
    3361       528629 :             for (int i = 1; i <= wm->nglfacep; ++i) {
    3362       379266 :                 errtemp += std::abs(wm->thetas[i - 1] - wm->thetasPrev[i - 1]);
    3363              :             }
    3364       149363 :             errtemp /= wm->nglfacep;
    3365              :         }
    3366              : 
    3367        85895 :         s_surf->SurfWinWindowCalcIterationsRep(SurfNum) = iter;
    3368              : 
    3369              :         // We have reached iteration limit or we have converged. If we have reached the
    3370              :         // iteration limit the following test relaxes the convergence tolerance.
    3371              :         // If we have converged (errtemp <= errtemptol) the following test has not effect.
    3372              : 
    3373        85895 :         if (errtemp < 10 * errtemptol) {
    3374              : 
    3375              :             // Window heat balance solution has converged.
    3376              : 
    3377              :             // For interior shade, add convective gain from glass/shade gap air flow to zone convective gain;
    3378              :             // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for
    3379              :             // contribution of frame and divider.
    3380              :             // IncidentSolar = s_surf->Surface(SurfNum).Area * state.dataHeatBal->SurfQRadSWOutIncident(SurfNum);
    3381        85895 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3382              :                 // Interior shade or blind
    3383              :                 // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection
    3384              :                 //   from air exiting gap, convection from zone-side of shade/blind, net IR to zone from shade and net IR to
    3385              :                 //   zone from the glass adjacent to the shade/blind (zero if shade/blind IR transmittance is zero).
    3386              :                 // Following assumes glazed area = window area (i.e., dividers ignored) in calculating
    3387              :                 //   IR to zone from glass when interior shade/blind is present.
    3388            0 :                 ShadeArea = s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum);
    3389              :                 // CondHeatGainShade = ShadeArea * sconsh *
    3390              :                 //                     (wm->thetas(wm->nglfacep - 1) -
    3391              :                 //                     wm->thetas[wm->nglfacep-1]);
    3392            0 :                 s_surf->SurfWinGainIRShadeToZoneRep(SurfNum) =
    3393            0 :                     ShadeArea * EpsShIR2 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 1]) - wm->Rmir) +
    3394            0 :                     EpsShIR1 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 2]) - wm->Rmir) * RhoGlIR2 * TauShIR / ShGlReflFacIR;
    3395            0 :                 s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) = ShadeArea * (wm->emis[2 * wm->ngllayer - 1] * TauShIR / ShGlReflFacIR) *
    3396            0 :                                                               (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
    3397            0 :                 s_surf->SurfWinGainConvShadeToZoneRep(SurfNum) = ShadeArea * wm->hcin * (wm->thetas[wm->nglfacep - 1] - wm->tin);
    3398            0 :                 s_surf->SurfWinHeatGain(SurfNum) = s_surf->SurfWinTransSolar(SurfNum) + s_surf->SurfWinConvHeatFlowNatural(SurfNum) +
    3399            0 :                                                    s_surf->SurfWinGainConvShadeToZoneRep(SurfNum) + s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) +
    3400            0 :                                                    s_surf->SurfWinGainIRShadeToZoneRep(SurfNum);
    3401              :             } else {
    3402              :                 // Interior shade or blind not present; innermost layer is glass
    3403              :                 // CondHeatGainGlass = s_surf->Surface(SurfNum).Area * wm->scon(wm->ngllayer) *
    3404              :                 //                     (wm->thetas(2 * wm->ngllayer - 1) -
    3405              :                 //                     wm->thetas[2 * wm->ngllayer - 1]);
    3406       171790 :                 s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) = s_surf->Surface(SurfNum).Area * wm->emis[2 * wm->ngllayer - 1] *
    3407        85895 :                                                               (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
    3408        85895 :                 s_surf->SurfWinGainConvGlazToZoneRep(SurfNum) =
    3409        85895 :                     s_surf->Surface(SurfNum).Area * wm->hcin * (wm->thetas[2 * wm->ngllayer - 1] - wm->tin);
    3410        85895 :                 s_surf->SurfWinHeatGain(SurfNum) =
    3411        85895 :                     s_surf->SurfWinTransSolar(SurfNum) + s_surf->SurfWinGainConvGlazToZoneRep(SurfNum) + s_surf->SurfWinGainIRGlazToZoneRep(SurfNum);
    3412              :             }
    3413              : 
    3414              :             // Add convective heat gain from airflow window
    3415              :             // Note: effect of fan heat on gap outlet temperature is neglected since fan power (based
    3416              :             // on pressure drop through the gap) is extremely small
    3417              : 
    3418        85895 :             s_surf->SurfWinGapConvHtFlowRep(SurfNum) = 0.0;
    3419        85895 :             s_surf->SurfWinGapConvHtFlowRepEnergy(SurfNum) = 0.0;
    3420        85895 :             TotAirflowGap = s_surf->SurfWinAirflowThisTS(SurfNum) * s_surf->Surface(SurfNum).Width;
    3421        85895 :             TAirflowGapOutletC = TAirflowGapOutlet - Constant::Kelvin;
    3422        85895 :             s_surf->SurfWinTAirflowGapOutlet(SurfNum) = TAirflowGapOutletC;
    3423        85895 :             if (s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    3424            0 :                 s_surf->SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowForced;
    3425            0 :                 s_surf->SurfWinGapConvHtFlowRepEnergy(SurfNum) = s_surf->SurfWinGapConvHtFlowRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    3426              :                 // Add heat from gap airflow to zone air if destination is inside air; save the heat gain to return
    3427              :                 // air in case it needs to be sent to the zone (due to no return air determined in HVAC simulation)
    3428            0 :                 if (s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor ||
    3429            0 :                     s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Return) {
    3430            0 :                     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    3431            0 :                     if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    3432            0 :                         InletAirHumRat = thisZoneHB.airHumRat;
    3433              :                     } else { // AirflowSource = outside air
    3434            0 :                         InletAirHumRat = state.dataEnvrn->OutHumRat;
    3435              :                     }
    3436            0 :                     Real64 ZoneTemp = thisZoneHB.MAT; // this should be Tin (account for different reference temps)
    3437            0 :                     CpAirOutlet = Psychrometrics::PsyCpAirFnW(InletAirHumRat);
    3438            0 :                     CpAirZone = Psychrometrics::PsyCpAirFnW(thisZoneHB.airHumRat);
    3439            0 :                     s_surf->SurfWinRetHeatGainToZoneAir(SurfNum) = TotAirflowGap * (CpAirOutlet * (TAirflowGapOutletC)-CpAirZone * ZoneTemp);
    3440            0 :                     if (s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor) {
    3441            0 :                         s_surf->SurfWinHeatGain(SurfNum) += s_surf->SurfWinRetHeatGainToZoneAir(SurfNum);
    3442              :                     }
    3443              :                 }
    3444              :                 // For AirflowDestination = ReturnAir in a controlled (i.e., conditioned) zone with return air, see CalcZoneLeavingConditions
    3445              :                 // for calculation of modification of return-air temperature due to airflow from window gaps into return air.
    3446              :             }
    3447              : 
    3448              :             // Correct WinHeatGain for interior diffuse shortwave (solar and shortwave from lights) transmitted
    3449              :             // back out window
    3450        85895 :             int const ConstrNum = s_surf->SurfActiveConstruction(SurfNum);
    3451        85895 :             int const ConstrNumSh = s_surf->SurfWinActiveShadedConstruction(SurfNum);
    3452              : 
    3453        85895 :             Real64 reflDiff = 0.0; // Diffuse shortwave back reflectance
    3454        85895 :             if (NOT_SHADED(ShadeFlag)) {
    3455        85895 :                 reflDiff = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack;
    3456            0 :             } else if (ANY_SHADE_SCREEN(ShadeFlag)) {
    3457            0 :                 reflDiff = state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack;
    3458            0 :             } else if (ANY_BLIND(ShadeFlag)) {
    3459            0 :                 auto const &surfShade = s_surf->surfShades(SurfNum);
    3460            0 :                 auto const &constrSh = state.dataConstruction->Construct(ConstrNumSh);
    3461            0 :                 reflDiff = Interp(constrSh.blindTARs[surfShade.blind.slatAngIdxLo].Sol.Bk.Df.Ref,
    3462            0 :                                   constrSh.blindTARs[surfShade.blind.slatAngIdxHi].Sol.Bk.Df.Ref,
    3463            0 :                                   surfShade.blind.slatAngInterpFac);
    3464            0 :             } else if (ShadeFlag == WinShadingType::SwitchableGlazing) {
    3465            0 :                 reflDiff = InterpSw(s_surf->SurfWinSwitchingFactor(SurfNum),
    3466            0 :                                     state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack,
    3467            0 :                                     state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack);
    3468              :             }
    3469              :             // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is?  LKL (9/2012)
    3470        85895 :             s_surf->SurfWinLossSWZoneToOutWinRep(SurfNum) =
    3471        85895 :                 state.dataHeatBal->EnclSolQSWRad(s_surf->Surface(SurfNum).SolarEnclIndex) * s_surf->Surface(SurfNum).Area * (1 - reflDiff) +
    3472        85895 :                 state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
    3473       171790 :             s_surf->SurfWinHeatGain(SurfNum) -= (s_surf->SurfWinLossSWZoneToOutWinRep(SurfNum) +
    3474        85895 :                                                  state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * s_surf->Surface(SurfNum).Area);
    3475              : 
    3476        85895 :             if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
    3477            0 :                 s_surf->SurfWinShadingAbsorbedSolar(SurfNum) =
    3478            0 :                     (s_surf->SurfWinExtBeamAbsByShade(SurfNum) + s_surf->SurfWinExtDiffAbsByShade(SurfNum)) *
    3479            0 :                     (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum));
    3480            0 :                 s_surf->SurfWinShadingAbsorbedSolarEnergy(SurfNum) = s_surf->SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    3481              :             }
    3482        85895 :             if (state.dataEnvrn->SunIsUp) {
    3483              : 
    3484        42964 :                 s_surf->SurfWinSysSolTransmittance(SurfNum) =
    3485        42964 :                     s_surf->SurfWinTransSolar(SurfNum) /
    3486        42964 :                     (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) * (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)) +
    3487              :                      0.0001);
    3488        42964 :                 s_surf->SurfWinSysSolAbsorptance(SurfNum) =
    3489        42964 :                     (state.dataHeatBal->SurfWinQRadSWwinAbsTot(SurfNum) + s_surf->SurfWinShadingAbsorbedSolar(SurfNum)) /
    3490        42964 :                     (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) * (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)) +
    3491              :                      0.0001);
    3492        42964 :                 s_surf->SurfWinSysSolReflectance(SurfNum) =
    3493        42964 :                     1.0 - s_surf->SurfWinSysSolTransmittance(SurfNum) - s_surf->SurfWinSysSolAbsorptance(SurfNum);
    3494              :             } else {
    3495        42931 :                 s_surf->SurfWinSysSolTransmittance(SurfNum) = 0.0;
    3496        42931 :                 s_surf->SurfWinSysSolAbsorptance(SurfNum) = 0.0;
    3497        42931 :                 s_surf->SurfWinSysSolReflectance(SurfNum) = 0.0;
    3498              :             }
    3499              : 
    3500              :             // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps)
    3501        85895 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) s_surf->SurfWinConvCoeffWithShade(SurfNum) = hcv;
    3502              :         } else {
    3503              :             // No convergence after MaxIterations even with relaxed error tolerance
    3504            0 :             ShowSevereError(state, format("Convergence error in SolveForWindowTemperatures for window {}", s_surf->Surface(SurfNum).Name));
    3505            0 :             ShowContinueErrorTimeStamp(state, "");
    3506              : 
    3507            0 :             if (state.dataGlobal->DisplayExtraWarnings) {
    3508              :                 // report out temperatures
    3509            0 :                 for (int i = 1; i <= wm->nglfacep; ++i) {
    3510            0 :                     ShowContinueError(state,
    3511            0 :                                       format("Glazing face index = {} ; new temperature ={:.4R}C  ; previous temperature = {:.4R}C",
    3512              :                                              i,
    3513            0 :                                              wm->thetas[i - 1] - Constant::Kelvin,
    3514            0 :                                              wm->thetasPrev[i - 1] - Constant::Kelvin));
    3515              :                 }
    3516              :             }
    3517              : 
    3518            0 :             ShowFatalError(
    3519              :                 state,
    3520            0 :                 format("Program halted because of convergence error in SolveForWindowTemperatures for window {}", s_surf->Surface(SurfNum).Name));
    3521              :         }
    3522        85895 :     } // SolveForWindowTemperatures()
    3523              : 
    3524              :     //****************************************************************************
    3525              : 
    3526            0 :     void ExtOrIntShadeNaturalFlow(EnergyPlusData &state,
    3527              :                                   int const SurfNum,  // Surface number
    3528              :                                   int const iter,     // Iteration number for glass heat balance calculation
    3529              :                                   Real64 &VGap,       // Air velocity in glass-shade/blind gap (m/s)
    3530              :                                   Real64 &TGapNew,    // Current-iteration average air temp in glass-shade/blind gap (K)
    3531              :                                   Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
    3532              :                                   Real64 &hcv,        // Convection coefficient from gap glass or shade to gap air (W/m2-K)
    3533              :                                   Real64 &QConvGap    // Convective heat gain from glass-shade/blind gap for interior shade (W)
    3534              :     )
    3535              :     {
    3536              : 
    3537              :         // SUBROUTINE INFORMATION:
    3538              :         //       AUTHOR         F. Winkelmann
    3539              :         //       DATE WRITTEN   December 2000
    3540              :         //       MODIFIED       June 2001: add window blinds
    3541              :         //                      May 2006 (RR): add exterior window screens
    3542              :         //       RE-ENGINEERED  na
    3543              : 
    3544              :         // PURPOSE OF THIS SUBROUTINE:
    3545              :         // Called by SolveForWindowTemperatures for windows that have an interior
    3546              :         // or exterior blind or shade in place.
    3547              :         // Solves for air flow in gap between glass and shade/blind.
    3548              :         // Finds temperature of gap air and coefficient for convective heat transfer
    3549              :         // from glass to gap air and shade/blind to gap air.
    3550              : 
    3551              :         // METHODOLOGY EMPLOYED:
    3552              :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    3553              :         // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
    3554              : 
    3555              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    3556              :         //   air flow or bottom for downward air flow (K)
    3557              : 
    3558              :         int ConstrNumSh;  // Shaded construction number
    3559              :         int MatNumSh;     // Material number of shade/blind layer
    3560              :         int nglassfaces;  // Number of glass faces in construction
    3561              :         Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
    3562              :         //   air flow or top for downward air flow (K)
    3563              :         Real64 TGlassFace; // Temperature of glass surface facing glass-shade/blind gap (K)
    3564              :         Real64 TShadeFace; // Temperature of shade surface facing glass-shade/blind gap (K)
    3565              :         Real64 hGapStill;  // Still-air glass-shade/blind gap conduction/convection coeff (W/m2-K)
    3566              :         Real64 TGapOld;    // Previous-iteration average air temp in glass-shade/blind gap (K)
    3567              :         Real64 GapHeight;  // Vertical length of glass-shade/blind gap (m)
    3568              :         Real64 GapDepth;   // Distance from shade to glass (m)
    3569              :         Real64 RhoAir;     // Density of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
    3570              :         Real64 RhoTRef;    // Density of glass-shade/blind air at reference temp = KelvinConv (kg/m3)
    3571              :         Real64 ViscAir;    // Viscosity of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
    3572              :         Real64 AGap;       // Cross sectional area of glass-shade/blind gap (m2); for vertical window, this
    3573              :         //   is in horizontal plane normal to window.
    3574              :         Real64 ATopGap; // Area of the top and bottom openings (m2)
    3575              :         Real64 ABotGap;
    3576              :         Real64 ALeftGap; // Area of the left and right openings (m2)
    3577              :         Real64 ARightGap;
    3578              :         Real64 AHolesGap; // Area of the holes in the shade (assumed homogeneously
    3579              :         //   distributed) (m2)
    3580              :         Real64 ATopLRH; // Intermediate variables
    3581              :         Real64 ABotLRH;
    3582              :         Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
    3583              :         Real64 AEqOutlet;
    3584              :         Real64 Zinlet; // Inlet and outlet pressure loss factors
    3585              :         Real64 Zoutlet;
    3586              :         Real64 AVGap;         // Coeff. of VGap**2 term in pressure balance equation
    3587              :         Real64 BVGap;         // Coeff. of VGap term in pressure balance equation
    3588              :         Real64 CVGap;         // VGap-independent term in pressure balance equation
    3589              :         Real64 GapHeightChar; // Characteristic height of the gap air temperature profile (m)
    3590              :         Real64 TAve;          // Average of TGlass and TShade (K)
    3591              :         // REAL(r64)            :: AirProps(8)         ! Air properties
    3592              :         int TotGaps;              // Glass/glass gaps + glass-shade/blind gap
    3593              :         Real64 con;               // Gap conductivity and derivative
    3594              :         Real64 gr;                // glass-shade/blind gap Grashof number
    3595              :         Real64 pr;                // glass-shade/blind gap Prandtl number
    3596              :         Real64 nu;                // glass-shade/blind gap Nusselt number
    3597              :         WinShadingType ShadeFlag; // Shading flag
    3598              : 
    3599            0 :         auto &s_mat = state.dataMaterial;
    3600            0 :         auto &s_surf = state.dataSurface;
    3601            0 :         auto &wm = state.dataWindowManager;
    3602              : 
    3603            0 :         auto &surf = s_surf->Surface(SurfNum);
    3604              : 
    3605              :         // Air properties
    3606              :         //               Dens  dDens/dT  Con    dCon/dT   Vis    dVis/dT Prandtl dPrandtl/dT
    3607              :         // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72,   1.8d-3  /
    3608              : 
    3609            0 :         ConstrNumSh = s_surf->SurfWinActiveShadedConstruction(SurfNum);
    3610            0 :         ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    3611            0 :         nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
    3612            0 :         TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
    3613              : 
    3614            0 :         if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind
    3615            0 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces);
    3616            0 :             TGapInlet = wm->tin;
    3617            0 :             TGlassFace = wm->thetas[nglassfaces - 1];
    3618            0 :             TShadeFace = wm->thetas[nglassfaces];
    3619              :         } else { // Exterior shade, screen or blind
    3620            0 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
    3621            0 :             TGapInlet = wm->tout;
    3622            0 :             TGlassFace = wm->thetas[0];
    3623            0 :             TShadeFace = wm->thetas[nglassfaces + 1];
    3624              :         }
    3625            0 :         TAve = 0.5 * (TGlassFace + TShadeFace);
    3626              : 
    3627            0 :         if (iter == 0) {
    3628            0 :             TGapOld = 0.5 * (TAve + TGapInlet);
    3629              :         } else {
    3630            0 :             TGapOld = TGapNew;
    3631              :         }
    3632              : 
    3633              :         // Conductance of gap between glass and shade assuming gap is sealed
    3634            0 :         WindowGasConductance(state, TGlassFace, TShadeFace, TotGaps, con, pr, gr);
    3635            0 :         NusseltNumber(state, SurfNum, TGlassFace, TShadeFace, TotGaps, gr, pr, nu);
    3636            0 :         hGapStill = con / wm->gaps[TotGaps - 1].width * nu;
    3637              : 
    3638              :         // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
    3639              :         // there is no air flow thru gap
    3640              : 
    3641            0 :         if (std::abs(surf.SinTilt) < 0.0872) {
    3642            0 :             VGap = 0.0;
    3643            0 :             hcv = 2.0 * hGapStill;
    3644            0 :             QConvGap = 0.0;
    3645            0 :             TGapNew = TAve;
    3646            0 :             TGapOutlet = TAve;
    3647            0 :             return;
    3648              :         }
    3649              : 
    3650            0 :         GapHeight = surf.Height;
    3651              : 
    3652            0 :         auto const *matShadingDevice = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(MatNumSh));
    3653            0 :         assert(matShadingDevice != nullptr);
    3654              : 
    3655            0 :         GapDepth = matShadingDevice->toGlassDist;
    3656            0 :         AGap = GapDepth * surf.Width;
    3657            0 :         ATopGap = matShadingDevice->topOpeningMult * AGap;
    3658            0 :         ABotGap = matShadingDevice->bottomOpeningMult * AGap;
    3659            0 :         ALeftGap = matShadingDevice->leftOpeningMult * GapHeight * GapDepth;
    3660            0 :         ARightGap = matShadingDevice->rightOpeningMult * GapHeight * GapDepth;
    3661              :         // For blinds, airFlowPermeability depends on slat angle which is a property of the surface, not the material
    3662            0 :         if (matShadingDevice->group == Material::Group::Blind) {
    3663            0 :             AHolesGap = s_surf->surfShades(SurfNum).blind.airFlowPermeability * GapHeight * surf.Width;
    3664              :         } else {
    3665            0 :             AHolesGap = matShadingDevice->airFlowPermeability * GapHeight * surf.Width;
    3666              :         }
    3667              : 
    3668            0 :         RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
    3669            0 :         ViscAir = wm->AirProps[4] + wm->AirProps[5] * (TGapOld - Constant::Kelvin);
    3670              :         // The factor 12 in the next line is based on the solution of steady laminar flow between fixed
    3671              :         // parallel plates given in Sec. 6.9.1 of Fundamentals of Fluid Mechanics, Munson/Young/Okishi, Third Edition
    3672              :         // Update, John Wiley & Sons, 1998; ISO 15099 has 8 for this factor, which is for flow through a tube.
    3673            0 :         BVGap = 12.0 * ViscAir * GapHeight / pow_2(GapDepth);
    3674              :         // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
    3675              :         // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
    3676              :         // bottom and top but possibly open at left side, right side and/or in-shade/blind)
    3677            0 :         ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    3678            0 :         ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    3679            0 :         if (TGapOld > TGapInlet) {
    3680            0 :             AEqInlet = ABotGap + ATopLRH;
    3681            0 :             AEqOutlet = ATopGap + ABotLRH;
    3682              :         } else {
    3683            0 :             AEqOutlet = ABotGap + ATopLRH;
    3684            0 :             AEqInlet = ATopGap + ABotLRH;
    3685              :         }
    3686              :         // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
    3687              :         // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
    3688              :         // when there is no inlet and/or outlet for air. This then reduces to the
    3689              :         // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
    3690            0 :         Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
    3691            0 :         Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
    3692            0 :         AVGap = 0.5 * RhoAir * (1 + Zinlet + Zoutlet);
    3693            0 :         RhoTRef = wm->AirProps[0] * Constant::Kelvin;
    3694            0 :         CVGap = RhoTRef * 9.81 * GapHeight * s_surf->Surface(SurfNum).SinTilt * (TGapOld - TGapInlet) / (TGapOld * TGapInlet);
    3695              : 
    3696              :         // Solution of quadratic equation in VGap
    3697            0 :         VGap = (std::sqrt(pow_2(BVGap) + std::abs(4.0 * AVGap * CVGap)) - BVGap) / (2.0 * AVGap);
    3698            0 :         hcv = 2.0 * hGapStill + 4.0 * VGap;
    3699            0 :         GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
    3700              :         // The following avoids divide by zero and exponential underflow
    3701            0 :         if (GapHeightChar == 0.0) {
    3702            0 :             TGapOutlet = TAve;
    3703            0 :         } else if ((GapHeight / GapHeightChar) > 15.0) {
    3704            0 :             TGapOutlet = TAve;
    3705              :         } else {
    3706            0 :             TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
    3707              :         }
    3708            0 :         TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
    3709              : 
    3710              :         // Convective heat flow from gap to room air for interior shade or blind
    3711            0 :         if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3712            0 :             RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
    3713            0 :             QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
    3714              :             // Exclude convection to gap due to divider, if present; divider convection handled
    3715              :             // separately in CalcWinFrameAndDividerTemps
    3716            0 :             QConvGap *= 0.5 * (1.0 + s_surf->Surface(SurfNum).Area / (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)));
    3717              :         }
    3718              :     }
    3719              : 
    3720              :     //****************************************************************************
    3721              : 
    3722            0 :     void BetweenGlassShadeNaturalFlow(EnergyPlusData &state,
    3723              :                                       int const SurfNum,       // Surface number
    3724              :                                       int const iter,          // Iteration number for glass heat balance calculation
    3725              :                                       Real64 &VGap,            // Gas velocity in gaps (m/s)
    3726              :                                       Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
    3727              :                                       Array1A<Real64> hcv      // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
    3728              :     )
    3729              :     {
    3730              : 
    3731              :         // SUBROUTINE INFORMATION:
    3732              :         //       AUTHOR         F. Winkelmann
    3733              :         //       DATE WRITTEN   December 2002
    3734              :         //       MODIFIED       na
    3735              :         //       RE-ENGINEERED  na
    3736              : 
    3737              :         // PURPOSE OF THIS SUBROUTINE:
    3738              :         // Called by SolveForWindowTemperatures for windows that have a
    3739              :         // between-glass shade or blind in place.
    3740              :         // Solves for gas flow in the two gaps on either side of shade/blind.
    3741              :         // Finds average temperature of gas in the two gaps, and the coefficient
    3742              :         // for convective heat transfer from glass to gap gas and shade/blind to gap gas
    3743              :         // for the two gaps. The two gaps are assumed to have the same depth so that the
    3744              :         // gas velocity due to natural convection is the same in the two gaps.
    3745              :         // The Between-glass shade/blind is between the two glass layers of double glazing
    3746              :         // or between the two inner glass layers of triple glazing. The quadruple glazing
    3747              :         // case is not considered.
    3748              : 
    3749              :         // METHODOLOGY EMPLOYED:
    3750              :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    3751              :         // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
    3752              : 
    3753              :         // Argument array dimensioning
    3754            0 :         TGapNew.dim(2);
    3755            0 :         hcv.dim(2);
    3756              : 
    3757              :         int ConstrNumSh; // Shaded construction number
    3758              :         int MatNumSh;    // Material number of shade/blind layer
    3759              :         // In the following, "gaps" refer to the gaps on either side of the shade/blind
    3760            0 :         Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
    3761            0 :         Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
    3762            0 :         Array1D<Real64> hGapStill(2);  // Still-air conduction/convection coeffs for the gaps (W/m2-K)
    3763            0 :         Array1D<Real64> TGapOld(2);    // Previous-iteration average gas temp in gaps (K)
    3764              :         Real64 GapHeight;              // Vertical length of glass-shade/blind gap (m)
    3765              :         Real64 GapDepth;               // Distance from shade/blind to glass; assumed same for both gaps (m)
    3766            0 :         Array1D<Real64> RhoGas(2);     // Density of gap gas at a temperature of TGapOld (kg/m3)
    3767              :         Real64 RhoTRef;                // Density of gap gas at reference temp = KelvinConvK (kg/m3)
    3768            0 :         Array1D<Real64> ViscGas(2);    // Viscosity of gap gas at a temperature of TGapOld (kg/m3)
    3769              :         Real64 RhoGasZero;             // Gas density at KelvinConvK
    3770              :         Real64 ViscGasZero;            // Gas viscosity at KelvinConvK (not used)
    3771              :         Real64 AGap;                   // Cross sectional area of gaps (m2); for vertical window, this
    3772              :         //   is in horizontal plane normal to window.
    3773              :         Real64 ATopGap; // Area of the top and bottom openings of shade/blind (m2)
    3774              :         Real64 ABotGap;
    3775              :         Real64 ALeftGap; // Area of the left and right openings of shade/blind (m2)
    3776              :         Real64 ARightGap;
    3777              :         Real64 AHolesGap; // Area of the holes in the shade/blind (assumed homogeneously
    3778              :         //   distributed) (m2)
    3779              :         Real64 ATopLRH; // Intermediate variables
    3780              :         Real64 ABotLRH;
    3781              :         Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
    3782              :         Real64 AEqOutlet;
    3783              :         Real64 Zinlet; // Inlet and outlet pressure loss factors
    3784              :         Real64 Zoutlet;
    3785              :         Real64 AVGap;                     // Coeff. of VGap**2 term in pressure balance equation
    3786              :         Real64 BVGap;                     // Coeff. of VGap term in pressure balance equation
    3787              :         Real64 CVGap;                     // VGap-independent term in pressure balance equation
    3788            0 :         Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap gas temperature profile (m)
    3789            0 :         Array1D<Real64> EpsChar(2);       // EXP(-GapHeight/GapHeightChar(IGap))
    3790            0 :         Array1D<Real64> TAve(2);          // Average of TGlass and TShade for the gaps (K)
    3791              :         Real64 con;                       // Gap gas conductivity and derivative
    3792              :         Real64 gr;                        // Gap gas Grashof number
    3793              :         Real64 pr;                        // Gap gas Prandtl number
    3794              :         Real64 nu;                        // Gap gas Nusselt number
    3795              :         WinShadingType ShadeFlag;         // Shading flag
    3796              :         int IGapInc;                      // Gap increment (0 or 1)
    3797              : 
    3798            0 :         auto &wm = state.dataWindowManager;
    3799            0 :         auto &s_mat = state.dataMaterial;
    3800            0 :         auto &s_surf = state.dataSurface;
    3801              : 
    3802            0 :         auto &surf = s_surf->Surface(SurfNum);
    3803              : 
    3804            0 :         ConstrNumSh = surf.activeShadedConstruction;
    3805            0 :         ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    3806              : 
    3807            0 :         if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
    3808            0 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
    3809            0 :             IGapInc = 0;
    3810            0 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    3811            0 :                 TGlassFace(IGap) = wm->thetas[IGap];
    3812            0 :                 TShadeFace(IGap) = wm->thetas[IGap + 3];
    3813              :             }
    3814              :         } else { // Triple glazing
    3815            0 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
    3816            0 :             IGapInc = 1;
    3817            0 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    3818            0 :                 TGlassFace(IGap) = wm->thetas[IGap + 2];
    3819            0 :                 TShadeFace(IGap) = wm->thetas[IGap + 5];
    3820              :             }
    3821              :         }
    3822              : 
    3823            0 :         auto const *matShadingDevice = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(MatNumSh));
    3824              : 
    3825            0 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    3826            0 :             TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
    3827            0 :             if (iter == 0) {
    3828            0 :                 TGapOld(IGap) = TAve(IGap);
    3829              :             } else {
    3830            0 :                 TGapOld(IGap) = TGapNew(IGap);
    3831              :             }
    3832              :             // Conductance of gaps on either side of shade/blind assuming gaps are sealed
    3833            0 :             WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
    3834            0 :             NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
    3835            0 :             hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
    3836              :         }
    3837              : 
    3838              :         // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
    3839              :         // there is no air flow thru gap
    3840              : 
    3841            0 :         if (std::abs(s_surf->Surface(SurfNum).SinTilt) < 0.0872) {
    3842            0 :             VGap = 0.0;
    3843            0 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    3844            0 :                 hcv(IGap) = 2.0 * hGapStill(IGap);
    3845            0 :                 TGapNew(IGap) = TAve(IGap);
    3846              :             }
    3847            0 :             return;
    3848              :         }
    3849              : 
    3850            0 :         GapHeight = s_surf->Surface(SurfNum).Height;
    3851            0 :         GapDepth = wm->gaps[IGapInc].width;
    3852            0 :         AGap = GapDepth * s_surf->Surface(SurfNum).Width;
    3853              : 
    3854            0 :         ATopGap = matShadingDevice->topOpeningMult * AGap;
    3855            0 :         ABotGap = matShadingDevice->bottomOpeningMult * AGap;
    3856            0 :         ALeftGap = matShadingDevice->leftOpeningMult * GapHeight * GapDepth;
    3857            0 :         ARightGap = matShadingDevice->rightOpeningMult * GapHeight * GapDepth;
    3858              :         // For blinds, airFlowPermeability depends on slat angle which is a property of the surface, not the material
    3859            0 :         if (matShadingDevice->group == Material::Group::Blind) {
    3860            0 :             AHolesGap = s_surf->surfShades(SurfNum).blind.airFlowPermeability * GapHeight * surf.Width;
    3861              :         } else {
    3862            0 :             AHolesGap = matShadingDevice->airFlowPermeability * GapHeight * surf.Width;
    3863              :         }
    3864              : 
    3865            0 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    3866            0 :             WindowGasPropertiesAtTemp(state, TGapOld(IGap), IGap + IGapInc, RhoGas(IGap), ViscGas(IGap));
    3867              :         }
    3868              : 
    3869            0 :         BVGap = 12.0 * (ViscGas(1) + ViscGas(2)) * GapHeight / pow_2(GapDepth);
    3870              :         // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
    3871              :         // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
    3872              :         // bottom and top but possibly open at left side, right side and/or in shade/blind)
    3873            0 :         ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    3874            0 :         ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    3875            0 :         AEqInlet = ABotGap + ATopLRH;
    3876            0 :         AEqOutlet = ATopGap + ABotLRH;
    3877              : 
    3878              :         // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
    3879              :         // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
    3880              :         // when there is no inlet and/or outlet for air. This then reduces to the
    3881              :         // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
    3882            0 :         Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
    3883            0 :         Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
    3884            0 :         AVGap = 0.5 * (RhoGas(1) + RhoGas(2)) * (1.0 + Zinlet + Zoutlet);
    3885            0 :         WindowGasPropertiesAtTemp(state, Constant::Kelvin, 1 + IGapInc, RhoGasZero, ViscGasZero);
    3886            0 :         RhoTRef = RhoGasZero * Constant::Kelvin;
    3887            0 :         CVGap = RhoTRef * 9.81 * GapHeight * s_surf->Surface(SurfNum).SinTilt * (TGapOld(1) - TGapOld(2)) / (TGapOld(1) * TGapOld(2));
    3888              : 
    3889              :         // Solution of quadratic equation in VGap
    3890              : 
    3891            0 :         VGap = (std::sqrt(pow_2(BVGap) + std::abs(4 * AVGap * CVGap)) - BVGap) / (2 * AVGap);
    3892              : 
    3893            0 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    3894            0 :             hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
    3895            0 :             GapHeightChar(IGap) = RhoGas(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
    3896              :             // The following avoids divide by zero and exponential underflow
    3897            0 :             if (GapHeightChar(IGap) == 0.0) {
    3898            0 :                 EpsChar(IGap) = 0.0;
    3899            0 :             } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
    3900            0 :                 EpsChar(IGap) = 0.0;
    3901              :             } else {
    3902            0 :                 EpsChar(IGap) = std::exp(-GapHeight / GapHeightChar(IGap));
    3903              :             }
    3904              :         }
    3905              : 
    3906            0 :         TGapNew(1) =
    3907            0 :             TAve(1) - (TAve(1) - TAve(2)) * (GapHeightChar(1) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
    3908              : 
    3909            0 :         TGapNew(2) =
    3910            0 :             TAve(2) - (TAve(2) - TAve(1)) * (GapHeightChar(2) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
    3911            0 :     }
    3912              : 
    3913              :     //****************************************************************************
    3914              : 
    3915            0 :     void BetweenGlassForcedFlow(EnergyPlusData &state,
    3916              :                                 int const SurfNum,  // Surface number
    3917              :                                 int const iter,     // Iteration number for glass heat balance calculation
    3918              :                                 Real64 &VGap,       // Air velocity in airflow gap (m/s)
    3919              :                                 Real64 &TGapNew,    // Current-iteration average air temp in airflow gap (K)
    3920              :                                 Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
    3921              :                                 Real64 &hcv,        // Convection coefficient from gap glass faces to gap air (W/m2-K)
    3922              :                                 Real64 &QConvGap    // Convective heat gain from air flow gap (W)
    3923              :     )
    3924              :     {
    3925              : 
    3926              :         // SUBROUTINE INFORMATION:
    3927              :         //       AUTHOR         F. Winkelmann
    3928              :         //       DATE WRITTEN   February 2003
    3929              :         //       MODIFIED       na
    3930              :         //       RE-ENGINEERED  na
    3931              : 
    3932              :         // PURPOSE OF THIS SUBROUTINE:
    3933              :         // Called by SolveForWindowTemperatures for "airflow windows",i.e., windows
    3934              :         // with forced airflow in one of the gaps between layers of glass. Based on
    3935              :         // the velocity of airflow through gap, finds effective temperature of gap air,
    3936              :         // convective heat transfer coefficient from glass to gap air,
    3937              :         // the gap outlet temperature, and the outlet convective heat flow.
    3938              : 
    3939              :         // Called only for double and triple glazing. For triple glazing the airflow
    3940              :         // is assumed to be between the inner two layers of glass (glass layers 2 and 3).
    3941              : 
    3942              :         // METHODOLOGY EMPLOYED:
    3943              :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    3944              :         // Detailed Calculations"
    3945              : 
    3946              :         // Locals
    3947              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    3948              :         //   air flow or bottom for downward air flow (K)
    3949              : 
    3950              :         int ConstrNum;    // Construction number of surface
    3951              :         int NGlass;       // Number of glass layers in construction
    3952              :         int GapNum;       // Number of airflow gap
    3953              :         Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
    3954              :         //   air flow or top for downward air flow (K)
    3955              :         Real64 TGlassFace1; // Temperature of left-hand glass surface facing airflow gap (K)
    3956              :         Real64 TGlassFace2; // Temperature of right-hand glass surface facing airflow gap (K)
    3957              :         Real64 hGapStill;   // Still-air gap conduction/convection coeff (W/m2-K)
    3958              :         Real64 TGapOld;     // Previous-iteration average air temp in airflow gap (K)
    3959              :         Real64 GapHeight;   // Vertical length of airflow gap (m)
    3960              :         Real64 GapDepth;    // Thickness of airflow gap (m)
    3961              :         Real64 RhoAir;      // Density of airflow gap air at a temperature of TGapOld (kg/m3)
    3962              :         Real64 AGap;        // Cross sectional area of airflow gap (m2); for vertical window, this
    3963              :         //   is in horizontal plane normal to window.
    3964              :         Real64 GapHeightChar; // Characteristic height of the airflow gap air temperature profile (m)
    3965              :         Real64 TAve;          // Average of TGlassFace1 and TGlassFace2 (K)
    3966              :         // REAL(r64)            :: AirProps(8)         ! Air properties
    3967              :         Real64 con; // Gap conductivity and derivative
    3968              :         Real64 gr;  // Gap air Grashof number
    3969              :         Real64 pr;  // Gap air Prandtl number
    3970              :         Real64 nu;  // Gap air Nusselt number
    3971              : 
    3972              :         // Air properties
    3973              :         //               Dens  dDens/dT  Con    dCon/dT   Vis    dVis/dT Prandtl dPrandtl/dT
    3974              :         // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72,   1.8d-3  /
    3975              : 
    3976            0 :         auto &s_mat = state.dataMaterial;
    3977            0 :         auto &s_surf = state.dataSurface;
    3978            0 :         auto const &wm = state.dataWindowManager;
    3979              : 
    3980            0 :         auto const &surf = s_surf->Surface(SurfNum);
    3981              : 
    3982            0 :         ConstrNum = surf.Construction;
    3983            0 :         NGlass = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    3984            0 :         TGlassFace1 = wm->thetas[2 * NGlass - 3];
    3985            0 :         TGlassFace2 = wm->thetas[2 * NGlass - 2];
    3986            0 :         GapNum = NGlass - 1;
    3987            0 :         TAve = 0.5 * (TGlassFace1 + TGlassFace2);
    3988              : 
    3989            0 :         if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    3990            0 :             TGapInlet = wm->tin; // Source is inside air
    3991              :         } else {
    3992            0 :             TGapInlet = wm->tout; // Source is outside air
    3993              :         }
    3994              : 
    3995            0 :         if (iter == 0) {
    3996            0 :             TGapOld = 0.5 * (TAve + TGapInlet);
    3997              :         } else {
    3998            0 :             TGapOld = TGapNew;
    3999              :         }
    4000              : 
    4001              :         // Conductance of gap assuming it is sealed
    4002            0 :         WindowGasConductance(state, TGlassFace1, TGlassFace2, GapNum, con, pr, gr);
    4003            0 :         NusseltNumber(state, SurfNum, TGlassFace1, TGlassFace2, GapNum, gr, pr, nu);
    4004            0 :         hGapStill = con / wm->gaps[GapNum - 1].width * nu;
    4005            0 :         GapHeight = surf.Height;
    4006            0 :         GapDepth = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * NGlass - 2))->Thickness;
    4007            0 :         AGap = GapDepth * surf.Width;
    4008            0 :         VGap = s_surf->SurfWinAirflowThisTS(SurfNum) / GapDepth;
    4009            0 :         hcv = 2.0 * hGapStill + 4.0 * VGap;
    4010            0 :         RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
    4011            0 :         GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
    4012              :         // The following avoids divide by zero and exponential underflow
    4013            0 :         if (GapHeightChar == 0.0) {
    4014            0 :             TGapOutlet = TAve;
    4015            0 :         } else if ((GapHeight / GapHeightChar) > 15.0) {
    4016            0 :             TGapOutlet = TAve;
    4017              :         } else {
    4018            0 :             TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
    4019              :         }
    4020            0 :         TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
    4021              :         // Convective heat flow from gap [W]
    4022            0 :         RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
    4023            0 :         QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
    4024            0 :     } // BetweenGlassForcedFlow()
    4025              : 
    4026              :     //****************************************************************************
    4027              : 
    4028            0 :     void BetweenGlassShadeForcedFlow(EnergyPlusData &state,
    4029              :                                      int const SurfNum,       // Surface number
    4030              :                                      int const iter,          // Iteration number for glass heat balance calculation
    4031              :                                      Real64 &VGap,            // Air velocity in each gap (m/s)
    4032              :                                      Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
    4033              :                                      Real64 &TGapOutletAve,   // Average of TGapOutlet(1) and TGapOutlet(2) (K)
    4034              :                                      Array1A<Real64> hcv,     // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
    4035              :                                      Real64 &QConvTot         // Sum of convective heat flow from gaps (W)
    4036              :     )
    4037              :     {
    4038              : 
    4039              :         // SUBROUTINE INFORMATION:
    4040              :         //       AUTHOR         F. Winkelmann
    4041              :         //       DATE WRITTEN   February 2003
    4042              :         //       MODIFIED       na
    4043              :         //       RE-ENGINEERED  na
    4044              : 
    4045              :         // PURPOSE OF THIS SUBROUTINE:
    4046              :         // Called by SolveForWindowTemperatures for airflow windows with a
    4047              :         // between-glass shade or blind over which fan-forced air flows.
    4048              :         // Based on the air flow velocity (which is assumed to be the same in the
    4049              :         // gaps on either side of the shade/blind), finds, for each gap: the average
    4050              :         // air temperature, the shade/blind or glass surface to air convective heat
    4051              :         // transfer coefficient, the gap outlet temperature, and the outlet convective heat flow.
    4052              : 
    4053              :         // Called only for double and triple glazing. For triple glazing the airflow
    4054              :         // is assumed to be between the inner two layers of glass (glass layers 2 and 3),
    4055              :         // between which the shade/blind is located.
    4056              : 
    4057              :         // METHODOLOGY EMPLOYED:
    4058              :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    4059              :         // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
    4060              : 
    4061              :         // Argument array dimensioning
    4062            0 :         TGapNew.dim(2);
    4063            0 :         hcv.dim(2);
    4064              : 
    4065              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4066              :         int ConstrNumSh; // Shaded construction number
    4067              :         // In the following, "gaps" refer to the gaps on either side of the shade/blind
    4068            0 :         Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
    4069            0 :         Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
    4070            0 :         Array1D<Real64> hGapStill(2);  // Still-air conduction/convection coeffs for the gaps (W/m2-K)
    4071            0 :         Array1D<Real64> TGapOld(2);    // Previous-iteration average gas temp in gaps (K)
    4072              :         Real64 GapHeight;              // Vertical length of glass-shade/blind gap (m)
    4073              :         Real64 GapDepth;               // Distance from shade/blind to glass; assumed same for both gaps (m)
    4074            0 :         Array1D<Real64> RhoAir(2);     // Density of gap air (kg/m3)
    4075              :         Real64 AGap;                   // Cross sectional area of each gap (m2); for vertical window, this
    4076              :         //   is in horizontal plane normal to window.
    4077              :         Real64 TGapInlet;                 // Gap inlet air temperature (K)
    4078            0 :         Array1D<Real64> TGapOutlet(2);    // Gap outlet air temperature (K)
    4079            0 :         Array1D<Real64> QConvGap(2);      // Convective heat flow from each gap (W)
    4080            0 :         Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap air temperature profile (m)
    4081            0 :         Array1D<Real64> TAve(2);          // Average of TGlass and TShade for the gaps (K)
    4082              :         Real64 con;                       // Gap air conductivity and derivative
    4083              :         Real64 gr;                        // Gap air Grashof number
    4084              :         Real64 pr;                        // Gap air Prandtl number
    4085              :         Real64 nu;                        // Gap air Nusselt number
    4086              :         WinShadingType ShadeFlag;         // Shading flag
    4087              :         int IGapInc;                      // Gap increment; =0, double glass, =1, triple glass
    4088              :         // REAL(r64)            :: AirProps(8)         ! Air properties
    4089              : 
    4090            0 :         auto &s_surf = state.dataSurface;
    4091            0 :         auto const &wm = state.dataWindowManager;
    4092              : 
    4093              :         // Air properties
    4094              :         //               Dens  dDens/dT  Con    dCon/dT   Vis    dVis/dT Prandtl dPrandtl/dT
    4095              :         // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72,   1.8d-3  /
    4096              : 
    4097            0 :         ConstrNumSh = s_surf->Surface(SurfNum).activeShadedConstruction;
    4098            0 :         ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    4099              : 
    4100            0 :         if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
    4101            0 :             IGapInc = 0;
    4102            0 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4103            0 :                 TGlassFace(IGap) = wm->thetas[IGap];
    4104            0 :                 TShadeFace(IGap) = wm->thetas[IGap + 3];
    4105              :             }
    4106              :         } else { // Triple glazing
    4107            0 :             IGapInc = 1;
    4108            0 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4109            0 :                 TGlassFace(IGap) = wm->thetas[IGap + 2];
    4110            0 :                 TShadeFace(IGap) = wm->thetas[IGap + 5];
    4111              :             }
    4112              :         }
    4113              : 
    4114            0 :         if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    4115            0 :             TGapInlet = wm->tin;
    4116              :         } else {
    4117            0 :             TGapInlet = wm->tout;
    4118              :         }
    4119              : 
    4120            0 :         GapHeight = s_surf->Surface(SurfNum).Height;
    4121            0 :         GapDepth = wm->gaps[IGapInc].width;
    4122            0 :         AGap = GapDepth * s_surf->Surface(SurfNum).Width;
    4123              :         // Factor of 2 below assumes gaps on either side of shade/blind have same depth
    4124            0 :         VGap = s_surf->SurfWinAirflowThisTS(SurfNum) / (2.0 * GapDepth);
    4125              : 
    4126            0 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    4127            0 :             TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
    4128            0 :             if (iter == 0) {
    4129            0 :                 TGapOld(IGap) = TAve(IGap);
    4130              :             } else {
    4131            0 :                 TGapOld(IGap) = TGapNew(IGap);
    4132              :             }
    4133              :             // Conductance of gaps on either side of shade/blind assuming gaps are sealed
    4134            0 :             WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
    4135            0 :             NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
    4136            0 :             hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
    4137              :             // Shade/blind or glass surface to air convection coefficient
    4138            0 :             hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
    4139            0 :             RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapOld(IGap) - Constant::Kelvin);
    4140            0 :             hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
    4141            0 :             GapHeightChar(IGap) = RhoAir(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
    4142              :             // The following avoids divide by zero and exponential underflow
    4143            0 :             if (GapHeightChar(IGap) == 0.0) {
    4144            0 :                 TGapOutlet(IGap) = TAve(IGap);
    4145            0 :             } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
    4146            0 :                 TGapOutlet(IGap) = TAve(IGap);
    4147              :             } else {
    4148            0 :                 TGapOutlet(IGap) = TAve(IGap) - (TAve(IGap) - TGapInlet) * std::exp(-GapHeight / GapHeightChar(IGap));
    4149              :             }
    4150            0 :             TGapNew(IGap) = TAve(IGap) - (GapHeightChar(IGap) / GapHeight) * (TGapOutlet(IGap) - TGapInlet);
    4151              :             // Convective heat flow from gap [W]
    4152            0 :             RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapNew(IGap) - Constant::Kelvin);
    4153            0 :             QConvGap(IGap) = RhoAir(IGap) * AGap * VGap * 1008.0 * (TGapOutlet(IGap) - TGapInlet);
    4154              :         }
    4155              : 
    4156            0 :         QConvTot = QConvGap(1) + QConvGap(2);
    4157            0 :         TGapOutletAve = 0.5 * (TGapOutlet(1) + TGapOutlet(2));
    4158            0 :     } // BetweenGlassShadeForcedFlow()
    4159              : 
    4160              :     //****************************************************************************
    4161              : 
    4162       204621 :     void LUdecomposition(EnergyPlusData &state,
    4163              :                          Array2<Real64> &ajac, // As input: matrix to be decomposed;
    4164              :                          int const n,          // Dimension of matrix
    4165              :                          Array1D_int &indx,    // Vector of row permutations
    4166              :                          int &d                // +1 if even number of row interchange is even, -1
    4167              :     )
    4168              :     {
    4169              : 
    4170              :         // SUBROUTINE INFORMATION:
    4171              :         //       AUTHOR         F. Winkelmann, adapted from Numerical Recipes
    4172              :         //       DATE WRITTEN   February 2000
    4173              : 
    4174              :         // PURPOSE OF THIS SUBROUTINE:
    4175              :         // Performs LU decomposition of a matrix.
    4176              : 
    4177              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    4178              :         //   as output: decomposed matrix
    4179              :         //   if odd
    4180              : 
    4181              :         int imax; // Temporary variable
    4182              :         //   as output: decomposed matrix
    4183              : 
    4184       204621 :         assert(n <= 10);                   // vv sizing
    4185       204621 :         std::array<Real64, 10> vv = {0.0}; // Stores the implicit scaling of each row
    4186              : 
    4187       204621 :         d = 1;
    4188       803903 :         for (int i = 1; i <= n; ++i) {
    4189       599282 :             Real64 aamax = 0.0;
    4190      2558006 :             for (int j = 1; j <= n; ++j) {
    4191      1958724 :                 if (std::abs(ajac(j, i)) > aamax) aamax = std::abs(ajac(j, i));
    4192              :             }
    4193       599282 :             if (aamax == 0.0) ShowFatalError(state, "Singular matrix in LUdecomposition, window calculations");
    4194       599282 :             vv[i - 1] = 1.0 / aamax;
    4195              :         }
    4196       803903 :         for (int j = 1; j <= n; ++j) {
    4197      1279003 :             for (int i = 1; i <= j - 1; ++i) {
    4198       679721 :                 Real64 sum = ajac(j, i);
    4199      1059801 :                 for (int k = 1; k <= i - 1; ++k) {
    4200       380080 :                     sum -= ajac(k, i) * ajac(j, k);
    4201              :                 }
    4202       679721 :                 ajac(j, i) = sum;
    4203              :             }
    4204       599282 :             Real64 aamax = 0.0;
    4205      1878285 :             for (int i = j; i <= n; ++i) {
    4206      1279003 :                 Real64 sum = ajac(j, i);
    4207      2338804 :                 for (int k = 1; k <= j - 1; ++k) {
    4208      1059801 :                     sum -= ajac(k, i) * ajac(j, k);
    4209              :                 }
    4210      1279003 :                 ajac(j, i) = sum;
    4211      1279003 :                 Real64 dum = vv[i - 1] * std::abs(sum);
    4212      1279003 :                 if (dum >= aamax) {
    4213       599282 :                     imax = i;
    4214       599282 :                     aamax = dum;
    4215              :                 }
    4216              :             }
    4217       599282 :             if (j != imax) {
    4218            0 :                 for (int k = 1; k <= n; ++k) {
    4219            0 :                     Real64 dum = ajac(k, imax);
    4220            0 :                     ajac(k, imax) = ajac(k, j);
    4221            0 :                     ajac(k, j) = dum;
    4222              :                 }
    4223            0 :                 d = -d;
    4224            0 :                 vv[imax - 1] = vv[j - 1];
    4225              :             }
    4226       599282 :             indx(j) = imax;
    4227       599282 :             if (ajac(j, j) == 0.0) ajac(j, j) = Constant::rTinyValue;
    4228       599282 :             if (j != n) {
    4229       394661 :                 Real64 dum = 1.0 / ajac(j, j);
    4230      1074382 :                 for (int i = j + 1; i <= n; ++i) {
    4231       679721 :                     ajac(j, i) *= dum;
    4232              :                 }
    4233              :             }
    4234              :         }
    4235       204621 :     } // LUdecomposition()
    4236              : 
    4237              :     //**************************************************************************
    4238              : 
    4239       368607 :     void LUsolution([[maybe_unused]] EnergyPlusData &state,
    4240              :                     Array2<Real64> const &a, // Matrix and vector in a.x = b;
    4241              :                     int const n,             // Dimension of a and b
    4242              :                     Array1D_int const &indx, // Vector of row permutations
    4243              :                     Array1D<Real64> &b       // Matrix and vector in a.x = b;
    4244              :     )
    4245              :     {
    4246              : 
    4247              :         // SUBROUTINE INFORMATION:
    4248              :         //       AUTHOR         F. Winkelmann, adapted from Numerical Recipes
    4249              :         //       DATE WRITTEN   February 2000
    4250              :         //       MODIFIED       na
    4251              :         //       RE-ENGINEERED  na
    4252              : 
    4253              :         // PURPOSE OF THIS SUBROUTINE:
    4254              :         // Solves set of linear equations a.x = b
    4255              : 
    4256              :         // Locals
    4257              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    4258              :         //   b is also output as the solution, x
    4259              :         //   b is also output as the solution, x
    4260              : 
    4261              :         Real64 sum; // Summation variable
    4262              : 
    4263       368607 :         int ii = 0;
    4264      1623833 :         for (int i = 1; i <= n; ++i) {
    4265      1255226 :             int ll = indx(i);
    4266      1255226 :             sum = b(ll);
    4267      1255226 :             b(ll) = b(i);
    4268      1255226 :             if (ii != 0) {
    4269      1456962 :                 for (int j = ii; j <= i - 1; ++j) {
    4270       898333 :                     sum -= a(j, i) * b(j);
    4271              :                 }
    4272       696597 :             } else if (sum != 0.0) {
    4273       368607 :                 ii = i;
    4274              :             }
    4275      1255226 :             b(i) = sum;
    4276              :         }
    4277      1623833 :         for (int i = n; i >= 1; --i) {
    4278      1255226 :             sum = b(i);
    4279      2918863 :             for (int j = i + 1; j <= n; ++j) {
    4280      1663637 :                 sum -= a(j, i) * b(j);
    4281              :             }
    4282      1255226 :             b(i) = sum / a(i, i);
    4283              :         }
    4284       368607 :     } // LUsolution()
    4285              : 
    4286              :     //******************************************************************************
    4287              : 
    4288        40358 :     void WindowGasConductance(EnergyPlusData &state,
    4289              :                               Real64 const tleft,  // Temperature of gap surface closest to outside (K)
    4290              :                               Real64 const tright, // Temperature of gap surface closest to zone (K)
    4291              :                               int const IGap,      // Gap number
    4292              :                               Real64 &con,         // Gap gas conductance (W/m2-K)
    4293              :                               Real64 &pr,          // Gap gas Prandtl number
    4294              :                               Real64 &gr           // Gap gas Grashof number
    4295              :     )
    4296              :     {
    4297              : 
    4298              :         // SUBROUTINE INFORMATION:
    4299              :         //       AUTHOR         Adapted by Fred Winkelmann from Window5 subroutine gasses
    4300              :         //       DATE WRITTEN   September 2001
    4301              :         //       MODIFIED       na
    4302              :         //       RE-ENGINEERED  na
    4303              : 
    4304              :         // PURPOSE OF THIS SUBROUTINE:
    4305              :         // Find the coefficient of convective/conductive heat transfer in the gas-filled gap
    4306              :         // between isothermal solid layers. The gap may be filled with a single gas or a gas mixture.
    4307              : 
    4308              :         // METHODOLOGY EMPLOYED:
    4309              :         // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
    4310              :         // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
    4311              :         // The equation numbers below correspond to those in the standard.
    4312              : 
    4313              :         // REFERENCES:
    4314              :         // Window5 source code; ISO 15099
    4315              : 
    4316        40358 :         constexpr Real64 pres(1.0e5);     // Gap gas pressure (Pa)
    4317        40358 :         constexpr Real64 gaslaw(8314.51); // Molar gas constant (J/kMol-K)
    4318        40358 :         Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
    4319              : 
    4320              :         int NMix;      // Number of gases in a mixture
    4321              :         Real64 molmix; // Molecular weight of mixture
    4322              : 
    4323        40358 :         auto &wm = state.dataWindowManager;
    4324              : 
    4325              :         Real64 kpmix; // Monotonic thermal conductivity of mixture
    4326              :         Real64 kdpmix;
    4327              :         Real64 kmix;      // For accumulating conductance of gas mixture
    4328              :         Real64 mumix;     // For accumulating viscosity of gas mixture
    4329        40358 :         Real64 visc(0.0); // Dynamic viscosity of mixture at tmean (g/m-s)
    4330        40358 :         Real64 cp(0.0);   // Specific heat of mixture at tmean (J/m3-K)
    4331        40358 :         Real64 dens(0.0); // Density of mixture at tmean (kg/m3)
    4332              :         Real64 cpmixm;    // Gives cp when divided by molmix
    4333              :         Real64 phimup;    // Numerator factor
    4334              :         Real64 downer;    // Denominator factor
    4335              :         Real64 psiup;     // Numerator factor
    4336              :         Real64 psiterm;   // Factor
    4337              :         Real64 phikup;    // Numerator factor
    4338              :         Real64 rhomix;    // Density of gas mixture (kg/m3)
    4339              : 
    4340        40358 :         std::array<Real64, 10> mukpdwn = {0.0}; // Denominator term
    4341        40358 :         std::array<Real64, 10> kpdown = {0.0};  // Denominator terms
    4342        40358 :         std::array<Real64, 10> kdpdown = {0.0};
    4343              :         // Conductivity term accounting for additional energy moved by the diffusional transport of internal energy in polyatomic gases.
    4344        40358 :         std::array<Real64, 10> kdblprm = {0.0};
    4345        40358 :         std::array<Real64, 10> frct = {0.0};   // Fraction of each gas in a mixture
    4346        40358 :         std::array<Real64, 10> kprime = {0.0}; // Monotonic thermal conductivity
    4347              : 
    4348        40358 :         std::array<Real64, 10> fvis = {0.0};  // Viscosity of each gas in a mixture (g/m-s)
    4349        40358 :         std::array<Real64, 10> fcon = {0.0};  // Conductance of each gas in a mixture (W/m2-K)
    4350        40358 :         std::array<Real64, 10> fdens = {0.0}; // Density of each gas in a mixture (kg/m3)
    4351        40358 :         std::array<Real64, 10> fcp = {0.0};   // Specific heat of each gas in a mixture (J/m3-K)
    4352              : 
    4353              :         // Autodesk:Logic Either assert NMix>0 or handle NMix<=0 in logic so that con and locals guar. initialized before use
    4354        40358 :         NMix = wm->gaps[IGap - 1].numGases;
    4355              : 
    4356        80716 :         for (int IMix = 0; IMix < NMix; ++IMix) {
    4357        40358 :             frct[IMix] = wm->gaps[IGap - 1].gasFracts[IMix];
    4358              :         }
    4359              : 
    4360        40358 :         Real64 const tmean(0.5 * (tleft + tright)); // Average gap gas temperature (K)
    4361        40358 :         Real64 const tmean_2(pow_2(tmean));
    4362              : 
    4363        40358 :         auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
    4364        40358 :         fcon[0] = wmgas0.con.c0 + wmgas0.con.c1 * tmean + wmgas0.con.c2 * tmean_2;
    4365        40358 :         fvis[0] = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
    4366        40358 :         fcp[0] = wmgas0.cp.c0 + wmgas0.cp.c1 * tmean + wmgas0.cp.c2 * tmean_2;
    4367        40358 :         fdens[0] = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
    4368              :         //  rho=(presure*molecweight)/(gasconst*tmean)
    4369              : 
    4370        40358 :         if (NMix == 1) { // Single gas
    4371        40358 :             con = fcon[0];
    4372        40358 :             visc = fvis[0];
    4373        40358 :             cp = fcp[0];
    4374        40358 :             dens = fdens[0];
    4375            0 :         } else if (NMix > 1) {                                   // Multiple gases; calculate mixture properties
    4376            0 :             molmix = frct[0] * wmgas0.wght;                      // initialize eq. 56
    4377            0 :             cpmixm = molmix * fcp[0];                            // initialize eq. 58
    4378            0 :             kprime[0] = 3.75 * (gaslaw / wmgas0.wght) * fvis[0]; // eq. 67
    4379            0 :             kdblprm[0] = fcon[0] - kprime[0];                    // eq. 67
    4380              : 
    4381              :             // Initialize summations for eqns 60-66
    4382            0 :             mumix = 0.0;
    4383            0 :             kpmix = 0.0;
    4384            0 :             kdpmix = 0.0;
    4385            0 :             mukpdwn[0] = 1.0;
    4386            0 :             kpdown[0] = 1.0;
    4387            0 :             kdpdown[0] = 1.0;
    4388              : 
    4389              :             // Calculate properties of mixture constituents
    4390            0 :             for (int i = 2; i <= NMix; ++i) {
    4391            0 :                 auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
    4392              : 
    4393            0 :                 fcon[i - 1] = wmgas.con.c0 + wmgas.con.c1 * tmean + wmgas.con.c2 * tmean_2;
    4394            0 :                 fvis[i - 1] = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
    4395            0 :                 fcp[i - 1] = wmgas.cp.c0 + wmgas.cp.c1 * tmean + wmgas.cp.c2 * tmean_2;
    4396            0 :                 molmix += frct[i - 1] * wmgas.wght;                       // eq. 56
    4397            0 :                 cpmixm += frct[i - 1] * fcp[i - 1] * wmgas.wght;          // eq. 58-59
    4398            0 :                 kprime[i - 1] = 3.75 * gaslaw / wmgas.wght * fvis[i - 1]; // eq. 67
    4399            0 :                 kdblprm[i - 1] = fcon[i - 1] - kprime[i - 1];             // eq. 68
    4400            0 :                 mukpdwn[i - 1] = 1.0;                                     // initialize denominator of eq. 60
    4401            0 :                 kpdown[i - 1] = 1.0;                                      // initialize denominator of eq. 63
    4402            0 :                 kdpdown[i - 1] = 1.0;                                     // initialize denominator of eq. 65
    4403              :             }
    4404              : 
    4405            0 :             for (int i = 1; i <= NMix; ++i) {
    4406            0 :                 auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
    4407              : 
    4408            0 :                 for (int j = 1; j <= NMix; ++j) {
    4409            0 :                     auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
    4410              : 
    4411              :                     // numerator of equation 61
    4412            0 :                     phimup = pow_2(1.0 + std::sqrt(fvis[i - 1] / fvis[j - 1]) * root_4(wmgasJ.wght / wmgasI.wght));
    4413              :                     // denominator of eq. 61, 64 and 66
    4414            0 :                     downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
    4415              :                     // calculate the denominator of eq. 60
    4416            0 :                     if (i != j) mukpdwn[i - 1] += phimup / downer * frct[j - 1] / frct[i - 1];
    4417              :                     // numerator of eq. 64; psiterm is the multiplied term in brackets
    4418            0 :                     psiup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
    4419            0 :                     psiterm = 1.0 + 2.41 * (wmgasI.wght - wmgasJ.wght) * (wmgasI.wght - 0.142 * wmgasJ.wght) / pow_2(wmgasI.wght + wmgasJ.wght);
    4420              :                     // using the common denominator, downer, calculate the denominator for eq. 63
    4421            0 :                     if (i != j) kpdown[i - 1] += psiup * (psiterm / downer) * (frct[j - 1] / frct[i - 1]);
    4422              :                     // calculate the numerator of eq. 66
    4423            0 :                     phikup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
    4424              :                     // using the common denominator, downer, calculate the denominator for eq. 65
    4425            0 :                     if (i != j) kdpdown[i - 1] += (phikup / downer) * (frct[j - 1] / frct[i - 1]);
    4426              :                 }
    4427            0 :                 mumix += fvis[i - 1] / mukpdwn[i - 1];     // eq. 60
    4428            0 :                 kpmix += kprime[i - 1] / kpdown[i - 1];    // eq. 63
    4429            0 :                 kdpmix += kdblprm[i - 1] / kdpdown[i - 1]; // eq. 65
    4430              :             }
    4431              : 
    4432              :             // Calculate the density of the mixture assuming an ideal gas
    4433            0 :             rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
    4434            0 :             kmix = kpmix + kdpmix;                     // eq. 68-a
    4435              : 
    4436              :             // Final mixture properties
    4437            0 :             visc = mumix;
    4438            0 :             con = kmix;
    4439            0 :             dens = rhomix;
    4440            0 :             cp = cpmixm / molmix;
    4441              : 
    4442              :         } else {
    4443            0 :             assert(false);
    4444              :         } // End of check if single or multiple gases in gap
    4445              : 
    4446        40358 :         pr = cp * visc / con;
    4447        40358 :         gr = 9.807 * pow_3(wm->gaps[IGap - 1].width) * std::abs(tleft - tright) * pow_2(dens) / (tmean * pow_2(visc));
    4448        40358 :     } // WindowGasConductance()
    4449              : 
    4450              :     //******************************************************************************
    4451              : 
    4452            0 :     void WindowGasPropertiesAtTemp(EnergyPlusData const &state,
    4453              :                                    Real64 const tmean, // Temperature of gas in gap (K)
    4454              :                                    int const IGap,     // Gap number
    4455              :                                    Real64 &dens,       // Gap gas density at tmean (kg/m3)
    4456              :                                    Real64 &visc        // Gap gas dynamic viscosity at tmean (g/m-s)
    4457              :     )
    4458              :     {
    4459              : 
    4460              :         // SUBROUTINE INFORMATION:
    4461              :         //       AUTHOR         F. Winkelmann
    4462              :         //       DATE WRITTEN   December 2002
    4463              :         //       MODIFIED       na
    4464              :         //       RE-ENGINEERED  na
    4465              : 
    4466              :         // PURPOSE OF THIS SUBROUTINE:
    4467              :         // Finds the density and viscosity of the gas in a gap at a particular temperature.
    4468              :         // The gap may be filled with a single gas or a gas mixture.
    4469              :         // Based on Subroutine WindowGasConductance.
    4470              : 
    4471              :         // METHODOLOGY EMPLOYED:
    4472              :         // See Subr. WindowGasConductance
    4473              : 
    4474              :         // REFERENCES:
    4475              :         // See Subr. WindowGasConductance
    4476              : 
    4477            0 :         Real64 constexpr pres(1.0e5);     // Gap gas pressure (Pa)
    4478            0 :         Real64 constexpr gaslaw(8314.51); // Molar gas constant (J/kMol-K)
    4479            0 :         Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
    4480              : 
    4481              :         int NMix;                    // Number of gases in a mixture
    4482              :         Real64 molmix;               // Molecular weight of mixture
    4483            0 :         Array1D<Real64> mukpdwn(10); // Denominator term
    4484              :         Real64 mumix;                // For accumulating viscosity of gas mixture
    4485              :         Real64 phimup;               // Numerator factor
    4486              :         Real64 downer;               // Denominator factor
    4487              :         Real64 rhomix;               // Density of gas mixture (kg/m3)
    4488            0 :         Array1D<Real64> frct(10);    // Fraction of each gas in a mixture
    4489            0 :         Array1D<Real64> fvis(10);    // Viscosity of each gas in a mixture (g/m-s)
    4490            0 :         Array1D<Real64> fdens(10);   // Density of each gas in a mixture (kg/m3)
    4491              : 
    4492            0 :         auto const &wm = state.dataWindowManager;
    4493              : 
    4494            0 :         NMix = wm->gaps[IGap - 1].numGases;
    4495              : 
    4496            0 :         for (int IMix = 1; IMix <= NMix; ++IMix) {
    4497            0 :             frct(IMix) = wm->gaps[IGap - 1].gasFracts[IMix - 1];
    4498              :         }
    4499              : 
    4500            0 :         Real64 const tmean_2(pow_2(tmean));
    4501            0 :         auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
    4502            0 :         fvis(1) = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
    4503            0 :         fdens(1) = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
    4504              :         //  rho=(presure*molecweight)/(gasconst*tmean)
    4505            0 :         if (NMix == 1) { // Single gas
    4506            0 :             visc = fvis(1);
    4507            0 :             dens = fdens(1);
    4508              :         } else {                            // Multiple gases; calculate mixture properties
    4509            0 :             molmix = frct(1) * wmgas0.wght; // initialize eq. 56
    4510              : 
    4511              :             // Initialize summations for eqns 60-66
    4512            0 :             mumix = 0.0;
    4513            0 :             mukpdwn(1) = 1.0;
    4514              : 
    4515              :             // Calculate properties of mixture constituents
    4516            0 :             for (int i = 2; i <= NMix; ++i) {
    4517            0 :                 auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
    4518            0 :                 fvis(i) = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
    4519            0 :                 fdens(i) = pres * wmgas.wght / (gaslaw * tmean);
    4520            0 :                 molmix += frct(i) * wmgas.wght; // eq. 56
    4521            0 :                 mukpdwn(i) = 1.0;               // initialize denominator of eq. 60
    4522              :             }
    4523              : 
    4524            0 :             for (int i = 1; i <= NMix; ++i) {
    4525            0 :                 auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
    4526            0 :                 for (int j = 1; j <= NMix; ++j) {
    4527            0 :                     auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
    4528              :                     // numerator of equation 61
    4529            0 :                     phimup = pow_2(1.0 + std::sqrt(fvis(i) / fvis(j)) * root_4(wmgasJ.wght / wmgasI.wght));
    4530              :                     // denominator of eq. 61, 64 and 66
    4531            0 :                     downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
    4532              :                     // calculate the denominator of eq. 60
    4533            0 :                     if (i != j) mukpdwn(i) += phimup / downer * frct(j) / frct(i);
    4534              :                 }
    4535            0 :                 mumix += fvis(i) / mukpdwn(i); // eq. 60
    4536              :             }
    4537              : 
    4538              :             // Calculate the density of the mixture assuming an ideal gas
    4539            0 :             rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
    4540              : 
    4541              :             // Final mixture properties
    4542            0 :             visc = mumix;
    4543            0 :             dens = rhomix;
    4544              : 
    4545              :         } // End of check if single or multiple gases in gap
    4546            0 :     }     // WindowGasPropertiesAtTemp()
    4547              : 
    4548              :     //********************************************************************************
    4549              : 
    4550        85895 :     void StartingWindowTemps(EnergyPlusData &state,
    4551              :                              int const SurfNum,          // Surface number
    4552              :                              Array1A<Real64> AbsRadShade // Short-wave radiation absorbed by shade/blind faces
    4553              :     )
    4554              :     {
    4555              : 
    4556              :         // SUBROUTINE INFORMATION:
    4557              :         //       AUTHOR         F. Winkelmann
    4558              :         //       DATE WRITTEN   January 2000
    4559              :         //       MODIFIED       March 2003, FW: add rough calc of increase above ambient of
    4560              :         //                        initial shade/blind temperature when shade/blind deployed
    4561              :         //                        after having been off.
    4562              :         //                      Jan 2004, FW: take into account whether storm window was added
    4563              :         //                        or removed in the current time step.
    4564              :         //       RE-ENGINEERED  na
    4565              : 
    4566              :         // PURPOSE OF THIS SUBROUTINE:
    4567              :         // Initializes face temperature distribution prior to iteration
    4568              : 
    4569              :         // Argument array dimensioning
    4570        85895 :         AbsRadShade.dim(2);
    4571              : 
    4572        85895 :         constexpr Real64 hrad(5.3);    // Typical radiative conductance (W/m2-K)
    4573        85895 :         constexpr Real64 resgap(0.21); // Typical gap resistance (m2-K/W)
    4574              : 
    4575              :         WinShadingType ShadeFlag;   // Shading flag
    4576        85895 :         Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
    4577              :         // inside or outside air film, or gap
    4578              :         Real64 restot; // Total window resistance including outside
    4579              :         //   and inside air films (m2-K/W)
    4580              :         Real64 temdiff;          // Inside/outside air temperature difference (K)
    4581              :         Real64 ressum;           // Resistance sum (m2-K/W)
    4582              :         int StormWinFlagPrevDay; // Previous time step value (day) of storm window flag
    4583              :         int StormWinFlagThisDay; // Current time step value (day) of storm window flag
    4584              :         //   current time step value, nglface, if storm window was
    4585              :         //   added or removed during the current time step).
    4586              : 
    4587        85895 :         auto &s_surf = state.dataSurface;
    4588        85895 :         auto const &wm = state.dataWindowManager;
    4589              : 
    4590        85895 :         StormWinFlagPrevDay = s_surf->SurfWinStormWinFlagPrevDay(SurfNum);
    4591        85895 :         StormWinFlagThisDay = s_surf->SurfWinStormWinFlag(SurfNum);
    4592              : 
    4593        85895 :         if (state.dataGlobal->BeginEnvrnFlag || (StormWinFlagThisDay != StormWinFlagPrevDay)) {
    4594              : 
    4595              :             // Guess values of glass face temperatures based on a simple resistance-network solution
    4596              :             // that (1) ignores short- and long-wave radiation (from lights and zone equipment) absorbed
    4597              :             // by the glass faces, and (2) assumes zero glass resistance. Absorbed solar is also ignored
    4598              :             // since the tests on BeginEnvrnFlag and storm window transition can be true only at midnight.
    4599              :             // Interaction with shade or blind, if one of these is present, is ignored. See below for
    4600              :             // separate calculation of shade/blind temperature.
    4601              : 
    4602          122 :             rguess(1) = 1.0 / (wm->hcout + hrad);
    4603          122 :             rguess(wm->nglface + 1) = 1.0 / (wm->hcin + hrad);
    4604              : 
    4605          281 :             for (int i = 2; i <= wm->nglface; i += 2) {
    4606          159 :                 rguess(i) = 1.0 / wm->scon[i / 2 - 1];
    4607          159 :                 if (i < wm->nglface) rguess(i + 1) = resgap;
    4608              :             }
    4609              : 
    4610          122 :             restot = 0.0;
    4611          562 :             for (int i = 1; i <= wm->nglface + 1; ++i) {
    4612          440 :                 restot += rguess(i);
    4613              :             }
    4614              : 
    4615          122 :             temdiff = wm->tin - wm->tout;
    4616          122 :             if (std::abs(temdiff) < 0.5) temdiff = 2.0;
    4617              : 
    4618          122 :             ressum = 0.0;
    4619          440 :             for (int i = 1; i <= wm->nglface; ++i) {
    4620          318 :                 ressum += rguess(i);
    4621          318 :                 wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
    4622              :             }
    4623              : 
    4624              :         } else {
    4625              :             // Use previous time step values
    4626       305639 :             for (int i = 1; i <= wm->nglface; ++i) {
    4627       219866 :                 wm->thetas[i - 1] = s_surf->SurfaceWindow(SurfNum).thetaFace[i];
    4628              :             }
    4629              :         }
    4630              : 
    4631              :         // Initialize face temperatures of shade or blind, if present
    4632              : 
    4633        85895 :         ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    4634        85895 :         if (ANY_INTERIOR_SHADE_BLIND(s_surf->SurfWinExtIntShadePrevTS(SurfNum)) ||
    4635        85895 :             s_surf->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade ||
    4636       257685 :             s_surf->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind ||
    4637        85895 :             ANY_BETWEENGLASS_SHADE_BLIND(s_surf->SurfWinExtIntShadePrevTS(SurfNum))) {
    4638              :             // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps.
    4639              :             // Note that if shade or blind is NOT on in the current TS the following two
    4640              :             // temperature values, although calculated here, are not used. The shade/blind face numbers
    4641              :             // during the previous time step depend on whether a storm window glass layer was added to
    4642              :             // or removed from the window during the current time step.
    4643            0 :             int nglfacePrevDay = wm->nglface;
    4644            0 :             if (StormWinFlagPrevDay == 0 && StormWinFlagThisDay == 1) nglfacePrevDay = wm->nglface - 2;
    4645            0 :             if (StormWinFlagPrevDay == 1 && StormWinFlagThisDay == 0) nglfacePrevDay = wm->nglface + 2;
    4646            0 :             wm->thetas[wm->nglface] = s_surf->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 1];
    4647            0 :             wm->thetas[wm->nglface + 1] = s_surf->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 2];
    4648              :         } else {
    4649              :             // No shade or blind previous time step; guess starting values of shade/blind
    4650              :             // taking into account short- and long-wave radiation (from solar, lights and zone equipment)
    4651              :             // absorbed by shade/blind faces. Face temps are assumed to be the same and
    4652              :             // equal to shade/blind temp. For interior shade/blind, air temp on either side is
    4653              :             // assumed to be the same and equal to tin; for exterior blind it is assumed to be
    4654              :             // equal to tout. For between-glass shade/blind it is assumed to be equal to the
    4655              :             // average temperature of the adjacent glass faces.
    4656              : 
    4657        85895 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    4658            0 :                 wm->thetas[wm->nglface] = wm->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcin + hrad));
    4659            0 :                 wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4660        85895 :             } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) {
    4661            0 :                 wm->thetas[wm->nglface] = wm->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcout + hrad));
    4662            0 :                 wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4663        85895 :             } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    4664              :                 // Between-glass shade/blind allowed only for double and triple glazing.
    4665              :                 // The factor 16.0 below is based on a combined convective/radiative heat transfer
    4666              :                 // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F.
    4667            0 :                 if (wm->nglface == 4) { // double glazing
    4668            0 :                     wm->thetas[wm->nglface] = 0.5 * (wm->thetas[1] + wm->thetas[2]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
    4669            0 :                     wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4670              :                 } else { // triple glazing
    4671            0 :                     wm->thetas[wm->nglface] = 0.5 * (wm->thetas[3] + wm->thetas[4]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
    4672            0 :                     wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4673              :                 }
    4674              :             }
    4675              :         }
    4676        85895 :     } // StartingWindowTemps()
    4677              : 
    4678              :     //****************************************************************************
    4679              : 
    4680        40358 :     void NusseltNumber(EnergyPlusData &state,
    4681              :                        int const SurfNum, // Surface number
    4682              :                        Real64 const tso,  // Temperature of gap surface closest to outside (K)
    4683              :                        Real64 const tsi,  // Temperature of gap surface closest to zone (K)
    4684              :                        int const IGap,    // Gap number
    4685              :                        Real64 const gr,   // Gap gas Grashof number
    4686              :                        Real64 const pr,   // Gap gas Prandtl number
    4687              :                        Real64 &gnu        // Gap gas Nusselt number
    4688              :     )
    4689              :     {
    4690              : 
    4691              :         // SUBROUTINE INFORMATION:
    4692              :         //       AUTHOR         Adapted by Fred Winkelmann from Window5 subroutine nusselt
    4693              :         //       DATE WRITTEN   September 2001
    4694              :         //       MODIFIED       na
    4695              :         //       RE-ENGINEERED  na
    4696              : 
    4697              :         // PURPOSE OF THIS SUBROUTINE:
    4698              :         // Finds the Nusselt number for gas-filled gaps between isothermal solid layers.
    4699              :         // The gap may be filled with a single gas or a gas mixture.
    4700              : 
    4701              :         // METHODOLOGY EMPLOYED:
    4702              :         // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
    4703              :         // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
    4704              :         // The equation numbers below correspond to those in the standard.
    4705              : 
    4706              :         // REFERENCES:
    4707              :         // Window5 source code; ISO 15099
    4708              : 
    4709              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4710              :         Real64 asp;    // Aspect ratio: window height to gap width
    4711              :         Real64 ra;     // Rayleigh number
    4712              :         Real64 gnu901; // Nusselt number temporary variables for
    4713              :         Real64 gnu902;
    4714              :         Real64 gnu90;
    4715              :         Real64 gnu601;
    4716              :         Real64 gnu602; // different tilt and Ra ranges
    4717              :         Real64 gnu60;
    4718              :         Real64 gnu601a;
    4719              :         Real64 gnua;
    4720              :         Real64 gnub;
    4721              :         Real64 cra; // Temporary variables
    4722              :         Real64 a;
    4723              :         Real64 b;
    4724              :         Real64 g;
    4725              :         Real64 ang;
    4726              : 
    4727        40358 :         auto const &wm = state.dataWindowManager;
    4728              : 
    4729        40358 :         if (SurfNum > 0) {
    4730        40270 :             auto const &s_surf = state.dataSurface;
    4731        40270 :             asp = s_surf->Surface(SurfNum).Height / wm->gaps[IGap - 1].width;
    4732              :         } else { // SurfNum = 0 when NusseltNumber is called from CalcNominalWindowCond, which applies to a
    4733              :             // particular construction. So window height is not known and we assume 5 ft (1.524 m)
    4734           88 :             asp = 1.524 / wm->gaps[IGap - 1].width;
    4735              :         }
    4736              : 
    4737        40358 :         wm->tiltr = wm->tilt * Constant::DegToRad;
    4738        40358 :         ra = gr * pr;
    4739              :         //! fw if (ra > 2.0e6): error that outside range of Rayleigh number?
    4740              : 
    4741        40358 :         if (ra <= 1.0e4) gnu901 = 1.0 + 1.7596678e-10 * std::pow(ra, 2.2984755); // eq. 51
    4742        40358 :         if (ra > 1.0e4 && ra <= 5.0e4) gnu901 = 0.028154 * std::pow(ra, 0.4134); // eq. 50
    4743        40358 :         if (ra > 5.0e4) gnu901 = 0.0673838 * std::pow(ra, 1.0 / 3.0);            // eq. 49
    4744              : 
    4745        40358 :         gnu902 = 0.242 * std::pow(ra / asp, 0.272); // eq. 52
    4746        40358 :         gnu90 = max(gnu901, gnu902);
    4747              : 
    4748        40358 :         if (tso > tsi) {                                     // window heated from above
    4749        18283 :             gnu = 1.0 + (gnu90 - 1.0) * std::sin(wm->tiltr); // eq. 53
    4750              :         } else {                                             // window heated from below
    4751        22075 :             if (wm->tilt >= 60.0) {
    4752        22069 :                 if (ra >= 0.001) {
    4753        22069 :                     g = 0.5 * std::pow(1.0 + std::pow(ra / 3160.0, 20.6), -0.1); // eq. 47
    4754              :                 } else {
    4755            0 :                     g = 0.5;
    4756              :                 }
    4757        22069 :                 gnu601a = 1.0 + pow_7(0.0936 * std::pow(ra, 0.314) / (1.0 + g)); // eq. 45
    4758        22069 :                 gnu601 = std::pow(gnu601a, 0.142857);
    4759              : 
    4760              :                 // For any aspect ratio
    4761        22069 :                 gnu602 = (0.104 + 0.175 / asp) * std::pow(ra, 0.283); // eq. 46
    4762        22069 :                 gnu60 = max(gnu601, gnu602);
    4763              : 
    4764              :                 // linear interpolation for layers inclined at angles between 60 and 90 deg
    4765        22069 :                 gnu = ((90.0 - wm->tilt) * gnu60 + (wm->tilt - 60.0) * gnu90) / 30.0;
    4766              :             }
    4767        22075 :             if (wm->tilt < 60.0) { // eq. 42
    4768            6 :                 cra = ra * std::cos(wm->tiltr);
    4769            6 :                 a = 1.0 - 1708.0 / cra;
    4770            6 :                 b = std::pow(cra / 5830.0, 0.33333) - 1.0;
    4771            6 :                 gnua = (std::abs(a) + a) / 2.0;
    4772            6 :                 gnub = (std::abs(b) + b) / 2.0;
    4773            6 :                 ang = 1708.0 * std::pow(std::sin(1.8 * wm->tiltr), 1.6);
    4774            6 :                 gnu = 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
    4775              :             }
    4776              :         }
    4777        40358 :     } // NusseltNumber()
    4778              : 
    4779              :     //*******************************************************************************************************
    4780              : 
    4781        22932 :     void TransAndReflAtPhi(Real64 const cs,                // Cosine of incidence angle
    4782              :                            Real64 const tf0,               // Transmittance at zero incidence angle
    4783              :                            Real64 const rf0,               // Front reflectance at zero incidence angle
    4784              :                            Real64 const rb0,               // Back reflectance at zero incidence angle
    4785              :                            Real64 &tfp,                    // Transmittance at cs
    4786              :                            Real64 &rfp,                    // Front reflectance at cs
    4787              :                            Real64 &rbp,                    // Back reflectance at cs
    4788              :                            bool const SimpleGlazingSystem, // .TRUE. if simple block model being used
    4789              :                            Real64 const SimpleGlazingSHGC, // SHGC value to use in alternate model for simple glazing system
    4790              :                            Real64 const SimpleGlazingU     // U-factor value to use in alternate model for simple glazing system
    4791              :     )
    4792              :     {
    4793              : 
    4794              :         // SUBROUTINE INFORMATION:
    4795              :         //       AUTHOR         F. Winkelmann
    4796              :         //       DATE WRITTEN   January 2000
    4797              :         //       MODIFIED       5 June 2003, FCW: modify to correspond to WINDOW 4 and WINDOW 5.
    4798              :         //                      Original routine was based on the method in E.U. Finlayson et al,
    4799              :         //                      "WINDOW 4.0: Documentation of Calculation Procedures," LBL-33943,
    4800              :         //                      July 1993, which is not used in either WINDOW 4 or WINDOW 5.
    4801              :         //                      The current routine is based on ASHRAE Handbook of Fundamentals,
    4802              :         //                      2001, pp. 30.20-23, "Optical Properties of Single Glazing Layers."
    4803              :         //                      Original routine underpredicted transmittance at angles of
    4804              :         //                      incidence > 60 degrees.
    4805              :         //                      June 2009.  Brent Griffith.  add simple window correlation
    4806              :         //                                   newer model from LBNL windows group 5/15/2009
    4807              :         //       RE-ENGINEERED  na
    4808              : 
    4809              :         // PURPOSE OF THIS SUBROUTINE:
    4810              :         // For a single glazing layer, calculate transmittance and reflectance at an arbitrary
    4811              :         // angle of incidence given transmittance and reflectance at zero incidence angle.
    4812              : 
    4813              :         // REFERENCES:
    4814              :         // ASHRAE Handbook of Fundamentals, 2001, pp. 30.20-23,
    4815              :         // "Optical Properties of Single Glazing Layers."
    4816              : 
    4817              :         Real64 tfp1; // Transmittance at cs for each polarization
    4818              :         Real64 tfp2;
    4819              :         Real64 rfp1; // Front reflectance at cs for each polarization
    4820              :         Real64 rfp2;
    4821              :         Real64 rbp1; // Back reflectance at cs for each polarization
    4822              :         Real64 rbp2;
    4823              :         Real64 betaf; // Intermediate variables
    4824              :         Real64 betab;
    4825              :         Real64 r0f;
    4826              :         Real64 r0b;
    4827              :         Real64 abf;
    4828              :         Real64 abb;
    4829              :         Real64 ngf; // Front and back index of refraction
    4830              :         Real64 ngb;
    4831              :         Real64 cgf; // Intermediate variables
    4832              :         Real64 cgb;
    4833              :         Real64 rpf1; // Front and back air/glass interface reflectivity
    4834              :         Real64 rpb1;
    4835              :         Real64 tpf1;
    4836              :         Real64 tpb1;
    4837              :         //  and transmittivity for first polarization
    4838              :         Real64 rpf2; // Front and back air/glass interface reflectivity
    4839              :         Real64 rpb2;
    4840              :         Real64 tpf2;
    4841              :         Real64 tpb2;
    4842              :         //  and transmittivity for second polarization
    4843              :         Real64 tcl; // Transmittance and reflectance for clear glass
    4844              :         Real64 rcl;
    4845              :         Real64 tbnz; // Transmittance and reflectance for bronze glass
    4846              :         Real64 rbnz;
    4847              :         Real64 expmabfdivcgf;
    4848              :         Real64 expm2abfdivcgf;
    4849              :         Real64 expmabbdivcgb;
    4850              : 
    4851              :         Real64 testval; // temporary value for calculations
    4852              :         Real64 tmp1;    // temporary value for calculations
    4853              :         Real64 tmp2;    // temporary value for calculations
    4854              :         Real64 tmp3;    // temporary value for calculations
    4855              :         Real64 tmp4;    // temporary value for calculations
    4856              :         Real64 tmp5;    // temporary value for calculations
    4857              :         Real64 tmp6;    // temporary value for calculations
    4858              :         Real64 tmp7;    // temporary value for calculations
    4859              :         Real64 tmp8;    // temporary value for calculations
    4860              :         Real64 tmp9;    // temporary value for calculations
    4861              : 
    4862        22932 :         if (SimpleGlazingSystem) { // use alternate angular dependence model for block model of simple glazing input
    4863              : 
    4864          491 :             Real64 const cs_2(pow_2(cs));
    4865          491 :             Real64 const cs_3(pow_3(cs));
    4866          491 :             Real64 const cs_4(pow_4(cs));
    4867          491 :             Real64 TransCurveA = 0.00 + 3.36 * cs - 3.85 * cs_2 + 1.49 * cs_3 + 0.01 * cs_4;
    4868          491 :             Real64 TransCurveB = 0.00 + 2.83 * cs - 2.42 * cs_2 + 0.04 * cs_3 + 0.55 * cs_4;
    4869          491 :             Real64 TransCurveC = 0.00 + 2.45 * cs - 1.58 * cs_2 - 0.64 * cs_3 + 0.77 * cs_4;
    4870          491 :             Real64 TransCurveD = 0.00 + 2.85 * cs - 2.58 * cs_2 + 0.40 * cs_3 + 0.35 * cs_4;
    4871          491 :             Real64 TransCurveE = 0.00 + 1.51 * cs + 2.49 * cs_2 - 5.87 * cs_3 + 2.88 * cs_4;
    4872          491 :             Real64 TransCurveF = 0.00 + 1.21 * cs + 3.14 * cs_2 - 6.37 * cs_3 + 3.03 * cs_4;
    4873          491 :             Real64 TransCurveG = 0.00 + 1.09 * cs + 3.54 * cs_2 - 6.84 * cs_3 + 3.23 * cs_4;
    4874          491 :             Real64 TransCurveH = 0.00 + 0.98 * cs + 3.83 * cs_2 - 7.13 * cs_3 + 3.33 * cs_4;
    4875          491 :             Real64 TransCurveI = 0.00 + 0.79 * cs + 3.93 * cs_2 - 6.86 * cs_3 + 3.15 * cs_4;
    4876          491 :             Real64 TransCurveJ = 0.00 + 0.08 * cs + 6.02 * cs_2 - 8.84 * cs_3 + 3.74 * cs_4;
    4877          491 :             Real64 TransCurveFGHI = (TransCurveF + TransCurveG + TransCurveH + TransCurveI) / 4.0;
    4878          491 :             Real64 TransCurveFH = (TransCurveF + TransCurveH) / 2.0;
    4879          491 :             Real64 TransCurveBDCD = (TransCurveB + TransCurveD + TransCurveC + TransCurveD) / 4.0;
    4880              : 
    4881          491 :             Real64 ReflectCurveA = 1.00 - 0.70 * cs + 2.57 * cs_2 - 3.20 * cs_3 + 1.33 * cs_4 - TransCurveA;
    4882          491 :             Real64 ReflectCurveB = 1.00 - 1.87 * cs + 6.50 * cs_2 - 7.86 * cs_3 + 3.23 * cs_4 - TransCurveB;
    4883          491 :             Real64 ReflectCurveC = 1.00 - 2.52 * cs + 8.40 * cs_2 - 9.86 * cs_3 + 3.99 * cs_4 - TransCurveC;
    4884          491 :             Real64 ReflectCurveD = 1.00 - 1.85 * cs + 6.40 * cs_2 - 7.64 * cs_3 + 3.11 * cs_4 - TransCurveD;
    4885          491 :             Real64 ReflectCurveE = 1.00 - 1.57 * cs + 5.60 * cs_2 - 6.82 * cs_3 + 2.80 * cs_4 - TransCurveE;
    4886          491 :             Real64 ReflectCurveF = 1.00 - 3.15 * cs + 10.98 * cs_2 - 13.14 * cs_3 + 5.32 * cs_4 - TransCurveF;
    4887          491 :             Real64 ReflectCurveG = 1.00 - 3.25 * cs + 11.32 * cs_2 - 13.54 * cs_3 + 5.49 * cs_4 - TransCurveG;
    4888          491 :             Real64 ReflectCurveH = 1.00 - 3.39 * cs + 11.70 * cs_2 - 13.94 * cs_3 + 5.64 * cs_4 - TransCurveH;
    4889          491 :             Real64 ReflectCurveI = 1.00 - 4.06 * cs + 13.55 * cs_2 - 15.74 * cs_3 + 6.27 * cs_4 - TransCurveI;
    4890          491 :             Real64 ReflectCurveJ = 1.00 - 4.35 * cs + 14.27 * cs_2 - 16.32 * cs_3 + 6.39 * cs_4 - TransCurveJ;
    4891              : 
    4892          491 :             Real64 ReflectCurveFGHI = (ReflectCurveF + ReflectCurveG + ReflectCurveH + ReflectCurveI) / 4.0;
    4893          491 :             Real64 ReflectCurveFH = (ReflectCurveF + ReflectCurveH) / 2.0;
    4894          491 :             Real64 ReflectCurveBDCD = (ReflectCurveB + ReflectCurveD + ReflectCurveC + ReflectCurveD) / 4.0;
    4895              : 
    4896          491 :             Real64 TransTmp(0.0);
    4897          491 :             Real64 ReflectTmp(0.0);
    4898              : 
    4899          491 :             if (SimpleGlazingU < 1.4195) { // cell 1, 2, or 3
    4900           80 :                 if (SimpleGlazingSHGC > 0.45) {
    4901              :                     // cell # 1
    4902              :                     // Curve E
    4903           40 :                     TransTmp = TransCurveE;
    4904           40 :                     ReflectTmp = ReflectCurveE;
    4905              : 
    4906           40 :                 } else if ((0.35 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    4907              :                     // cell # 2
    4908              :                     // 2 way interpolation between Curve E and Curve J
    4909            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, TransCurveJ, TransCurveE);
    4910            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, ReflectCurveJ, ReflectCurveE);
    4911              : 
    4912           40 :                 } else if (SimpleGlazingSHGC < 0.35) {
    4913              :                     // cell # 3
    4914              :                     // Curve J
    4915           40 :                     TransTmp = TransCurveJ;
    4916           40 :                     ReflectTmp = ReflectCurveJ;
    4917              :                 }
    4918              : 
    4919          411 :             } else if ((1.4195 <= SimpleGlazingU) && (SimpleGlazingU <= 1.7034)) { // cell 4, 5 , 6, 7, 8, 9, or 10
    4920            0 :                 if (SimpleGlazingSHGC > 0.55) {
    4921              :                     // cell # 4
    4922              :                     // Curve E
    4923            0 :                     TransTmp = TransCurveE;
    4924            0 :                     ReflectTmp = ReflectCurveE;
    4925              : 
    4926            0 :                 } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
    4927              :                     // cell # 5
    4928              :                     // 4 way interpolation between Curve E , Curve E, Curve E and Curve FGHI
    4929              : 
    4930            0 :                     TransTmp = InterpolateBetweenFourValues(
    4931              :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, TransCurveE, TransCurveE, TransCurveFGHI, TransCurveE);
    4932            0 :                     ReflectTmp = InterpolateBetweenFourValues(
    4933              :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, ReflectCurveE, ReflectCurveE, ReflectCurveFGHI, ReflectCurveE);
    4934              : 
    4935            0 :                 } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
    4936              :                     // cell # 6
    4937              :                     // 2 way interpolation between Curve E and Curve FGHI
    4938            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveE, TransCurveFGHI);
    4939            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveE, ReflectCurveFGHI);
    4940              : 
    4941            0 :                 } else if ((0.35 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    4942              :                     // cell # 7
    4943              :                     // 4 way interpolation between Curve E , Curve FGHI, Curve J and Curve FGHI
    4944            0 :                     TransTmp = InterpolateBetweenFourValues(
    4945              :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.35, 0.45, TransCurveJ, TransCurveE, TransCurveFGHI, TransCurveFGHI);
    4946            0 :                     ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
    4947              :                                                               SimpleGlazingSHGC,
    4948              :                                                               1.4195,
    4949              :                                                               1.7034,
    4950              :                                                               0.35,
    4951              :                                                               0.45,
    4952              :                                                               ReflectCurveJ,
    4953              :                                                               ReflectCurveE,
    4954              :                                                               ReflectCurveFGHI,
    4955              :                                                               ReflectCurveFGHI);
    4956              : 
    4957            0 :                 } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.35)) {
    4958              :                     // cell # 8
    4959              :                     // 2 way interpolation between Curve J and Curve FGHI
    4960            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFGHI);
    4961            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFGHI);
    4962              : 
    4963            0 :                 } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
    4964              :                     // cell # 9
    4965              :                     // 4 way interpolation between Curve J, Curve FGHI, Curve J and Curve FH
    4966            0 :                     TransTmp = InterpolateBetweenFourValues(
    4967              :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, TransCurveJ, TransCurveJ, TransCurveFH, TransCurveFGHI);
    4968            0 :                     ReflectTmp = InterpolateBetweenFourValues(
    4969              :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, ReflectCurveJ, ReflectCurveJ, ReflectCurveFH, ReflectCurveFGHI);
    4970              : 
    4971            0 :                 } else if (SimpleGlazingSHGC <= 0.25) {
    4972              :                     // cell # 10
    4973              :                     // 2 way interpolation between Curve J and Curve FH
    4974            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFH);
    4975            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFH);
    4976              :                 }
    4977          411 :             } else if ((1.7034 < SimpleGlazingU) && (SimpleGlazingU < 3.4068)) { // cell 11, 12, 13, 14, or 15
    4978          331 :                 if (SimpleGlazingSHGC > 0.55) {
    4979              :                     // cell # 11
    4980              :                     // Curve E
    4981            0 :                     TransTmp = TransCurveE;
    4982            0 :                     ReflectTmp = ReflectCurveE;
    4983              : 
    4984          331 :                 } else if ((0.5 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
    4985              :                     // cell # 12
    4986              :                     // 2 way interpolation between Curve E and Curve FGHI
    4987           80 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, TransCurveFGHI, TransCurveE);
    4988           80 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, ReflectCurveFGHI, ReflectCurveE);
    4989              : 
    4990          251 :                 } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.5)) {
    4991              :                     // cell # 13
    4992              :                     // Curve FGHI
    4993          251 :                     TransTmp = TransCurveFGHI;
    4994          251 :                     ReflectTmp = ReflectCurveFGHI;
    4995              : 
    4996            0 :                 } else if ((0.25 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
    4997              :                     // cell # 14
    4998              :                     // 2 way interpolation between Curve FGHI and Curve FH
    4999            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, TransCurveFH, TransCurveFGHI);
    5000            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, ReflectCurveFH, ReflectCurveFGHI);
    5001              : 
    5002            0 :                 } else if (SimpleGlazingSHGC < 0.25) {
    5003              :                     // cell # 15
    5004              :                     // Curve FH
    5005            0 :                     TransTmp = TransCurveFH;
    5006            0 :                     ReflectTmp = ReflectCurveFH;
    5007              :                 }
    5008              : 
    5009           80 :             } else if ((3.4068 <= SimpleGlazingU) && (SimpleGlazingU <= 4.5424)) { // cell 16, 17, 18, 19, 20, 21, 22, or 23
    5010            0 :                 if (SimpleGlazingSHGC > 0.65) {
    5011              :                     // cell # 16
    5012              :                     // 2 way interpolation between Curve E and Curve A
    5013            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveA);
    5014            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveA);
    5015              : 
    5016            0 :                 } else if ((0.6 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
    5017              :                     // cell # 17
    5018              :                     // 4 way interpolation between Curve E , Curve E, Curve A, and Curve BDCD
    5019            0 :                     TransTmp = InterpolateBetweenFourValues(
    5020              :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, TransCurveE, TransCurveE, TransCurveBDCD, TransCurveA);
    5021            0 :                     ReflectTmp = InterpolateBetweenFourValues(
    5022              :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, ReflectCurveE, ReflectCurveE, ReflectCurveBDCD, ReflectCurveA);
    5023              : 
    5024            0 :                 } else if ((0.55 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.6)) {
    5025              :                     // cell # 18
    5026              :                     // 2 way interpolation between Curve E and Curve BDCD
    5027            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveBDCD);
    5028            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveBDCD);
    5029              : 
    5030            0 :                 } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
    5031              :                     // cell # 19
    5032              :                     // 4 way interpolation between Curve E , Curve FGHI, Curve BDCD and Curve BDCD
    5033            0 :                     TransTmp = InterpolateBetweenFourValues(
    5034              :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.5, 0.55, TransCurveFGHI, TransCurveE, TransCurveBDCD, TransCurveBDCD);
    5035            0 :                     ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
    5036              :                                                               SimpleGlazingSHGC,
    5037              :                                                               3.4068,
    5038              :                                                               4.5424,
    5039              :                                                               0.5,
    5040              :                                                               0.55,
    5041              :                                                               ReflectCurveFGHI,
    5042              :                                                               ReflectCurveE,
    5043              :                                                               ReflectCurveBDCD,
    5044              :                                                               ReflectCurveBDCD);
    5045              : 
    5046            0 :                 } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
    5047              :                     // cell # 20
    5048              :                     // 2 way interpolation between Curve FGHI and Curve BDCD
    5049            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFGHI, TransCurveBDCD);
    5050            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFGHI, ReflectCurveBDCD);
    5051              : 
    5052            0 :                 } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    5053              :                     // cell # 21
    5054              :                     // 4 way interpolation between Curve FGHI, Curve FGHI, Curve BDCD, and Curve D
    5055            0 :                     TransTmp = InterpolateBetweenFourValues(
    5056              :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.3, 0.45, TransCurveFGHI, TransCurveFGHI, TransCurveD, TransCurveBDCD);
    5057            0 :                     ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
    5058              :                                                               SimpleGlazingSHGC,
    5059              :                                                               3.4068,
    5060              :                                                               4.5424,
    5061              :                                                               0.3,
    5062              :                                                               0.45,
    5063              :                                                               ReflectCurveFGHI,
    5064              :                                                               ReflectCurveFGHI,
    5065              :                                                               ReflectCurveD,
    5066              :                                                               ReflectCurveBDCD);
    5067              : 
    5068            0 :                 } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
    5069              :                     // cell # 22
    5070              :                     // 4 way interpolation between Curve FGHI, Curve FH, Curve D, and Curve D
    5071            0 :                     TransTmp = InterpolateBetweenFourValues(
    5072              :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, TransCurveFH, TransCurveFGHI, TransCurveD, TransCurveD);
    5073            0 :                     ReflectTmp = InterpolateBetweenFourValues(
    5074              :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, ReflectCurveFH, ReflectCurveFGHI, ReflectCurveD, ReflectCurveD);
    5075              : 
    5076            0 :                 } else if (SimpleGlazingSHGC <= 0.25) {
    5077              :                     // cell # 23
    5078              :                     // 2 way interpolation between Curve FH and Curve D
    5079            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFH, TransCurveD);
    5080            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFH, ReflectCurveD);
    5081              :                 }
    5082           80 :             } else if (SimpleGlazingU > 4.5424) { // cell 24, 25, 26, 27, or 28
    5083           80 :                 if (SimpleGlazingSHGC > 0.65) {
    5084              :                     // cell # 24
    5085              :                     // Curve A
    5086           40 :                     TransTmp = TransCurveA;
    5087           40 :                     ReflectTmp = ReflectCurveA;
    5088           40 :                 } else if ((0.6 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
    5089              :                     // cell # 25
    5090              :                     // 2 way interpolation between Curve A and Curve BDCD
    5091            0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, TransCurveBDCD, TransCurveA);
    5092            0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, ReflectCurveBDCD, ReflectCurveA);
    5093              : 
    5094           40 :                 } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.6)) {
    5095              :                     // cell # 26
    5096              :                     // Curve BDCD
    5097            0 :                     TransTmp = TransCurveBDCD;
    5098            0 :                     ReflectTmp = ReflectCurveBDCD;
    5099              : 
    5100           40 :                 } else if ((0.3 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    5101              :                     // cell # 27
    5102              :                     // 2 way interpolation between Curve BDCD and Curve D
    5103           40 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, TransCurveD, TransCurveBDCD);
    5104           40 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, ReflectCurveD, ReflectCurveBDCD);
    5105              : 
    5106            0 :                 } else if (SimpleGlazingSHGC < 0.3) {
    5107              :                     // cell # 28
    5108              :                     // Curve D
    5109            0 :                     TransTmp = TransCurveD;
    5110            0 :                     ReflectTmp = ReflectCurveD;
    5111              : 
    5112              :                 } else {
    5113            0 :                     assert(false);
    5114              :                 }
    5115              :             } else {
    5116            0 :                 assert(false);
    5117              :             }
    5118              : 
    5119          491 :             if (cs == 1.0) { // at 0 deg incident, TransTmp and ReflectTmp should be 1.0
    5120           49 :                 TransTmp = 1.0;
    5121           49 :                 ReflectTmp = 0.0;
    5122              :             }
    5123              : 
    5124              :             // now apply normalization factors to zero incidence angle properties
    5125          491 :             tfp = tf0 * TransTmp;
    5126          491 :             tfp = max(min(1.0, tfp), 0.0);
    5127              : 
    5128          491 :             rfp = rf0 * (1. - ReflectTmp) + ReflectTmp;
    5129          491 :             rfp = max(min(0.9999 - tfp, rfp), 0.0);
    5130              : 
    5131          491 :             rbp = rfp;
    5132              : 
    5133        22441 :         } else if (tf0 <= 0.0) {
    5134              :             // This is an opaque window.  For all angles, set transmittance to 0; set reflectance to that at zero incidence angle.
    5135            0 :             tfp = 0.0;
    5136            0 :             rfp = rf0;
    5137            0 :             rbp = rb0;
    5138              :         } else {
    5139              : 
    5140        22441 :             betaf = pow_2(tf0) - pow_2(rf0) + 2.0 * rf0 + 1.0;
    5141        22441 :             betab = pow_2(tf0) - pow_2(rb0) + 2.0 * rb0 + 1.0;
    5142        22441 :             r0f = (betaf - std::sqrt(pow_2(betaf) - 4.0 * (2.0 - rf0) * rf0)) / (2.0 * (2.0 - rf0));
    5143        22441 :             r0b = (betab - std::sqrt(pow_2(betab) - 4.0 * (2.0 - rb0) * rb0)) / (2.0 * (2.0 - rb0));
    5144              : 
    5145        22441 :             tmp1 = std::abs(r0f - r0b);
    5146        22441 :             if (tmp1 != 0.0) {
    5147        12680 :                 testval = std::abs(r0f - r0b) / (r0f + r0b);
    5148              :             } else {
    5149         9761 :                 testval = 0.0;
    5150              :             }
    5151              : 
    5152        22441 :             if (testval < 0.001) { // CR8830, CR8942, implications of relaxation of glazing properties CR8413
    5153              :                 // UNCOATED GLASS
    5154         9761 :                 tmp1 = r0f * tf0;
    5155         9761 :                 if (tmp1 != 0.0) {
    5156         9761 :                     abf = std::log(tmp1 / (rf0 - r0f));
    5157              :                 } else {
    5158            0 :                     abf = 0.0;
    5159              :                 }
    5160         9761 :                 tmp2 = r0b * tf0;
    5161         9761 :                 if (tmp2 != 0.0) {
    5162         9761 :                     abb = std::log(tmp2 / (rb0 - r0b));
    5163              :                 } else {
    5164            0 :                     abb = 0.0;
    5165              :                 }
    5166         9761 :                 ngf = (1.0 + std::sqrt(r0f)) / (1.0 - std::sqrt(r0f));
    5167         9761 :                 ngb = (1.0 + std::sqrt(r0b)) / (1.0 - std::sqrt(r0b));
    5168         9761 :                 cgf = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngf));
    5169         9761 :                 cgb = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngb));
    5170         9761 :                 tmp3 = ngf * cs - cgf;
    5171         9761 :                 if (tmp3 != 0.0) {
    5172         9761 :                     rpf1 = pow_2(tmp3 / (ngf * cs + cgf));
    5173              :                 } else {
    5174            0 :                     rpf1 = 0.0;
    5175              :                 }
    5176         9761 :                 tmp4 = ngf * cgf - cs;
    5177         9761 :                 if (tmp4 != 0.0) {
    5178         9761 :                     rpf2 = pow_2(tmp4 / (ngf * cgf + cs));
    5179              :                 } else {
    5180            0 :                     rpf2 = 0.0;
    5181              :                 }
    5182         9761 :                 tpf1 = 1 - rpf1;
    5183         9761 :                 tpf2 = 1 - rpf2;
    5184         9761 :                 tmp5 = ngb * cs - cgb;
    5185         9761 :                 if (tmp5 != 0.0) {
    5186         9761 :                     rpb1 = pow_2(tmp5 / (ngb * cs + cgb));
    5187              :                 } else {
    5188            0 :                     rpb1 = 0.0;
    5189              :                 }
    5190         9761 :                 tmp6 = ngb * cgb - cs;
    5191         9761 :                 if (tmp6 != 0.0) {
    5192         9761 :                     rpb2 = pow_2(tmp6 / (ngb * cgb + cs));
    5193              :                 } else {
    5194            0 :                     rpb2 = 0.0;
    5195              :                 }
    5196         9761 :                 tpb1 = 1 - rpf1;
    5197         9761 :                 tpb2 = 1 - rpf2;
    5198         9761 :                 tmp7 = -abf;
    5199         9761 :                 if (cgf != 0.0) {
    5200         9761 :                     expmabfdivcgf = std::exp(tmp7 / cgf);
    5201              :                 } else {
    5202            0 :                     expmabfdivcgf = 0.0;
    5203              :                 }
    5204         9761 :                 tmp8 = -2.0 * abf;
    5205         9761 :                 if (cgf != 0.0) {
    5206         9761 :                     expm2abfdivcgf = std::exp(tmp8 / cgf);
    5207              :                 } else {
    5208            0 :                     expm2abfdivcgf = 0.0;
    5209              :                 }
    5210         9761 :                 if (tpf1 != 0.0) {
    5211         9761 :                     tfp1 = pow_2(tpf1) * expmabfdivcgf / (1.0 - pow_2(rpf1) * expm2abfdivcgf);
    5212              :                 } else {
    5213            0 :                     tfp1 = 0.0;
    5214              :                 }
    5215         9761 :                 rfp1 = rpf1 * (1.0 + tfp1 * expmabfdivcgf);
    5216         9761 :                 if (tpf2 != 0.0) {
    5217         8805 :                     tfp2 = pow_2(tpf2) * expmabfdivcgf / (1.0 - pow_2(rpf2) * expm2abfdivcgf);
    5218              :                 } else {
    5219          956 :                     tfp2 = 0.0;
    5220              :                 }
    5221         9761 :                 rfp2 = rpf2 * (1.0 + tfp2 * expmabfdivcgf);
    5222         9761 :                 tfp = 0.5 * (tfp1 + tfp2);
    5223         9761 :                 rfp = 0.5 * (rfp1 + rfp2);
    5224         9761 :                 tmp9 = -abb;
    5225         9761 :                 if (tmp9 != 0.0) {
    5226         9761 :                     expmabbdivcgb = std::exp(tmp9 / cgb);
    5227              :                 } else {
    5228            0 :                     expmabbdivcgb = 0.0;
    5229              :                 }
    5230         9761 :                 rbp1 = rpb1 * (1.0 + tfp1 * expmabbdivcgb);
    5231         9761 :                 rbp2 = rpb2 * (1.0 + tfp2 * expmabbdivcgb);
    5232         9761 :                 rbp = 0.5 * (rbp1 + rbp2);
    5233              :             } else {
    5234              :                 // COATED GLASS
    5235        12680 :                 if (tf0 > 0.645) {
    5236              :                     // Use clear glass angular distribution.
    5237              :                     // Normalized clear glass transmittance and reflectance distribution
    5238        12500 :                     if (cs > 0.999) { // Angle of incidence = 0 deg
    5239         1250 :                         tcl = 1.0;
    5240         1250 :                         rcl = 0.0;
    5241        11250 :                     } else if (cs < 0.001) { // Angle of incidence = 90 deg
    5242         1250 :                         tcl = 0.0;
    5243         1250 :                         rcl = 1.0;
    5244              :                     } else {
    5245        10000 :                         tcl = -0.0015 + (3.355 + (-3.840 + (1.460 + 0.0288 * cs) * cs) * cs) * cs;
    5246        10000 :                         rcl = 0.999 + (-0.563 + (2.043 + (-2.532 + 1.054 * cs) * cs) * cs) * cs - tcl;
    5247              :                     }
    5248        12500 :                     tfp = tf0 * tcl;
    5249        12500 :                     rfp = rf0 * (1.0 - rcl) + rcl;
    5250        12500 :                     rbp = rb0 * (1.0 - rcl) + rcl;
    5251              :                 } else {
    5252              :                     // Use bronze glass angular distribution.
    5253              :                     // Normalized bronze tinted glass transmittance and reflectance distribution
    5254          180 :                     if (cs > 0.999) { // Angle of incidence = 0 deg
    5255           18 :                         tbnz = 1.0;
    5256           18 :                         rbnz = 0.0;
    5257          162 :                     } else if (cs < 0.001) { // Angle of incidence = 90 deg
    5258           18 :                         tbnz = 0.0;
    5259           18 :                         rbnz = 1.0;
    5260              :                     } else {
    5261          144 :                         tbnz = -0.002 + (2.813 + (-2.341 + (-0.05725 + 0.599 * cs) * cs) * cs) * cs;
    5262          144 :                         rbnz = 0.997 + (-1.868 + (6.513 + (-7.862 + 3.225 * cs) * cs) * cs) * cs - tbnz;
    5263              :                     }
    5264          180 :                     tfp = tf0 * tbnz;
    5265          180 :                     rfp = rf0 * (1.0 - rbnz) + rbnz;
    5266          180 :                     rbp = rb0 * (1.0 - rbnz) + rbnz;
    5267              :                 }
    5268              :             }
    5269              :         }
    5270              : 
    5271              :         // total absorptance cannot be negative
    5272        22932 :         assert(1.0 - rfp - tfp >= -1e6);
    5273        22932 :         assert(1.0 - rbp - tfp >= -1e6);
    5274        22932 :     } // TransAndReflAtPhi()
    5275              : 
    5276          240 :     Real64 InterpolateBetweenTwoValues(Real64 const X, Real64 const X0, Real64 const X1, Real64 const F0, Real64 const F1)
    5277              :     {
    5278              : 
    5279              :         // FUNCTION INFORMATION:
    5280              :         //       AUTHOR         Brent Griffith
    5281              :         //       DATE WRITTEN   June 2009
    5282              :         //       MODIFIED       na
    5283              :         //       RE-ENGINEERED  na
    5284              : 
    5285              :         // PURPOSE OF THIS FUNCTION:
    5286              :         // Interpolate between two results
    5287              : 
    5288              :         // METHODOLOGY EMPLOYED:
    5289              :         // linear interpolation
    5290              : 
    5291              :         Real64 InterpResult;
    5292              : 
    5293          240 :         InterpResult = F0 + ((X - X0) / (X1 - X0)) * (F1 - F0);
    5294          240 :         return InterpResult;
    5295              :     } // InterpolateBetweenTwoValues()
    5296              : 
    5297            0 :     Real64 InterpolateBetweenFourValues(Real64 const X,
    5298              :                                         Real64 const Y,
    5299              :                                         Real64 const X1,
    5300              :                                         Real64 const X2,
    5301              :                                         Real64 const Y1,
    5302              :                                         Real64 const Y2,
    5303              :                                         Real64 const Fx1y1,
    5304              :                                         Real64 const Fx1y2,
    5305              :                                         Real64 const Fx2y1,
    5306              :                                         Real64 const Fx2y2)
    5307              :     {
    5308              : 
    5309              :         // FUNCTION INFORMATION:
    5310              :         //       AUTHOR         Brent Griffith
    5311              :         //       DATE WRITTEN   June 2009
    5312              :         //       MODIFIED       na
    5313              :         //       RE-ENGINEERED  na
    5314              : 
    5315              :         // PURPOSE OF THIS FUNCTION:
    5316              :         // Interpolate between four results.
    5317              : 
    5318              :         // METHODOLOGY EMPLOYED:
    5319              :         // bilinear interpolation (approximate)
    5320              : 
    5321              :         // REFERENCES:
    5322              :         // http://en.wikipedia.org/wiki/Bilinear_interpolation
    5323              : 
    5324              :         // Return value
    5325              :         Real64 InterpResult;
    5326              : 
    5327            0 :         InterpResult = (Fx1y1 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y2 - Y) + (Fx2y1 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y2 - Y) +
    5328            0 :                        (Fx1y2 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y - Y1) + (Fx2y2 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y - Y1);
    5329            0 :         return InterpResult;
    5330              :     } // InterpolateBetweenFourValues()
    5331              : 
    5332              :     //**************************************************************************
    5333          546 :     void W5LsqFit(std::array<Real64, numPhis> const &ivars, // Independent variables
    5334              :                   std::array<Real64, numPhis> const &dvars, // Dependent variables
    5335              :                   std::array<Real64, maxPolyCoef> &coeffs   // Polynomial coefficients from fit
    5336              :     )
    5337              :     {
    5338              : 
    5339              :         // SUBROUTINE INFORMATION:
    5340              :         //       AUTHOR         George Walton
    5341              :         //       DATE WRITTEN   April 1976
    5342              :         //       MODIFIED       November 1999 F.Winkelmann
    5343              :         //       RE-ENGINEERED  na
    5344              : 
    5345              :         // PURPOSE OF THIS SUBROUTINE:
    5346              :         // Does least squares fit for coefficients of a polynomial
    5347              :         // that gives a window property, such as transmittance, as a function of
    5348              :         // the cosine of the angle of incidence. The polynomial is of the
    5349              :         // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
    5350              :         // Adapted from BLAST subroutine LSQFIT.
    5351              : 
    5352              :         std::array<std::array<Real64, maxPolyCoef>, maxPolyCoef> A; // Least squares derivative matrix
    5353              :         std::array<Real64, maxPolyCoef> B;                          // Least squares derivative vector
    5354              :         std::array<std::array<Real64, 16>, maxPolyCoef> D;          // Powers of independent variable
    5355              : 
    5356              :         // Set up least squares matrix
    5357         6006 :         for (int M = 0; M < numPhis; ++M) {
    5358         5460 :             D[0][M] = ivars[M];
    5359              :         }
    5360              : 
    5361         3276 :         for (int i = 1; i < maxPolyCoef; ++i) {
    5362        30030 :             for (int M = 0; M < numPhis; ++M) {
    5363        27300 :                 D[i][M] = D[i - 1][M] * ivars[M];
    5364              :             }
    5365              :         }
    5366              : 
    5367         3822 :         for (int i = 0; i < maxPolyCoef; ++i) {
    5368         3276 :             Real64 SUM = 0.0;
    5369        36036 :             for (int M = 0; M < numPhis; ++M) {
    5370        32760 :                 SUM += dvars[M] * D[i][M];
    5371              :             }
    5372         3276 :             B[i] = SUM;
    5373        22932 :             for (int j = 0; j < maxPolyCoef; ++j) {
    5374        19656 :                 Real64 SUM2 = 0.0;
    5375       216216 :                 for (int M = 0; M < numPhis; ++M) {
    5376       196560 :                     SUM2 += D[i][M] * D[j][M];
    5377              :                 }
    5378        19656 :                 A[j][i] = SUM2;
    5379        19656 :                 A[i][j] = SUM2;
    5380              :             }
    5381              :         }
    5382              : 
    5383              :         // Solve the simultaneous equations using Gauss elimination
    5384          546 :         int order1 = maxPolyCoef - 1;
    5385         3276 :         for (int K = 0; K < order1; ++K) {
    5386         2730 :             int KP1 = K + 1;
    5387        10920 :             for (int i = KP1; i < maxPolyCoef; ++i) {
    5388         8190 :                 Real64 ACON = A[K][i] / A[K][K];
    5389         8190 :                 B[i] -= B[K] * ACON;
    5390        46410 :                 for (int j = K; j < maxPolyCoef; ++j) {
    5391        38220 :                     A[j][i] -= A[j][K] * ACON;
    5392              :                 }
    5393              :             }
    5394              :         }
    5395              : 
    5396              :         // Perform back substitution
    5397          546 :         coeffs[maxPolyCoef - 1] = B[maxPolyCoef - 1] / A[maxPolyCoef - 1][maxPolyCoef - 1];
    5398          546 :         int LP1 = maxPolyCoef - 1;
    5399          546 :         int L = maxPolyCoef - 2;
    5400              : 
    5401         3276 :         while (L >= 0) {
    5402         2730 :             Real64 SUM = 0.0;
    5403        10920 :             for (int j = LP1; j < maxPolyCoef; ++j) {
    5404         8190 :                 SUM += A[j][L] * coeffs[j];
    5405              :             }
    5406         2730 :             coeffs[L] = (B[L] - SUM) / A[L][L];
    5407         2730 :             LP1 = L;
    5408         2730 :             --L;
    5409              :         }
    5410          546 :     } // W5LsqFit()
    5411              : 
    5412              :     //********************************************************************************
    5413              : 
    5414            0 :     void W5LsqFit2(Array1A<Real64> const IndepVar, // Independent variables
    5415              :                    Array1A<Real64> const DepVar,   // Dependent variables
    5416              :                    int const N,                    // Order of polynomial
    5417              :                    int const N1,                   // First and last data points used
    5418              :                    int const N2,
    5419              :                    Array1A<Real64> CoeffsCurve // Polynomial coefficients from fit
    5420              :     )
    5421              :     {
    5422              : 
    5423              :         // SUBROUTINE INFORMATION:
    5424              :         //       AUTHOR         George Walton
    5425              :         //       DATE WRITTEN   April 1976
    5426              :         //       MODIFIED       November 1999 F.Winkelmann
    5427              :         //                      May 2001 F. Winkelmann, to do 19 indep. variables
    5428              :         //       RE-ENGINEERED  na
    5429              : 
    5430              :         // PURPOSE OF THIS SUBROUTINE:
    5431              :         // Does least squares fit for coefficients of a polynomial
    5432              :         // that gives a window property, such as transmittance, as a function of
    5433              :         // the cosine of the angle of incidence. The polynomial is of the
    5434              :         // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
    5435              :         // Adapted from BLAST subroutine LSQFIT.
    5436              : 
    5437              :         // Argument array dimensioning
    5438            0 :         IndepVar.dim(19);
    5439            0 :         DepVar.dim(19);
    5440            0 :         CoeffsCurve.dim(6);
    5441              : 
    5442            0 :         Array2D<Real64> A(6, 6);  // Least squares derivative matrix
    5443            0 :         Array1D<Real64> B(6);     // Least squares derivative vector
    5444            0 :         Array2D<Real64> D(6, 16); // Powers of independent variable
    5445              :         Real64 ACON;              // Intermediate variables
    5446              :         Real64 SUM;
    5447              :         int LP1;
    5448              :         int NM1;
    5449              : 
    5450              :         // Set up least squares matrix
    5451            0 :         for (int M = N1; M <= N2; ++M) {
    5452            0 :             D(1, M) = IndepVar(M);
    5453              :         }
    5454              : 
    5455            0 :         for (int i = 2; i <= N; ++i) {
    5456            0 :             for (int M = N1; M <= N2; ++M) {
    5457            0 :                 D(i, M) = D(i - 1, M) * IndepVar(M);
    5458              :             }
    5459              :         }
    5460              : 
    5461            0 :         for (int i = 1; i <= N; ++i) {
    5462            0 :             SUM = 0.0;
    5463            0 :             for (int M = N1; M <= N2; ++M) {
    5464            0 :                 SUM += DepVar(M) * D(i, M);
    5465              :             }
    5466            0 :             B(i) = SUM;
    5467            0 :             for (int j = 1; j <= N; ++j) {
    5468            0 :                 SUM = 0.0;
    5469            0 :                 for (int M = N1; M <= N2; ++M) {
    5470            0 :                     SUM += D(i, M) * D(j, M);
    5471              :                 }
    5472            0 :                 A(j, i) = SUM;
    5473            0 :                 A(i, j) = SUM;
    5474              :             }
    5475              :         }
    5476              : 
    5477              :         // Solve the simultaneous equations using Gauss elimination
    5478            0 :         NM1 = N - 1;
    5479            0 :         for (int K = 1; K <= NM1; ++K) {
    5480            0 :             int KP1 = K + 1;
    5481            0 :             for (int i = KP1; i <= N; ++i) {
    5482            0 :                 ACON = A(K, i) / A(K, K);
    5483            0 :                 B(i) -= B(K) * ACON;
    5484            0 :                 for (int j = K; j <= N; ++j) {
    5485            0 :                     A(j, i) -= A(j, K) * ACON;
    5486              :                 }
    5487              :             }
    5488              :         }
    5489              : 
    5490              :         // Perform back substitution
    5491            0 :         CoeffsCurve(N) = B(N) / A(N, N);
    5492            0 :         LP1 = N;
    5493            0 :         int L = N - 1;
    5494              : 
    5495            0 :         while (L > 0) {
    5496            0 :             SUM = 0.0;
    5497            0 :             for (int j = LP1; j <= N; ++j) {
    5498            0 :                 SUM += A(j, L) * CoeffsCurve(j);
    5499              :             }
    5500            0 :             CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
    5501            0 :             LP1 = L;
    5502            0 :             --L;
    5503              :         }
    5504            0 :     } // W5LsqFit2()
    5505              : 
    5506              :     //***********************************************************************
    5507              : 
    5508         1982 :     Real64 DiffuseAverage(std::array<Real64, numPhis> const &props) // Property value at angles of incidence
    5509              :     {
    5510              : 
    5511              :         // FUNCTION INFORMATION:
    5512              :         //       AUTHOR         Fred Winkelmann
    5513              :         //       DATE WRITTEN   November 1999
    5514              :         //       MODIFIED       na
    5515              :         //       RE-ENGINEERED  na
    5516              : 
    5517              :         // PURPOSE OF THIS FUNCTION:
    5518              :         // Calculate value of property, such as transmittance, for hemispherical
    5519              :         // diffuse radiation from property values at angles of incidence from
    5520              :         // 0 to 90 degrees in 10 degree increments.
    5521              : 
    5522              :         // METHODOLOGY EMPLOYED:
    5523              :         // By Simpson's rule, evaluates the integral from 0 to 90 deg of
    5524              :         // 2*PropertyValue(phi)*cos(phi)*sin(phi)*dphi (which is same as
    5525              :         // PropertyValue(phi)*sin(2*phi)*dphi)
    5526              : 
    5527              :         // Locals
    5528              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    5529              :         // 0,10,20,...,80,90 degrees
    5530              : 
    5531         1982 :         constexpr Real64 dPhiR = dPhiDeg * Constant::DegToRad; // Half of 10-deg incidence angle increment (radians)
    5532              : 
    5533         1982 :         Real64 avg = 0.0;
    5534        19820 :         for (int iPhi = 0; iPhi < numPhis - 1; ++iPhi) {
    5535        17838 :             avg += 0.5 * dPhiR * (props[iPhi] * std::sin(2.0 * iPhi * dPhiR) + props[iPhi + 1] * std::sin(2.0 * (iPhi + 1) * dPhiR));
    5536              :         }
    5537              : 
    5538         1982 :         return (avg < 0.0) ? 0.0 : avg;
    5539              :     } // DiffuseAverage()
    5540              : 
    5541              :     //*************************************************************************************
    5542              : 
    5543            9 :     void CalcWinFrameAndDividerTemps(EnergyPlusData &state,
    5544              :                                      int const SurfNum,     // Surface number
    5545              :                                      Real64 const tout,     // Outside air temperature (K)
    5546              :                                      Real64 const tin,      // Inside air temperature (K)
    5547              :                                      Real64 const HOutConv, // Outside convective air film conductance (W/m2-K)
    5548              :                                      Real64 const HInConv,  // Inside convective air film conductance (W/m2-K)
    5549              :                                      Real64 const Outir,    // Exterior IR irradiance from sky and ground
    5550              :                                      int const ConstrNum    // Construction number of window
    5551              :     )
    5552              :     {
    5553              : 
    5554              :         // SUBROUTINE INFORMATION:
    5555              :         //       AUTHOR         F. Winkelmann
    5556              :         //       DATE WRITTEN   May 2000
    5557              :         //       MODIFIED       Aug 2000, FCW: Add effect of frame and divider projections
    5558              :         //                      Jun 2001, FCW: Add frame/divider contribution to WinHeatGain
    5559              :         //                      Aug 2003, FCW: Fix calculation of divider outside temp: frame
    5560              :         //                       inside temp was being used instead of divider inside temp
    5561              :         //       RE-ENGINEERED  na
    5562              : 
    5563              :         // PURPOSE OF THIS SUBROUTINE:
    5564              :         // Calculates window frame divider face temperatures from a linearized
    5565              :         // heat balance on the inside and outside faces
    5566              : 
    5567              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5568              :         Real64 HInRad;            // Inside radiative conductance (W/m2-K)
    5569              :         Real64 HOutRad;           // Outside radiative conductance (W/m2-K)
    5570              :         int FrDivNum;             // Frame/divider number
    5571              :         Real64 TInRad;            // Inside radiative temperature (K)
    5572              :         Real64 TInRadFr;          // Effective inside radiative temperature for frame (K)
    5573              :         Real64 TInRadDiv;         // Effective inside radiative temperature for divider (K)
    5574              :         Real64 TOutRad;           // Outside radiative temperature (K)
    5575              :         Real64 TOutRadFr;         // Effective outside radiative temperature for frame (K)
    5576              :         Real64 TOutRadDiv;        // Effective outside radiative temperature for divider (K)
    5577              :         WinShadingType ShadeFlag; // Window shading flag
    5578              :         Real64 FrameCon;          // Frame conductance (W/m2-K)
    5579              : 
    5580              :         Real64 Afac; // Intermediate calculation variables
    5581              :         Real64 Bfac;
    5582              :         Real64 Dfac;
    5583              :         Real64 Efac;
    5584              :         DataSurfaces::FrameDividerType DivType; // Divider type
    5585              :         Real64 DivCon;                          // Divider conductance (W/m2-K)
    5586              :         Real64 DivEmisIn;                       // Inside divider emissivity
    5587              :         Real64 DivEmisOut;                      // Outside divider emissivity
    5588              : 
    5589              :         Real64 ProjCorrFrOut; // Outside correction factor for absorbed radiation
    5590              :         //   for frame with outside projection
    5591              :         Real64 ProjCorrFrIn; // Inside correction factor for absorbed radiation
    5592              :         //   for frame with inside projection
    5593              :         Real64 HOutConvFr; // Effective outside convective coeff for frame
    5594              :         //   with outside projection (W/m2-K)
    5595              :         Real64 HOutConvDiv; // Effective outside convective coeff for divider
    5596              :         //   with outside projection (W/m2-K)
    5597              :         Real64 HInConvFr; // Effective inside convective coeff for frame
    5598              :         //   with inside projection (W/m2-K)
    5599              :         Real64 HInConvDiv; // Effective inside convective coeff for divider
    5600              :         //   with inside projection (W/m2-K)
    5601              :         Real64 EmisGlassOut; // Outside surface emissivity of window glazing
    5602              :         Real64 EmisGlassIn;  // Inside surface emissivity of window glazing
    5603              :         int TotGlassLayers;  // Total number of glass layers
    5604              :         int TotLayers;       // Total number of layers in unshaded construction
    5605              :         // Real64 DivTempOut;          // Outside surface divider temperature (K)
    5606              :         Real64 FrameHeatGain; // Heat gain to zone from frame (W)
    5607              :         // Real64 FrameHeatTransfer;   // Heat transfer through frame (W)
    5608              :         // Real64 ProjCorrWinHeatGain; // Inside projection correction to IR from divider to zone
    5609              :         //   for window heat gain calculation
    5610              :         Real64 DividerHeatGain; // Heat gain to zone from divider (W)
    5611              :         // Real64 DividerHeatTransfer; // Heat transfer through divider (W)
    5612              : 
    5613            9 :         auto &s_mat = state.dataMaterial;
    5614            9 :         auto &s_surf = state.dataSurface;
    5615              : 
    5616            9 :         auto const &surfWin = s_surf->SurfaceWindow(SurfNum);
    5617              : 
    5618            9 :         TInRad = root_4(s_surf->SurfWinIRfromParentZone(SurfNum) / Constant::StefanBoltzmann);
    5619            9 :         TOutRad = root_4(Outir / Constant::StefanBoltzmann);
    5620            9 :         ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
    5621            9 :         FrDivNum = s_surf->Surface(SurfNum).FrameDivider;
    5622            9 :         auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
    5623            9 :         TotLayers = thisConstruct.TotLayers;
    5624            9 :         TotGlassLayers = thisConstruct.TotSolidLayers;
    5625            9 :         EmisGlassOut = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
    5626            9 :         EmisGlassIn = s_mat->materials(thisConstruct.LayerPoint(TotLayers))->AbsorpThermalBack;
    5627            9 :         FrameHeatGain = 0.0;
    5628            9 :         DividerHeatGain = 0.0;
    5629            9 :         s_surf->SurfWinFrameHeatGain(SurfNum) = 0.0;
    5630            9 :         s_surf->SurfWinFrameHeatLoss(SurfNum) = 0.0;
    5631            9 :         s_surf->SurfWinDividerHeatGain(SurfNum) = 0.0;
    5632            9 :         s_surf->SurfWinDividerHeatLoss(SurfNum) = 0.0;
    5633              : 
    5634            9 :         if (s_surf->SurfWinFrameArea(SurfNum) > 0.0) {
    5635              :             // Window has a frame. Note that if a shade, screen or blind is present it covers only the glazed part of the
    5636              :             // window and is assumed not to shadow long- or short-wave radiation incident on the frame elements.
    5637            9 :             ProjCorrFrOut = s_surf->SurfWinProjCorrFrOut(SurfNum);
    5638            9 :             ProjCorrFrIn = s_surf->SurfWinProjCorrFrIn(SurfNum);
    5639            9 :             TOutRadFr = TOutRad * root_4((1.0 + 0.5 * ProjCorrFrOut) / (1.0 + ProjCorrFrOut));
    5640            9 :             TInRadFr = TInRad * root_4((1.0 + 0.5 * ProjCorrFrIn) / (1.0 + ProjCorrFrIn));
    5641            9 :             FrameCon = s_surf->SurfWinFrameConductance(SurfNum);
    5642            9 :             HInRad = 0.5 * s_surf->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
    5643            9 :                      pow_3(TInRadFr + s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin);
    5644            9 :             HInConvFr = HInConv;
    5645            9 :             HOutRad = 0.5 * s_surf->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
    5646            9 :                       pow_3(TOutRadFr + s_surf->SurfWinFrameTempSurfOut(SurfNum) + Constant::Kelvin);
    5647            9 :             HOutConvFr = HOutConv;
    5648            9 :             auto const &frdiv = s_surf->FrameDivider(FrDivNum);
    5649            9 :             if (frdiv.FrameProjectionOut > 0.0) {
    5650            0 :                 HOutRad *= (1.0 + ProjCorrFrOut);
    5651            0 :                 HOutConvFr = HOutConv * (1.0 + ProjCorrFrOut);
    5652              :                 // Add long-wave from outside window surface absorbed by frame outside projection
    5653            0 :                 s_surf->SurfWinFrameQRadOutAbs(SurfNum) += 0.5 * s_surf->SurfWinProjCorrFrOut(SurfNum) * frdiv.FrameEmis * EmisGlassOut *
    5654            0 :                                                            Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
    5655              :             }
    5656            9 :             if (frdiv.FrameProjectionIn > 0.0) {
    5657            0 :                 HInRad *= (1.0 + ProjCorrFrIn);
    5658            0 :                 HInConvFr = HInConv * (1.0 + ProjCorrFrIn);
    5659              :                 // Add long-wave from inside window surface absorbed by frame inside projection
    5660            0 :                 s_surf->SurfWinFrameQRadInAbs(SurfNum) += 0.5 * s_surf->SurfWinProjCorrFrIn(SurfNum) * frdiv.FrameEmis * EmisGlassIn *
    5661            0 :                                                           Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
    5662              :             }
    5663            9 :             Afac = (HOutRad * TOutRadFr + HOutConvFr * tout + s_surf->SurfWinFrameQRadOutAbs(SurfNum)) / (HOutRad + FrameCon + HOutConvFr);
    5664            9 :             Bfac = FrameCon / (HOutRad + FrameCon + HOutConvFr);
    5665            9 :             Dfac = (HInRad * TInRadFr + HInConvFr * tin + s_surf->SurfWinFrameQRadInAbs(SurfNum)) / (HInRad + FrameCon + HInConvFr);
    5666            9 :             Efac = FrameCon / (HInRad + FrameCon + HInConvFr);
    5667            9 :             s_surf->SurfWinFrameTempIn(SurfNum) = (Dfac + Efac * Afac) / (1.0 - Efac * Bfac) - Constant::Kelvin;
    5668            9 :             s_surf->SurfWinFrameTempSurfOut(SurfNum) = Afac + Bfac * (s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
    5669              :             // Heat gain to zone from frame
    5670              : 
    5671              :             // FrameHeatTransfer = s_surf->SurfWinFrameArea(SurfNum) * FrameCon *
    5672              :             //                     (s_surf->SurfWinFrameTempSurfOut(SurfNum) - s_surf->SurfWinFrameTempIn(SurfNum));
    5673            9 :             FrameHeatGain = s_surf->SurfWinFrameArea(SurfNum) * (1.0 + s_surf->SurfWinProjCorrFrIn(SurfNum)) *
    5674            9 :                             (HInConvFr * (s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin - tin));
    5675              : 
    5676            9 :             if (FrameHeatGain > 0.0) {
    5677            0 :                 s_surf->SurfWinFrameHeatGain(SurfNum) = FrameHeatGain;
    5678              :             } else {
    5679            9 :                 s_surf->SurfWinFrameHeatLoss(SurfNum) = std::abs(FrameHeatGain);
    5680              :             }
    5681              : 
    5682            9 :             s_surf->SurfWinHeatGain(SurfNum) += FrameHeatGain;
    5683            9 :             s_surf->SurfWinGainFrameDividerToZoneRep(SurfNum) = FrameHeatGain;
    5684              :         } // End of check if window has a frame
    5685              : 
    5686            9 :         if (s_surf->SurfWinDividerArea(SurfNum) > 0.0 && s_surf->SurfWinStormWinFlag(SurfNum) < 1) {
    5687              :             // Window has divider. Note that if the window has a storm window layer in place (StormWinFlag = 1)
    5688              :             // the divider heat transfer calculation is not done.
    5689              : 
    5690            9 :             DivType = s_surf->SurfWinDividerType(SurfNum);
    5691            9 :             DivCon = s_surf->SurfWinDividerConductance(SurfNum);
    5692              : 
    5693            9 :             if (DivType == DataSurfaces::FrameDividerType::DividedLite) { // Divided lite
    5694            9 :                 DivEmisIn = s_surf->SurfWinDividerEmis(SurfNum);
    5695            9 :                 DivEmisOut = DivEmisIn;
    5696              :             } else { // Suspended (between-glass) divider
    5697            0 :                 DivEmisOut = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
    5698            0 :                 DivEmisIn = s_mat->materials(thisConstruct.LayerPoint(thisConstruct.TotLayers))->AbsorpThermalBack;
    5699              :             }
    5700              : 
    5701            9 :             TOutRadDiv = TOutRad * root_4((1.0 + s_surf->SurfWinProjCorrDivOut(SurfNum)) / (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum)));
    5702            9 :             TInRadDiv = TInRad * root_4((1.0 + s_surf->SurfWinProjCorrDivIn(SurfNum)) / (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum)));
    5703            9 :             HInRad = 0.5 * DivEmisIn * Constant::StefanBoltzmann * pow_3(TInRadDiv + s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin);
    5704            9 :             HOutRad =
    5705            9 :                 0.5 * DivEmisOut * Constant::StefanBoltzmann * pow_3(TOutRadDiv + s_surf->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin);
    5706            9 :             HOutConvDiv = HOutConv;
    5707            9 :             auto const &frdiv = s_surf->FrameDivider(FrDivNum);
    5708            9 :             if (frdiv.DividerProjectionOut > 0.0) {
    5709            0 :                 HOutRad *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum));
    5710            0 :                 if (s_surf->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) HOutConvDiv = s_surf->SurfWinConvCoeffWithShade(SurfNum);
    5711            0 :                 HOutConvDiv *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum));
    5712              :                 // Add long-wave from outside window surface absorbed by divider outside projection
    5713            0 :                 s_surf->SurfWinDividerQRadOutAbs(SurfNum) += s_surf->SurfWinProjCorrDivOut(SurfNum) * frdiv.DividerEmis * EmisGlassOut *
    5714            0 :                                                              Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
    5715              :             }
    5716              : 
    5717            9 :             HInConvDiv = HInConv;
    5718              : 
    5719            9 :             if (frdiv.DividerProjectionIn > 0.0) {
    5720            0 :                 HInRad *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum));
    5721            0 :                 if (s_surf->SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade) HInConvDiv = s_surf->SurfWinConvCoeffWithShade(SurfNum);
    5722            0 :                 HInConvDiv *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum));
    5723              :                 // Add long-wave from inside window surface absorbed by divider inside projection
    5724            0 :                 s_surf->SurfWinDividerQRadInAbs(SurfNum) += s_surf->SurfWinProjCorrDivIn(SurfNum) * frdiv.DividerEmis * EmisGlassIn *
    5725            0 :                                                             Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
    5726              :             }
    5727            9 :             Afac = (HOutRad * TOutRadDiv + HOutConvDiv * tout + s_surf->SurfWinDividerQRadOutAbs(SurfNum)) / (HOutRad + DivCon + HOutConvDiv);
    5728            9 :             Bfac = DivCon / (HOutRad + DivCon + HOutConvDiv);
    5729            9 :             Dfac = (HInRad * TInRadDiv + HInConvDiv * tin + s_surf->SurfWinDividerQRadInAbs(SurfNum)) / (HInRad + DivCon + HInConvDiv);
    5730            9 :             Efac = DivCon / (HInRad + DivCon + HInConvDiv);
    5731            9 :             s_surf->SurfWinDividerTempIn(SurfNum) = (Dfac + Efac * Afac) / (1 - Efac * Bfac) - Constant::Kelvin;
    5732            9 :             s_surf->SurfWinDividerTempSurfOut(SurfNum) = Afac + Bfac * (s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
    5733              :             // Contribution of divider to window heat gain
    5734              :             // ProjCorrWinHeatGain = 1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum);
    5735              : 
    5736            9 :             DividerHeatGain = s_surf->SurfWinDividerArea(SurfNum) * (1.0 + s_surf->SurfWinProjCorrDivIn(SurfNum)) *
    5737            9 :                               (HInConvDiv * (s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin - tin));
    5738              :             // DividerHeatTransfer = s_surf->SurfWinDividerArea(SurfNum) * DivCon *
    5739              :             //                      (s_surf->SurfWinDividerTempSurfOut(SurfNum) - s_surf->SurfWinDividerTempIn(SurfNum));
    5740              : 
    5741            9 :             if (DividerHeatGain > 0.0) {
    5742            0 :                 s_surf->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
    5743              :             } else {
    5744            9 :                 s_surf->SurfWinDividerHeatLoss(SurfNum) = std::abs(DividerHeatGain);
    5745              :             }
    5746            9 :             s_surf->SurfWinHeatGain(SurfNum) += DividerHeatGain;
    5747            9 :             s_surf->SurfWinGainFrameDividerToZoneRep(SurfNum) += DividerHeatGain;
    5748              :             // If interior shade is present it is assumed that both the convective and IR radiative gain
    5749              :             // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
    5750              :             // interaction between divider and shade is ignored due to the difficulty of calculating this interaction
    5751              :             // at the same time that the interaction between glass and shade is calculated.
    5752            9 :             if (ANY_INTERIOR_SHADE_BLIND(s_surf->SurfWinShadingFlag(SurfNum))) s_surf->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
    5753              :             // DivTempOut = s_surf->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin;
    5754              :         } // End of check if window has dividers
    5755            9 :     }     // CalcWinFrameAndDividerTemps()
    5756              : 
    5757              :     //************************************************************************************
    5758              : 
    5759           66 :     void CalcNominalWindowCond(EnergyPlusData &state,
    5760              :                                int const ConstrNum,        // Construction number
    5761              :                                int const WinterSummerFlag, // 1=winter, 2=summer
    5762              :                                Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
    5763              :                                Real64 &SHGC,               // Nominal center-of-glass solar heat gain coefficient for
    5764              :                                Real64 &TSolNorm,           // Overall beam solar transmittance at normal incidence
    5765              :                                Real64 &TVisNorm,           // Overall beam visible transmittance at normal incidence
    5766              :                                int &errFlag                // Error flag
    5767              :     )
    5768              :     {
    5769              : 
    5770              :         // SUBROUTINE INFORMATION:
    5771              :         //       AUTHOR         F. Winkelmann
    5772              :         //       DATE WRITTEN   September 2000
    5773              :         //       MODIFIED       Oct 2000, FW: add solar heat gain coefficient
    5774              :         //                      June 2001, FW: account for blinds; change summer outside air
    5775              :         //                       temp from 35.0C to 31.7C to correspond to ASHRAE value
    5776              :         //                      Feb 2003, FW: add comments that this routine is not called for
    5777              :         //                       between-glass shade/blind constructions.
    5778              :         //                      May 2006, RR: account for screens
    5779              :         //                      Oct 2007, LKL: change temps to match Window 5 values
    5780              :         //                      Feb 2009, BG: Changes for CR7682 (SHGC)
    5781              :         //       RE-ENGINEERED  na
    5782              : 
    5783              :         // PURPOSE OF THIS SUBROUTINE:
    5784              :         // Calculates nominal center-of-glass U-value and solar heat gain coefficient
    5785              :         // (SHGC) of a window construction for ASHRAE winter and summer conditions.
    5786              :         // This function is just for reporting
    5787              :         // Winter:
    5788              :         // Inside air temperature = 21.C (69.80F)
    5789              :         // Outside air temperature = -18C (-.4F)
    5790              :         // Windspeed = 5.5 m/s (12.3 mph)
    5791              :         // No solar radiation
    5792              :         // Replaced Winter:
    5793              :         // Inside air temperature = 21.1C (70F)
    5794              :         // Outside air temperature = -17.8C (0F)
    5795              :         // Windspeed = 6.71 m/s (15 mph)
    5796              :         // No solar radiation
    5797              :         // Summer:
    5798              :         // Inside air temperature = 24C (75.2F)
    5799              :         // Outside air temperature = 32C (89.6F)
    5800              :         // Windspeed = 2.8 m/s (6.2 mph)
    5801              :         // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
    5802              :         // Replaced Summer:
    5803              :         // Inside air temperature = 24C (75.2F) ! BG changed again Feb. 2009 by 0.1 (per Window5 team)
    5804              :         // Outside air temperature = 31.7C (89F)
    5805              :         // Windspeed = 3.35 m/s (7.5 mph)
    5806              :         // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
    5807              :         // The window's inside surround is assumed to be a black body at the inside air temp.
    5808              :         // The window's outside surround is assumed t be a black body at the outside air temp.
    5809              :         // Note that in this routine we use a value of 26 W/m2 for the outside convective
    5810              :         // air film conductance for 5.5 m/s (12.3 mph) wind speed.
    5811              :         // This is the value used in Window 5 and is also the value for which the center-of-glass
    5812              :         // conductances in the EnergyPlus window construction reference data set were calculated.
    5813              :         // However, in the time step loop we will have different values of outside film
    5814              :         // conductance depending on that time step's wind speed, wind direction, surface-to-air temp difference,
    5815              :         // etc.(see subroutine InitExteriorConvectionCoeff).
    5816              :         // This routine will return an error and exit for window constructions with between-glass shade or blind
    5817              :         // until a method is worked out to determine the nominal conductance and SHGC in this case.
    5818              :         // If an interior or exterior shade or blind is present in the construction,
    5819              :         // the conductance calculation does not include the effect of the shade or blind.
    5820              :         // This is because in this case the conductance depends on the natural convective
    5821              :         // air flow in the shade/glass, screen/glass or blind/glass channel, which in turn is highly dependent
    5822              :         // on window height and other parameters that are not part of the construction definition.
    5823              :         // Therefore, the reported conductance value will be too high for windows with a tightly fitting
    5824              :         // shade, screen or blind with a relatively high thermal resistance.
    5825              :         // For SHGC calculation, all solar absorbed by interior blind or shade is assumed
    5826              :         // to go into zone air. (This is not true in general; the fraction of this absorbed solar that
    5827              :         // is conducted back out is accounted for in the time-step glazing calculation.)
    5828              :         // For CR 7682, the SHGC calculations were changed to model the absorbed solar arriving at the middle of the layer
    5829              :         // rather than at the outer face of the layer.  The resistances changed by one half the glazing layer, or 0.5/scon(n).
    5830              :         // (CR 7682 also changed WindowTempsForNominalCond to include absorbed solar, a bigger change)
    5831              : 
    5832              :         // Locals
    5833              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    5834              :         //   normal incidence beam solar radiation
    5835              : 
    5836              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5837              :         int TotLay; // Total number of layers in a construction
    5838              :         //   (sum of solid layers and gap layers)
    5839              :         int TotGlassLay; // Total number of glass layers in a construction
    5840              :         int LayPtr;      // Material number for a layer
    5841              : 
    5842              :         Real64 BeamSolarInc; // Incident beam radiation at zero angle of incidence (W/m2)
    5843              :                              //        Real64 hOutRad;      // Radiative conductance of outside and inside airfilm [W/m2-K]
    5844              :                              //        Real64 hInRad;
    5845              :                              //        Real64 rOut; // Combined radiative and conductive outside and inside film
    5846              :                              //        Real64 rIn;
    5847              :         //   resistance [m2-K/W]
    5848              :         Array1D<Real64> hgap(
    5849           66 :             maxGlassLayers);      // Conductive gap conductance [W/m2-K]
    5850              :                                   //        Array1D<Real64> hGapTot(5);     // Combined radiative and conductive gap conductance [W/m2-K]
    5851              :                                   //        Real64 Rbare;                   // Nominal center-of-glass resistance without air films [m2-K/W]
    5852              :         WinShadingType ShadeFlag; // Shading flag
    5853              :         Real64 ShadeRes;          // Thermal resistance of shade
    5854              :         int MatOutside;           // Material number of outside layer of construction
    5855              :         int MatInside;            // Material number of inside layer of construction
    5856              :         int MatShade;             // Material number of shade layer
    5857           66 :         Array1D<Real64> AbsBeamNorm(maxGlassLayers); // Beam absorptance at normal incidence for each glass layer
    5858              :         Real64 AbsBeamShadeNorm;                     // Shade solar absorptance at normal incidence
    5859              :         int ConstrNumBare;                           // Construction without shading device
    5860              :         int BlNum;                                   // Blind number
    5861              :         Real64 SlatAng;                              // Slat angle (rad)
    5862              :         int LayPtrSh;                                // Layer pointer of blind
    5863              :         Real64 TBmBm;                                // Bare glass normal incidence beam-beam transmittance
    5864              :         Real64 TBmBmVis;
    5865              :         Real64 TBlBmBm; // Normal incidence blind beam-beam transmittance
    5866              :         Real64 TScBmBm; // Screen incident beam-beam transmittance
    5867              :         Real64 TScBmBmVis;
    5868              :         Real64 TBmBmBl; // TBmBm * TBlBmBm, TBmBmVis * TBlBmBm
    5869              :         Real64 TBmBmBlVis;
    5870              :         Real64 RGlDiffBack; // Bare glass back sol/vis reflectance
    5871              :         Real64 RGlDiffBackVis;
    5872              :         Real64 RGlDiffFront; // Bare glass front sol/vis reflectance
    5873              :         Real64 RGlDiffFrontVis;
    5874              :         Real64 RhoBlFront; // Blind normal front beam-diffuse sol/vis reflectance
    5875              :         Real64 RhoBlFrontVis;
    5876              :         Real64 RhoBlBack; // Blind normal back beam-diffuse sol/vis reflectance
    5877              :         Real64 RhoBlBackVis;
    5878              :         Real64 RScBack; // Screen back beam-diffuse sol/vis reflectance (same as front)
    5879              :         Real64 RScBackVis;
    5880              :         Real64 AbsBlFront;     // Blind normal front beam solar absorptance
    5881              :         Real64 AbsBlBack;      // Blind normal back beam solar absorptance
    5882              :         Real64 RhoBlDiffFront; // Blind front diffuse-diffuse sol/vis reflectance
    5883              :         Real64 RhoBlDiffFrontVis;
    5884              :         Real64 AbsBlDiffFront; // Blind front diffuse solar absorptance
    5885              :         Real64 AbsBlDiffBack;  // Blind back diffuse solar absorptance
    5886              :         Real64 RGlFront;       // Bare glass normal front beam sol/vis reflectance
    5887              :         Real64 RGlFrontVis;
    5888              :         Real64 RhoBlDiffBack; // Blind back diffuse-diffuse sol/vis reflectance
    5889              :         Real64 RhoBlDiffBackVis;
    5890              :         Real64 RScDifBack; // Screen back diffuse-diffuse sol/vis reflectance (doesn't change with sun angle)
    5891              :         Real64 RScDifBackVis;
    5892              :         Real64 TBlBmDif; // Blind front normal beam-diffuse sol/vis transmittance
    5893              :         Real64 TBlBmDifVis;
    5894              :         Real64 TBlDifDif; // Blind front diffuse-diffuse sol/vis transmittance
    5895              :         Real64 TBlDifDifVis;
    5896              :         Real64 TScBmDif; // Screen front beam-diffuse sol/vis transmittance
    5897              :         Real64 TScBmDifVis;
    5898              :         Real64 TDif; // Bare glass diffuse sol/vis transmittance
    5899              :         Real64 TDifVis;
    5900              :         Real64 AGlDiffBack; // Back diffuse solar absorptance of a glass layer
    5901              : 
    5902           66 :         auto &s_mat = state.dataMaterial;
    5903           66 :         auto &s_surf = state.dataSurface;
    5904           66 :         auto &wm = state.dataWindowManager;
    5905              :         // Autodesk:Uninit Initialize variables used uninitialized
    5906              :         //        Rbare = 0.0; // Autodesk:Uninit Force default initialization
    5907              : 
    5908           66 :         NominalConductance = 0.0;
    5909           66 :         errFlag = 0;
    5910           66 :         TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5911           66 :         TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    5912           66 :         wm->ngllayer = TotGlassLay; // Autodesk:Uninit This routine needs to check/enforce 1<=ngllayer<=4
    5913              :         // EPTeam - believe that is done on input.
    5914           66 :         wm->nglface = 2 * wm->ngllayer;
    5915           66 :         wm->tilt = 90.0; // Assume vertical window
    5916              : 
    5917           66 :         if (WinterSummerFlag == 1) { // Winter
    5918              :             // LKL Oct 2007:  According to Window5, Winter environmental conditions are:
    5919           41 :             wm->tin = 294.15;  // Inside air temperature (69.8F, 21.C)
    5920           41 :             wm->tout = 255.15; // Outside air temperature (-.4F, -18C)
    5921           41 :             wm->hcout = 26.0;  // Outside convective film conductance for 5.5 m/s (12.3 mph) wind speed
    5922              :             // (the value used in Window 5)
    5923              :             //  tin = 294.26   ! Inside air temperature (70F, 21.1C)
    5924              :             //  tout = 255.35  ! Outside air temperature (0F, -17.8C)
    5925              :             //  hcout = 25.47  ! Outside convective film conductance for 6.71 m/s (15 mph) wind speed
    5926              :             //                 ! (the value used in Window 4)
    5927           41 :             BeamSolarInc = 0.0;
    5928              :         } else { // Summer
    5929              :             // LKL Oct 2007: According to Window5, Summer environmental conditions are:
    5930              :             // tin = 297.05d0   ! Inside air temperature (75.2F, 24C)
    5931              :             // BG Feb. 2009: According to Window5 Expert Christian Kohler, it is exactly 24C or 297.15
    5932           25 :             wm->tin = 297.15;
    5933           25 :             wm->tout = 305.15; // Outside air temperature (89.6F, 32C)
    5934           25 :             wm->hcout = 15.0;  // Outside convective film conductance for 2.8 m/s (6.2 mph) wind speed
    5935              :             // (the value used in Window 5)
    5936              :             //  tin = 297.05   ! Inside air temperature (75F, 23.9C)
    5937              :             //  !tout = 308.15  ! Outside air temperature (95F, 35.0C)
    5938              :             //  ! Changed 6/20/01 by FCW to make consistent with Window 4 and 5.
    5939              :             //  tout = 304.82  ! Outside air temperature (89F, 31.7C)
    5940              :             //  hcout = 18.86  ! Outside convective film conductance for 3.35 m/s (7.5 mph) wind speed
    5941              :             //                 ! (average of Window 4 0 m/s and 6.71 m/s values)
    5942           25 :             BeamSolarInc = 783.0;
    5943              :         }
    5944              : 
    5945              :         // IR incident on inside of glazing (inside surround assumed to be
    5946              :         // a black body at inside air temperature)
    5947           66 :         wm->Rmir = Constant::StefanBoltzmann * pow_4(wm->tin);
    5948              : 
    5949              :         // IR incident on outside of glazing
    5950              :         // (outside surround is assumed to be a black body at outside air temperature)
    5951           66 :         wm->Outir = Constant::StefanBoltzmann * pow_4(wm->tout);
    5952              : 
    5953              :         // Determine whether construction has an exterior or interior shade or blind
    5954           66 :         ShadeFlag = WinShadingType::NoShade;
    5955           66 :         ShadeRes = 0.0;
    5956           66 :         MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
    5957           66 :         MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
    5958           66 :         if (s_mat->materials(MatOutside)->group == Material::Group::Shade) { // Exterior shade present
    5959            0 :             MatShade = MatOutside;
    5960            0 :             ShadeFlag = WinShadingType::ExtShade;
    5961              :             // Set glazing outside convection coefficient to Window 4 still-air value
    5962            0 :             wm->hcout = 12.25;
    5963           66 :         } else if (s_mat->materials(MatOutside)->group == Material::Group::Screen) { // Exterior screen present
    5964            0 :             MatShade = MatOutside;
    5965            0 :             ShadeFlag = WinShadingType::ExtScreen;
    5966            0 :             wm->hcout = 12.25;
    5967           66 :         } else if (s_mat->materials(MatOutside)->group == Material::Group::Blind) { // Exterior blind present
    5968            0 :             MatShade = MatOutside;
    5969            0 :             ShadeFlag = WinShadingType::ExtBlind;
    5970            0 :             BlNum = MatOutside;
    5971            0 :             wm->hcout = 12.25;
    5972           66 :         } else if (s_mat->materials(MatInside)->group == Material::Group::Shade) { // Interior shade present
    5973            0 :             MatShade = MatInside;
    5974            0 :             ShadeFlag = WinShadingType::IntShade;
    5975           66 :         } else if (s_mat->materials(MatInside)->group == Material::Group::Blind) { // Interior blind present
    5976            2 :             MatShade = MatInside;
    5977            2 :             BlNum = MatShade;
    5978            2 :             ShadeFlag = WinShadingType::IntBlind;
    5979           64 :         } else if (TotGlassLay == 2) {
    5980           17 :             if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Shade)
    5981            0 :                 ShadeFlag = WinShadingType::BGShade;
    5982           17 :             if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Blind)
    5983            0 :                 ShadeFlag = WinShadingType::BGBlind;
    5984           47 :         } else if (TotGlassLay == 3) {
    5985            0 :             if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Shade)
    5986            0 :                 ShadeFlag = WinShadingType::BGShade;
    5987            0 :             if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Blind)
    5988            0 :                 ShadeFlag = WinShadingType::BGBlind;
    5989              :         }
    5990              : 
    5991           66 :         if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    5992            0 :             errFlag = 2;
    5993            0 :             return;
    5994              :         }
    5995              : 
    5996           66 :         TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef);
    5997           66 :         TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef);
    5998           66 :         AbsBeamShadeNorm = 0.0;
    5999           66 :         if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { // Exterior or interior shade on
    6000            0 :             AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef);
    6001              :             // Exterior blind or screen or interior blind on
    6002           66 :         } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) {
    6003              :             // Find unshaded construction that goes with this construction w/blind or screen
    6004            2 :             ConstrNumBare = 0;
    6005           24 :             for (int ConstrNum1 = 1; ConstrNum1 <= state.dataHeatBal->TotConstructs; ++ConstrNum1) {
    6006           24 :                 if (ConstrNum1 != ConstrNum && state.dataConstruction->Construct(ConstrNum1).TypeIsWindow &&
    6007           50 :                     state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum1).TotSolidLayers &&
    6008            2 :                     state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum).TotGlassLayers) {
    6009              :                     // We have an unshaded window construction with the same number of glass layers as ConstrNum;
    6010              :                     // see if the glass and gas layers match
    6011            2 :                     ConstrNumBare = ConstrNum1;
    6012            4 :                     for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) {
    6013            2 :                         LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay);
    6014            2 :                         if (ShadeFlag == WinShadingType::IntBlind) { // The shaded construction has an interior blind
    6015            2 :                             LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    6016              :                         } else { // The shaded construction has an exterior blind or screen
    6017            0 :                             LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1);
    6018              :                         }
    6019            2 :                         if (LayPtrSh != LayPtr) ConstrNumBare = 0;
    6020              :                     }
    6021            2 :                     if (ConstrNumBare != 0) break;
    6022              :                 }
    6023              :             }
    6024            2 :             if (ConstrNumBare == 0) {
    6025              :                 // No matching bare construction found for this construction with blind or screen
    6026            0 :                 errFlag = 1;
    6027            0 :                 return;
    6028              :             }
    6029              : 
    6030            2 :             auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6031            2 :             TBmBm = POLYF(1.0, constructBare.TransSolBeamCoef);
    6032            2 :             TBmBmVis = POLYF(1.0, constructBare.TransVisBeamCoef);
    6033              : 
    6034            2 :             if (ShadeFlag == WinShadingType::ExtScreen) {
    6035              :                 //   Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond)
    6036              :                 //   Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties
    6037            0 :                 auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(MatShade));
    6038            0 :                 assert(matScreen != nullptr);
    6039            0 :                 auto const &btar = matScreen->btars[0][0];
    6040            0 :                 TScBmBm = btar.BmTrans;
    6041            0 :                 TScBmBmVis = btar.BmTransVis;
    6042            0 :                 TScBmDif = btar.DfTrans;
    6043            0 :                 TScBmDifVis = btar.DfTransVis;
    6044            0 :                 TDif = constructBare.TransDiff;
    6045            0 :                 TDifVis = constructBare.TransDiffVis;
    6046            0 :                 RScBack = matScreen->ShadeRef;
    6047            0 :                 RScBackVis = matScreen->ShadeRefVis;
    6048            0 :                 RScDifBack = matScreen->DfRef;
    6049            0 :                 RScDifBackVis = matScreen->DfRefVis;
    6050            0 :                 RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6051            0 :                 RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6052            0 :                 RGlDiffFront = constructBare.ReflectSolDiffFront;
    6053            0 :                 RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
    6054            0 :                 TSolNorm = TScBmBm * (TBmBm + TDif * RGlFront * RScBack / (1 - RGlDiffFront * RScDifBack)) +
    6055            0 :                            TScBmDif * TDif / (1 - RGlDiffFront * RScDifBack);
    6056            0 :                 TVisNorm = TScBmBmVis * (TBmBmVis + TDifVis * RGlFrontVis * RScBackVis / (1 - RGlDiffFrontVis * RScDifBackVis)) +
    6057            0 :                            TScBmDifVis * TDifVis / (1 - RGlDiffFrontVis * RScDifBackVis);
    6058              : 
    6059              :             } else { // Blind
    6060            2 :                 auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
    6061            2 :                 assert(matBlind != nullptr);
    6062              : 
    6063            2 :                 SlatAng = matBlind->SlatAngle * Constant::DegToRad;
    6064            2 :                 Real64 ProfAng = 0.0;
    6065              : 
    6066              :                 int slatIdxLo, slatIdxHi;
    6067              :                 Real64 slatInterpFac;
    6068            2 :                 Material::GetSlatIndicesInterpFac(SlatAng, slatIdxLo, slatIdxHi, slatInterpFac);
    6069            2 :                 Material::BlindTraAbsRef<Material::MaxProfAngs + 1> blindTAR;
    6070              :                 // This interpolates all blind properties.  No need to interpolate them one-by-one
    6071            2 :                 blindTAR.interpSlatAng(matBlind->TARs[slatIdxLo], matBlind->TARs[slatIdxHi], slatInterpFac);
    6072              : 
    6073              :                 int profIdxLo, profIdxHi;
    6074            2 :                 Material::GetProfIndices(ProfAng, profIdxLo, profIdxHi);
    6075              : 
    6076            2 :                 assert(profIdxLo == (Material::MaxProfAngs / 2) + 1); // Should be true for ProfAng == 0.0
    6077              : 
    6078            2 :                 TBlBmBm = matBlind->BeamBeamTrans(0.0, SlatAng);
    6079            2 :                 TBmBmBl = TBmBm * TBlBmBm;
    6080            2 :                 TBmBmBlVis = TBmBmVis * TBlBmBm;
    6081            2 :                 TBlBmDif = blindTAR.Sol.Ft.Bm[profIdxLo].DfTra;
    6082            2 :                 TBlBmDifVis = blindTAR.Vis.Ft.Bm[profIdxLo].DfTra;
    6083            2 :                 TDif = constructBare.TransDiff;
    6084            2 :                 TDifVis = constructBare.TransDiffVis;
    6085            2 :                 if (ShadeFlag == WinShadingType::IntBlind) {
    6086            2 :                     RGlDiffBack = constructBare.ReflectSolDiffBack;
    6087            2 :                     RGlDiffBackVis = constructBare.ReflectVisDiffBack;
    6088            2 :                     RhoBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].DfRef;
    6089            2 :                     RhoBlFrontVis = blindTAR.Vis.Ft.Bm[profIdxLo].DfRef;
    6090            2 :                     AbsBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].Abs;
    6091            2 :                     RhoBlDiffFront = blindTAR.Sol.Ft.Df.Ref;
    6092            2 :                     RhoBlDiffFrontVis = blindTAR.Vis.Ft.Df.Ref;
    6093            2 :                     AbsBlDiffFront = blindTAR.Sol.Ft.Df.Abs;
    6094            2 :                     AbsBeamShadeNorm = TBmBm * (AbsBlFront + RhoBlFront * RGlDiffBack * AbsBlDiffFront / (1.0 - RhoBlDiffFront * RGlDiffBack));
    6095            2 :                     TBlDifDif = blindTAR.Sol.Ft.Df.Tra;
    6096            2 :                     TBlDifDifVis = blindTAR.Vis.Ft.Df.Tra;
    6097            2 :                     TSolNorm = TBmBm * (TBlBmBm + TBlBmDif + TBlDifDif * RhoBlFront * RGlDiffBack / (1.0 - RhoBlDiffFront * RGlDiffBack));
    6098              :                     //     use of TBlBmBm here is correct, visible and IR transmittance are the same (reference deleted CR6925 on 3/20/2006)
    6099            2 :                     TVisNorm = TBmBmVis *
    6100            2 :                                (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis));
    6101              : 
    6102            0 :                 } else if (ShadeFlag == WinShadingType::ExtBlind) {
    6103            0 :                     RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6104            0 :                     RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6105            0 :                     AbsBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].Abs;
    6106            0 :                     AbsBlBack = blindTAR.Sol.Bk.Bm[profIdxLo].Abs;
    6107            0 :                     AbsBlDiffBack = blindTAR.Sol.Bk.Df.Abs;
    6108            0 :                     RGlDiffFront = constructBare.ReflectSolDiffFront;
    6109            0 :                     RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
    6110              : 
    6111            0 :                     RhoBlDiffBack = blindTAR.Sol.Bk.Df.Ref;
    6112            0 :                     RhoBlDiffBackVis = blindTAR.Vis.Bk.Df.Ref;
    6113            0 :                     RhoBlBack = blindTAR.Sol.Bk.Bm[profIdxLo].DfRef;
    6114            0 :                     RhoBlBackVis = blindTAR.Vis.Bk.Bm[profIdxLo].DfRef;
    6115              : 
    6116            0 :                     AbsBeamShadeNorm =
    6117            0 :                         AbsBlFront + AbsBlBack * RGlFront * TBlBmBm +
    6118            0 :                         (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDif);
    6119            0 :                     RGlDiffFront = constructBare.ReflectSolDiffFront;
    6120            0 :                     TSolNorm = TBlBmBm * (TBmBm + TDif * RGlFront * RhoBlBack / (1 - RGlDiffFront * RhoBlDiffBack)) +
    6121            0 :                                TBlBmDif * TDif / (1.0 - RGlDiffFront * RhoBlDiffBack);
    6122            0 :                     TVisNorm = TBlBmBm * (TBmBmVis + TDifVis * RGlFrontVis * RhoBlBackVis / (1 - RGlDiffFrontVis * RhoBlDiffBackVis)) +
    6123            0 :                                TBlBmDifVis * TDifVis / (1.0 - RGlDiffFrontVis * RhoBlDiffBackVis);
    6124              :                 } // (ExtBlind)
    6125              :             }     // (Screen or Blind)
    6126              :         }         // (Shade, Blind, or Screen)
    6127              : 
    6128              :         // Fill the layer properties needed for the thermal calculation.
    6129              : 
    6130              :         // The layer and face numbering are as follows (for the triple glazing case):
    6131              :         // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
    6132              :         //   layer and 3 is the inside (room-facing) layer;
    6133              :         // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
    6134              :         //   outside (front) face of glass layer 1, face 2 is the inside (back)
    6135              :         //   face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
    6136              :         //   inner face of glass layer 2, etc.
    6137              :         // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
    6138              :         //   and gap layer 2 is between glass layers 2 and 3.
    6139              : 
    6140           66 :         int IGlass = 0;
    6141           66 :         int IGap = 0;
    6142              : 
    6143          172 :         for (int Lay = 1; Lay <= TotLay; ++Lay) {
    6144          106 :             LayPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    6145          106 :             auto const *mat = s_mat->materials(LayPtr);
    6146              : 
    6147          106 :             if ((mat->group == Material::Group::Glass) || (mat->group == Material::Group::GlassSimple)) {
    6148           83 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
    6149           83 :                 assert(matGlass != nullptr);
    6150              : 
    6151           83 :                 ++IGlass;
    6152           83 :                 wm->thick[IGlass - 1] = matGlass->Thickness;
    6153           83 :                 wm->scon[IGlass - 1] = matGlass->Conductivity / matGlass->Thickness;
    6154           83 :                 wm->emis[2 * IGlass - 2] = matGlass->AbsorpThermalFront;
    6155           83 :                 wm->emis[2 * IGlass - 1] = matGlass->AbsorpThermalBack;
    6156           83 :                 wm->tir[2 * IGlass - 2] = matGlass->TransThermal;
    6157           83 :                 wm->tir[2 * IGlass - 1] = matGlass->TransThermal;
    6158           83 :                 AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef(IGlass));
    6159           83 :                 if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on
    6160            2 :                     auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6161            2 :                     AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
    6162            2 :                     AGlDiffBack = constructBare.AbsDiffBack(IGlass);
    6163            2 :                     AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack);
    6164           81 :                 } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on
    6165            0 :                     auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6166            0 :                     AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
    6167            0 :                     AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) *
    6168            0 :                                                                               constructBare.AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack);
    6169           81 :                 } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on
    6170            0 :                     auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6171            0 :                     AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
    6172            0 :                     AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * constructBare.AbsDiff(IGlass) /
    6173            0 :                                                                               (1.0 - RGlDiffFront * RScDifBack);
    6174              :                 }
    6175           83 :                 wm->AbsRadGlassFace[2 * IGlass - 2] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
    6176           83 :                 wm->AbsRadGlassFace[2 * IGlass - 1] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
    6177              :             }
    6178          106 :             if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture ||
    6179           91 :                 mat->group == Material::Group::ComplexWindowGap) { // Gap layer
    6180           19 :                 ++IGap;
    6181              : 
    6182           19 :                 auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
    6183           19 :                 assert(matGas != nullptr);
    6184           19 :                 wm->gaps[IGap - 1].width = matGas->Thickness;
    6185           19 :                 wm->gaps[IGap - 1].numGases = matGas->numGases;
    6186           38 :                 for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
    6187           19 :                     wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
    6188           19 :                     wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
    6189              :                 }
    6190              :             }
    6191              :         } // for (Lay)
    6192              : 
    6193              :         // Factors used in glass temperature solution
    6194           66 :         if (wm->ngllayer >= 2) {
    6195           17 :             wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    6196           17 :             wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    6197           17 :             wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
    6198              :         }
    6199              : 
    6200           66 :         if (wm->ngllayer >= 3) {
    6201            0 :             wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    6202            0 :             wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    6203            0 :             wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
    6204              :         }
    6205              : 
    6206           66 :         if (wm->ngllayer == 4) {
    6207            0 :             wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    6208            0 :             wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    6209            0 :             wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
    6210              :         }
    6211              : 
    6212           66 :         wm->thetas = {0.0};
    6213              : 
    6214           66 :         WindowTempsForNominalCond(state, ConstrNum, hgap, 1.0);
    6215              : 
    6216           66 :         if (!ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsBeamShadeNorm = 0.0;
    6217              : 
    6218              :         // Get center-of-glass conductance and solar heat gain coefficient
    6219              :         // including inside and outside air films
    6220           66 :         auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1));
    6221           29 :         Real64 inputU = (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple)
    6222           95 :                             ? dynamic_cast<Material::MaterialGlass const *>(mat)->SimpleWindowUfactor
    6223           66 :                             : 0.0;
    6224              : 
    6225              :         // Calculate the NominalConductance glazing only (before adjusted)
    6226           66 :         EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
    6227              : 
    6228           66 :         if (WinterSummerFlag == 1) {
    6229           41 :             state.dataHeatBal->NominalUBeforeAdjusted(ConstrNum) = NominalConductance;
    6230           41 :             if (inputU > 0) {                  // only compute adjustment ratio when there is valid user input U
    6231           15 :                 Real64 wettedAreaAdjRatio = 1; // Adjustment ratio for the wetted area
    6232           15 :                 Real64 hcoutRated = wm->hcout;
    6233              :                 // Adjustment ratio applies to convective film coefficients when input U value is above the limit of the simple glazing nominal U
    6234              :                 // Representing the nominal highly conductive frame effects. Solved iteratively.
    6235           15 :                 Real64 adjLower = 1.0;
    6236           15 :                 Real64 adjUpper = 2.0;
    6237           15 :                 int MaxIter = 100;
    6238           39 :                 while (std::abs(inputU - NominalConductance) > 0.01 && MaxIter > 0) {
    6239           24 :                     wettedAreaAdjRatio = (adjLower + adjUpper) / 2;
    6240           24 :                     WindowTempsForNominalCond(
    6241              :                         state, ConstrNum, hgap, wettedAreaAdjRatio); // reeval hcout at each iteration, hcin is not linear to wetted area
    6242           24 :                     wm->hcout = hcoutRated * wettedAreaAdjRatio;     // reeval hcout
    6243           24 :                     EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
    6244           24 :                     if (NominalConductance < inputU) {
    6245            8 :                         adjLower = wettedAreaAdjRatio;
    6246              :                     } else {
    6247           16 :                         adjUpper = wettedAreaAdjRatio;
    6248              :                     }
    6249           24 :                     MaxIter -= 1;
    6250              :                 }
    6251           15 :                 state.dataHeatBal->CoeffAdjRatio(ConstrNum) = wettedAreaAdjRatio;
    6252              :             }
    6253              :         }
    6254              : 
    6255              :         // EPTeam - again -- believe that is enforced in input //Autodesk But this routine is not self-protecting: Add as an assert
    6256              : 
    6257              :         // init the surface convective and radiative adjustment ratio
    6258          220 :         for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    6259          308 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    6260          154 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    6261          154 :                 int const firstSurfWin = thisSpace.WindowSurfaceFirst;
    6262          154 :                 int const lastSurfWin = thisSpace.WindowSurfaceLast;
    6263          367 :                 for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
    6264          213 :                     if (s_surf->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
    6265          213 :                         int ConstrNum2 = s_surf->Surface(SurfNum).Construction;
    6266          213 :                         state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum) = state.dataHeatBal->CoeffAdjRatio(ConstrNum2);
    6267              :                     }
    6268              :                 }
    6269              :             }
    6270              :         }
    6271              : 
    6272              :         // Need to add variables writing here since this routine will override previously calculated values from WinCalc-Engine
    6273           66 :         if (wm->inExtWindowModel->isExternalLibraryModel()) {
    6274            0 :             TSolNorm = GetSolarTransDirectHemispherical(state, ConstrNum);
    6275            0 :             TVisNorm = GetVisibleTransDirectHemispherical(state, ConstrNum);
    6276              :         }
    6277           66 :     } // CalcNominalWindowCond()
    6278              : 
    6279           90 :     void EvalNominalWindowCond(EnergyPlusData &state,
    6280              :                                Real64 const AbsBeamShadeNorm,     // Shade solar absorptance at normal incidence
    6281              :                                Array1D<Real64> const AbsBeamNorm, // Beam absorptance at normal incidence for each glass layer
    6282              :                                Array1D<Real64> const hgap,        // Conductive gap conductance [W/m2-K]
    6283              :                                Real64 &NominalConductance,        // Nominal center-of-glass conductance, including air films
    6284              :                                Real64 &SHGC,                      // Nominal center-of-glass solar heat gain coefficient for
    6285              :                                Real64 const TSolNorm              // Overall beam solar transmittance at normal incidence
    6286              :     )
    6287              :     {
    6288           90 :         Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
    6289              : 
    6290           90 :         auto const &wm = state.dataWindowManager;
    6291           90 :         Real64 hOutRad = wm->emis[0] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tout + wm->thetas[0]);
    6292           90 :         Real64 rOut = 1.0 / (hOutRad + wm->hcout);
    6293           90 :         Real64 hInRad = wm->emis[wm->nglface - 1] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tin + wm->thetas[wm->nglface - 1]);
    6294           90 :         Real64 rIn = 1.0 / (hInRad + wm->hcin);
    6295           90 :         Real64 Rbare = 0;
    6296              : 
    6297           90 :         switch (wm->ngllayer) {
    6298              :         // the switch cases here are just the integer number of layers, not exactly "magic" numbers 1, 2, 3. and 4.
    6299           73 :         case 1: {
    6300           73 :             Rbare = 1.0 / wm->scon[0];
    6301           73 :             wm->Rtot = rOut + Rbare + rIn;
    6302           73 :             SHGC = AbsBeamNorm(1) * (rOut + (0.5 / wm->scon[0])) / wm->Rtot; // BG changed for CR7682 (solar absorbed in middle of layer)
    6303           73 :             SHGC += AbsBeamShadeNorm;
    6304           73 :             SHGC += TSolNorm;
    6305           73 :         } break;
    6306              : 
    6307           17 :         case 2: {
    6308           17 :             hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
    6309           17 :             Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1];
    6310           17 :             wm->Rtot = rOut + Rbare + rIn;
    6311           17 :             SHGC = AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
    6312           17 :                    AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot; // CR7682
    6313           17 :             SHGC += AbsBeamShadeNorm;
    6314           17 :             SHGC += TSolNorm;
    6315           17 :         } break;
    6316              : 
    6317            0 :         case 3: {
    6318            0 :             hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
    6319            0 :             hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
    6320            0 :             Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2];
    6321            0 :             wm->Rtot = rOut + Rbare + rIn;
    6322            0 :             SHGC =
    6323            0 :                 AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
    6324            0 :                 AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
    6325            0 :                 AbsBeamNorm(3) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 0.5 / wm->scon[2]) / wm->Rtot;
    6326            0 :             SHGC += AbsBeamShadeNorm;
    6327            0 :             SHGC += TSolNorm;
    6328            0 :         } break;
    6329              : 
    6330            0 :         case 4: {
    6331            0 :             hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
    6332            0 :             hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
    6333            0 :             hGapTot(3) = hgap(3) + std::abs(wm->A67) * 0.5 * pow_3(wm->thetas[5] + wm->thetas[6]);
    6334            0 :             Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2] + 1.0 / hGapTot(3) +
    6335            0 :                     1.0 / wm->scon[3];
    6336            0 :             wm->Rtot = rOut + Rbare + rIn;
    6337            0 :             SHGC =
    6338            0 :                 AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
    6339            0 :                 AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
    6340            0 :                 AbsBeamNorm(3) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 0.5 / wm->scon[2]) / wm->Rtot +
    6341            0 :                 AbsBeamNorm(4) *
    6342            0 :                     (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2] + 1.0 / hGapTot(3) +
    6343            0 :                      0.5 / wm->scon[3]) /
    6344            0 :                     wm->Rtot; // CR7682
    6345            0 :             SHGC += AbsBeamShadeNorm;
    6346            0 :             SHGC += TSolNorm;
    6347            0 :         } break;
    6348            0 :         default:
    6349            0 :             break;
    6350              :         }
    6351           90 :         NominalConductance = 1.0 / (rOut + Rbare + rIn);
    6352           90 :     } // EvalNominalWindowCond()
    6353              : 
    6354              :     //****************************************************************************
    6355              : 
    6356           90 :     void WindowTempsForNominalCond(EnergyPlusData &state,
    6357              :                                    int const ConstrNum,  // Construction number
    6358              :                                    Array1A<Real64> hgap, // Gap gas conductive conductance (W/m2-K)
    6359              :                                    Real64 const adjRatio // adjustment Ratio to hcin
    6360              :     )
    6361              :     {
    6362              : 
    6363              :         // SUBROUTINE INFORMATION:
    6364              :         //       AUTHOR         F. Winkelmann
    6365              :         //       DATE WRITTEN   September 2000
    6366              :         //       MODIFIED       Nov 2002, FW: increase MaxIterations from 15 to 100, add face
    6367              :         //                       temperature relaxation, and increase convergence tolerance by
    6368              :         //                       a factor of 10 if no convergence after MaxIterations,
    6369              :         //                       all for consistency with SolveForWindowTemperatures.
    6370              :         //                      Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02;
    6371              :         //                       remove redundant relaxation on radiative conductances (both of
    6372              :         //                       these were also done in SolveForWindowTemperatures).
    6373              :         //                      Jan 2009, BG: changed interior convection coefficient correlation to match
    6374              :         //                       ISO 15099.
    6375              :         //                      Feb 2009, BG: extended coefficient to include absorbed radiation
    6376              :         //                       to cover summer conditions for SHGC determination.
    6377              :         //       RE-ENGINEERED  na
    6378              : 
    6379              :         // PURPOSE OF THIS SUBROUTINE:
    6380              :         // This is a shortened form of SolveForWindowTemperatures tailored
    6381              :         // for calculation of the nominal center-of-glass U-value for a window
    6382              :         // construction at ASHRAE winter conditions and for determining conditions at
    6383              :         // summer conditions for calculating SHGC.
    6384              :         // Evaluates the coefficients Aface and Bface in the system of linear
    6385              :         // algebraic equations
    6386              :         //     Sum    [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglface
    6387              :         //  j=1,nglface
    6388              :         // where
    6389              :         // nglface = number of glass faces (= 2 * number of layers) and
    6390              :         // thetas(j) = temperature of face j
    6391              : 
    6392              :         // METHODOLOGY EMPLOYED:
    6393              :         // The Aface and Bface coefficients are determined by the equations for
    6394              :         // heat balance at the glass faces. The system of linear equations is solved
    6395              :         // by LU decomposition.
    6396              : 
    6397              :         // Argument array dimensioning
    6398           90 :         hgap.dim(5);
    6399              : 
    6400           90 :         int constexpr MaxIterations(100);  // Maximum allowed number of iterations
    6401           90 :         Real64 constexpr errtemptol(0.02); // Tolerance on errtemp for convergence
    6402              :         static constexpr std::string_view RoutineName("WindowTempsForNominalCond");
    6403              : 
    6404           90 :         Array1D<Real64> hr(10); // Radiative conductance (W/m2-K)
    6405              :         Real64 hcinprev;        // Value of hcin from previous iteration
    6406              :         int d;                  // +1 if number of row interchanges is even,
    6407              :         // -1 if odd (in LU decomposition)
    6408           90 :         Array1D_int indx(10);          // Vector of row permutations in LU decomposition
    6409           90 :         Array2D<Real64> Aface(10, 10); // Coefficient in equation Aface*thetas = Bface
    6410           90 :         Array1D<Real64> Bface(10);     // Coefficient in equation Aface*thetas = Bface
    6411              :         int iter;                      // Iteration number
    6412              :         Real64 errtemp;                // Absolute value of sum of face temperature differences
    6413              :         //   between iterations, divided by number of faces
    6414              :         Real64 TmeanFilm;       // mean film temperature
    6415              :         Real64 TmeanFilmKelvin; // mean film temperature for property evaluation
    6416              :         Real64 rho;             // density of (apparently dry) air [kg/m3]
    6417              :         Real64 g;               // acceleration due to gravity [m/s2]
    6418              :         Real64 Height;          // window cavity height [m]
    6419              :         Real64 Cp;              // specific heat of air [J/kg-K]
    6420              :         Real64 lambda;          // thermal conductivity of air [W/m-K]
    6421              :         Real64 mu;              // dynamic viscosity of air [kg/m-s]
    6422              :         Real64 RaH;             // Rayleigh number for cavity height [ Non dim]
    6423              :         Real64 TiltDeg;         // glazing tilt in degrees
    6424              :         Real64 sineTilt;        // sine of glazing tilt
    6425              :         Real64 Nuint;           // Nusselt number for interior surface convection
    6426              : 
    6427           90 :         auto &wm = state.dataWindowManager;
    6428              : 
    6429           90 :         iter = 0;
    6430              : 
    6431              :         // Initialize face temperatures
    6432           90 :         StartingWinTempsForNominalCond(state);
    6433              : 
    6434              :         // Calculate radiative conductance
    6435           90 :         errtemp = errtemptol * 2.0;
    6436              : 
    6437           90 :         TiltDeg = 90.0;
    6438              : 
    6439           90 :         sineTilt = std::sin(TiltDeg * Constant::DegToRad); // degrees as arg
    6440              : 
    6441          686 :         while (iter < MaxIterations && errtemp > errtemptol) {
    6442         1964 :             for (int i = 1; i <= wm->nglface; ++i) {
    6443         1368 :                 hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
    6444              :                 //! fw 3/4/03 if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
    6445              :             }
    6446              : 
    6447          596 :             Aface = 0.0;
    6448          596 :             Bface = 0.0;
    6449              : 
    6450              :             // Inside convective film conductance for vertical window
    6451          596 :             if (iter >= 1) {
    6452          506 :                 hcinprev = wm->hcin;
    6453              :             }
    6454              :             // CR7670 BG this next correlation was used for hcin but is not "standard" for windows
    6455              :             //  hcin = 1.31d0*((ABS(thetas(nglface)-tin))**0.3333d0)
    6456              :             // Begin calculating for ISO 15099 method.
    6457              :             // mean film temperature
    6458          596 :             TmeanFilmKelvin = wm->tin + 0.25 * (wm->thetas[wm->nglface - 1] - wm->tin); // eq. 133 in ISO 15099
    6459          596 :             TmeanFilm = TmeanFilmKelvin - 273.15;
    6460              :             // the following properties are constants or linear relations for "standard" type reporting
    6461          596 :             rho = Psychrometrics::PsyRhoAirFnPbTdbW(state, 101325.0, TmeanFilm, 0.0, RoutineName); // dry air assumption
    6462          596 :             g = 9.81;
    6463          596 :             Height = 1.0; // standard window rating practice is to use 1 meter (rather than actual)
    6464              : 
    6465          596 :             lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // Table B.1 in ISO 15099
    6466          596 :             mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin;     // Table B.2 in ISO 15099
    6467          596 :             Cp = 1002.737 + 1.2324E-2 * TmeanFilmKelvin;   // Table B.3 in ISO 15099
    6468              : 
    6469              :             // eq 132 in ISO 15099
    6470          596 :             RaH = (pow_2(rho) * pow_3(Height) * g * Cp * (std::abs(wm->thetas[wm->nglface - 1] - wm->tin))) / (TmeanFilmKelvin * mu * lambda);
    6471              : 
    6472          596 :             Nuint = 0.56 * root_4(RaH * sineTilt); // eq. 135 in ISO 15099 (only need this one because tilt is 90 deg
    6473              : 
    6474          596 :             wm->hcin = Nuint * lambda / Height;
    6475              : 
    6476              :             // End calculations for ISO 15099 method.
    6477              : 
    6478          596 :             if (iter >= 1) wm->hcin = 0.5 * (hcinprev + wm->hcin);
    6479              : 
    6480          596 :             wm->hcin *= adjRatio;
    6481              : 
    6482          596 :             ++iter;
    6483              : 
    6484          596 :             GetHeatBalanceEqCoefMatrixSimple(state, wm->ngllayer, hr, hgap, Aface, Bface);
    6485              : 
    6486          596 :             LUdecomposition(state, Aface, wm->nglface, indx, d); // Note that these routines change Aface;
    6487          596 :             LUsolution(state, Aface, wm->nglface, indx, Bface);  // face temperatures are returned in Bface
    6488              : 
    6489          596 :             errtemp = 0.0;
    6490         1964 :             for (int i = 1; i <= wm->nglface; ++i) {
    6491         1368 :                 errtemp += std::abs(wm->thetas[i - 1] - Bface(i)) / wm->nglface;
    6492              :             }
    6493              : 
    6494         1964 :             for (int i = 1; i <= wm->nglface; ++i) {
    6495         1368 :                 wm->thetas[i - 1] = 0.5 * (wm->thetas[i - 1] + Bface(i));
    6496              :             }
    6497              :         }
    6498              : 
    6499              :         // No convergence after MaxIterations; and/or error tolerance
    6500           90 :         if (errtemp >= 10 * errtemptol) {
    6501              :             // Fatal error: didn't converge
    6502            0 :             ShowFatalError(
    6503              :                 state,
    6504            0 :                 format("Convergence error in WindowTempsForNominalCond for construction {}", state.dataConstruction->Construct(ConstrNum).Name));
    6505              :         }
    6506           90 :     } // WindowTempsForNominalCond()
    6507              : 
    6508              :     //****************************************************************************
    6509              : 
    6510           90 :     void StartingWinTempsForNominalCond(EnergyPlusData &state)
    6511              :     {
    6512              : 
    6513              :         // SUBROUTINE INFORMATION:
    6514              :         //       AUTHOR         F. Winkelmann
    6515              :         //       DATE WRITTEN   September 2000
    6516              : 
    6517              :         // PURPOSE OF THIS SUBROUTINE:
    6518              :         // Initializes face temperature distribution prior to iteration.
    6519              :         // This is a shortened form of StartingWindowTemps for use in calculating
    6520              :         // the nominal center-of-glass U-value.
    6521              : 
    6522           90 :         Real64 constexpr hrad = 5.3;           // Typical radiative conductance (W/m2-K)
    6523           90 :         Real64 constexpr hcinStartValue = 3.2; // Starting value for inside air film convective
    6524              :         //   conductance (estimated for typical double glazing
    6525              :         //   using 1.31(dT**0.333), where dT =
    6526              :         //   room air temp - inside surface temp = 14.2K)
    6527           90 :         Real64 constexpr resgap = 0.21; // Typical gap resistance (m2-K/W)
    6528              : 
    6529           90 :         Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
    6530              :         // inside or outside air film, or gap
    6531              :         Real64 restot; // Total window resistance including outside
    6532              :         //   and inside air films (m2-K/W)
    6533              :         Real64 temdiff; // Inside/outside air temperature difference (K)
    6534              :         Real64 ressum;  // Resistance sum (m2-K/W)
    6535              : 
    6536           90 :         auto const &wm = state.dataWindowManager;
    6537              : 
    6538           90 :         rguess(1) = 1.0 / (wm->hcout + hrad);
    6539           90 :         rguess(wm->nglface + 1) = 1.0 / (hcinStartValue + hrad);
    6540              : 
    6541          197 :         for (int i = 2; i <= wm->nglface; i += 2) {
    6542          107 :             rguess(i) = 1.0 / wm->scon[i / 2 - 1];
    6543          107 :             if (i < wm->nglface) rguess(i + 1) = resgap;
    6544              :         }
    6545           90 :         restot = 0.0;
    6546              : 
    6547          394 :         for (int i = 1; i <= wm->nglface + 1; ++i) {
    6548          304 :             restot += rguess(i);
    6549              :         }
    6550              : 
    6551           90 :         temdiff = wm->tin - wm->tout;
    6552           90 :         if (std::abs(temdiff) < 0.5) temdiff = 2.0;
    6553           90 :         ressum = 0.0;
    6554              : 
    6555          304 :         for (int i = 1; i <= wm->nglface; ++i) {
    6556          214 :             ressum += rguess(i);
    6557          214 :             wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
    6558              :         }
    6559           90 :     } // StartingWinTempsForNominalCond()
    6560              : 
    6561              :     //****************************************************************************
    6562              : 
    6563          110 :     void ReportGlass(EnergyPlusData &state)
    6564              :     {
    6565              : 
    6566              :         // SUBROUTINE INFORMATION:
    6567              :         //       AUTHOR         Linda K. Lawrie
    6568              :         //       DATE WRITTEN   March 2000
    6569              : 
    6570              :         // PURPOSE OF THIS SUBROUTINE:
    6571              :         // This routine gives a detailed report to the user about
    6572              :         // the calculation parameters for windows and their associated
    6573              :         // materials.
    6574              : 
    6575          110 :         Real64 TempVar = 0.0; // just temporary usage for complex fenestration
    6576              : 
    6577              :         Real64 NominalConductanceWinter; // Nominal center-of-glass conductance of a window construction
    6578              :         // for ASHRAE winter conditions (W/m2-K):
    6579              :         // Inside air temperature = 21.1C (70F)
    6580              :         // Outside air temperature = -17.8C (0F)
    6581              :         // Windspeed = 6.71 m/s (15 mph)
    6582              :         // No solar radiation
    6583              :         Real64 NominalConductanceSummer; // Nominal center-of-glass conductance of a window construction
    6584              :         // for ASHRAE summer conditions (W/m2-K):
    6585              :         // Inside air temperature = 23.9C (75F)
    6586              :         // Outside air temperature = 35.0C (95F)
    6587              :         // Windspeed = 3.35 m/s (7.5 mph)
    6588              :         // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
    6589          110 :         Real64 SHGCWinter(0.0); // Center-of-glass solar heat gain coefficient for ASHRAE
    6590          110 :         Real64 SHGCSummer(0.0);
    6591              :         // winter and summer conditions
    6592              :         Real64 TransSolNorm; // Window construction solar transmittance at normal incidence
    6593              :         Real64 TransVisNorm; // Window construction visible transmittance at normal incidence
    6594              :         int errFlag;         // Error flag
    6595              : 
    6596          110 :         auto &wm = state.dataWindowManager;
    6597              : 
    6598          330 :         General::ScanForReports(state, "Constructions", wm->DoReport, "Constructions");
    6599              : 
    6600          110 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    6601          110 :                         state.dataConstruction->Construct.end(),
    6602          296 :                         [](Construction::ConstructionProps const &e) { return e.TypeIsWindow; }))
    6603           28 :             wm->HasWindows = true;
    6604          110 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    6605          110 :                         state.dataConstruction->Construct.end(),
    6606          323 :                         [](Construction::ConstructionProps const &e) { return e.WindowTypeBSDF; }))
    6607            1 :             wm->HasComplexWindows = true; // Yes, this is a bit different than actually using them.
    6608          110 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    6609          110 :                         state.dataConstruction->Construct.end(),
    6610          323 :                         [](Construction::ConstructionProps const &e) { return e.WindowTypeEQL; }))
    6611            6 :             wm->HasEQLWindows = true; // for reporting purpose only
    6612          110 :         if (wm->DoReport && (wm->HasWindows || wm->HasComplexWindows || wm->HasEQLWindows)) {
    6613            1 :             auto const &s_mat = state.dataMaterial;
    6614              :             //                                      Write Descriptions
    6615            1 :             print(state.files.eio,
    6616              :                   "{}\n",
    6617              :                   "! <WindowConstruction>,Construction Name,Index,#Layers,Roughness,Conductance {W/m2-K},Conductance (Before Adjusted) {W/m2-K},"
    6618              :                   "Convection Coefficient Adjustment Ratio,SHGC,"
    6619              :                   "Solar Transmittance at Normal Incidence,Visible Transmittance at Normal Incidence");
    6620            1 :             if ((s_mat->NumSimpleWindows > 0) || (s_mat->NumW5Glazings > 0) || (s_mat->NumW5AltGlazings > 0))
    6621            1 :                 print(state.files.eio,
    6622              :                       "{}\n",
    6623              :                       "! <WindowMaterial:Glazing>, Material Name, Optical Data Type, Spectral Data Set Name, "
    6624              :                       "Thickness {m}, Solar Transmittance,Front Solar Reflectance, Back Solar Reflectance, Visible "
    6625              :                       "Transmittance, Front Visible Reflectance,Back Visible Reflectance,Infrared Transmittance, "
    6626              :                       "Front Thermal Emissivity, Back Thermal Emissivity,Conductivity {W/m-K},Dirt Factor,Solar "
    6627              :                       "Diffusing");
    6628            1 :             if ((s_mat->NumW5Gases > 0) || (s_mat->NumW5GasMixtures > 0))
    6629            0 :                 print(state.files.eio, "{}\n", "! <WindowMaterial:Gas>,Material Name,GasType,Thickness {m}");
    6630            1 :             if (s_mat->NumShades > 0)
    6631            0 :                 print(state.files.eio,
    6632              :                       "{}\n",
    6633              :                       "! <WindowMaterial:Shade>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
    6634              :                       "Absorptance,Transmittance,Visible Transmittance,Shade Reflectance");
    6635            1 :             if (s_mat->NumScreens > 0)
    6636            0 :                 print(state.files.eio,
    6637              :                       "{}\n",
    6638              :                       "! <WindowMaterial:Screen>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
    6639              :                       "Absorptance,Transmittance,Reflectance,Visible Reflectance,Diffuse Reflectance,Diffuse Visible "
    6640              :                       "Reflectance,Screen Material Diameter To Spacing Ratio,Screen To GlassDistance {m}");
    6641            1 :             if (s_mat->NumBlinds > 0)
    6642            1 :                 print(state.files.eio,
    6643              :                       "{}\n",
    6644              :                       "! <WindowMaterial:Blind>,Material Name,Slat Width {m},Slat Separation {m},Slat Thickness "
    6645              :                       "{m},Slat Angle {deg},Slat Beam Solar Transmittance,Slat Beam Solar Front Reflectance,Blind To "
    6646              :                       "Glass Distance {m}");
    6647              : 
    6648            1 :             if (wm->HasComplexWindows)
    6649            0 :                 print(state.files.eio,
    6650              :                       "{}\n",
    6651              :                       "! <WindowConstruction:Complex>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC"
    6652              :                       "NFRC Product Type,Assembly U-Factor {W/m2-K},Assembly SHGC,Assembly Visible Transmittance");
    6653              : 
    6654            1 :             if (wm->HasEQLWindows)
    6655            0 :                 print(state.files.eio,
    6656              :                       "{}\n",
    6657              :                       "! <Construction:WindowEquivalentLayer>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC, "
    6658              :                       "Solar Transmittance at Normal Incidence");
    6659            1 :             if (s_mat->NumEQLGlazings > 0)
    6660            0 :                 print(state.files.eio,
    6661              :                       "{}\n",
    6662              :                       "! <WindowMaterial:Glazing:EquivalentLayer>, Material Name, Optical Data Type, Spectral Data "
    6663              :                       "Set Name, Front Side Beam-Beam Solar Transmittance, Back Side Beam-Beam Solar Transmittance, "
    6664              :                       "Front Side Beam-Beam Solar Reflectance, Back Side Beam-Beam Solar Reflectance, Front Side "
    6665              :                       "Beam-Diffuse Solar Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side "
    6666              :                       "Beam-Diffuse Solar Reflectance, Back Side Beam-Diffuse Solar Reflectance, Diffuse-Diffuse "
    6667              :                       "Solar Transmittance, Front Side Diffuse-Diffuse Solar Reflectance, Back Side Diffuse-Diffuse "
    6668              :                       "Solar Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
    6669              :                       "Emissivity");
    6670            1 :             if (s_mat->NumEQLShades > 0)
    6671            0 :                 print(state.files.eio,
    6672              :                       "{}\n",
    6673              :                       "! <WindowMaterial:Shade:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
    6674              :                       "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
    6675              :                       "Transmittance, Back Side Beam-Diffuse Solar Transmittance, Front Side Beam-Diffuse Solar "
    6676              :                       "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
    6677              :                       "Infrared Emissivity, Back Side Infrared Emissivity");
    6678              : 
    6679            1 :             if (s_mat->NumEQLDrapes > 0)
    6680            0 :                 print(state.files.eio,
    6681              :                       "{}\n",
    6682              :                       "! <WindowMaterial:Drape:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
    6683              :                       "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
    6684              :                       "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
    6685              :                       "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
    6686              :                       "Infrared Emissivity, Back Side Infrared Emissivity, Width of Pleated Fabric, Length of Pleated "
    6687              :                       "Fabric");
    6688              : 
    6689            1 :             if (s_mat->NumEQLBlinds > 0)
    6690            0 :                 print(state.files.eio,
    6691              :                       "{}\n",
    6692              :                       "! <WindowMaterial:Blind:EquivalentLayer>, Material Name, Slat Orientation, Slat Width, Slat "
    6693              :                       "Separation, Slat Crown, Slat Angle, Front Side Slate Beam-Diffuse Solar Transmittance, Back "
    6694              :                       "Side Slate Beam-Diffuse Solar Transmittance, Front Side Slate Beam-Diffuse Solar Reflectance, "
    6695              :                       "Back Side Slate Beam-Diffuse Solar Reflectance, Slat Diffuse-Diffuse Solar Transmittance, "
    6696              :                       "Front Side Slat Diffuse-Diffuse Solar Reflectance, Back Side Slat Diffuse-Diffuse Solar "
    6697              :                       "Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
    6698              :                       "Emissivity, Slat Angle Control");
    6699            1 :             if (s_mat->NumEQLScreens > 0)
    6700            0 :                 print(state.files.eio,
    6701              :                       "{}\n",
    6702              :                       "! <WindowMaterial:Screen:EquivalentLayer>, Material Name, Screen Beam-Beam Solar "
    6703              :                       "Transmittance, Screen Beam-Diffuse Solar Transmittance, Screen Beam-Diffuse Solar Reflectance, "
    6704              :                       "Screen Infrared Transmittance, Screen Infrared Emissivity, Screen Wire Spacing, Screen Wire "
    6705              :                       "Diameter");
    6706            1 :             if (s_mat->NumEQLGaps > 0)
    6707            0 :                 print(state.files.eio, "{}\n", "! <WindowMaterial:Gap:EquivalentLayer>, Material Name, GasType, Gap Thickness {m}, Gap Vent Type");
    6708              : 
    6709           26 :             for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
    6710           25 :                 auto &construct = state.dataConstruction->Construct(ThisNum);
    6711           25 :                 if (construct.WindowTypeBSDF) {
    6712              : 
    6713            0 :                     int i = ThisNum;
    6714            0 :                     WindowComplexManager::CalcComplexWindowThermal(
    6715              :                         state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Winter);
    6716            0 :                     WindowComplexManager::CalcComplexWindowThermal(
    6717              :                         state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Summer);
    6718              : 
    6719              :                     static constexpr std::string_view Format_800(" WindowConstruction:Complex,{},{},{},{:.3R},{:.3R}\n");
    6720            0 :                     print(state.files.eio,
    6721              :                           Format_800,
    6722            0 :                           construct.Name,
    6723              :                           ThisNum,
    6724            0 :                           construct.TotSolidLayers,
    6725            0 :                           state.dataHeatBal->NominalU(ThisNum),
    6726            0 :                           construct.SummerSHGC);
    6727              : 
    6728           25 :                 } else if (construct.TypeIsWindow) {
    6729              :                     // Calculate for ASHRAE winter and summer conditions:
    6730              :                     // (1) nominal center-of-glass conductance, including inside and outside air films,
    6731              :                     // (2) solar heat gain coefficient (SHGC),
    6732              :                     // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
    6733              : 
    6734            5 :                     if (construct.WindowTypeEQL) {
    6735              :                         // for equivalent layer Window already calculated
    6736              :                         // NominalU(ThisNum)=NominalConductanceWinter
    6737              :                         // Save the SHGC for later use in tabular report IVRS
    6738              :                         // Construct(ThisNum)%SummerSHGC = SHGCSummer
    6739            0 :                         construct.VisTransNorm = 0.0; // TODO list
    6740              : 
    6741              :                         static constexpr std::string_view Format_799(" Construction:WindowEquivalentLayer,{},{},{},{:.3R},{:.3R},{:.3R}\n");
    6742            0 :                         print(state.files.eio,
    6743              :                               Format_799,
    6744            0 :                               construct.Name,
    6745              :                               ThisNum,
    6746            0 :                               construct.TotSolidLayers,
    6747            0 :                               state.dataHeatBal->NominalU(ThisNum),
    6748            0 :                               construct.SummerSHGC,
    6749            0 :                               construct.SolTransNorm);
    6750              : 
    6751              :                     } else {
    6752              : 
    6753            5 :                         CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
    6754              : 
    6755            5 :                         if (errFlag == 1) {
    6756            0 :                             ShowWarningError(state, format("Window construction {} has an interior or exterior blind", construct.Name));
    6757            0 :                             ShowContinueError(state, "but the corresponding construction without the blind cannot be found.");
    6758            0 :                             ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
    6759            0 :                             continue;
    6760              :                         }
    6761              : 
    6762              :                         // Skip constructions with between-glass shade/blind until method is worked out to determine
    6763              :                         // nominal conductance and SHGC.
    6764              : 
    6765            5 :                         if (errFlag == 2) {
    6766            0 :                             ShowWarningError(state, format("Window construction {} has a between-glass shade or blind", construct.Name));
    6767            0 :                             ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
    6768            0 :                             continue;
    6769              :                         }
    6770              : 
    6771            5 :                         state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
    6772            5 :                         if (!construct.WindowTypeEQL) {
    6773            5 :                             CalcNominalWindowCond(state, ThisNum, 2, NominalConductanceSummer, SHGCSummer, TransSolNorm, TransVisNorm, errFlag);
    6774              :                         }
    6775              :                         // Save the SHGC for later use in tabular report IVRS
    6776            5 :                         construct.SummerSHGC = SHGCSummer;
    6777            5 :                         construct.VisTransNorm = TransVisNorm;
    6778            5 :                         construct.SolTransNorm = TransSolNorm;
    6779              : 
    6780              :                         static constexpr std::string_view Format_700(" WindowConstruction,{},{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    6781           10 :                         print(state.files.eio,
    6782              :                               Format_700,
    6783            5 :                               construct.Name,
    6784              :                               ThisNum,
    6785            5 :                               construct.TotLayers,
    6786            5 :                               Material::surfaceRoughnessNames[(int)construct.OutsideRoughness],
    6787              :                               NominalConductanceWinter,
    6788            5 :                               state.dataHeatBal->NominalUBeforeAdjusted(ThisNum),
    6789            5 :                               state.dataHeatBal->CoeffAdjRatio(ThisNum),
    6790              :                               SHGCSummer,
    6791              :                               TransSolNorm,
    6792              :                               TransVisNorm);
    6793              :                     }
    6794              :                     //    Write(OutputFileConstrainParams, 705)  TRIM(Construct(ThisNum)%Name), SHGCSummer ,TransVisNorm
    6795              : 
    6796           11 :                     for (int i = 1; i <= construct.TotLayers; ++i) {
    6797            6 :                         int Layer = construct.LayerPoint(i);
    6798            6 :                         auto const *mat = s_mat->materials(Layer);
    6799            6 :                         std::string SpectralDataName;
    6800              : 
    6801            6 :                         switch (mat->group) {
    6802              : 
    6803            0 :                         case Material::Group::Gas: {
    6804            0 :                             auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
    6805            0 :                             assert(matGas != nullptr);
    6806              :                             static constexpr std::string_view Format_702(" WindowMaterial:Gas,{},{},{:.3R}\n");
    6807            0 :                             print(state.files.eio, Format_702, matGas->Name, Material::gasTypeNames[(int)matGas->gases[0].type], matGas->Thickness);
    6808              :                             //! fw CASE(WindowGasMixture)
    6809            0 :                         } break;
    6810              : 
    6811            0 :                         case Material::Group::Shade: {
    6812            0 :                             auto const *matShade = dynamic_cast<Material::MaterialShade const *>(mat);
    6813            0 :                             assert(matShade != nullptr);
    6814              : 
    6815              :                             static constexpr std::string_view Format_703(" WindowMaterial:Shade,{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    6816            0 :                             print(state.files.eio,
    6817              :                                   Format_703,
    6818            0 :                                   matShade->Name,
    6819            0 :                                   matShade->Thickness,
    6820            0 :                                   matShade->Conductivity,
    6821            0 :                                   matShade->AbsorpThermal,
    6822            0 :                                   matShade->Trans,
    6823            0 :                                   matShade->TransVis,
    6824            0 :                                   matShade->ReflectShade);
    6825            0 :                         } break;
    6826              : 
    6827            1 :                         case Material::Group::Blind: {
    6828            1 :                             auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
    6829              : 
    6830              :                             static constexpr std::string_view Format_704(
    6831              :                                 " WindowMaterial:Blind,{},{:.4R},{:.4R},{:.4R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    6832            1 :                             print(state.files.eio,
    6833              :                                   Format_704,
    6834            1 :                                   matBlind->Name,
    6835            1 :                                   matBlind->SlatWidth,
    6836            1 :                                   matBlind->SlatSeparation,
    6837            1 :                                   matBlind->SlatThickness,
    6838            1 :                                   matBlind->SlatAngle,
    6839            1 :                                   matBlind->slatTAR.Sol.Ft.Bm[0].DfTra,
    6840            1 :                                   matBlind->slatTAR.Sol.Ft.Bm[0].DfRef,
    6841            1 :                                   matBlind->toGlassDist);
    6842            1 :                         } break;
    6843              : 
    6844            0 :                         case Material::Group::Screen: {
    6845            0 :                             auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(mat);
    6846            0 :                             assert(matScreen != nullptr);
    6847            0 :                             auto const &btar = matScreen->btars[0][0]; // AR: Going with normal incidence here
    6848              : 
    6849              :                             static constexpr std::string_view Format_706 =
    6850              :                                 " WindowMaterial:Screen,{},{:.5R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n";
    6851              : 
    6852              :                             // AR: assuming normal incidence
    6853            0 :                             print(state.files.eio,
    6854              :                                   Format_706,
    6855            0 :                                   matScreen->Name,
    6856            0 :                                   matScreen->Thickness,
    6857            0 :                                   matScreen->Conductivity,
    6858            0 :                                   matScreen->AbsorpThermal,
    6859            0 :                                   btar.BmTrans,
    6860            0 :                                   btar.RefSolFront,
    6861            0 :                                   btar.RefVisFront,
    6862            0 :                                   matScreen->DfRef,
    6863            0 :                                   matScreen->DfRefVis,
    6864            0 :                                   matScreen->diameterToSpacingRatio,
    6865            0 :                                   matScreen->toGlassDist);
    6866            0 :                         } break;
    6867              : 
    6868            5 :                         case Material::Group::Glass:
    6869              :                         case Material::Group::GlassSimple: {
    6870            5 :                             auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
    6871            5 :                             assert(matGlass != nullptr);
    6872            5 :                             std::string SolarDiffusing = "No";
    6873            5 :                             if (matGlass->SolarDiffusing) SolarDiffusing = "Yes";
    6874              : 
    6875            5 :                             if (matGlass->windowOpticalData == Window::OpticalDataModel::Spectral) {
    6876            0 :                                 SpectralDataName = s_mat->SpectralData(matGlass->GlassSpectralDataPtr).Name;
    6877            5 :                             } else if (matGlass->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
    6878            0 :                                 SpectralDataName = format("{}, {}, {}",
    6879            0 :                                                           matGlass->GlassSpecAngTransCurve->Name,
    6880            0 :                                                           matGlass->GlassSpecAngFReflCurve->Name,
    6881            0 :                                                           matGlass->GlassSpecAngBReflCurve->Name);
    6882              :                             } else {
    6883            5 :                                 SpectralDataName = "";
    6884              :                             }
    6885              : 
    6886              :                             static constexpr std::string_view Format_707(
    6887              :                                 " WindowMaterial:Glazing,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{"
    6888              :                                 ":.5R},{:.5R},{:.5R},{:.5R},{:.5R},{}\n");
    6889            5 :                             print(state.files.eio,
    6890              :                                   Format_707,
    6891            5 :                                   matGlass->Name,
    6892            5 :                                   Window::opticalDataModelNames[(int)matGlass->windowOpticalData],
    6893              :                                   SpectralDataName,
    6894            5 :                                   matGlass->Thickness,
    6895            5 :                                   matGlass->Trans,
    6896            5 :                                   matGlass->ReflectSolBeamFront,
    6897            5 :                                   matGlass->ReflectSolBeamBack,
    6898            5 :                                   matGlass->TransVis,
    6899            5 :                                   matGlass->ReflectVisBeamFront,
    6900            5 :                                   matGlass->ReflectVisBeamBack,
    6901            5 :                                   matGlass->TransThermal,
    6902            5 :                                   matGlass->AbsorpThermalFront,
    6903            5 :                                   matGlass->AbsorpThermalBack,
    6904            5 :                                   matGlass->Conductivity,
    6905            5 :                                   matGlass->GlassTransDirtFactor,
    6906              :                                   SolarDiffusing);
    6907            5 :                         } break;
    6908              : 
    6909            0 :                         case Material::Group::GlassEQL: {
    6910            0 :                             auto const *matEQL = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
    6911            0 :                             assert(matEQL != nullptr);
    6912            0 :                             std::string OpticalDataType = "SpectralAverage";
    6913            0 :                             SpectralDataName = "";
    6914              :                             static constexpr std::string_view Format_708(
    6915              :                                 " WindowMaterial:Glazing:EquivalentLayer,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}"
    6916              :                                 ",{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}\n");
    6917            0 :                             print(state.files.eio,
    6918              :                                   Format_708,
    6919            0 :                                   matEQL->Name,
    6920              :                                   OpticalDataType,
    6921              :                                   SpectralDataName,
    6922            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].BmTra,
    6923            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].BmTra,
    6924            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].BmRef,
    6925            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].BmRef,
    6926            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfTra,
    6927            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfTra,
    6928            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfRef,
    6929            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfRef,
    6930            0 :                                   matEQL->TAR.Sol.Ft.Df.Tra,
    6931            0 :                                   matEQL->TAR.Sol.Ft.Df.Ref,
    6932            0 :                                   matEQL->TAR.Sol.Bk.Df.Ref,
    6933            0 :                                   matEQL->TAR.IR.Ft.Tra,
    6934            0 :                                   matEQL->TAR.IR.Ft.Emi,
    6935            0 :                                   matEQL->TAR.IR.Bk.Emi);
    6936            0 :                         } break;
    6937              : 
    6938            0 :                         case Material::Group::ShadeEQL: {
    6939            0 :                             auto const *matEQL = dynamic_cast<Material::MaterialShadeEQL const *>(mat);
    6940            0 :                             assert(matEQL != nullptr);
    6941              :                             static constexpr std::string_view Format_709(
    6942              :                                 " WindowMaterial:Shade:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}\n");
    6943            0 :                             print(state.files.eio,
    6944              :                                   Format_709,
    6945            0 :                                   matEQL->Name,
    6946            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].BmTra,
    6947            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].BmTra,
    6948            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfTra,
    6949            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfTra,
    6950            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfRef,
    6951            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfRef,
    6952            0 :                                   matEQL->TAR.IR.Ft.Tra,
    6953            0 :                                   matEQL->TAR.IR.Ft.Emi,
    6954            0 :                                   matEQL->TAR.IR.Bk.Emi);
    6955            0 :                         } break;
    6956              : 
    6957            0 :                         case Material::Group::DrapeEQL: {
    6958            0 :                             auto const *matEQL = dynamic_cast<Material::MaterialDrapeEQL const *>(mat);
    6959            0 :                             assert(matEQL != nullptr);
    6960              :                             static constexpr std::string_view Format_710(
    6961              :                                 " WindowMaterial:Drape:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},"
    6962              :                                 "{:.4R},{:.4R},{:.5R},{:.5R}\n");
    6963            0 :                             print(state.files.eio,
    6964              :                                   Format_710,
    6965            0 :                                   matEQL->Name,
    6966            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].BmTra,
    6967            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfTra,
    6968            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfTra,
    6969            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfRef,
    6970            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfRef,
    6971            0 :                                   matEQL->TAR.IR.Ft.Tra,
    6972            0 :                                   matEQL->TAR.IR.Ft.Emi,
    6973            0 :                                   matEQL->TAR.IR.Bk.Emi,
    6974            0 :                                   matEQL->pleatedWidth,
    6975            0 :                                   matEQL->pleatedLength);
    6976            0 :                         } break;
    6977              : 
    6978            0 :                         case Material::Group::ScreenEQL: {
    6979            0 :                             auto const *matEQL = dynamic_cast<Material::MaterialScreenEQL const *>(mat);
    6980            0 :                             assert(matEQL != nullptr);
    6981              :                             static constexpr std::string_view Format_711(
    6982              :                                 " WindowMaterial:Screen:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}"
    6983              :                                 ",{:.4R},{:.4R},{:.5R},{:.5R}\n");
    6984            0 :                             print(state.files.eio,
    6985              :                                   Format_711,
    6986            0 :                                   matEQL->Name,
    6987            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].BmTra,
    6988            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfTra,
    6989            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfTra,
    6990            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfRef,
    6991            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfRef,
    6992            0 :                                   matEQL->TAR.IR.Ft.Tra,
    6993            0 :                                   matEQL->TAR.IR.Ft.Emi,
    6994            0 :                                   matEQL->TAR.IR.Bk.Emi,
    6995            0 :                                   matEQL->wireSpacing,
    6996            0 :                                   matEQL->wireDiameter);
    6997            0 :                         } break;
    6998              : 
    6999            0 :                         case Material::Group::BlindEQL: {
    7000            0 :                             auto const *matEQL = dynamic_cast<Material::MaterialBlindEQL const *>(mat);
    7001            0 :                             assert(matEQL != nullptr);
    7002              : 
    7003              :                             // Formats
    7004              :                             static constexpr std::string_view Format_712(
    7005              :                                 " WindowMaterial:Blind:EquivalentLayer,{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:."
    7006              :                                 "5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}");
    7007            0 :                             print(state.files.eio,
    7008              :                                   Format_712,
    7009            0 :                                   matEQL->Name,
    7010            0 :                                   DataWindowEquivalentLayer::orientationNames[(int)matEQL->SlatOrientation],
    7011            0 :                                   matEQL->SlatWidth,
    7012            0 :                                   matEQL->SlatSeparation,
    7013            0 :                                   matEQL->SlatCrown,
    7014            0 :                                   matEQL->SlatAngle,
    7015            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfTra,
    7016            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfTra,
    7017            0 :                                   matEQL->TAR.Sol.Ft.Bm[0].DfRef,
    7018            0 :                                   matEQL->TAR.Sol.Bk.Bm[0].DfRef,
    7019            0 :                                   matEQL->TAR.Sol.Ft.Df.Tra,
    7020            0 :                                   matEQL->TAR.Sol.Ft.Df.Ref,
    7021            0 :                                   matEQL->TAR.Sol.Bk.Df.Ref,
    7022            0 :                                   matEQL->TAR.IR.Ft.Tra,
    7023            0 :                                   matEQL->TAR.IR.Ft.Emi,
    7024            0 :                                   matEQL->TAR.IR.Bk.Emi);
    7025            0 :                         } break;
    7026              : 
    7027            0 :                         case Material::Group::WindowGapEQL: {
    7028            0 :                             auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
    7029            0 :                             assert(matGas != nullptr);
    7030              :                             static constexpr std::string_view Format_713(" WindowMaterial:Gap:EquivalentLayer,{},{},{:.3R},{}\n");
    7031            0 :                             print(state.files.eio,
    7032              :                                   Format_713,
    7033            0 :                                   matGas->Name,
    7034            0 :                                   Material::gasTypeNames[(int)matGas->gases[0].type],
    7035            0 :                                   matGas->Thickness,
    7036            0 :                                   Material::gapVentTypeNames[(int)matGas->gapVentType]);
    7037            0 :                         } break;
    7038              : 
    7039            0 :                         default:
    7040            0 :                             break;
    7041              :                         }
    7042            6 :                     } // for (i)
    7043              :                 }     // if (construct.TypeIsWindow)
    7044              :             }         // for (ThisNum)
    7045              : 
    7046          109 :         } else if (wm->HasWindows) {
    7047              : 
    7048          143 :             for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
    7049          116 :                 auto &construct = state.dataConstruction->Construct(ThisNum);
    7050          116 :                 if (!construct.TypeIsWindow) continue;
    7051           37 :                 if (construct.WindowTypeEQL) continue; // skip if equivalent layer window
    7052              : 
    7053              :                 // Calculate for ASHRAE winter and summer conditions: (1)nominal center-of-glass conductance,
    7054              :                 // (2) solar heat gain coefficient (SHGC), including inside and outside air films,
    7055              :                 // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
    7056              : 
    7057           31 :                 CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
    7058           31 :                 if (errFlag == 1 || errFlag == 2) continue;
    7059           31 :                 state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
    7060              :                 // Need to have this because of window assembly reports (Simon)
    7061           31 :                 construct.SummerSHGC = SHGCSummer;
    7062           31 :                 construct.VisTransNorm = TransVisNorm;
    7063              :             }
    7064              :         }
    7065          110 :     } // ReportGlass()
    7066              : 
    7067              :     //*************************************************************************************
    7068              : 
    7069            2 :     void CalcWindowBlindProperties(EnergyPlusData &state)
    7070              :     {
    7071              : 
    7072              :         // SUBROUTINE INFORMATION:
    7073              :         //       AUTHOR         Hans Simmler
    7074              :         //       DATE WRITTEN   July-Aug 1995
    7075              :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    7076              :         //                      Dec 2001 (FCW): add variable slat angle
    7077              : 
    7078              :         // PURPOSE OF THIS SUBROUTINE:
    7079              :         // Calculates solar-optical properties of a window blind
    7080              :         // from slat properties and solar profile angle. Assumes flat slats.
    7081              : 
    7082              :         // METHODOLOGY EMPLOYED:
    7083              :         // The solar profile angle is varied from -90 to +90 deg and slat angle is varied from 0 to 180deg,
    7084              :         // covering the full range of possible profile angles and slat angles.
    7085              :         // (The profile angle is defined as the angle of incidence when the radiation
    7086              :         // source is located in a plane that (1)is perpendicular to the  plane of the blinds [which is
    7087              :         // the same as the window plane] and (2) contains the slat normal vector.)
    7088              : 
    7089              :         // In the time-step calculation,the blind properties vs. profile angle and slat angle
    7090              :         // that are calculated here will be applicable to windows and slats
    7091              :         // of arbitrary orientation, and to arbitrary sun positions, as long as the appropriate
    7092              :         // profile angle is used. The slat angle for a particular window with blinds is determined
    7093              :         // each time step in subroutine WindowShadingManager on the basis of user-specified
    7094              :         // slat control options.
    7095              : 
    7096              :         // REFERENCES:
    7097              :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    7098              :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    7099              : 
    7100              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7101              : 
    7102            2 :         Array1D<Real64> bld_pr(15);                        // Slat properties
    7103            2 :         Array1D<Real64> st_lay(16);                        // Solar-optical blind/glazing system properties
    7104              :         Real64 sun_el;                                     // Solar profile angle (radians)
    7105            2 :         Array1D<Real64> sun_el_deg(Material::MaxProfAngs); // Solar profile angle (deg) corresponding to sun_el values
    7106              :         Real64 bld_el;                                     // Slat angle (elevation of slat normal vector in plane
    7107              :         //  perpendicular to window and containing the slat normal vector) (radians)
    7108              : 
    7109            2 :         auto &s_mat = state.dataMaterial;
    7110              : 
    7111           46 :         for (auto *mat : s_mat->materials) {
    7112           44 :             if (mat->group != Material::Group::Blind) continue;
    7113              : 
    7114            2 :             auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
    7115            2 :             assert(matBlind != nullptr);
    7116              : 
    7117            2 :             bld_pr(2) = matBlind->SlatWidth;
    7118            2 :             bld_pr(3) = matBlind->SlatSeparation;
    7119              : 
    7120            6 :             for (int ISolVis = 1; ISolVis <= 2; ++ISolVis) {
    7121            4 :                 if (ISolVis == 1) { // For solar calculation
    7122            2 :                     bld_pr(4) = 0.0;
    7123            2 :                     bld_pr(5) = 0.0;
    7124            2 :                     bld_pr(6) = 0.0;
    7125            2 :                     bld_pr(7) = matBlind->slatTAR.Sol.Ft.Bm[0].DfTra;
    7126            2 :                     bld_pr(8) = matBlind->slatTAR.Sol.Ft.Bm[0].DfRef;
    7127            2 :                     bld_pr(9) = matBlind->slatTAR.Sol.Bk.Bm[0].DfRef;
    7128            2 :                     bld_pr(10) = matBlind->slatTAR.Sol.Ft.Df.Tra;
    7129            2 :                     bld_pr(11) = matBlind->slatTAR.Sol.Ft.Df.Ref;
    7130            2 :                     bld_pr(12) = matBlind->slatTAR.Sol.Bk.Df.Ref;
    7131              :                 } else { // For visible calculation
    7132            2 :                     bld_pr(4) = 0.0;
    7133            2 :                     bld_pr(5) = 0.0;
    7134            2 :                     bld_pr(6) = 0.0;
    7135            2 :                     bld_pr(7) = matBlind->slatTAR.Vis.Ft.Bm[0].DfTra;
    7136            2 :                     bld_pr(8) = matBlind->slatTAR.Vis.Ft.Bm[0].DfRef;
    7137            2 :                     bld_pr(9) = matBlind->slatTAR.Vis.Bk.Bm[0].DfRef;
    7138            2 :                     bld_pr(10) = matBlind->slatTAR.Vis.Ft.Df.Tra;
    7139            2 :                     bld_pr(11) = matBlind->slatTAR.Vis.Ft.Df.Ref;
    7140            2 :                     bld_pr(12) = matBlind->slatTAR.Vis.Bk.Df.Ref;
    7141              :                 }
    7142              :                 // For IR calculation
    7143            4 :                 bld_pr(13) = matBlind->slatTAR.IR.Ft.Tra;
    7144            4 :                 bld_pr(14) = matBlind->slatTAR.IR.Ft.Emi;
    7145            4 :                 bld_pr(15) = matBlind->slatTAR.IR.Bk.Emi;
    7146              : 
    7147              :                 // Calculate diffuse properties of blind. If blind has variable slat angle, &
    7148              :                 // vary slat angle from 0 to 180 deg in 10-deg steps (for Material::MaxSlatAngs = 19).
    7149              :                 // If blind has fixed slat angle, calculate properties at that angle only.
    7150              : 
    7151          728 :                 for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
    7152              : 
    7153          724 :                     auto &btar = matBlind->TARs[iSlatAng];
    7154              : 
    7155          724 :                     st_lay = 0.0;
    7156          724 :                     bld_el = Material::dSlatAng * iSlatAng; // 0 <= bld_el <= 180 deg
    7157              : 
    7158          724 :                     BlindOpticsDiffuse(state, matBlind->Num, ISolVis, bld_pr, bld_el, st_lay);
    7159              : 
    7160          724 :                     if (ISolVis == 1) { // Fill blind diffuse solar and IR properties
    7161          362 :                         btar.Sol.Ft.Df.Tra = st_lay(9);
    7162          362 :                         btar.Sol.Ft.Df.Ref = st_lay(10);
    7163          362 :                         btar.Sol.Bk.Df.Tra = st_lay(11);
    7164          362 :                         btar.Sol.Bk.Df.Ref = st_lay(12);
    7165          362 :                         btar.Sol.Ft.Df.Abs = max(0.0, 1.0 - st_lay(9) - st_lay(10));
    7166          362 :                         btar.Sol.Bk.Df.Abs = max(0.0, 1.0 - st_lay(11) - st_lay(12));
    7167          362 :                         btar.IR.Ft.Tra = st_lay(13);
    7168          362 :                         btar.IR.Ft.Emi = st_lay(14);
    7169          362 :                         btar.IR.Bk.Tra = st_lay(13);
    7170          362 :                         btar.IR.Bk.Emi = st_lay(15);
    7171              :                     } else { // Fill blind diffuse visible properties
    7172          362 :                         btar.Vis.Ft.Df.Tra = st_lay(9);
    7173          362 :                         btar.Vis.Ft.Df.Ref = st_lay(10);
    7174          362 :                         btar.Vis.Bk.Df.Tra = st_lay(11);
    7175          362 :                         btar.Vis.Bk.Df.Ref = st_lay(12);
    7176              :                     }
    7177              : 
    7178              :                     // If blind has variable slat angle, vary slat angle from 0 to 180 deg in 10-deg steps
    7179              :                     // (for Material::MaxSlatAngs = 19). If blind has fixed slat angle, calculate properties at that angle only.
    7180              : 
    7181        27512 :                     for (int IProfAng = 1; IProfAng <= Material::MaxProfAngs; ++IProfAng) {
    7182        26788 :                         sun_el = -Constant::Pi / 2.0 + (Constant::Pi / 36.0) * (IProfAng - 1);
    7183        26788 :                         sun_el_deg(IProfAng) = 57.2958 * sun_el;
    7184              : 
    7185              :                         // Beam solar-optical properties of blind for given profile angle and slat angle
    7186              : 
    7187        26788 :                         BlindOpticsBeam(state, matBlind->Num, bld_pr, bld_el, sun_el, st_lay);
    7188              : 
    7189        26788 :                         if (ISolVis == 1) { // Fill blind beam solar properties
    7190        13394 :                             btar.Sol.Ft.Bm[IProfAng].BmTra = st_lay(1);
    7191        13394 :                             btar.Sol.Ft.Bm[IProfAng].BmRef = st_lay(2);
    7192        13394 :                             btar.Sol.Bk.Bm[IProfAng].BmTra = st_lay(3);
    7193        13394 :                             btar.Sol.Bk.Bm[IProfAng].BmRef = st_lay(4);
    7194        13394 :                             btar.Sol.Ft.Bm[IProfAng].DfTra = st_lay(5);
    7195        13394 :                             btar.Sol.Ft.Bm[IProfAng].DfRef = st_lay(6);
    7196        13394 :                             btar.Sol.Bk.Bm[IProfAng].DfTra = st_lay(7);
    7197        13394 :                             btar.Sol.Bk.Bm[IProfAng].DfRef = st_lay(8);
    7198        13394 :                             btar.Sol.Ft.Bm[IProfAng].Abs = max(0.0, 1.0 - st_lay(6) - st_lay(1) - st_lay(5));
    7199        13394 :                             btar.Sol.Bk.Bm[IProfAng].Abs = max(0.0, 1.0 - st_lay(7) - st_lay(3) - st_lay(8));
    7200              : 
    7201              :                         } else { // Fill blind beam visible properties
    7202        13394 :                             btar.Vis.Ft.Bm[IProfAng].BmTra = st_lay(1);
    7203        13394 :                             btar.Vis.Ft.Bm[IProfAng].BmRef = st_lay(2);
    7204        13394 :                             btar.Vis.Bk.Bm[IProfAng].BmTra = st_lay(3);
    7205        13394 :                             btar.Vis.Bk.Bm[IProfAng].BmRef = st_lay(4);
    7206        13394 :                             btar.Vis.Ft.Bm[IProfAng].DfTra = st_lay(5);
    7207        13394 :                             btar.Vis.Ft.Bm[IProfAng].DfRef = st_lay(6);
    7208        13394 :                             btar.Vis.Bk.Bm[IProfAng].DfTra = st_lay(7);
    7209        13394 :                             btar.Vis.Bk.Bm[IProfAng].DfRef = st_lay(8);
    7210              :                         }
    7211              :                     } // End of loop over slat angles
    7212              :                 }     // End of loop over profile angles
    7213              : 
    7214            4 :                 if (ISolVis == 1) {
    7215              : 
    7216          364 :                     for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
    7217          362 :                         auto &btar = matBlind->TARs[iSlatAng];
    7218              : 
    7219          362 :                         Real64 sumDenom = 0.0, sumTra1 = 0.0, sumTra2 = 0.0, sumRef = 0.0, sumAbs = 0.0;
    7220              : 
    7221              :                         // Integrate from -90 to 0 deg
    7222         6878 :                         for (int IPhi = 1; IPhi <= 18; ++IPhi) {
    7223         6516 :                             auto const &btargs = btar.Sol.Ft.Bm[IPhi];
    7224         6516 :                             auto const &btargs1 = btar.Sol.Ft.Bm[IPhi + 1];
    7225              : 
    7226         6516 :                             Real64 denom = Material::dProfAng * std::cos(-Constant::PiOvr2 + (IPhi - 0.5) * Material::dProfAng);
    7227         6516 :                             sumDenom += denom;
    7228              :                             // Why adding beam transmittance here?
    7229         6516 :                             sumTra1 += denom * (btargs.BmTra + btargs1.BmTra) * 0.5;
    7230         6516 :                             sumTra2 += denom * (btargs.DfTra + btargs1.DfTra) * 0.5;
    7231         6516 :                             sumRef += denom * (btargs.DfRef + btargs1.DfRef) * 0.5;
    7232         6516 :                             sumAbs += denom * (btargs.Abs + btargs1.Abs) * 0.5;
    7233              :                         }
    7234              : 
    7235          362 :                         btar.Sol.Ft.Df.TraGnd = std::max(0.0, sumTra1 / sumDenom) + std::max(0.0, sumTra2 / sumDenom);
    7236          362 :                         btar.Sol.Ft.Df.RefGnd = std::max(0.0, sumRef / sumDenom);
    7237          362 :                         btar.Sol.Ft.Df.AbsGnd = std::max(0.0, sumAbs / sumDenom);
    7238              : 
    7239          362 :                         sumDenom = sumTra1 = sumTra2 = sumRef = sumAbs = 0.0;
    7240              : 
    7241              :                         // Integrate from -90 to 0 deg
    7242         6878 :                         for (int IPhi = 19; IPhi <= Material::MaxProfAngs - 1; ++IPhi) {
    7243         6516 :                             auto const &btargs = btar.Sol.Ft.Bm[IPhi];
    7244         6516 :                             auto const &btargs1 = btar.Sol.Ft.Bm[IPhi + 1];
    7245              : 
    7246         6516 :                             Real64 denom = Material::dProfAng * std::cos(-Constant::PiOvr2 + (IPhi - 0.5) * Material::dProfAng);
    7247         6516 :                             sumDenom += denom;
    7248              :                             // Why adding beam transmittance here?
    7249         6516 :                             sumTra1 += denom * (btargs.BmTra + btargs1.BmTra) * 0.5;
    7250         6516 :                             sumTra2 += denom * (btargs.DfTra + btargs1.DfTra) * 0.5;
    7251         6516 :                             sumRef += denom * (btargs.DfRef + btargs1.DfRef) * 0.5;
    7252         6516 :                             sumAbs += denom * (btargs.Abs + btargs1.Abs) * 0.5;
    7253              :                         }
    7254              : 
    7255          362 :                         btar.Sol.Ft.Df.TraSky = std::max(0.0, sumTra1 / sumDenom) + std::max(0.0, sumTra2 / sumDenom);
    7256          362 :                         btar.Sol.Ft.Df.RefSky = std::max(0.0, sumRef / sumDenom);
    7257          362 :                         btar.Sol.Ft.Df.AbsSky = std::max(0.0, sumAbs / sumDenom);
    7258              :                     } // for (iSlatAng)
    7259              :                 }
    7260              : 
    7261              :             } // End of loop over solar vs. visible properties
    7262              : 
    7263              :         } // End of loop over blinds
    7264            2 :     }     // CalcWindowBlindProperties()
    7265              : 
    7266              :     //*************************************************************************************
    7267              : 
    7268            0 :     void CalcWindowScreenProperties(EnergyPlusData &state)
    7269              :     {
    7270              : 
    7271              :         // SUBROUTINE INFORMATION:
    7272              :         //       AUTHOR         Richard Raustad
    7273              :         //       DATE WRITTEN   April 2006
    7274              : 
    7275              :         // PURPOSE OF THIS SUBROUTINE:
    7276              :         // Initialize static properties of window screens.
    7277              : 
    7278              :         // METHODOLOGY EMPLOYED:
    7279              :         // Loop through all surfaces to determine which window has an exterior screen. Static
    7280              :         // variables are defined here, dynamic variables are calculated in CalcScreenTransmittance.
    7281              : 
    7282              :         // Locals
    7283              :         // SUBROUTINE PARAMETER DEFINITIONS:
    7284            0 :         int constexpr M = 18;
    7285            0 :         int constexpr N = 18;
    7286              : 
    7287              :         int ConstrNumSh;      // Index to shaded construction
    7288              :         int MatNum;           // Index to material number
    7289              :         Real64 SumTrans;      // Integration variable for transmittance
    7290              :         Real64 SumTransVis;   // Integration variable for visible transmittance
    7291              :         Real64 SumReflect;    // Integration variable for reflectance
    7292              :         Real64 SumReflectVis; // Integration variable for visible reflectance
    7293              :         Real64 SumArea;       // Integration variable for area of quarter hemisphere
    7294              :         // is used on multiple surfaces
    7295              : 
    7296              :         // Pre-calculate these constants
    7297            0 :         std::vector<Real64> sunAzimuth;
    7298            0 :         std::vector<Real64> sin_sunAzimuth;
    7299            0 :         std::vector<Real64> cos_sunAzimuth;
    7300            0 :         std::vector<Real64> sunAltitude;
    7301            0 :         std::vector<Real64> sin_sunAltitude;
    7302            0 :         std::vector<Real64> cos_sunAltitude;
    7303            0 :         std::vector<Real64> skyArea;      // Area of integration
    7304            0 :         Array2D<Real64> relativeAzimuth;  // Relative azimuth angle of sun with respect to surface outward normal
    7305            0 :         Array2D<Real64> relativeAltitude; // Relative altitude angle of sun with respect to surface outward normal
    7306              : 
    7307            0 :         auto &s_mat = state.dataMaterial;
    7308            0 :         auto &s_surf = state.dataSurface;
    7309              : 
    7310            0 :         relativeAzimuth.allocate(N, M);
    7311            0 :         relativeAltitude.allocate(N, M);
    7312              : 
    7313            0 :         for (int j = 0; j <= N - 1; ++j) {
    7314            0 :             Real64 currAzimuth = (90.0 / N) * j * Constant::DegToRad;
    7315            0 :             sunAzimuth.push_back(currAzimuth); // Azimuth angle of sun during integration
    7316            0 :             sin_sunAzimuth.push_back(std::sin(currAzimuth));
    7317            0 :             cos_sunAzimuth.push_back(std::cos(currAzimuth));
    7318              :         }
    7319              : 
    7320            0 :         for (int i = 0; i <= M - 1; ++i) {
    7321            0 :             Real64 currAltitude = (90.0 / M) * i * Constant::DegToRad;
    7322            0 :             sunAltitude.push_back(currAltitude); // Altitude angle of sun during integration
    7323            0 :             sin_sunAltitude.push_back(std::sin(currAltitude));
    7324            0 :             cos_sunAltitude.push_back(std::cos(currAltitude));
    7325            0 :             skyArea.push_back(sin_sunAltitude[i] * cos_sunAltitude[i]);
    7326              :         }
    7327              : 
    7328            0 :         for (int j = 1; j <= N; ++j) {
    7329            0 :             for (int i = 1; i <= M; ++i) {
    7330              :                 // Integrate transmittance using coordinate transform
    7331            0 :                 relativeAzimuth(i, j) = std::asin(sin_sunAltitude[i - 1] * cos_sunAzimuth[j - 1]);        // phi prime
    7332            0 :                 relativeAltitude(i, j) = std::atan(std::tan(sunAltitude[i - 1]) * sin_sunAzimuth[j - 1]); // alpha
    7333              :             }
    7334              :         }
    7335              : 
    7336            0 :         bool PrintTransMap = false; // Flag used to print transmittance map
    7337              : 
    7338            0 :         for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
    7339            0 :             auto const &surf = s_surf->Surface(SurfNum);
    7340              : 
    7341            0 :             if (!surf.HasShadeControl) continue;
    7342              : 
    7343            0 :             if (s_surf->WindowShadingControl(surf.activeWindowShadingControl).ShadingType != WinShadingType::ExtScreen) continue;
    7344              : 
    7345            0 :             ConstrNumSh = surf.activeShadedConstruction;
    7346            0 :             MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
    7347            0 :             auto *matScreen = dynamic_cast<Material::MaterialScreen *>(s_mat->materials(MatNum));
    7348            0 :             assert(matScreen != nullptr);
    7349            0 :             s_surf->SurfaceWindow(SurfNum).screenNum = MatNum;
    7350              : 
    7351            0 :             if (matScreen->isUsed) continue; // Has already been initialized
    7352              : 
    7353            0 :             matScreen->isUsed = true;
    7354            0 :             if (matScreen->mapDegResolution > 0) PrintTransMap = true;
    7355              : 
    7356              :             //     If a screen material is used more than once, the Material structure's screen data pointer holds the screen number
    7357              :             //     of the last window surface. Use this method to access the screen parameter's only for static variables such as
    7358              :             //     diffuse properties (InitGlassOpticalCalculations). For all cases where the screen properties are a function of
    7359              :             //     sun azimuth and altitude angles, use the Screens structure.
    7360              :             //     Invert calculation done in GetMaterialInput to find Diameter to Spacing ratio (Props(7)/Props(6))
    7361              :             //     dataMaterial.Material(MaterNum)%Trans = (1 - MaterialProps(7)/MaterialProps(6))**2.0
    7362            0 :             matScreen->diameterToSpacingRatio = 1.0 - std::sqrt(matScreen->Trans);
    7363              : 
    7364              :             // Reflectance of screen material only
    7365            0 :             matScreen->CylinderRef = matScreen->ShadeRef / (1 - matScreen->Trans);
    7366            0 :             matScreen->CylinderRefVis = matScreen->ShadeRefVis / (1 - matScreen->Trans);
    7367              : 
    7368              :             //     Integrate the transmittance over a quarter hemisphere for use in diffuse calculations
    7369            0 :             SumTrans = 0.0;
    7370            0 :             SumTransVis = 0.0;
    7371            0 :             SumReflect = 0.0;
    7372            0 :             SumReflectVis = 0.0;
    7373            0 :             SumArea = 0.0;
    7374              :             //     Integration over quarter hemisphere in polar coordinates and converting to rectangular to call screen model.
    7375              :             //     Proceed in reverse order such that the last calculation yields zero sun angle to window screen normal (angles=0,0).
    7376              :             //     The properties calculated at zero sun angle are then used elsewhere prior to the start of the actual simulation.
    7377              : 
    7378            0 :             Material::ScreenBmTransAbsRef btar;
    7379              : 
    7380            0 :             for (int j = N; j >= 1; --j) {
    7381            0 :                 for (int i = M; i >= 1; --i) {
    7382              :                     // Integrate transmittance using coordinate transform
    7383              :                     // TODO: switch to interpolation?
    7384            0 :                     CalcScreenTransmittance(state, matScreen, relativeAltitude(i, j), relativeAzimuth(i, j), btar);
    7385            0 :                     SumTrans += (btar.BmTrans + btar.DfTrans) * skyArea[i - 1];
    7386            0 :                     SumTransVis += (btar.BmTransVis + btar.DfTransVis) * skyArea[i - 1];
    7387            0 :                     SumReflect += btar.RefSolFront * skyArea[i - 1];
    7388            0 :                     SumReflectVis += btar.RefVisFront * skyArea[i - 1];
    7389            0 :                     SumArea += skyArea[i - 1];
    7390              :                 }
    7391              :             }
    7392              : 
    7393              :             // Reflectance of overall screen including openings and scattered transmittance
    7394            0 :             matScreen->ShadeRef = matScreen->CylinderRef * (1.0 - (btar.BmTrans + btar.DfTrans));
    7395            0 :             matScreen->ShadeRefVis = matScreen->CylinderRefVis * (1.0 - (btar.BmTransVis + btar.DfTransVis));
    7396              : 
    7397            0 :             if (SumArea != 0) {
    7398            0 :                 matScreen->DfTrans = SumTrans / SumArea;
    7399            0 :                 matScreen->DfTransVis = SumTransVis / SumArea;
    7400            0 :                 matScreen->DfRef = SumReflect / SumArea;
    7401            0 :                 matScreen->DfRefVis = SumReflectVis / SumArea;
    7402              :             }
    7403            0 :             matScreen->DfAbs = max(0.0, (1.0 - matScreen->DfTrans - matScreen->DfRef));
    7404              : 
    7405            0 :             matScreen->AbsorpThermalBack = matScreen->DfAbs;
    7406            0 :             matScreen->AbsorpThermalFront = matScreen->DfAbs;
    7407            0 :             matScreen->ReflectSolBeamFront = matScreen->DfRef;
    7408            0 :             matScreen->ReflectSolBeamBack = matScreen->DfRef;
    7409              : 
    7410              :             // Initialize incident-angle dependent beam matrix (will interpolate from this)
    7411            0 :             for (int ip = 0; ip < Material::maxIPhi; ++ip) {
    7412            0 :                 Real64 Phi = ip * matScreen->dPhi;
    7413            0 :                 for (int it = 0; it < Material::maxITheta; ++it) {
    7414            0 :                     Real64 Theta = it * matScreen->dTheta;
    7415            0 :                     CalcScreenTransmittance(state, matScreen, Phi, Theta, matScreen->btars[ip][it]);
    7416              :                 }
    7417              :             }
    7418              : 
    7419              :         } // for (SurfNum)
    7420              : 
    7421              :         // Write transmittance versus direct normal angle to csv file
    7422              : 
    7423            0 :         if (PrintTransMap) {
    7424              :             // Fortran version did not have error handling in case of file open failure. This one does.
    7425              :             // Which is correct?
    7426            0 :             auto screenCsvFile = state.files.screenCsv.open(state, "CalcWindowScreenComponents", state.files.outputControl.screen);
    7427              : 
    7428              :             //  WRITE(ScreenTransUnitNo,*)' '
    7429            0 :             for (auto *mat : s_mat->materials) {
    7430              : 
    7431            0 :                 if (mat->group != Material::Group::Screen) continue;
    7432            0 :                 if (!mat->isUsed) continue;
    7433              : 
    7434            0 :                 auto *screen = dynamic_cast<Material::MaterialScreen *>(mat);
    7435            0 :                 assert(screen != nullptr);
    7436              : 
    7437              :                 //   Do not print transmittance map if angle increment is equal to 0
    7438            0 :                 if (screen->mapDegResolution == 0) continue;
    7439              : 
    7440            0 :                 int maxIPrint = int(90 / screen->mapDegResolution);
    7441              : 
    7442            0 :                 print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
    7443            0 :                 print(screenCsvFile,
    7444              :                       "Tabular data for beam solar transmittance at varying \"relative\" azimuth (row) and "
    7445              :                       "altitude (column) angles (deg) [relative to surface normal].\n");
    7446            0 :                 for (int it = maxIPrint; it >= 0; --it) {
    7447            0 :                     print(screenCsvFile, ",{}", it * screen->mapDegResolution);
    7448              :                 }
    7449            0 :                 print(screenCsvFile, "\n");
    7450              : 
    7451            0 :                 for (int it = 0; it <= maxIPrint; ++it) {
    7452            0 :                     print(screenCsvFile, "{}", it * screen->mapDegResolution);
    7453            0 :                     for (int ip = maxIPrint; ip >= 0; --ip) {
    7454            0 :                         Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
    7455            0 :                         Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
    7456              :                         int ip1, ip2, it1, it2;
    7457              :                         BilinearInterpCoeffs coeffs;
    7458            0 :                         Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
    7459            0 :                         GetBilinearInterpCoeffs(
    7460            0 :                             phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
    7461            0 :                         Real64 bmTrans = BilinearInterp(screen->btars[ip1][it1].BmTrans,
    7462            0 :                                                         screen->btars[ip1][it2].BmTrans,
    7463            0 :                                                         screen->btars[ip2][it1].BmTrans,
    7464            0 :                                                         screen->btars[ip2][it2].BmTrans,
    7465            0 :                                                         coeffs);
    7466              :                         // bmTrans = screen->btars[ip][it].BmTrans;
    7467            0 :                         print(screenCsvFile, ",{:.6R}", bmTrans);
    7468              :                     }
    7469            0 :                     print(screenCsvFile, "\n");
    7470              :                 }
    7471            0 :                 print(screenCsvFile, "\n\n");
    7472              : 
    7473            0 :                 print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
    7474            0 :                 print(screenCsvFile,
    7475              :                       "Tabular data for scattered solar transmittance at varying \"relative\" azimuth (row) and "
    7476              :                       "altitude (column) angles (deg) [relative to surface normal].\n");
    7477              : 
    7478            0 :                 for (int it = 0; it <= maxIPrint; ++it) {
    7479            0 :                     print(screenCsvFile, ",{}", it * screen->mapDegResolution);
    7480              :                 }
    7481            0 :                 print(screenCsvFile, "\n");
    7482              : 
    7483            0 :                 for (int it = 0; it <= maxIPrint; ++it) {
    7484            0 :                     print(screenCsvFile, "{}", it * screen->mapDegResolution);
    7485            0 :                     for (int ip = 0; ip <= maxIPrint; ++ip) {
    7486            0 :                         Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
    7487            0 :                         Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
    7488              :                         int ip1, ip2, it1, it2;
    7489              :                         BilinearInterpCoeffs coeffs;
    7490            0 :                         Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
    7491            0 :                         GetBilinearInterpCoeffs(
    7492            0 :                             phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
    7493            0 :                         Real64 dfTrans = BilinearInterp(screen->btars[ip1][it1].DfTrans,
    7494            0 :                                                         screen->btars[ip1][it2].DfTrans,
    7495            0 :                                                         screen->btars[ip2][it1].DfTrans,
    7496            0 :                                                         screen->btars[ip2][it2].DfTrans,
    7497            0 :                                                         coeffs);
    7498              : 
    7499              :                         // dfTrans = screen->btars[ip][it].DfTrans;
    7500            0 :                         print(screenCsvFile, ",{:.6R}", dfTrans);
    7501              :                     }
    7502            0 :                     print(screenCsvFile, "\n");
    7503              :                 }
    7504            0 :                 print(screenCsvFile, "\n\n");
    7505              :             }
    7506            0 :         } // if (PrintTransMap)
    7507            0 :     }     // CalcWindowScreenProperties()
    7508              : 
    7509          724 :     void BlindOpticsDiffuse(EnergyPlusData &state,
    7510              :                             int const BlindNum,      // Blind number
    7511              :                             int const ISolVis,       // 1 = solar and IR calculation; 2 = visible calculation
    7512              :                             Array1A<Real64> const c, // Slat properties
    7513              :                             Real64 const b_el,       // Slat elevation (radians)
    7514              :                             Array1A<Real64> p        // Blind properties
    7515              :     )
    7516              :     {
    7517              : 
    7518              :         // SUBROUTINE INFORMATION:
    7519              :         //       AUTHOR         Hans Simmler
    7520              :         //       DATE WRITTEN   July-Aug 1995
    7521              :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    7522              :         //                      Aug 2002 (FCW): make corrections so that calculations are consistent with
    7523              :         //                       G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
    7524              :         //                      interchanged in F, so that
    7525              :         //                       G(i) = Sum over j of J(j)*F(i,j), which is wrong.
    7526              :         //                      This change was made to resolve discrepancies between EnergyPlus results
    7527              :         //                      and blind transmittance measurements made at Oklahoma State Univ.
    7528              :         //                      Feb 2004 (FCW): modify slat edge correction calc to avoid possible divide by zero
    7529              : 
    7530              :         // PURPOSE OF THIS SUBROUTINE:
    7531              :         // From the slat properties, calculates the diffuse solar, diffuse visible and IR
    7532              :         // transmission and reflection properties of a window blind.
    7533              : 
    7534              :         // REFERENCES:
    7535              :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    7536              :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    7537              : 
    7538              :         // Argument array dimensioning
    7539          724 :         c.dim(15);
    7540          724 :         p.dim(16);
    7541              : 
    7542          724 :         Array1D<Real64> fEdgeA(2); // Average slat edge correction factor for upper and lower quadrants
    7543              :         //  seen by window blind
    7544          724 :         Array1D<Real64> j(6);       // Slat section radiosity vector
    7545          724 :         Array1D<Real64> G(6);       // Slat section irradiance vector
    7546          724 :         Array1D<Real64> Q(6);       // Slat section radiance vector
    7547          724 :         Array2D<Real64> F(6, 6);    // View factor array
    7548          724 :         Array2D<Real64> X(4, 4);    // Exchange matrix
    7549          724 :         Array2D<Real64> Xinv(4, 4); // Inverse of exchange matrix
    7550          724 :         Array1D_int indx(4);        // LU decomposition indices
    7551              : 
    7552              :         // The slat input properties are:
    7553              :         // c(1)    0. (unused)
    7554              :         // c(2)    Slat width (m)
    7555              :         // c(3)    Slat separation (m)
    7556              :         // c(4)    0. (unused)
    7557              :         // c(5)    0. (unused)
    7558              :         // c(6)    0. (unused)
    7559              :         //      The following are solar or visible properties
    7560              :         // c(7)    trans beam-diff
    7561              :         // c(8)    refl front beam-diff
    7562              :         // c(9)    refl back beam-diff
    7563              :         // c(10)   trans diff-diff
    7564              :         // c(11)   refl front diff-diff
    7565              :         // c(12)   refl back diff-diff
    7566              :         //      The following are hemispherical thermal IR properties
    7567              :         // c(13)   trans diff-diff
    7568              :         // c(14)   emiss front diff
    7569              :         // c(15)   emiss back diff
    7570              : 
    7571              :         // The calculated blind properties are:
    7572              :         //      The following are solar or visible properties
    7573              :         // p(1)    trans front beam-beam
    7574              :         // p(2)    refl front beam-beam
    7575              :         // p(3)    trans back beam-beam
    7576              :         // p(4)    refl back beam-beam
    7577              :         // p(5)    trans front beam-diff
    7578              :         // p(6)    refl front beam-diff
    7579              :         // p(7)    trans back beam-diff
    7580              :         // p(8)    refl back beam-diff
    7581              :         // p(9)    trans front diff-diff
    7582              :         // p(10)   refl front diff-diff
    7583              :         // p(11)   trans back diff-diff
    7584              :         // p(12)   refl back diff-diff
    7585              :         //      The following are IR properties
    7586              :         // p(13)   IR trans front (same as IR trans back)
    7587              :         // p(14)   IR emissivity front
    7588              :         // p(15)   IR emissivity back
    7589              :         // p(16)   0.0 (unused)
    7590              : 
    7591          724 :         auto &s_mat = state.dataMaterial;
    7592          724 :         auto *matBlind = dynamic_cast<Material::MaterialBlind *>(s_mat->materials(BlindNum));
    7593              :         //     Calculate view factors between slat sections (slat is divided longitudinally into two equal parts)
    7594              : 
    7595          724 :         ViewFac(c(2), c(3), b_el, Constant::PiOvr2, F);
    7596              : 
    7597              :         //     Set up exchange matrix X for diffuse properties
    7598              : 
    7599         2172 :         for (int k = 3; k <= 5; k += 2) {
    7600         7240 :             for (int m = 3; m <= 6; ++m) {
    7601         5792 :                 X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
    7602         5792 :                 X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
    7603              :             }
    7604              :         }
    7605              : 
    7606         3620 :         for (int k = 1; k <= 4; ++k) {
    7607         2896 :             ++X(k, k);
    7608              :         }
    7609              : 
    7610          724 :         indx = 0;
    7611          724 :         InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
    7612              : 
    7613              :         //---------Calculate diffuse short-wave properties for the front side of the blind
    7614              : 
    7615              :         //     Sources
    7616              : 
    7617          724 :         Q(3) = c(12) * F(3, 1) + c(10) * F(4, 1);
    7618          724 :         Q(4) = c(10) * F(3, 1) + c(11) * F(4, 1);
    7619          724 :         Q(5) = c(12) * F(5, 1) + c(10) * F(6, 1);
    7620          724 :         Q(6) = c(10) * F(5, 1) + c(11) * F(6, 1);
    7621              : 
    7622              :         //     Radiosities
    7623              : 
    7624          724 :         j(1) = 1.0;
    7625          724 :         j(2) = 0.0;
    7626         3620 :         for (int k = 3; k <= 6; ++k) {
    7627         2896 :             j(k) = 0.0;
    7628        14480 :             for (int m = 3; m <= 6; ++m) {
    7629        11584 :                 j(k) += Xinv(m - 2, k - 2) * Q(m);
    7630              :             }
    7631              :         }
    7632              : 
    7633              :         //     Irradiances
    7634         5068 :         for (int k = 1; k <= 6; ++k) {
    7635         4344 :             G(k) = 0.0;
    7636        30408 :             for (int m = 1; m <= 6; ++m) {
    7637              :                 // G(k)=G(k)+F(k,m)*J(m)
    7638        26064 :                 G(k) += j(m) * F(k, m);
    7639              :             }
    7640              :         }
    7641              : 
    7642              :         //     Slat edge correction factor
    7643              :         std::array<Real64, numPhis> fEdgeSource; // Slat edge correction factor vs source elevation
    7644              : 
    7645          724 :         Real64 const phib = b_el; // Elevation of slat normal vector (radians)
    7646          724 :         Real64 constexpr delphis =
    7647              :             Constant::PiOvr2 /
    7648              :             10.0; // Angle increment for integration over source distribution (radians) // This is a bug, the delta is 10.0, PiOvr2/10.0 is 9.0.
    7649              : 
    7650         2172 :         for (int IUpDown = 1; IUpDown <= 2; ++IUpDown) {
    7651        15928 :             for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
    7652        14480 :                 Real64 phis = -((double)iPhi + 0.5) * delphis; // Source elevation (radians)
    7653        14480 :                 if (IUpDown == 2) phis = ((double)iPhi + 0.5) * delphis;
    7654        14480 :                 fEdgeSource[iPhi] = 0.0;
    7655        14480 :                 Real64 fEdge1 = 0.0;
    7656        14480 :                 Real64 gamma = phib - phis;
    7657        14480 :                 if (std::abs(std::sin(gamma)) > 0.01) {
    7658        14320 :                     if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
    7659         7120 :                         (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
    7660        10720 :                         fEdge1 = matBlind->SlatThickness * std::abs(std::sin(gamma)) /
    7661        10720 :                                  ((matBlind->SlatSeparation + matBlind->SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
    7662              :                     }
    7663        14320 :                     fEdgeSource[iPhi] = min(1.0, std::abs(fEdge1));
    7664              :                 }
    7665              :             }
    7666         1448 :             fEdgeA(IUpDown) = DiffuseAverage(fEdgeSource);
    7667              :         }
    7668          724 :         Real64 fEdge = 0.5 * (fEdgeA(1) + fEdgeA(2)); // Slat edge correction factor
    7669              : 
    7670              :         //     Front diffuse-diffuse transmittance (transmittance of slat edge assumed zero)
    7671          724 :         p(9) = G(2) * (1.0 - fEdge);
    7672              : 
    7673              :         //     Front diffuse-diffuse reflectance (edge of slat is assumed to have same diffuse
    7674              :         //     reflectance as front side of slat, c(11))
    7675          724 :         p(10) = G(1) * (1.0 - fEdge) + fEdge * c(11);
    7676              : 
    7677              :         //-----------Calculate diffuse short-wave properties for the back side of the blind
    7678              : 
    7679              :         //     Sources
    7680              : 
    7681          724 :         Q(3) = c(12) * F(3, 2) + c(10) * F(4, 2);
    7682          724 :         Q(4) = c(10) * F(3, 2) + c(11) * F(4, 2);
    7683          724 :         Q(5) = c(12) * F(5, 2) + c(10) * F(6, 2);
    7684          724 :         Q(6) = c(10) * F(5, 2) + c(11) * F(6, 2);
    7685              : 
    7686              :         //     Radiosities
    7687              : 
    7688          724 :         j(1) = 0.0;
    7689          724 :         j(2) = 1.0;
    7690         3620 :         for (int k = 3; k <= 6; ++k) {
    7691         2896 :             j(k) = 0.0;
    7692        14480 :             for (int m = 3; m <= 6; ++m) {
    7693        11584 :                 j(k) += Xinv(m - 2, k - 2) * Q(m);
    7694              :             }
    7695              :         }
    7696              : 
    7697              :         //     Irradiances
    7698              : 
    7699         5068 :         for (int k = 1; k <= 6; ++k) {
    7700         4344 :             G(k) = 0.0;
    7701        30408 :             for (int m = 1; m <= 6; ++m) {
    7702              :                 // G(k)=G(k)+F(k,m)*J(m)
    7703        26064 :                 G(k) += j(m) * F(k, m);
    7704              :             }
    7705              :         }
    7706              : 
    7707              :         //     Back diffuse-diffuse transmittance
    7708          724 :         p(11) = G(1) * (1.0 - fEdge);
    7709              : 
    7710              :         //     Back hemi-hemi reflectance
    7711          724 :         p(12) = G(2) * (1.0 - fEdge) + fEdge * c(11);
    7712              : 
    7713          724 :         if (ISolVis == 1) {
    7714              : 
    7715              :             //-----------Calculate IR properties of the blind
    7716              :             //           (use same set of view factors as for diffuse short-wave properties)
    7717              : 
    7718              :             //     Front and back slat IR reflectances
    7719          362 :             Real64 ri = 1 - c(13) - c(14); // Front and back IR slat reflectance
    7720          362 :             Real64 rib = 1 - c(13) - c(15);
    7721              : 
    7722              :             //     Set up exchange matrix X for diffuse properties
    7723              : 
    7724         1086 :             for (int k = 3; k <= 5; k += 2) {
    7725         3620 :                 for (int m = 3; m <= 6; ++m) {
    7726         2896 :                     X(m - 2, k - 2) = -rib * F(k, m) - c(13) * F(k + 1, m);
    7727         2896 :                     X(m - 2, k - 1) = -c(13) * F(k, m) - ri * F(k + 1, m);
    7728              :                 }
    7729              :             }
    7730              : 
    7731         1810 :             for (int k = 1; k <= 4; ++k) {
    7732         1448 :                 ++X(k, k);
    7733              :             }
    7734              : 
    7735          362 :             indx = 0;
    7736          362 :             InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
    7737              : 
    7738              :             //---------Calculate diffuse IR properties for the FRONT side of the blind
    7739              : 
    7740              :             //     Sources
    7741              : 
    7742          362 :             Q(3) = rib * F(3, 1) + c(13) * F(4, 1);
    7743          362 :             Q(4) = c(13) * F(3, 1) + ri * F(4, 1);
    7744          362 :             Q(5) = rib * F(5, 1) + c(13) * F(6, 1);
    7745          362 :             Q(6) = c(13) * F(5, 1) + ri * F(6, 1);
    7746              : 
    7747              :             //     Radiosities
    7748              : 
    7749          362 :             j(1) = 1.0;
    7750          362 :             j(2) = 0.0;
    7751         1810 :             for (int k = 3; k <= 6; ++k) {
    7752         1448 :                 j(k) = 0.0;
    7753         7240 :                 for (int m = 3; m <= 6; ++m) {
    7754         5792 :                     j(k) += Xinv(m - 2, k - 2) * Q(m);
    7755              :                 }
    7756              :             }
    7757              : 
    7758              :             //     Irradiances
    7759         2534 :             for (int k = 1; k <= 6; ++k) {
    7760         2172 :                 G(k) = 0.0;
    7761        15204 :                 for (int m = 1; m <= 6; ++m) {
    7762              :                     // G(k)=G(k)+F(k,m)*J(m)
    7763        13032 :                     G(k) += j(m) * F(k, m);
    7764              :                 }
    7765              :             }
    7766              : 
    7767              :             //     Front diffuse-diffuse IR transmittance (transmittance of slat edge assumed zero)
    7768          362 :             p(13) = G(2) * (1.0 - fEdge);
    7769              : 
    7770              :             //     Front diffuse-diffuse IR reflectance (edge of slat is assumed to have same IR
    7771              :             //     reflectance as front side of slat, ri)
    7772          362 :             Real64 BlindIRreflFront = G(1) * (1.0 - fEdge) + fEdge * ri; // Blind front IR reflectance
    7773              : 
    7774              :             //     Front IR emissivity
    7775          362 :             p(14) = max(0.0001, 1.0 - p(13) - BlindIRreflFront);
    7776              : 
    7777              :             //-----------Calculate diffuse IR properties for the BACK side of the blind
    7778              : 
    7779              :             //     Sources
    7780              : 
    7781          362 :             Q(3) = rib * F(3, 2) + c(13) * F(4, 2);
    7782          362 :             Q(4) = c(13) * F(3, 2) + ri * F(4, 2);
    7783          362 :             Q(5) = rib * F(5, 2) + c(13) * F(6, 2);
    7784          362 :             Q(6) = c(13) * F(5, 2) + ri * F(6, 2);
    7785              : 
    7786              :             //     Radiosities
    7787              : 
    7788          362 :             j(1) = 0.0;
    7789          362 :             j(2) = 1.0;
    7790         1810 :             for (int k = 3; k <= 6; ++k) {
    7791         1448 :                 j(k) = 0.0;
    7792         7240 :                 for (int m = 3; m <= 6; ++m) {
    7793         5792 :                     j(k) += Xinv(m - 2, k - 2) * Q(m);
    7794              :                 }
    7795              :             }
    7796              : 
    7797              :             //     Irradiances
    7798              : 
    7799         2534 :             for (int k = 1; k <= 6; ++k) {
    7800         2172 :                 G(k) = 0.0;
    7801        15204 :                 for (int m = 1; m <= 6; ++m) {
    7802              :                     // G(k)=G(k)+F(k,m)*J(m)
    7803        13032 :                     G(k) += j(m) * F(k, m);
    7804              :                 }
    7805              :             }
    7806              : 
    7807              :             //     Back diffuse-diffuse IR reflectance
    7808          362 :             Real64 BlindIRreflBack = G(2) * (1.0 - fEdge) + fEdge * ri; // Blind back IR reflectance
    7809              : 
    7810              :             //     Back IR emissivity
    7811          362 :             p(15) = max(0.0001, 1.0 - p(13) - BlindIRreflBack);
    7812              : 
    7813              :         } // End of IR properties calculation
    7814          724 :     }     // BlindOpticsDiffuse()
    7815              : 
    7816              :     //**********************************************************************************************
    7817              : 
    7818        26788 :     void BlindOpticsBeam(EnergyPlusData &state,
    7819              :                          int const BlindNum,      // Blind number
    7820              :                          Array1A<Real64> const c, // Slat properties (equivalent to BLD_PR)
    7821              :                          Real64 const b_el,       // Slat elevation (radians)
    7822              :                          Real64 const s_el,       // Solar profile angle (radians)
    7823              :                          Array1A<Real64> p        // Blind properties (equivalent to ST_LAY)
    7824              :     )
    7825              :     {
    7826              : 
    7827              :         // SUBROUTINE INFORMATION:
    7828              :         //       AUTHOR         Hans Simmler
    7829              :         //       DATE WRITTEN   July-Aug 1995
    7830              :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    7831              :         //                      Aug 2002 (FCW): make corrections so that calculations are consistent with
    7832              :         //                       G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
    7833              :         //                      interchanged in F, so that
    7834              :         //                       G(i) = Sum over j of J(j)*F(i,j), which is wrong.
    7835              :         //                      This change was made to resolve discrepancies between EnergyPlus results
    7836              :         //                      and blind transmittance measurements made at Oklahoma State Univ.
    7837              : 
    7838              :         // PURPOSE OF THIS SUBROUTINE:
    7839              :         //     Calculates the beam radiation properties of a
    7840              :         //     window blind consisting of flat slats with known material properties.
    7841              :         //     The calculation for the reverse direction is done with the radiation source
    7842              :         //     reflected at the window plane.
    7843              : 
    7844              :         // REFERENCES:
    7845              :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    7846              :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    7847              : 
    7848              :         // Argument array dimensioning
    7849        26788 :         c.dim(15);
    7850        26788 :         p.dim(16);
    7851              : 
    7852              :         struct BlindInputs
    7853              :         {
    7854              :             Real64 slatWidth;
    7855              :             Real64 slatSeparation;
    7856              :             Real64 BmDfTrans;
    7857              :             Real64 BmDfRefFront;
    7858              :             Real64 BmDfRefBack;
    7859              :             Real64 DfDfTrans;
    7860              :             Real64 DfDfRefFront;
    7861              :             Real64 DfDfRefBack;
    7862              :             Real64 DfDfTransIR;
    7863              :             Real64 DfEmissFront;
    7864              :             Real64 DfEmissBack;
    7865              :         };
    7866              : 
    7867              :         // The slat input properties are:
    7868              :         // c(1)    0. (unused)
    7869              :         // c(2)    Slat width (m)
    7870              :         // c(3)    Slat separation (m)
    7871              :         // c(4)    0. (unused)
    7872              :         // c(5)    0. (unused)
    7873              :         // c(6)    0. (unused)
    7874              :         //      The following are solar or visible properties
    7875              :         // c(7)    trans beam-diff
    7876              :         // c(8)    refl front beam-diff
    7877              :         // c(9)    refl back beam-diff
    7878              :         // c(10)   trans diff-diff
    7879              :         // c(11)   refl front diff-diff
    7880              :         // c(12)   refl back diff-diff
    7881              :         //      The following are hemispherical thermal IR properties
    7882              :         // c(13)   trans diff-diff
    7883              :         // c(14)   emiss front diff
    7884              :         // c(15)   emiss back diff
    7885              : 
    7886              :         struct BlindOutputs
    7887              :         {
    7888              :             Real64 BmBmTransFront;
    7889              :             Real64 BmBmRefFront;
    7890              :             Real64 BmBmTransBack;
    7891              :             Real64 BmBmRefBack;
    7892              :             Real64 BmDfTransFront;
    7893              :             Real64 BmDfRefFront;
    7894              :             Real64 BmDfTransBack;
    7895              :             Real64 BmDfRefBack;
    7896              :             Real64 DfDfTransFront;
    7897              :             Real64 DfDfRefFront;
    7898              :             Real64 DfDfTransBack;
    7899              :             Real64 DfDfRefBack;
    7900              : 
    7901              :             Real64 TransFrontIR;
    7902              :             Real64 TransBackIR;
    7903              :             Real64 EmissFrontIR;
    7904              :             Real64 EmissBackIR;
    7905              :         };
    7906              : 
    7907              :         // The calculated blind properties are:
    7908              :         //      The following are solar or visible properties
    7909              :         // p(1)    trans front beam-beam
    7910              :         // p(2)    refl front beam-beam
    7911              :         // p(3)    trans back beam-beam
    7912              :         // p(4)    refl back beam-beam
    7913              :         // p(5)    trans front beam-diff
    7914              :         // p(6)    refl front beam-diff
    7915              :         // p(7)    trans back beam-diff
    7916              :         // p(8)    refl back beam-diff
    7917              :         // p(9)    trans front diff-diff
    7918              :         // p(10)   refl front diff-diff
    7919              :         // p(11)   trans back diff-diff
    7920              :         // p(12)   refl back diff-diff
    7921              :         //      The following are IR properties
    7922              :         // p(13)   IR trans front (same as IR trans back)
    7923              :         // p(14)   IR emissivity front
    7924              :         // p(15)   IR emissivity back
    7925              :         // p(16)   0.0 (unused)
    7926              : 
    7927              :         Real64 phib;                // Elevation angle of normal vector to front of slat (0 to pi radians)
    7928              :         Real64 phis;                // Elevation angle of source vector; same as "profile angle" (-pi/2 to pi/2 radians)
    7929              :         Real64 gamma;               // phib - phis (radians)
    7930        26788 :         Array1D<Real64> j(6);       // Slat surface section radiosity vector
    7931        26788 :         Array1D<Real64> G(6);       // Slat surface section irradiance vector
    7932        26788 :         Array1D<Real64> Q(6);       // Slat surface section source vector
    7933        26788 :         Array2D<Real64> F(6, 6);    // View factor array
    7934        26788 :         Array2D<Real64> X(4, 4);    // X*J = Q
    7935        26788 :         Array2D<Real64> Xinv(4, 4); // J = Xinv*Q
    7936              :         Real64 fEdge;               // Slat edge correction factor
    7937              :         Real64 fEdge1;
    7938        26788 :         Array1D_int indx(4); // Indices for LU decomposition
    7939              : 
    7940        26788 :         auto &s_mat = state.dataMaterial;
    7941        26788 :         auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlindNum));
    7942              : 
    7943        26788 :         p = 0.0;
    7944              : 
    7945              :         //     Elevation of radiation source; source is assumed to be in a plane that
    7946              :         //     (1) contains the slat outward normal and (2) is perpendicular to plane of the blinds.
    7947        26788 :         phis = s_el;
    7948              : 
    7949              :         //     Elevation of slat outward normal
    7950        26788 :         phib = b_el;
    7951              : 
    7952              :         //     Loop twice for front and back side properties of blind
    7953        80364 :         for (int i = 0; i <= 2; i += 2) {
    7954              : 
    7955              :             //       For back-side properties, reflect the source position so that it is the mirror
    7956              :             //       image of the original source position, where the "mirror" is in the plane of the
    7957              :             //       blinds. This is equivalent to keeping the original source position but rotating
    7958              :             //       the slats so that the original slat angle (e.g., 45 deg) becomes 180 - original slat
    7959              :             //       angle (135 deg).
    7960              : 
    7961        53576 :             if (i == 2) {
    7962        26788 :                 phib = Constant::Pi - phib;
    7963              :             }
    7964              : 
    7965              :             //       Correction factor that accounts for finite thickness of slats. It is used to modify the
    7966              :             //       blind transmittance and reflectance to account for reflection and absorption by the
    7967              :             //       edge of the slat. fEdge is ratio of area subtended by edge of slat
    7968              :             //       to area between tops of adjacent slats.
    7969              : 
    7970        53576 :             fEdge = 0.0;
    7971        53576 :             fEdge1 = 0.0;
    7972        53576 :             gamma = phib - phis;
    7973        53576 :             if (std::abs(std::sin(gamma)) > 0.01) {
    7974        53272 :                 if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
    7975        26496 :                     (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
    7976        39448 :                     fEdge1 = matBlind->SlatThickness * std::abs(std::sin(gamma)) /
    7977        39448 :                              ((matBlind->SlatSeparation + matBlind->SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
    7978              :                 }
    7979        53272 :                 fEdge = min(1.0, std::abs(fEdge1));
    7980              :             }
    7981              : 
    7982              :             //       Direct-to-direct transmittance (portion of beam that passes between slats without
    7983              :             //       without touching them
    7984              : 
    7985        53576 :             p(1 + i) = matBlind->BeamBeamTrans(phis, phib);
    7986              :             //       Direct-to-direct reflectance; this is zero for now since all reflection is assumed to be diffuse.
    7987        53576 :             p(2 + i) = 0.0;
    7988              : 
    7989              :             //       View factors between slat sections for calculating direct-to-diffuse transmittance and reflectance
    7990        53576 :             ViewFac(c(2), c(3), phib, phis, F);
    7991              : 
    7992              :             //       Set up exchange matrix X for calculating direct-to-diffuse properties
    7993              : 
    7994       160728 :             for (int k = 3; k <= 5; k += 2) {
    7995       535760 :                 for (int m = 3; m <= 6; ++m) {
    7996       428608 :                     X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
    7997       428608 :                     X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
    7998              :                 }
    7999              :             }
    8000              : 
    8001       267880 :             for (int k = 1; k <= 4; ++k) {
    8002       214304 :                 ++X(k, k);
    8003              :             }
    8004              : 
    8005        53576 :             indx = 0;
    8006              :             // In the following, note that InvertMatrix changes X
    8007        53576 :             InvertMatrix(state, X, Xinv, indx, 4);
    8008              : 
    8009              :             //       Set up sources for direct-diffuse slat properties
    8010        53576 :             if (std::abs(phis - phib) <= Constant::PiOvr2) { // Beam hits front of slat
    8011        26892 :                 Q(3) = c(4) + c(7);                          // beam-beam trans of slat + beam-diff trans of slat
    8012        26892 :                 Q(4) = c(5) + c(8);                          // front beam-beam refl of slat + front beam-diff refl of slat
    8013              :             } else {                                         // Beam hits back of slat
    8014        26684 :                 Q(3) = c(6) + c(9);                          // back beam-beam refl of slat  + back beam-diff refl of slat
    8015        26684 :                 Q(4) = c(4) + c(7);                          // beam-beam trans of slat + beam-diff trans of slat
    8016              :             }
    8017              : 
    8018              :             //       Correct for fraction of beam that is not directly transmitted; 1 - this fraction is
    8019              :             //       the fraction of the incoming beam that is incident on the front or back surfaces of the slats.
    8020        53576 :             Q(3) *= (1.0 - p(1 + i));
    8021        53576 :             Q(4) *= (1.0 - p(1 + i));
    8022              : 
    8023              :             //       Radiosities (radiance of slat sections)
    8024        53576 :             j(1) = 0.0;
    8025        53576 :             j(2) = 0.0;
    8026       267880 :             for (int k = 3; k <= 6; ++k) {
    8027       214304 :                 j(k) = 0.0;
    8028       642912 :                 for (int m = 3; m <= 4; ++m) {
    8029       428608 :                     j(k) += Xinv(m - 2, k - 2) * Q(m);
    8030              :                 }
    8031              :             }
    8032              : 
    8033              :             //       Irradiance on slat sections
    8034       375032 :             for (int k = 1; k <= 6; ++k) {
    8035       321456 :                 G(k) = 0.0;
    8036      1607280 :                 for (int m = 3; m <= 6; ++m) {
    8037      1285824 :                     G(k) += j(m) * F(k, m);
    8038              :                 }
    8039              :             }
    8040              : 
    8041              :             //       Direct-to-diffuse transmittance
    8042        53576 :             p(5 + i) = G(2) * (1.0 - fEdge);
    8043              : 
    8044              :             //       Direct-to-diffuse reflectance (assuming the edge reflectance is the same as the
    8045              :             //       reflectance of the front side of the slat, C(8))
    8046        53576 :             p(6 + i) = G(1) * (1.0 - fEdge) + fEdge * c(8);
    8047              : 
    8048              :         } // End of loop over front and back side properties of blind
    8049        26788 :     }     // BlindOpticsBeam()
    8050              : 
    8051              :     //********************************************************************************************
    8052              : 
    8053        54300 :     void ViewFac(Real64 const s,    // Slat width (m)
    8054              :                  Real64 const h,    // Distance between faces of adjacent slats (m)
    8055              :                  Real64 const phib, // Elevation angle of normal to slat (radians)
    8056              :                  Real64 const phis, // Profile angle of radiation source (radians)
    8057              :                  Array2A<Real64> F  // View factor array
    8058              :     )
    8059              :     {
    8060              : 
    8061              :         // SUBROUTINE INFORMATION:
    8062              :         //       AUTHOR         Hans Simmler
    8063              :         //       DATE WRITTEN   July-Aug 1995
    8064              :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    8065              :         //                      Apr 2002 (FCW): prevent sqrt of small negative argument
    8066              : 
    8067              :         // PURPOSE OF THIS SUBROUTINE:
    8068              :         //     Calculates the view factors between sections of adjacent slats,
    8069              :         //     where each slat is divided longitudinally into two equal sections whose
    8070              :         //     dimensions depend on source profile angle and slat geometry. The view
    8071              :         //     factors are used in BlindOpticsBeam and BlindOpticsDiffuse to determine blind
    8072              :         //     transmittance and reflectance for short-wave and long-wave radiation.
    8073              : 
    8074              :         // METHODOLOGY EMPLOYED:
    8075              :         //     Uses expressions for view factor between flat strips with a common edge
    8076              :         //     and flat strips displaced from one another. See engineering documentation.
    8077              : 
    8078              :         // REFERENCES:
    8079              :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    8080              :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    8081              : 
    8082              :         // Argument array dimensioning
    8083        54300 :         F.dim(6, 6);
    8084              : 
    8085        54300 :         Array1D<Real64> L(6); // Length of slat sections: L1 = L2 = h; L3, L5 = length
    8086              : 
    8087        54300 :         Real64 h2 = pow_2(h);
    8088        54300 :         Real64 ht = 2.0 * h;
    8089        54300 :         Real64 co = std::cos(phis); // Cosine of source profile angle
    8090        54300 :         if (std::abs(co) < 0.001) co = 0.0;
    8091        54300 :         Real64 w = ht; // Slat geometry variable (m)
    8092        54300 :         if (co != 0.0) w = s * std::cos(phib - phis) / co;
    8093        54300 :         Real64 L3 = s * h / std::abs(w);
    8094        54300 :         if (L3 > s) L3 = s;
    8095        54300 :         Real64 L5 = s - L3;
    8096        54300 :         Real64 a = ht * std::cos(phib); // Intermediate variable (m)
    8097              :         // MAX(0.,...) in the following prevents small negative argument for sqrt
    8098        54300 :         Real64 d1 = std::sqrt(max(0.0, s * s + h2 + a * s)); // Slat geometry variables (m)
    8099        54300 :         Real64 d2 = std::sqrt(max(0.0, s * s + h2 - a * s));
    8100        54300 :         Real64 d3 = std::sqrt(max(0.0, L3 * L3 + h2 + a * L3));
    8101        54300 :         Real64 d4 = std::sqrt(max(0.0, L3 * L3 + h2 - a * L3));
    8102        54300 :         Real64 d5 = std::sqrt(max(0.0, L5 * L5 + h2 - a * L5));
    8103        54300 :         Real64 d6 = std::sqrt(max(0.0, L5 * L5 + h2 + a * L5));
    8104       380100 :         for (int i = 1; i <= 6; ++i) {
    8105       325800 :             F(i, i) = 0.0;
    8106              :         }
    8107        54300 :         F(1, 1) = 0.0;
    8108        54300 :         F(2, 1) = (d1 + d2 - 2.0 * s) / ht;
    8109        54300 :         F(3, 1) = (h + L3 - d3) / ht;
    8110        54300 :         F(4, 1) = (h + L3 - d4) / ht;
    8111        54300 :         F(5, 1) = (L5 + d3 - d1) / ht;
    8112        54300 :         F(6, 1) = (L5 + d4 - d2) / ht;
    8113        54300 :         F(3, 2) = (L3 + d5 - d2) / ht;
    8114        54300 :         F(4, 2) = (L3 + d6 - d1) / ht;
    8115        54300 :         F(5, 2) = (h + L5 - d5) / ht;
    8116        54300 :         F(6, 2) = (h + L5 - d6) / ht;
    8117        54300 :         F(4, 3) = (d3 + d4 - ht) / (2.0 * L3);
    8118        54300 :         F(5, 3) = 0.0;
    8119        54300 :         F(6, 3) = (d2 + h - d4 - d5) / (2.0 * L3);
    8120        54300 :         F(5, 4) = (d1 + h - d3 - d6) / (2.0 * L3);
    8121        54300 :         F(6, 4) = 0.0;
    8122        54300 :         F(6, 5) = 0.0;
    8123        54300 :         if (L5 > 0.0) F(6, 5) = (d5 + d6 - ht) / (2.0 * L5);
    8124        54300 :         L(1) = h;
    8125        54300 :         L(2) = h;
    8126        54300 :         L(3) = L3;
    8127        54300 :         L(4) = L3; // L4, L6 = length of lower slat
    8128        54300 :         L(5) = L5;
    8129        54300 :         L(6) = L5;
    8130       325800 :         for (int i = 2; i <= 6; ++i) {
    8131      1086000 :             for (int j = 1; j <= i - 1; ++j) {
    8132       814500 :                 F(j, i) = 0.0;
    8133       814500 :                 if (L(i) > 0.0) F(j, i) = F(i, j) * L(j) / L(i);
    8134              :             }
    8135              :         }
    8136        54300 :     } // ViewFac()
    8137              : 
    8138              :     //*****************************************************************************************
    8139              : 
    8140        54662 :     void InvertMatrix(EnergyPlusData &state,
    8141              :                       Array2D<Real64> &a, // Matrix to be inverted
    8142              :                       Array2D<Real64> &y, // Inverse of matrix a
    8143              :                       Array1D_int &indx,  // Index vector for LU decomposition
    8144              :                       int const n)
    8145              :     {
    8146              : 
    8147              :         // SUBROUTINE INFORMATION:
    8148              :         //       AUTHOR         Hans Simmler
    8149              :         //       DATE WRITTEN   July-Aug 1995
    8150              :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    8151              : 
    8152              :         // PURPOSE OF THIS SUBROUTINE:
    8153              :         //     Inverts a matrix.
    8154              : 
    8155              :         // METHODOLOGY EMPLOYED:
    8156              :         //     Uses LU decomposition.
    8157              : 
    8158        54662 :         Array1D<Real64> tmp(n);
    8159              : 
    8160              :         int d;
    8161              : 
    8162        54662 :         y = 0.0;
    8163       273310 :         for (int i = 1; i <= n; ++i) {
    8164       218648 :             y(i, i) = 1.0;
    8165              :         }
    8166        54662 :         indx = 0;
    8167              : 
    8168        54662 :         LUdecomposition(state, a, n, indx, d);
    8169              : 
    8170       273310 :         for (int j = 1; j <= n; ++j) {
    8171       218648 :             tmp = 0.0;
    8172       218648 :             tmp(j) = 1;
    8173       218648 :             LUsolution(state, a, n, indx, tmp);
    8174      1093240 :             for (int i = 1; i <= n; ++i)
    8175       874592 :                 y(j, i) = tmp(i);
    8176              :         }
    8177        54662 :     } // InvertMatrix()
    8178              : 
    8179              :     // added for custom solar or visible spectrum
    8180              : 
    8181          111 :     void CheckAndReadCustomSprectrumData(EnergyPlusData &state)
    8182              :     {
    8183              : 
    8184              :         // SUBROUTINE INFORMATION:
    8185              :         //       AUTHOR         T. Hong
    8186              :         //       DATE WRITTEN   August 2013
    8187              : 
    8188              :         // PURPOSE OF THIS SUBROUTINE:
    8189              :         // Check, read, and assign the custom solar or visible spectrum to:
    8190              :         //  solar: nume, wle(nume), e(nume). nume = 107
    8191              :         //  visible: numt3, wlt3(numt3), y30(numt3). numt3 = 81
    8192              :         // Three related IDD objects:
    8193              :         //  EnergyManagementSystem:ConstructionIndexVariable
    8194              :         //  Site:SolarAndVisibleSpectrum, Site:SpectrumData
    8195              : 
    8196              :         // METHODOLOGY EMPLOYED:
    8197              :         // Overwriting the default values
    8198              : 
    8199              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8200          111 :         bool ErrorsFound(false); // If errors detected in input
    8201              :         int NumAlphas;           // Number of Alphas for each GetobjectItem call
    8202              :         int NumNumbers;          // Number of Numbers for each GetobjectItem call
    8203              :         int NumArgs;
    8204          111 :         Array1D_string cAlphaArgs;    // Alpha input items for object
    8205          111 :         Array1D<Real64> rNumericArgs; // Numeric input items for object
    8206              : 
    8207          111 :         auto const &wm = state.dataWindowManager;
    8208              : 
    8209          111 :         if (wm->RunMeOnceFlag) return;
    8210              : 
    8211              :         // Step 1 - check whether there is custom solar or visible spectrum
    8212          111 :         std::string cCurrentModuleObject = "Site:SolarAndVisibleSpectrum";
    8213          111 :         int NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    8214              : 
    8215              :         // no custom spectrum data, done!
    8216          111 :         if (NumSiteSpectrum == 0) {
    8217          111 :             wm->RunMeOnceFlag = true;
    8218          111 :             return;
    8219              :         }
    8220              : 
    8221              :         // read custom spectrum data from Site:SolarAndVisibleSpectrum
    8222            0 :         if (NumSiteSpectrum > 1) { // throw error
    8223            0 :             ShowSevereError(state, format("Only one {} object is allowed", cCurrentModuleObject));
    8224            0 :             ErrorsFound = true;
    8225              :         }
    8226              : 
    8227            0 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
    8228            0 :         cAlphaArgs.allocate(NumAlphas);
    8229            0 :         rNumericArgs.dimension(NumNumbers, 0.0);
    8230              : 
    8231            0 :         if (NumSiteSpectrum == 1) {
    8232              :             int IOStatus;
    8233            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8234              :                                                                      cCurrentModuleObject,
    8235              :                                                                      1,
    8236            0 :                                                                      state.dataIPShortCut->cAlphaArgs,
    8237              :                                                                      NumAlphas,
    8238            0 :                                                                      state.dataIPShortCut->rNumericArgs,
    8239              :                                                                      NumNumbers,
    8240              :                                                                      IOStatus);
    8241              : 
    8242              :             // use default spectrum data, done!
    8243            0 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "Default")) {
    8244            0 :                 wm->RunMeOnceFlag = true;
    8245            0 :                 return;
    8246              :             }
    8247              : 
    8248              :             // now read custom solar and visible spectrum data
    8249            0 :             std::string cSolarSpectrum = state.dataIPShortCut->cAlphaArgs(3);
    8250            0 :             std::string cVisibleSpectrum = state.dataIPShortCut->cAlphaArgs(4);
    8251              : 
    8252            0 :             cCurrentModuleObject = "Site:SpectrumData";
    8253            0 :             NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    8254            0 :             if (NumSiteSpectrum == 0) { // throw error
    8255            0 :                 ShowSevereError(state, format("No {} object is found", cCurrentModuleObject));
    8256            0 :                 ErrorsFound = true;
    8257              :             }
    8258              : 
    8259            0 :             cAlphaArgs.deallocate();
    8260            0 :             rNumericArgs.deallocate();
    8261              : 
    8262            0 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
    8263            0 :             cAlphaArgs.allocate(NumAlphas);
    8264            0 :             rNumericArgs.dimension(NumNumbers, 0.0);
    8265              : 
    8266            0 :             int iSolarSpectrum = 0;
    8267            0 :             int iVisibleSpectrum = 0;
    8268            0 :             for (int Loop = 1; Loop <= NumSiteSpectrum; ++Loop) {
    8269              :                 // Step 2 - read user-defined spectrum data
    8270            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8271              :                                                                          cCurrentModuleObject,
    8272              :                                                                          Loop,
    8273            0 :                                                                          state.dataIPShortCut->cAlphaArgs,
    8274              :                                                                          NumAlphas,
    8275            0 :                                                                          state.dataIPShortCut->rNumericArgs,
    8276              :                                                                          NumNumbers,
    8277              :                                                                          IOStatus);
    8278            0 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cSolarSpectrum)) {
    8279            0 :                     iSolarSpectrum = Loop;
    8280              :                     // overwrite the default solar spectrum
    8281            0 :                     if (NumNumbers > 2 * nume) {
    8282            0 :                         ShowSevereError(
    8283              :                             state,
    8284            0 :                             format("Solar spectrum data pair is more than 107 - {} - {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    8285            0 :                         ErrorsFound = true;
    8286              :                     } else {
    8287              :                         // Step 3 - overwrite default solar spectrum data
    8288            0 :                         for (int iTmp = 1; iTmp <= nume; ++iTmp) {
    8289            0 :                             if (iTmp <= NumNumbers / 2) {
    8290            0 :                                 wm->wle[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
    8291            0 :                                 wm->e[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
    8292              :                             } else {
    8293            0 :                                 wm->wle[iTmp - 1] = 0.0;
    8294            0 :                                 wm->e[iTmp - 1] = 0.0;
    8295              :                             }
    8296              :                         }
    8297              :                     }
    8298              :                 }
    8299            0 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cVisibleSpectrum)) {
    8300            0 :                     iVisibleSpectrum = Loop;
    8301              :                     // overwrite the default solar spectrum
    8302            0 :                     if (NumNumbers > 2 * numt3) {
    8303            0 :                         ShowSevereError(state,
    8304            0 :                                         format("Visible spectrum data pair is more than 81 - {} - {}",
    8305              :                                                cCurrentModuleObject,
    8306            0 :                                                state.dataIPShortCut->cAlphaArgs(1)));
    8307            0 :                         ErrorsFound = true;
    8308              :                     } else {
    8309              :                         // Step 3 - overwrite default visible spectrum data
    8310            0 :                         for (int iTmp = 1; iTmp <= numt3; ++iTmp) {
    8311            0 :                             if (iTmp <= NumNumbers / 2) {
    8312            0 :                                 wm->wlt3[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
    8313            0 :                                 wm->y30[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
    8314              :                             } else {
    8315            0 :                                 wm->wlt3[iTmp - 1] = 0.0;
    8316            0 :                                 wm->y30[iTmp - 1] = 0.0;
    8317              :                             }
    8318              :                         }
    8319              :                     }
    8320              :                 }
    8321            0 :                 if ((iSolarSpectrum > 0) && (iVisibleSpectrum > 0)) break;
    8322              :             }
    8323            0 :         }
    8324              : 
    8325            0 :         cAlphaArgs.deallocate();
    8326            0 :         rNumericArgs.deallocate();
    8327              : 
    8328            0 :         if (ErrorsFound) {
    8329            0 :             ShowFatalError(state, "Errors found in processing input for user-defined solar/visible spectrum");
    8330              :         }
    8331              : 
    8332            0 :         wm->RunMeOnceFlag = true;
    8333          333 :     } // CheckAndReadCustomSpectrumData()
    8334              : 
    8335              :     //*****************************************************************************************
    8336              : 
    8337          211 :     void initWindowModel(EnergyPlusData &state)
    8338              :     {
    8339          211 :         const std::string objectName = "WindowsCalculationEngine";
    8340          211 :         auto const &wm = state.dataWindowManager;
    8341          211 :         wm->inExtWindowModel = CWindowModel::WindowModelFactory(state, objectName);
    8342          211 :         wm->winOpticalModel = CWindowOpticalModel::WindowOpticalModelFactory(state);
    8343          211 :     } // InitWindowModel()
    8344              : 
    8345              :     //*****************************************************************************************
    8346              : 
    8347              : } // namespace Window
    8348              : 
    8349              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1