LCOV - code coverage report
Current view: top level - EnergyPlus - WindowManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 3819 4272 89.4 %
Date: 2024-08-24 18:31:18 Functions: 51 53 96.2 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <algorithm>
      50             : #include <cassert>
      51             : #include <cmath>
      52             : #include <memory>
      53             : #include <string>
      54             : 
      55             : // ObjexxFCL Headers
      56             : #include <ObjexxFCL/Array.functions.hh>
      57             : #include <ObjexxFCL/Fmath.hh>
      58             : 
      59             : // EnergyPlus Headers
      60             : #include <EnergyPlus/Construction.hh>
      61             : #include <EnergyPlus/ConvectionCoefficients.hh>
      62             : #include <EnergyPlus/CurveManager.hh>
      63             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      64             : #include <EnergyPlus/DataBSDFWindow.hh>
      65             : #include <EnergyPlus/DataEnvironment.hh>
      66             : #include <EnergyPlus/DataHeatBalSurface.hh>
      67             : #include <EnergyPlus/DataHeatBalance.hh>
      68             : #include <EnergyPlus/DataIPShortCuts.hh>
      69             : #include <EnergyPlus/DataLoopNode.hh>
      70             : #include <EnergyPlus/DataSurfaces.hh>
      71             : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
      72             : #include <EnergyPlus/DataZoneEquipment.hh>
      73             : #include <EnergyPlus/General.hh>
      74             : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
      75             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      76             : #include <EnergyPlus/Material.hh>
      77             : #include <EnergyPlus/Psychrometrics.hh>
      78             : #include <EnergyPlus/ScheduleManager.hh>
      79             : #include <EnergyPlus/UtilityRoutines.hh>
      80             : #include <EnergyPlus/WindowComplexManager.hh>
      81             : #include <EnergyPlus/WindowEquivalentLayer.hh>
      82             : #include <EnergyPlus/WindowManager.hh>
      83             : #include <EnergyPlus/WindowManagerExteriorOptical.hh>
      84             : #include <EnergyPlus/WindowManagerExteriorThermal.hh>
      85             : #include <EnergyPlus/WindowModel.hh>
      86             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      87             : 
      88             : namespace EnergyPlus {
      89             : 
      90             : namespace Window {
      91             : 
      92             :     // MODULE INFORMATION
      93             :     //       AUTHOR         Fred Winkelmann
      94             :     //       DATE WRITTEN   September 1999
      95             :     //       MODIFIED       August 2001 (FW): add window shade thermal calculation;
      96             :     //                                        add window blind optical and thermal model.
      97             :     //                      February 2003 (FW/LKL): Name changed to WindowManager
      98             :     //       RE-ENGINEERED  na
      99             : 
     100             :     // PURPOSE OF THIS MODULE:
     101             :     // Manages the window optical and thermal calculations derived
     102             :     // from WINDOW 4 and WINDOW 5.
     103             : 
     104             :     // METHODOLOGY EMPLOYED:
     105             : 
     106             :     // REFERENCES:
     107             :     // WINDOW 4:
     108             :     // D.Arasteh, M.Reilly and M.Rubin. A versative procedure for
     109             :     // calculating heat transfer through windows. ASHRAE Trans. 1989, Vol. 95, Pt. 2.
     110             : 
     111             :     // E.Finlayson, D.Arasteh, C.Huizenga, M.Rubin, and M.Reilly. WINDOW 4.0:
     112             :     // Documentation of calculation procedures. LBL-33943. July 1993.
     113             : 
     114             :     // WINDOW 5:
     115             :     // ASHRAE Standard 142P (draft 1/13/98): Standard method for determining and expressing
     116             :     // the heat transfer and total optical properties of fenestration products.
     117             : 
     118             :     // Shade and blind thermal model:
     119             :     // ISO/DIS 15099, Thermal Performance of Windows, Doors and Shading Devices,
     120             :     // Detailed Calculations, 1/12/00.
     121             : 
     122             :     // Blind optical model:
     123             :     // H. Simmler, U. Fischer and Frederick Winkelmann, Solar-Thermal Window Blind Model
     124             :     // for DOE-2, Lawrence Berkeley National Laboratory, Jan. 1996.
     125             : 
     126             :     // Using/Aliasing
     127             :     using namespace DataEnvironment;
     128             :     using namespace DataHeatBalance;
     129             :     using namespace DataSurfaces;
     130             : 
     131             :     // SUBROUTINE SPECIFICATIONS FOR MODULE WindowManager:
     132             :     //   Optical Calculation Routines
     133             :     //   Heat Balance Routines
     134             : 
     135         796 :     void InitWindowOpticalCalculations(EnergyPlusData &state)
     136             :     {
     137             :         // SUBROUTINE INFORMATION:
     138             :         //       AUTHOR         Simon Vidanovic
     139             :         //       DATE WRITTEN   September 2016
     140             :         //       MODIFIED       na
     141             :         //       RE-ENGINEERED  na
     142             : 
     143             :         // PURPOSE OF THIS SUBROUTINE:
     144             :         // Manages if optical calculation will be performed with internal or external routines
     145             : 
     146             :         // check and read custom solar and/or visible spectrum data if any
     147         796 :         CheckAndReadCustomSprectrumData(state);
     148             : 
     149             :         // allocate surface level adj ratio data member
     150         796 :         state.dataHeatBalSurf->SurfWinCoeffAdjRatio.dimension(state.dataSurface->TotSurfaces, 1.0);
     151             : 
     152         796 :         if (state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) {
     153           3 :             InitWCE_SimplifiedOpticalData(state);
     154             :         } else {
     155         793 :             InitGlassOpticalCalculations(state);
     156             :         }
     157         796 :     }
     158             : 
     159         793 :     void InitGlassOpticalCalculations(EnergyPlusData &state)
     160             :     {
     161             : 
     162             :         // SUBROUTINE INFORMATION:
     163             :         //       AUTHOR         F. Winkelmann
     164             :         //       DATE WRITTEN   August 1999
     165             :         //       MODIFIED       May 2001 (FW): add window blinds
     166             :         //                      Jan 2002 (FW): add blinds with variable slat angle
     167             :         //                      Jan 2003 (FW): add between-glass shade/blind
     168             :         //                      May 2006 (RR): add exterior window screen
     169             :         //                      Aug 2010 (TH): allow spectral data for between-glass shade/blind
     170             :         //                      Aug 2013 (TH): allow user defined solar and visible spectrum data
     171             :         //       RE-ENGINEERED  na
     172             : 
     173             :         // PURPOSE OF THIS SUBROUTINE:
     174             :         // Manages the calculation of the solar and visible properties of a multi-layer glazing
     175             :         // system from the properties of the individual glazing and shading layers
     176             : 
     177             :         // Using/Aliasing
     178             :         using namespace Vectors;
     179             : 
     180             :         using WindowEquivalentLayer::InitEquivalentLayerWindowCalculations;
     181             : 
     182             :         int CoefNum;                    // Polynomial coefficient number
     183             :         int j;                          // Wavelength counter
     184             :         int TotLay;                     // Total solid and gas layers in a window construction
     185             :         int ConstrNum;                  // Construction number
     186             :         int ConstrNumSh;                // Shaded construction number
     187             :         int ShadeLayNum;                // Layer number for shade or blind, if present
     188             :         int ShadeLayPtr;                // Material number for shade or blind
     189             :         bool lquasi;                    // True if one or more glass layers have no spectral data
     190             :         bool AllGlassIsSpectralAverage; // True if all glazing in a construction is spectral average
     191             :         bool IntShade;                  // True if construction has an interior,exterior or between-glass shade
     192             :         bool ExtShade;
     193             :         bool BGShade;
     194             :         bool IntBlind; // True if construction has an interior,exterior or between-glass blind
     195             :         bool ExtBlind;
     196             :         bool BGBlind;
     197             :         bool ExtScreen; // True if construction has an exterior screen
     198             :         bool ScreenOn;  // True if construction has an exterior screen
     199             :         bool BlindOn;   // True if IntBlind, ExtBlind or BGBlind is true
     200             :         bool ShadeOn;   // True if IntShade, ExtShade or BGShade is true
     201             :         int BlNum;      // Blind number
     202             : 
     203         793 :         auto &wm = state.dataWindowManager;
     204         793 :         Array1D<Real64> sabsPhi(nume); // Glazing system absorptance for a glass layer
     205             :         //  and angle of incidence, for each wavelength
     206             :         //   glass layer for an angle of incidence, for each wavelength
     207             :         // Glazing system layer solar absorptance for each glass layer
     208         793 :         Array1D<Real64> solabsDiff(maxGlassLayers);
     209             :         // Glazing system solar absorptance for a layer at each incidence angle
     210         793 :         Array1D<Real64> solabsPhiLay(maxIncidentAngles);
     211             :         // Glazing system solar transmittance from fit at each incidence angle
     212         793 :         Array1D<Real64> tsolPhiFit(maxIncidentAngles);
     213             :         // Glazing system visible transmittance from fit at each incidence angle
     214         793 :         Array1D<Real64> tvisPhiFit(maxIncidentAngles);
     215             :         // Isolated glass solar transmittance for each incidence angle
     216        1586 :         Array2D<Real64> tBareSolPhi(maxGlassLayers, maxIncidentAngles);
     217             :         Real64 t1; // = tBareSolPhi(,1)(,2)
     218             :         Real64 t2;
     219             :         // Isolated glass visible transmittance for each incidence angle
     220        1586 :         Array2D<Real64> tBareVisPhi(maxGlassLayers, maxIncidentAngles);
     221             :         Real64 t1v; // = tBareVisPhi(,1)(,2)
     222             :         Real64 t2v;
     223             :         // Isolated glass front solar reflectance for each incidence angle
     224        1586 :         Array2D<Real64> rfBareSolPhi(maxGlassLayers, maxIncidentAngles);
     225             :         // Isolated glass front visible reflectance for each incidence angle
     226        1586 :         Array2D<Real64> rfBareVisPhi(maxGlassLayers, maxIncidentAngles);
     227             :         // Isolated glass back solar reflectance for each incidence angle
     228        1586 :         Array2D<Real64> rbBareSolPhi(maxGlassLayers, maxIncidentAngles);
     229             :         // Isolated glass back visible reflectance for each incidence angle
     230        1586 :         Array2D<Real64> rbBareVisPhi(maxGlassLayers, maxIncidentAngles);
     231             :         // Isolated glass front solar absorptance for each incidence angle
     232        1586 :         Array2D<Real64> afBareSolPhi(maxGlassLayers, maxIncidentAngles);
     233             :         Real64 af1; // = afBareSolPhi(,1)(,2)
     234             :         Real64 af2;
     235             :         Real64 rbmf2; // Isolated glass #2 front beam reflectance
     236             :         // Isolated glass back solar absorptance for each incidence angle
     237        1586 :         Array2D<Real64> abBareSolPhi(maxGlassLayers, maxIncidentAngles);
     238             :         // Glazing system solar absorptance for each angle of incidence
     239        1586 :         Array2D<Real64> solabsPhi(maxGlassLayers, maxIncidentAngles);
     240             :         // Glazing system back solar absorptance for each angle of incidence
     241        1586 :         Array2D<Real64> solabsBackPhi(maxGlassLayers, maxIncidentAngles);
     242             :         // Glazing system interior shade solar absorptance for each angle of incidence
     243         793 :         Array1D<Real64> solabsShadePhi(maxIncidentAngles);
     244             : 
     245             :         // These need to stay as Array1D for a little longer because changing them spreads into many source files
     246         793 :         Array1D<Real64> tsolPhi(maxIncidentAngles);        // Glazing system solar transmittance for each angle of incidence
     247         793 :         Array1D<Real64> rfsolPhi(maxIncidentAngles);       // Glazing system solar front reflectance for each angle of incidence
     248         793 :         Array1D<Real64> rbsolPhi(maxIncidentAngles);       // Glazing system solar back reflectance for each angle of incidence
     249         793 :         Array1D<Real64> tvisPhi(maxIncidentAngles);        // Glazing system visible transmittance for each angle of incidence
     250         793 :         Array1D<Real64> rfvisPhi(maxIncidentAngles);       // Glazing system visible front reflectance for each angle of incidence
     251         793 :         Array1D<Real64> rbvisPhi(maxIncidentAngles);       // Glazing system visible back reflectance for each angle of incidence
     252         793 :         Array1D<Real64> CosPhiIndepVar(maxIncidentAngles); // Cos of incidence angles at 10-deg increments for curve fits
     253             : 
     254             :         Real64 ab1; // = abBareSolPhi(,1)(,2)
     255             :         Real64 ab2;
     256             :         Real64 td1; // Isolated glass diffuse solar transmittance
     257             :         Real64 td2;
     258             :         Real64 td3;
     259             :         Real64 td1v; // Isolated glass diffuse visible transmittance
     260             :         Real64 td2v;
     261             :         Real64 td3v;
     262             :         Real64 rf1; // Isolated glass diffuse solar front reflectance
     263             :         Real64 rf2;
     264             :         Real64 rf3;
     265             :         Real64 rf1v; // Isolated glass diffuse visible front reflectance
     266             :         Real64 rf2v;
     267             :         Real64 rf3v;
     268             :         Real64 rb1; // Isolated glass diffuse solar back reflectance
     269             :         Real64 rb2;
     270             :         Real64 rb3;
     271             :         Real64 rb1v; // Isolated glass diffuse visible back reflectance
     272             :         Real64 rb2v;
     273             :         Real64 rb3v;
     274             :         Real64 afd1; // Isolated glass diffuse solar front absorptance
     275             :         Real64 afd2;
     276             :         Real64 afd3;
     277             :         Real64 abd1; // Isolated glass diffuse solar back absorptance
     278             :         Real64 abd2;
     279             :         Real64 abd3;
     280             :         Real64 TauShIR;  // IR transmittance of isolated shade
     281             :         Real64 EpsShIR;  // IR absorptance of isolated shade
     282             :         Real64 RhoShIR;  // IR reflectance of isolated shade
     283             :         Real64 EpsGlIR;  // IR absorptance of front or back of isolated glass
     284             :         Real64 RhoGlIR;  // IR reflectance of inside face of inside glass
     285             :         int NGlass;      // Number of glass layers in a construction
     286             :         int LayNum;      // Layer number for a glass layer
     287             :         int LayPtr;      // Material number corresponding to LayNum
     288             :         Real64 Phi;      // Incidence angle (deg)
     289             :         Real64 CosPhi;   // Cosine of incidence angle
     290             :         int ILam;        // Wavelength counter
     291             :         Real64 tsolDiff; // Glazing system diffuse solar transmittance
     292             :         Real64 tvisDiff; // Glazing system diffuse visible transmittance
     293             :         int IGlassBack;  // Glass layer number counted from back of window
     294             :         Real64 ShadeAbs; // Solar absorptance of isolated shade
     295             :         Real64 ash;      // = ShadeAbs
     296             :         Real64 afsh;     // Diffuse solar front absorptance of isolated blind
     297             :         Real64 afshGnd;  // Ground and sky diffuse solar front absorptance of isolated blind
     298             :         Real64 afshSky;
     299             :         Real64 absh;          // Diffuse solar back absorptance of isolated blind
     300             :         Real64 ShadeTrans;    // Solar transmittance of isolated shade/blind
     301             :         Real64 ShadeTransGnd; // Diffuse-diffuse transmittance of isolated vertical blind with
     302             :         // horizontal slats for isotropic ground solar
     303             :         Real64 ShadeTransSky; // Diffuse-diffuse transmittance of isolated vertical blind with
     304             :         // horizontal slats for isotropic sky solar
     305             :         Real64 tsh;    // = ShadeTrans
     306             :         Real64 tshGnd; // = ShadeTransGnd,ShadeTransSky
     307             :         Real64 tshSky;
     308             :         Real64 tsh2;         // = tsh**2
     309             :         Real64 ShadeRefl;    // Solar reflectance of isolated shade
     310             :         Real64 ShadeReflGnd; // Front blind reflectance for ground diffuse solar
     311             :         Real64 ShadeReflSky; // Front blind reflectance for sky diffuse solar
     312             :         Real64 rsh;          // = ShadeRefl
     313             :         Real64 rfsh;         // Diffuse solar front reflectance of isolated blind
     314             :         Real64 rfshGnd;      // Ground and sky diffuse solar front reflectance of isolated blind
     315             :         Real64 rfshSky;
     316             :         Real64 rbsh;            // Diffuse solar back reflectance of isolated blind
     317             :         Real64 ShadeReflFac;    // Shade/blind solar reflection factor
     318             :         Real64 ShadeTransVis;   // Visible transmittance of isolated shade/blind
     319             :         Real64 tshv;            // = ShadeTransVis
     320             :         Real64 tshv2;           // = tshv**2
     321             :         Real64 ShadeReflVis;    // Visible reflectance of isolated shade
     322             :         Real64 rshv;            // = ShadeReflVis
     323             :         Real64 rfshv;           // Diffuse visible front reflectance of isolated blind
     324             :         Real64 rbshv;           // Diffuse visible back reflectance of isolated blind
     325             :         Real64 ShadeReflFacVis; // Shade/blind visible reflection factor
     326             :         int SpecDataNum;        // Spectral data set number
     327             :         int numptDAT;           // Number of wavelengths in a spectral data set
     328             :         bool StormWinConst;     // True if a construction with a storm window
     329             :         bool Triangle;          // True if window is triangular
     330             :         bool Rectangle;         // True if window is rectangular
     331         793 :         Vector3<Real64> W1;     // Window vertices (m)
     332         793 :         Vector3<Real64> W2;
     333         793 :         Vector3<Real64> W3;
     334         793 :         Vector3<Real64> W21; // W1-W2, W3-W2, resp. (m)
     335         793 :         Vector3<Real64> W23;
     336             : 
     337             :         // Spectral data wavelengths for each glass layer in a glazing system
     338         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> wlt = {0.0};
     339             : 
     340             :         // Following data, Spectral data for each layer for each wavelength in wlt
     341         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> t = {0.0};     // normal transmittance
     342         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rff = {0.0};   // normal front reflectance
     343         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbb = {0.0};   // normal back reflectance
     344         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tPhi = {0.0};  // transmittance at angle of incidence
     345         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfPhi = {0.0}; // front reflectance at angle of incidence
     346         793 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbPhi = {0.0}; // back reflectance at angle of incidence
     347             : 
     348             :         // Number of spectral data wavelengths for each layer; =2 if no spectra data for a layer
     349         793 :         std::array<int, maxGlassLayers> numpt = {0};
     350             : 
     351         793 :         W5InitGlassParameters(state);
     352             : 
     353             :         // Calculate optical properties of blind-type layers entered with MATERIAL:WindowBlind
     354         793 :         if (state.dataHeatBal->TotBlinds > 0) CalcWindowBlindProperties(state);
     355             : 
     356             :         // Initialize SurfaceScreen structure
     357         793 :         if (state.dataHeatBal->NumScreens > 0) CalcWindowScreenProperties(state);
     358             : 
     359             :         // Get glazing system optical properties of constructions with glass or glass plus
     360             :         //   shade, screen or blind
     361             :         // Loop over constructions and find those that are glazing constructions
     362        6820 :         for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
     363        6027 :             auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
     364        6043 :             if (!thisConstruct.TypeIsWindow) continue;
     365        1364 :             if (thisConstruct.WindowTypeBSDF) continue; // Skip Complex Fenestrations, they have separate
     366        1351 :             if (thisConstruct.WindowTypeEQL) continue;  // skip Equivalent Layer Fenestration
     367             :             // handling of optical properties
     368             : 
     369       14828 :             for (int IPhi = 1; IPhi <= 10; ++IPhi) {
     370       13480 :                 CosPhiIndepVar(IPhi) = std::cos((IPhi - 1) * 10.0 * Constant::DegToRadians);
     371             :             }
     372             : 
     373        1348 :             TotLay = thisConstruct.TotLayers;
     374             : 
     375        1348 :             auto const *mat = state.dataMaterial->Material(thisConstruct.LayerPoint(1));
     376             : 
     377             :             // First layer must be glass, shade, screen or blind to be a glazing construction
     378        1348 :             if (mat->group != Material::Group::WindowGlass && mat->group != Material::Group::Shade && mat->group != Material::Group::Screen &&
     379         134 :                 mat->group != Material::Group::WindowBlind && mat->group != Material::Group::WindowSimpleGlazing)
     380           0 :                 continue;
     381             : 
     382        1348 :             ShadeLayNum = 0;
     383        1348 :             ExtShade = false;
     384        1348 :             IntShade = false;
     385        1348 :             BGShade = false;
     386        1348 :             ExtBlind = false;
     387        1348 :             IntBlind = false;
     388        1348 :             BGBlind = false;
     389        1348 :             ExtScreen = false;
     390        1348 :             StormWinConst = false;
     391        1348 :             wm->lSimpleGlazingSystem = false;
     392             : 
     393        1348 :             if (mat->group == Material::Group::WindowSimpleGlazing) {
     394         132 :                 auto const *matWin = dynamic_cast<Material::MaterialChild const *>(mat);
     395         132 :                 assert(matWin != nullptr);
     396             : 
     397             :                 // what if outside layer is shade, blind, or screen?
     398         132 :                 wm->lSimpleGlazingSystem = true;
     399         132 :                 wm->SimpleGlazingSHGC = matWin->SimpleWindowSHGC;
     400         132 :                 wm->SimpleGlazingU = matWin->SimpleWindowUfactor;
     401             :             }
     402             : 
     403        1348 :             if (has_prefix(thisConstruct.Name, "BARECONSTRUCTIONWITHSTORMWIN") || has_prefix(thisConstruct.Name, "SHADEDCONSTRUCTIONWITHSTORMWIN"))
     404           1 :                 StormWinConst = true;
     405             : 
     406             :             // Get layer number of shade/blind
     407        1348 :             if (mat->group == Material::Group::Shade) {
     408           3 :                 ExtShade = true;
     409           3 :                 ShadeLayNum = 1;
     410        1345 :             } else if (state.dataMaterial->Material(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Shade) {
     411          24 :                 IntShade = true;
     412          24 :                 ShadeLayNum = TotLay;
     413        1321 :             } else if (thisConstruct.TotLayers == 5) {
     414          68 :                 if (state.dataMaterial->Material(thisConstruct.LayerPoint(3))->group == Material::Group::Shade) {
     415           1 :                     BGShade = true;
     416           1 :                     ShadeLayNum = 3;
     417             :                 }
     418        1253 :             } else if (thisConstruct.TotLayers == 7) {
     419           8 :                 if (state.dataMaterial->Material(thisConstruct.LayerPoint(5))->group == Material::Group::Shade) {
     420           1 :                     BGShade = true;
     421           1 :                     ShadeLayNum = 5;
     422             :                 }
     423             :             }
     424             : 
     425        1348 :             if (mat->group == Material::Group::WindowBlind) {
     426           2 :                 ExtBlind = true;
     427           2 :                 ShadeLayNum = 1;
     428           2 :                 BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
     429        1346 :             } else if (state.dataMaterial->Material(thisConstruct.LayerPoint(TotLay))->group == Material::Group::WindowBlind) {
     430          12 :                 IntBlind = true;
     431          12 :                 ShadeLayNum = TotLay;
     432          12 :                 BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
     433        1334 :             } else if (thisConstruct.TotLayers == 5) {
     434          68 :                 if (state.dataMaterial->Material(thisConstruct.LayerPoint(3))->group == Material::Group::WindowBlind) {
     435           2 :                     BGBlind = true;
     436           2 :                     ShadeLayNum = 3;
     437           2 :                     BlNum =
     438           2 :                         dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
     439             :                 }
     440        1266 :             } else if (thisConstruct.TotLayers == 7) {
     441           8 :                 if (state.dataMaterial->Material(thisConstruct.LayerPoint(5))->group == Material::Group::WindowBlind) {
     442           1 :                     BGBlind = true;
     443           1 :                     ShadeLayNum = 5;
     444           1 :                     BlNum =
     445           1 :                         dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
     446             :                 }
     447             :             }
     448             : 
     449        1348 :             if (mat->group == Material::Group::Screen) {
     450           2 :                 ShadeLayNum = 1;
     451           2 :                 ExtScreen = true;
     452             :             }
     453             : 
     454        1348 :             ScreenOn = ExtScreen;
     455        1348 :             BlindOn = IntBlind || ExtBlind || BGBlind;
     456        1348 :             ShadeOn = IntShade || ExtShade || BGShade;
     457        1348 :             wm->BGFlag = BGBlind || BGShade;
     458             : 
     459             :             // For construction with interior or exterior shade, get shade thermal absorptance (emissivity)
     460             :             // (accounting for inter-reflection with glazing) and correct the inside glass InsideAbsorpThermal
     461             :             // for presence of interior shade. Assumes inner and outer glass layers have zero thermal transmittance.
     462             : 
     463        1348 :             if (IntShade || ExtShade || ExtScreen) {
     464          29 :                 ShadeLayPtr = thisConstruct.LayerPoint(ShadeLayNum);
     465          29 :                 auto const *matShade = state.dataMaterial->Material(ShadeLayPtr);
     466          29 :                 if (ExtScreen) {
     467           2 :                     auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
     468           2 :                     assert(matScreen != nullptr);
     469           2 :                     TauShIR = matScreen->DfTrans;
     470             :                 } else {
     471          27 :                     TauShIR = matShade->TransThermal;
     472             :                 }
     473          29 :                 EpsShIR = matShade->AbsorpThermal;
     474          29 :                 RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
     475          29 :                 if (ExtShade || ExtScreen) { // Exterior shade or screen
     476           5 :                     EpsGlIR = state.dataMaterial->Material(thisConstruct.LayerPoint(2))->AbsorpThermalFront;
     477             :                 } else { // Interior shade
     478          24 :                     EpsGlIR = state.dataMaterial->Material(thisConstruct.LayerPoint(TotLay - 1))->AbsorpThermalBack;
     479             :                 }
     480          29 :                 RhoGlIR = max(0.0, 1.0 - EpsGlIR);
     481          29 :                 thisConstruct.ShadeAbsorpThermal = EpsShIR * (1.0 + TauShIR * RhoGlIR / (1.0 - RhoShIR * RhoGlIR));
     482          29 :                 if (IntShade) thisConstruct.InsideAbsorpThermal *= TauShIR / (1.0 - RhoShIR * RhoGlIR);
     483             :             }
     484             : 
     485             :             // From the individual glass layer properties, get the glazing system optical properties
     486             :             // for BARE GLASS (i.e., interior, exterior or between-glass shade or blind, or exterior screen, if present, not in place).
     487             :             // Get one set of system properties for solar incident on front of
     488             :             // window and a second set for solar incident on back of window. (The back-incident
     489             :             // properties are used with interior short-wave radiation striking the window from inside.)
     490             : 
     491             :             // After the front and back system optical properties are calculated for bare glass,
     492             :             // a correction is made for the effect of a shade, screen or blind if one of these
     493             :             // is present in the construction.
     494             : 
     495        1348 :             NGlass = thisConstruct.TotGlassLayers;
     496             : 
     497             :             //--------------------------------------------------------------------------------------------
     498             :             // Front calculation (solar incident from outside of room); bare glass portion of construction
     499             :             //--------------------------------------------------------------------------------------------
     500             : 
     501        1348 :             lquasi = false;
     502        1348 :             AllGlassIsSpectralAverage = true;
     503        1348 :             int constexpr TotalIPhi = 10;
     504        1348 :             wm->LayerNum = {0};
     505             : 
     506             :             // Loop over glass layers in the construction
     507        3361 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     508        2013 :                 LayNum = 1 + 2 * (IGlass - 1);
     509        2013 :                 if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + 2 * (IGlass - 1);
     510        2013 :                 if (BGShade || BGBlind) {
     511          12 :                     LayNum = 1;
     512          12 :                     if (NGlass == 2) {
     513           6 :                         if (IGlass == 2) LayNum = 5;
     514             :                     } else { // NGlass = 3
     515           6 :                         if (IGlass == 2) LayNum = 3;
     516           6 :                         if (IGlass == 3) LayNum = 7;
     517             :                     }
     518             :                 }
     519             : 
     520        2013 :                 wm->LayerNum[IGlass - 1] = LayNum;
     521        2013 :                 LayPtr = thisConstruct.LayerPoint(LayNum);
     522        2013 :                 auto *thisMaterial = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(LayPtr));
     523        2013 :                 assert(thisMaterial != nullptr);
     524        2013 :                 SpecDataNum = thisMaterial->GlassSpectralDataPtr;
     525        2013 :                 if (SpecDataNum != 0) {
     526         213 :                     if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
     527             : 
     528             :                     // Get the spectral data for the transmittance, front reflectance and
     529             :                     // back reflectance (all at normal incidence) for this layer.
     530             :                     // In this case, "front" means incident from the outside and "back"
     531             :                     // means incident from the inside.
     532         213 :                     numptDAT = state.dataHeatBal->SpectralData(SpecDataNum).NumOfWavelengths;
     533         213 :                     numpt[IGlass - 1] = numptDAT;
     534             : 
     535       42312 :                     for (int ILam = 1; ILam <= numptDAT; ++ILam) {
     536       42099 :                         wlt[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).WaveLength(ILam);
     537       42099 :                         t[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).Trans(ILam);
     538       42099 :                         if ((IGlass == 1 || (IGlass == 2 && StormWinConst)) && (!wm->BGFlag))
     539        6549 :                             t[IGlass - 1][ILam - 1] *= thisMaterial->GlassTransDirtFactor;
     540       42099 :                         rff[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflFront(ILam);
     541       42099 :                         rbb[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflBack(ILam);
     542             :                     }
     543             : 
     544             :                     // If there is spectral data for between-glass shades or blinds, calc the average spectral properties for use.
     545         213 :                     if (wm->BGFlag) {
     546             :                         // Add warning message for the glazing defined with full spectral data.
     547           0 :                         ShowWarningError(
     548             :                             state,
     549           0 :                             format(
     550             :                                 "Window glazing material \"{}\" was defined with full spectral data and has been converted to average spectral data",
     551           0 :                                 thisMaterial->Name));
     552           0 :                         ShowContinueError(
     553             :                             state,
     554           0 :                             format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
     555           0 :                         ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
     556           0 :                         ShowContinueError(state,
     557             :                                           "If this material is also used in other window constructions  without between-glass shades or blinds,");
     558           0 :                         ShowContinueError(state,
     559             :                                           "then make a duplicate material (with new name) if you want to model those windows  (and reference the new "
     560             :                                           "material) using the full spectral data.");
     561             :                         // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
     562             :                         //  assuming wlt same as wle
     563           0 :                         wm->tmpTrans = solarSpectrumAverage(state, t[0]);
     564           0 :                         wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
     565           0 :                         wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
     566             : 
     567             :                         // visible properties
     568           0 :                         wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
     569           0 :                         wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
     570           0 :                         wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
     571             : 
     572             :                         // set this material to average spectral data
     573           0 :                         thisMaterial->GlassSpectralDataPtr = 0;
     574           0 :                         thisMaterial->Trans = wm->tmpTrans;
     575           0 :                         thisMaterial->TransVis = wm->tmpTransVis;
     576           0 :                         thisMaterial->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
     577           0 :                         thisMaterial->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
     578           0 :                         thisMaterial->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
     579           0 :                         thisMaterial->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
     580           0 :                         SpecDataNum = 0;
     581             :                     }
     582             :                 }
     583             : 
     584        2013 :                 if (SpecDataNum == 0 && !thisMaterial->GlassSpectralAndAngle) { // No spectral data for this layer; use spectral average values
     585        1798 :                     lquasi = true;
     586        1798 :                     numpt[IGlass - 1] = 2;
     587        1798 :                     t[IGlass - 1][0] = thisMaterial->Trans;
     588        1798 :                     if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][0] *= thisMaterial->GlassTransDirtFactor;
     589        1798 :                     t[IGlass - 1][1] = thisMaterial->TransVis;
     590        1798 :                     if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][1] *= thisMaterial->GlassTransDirtFactor;
     591        1798 :                     rff[IGlass - 1][0] = thisMaterial->ReflectSolBeamFront;
     592        1798 :                     rbb[IGlass - 1][0] = thisMaterial->ReflectSolBeamBack;
     593        1798 :                     rff[IGlass - 1][1] = thisMaterial->ReflectVisBeamFront;
     594        1798 :                     rbb[IGlass - 1][1] = thisMaterial->ReflectVisBeamBack;
     595             :                 }
     596        2013 :                 if (thisMaterial->GlassSpectralAndAngle) {
     597           2 :                     if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
     598           2 :                     numptDAT = wm->wle.size();
     599           2 :                     numpt[IGlass - 1] = numptDAT;
     600           2 :                     if (wm->BGFlag) {
     601             :                         // 5/16/2012 CR 8793. Add warning message for the glazing defined with full spectral data.
     602           0 :                         ShowWarningError(state,
     603           0 :                                          format("Window glazing material \"{}\" was defined with full spectral and angular data and has been "
     604             :                                                 "converted to average spectral data",
     605           0 :                                                 thisMaterial->Name));
     606           0 :                         ShowContinueError(
     607             :                             state,
     608           0 :                             format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
     609           0 :                         ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
     610           0 :                         ShowContinueError(state,
     611             :                                           "If this material is also used in other window constructions  without between-glass shades or blinds,");
     612           0 :                         ShowContinueError(state,
     613             :                                           "then make a duplicate material (with new name) if you want to model those windows  (and reference the new "
     614             :                                           "material) using the full spectral data.");
     615             :                         // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
     616             :                         //  assuming wlt same as wle
     617           0 :                         for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
     618           0 :                             Real64 lam = wm->wle[ILam - 1];
     619           0 :                             wlt[IGlass - 1][ILam - 1] = lam;
     620           0 :                             t[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngTransDataPtr, 0.0, lam);
     621           0 :                             rff[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngFRefleDataPtr, 0.0, lam);
     622           0 :                             rbb[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngBRefleDataPtr, 0.0, lam);
     623             :                         }
     624           0 :                         wm->tmpTrans = solarSpectrumAverage(state, t[0]);
     625           0 :                         wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
     626           0 :                         wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
     627             : 
     628             :                         // visible properties
     629           0 :                         wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
     630           0 :                         wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
     631           0 :                         wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
     632             : 
     633             :                         // set this material to average spectral data
     634           0 :                         thisMaterial->GlassSpectralAndAngle = false;
     635           0 :                         thisMaterial->Trans = wm->tmpTrans;
     636           0 :                         thisMaterial->TransVis = wm->tmpTransVis;
     637           0 :                         thisMaterial->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
     638           0 :                         thisMaterial->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
     639           0 :                         thisMaterial->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
     640           0 :                         thisMaterial->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
     641           0 :                         SpecDataNum = 0;
     642             :                     }
     643             :                 }
     644             :             } // End of loop over glass layers in the construction for front calculation
     645             : 
     646             :             if (TotalIPhi > maxIncidentAngles) {
     647             :                 ShowSevereError(state,
     648             :                                 format("WindowManage::InitGlassOpticalCalculations = {}, Invalid maximum value of common incidet angles = {}.",
     649             :                                        thisConstruct.Name,
     650             :                                        TotalIPhi));
     651             :                 ShowContinueError(
     652             :                     state,
     653             :                     format("The maximum number of incident angles for each construct is {}. Please rearrange the dataset.", maxIncidentAngles));
     654             :                 ShowFatalError(state, "Errors found getting inputs. Previous error(s) cause program termination.");
     655             :             }
     656             : 
     657             :             // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
     658             :             // Get glass layer properties, then glazing system properties (which include the
     659             :             // effect of inter-reflection among glass layers) at each incidence angle.
     660             : 
     661       14828 :             for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
     662             :                 // 10 degree increment for incident angle is only value for a construction without a layer = SpectralAndAngle
     663       13480 :                 Phi = double(IPhi - 1) * 10.0;
     664       13480 :                 CosPhi = std::cos(Phi * Constant::DegToRadians);
     665       13480 :                 if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
     666             : 
     667             :                 // For each wavelength, get glass layer properties at this angle of incidence
     668             :                 // from properties at normal incidence
     669       33610 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     670       20130 :                     LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
     671       20130 :                     auto *thisMaterial = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(LayPtr));
     672       20130 :                     assert(thisMaterial != nullptr);
     673       20130 :                     if (!thisMaterial->GlassSpectralAndAngle) {
     674      477060 :                         for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
     675      456950 :                             TransAndReflAtPhi(CosPhi,
     676      456950 :                                               t[IGlass - 1][ILam - 1],
     677      456950 :                                               rff[IGlass - 1][ILam - 1],
     678      456950 :                                               rbb[IGlass - 1][ILam - 1],
     679      456950 :                                               tPhi[IGlass - 1][ILam - 1],
     680      456950 :                                               rfPhi[IGlass - 1][ILam - 1],
     681      456950 :                                               rbPhi[IGlass - 1][ILam - 1],
     682      456950 :                                               wm->lSimpleGlazingSystem,
     683      456950 :                                               wm->SimpleGlazingSHGC,
     684      456950 :                                               wm->SimpleGlazingU);
     685             :                         }
     686             :                     } else {
     687        2160 :                         for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
     688        2140 :                             Real64 lam = wm->wle[ILam - 1];
     689        2140 :                             wlt[IGlass - 1][ILam - 1] = lam;
     690        2140 :                             tPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngTransDataPtr, Phi, lam);
     691        2140 :                             rfPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngFRefleDataPtr, Phi, lam);
     692        2140 :                             rbPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngBRefleDataPtr, Phi, lam);
     693             :                         }
     694             :                     }
     695             :                     // For use with between-glass shade/blind, save angular properties of isolated glass
     696             :                     // for case that all glass layers were input with spectral-average properties
     697             :                     //  only used by between-glass shades or blinds
     698       20130 :                     if (AllGlassIsSpectralAverage) {
     699       17620 :                         tBareSolPhi(IGlass, IPhi) = tPhi[IGlass - 1][0];
     700       17620 :                         tBareVisPhi(IGlass, IPhi) = tPhi[IGlass - 1][1];
     701       17620 :                         rfBareSolPhi(IGlass, IPhi) = rfPhi[IGlass - 1][0];
     702       17620 :                         rfBareVisPhi(IGlass, IPhi) = rfPhi[IGlass - 1][1];
     703       17620 :                         rbBareSolPhi(IGlass, IPhi) = rbPhi[IGlass - 1][0];
     704       17620 :                         rbBareVisPhi(IGlass, IPhi) = rbPhi[IGlass - 1][1];
     705       17620 :                         afBareSolPhi(IGlass, IPhi) = max(0.0, 1.0 - (tBareSolPhi(IGlass, IPhi) + rfBareSolPhi(IGlass, IPhi)));
     706       17620 :                         abBareSolPhi(IGlass, IPhi) = max(0.0, 1.0 - (tBareSolPhi(IGlass, IPhi) + rbBareSolPhi(IGlass, IPhi)));
     707             :                     }
     708             :                 }
     709             : 
     710             :                 // For each wavelength in the solar spectrum, calculate system properties
     711             :                 // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence.
     712             :                 // In the following the argument "1" indicates that spectral average solar values
     713             :                 // should be used for layers without spectral data.
     714             : 
     715       13480 :                 std::array<Real64, nume> stPhi = {0.0};  // Glazing system transmittance at angle of incidence for each wavelength in wle
     716       13480 :                 std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
     717       13480 :                 std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelenth in wle
     718             :                 // For each layer, glazing system absorptance at angle of incidence
     719       26960 :                 Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
     720             : 
     721       13480 :                 SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
     722             : 
     723             :                 // Get solar properties of system by integrating over solar irradiance spectrum.
     724             :                 // For now it is assumed that the exterior and interior irradiance spectra are the same.
     725       13480 :                 tsolPhi(IPhi) = solarSpectrumAverage(state, stPhi);
     726       13480 :                 rfsolPhi(IPhi) = solarSpectrumAverage(state, srfPhi);
     727       13480 :                 rbsolPhi(IPhi) = solarSpectrumAverage(state, srbPhi);
     728             : 
     729       33610 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     730     2174040 :                     for (int ILam = 1; ILam <= nume; ++ILam) {
     731     2153910 :                         sabsPhi(ILam) = saPhi(IGlass, ILam);
     732             :                     }
     733       20130 :                     solabsPhi(IGlass, IPhi) = solarSpectrumAverage(state, sabsPhi);
     734             :                 }
     735             : 
     736             :                 // Get visible properties of system by integrating over solar irradiance
     737             :                 // spectrum weighted by photopic response.
     738             :                 // Need to redo the calculation of system spectral properties here only if
     739             :                 // one or more glass layers have no spectral data (lquasi = .TRUE.); in this
     740             :                 // case the spectral average visible properties will be used for the layers
     741             :                 // without spectral data, as indicated by the argument "2".
     742             : 
     743       13480 :                 if (lquasi) SystemSpectralPropertiesAtPhi(state, 2, NGlass, 0.37, 0.78, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
     744       13480 :                 tvisPhi(IPhi) = visibleSpectrumAverage(state, stPhi);
     745       13480 :                 rfvisPhi(IPhi) = visibleSpectrumAverage(state, srfPhi);
     746       13480 :                 rbvisPhi(IPhi) = visibleSpectrumAverage(state, srbPhi);
     747             : 
     748       13480 :             } // End of loop over incidence angles for front calculation
     749             : 
     750             :             //  only used by between-glass shades or blinds
     751        1348 :             if (AllGlassIsSpectralAverage) {
     752        3013 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     753        1762 :                     W5LsqFit(CosPhiIndepVar, tBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.tBareSolCoef(IGlass));
     754        1762 :                     W5LsqFit(CosPhiIndepVar, tBareVisPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.tBareVisCoef(IGlass));
     755        1762 :                     W5LsqFit(CosPhiIndepVar, rfBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rfBareSolCoef(IGlass));
     756        1762 :                     W5LsqFit(CosPhiIndepVar, rfBareVisPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rfBareVisCoef(IGlass));
     757        1762 :                     W5LsqFit(CosPhiIndepVar, rbBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rbBareSolCoef(IGlass));
     758        1762 :                     W5LsqFit(CosPhiIndepVar, rbBareVisPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rbBareVisCoef(IGlass));
     759        1762 :                     W5LsqFit(CosPhiIndepVar, afBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.afBareSolCoef(IGlass));
     760        1762 :                     W5LsqFit(CosPhiIndepVar, abBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.abBareSolCoef(IGlass));
     761             :                 }
     762             :             }
     763             : 
     764        1348 :             thisConstruct.ReflectSolDiffFront = DiffuseAverage(rfsolPhi);
     765        1348 :             thisConstruct.ReflectSolDiffBack = DiffuseAverage(rbsolPhi);
     766        1348 :             thisConstruct.ReflectVisDiffFront = DiffuseAverage(rfvisPhi);
     767        1348 :             thisConstruct.ReflectVisDiffBack = DiffuseAverage(rbvisPhi);
     768             : 
     769        1348 :             tsolDiff = DiffuseAverage(tsolPhi);
     770        1348 :             tvisDiff = DiffuseAverage(tvisPhi);
     771        1348 :             thisConstruct.TransDiff = tsolDiff;
     772        1348 :             thisConstruct.TransDiffVis = tvisDiff;
     773        3361 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     774        2013 :                 solabsPhiLay({1, TotalIPhi}) = solabsPhi(IGlass, {1, TotalIPhi});
     775        2013 :                 solabsDiff(IGlass) = DiffuseAverage(solabsPhiLay);
     776        2013 :                 thisConstruct.AbsDiff(IGlass) = solabsDiff(IGlass);
     777             : 
     778             :                 // For use with between-glass shade/blind, get diffuse properties of isolated glass for case when
     779             :                 // all glass layers were input with spectral-average properties
     780             :                 //  only used by between-glass shades or blinds
     781        2013 :                 if (AllGlassIsSpectralAverage) {
     782        1762 :                     thisConstruct.tBareSolDiff(IGlass) = DiffuseAverage(tBareSolPhi(IGlass, {1, TotalIPhi}));
     783        1762 :                     thisConstruct.tBareVisDiff(IGlass) = DiffuseAverage(tBareVisPhi(IGlass, {1, TotalIPhi}));
     784        1762 :                     thisConstruct.rfBareSolDiff(IGlass) = DiffuseAverage(rfBareSolPhi(IGlass, {1, TotalIPhi}));
     785        1762 :                     thisConstruct.rfBareVisDiff(IGlass) = DiffuseAverage(rfBareVisPhi(IGlass, {1, TotalIPhi}));
     786        1762 :                     thisConstruct.rbBareSolDiff(IGlass) = DiffuseAverage(rbBareSolPhi(IGlass, {1, TotalIPhi}));
     787        1762 :                     thisConstruct.rbBareVisDiff(IGlass) = DiffuseAverage(rbBareVisPhi(IGlass, {1, TotalIPhi}));
     788        1762 :                     thisConstruct.afBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rfBareSolDiff(IGlass)));
     789        1762 :                     thisConstruct.abBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rbBareSolDiff(IGlass)));
     790             :                 }
     791             :             }
     792             : 
     793             :             //------------------------------------------------------------------------------------------
     794             :             // Back calculation (solar incident from inside of room); bare glass portion of construction
     795             :             //------------------------------------------------------------------------------------------
     796             : 
     797        1348 :             lquasi = false;
     798        1348 :             wm->LayerNum = {0};
     799             : 
     800             :             // Loop over glass layers in the construction.
     801        3361 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     802        2013 :                 LayNum = 1 + (NGlass - IGlass) * 2;
     803        2013 :                 if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + (NGlass - IGlass) * 2;
     804        2013 :                 if (BGShade || BGBlind) {
     805          12 :                     if (NGlass == 2) {
     806           6 :                         if (IGlass == 1) LayNum = 5;
     807           6 :                         if (IGlass == 2) LayNum = 1;
     808             :                     } else { // NGlass = 3
     809           6 :                         if (IGlass == 1) LayNum = 7;
     810           6 :                         if (IGlass == 2) LayNum = 3;
     811           6 :                         if (IGlass == 3) LayNum = 1;
     812             :                     }
     813             :                 }
     814        2013 :                 wm->LayerNum[IGlass - 1] = LayNum;
     815        2013 :                 LayPtr = thisConstruct.LayerPoint(LayNum);
     816        2013 :                 auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(LayPtr));
     817        2013 :                 assert(thisMaterial != nullptr);
     818             : 
     819        2013 :                 SpecDataNum = thisMaterial->GlassSpectralDataPtr;
     820        2013 :                 if (SpecDataNum != 0) {
     821             : 
     822             :                     // Get the spectral data for the transmittance, front reflectance and
     823             :                     // back reflectance (all at normal incidence) for this layer.
     824             :                     // In this case, "front" means incident from the inside and "back"
     825             :                     // means incident from the outside.
     826             : 
     827         213 :                     numptDAT = state.dataHeatBal->SpectralData(SpecDataNum).NumOfWavelengths;
     828         213 :                     numpt[IGlass - 1] = numptDAT;
     829             : 
     830       42312 :                     for (int ILam = 1; ILam <= numptDAT; ++ILam) {
     831       42099 :                         wlt[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).WaveLength(ILam);
     832       42099 :                         t[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).Trans(ILam);
     833       42099 :                         if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst))
     834        6549 :                             t[IGlass - 1][ILam - 1] *= thisMaterial->GlassTransDirtFactor;
     835       42099 :                         rff[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflBack(ILam);
     836       42099 :                         rbb[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflFront(ILam);
     837             :                     }
     838             : 
     839             :                 } else { // No spectral data for this layer; use spectral average values
     840        1800 :                     if (!thisMaterial->GlassSpectralAndAngle) {
     841        1798 :                         lquasi = true;
     842        1798 :                         numpt[IGlass - 1] = 2;
     843        1798 :                         t[IGlass - 1][0] = thisMaterial->Trans;
     844        1798 :                         if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][0] *= thisMaterial->GlassTransDirtFactor;
     845        1798 :                         t[IGlass - 1][1] = thisMaterial->TransVis;
     846        1798 :                         if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][1] *= thisMaterial->GlassTransDirtFactor;
     847        1798 :                         rff[IGlass - 1][0] = thisMaterial->ReflectSolBeamBack;
     848        1798 :                         rbb[IGlass - 1][0] = thisMaterial->ReflectSolBeamFront;
     849        1798 :                         rff[IGlass - 1][1] = thisMaterial->ReflectVisBeamBack;
     850        1798 :                         rbb[IGlass - 1][1] = thisMaterial->ReflectVisBeamFront;
     851             :                     }
     852             :                 }
     853        2013 :                 if (thisMaterial->GlassSpectralAndAngle) {
     854           2 :                     numptDAT = wm->wle.size();
     855           2 :                     numpt[IGlass - 1] = numptDAT;
     856             :                 }
     857             :             } // End of loop over glass layers in the construction for back calculation
     858             : 
     859             :             // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
     860             :             // Get bare glass layer properties, then glazing system properties at each incidence angle.
     861             :             // The glazing system properties include the effect of inter-reflection among glass layers,
     862             :             // but exclude the effect of a shade or blind if present in the construction.
     863             :             // When a construction has a layer = SpectralAndAngle, the 10 degree increment will be overridden.
     864       14828 :             for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
     865       13480 :                 Phi = double(IPhi - 1) * 10.0;
     866       13480 :                 CosPhi = std::cos(Phi * Constant::DegToRadians);
     867       13480 :                 if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
     868             : 
     869             :                 // For each wavelength, get glass layer properties at this angle of incidence
     870             :                 // from properties at normal incidence
     871       33610 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     872       20130 :                     LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
     873       20130 :                     auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(LayPtr));
     874       20130 :                     assert(thisMaterial != nullptr);
     875       20130 :                     if (!thisMaterial->GlassSpectralAndAngle) {
     876      477060 :                         for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
     877             : 
     878      456950 :                             TransAndReflAtPhi(CosPhi,
     879      456950 :                                               t[IGlass - 1][ILam - 1],
     880      456950 :                                               rff[IGlass - 1][ILam - 1],
     881      456950 :                                               rbb[IGlass - 1][ILam - 1],
     882      456950 :                                               tPhi[IGlass - 1][ILam - 1],
     883      456950 :                                               rfPhi[IGlass - 1][ILam - 1],
     884      456950 :                                               rbPhi[IGlass - 1][ILam - 1],
     885      456950 :                                               wm->lSimpleGlazingSystem,
     886      456950 :                                               wm->SimpleGlazingSHGC,
     887      456950 :                                               wm->SimpleGlazingU);
     888             :                         }
     889             :                     } else {
     890        2160 :                         for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
     891        2140 :                             Real64 lam = wm->wle[ILam - 1];
     892        2140 :                             wlt[IGlass - 1][ILam - 1] = lam;
     893        2140 :                             tPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngTransDataPtr, Phi, lam);
     894        2140 :                             rfPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngFRefleDataPtr, Phi, lam);
     895        2140 :                             rbPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngBRefleDataPtr, Phi, lam);
     896             :                         }
     897             :                     }
     898             :                 }
     899             : 
     900             :                 // For each wavelength in the solar spectrum, calculate system properties
     901             :                 // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence
     902       13480 :                 std::array<Real64, nume> stPhi = {0.0};  // Glazing system transmittance at angle of incidence for each wavelength in wle
     903       13480 :                 std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
     904       13480 :                 std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelenth in wle
     905             :                 // For each layer, glazing system absorptance at angle of incidence
     906       26960 :                 Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
     907             : 
     908       13480 :                 SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
     909             : 
     910             :                 // Get back absorptance properties of system by integrating over solar irradiance spectrum.
     911             :                 // For now it is assumed that the exterior and interior irradiance spectra are the same.
     912             : 
     913       33610 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     914     2174040 :                     for (int j = 1; j <= nume; ++j) {
     915     2153910 :                         sabsPhi(j) = saPhi(IGlass, j);
     916             :                     }
     917       20130 :                     solabsBackPhi(IGlass, IPhi) = solarSpectrumAverage(state, sabsPhi);
     918             :                 }
     919             : 
     920       13480 :             } // End of loop over incidence angles for back calculation
     921             : 
     922        3361 :             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
     923        2013 :                 IGlassBack = NGlass - IGlass + 1;
     924        2013 :                 thisConstruct.AbsDiffBack(IGlass) = DiffuseAverage(solabsBackPhi(IGlassBack, {1, 10}));
     925             :             }
     926             : 
     927             :             //-----------------------------------------------------------------------
     928             :             // Correction for effect of shade, screen or blind if present in the construction
     929             :             //-----------------------------------------------------------------------
     930             : 
     931             :             // For construction with shade, screen or blind, get system shading device absorptance
     932             :             // and correct the system glass layer absorptances for the effect of reflection
     933             :             // and transmission by shade, screen or blind. Get system reflectance (front and back,
     934             :             // solar and visible)
     935             : 
     936        1348 :             if (ShadeOn || BlindOn || ScreenOn) {
     937             : 
     938             :                 // Solar and visible properties of isolated shade or blind
     939             :                 // (Note: for shades or screen we go through the following loop over slat angles only once.)
     940             : 
     941          48 :                 Real64 const tsolDiff_2(pow_2(tsolDiff));
     942          48 :                 Real64 const tvisDiff_2(pow_2(tvisDiff));
     943         591 :                 for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
     944             : 
     945         588 :                     if (ShadeOn) {
     946             :                         auto const *thisMaterialSh =
     947          29 :                             dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)));
     948          29 :                         assert(thisMaterialSh != nullptr);
     949          29 :                         ShadeAbs = thisMaterialSh->AbsorpSolar;
     950          29 :                         ShadeTrans = thisMaterialSh->Trans;
     951          29 :                         ShadeTransVis = thisMaterialSh->TransVis;
     952          29 :                         ShadeRefl = thisMaterialSh->ReflectShade;
     953          29 :                         ShadeReflVis = thisMaterialSh->ReflectShadeVis;
     954          29 :                         rsh = ShadeRefl;
     955          29 :                         rshv = ShadeReflVis;
     956          29 :                         tsh = ShadeTrans;
     957          29 :                         tshv = ShadeTransVis;
     958          29 :                         ash = ShadeAbs;
     959         559 :                     } else if (IntBlind || ExtBlind) {
     960         554 :                         auto const &blind = state.dataMaterial->Blind(BlNum);
     961         554 :                         ShadeTrans = blind.SolFrontDiffDiffTrans(ISlatAng);
     962         554 :                         ShadeTransGnd = blind.SolFrontDiffDiffTransGnd(ISlatAng);
     963         554 :                         ShadeTransSky = blind.SolFrontDiffDiffTransSky(ISlatAng);
     964         554 :                         ShadeTransVis = blind.VisFrontDiffDiffTrans(ISlatAng);
     965         554 :                         if (IntBlind) { // Interior blind
     966         372 :                             ShadeAbs = blind.SolFrontDiffAbs(ISlatAng);
     967         372 :                             ShadeRefl = blind.SolFrontDiffDiffRefl(ISlatAng);
     968         372 :                             ShadeReflGnd = blind.SolFrontDiffDiffReflGnd(ISlatAng);
     969         372 :                             ShadeReflSky = blind.SolFrontDiffDiffReflSky(ISlatAng);
     970         372 :                             ShadeReflVis = blind.VisFrontDiffDiffRefl(ISlatAng);
     971             :                         } else { // Exterior blind
     972         182 :                             ShadeAbs = blind.SolBackDiffAbs(ISlatAng);
     973         182 :                             ShadeRefl = blind.SolBackDiffDiffRefl(ISlatAng);
     974         182 :                             ShadeReflVis = blind.VisBackDiffDiffRefl(ISlatAng);
     975             :                         }
     976         559 :                     } else if (BGBlind) {
     977           3 :                         auto const &blind = state.dataMaterial->Blind(BlNum);
     978           3 :                         tsh = blind.SolFrontDiffDiffTrans(ISlatAng);
     979           3 :                         tshGnd = blind.SolFrontDiffDiffTransGnd(ISlatAng);
     980           3 :                         tshSky = blind.SolFrontDiffDiffTransSky(ISlatAng);
     981           3 :                         tshv = blind.VisFrontDiffDiffTrans(ISlatAng);
     982           3 :                         rfsh = blind.SolFrontDiffDiffRefl(ISlatAng);
     983           3 :                         rfshGnd = blind.SolFrontDiffDiffReflGnd(ISlatAng);
     984           3 :                         rfshSky = blind.SolFrontDiffDiffReflSky(ISlatAng);
     985           3 :                         rfshv = blind.VisFrontDiffDiffRefl(ISlatAng);
     986           3 :                         rbsh = blind.SolBackDiffDiffRefl(ISlatAng);
     987           3 :                         rbshv = blind.VisBackDiffDiffRefl(ISlatAng);
     988           3 :                         afsh = blind.SolFrontDiffAbs(ISlatAng);
     989           3 :                         afshGnd = blind.SolFrontDiffAbsGnd(ISlatAng);
     990           3 :                         afshSky = blind.SolFrontDiffAbsSky(ISlatAng);
     991           3 :                         absh = blind.SolBackDiffAbs(ISlatAng);
     992           2 :                     } else if (ScreenOn) {
     993             :                         //       diffuse screen properties are calculated during initialization (quarter-hemispherical integration of beam properties)
     994             :                         auto const *matScreen =
     995           2 :                             dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)));
     996           2 :                         assert(matScreen != nullptr);
     997             : 
     998           2 :                         ShadeAbs = matScreen->DfAbs;
     999           2 :                         ShadeTrans = matScreen->DfTrans;
    1000           2 :                         ShadeTransVis = matScreen->DfTransVis;
    1001           2 :                         ShadeRefl = matScreen->DfRef;
    1002           2 :                         ShadeReflVis = matScreen->DfRefVis;
    1003           2 :                         rsh = ShadeRefl;
    1004           2 :                         rshv = ShadeReflVis;
    1005           2 :                         tsh = ShadeTrans;
    1006           2 :                         tshv = ShadeTransVis;
    1007           2 :                         ash = ShadeAbs;
    1008             :                     }
    1009             : 
    1010             :                     // Correction factors for inter-reflections between glass and shading device
    1011             : 
    1012         588 :                     if (ExtShade || ExtBlind || ExtScreen) {
    1013         187 :                         ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffFront);
    1014         187 :                         ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffFront);
    1015         401 :                     } else if (IntShade || IntBlind) {
    1016         396 :                         ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffBack);
    1017         396 :                         ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffBack);
    1018             :                     }
    1019             : 
    1020         588 :                     if (ExtShade || ExtBlind || ExtScreen) { // Exterior shade or blind
    1021             : 
    1022             :                         // Front incident solar, beam, exterior shade, screen or blind
    1023             : 
    1024         187 :                         if (ExtShade) {
    1025          33 :                             for (int IPhi = 1; IPhi <= 10; ++IPhi) {
    1026          80 :                                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1027          50 :                                     solabsPhi(IGlass, IPhi) = ShadeTrans * solabsDiff(IGlass) * ShadeReflFac;
    1028             :                                 }
    1029          30 :                                 tsolPhi(IPhi) = ShadeTrans * ShadeReflFac * tsolDiff;
    1030          30 :                                 tvisPhi(IPhi) = ShadeTransVis * ShadeReflFacVis * tvisDiff;
    1031          30 :                                 solabsShadePhi(IPhi) = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront);
    1032             :                             }
    1033             :                         }
    1034             : 
    1035             :                         // Front incident solar, diffuse, exterior shade/screen/blind
    1036             : 
    1037         377 :                         for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1038         190 :                             if (ExtBlind) {
    1039         182 :                                 thisConstruct.BlAbsDiff(ISlatAng, IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
    1040         182 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, IGlass) = ShadeTransGnd * ShadeReflFac * solabsDiff(IGlass);
    1041         182 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, IGlass) = ShadeTransSky * ShadeReflFac * solabsDiff(IGlass);
    1042             :                             }
    1043         190 :                             if (ExtShade || ExtScreen) thisConstruct.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
    1044             :                         }
    1045         187 :                         if (ExtBlind) {
    1046         182 :                             auto const &blind = state.dataMaterial->Blind(BlNum);
    1047         364 :                             thisConstruct.AbsDiffBlind(ISlatAng) =
    1048         182 :                                 blind.SolFrontDiffAbs(ISlatAng) + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
    1049         364 :                             thisConstruct.AbsDiffBlindGnd(ISlatAng) =
    1050         182 :                                 blind.SolFrontDiffAbsGnd(ISlatAng) + ShadeTransGnd * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
    1051         364 :                             thisConstruct.AbsDiffBlindSky(ISlatAng) =
    1052         182 :                                 blind.SolFrontDiffAbsSky(ISlatAng) + ShadeTransSky * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
    1053         182 :                             thisConstruct.BlTransDiff(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTrans;
    1054         182 :                             thisConstruct.BlTransDiffGnd(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransGnd;
    1055         182 :                             thisConstruct.BlTransDiffSky(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransSky;
    1056         182 :                             thisConstruct.BlTransDiffVis(ISlatAng) = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1057         364 :                             thisConstruct.BlReflectSolDiffFront(ISlatAng) =
    1058         182 :                                 ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
    1059         182 :                             thisConstruct.BlReflectVisDiffFront(ISlatAng) =
    1060         182 :                                 ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
    1061             :                         }
    1062         187 :                         if (ExtShade || ExtScreen) {
    1063           5 :                             thisConstruct.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront);
    1064           5 :                             thisConstruct.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
    1065           5 :                             thisConstruct.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1066           5 :                             thisConstruct.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
    1067           5 :                             thisConstruct.ReflectVisDiffFront =
    1068           5 :                                 ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
    1069             :                         }
    1070             : 
    1071             :                         // Back incident solar, diffuse, exterior shade/blind
    1072             : 
    1073         187 :                         if (ExtBlind) {
    1074         364 :                             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1075         182 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, IGlass) =
    1076         182 :                                     thisConstruct.AbsDiffBack(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
    1077             :                             }
    1078         182 :                             thisConstruct.AbsDiffBackBlind(ISlatAng) = tsolDiff * ShadeReflFac * ShadeAbs;
    1079         182 :                             thisConstruct.BlReflectSolDiffBack(ISlatAng) = thisConstruct.ReflectSolDiffBack + tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1080         182 :                             thisConstruct.BlReflectVisDiffBack(ISlatAng) =
    1081         182 :                                 thisConstruct.ReflectVisDiffBack + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1082             :                         }
    1083         187 :                         if (ExtShade || ExtScreen) {
    1084          13 :                             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1085           8 :                                 thisConstruct.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
    1086             :                             }
    1087           5 :                             thisConstruct.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
    1088           5 :                             thisConstruct.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1089           5 :                             thisConstruct.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1090             :                         }
    1091             : 
    1092             :                     } // End check if exterior shade, screen or blind
    1093             : 
    1094         588 :                     if (IntShade || IntBlind) { // Interior shade or blind
    1095             : 
    1096             :                         // Front incident solar, beam, interior shade
    1097             : 
    1098         396 :                         if (IntShade) {
    1099         264 :                             for (int IPhi = 1; IPhi <= 10; ++IPhi) {
    1100         620 :                                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1101         380 :                                     solabsPhi(IGlass, IPhi) += tsolPhi(IPhi) * ShadeRefl * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
    1102             :                                 }
    1103         240 :                                 solabsShadePhi(IPhi) = tsolPhi(IPhi) * ShadeReflFac * ShadeAbs;
    1104         240 :                                 tsolPhi(IPhi) *= ShadeReflFac * ShadeTrans;
    1105         240 :                                 tvisPhi(IPhi) *= ShadeReflFacVis * ShadeTransVis;
    1106             :                             }
    1107             :                         } // End of check if interior shade
    1108             : 
    1109             :                         // Front incident solar, diffuse, interior blind
    1110             : 
    1111         396 :                         if (IntBlind) {
    1112         744 :                             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1113         744 :                                 thisConstruct.BlAbsDiff(ISlatAng, IGlass) =
    1114         372 :                                     thisConstruct.AbsDiff(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
    1115         744 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, IGlass) =
    1116         372 :                                     thisConstruct.AbsDiff(IGlass) + tsolDiff * ShadeReflGnd * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
    1117         372 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, IGlass) =
    1118         372 :                                     thisConstruct.AbsDiff(IGlass) + tsolDiff * ShadeReflSky * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
    1119             :                             }
    1120             : 
    1121         372 :                             auto const &blind = state.dataMaterial->Blind(BlNum);
    1122         372 :                             thisConstruct.AbsDiffBlind(ISlatAng) = tsolDiff * ShadeReflFac * ShadeAbs;
    1123         372 :                             thisConstruct.AbsDiffBlindGnd(ISlatAng) = tsolDiff * ShadeReflFac * blind.SolFrontDiffAbsGnd(ISlatAng);
    1124         372 :                             thisConstruct.AbsDiffBlindSky(ISlatAng) = tsolDiff * ShadeReflFac * blind.SolFrontDiffAbsSky(ISlatAng);
    1125         372 :                             thisConstruct.BlTransDiff(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTrans;
    1126         372 :                             thisConstruct.BlTransDiffGnd(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransGnd;
    1127         372 :                             thisConstruct.BlTransDiffSky(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransSky;
    1128         372 :                             thisConstruct.BlTransDiffVis(ISlatAng) = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1129         372 :                             thisConstruct.BlReflectSolDiffFront(ISlatAng) = thisConstruct.ReflectSolDiffFront + tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1130         744 :                             thisConstruct.BlReflectVisDiffFront(ISlatAng) =
    1131         372 :                                 thisConstruct.ReflectVisDiffFront + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1132             : 
    1133             :                             // Back incident solar, diffuse, interior blind
    1134             : 
    1135         744 :                             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1136         372 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, IGlass) = thisConstruct.AbsDiffBack(IGlass) * ShadeTrans * ShadeReflFac;
    1137             :                             }
    1138             : 
    1139         744 :                             thisConstruct.AbsDiffBackBlind(ISlatAng) =
    1140         372 :                                 blind.SolBackDiffAbs(ISlatAng) + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffBack * ShadeAbs;
    1141         744 :                             thisConstruct.BlReflectSolDiffBack(ISlatAng) =
    1142         372 :                                 blind.SolBackDiffDiffRefl(ISlatAng) + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffBack * ShadeReflFac;
    1143         372 :                             thisConstruct.BlReflectVisDiffBack(ISlatAng) =
    1144         372 :                                 blind.VisBackDiffDiffRefl(ISlatAng) + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffBack * ShadeReflFacVis;
    1145             :                         } // End of check if interior blind
    1146             : 
    1147             :                         // Front incident solar, diffuse, interior shade
    1148             : 
    1149         396 :                         if (IntShade) {
    1150          62 :                             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1151          38 :                                 thisConstruct.AbsDiff(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
    1152             :                             }
    1153             : 
    1154          24 :                             thisConstruct.AbsDiffShade = tsolDiff * ShadeReflFac * ShadeAbs;
    1155          24 :                             thisConstruct.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
    1156          24 :                             thisConstruct.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
    1157          24 :                             thisConstruct.ReflectSolDiffFront += tsolDiff_2 * ShadeRefl * ShadeReflFac;
    1158          24 :                             thisConstruct.ReflectVisDiffFront += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
    1159             : 
    1160             :                             // Back incident solar, diffuse, interior shade
    1161             : 
    1162          62 :                             for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1163          38 :                                 thisConstruct.AbsDiffBack(IGlass) *= ShadeTrans * ShadeReflFac;
    1164             :                             }
    1165             : 
    1166          24 :                             thisConstruct.AbsDiffBackShade = ShadeAbs * (1 + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffBack);
    1167          24 :                             thisConstruct.ReflectSolDiffBack = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffBack * ShadeReflFac;
    1168          24 :                             thisConstruct.ReflectVisDiffBack =
    1169          24 :                                 ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffBack * ShadeReflFacVis;
    1170             :                         } // End of check if interior shade
    1171             : 
    1172             :                     } // End check if interior shade or blind
    1173             : 
    1174         588 :                     if (BGShade || BGBlind) { // Between-glass shade/blind; assumed to be between glass #2 and glass #3
    1175             : 
    1176           5 :                         tsh2 = pow_2(tsh);
    1177           5 :                         tshv2 = pow_2(tshv);
    1178           5 :                         td1 = thisConstruct.tBareSolDiff(1);
    1179           5 :                         td2 = thisConstruct.tBareSolDiff(2);
    1180           5 :                         td1v = thisConstruct.tBareVisDiff(1);
    1181           5 :                         td2v = thisConstruct.tBareVisDiff(2);
    1182           5 :                         afd1 = thisConstruct.afBareSolDiff(1);
    1183           5 :                         afd2 = thisConstruct.afBareSolDiff(2);
    1184           5 :                         abd1 = thisConstruct.abBareSolDiff(1);
    1185           5 :                         abd2 = thisConstruct.abBareSolDiff(2);
    1186           5 :                         rb1 = thisConstruct.rbBareSolDiff(1);
    1187           5 :                         rb2 = thisConstruct.rbBareSolDiff(2);
    1188           5 :                         rb1v = thisConstruct.rbBareVisDiff(1);
    1189           5 :                         rb2v = thisConstruct.rbBareVisDiff(2);
    1190           5 :                         rf1 = thisConstruct.rfBareSolDiff(1);
    1191           5 :                         rf2 = thisConstruct.rfBareSolDiff(2);
    1192           5 :                         rf1v = thisConstruct.rfBareVisDiff(1);
    1193           5 :                         rf2v = thisConstruct.rfBareVisDiff(2);
    1194             : 
    1195           5 :                         if (BGShade) {
    1196           2 :                             if (NGlass == 2) {
    1197             : 
    1198             :                                 // Front incident solar, beam, between-glass shade, NGlass = 2
    1199             : 
    1200          11 :                                 for (int IPhi = 1; IPhi <= 10; ++IPhi) {
    1201          10 :                                     t1 = tBareSolPhi(1, IPhi);
    1202          10 :                                     t1v = tBareVisPhi(1, IPhi);
    1203          10 :                                     af1 = afBareSolPhi(1, IPhi);
    1204          10 :                                     ab1 = abBareSolPhi(1, IPhi);
    1205          10 :                                     tsolPhi(IPhi) = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * td2;
    1206          10 :                                     tvisPhi(IPhi) = t1v * (tshv + rshv * rb1v * tshv + tshv * rf2v * rshv) * td2v;
    1207          10 :                                     solabsShadePhi(IPhi) = t1 * (ash + rsh * rb1 + tsh * rf2) * ash;
    1208          10 :                                     solabsPhi(1, IPhi) = af1 + t1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * abd1;
    1209          10 :                                     solabsPhi(2, IPhi) = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
    1210             :                                 } // End of loop over incidence angles
    1211             : 
    1212             :                                 // Front incident solar, diffuse, between-glass shade, NGlass = 2
    1213             : 
    1214           1 :                                 thisConstruct.TransDiff = td1 * (tsh + rsh * rb1 * tsh + tsh * rb2 * rsh) * td2;
    1215           1 :                                 thisConstruct.TransDiffVis = td1v * (tshv + rshv * rb1v * tshv + tshv * rb2v * rshv) * td2v;
    1216           1 :                                 thisConstruct.AbsDiffShade = td1 * (ash + rsh * rb1 * ash + tsh * rf2 * ash);
    1217           1 :                                 thisConstruct.AbsDiff(1) = afd1 + td1 * (rsh + tsh * rb2 * tsh) * abd1;
    1218           1 :                                 thisConstruct.AbsDiff(2) = td1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
    1219           1 :                                 thisConstruct.ReflectSolDiffFront = rf1 + td1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * td1;
    1220           1 :                                 thisConstruct.ReflectVisDiffFront = rf1v + td1v * (rshv + rshv * rb1v * rshv + tshv * rf2v * tshv) * td1v;
    1221             : 
    1222             :                                 // Back incident solar, diffuse, between-glass shade, NGlass = 2
    1223             : 
    1224           1 :                                 thisConstruct.AbsDiffBackShade = td2 * (ash + rsh * rf2 * ash + tsh * rb1 * ash);
    1225           1 :                                 thisConstruct.AbsDiffBack(1) = td2 * (tsh + rsh * rf2 * tsh + tsh * rb1 * rsh) * abd1;
    1226           1 :                                 thisConstruct.AbsDiffBack(2) = abd2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * afd2;
    1227           1 :                                 thisConstruct.ReflectSolDiffBack = rb2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * td2;
    1228           1 :                                 thisConstruct.ReflectVisDiffBack = rb2v + td2v * (rshv + rshv * rf2v * rshv + tshv * rb1v * tshv) * td2v;
    1229             : 
    1230             :                             } // End of check if NGlass = 2
    1231             : 
    1232           2 :                             if (NGlass == 3) {
    1233             : 
    1234           1 :                                 td3 = thisConstruct.tBareSolDiff(3);
    1235           1 :                                 td3v = thisConstruct.tBareVisDiff(3);
    1236           1 :                                 afd3 = thisConstruct.afBareSolDiff(3);
    1237           1 :                                 abd3 = thisConstruct.abBareSolDiff(3);
    1238           1 :                                 rb3 = thisConstruct.rbBareSolDiff(3);
    1239           1 :                                 rb3v = thisConstruct.rbBareVisDiff(3);
    1240           1 :                                 rf3 = thisConstruct.rfBareSolDiff(3);
    1241           1 :                                 rf3v = thisConstruct.rfBareVisDiff(3);
    1242             : 
    1243             :                                 // Front incident solar, beam, between-glass shade, NGlass = 3
    1244             : 
    1245          11 :                                 for (int IPhi = 1; IPhi <= 10; ++IPhi) {
    1246          10 :                                     t1 = tBareSolPhi(1, IPhi);
    1247          10 :                                     t1v = tBareVisPhi(1, IPhi);
    1248          10 :                                     t2 = tBareSolPhi(2, IPhi);
    1249          10 :                                     t2v = tBareVisPhi(2, IPhi);
    1250          10 :                                     af1 = afBareSolPhi(1, IPhi);
    1251          10 :                                     af2 = afBareSolPhi(2, IPhi);
    1252          10 :                                     ab1 = abBareSolPhi(1, IPhi);
    1253          10 :                                     ab2 = abBareSolPhi(2, IPhi);
    1254          10 :                                     rbmf2 = max(0.0, 1.0 - (t2 + af2));
    1255             : 
    1256          10 :                                     tsolPhi(IPhi) = t1 * t2 * (tsh + tsh * rf3 * rsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh) * td3;
    1257          20 :                                     tvisPhi(IPhi) =
    1258          10 :                                         t1v * t2v * (tshv + tshv * rf3v * rshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv) * td3v;
    1259          10 :                                     solabsShadePhi(IPhi) = t1 * t2 * (1 + rsh * td2 * rb1 * td2 + rsh * rb2) * ash;
    1260          20 :                                     solabsPhi(1, IPhi) =
    1261          10 :                                         af1 + rbmf2 * ab1 + t1 * t2 * rsh * (1 + rf3 * tsh + rb2 * rsh + td2 * rb1 * td2 * rsh) * td2 * abd1;
    1262          20 :                                     solabsPhi(2, IPhi) =
    1263          10 :                                         t1 * af2 + t1 * t2 * ((rsh + tsh * rf3 * tsh + rsh * rb2 * rsh) * abd2 + rsh * td2 * rb1 * afd2);
    1264          10 :                                     solabsPhi(3, IPhi) = t1 * t2 * (tsh + rsh * (rb2 * tsh + td2 * rb2 * td2 * tsh + rf3 * rsh)) * afd3;
    1265             :                                 } // End of loop over incidence angle
    1266             : 
    1267             :                                 // Front incident solar, diffuse, between-glass shade, NGlass = 3
    1268             : 
    1269           1 :                                 thisConstruct.TransDiff = td1 * td2 * (tsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh + tsh * rf3 * rsh) * td3;
    1270           1 :                                 thisConstruct.TransDiffVis =
    1271           1 :                                     td1v * td2v * (tshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv + tshv * rf3v * rshv) * td3v;
    1272           1 :                                 thisConstruct.AbsDiffShade = td1 * td2 * (ash * (1 + rsh * td2 * rb1 * td2 + rsh * rb2 * ash) + tsh * rf3 * ash);
    1273           2 :                                 thisConstruct.AbsDiff(1) =
    1274           1 :                                     afd1 + td1 * (rf2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh + rsh * td2 * rb1 * td2 * rsh) * td2) * abd1;
    1275           1 :                                 thisConstruct.AbsDiff(2) = td1 * (afd2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh) * abd2);
    1276           1 :                                 thisConstruct.AbsDiff(3) = td1 * td2 * (tsh + rsh * rb2 * tsh + rsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rsh) * afd3;
    1277           1 :                                 thisConstruct.ReflectSolDiffFront =
    1278           1 :                                     rf1 + td1 * rf2 * td1 +
    1279           1 :                                     td1 * td2 * (rsh + tsh * rf3 * tsh + rsh * rb2 * rsh + rsh * td2 * rb1 * td2 * rsh) * td2 * td1;
    1280           1 :                                 thisConstruct.ReflectVisDiffFront =
    1281           1 :                                     rf1v + td1v * rf2v * td1v +
    1282           1 :                                     td1v * td2v * (rshv + tshv * rf3v * tshv + rshv * rb2v * rshv + rshv * td2v * rb1v * td2v * rshv) * td2v * td1v;
    1283             : 
    1284             :                                 // Back incident solar, diffuse, between-glass shade, NGlass = 3
    1285             : 
    1286           1 :                                 thisConstruct.AbsDiffBackShade = td3 * ((1 + rsh * rf3) * ash + (tsh * td2 * rb1 * td2 + tsh * rb2) * ash);
    1287           2 :                                 thisConstruct.AbsDiffBack(1) =
    1288           1 :                                     td3 * (tsh + rsh * rf3 * tsh + tsh * rb2 * rsh + tsh * td2 * rb1 * td2 * rsh) * td2 * abd1;
    1289           1 :                                 thisConstruct.AbsDiffBack(2) = td3 * ((tsh + rsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
    1290           1 :                                 thisConstruct.AbsDiffBack(3) = abd3 + td3 * (rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
    1291           1 :                                 thisConstruct.ReflectSolDiffBack =
    1292           1 :                                     rb3 + td3 * (rsh + rsh * rf3 * rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
    1293           1 :                                 thisConstruct.ReflectVisDiffBack =
    1294           1 :                                     rb3v + td3v * (rshv + rshv * rf3 * rshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
    1295             : 
    1296             :                             } // End of check if NGlass = 3
    1297             : 
    1298             :                         } // End of check if between-glass shade
    1299             : 
    1300           5 :                         if (BGBlind) {
    1301             : 
    1302           3 :                             if (NGlass == 2) {
    1303             : 
    1304             :                                 // Front incident solar, diffuse, between-glass blind, NGlass = 2
    1305             : 
    1306           2 :                                 thisConstruct.BlAbsDiff(ISlatAng, 1) = afd1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rb2 * tsh) * abd1;
    1307           4 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, 1) =
    1308           2 :                                     afd1 + td1 * (rfshGnd + rfshGnd * rb1 * rfshGnd + tshGnd * rb2 * tsh) * abd1;
    1309           4 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, 1) =
    1310           2 :                                     afd1 + td1 * (rfshSky + rfshSky * rb1 * rfshSky + tshSky * rb2 * tsh) * abd1;
    1311           2 :                                 thisConstruct.BlAbsDiff(ISlatAng, 2) = td1 * (tsh + rfsh * rb1 * tsh + tsh * rf2 * rbsh) * afd2;
    1312           2 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, 2) = td1 * (tshGnd + rfshGnd * rb1 * tsh + tshGnd * rf2 * rbsh) * afd2;
    1313           2 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, 2) = td1 * (tshSky + rfshSky * rb1 * tsh + tshSky * rf2 * rbsh) * afd2;
    1314           2 :                                 thisConstruct.AbsDiffBlind(ISlatAng) = td1 * (afsh + rfsh * rb1 * afsh + tsh * rf2 * absh);
    1315           2 :                                 thisConstruct.AbsDiffBlindGnd(ISlatAng) = td1 * (afshGnd + rfsh * rb1 * afsh + tshGnd * rf2 * absh);
    1316           2 :                                 thisConstruct.AbsDiffBlindSky(ISlatAng) = td1 * (afshSky + rfsh * rb1 * afsh + tshSky * rf2 * absh);
    1317           2 :                                 thisConstruct.BlTransDiff(ISlatAng) = td1 * (tsh + rfsh * rb1 * tsh + tsh * rb2 * rbsh) * td2;
    1318           2 :                                 thisConstruct.BlTransDiffGnd(ISlatAng) = td1 * (tshGnd + rfsh * rb1 * tshGnd + tshGnd * rb2 * rbsh) * td2;
    1319           2 :                                 thisConstruct.BlTransDiffSky(ISlatAng) = td1 * (tshSky + rfsh * rb1 * tshSky + tshSky * rb2 * rbsh) * td2;
    1320           2 :                                 thisConstruct.BlTransDiffVis(ISlatAng) = td1v * (tshv + rfshv * rb1v * tshv + tshv * rb2v * rbshv) * td2v;
    1321           2 :                                 thisConstruct.BlReflectSolDiffFront(ISlatAng) = rf1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rf2 * tsh) * td1;
    1322           4 :                                 thisConstruct.BlReflectVisDiffFront(ISlatAng) =
    1323           2 :                                     rf1v + td1v * (rfshv + rfshv * rb1v * rfshv + tshv * rf2v * tshv) * td1v;
    1324             : 
    1325             :                                 // Back incident solar, diffuse, between-glass blind, NGlass = 2
    1326             : 
    1327           2 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, 1) = td2 * (tsh + rbsh * rf2 * tsh + tsh * rb1 * rfsh) * abd1;
    1328           2 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, 2) = abd2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * afd2;
    1329           2 :                                 thisConstruct.AbsDiffBackBlind(ISlatAng) = td2 * (absh + rbsh * rf2 * absh + tsh * rb1 * afsh);
    1330           2 :                                 thisConstruct.BlReflectSolDiffBack(ISlatAng) = rb2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * td2;
    1331           2 :                                 thisConstruct.BlReflectVisDiffBack(ISlatAng) =
    1332           2 :                                     rb2v + td2v * (rbshv + rbshv * rf2v * rbshv + tshv * rb1v * tshv) * td2v;
    1333             : 
    1334             :                             } // End of check if NGlass = 2
    1335             : 
    1336           3 :                             if (NGlass == 3) {
    1337             : 
    1338           1 :                                 td3 = thisConstruct.tBareSolDiff(3);
    1339           1 :                                 td3v = thisConstruct.tBareVisDiff(3);
    1340           1 :                                 afd3 = thisConstruct.afBareSolDiff(3);
    1341           1 :                                 abd3 = thisConstruct.abBareSolDiff(3);
    1342           1 :                                 rb3 = thisConstruct.rbBareSolDiff(3);
    1343           1 :                                 rb3v = thisConstruct.rbBareVisDiff(3);
    1344           1 :                                 rf3 = thisConstruct.rfBareSolDiff(3);
    1345           1 :                                 rf3v = thisConstruct.rfBareVisDiff(3);
    1346             : 
    1347             :                                 // Front incident solar, diffuse, between-glass blind, NGlass = 3
    1348             : 
    1349           2 :                                 thisConstruct.BlAbsDiff(ISlatAng, 1) =
    1350           1 :                                     afd1 +
    1351           1 :                                     td1 * (rf2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh + rfsh * td2 * rb1 * td2 * rfsh) * td2) * abd1;
    1352           2 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, 1) =
    1353           1 :                                     afd1 +
    1354           1 :                                     td1 *
    1355           1 :                                         (rf2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh + rfshGnd * td2 * rb1 * td2 * rfsh) * td2) *
    1356             :                                         abd1;
    1357           2 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, 1) =
    1358           1 :                                     afd1 +
    1359           1 :                                     td1 *
    1360           1 :                                         (rf2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh + rfshSky * td2 * rb1 * td2 * rfsh) * td2) *
    1361             :                                         abd1;
    1362           1 :                                 thisConstruct.BlAbsDiff(ISlatAng, 2) = td1 * (afd2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh) * abd2);
    1363           2 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, 2) =
    1364           1 :                                     td1 * (afd2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh) * abd2);
    1365           2 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, 2) =
    1366           1 :                                     td1 * (afd2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh) * abd2);
    1367           2 :                                 thisConstruct.BlAbsDiff(ISlatAng, 3) =
    1368           1 :                                     td1 * td2 * (tsh + rfsh * rb2 * tsh + rfsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rbsh) * afd3;
    1369           2 :                                 thisConstruct.BlAbsDiffGnd(ISlatAng, 3) =
    1370           1 :                                     td1 * td2 * (tshGnd + rfshGnd * rb2 * tsh + rfshGnd * td2 * rb1 * td2 * tsh + tshGnd * rf3 * rbsh) * afd3;
    1371           2 :                                 thisConstruct.BlAbsDiffSky(ISlatAng, 3) =
    1372           1 :                                     td1 * td2 * (tshSky + rfshSky * rb2 * tsh + rfshSky * td2 * rb1 * td2 * tsh + tshSky * rf3 * rbsh) * afd3;
    1373           2 :                                 thisConstruct.AbsDiffBlind(ISlatAng) =
    1374           1 :                                     td1 * td2 * (afsh * (1 + rfsh * td2 * rb1 * td2) + rfsh * rb2 * afsh + tsh * rf3 * absh);
    1375           2 :                                 thisConstruct.AbsDiffBlindGnd(ISlatAng) =
    1376           1 :                                     td1 * td2 * (afshGnd + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshGnd * rf3 * absh);
    1377           2 :                                 thisConstruct.AbsDiffBlindSky(ISlatAng) =
    1378           1 :                                     td1 * td2 * (afshSky + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshSky * rf3 * absh);
    1379           2 :                                 thisConstruct.BlTransDiff(ISlatAng) =
    1380           1 :                                     td1 * td2 * (tsh + rfsh * td2 * rb1 * td2 * tsh + rfsh * rb2 * tsh + tsh * rf3 * rbsh) * td3;
    1381           2 :                                 thisConstruct.BlTransDiffGnd(ISlatAng) =
    1382           1 :                                     td1 * td2 * (tshGnd + rfsh * td2 * rb1 * td2 * tshGnd + rfsh * rb2 * tshGnd + tshGnd * rf3 * rbsh) * td3;
    1383           2 :                                 thisConstruct.BlTransDiffSky(ISlatAng) =
    1384           1 :                                     td1 * td2 * (tshSky + rfsh * td2 * rb1 * td2 * tshSky + rfsh * rb2 * tshSky + tshSky * rf3 * rbsh) * td3;
    1385           2 :                                 thisConstruct.BlTransDiffVis(ISlatAng) =
    1386           1 :                                     td1v * td2v * (tshv + rfshv * td2v * rb1v * td2v * tshv + rfshv * rb2v * tshv + tshv * rf3v * rbshv) * td3v;
    1387           2 :                                 thisConstruct.BlReflectSolDiffFront(ISlatAng) =
    1388           1 :                                     rf1 + td1 * rf2 * td1 +
    1389           1 :                                     td1 * td2 * (rfsh + tsh * rf3 * tsh + rfsh * rb2 * rfsh + rfsh * td2 * rb1 * td2 * rfsh) * td2 * td1;
    1390           2 :                                 thisConstruct.BlReflectVisDiffFront(ISlatAng) =
    1391           1 :                                     rf1v + td1v * rf2v * td1v +
    1392           1 :                                     td1v * td2v * (rfshv + tshv * rf3v * tshv + rfshv * rb2v * rfshv + rfshv * td2v * rb1v * td2v * rfshv) * td2v *
    1393             :                                         td1v;
    1394             : 
    1395             :                                 // Back incident solar, diffuse, between-glass blind, NGlass = 3
    1396             : 
    1397           2 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, 1) =
    1398           1 :                                     td3 * (tsh + rbsh * rf3 * tsh + tsh * rb2 * rfsh + tsh * td2 * rb1 * td2 * rfsh) * td2 * abd1;
    1399           2 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, 2) =
    1400           1 :                                     td3 * ((tsh + rbsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
    1401           1 :                                 thisConstruct.BlAbsDiffBack(ISlatAng, 3) = abd3 + td3 * (rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
    1402           2 :                                 thisConstruct.AbsDiffBackBlind(ISlatAng) =
    1403           1 :                                     td3 * ((1 + rbsh * rf3) * absh + (tsh * td2 * rb1 * td2 + tsh * rb2) * afsh);
    1404           2 :                                 thisConstruct.BlReflectSolDiffBack(ISlatAng) =
    1405           1 :                                     rb3 + td3 * (rbsh + rbsh * rf3 * rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
    1406           1 :                                 thisConstruct.BlReflectVisDiffBack(ISlatAng) =
    1407           1 :                                     rb3v + td3v * (rbshv + rbshv * rf3v * rbshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
    1408             : 
    1409             :                             } // End of check if NGlass = 3
    1410             : 
    1411             :                         } // End of check if between-glass blind
    1412             : 
    1413             :                     } // End of check if between-glass shade or blind
    1414             : 
    1415             :                     // Continue loop over slat angles only for blinds with variable slat angle
    1416         588 :                     if (ShadeOn || ScreenOn) break;
    1417         557 :                     if (BlindOn) {
    1418         557 :                         auto const &blind = state.dataMaterial->Blind(BlNum);
    1419         557 :                         if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
    1420             :                     }
    1421             :                 } // End of slat angle loop
    1422             :             }     // End of check if construction has a shade or blind
    1423             : 
    1424             :             // Curve fits to get solar transmittance, reflectance, layer absorptance and
    1425             :             // visible transmittance as polynomials in cosine of incidence angle
    1426             : 
    1427        1348 :             if (!BlindOn && !ScreenOn) { // Bare glass or shade on
    1428        1329 :                 W5LsqFit(CosPhiIndepVar, tsolPhi, 6, 1, TotalIPhi, thisConstruct.TransSolBeamCoef);
    1429        1329 :                 W5LsqFit(CosPhiIndepVar, rfsolPhi, 6, 1, TotalIPhi, thisConstruct.ReflSolBeamFrontCoef);
    1430        1329 :                 W5LsqFit(CosPhiIndepVar, rbsolPhi, 6, 1, TotalIPhi, thisConstruct.ReflSolBeamBackCoef);
    1431        1329 :                 W5LsqFit(CosPhiIndepVar, tvisPhi, 6, 1, TotalIPhi, thisConstruct.TransVisBeamCoef);
    1432        1329 :                 Array1D<Real64> DepVarCurveFit(TotalIPhi);
    1433        1329 :                 Array1D<Real64> CoeffsCurveFit(6);
    1434             : 
    1435        3318 :                 for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
    1436             :                     // Front absorptance coefficients for glass layers
    1437        1989 :                     DepVarCurveFit = solabsPhi(IGlass, {1, TotalIPhi});
    1438        1989 :                     W5LsqFit(CosPhiIndepVar, DepVarCurveFit, 6, 1, TotalIPhi, CoeffsCurveFit);
    1439        1989 :                     thisConstruct.AbsBeamCoef(IGlass) = CoeffsCurveFit;
    1440             :                     // Back absorptance coefficients for glass layers
    1441        1989 :                     IGlassBack = NGlass - IGlass + 1;
    1442        1989 :                     DepVarCurveFit = solabsBackPhi(IGlassBack, {1, TotalIPhi});
    1443        1989 :                     W5LsqFit(CosPhiIndepVar, DepVarCurveFit, 6, 1, TotalIPhi, CoeffsCurveFit);
    1444        1989 :                     thisConstruct.AbsBeamBackCoef(IGlass) = CoeffsCurveFit;
    1445             :                 }
    1446             : 
    1447             :                 // To check goodness of fit //Tuned
    1448             : 
    1449       14619 :                 for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
    1450       13290 :                     tsolPhiFit(IPhi) = 0.0;
    1451       13290 :                     tvisPhiFit(IPhi) = 0.0;
    1452             : 
    1453       13290 :                     Phi = double(IPhi - 1) * 10.0;
    1454       13290 :                     CosPhi = std::cos(Phi * Constant::DegToRadians);
    1455       13290 :                     if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
    1456       13290 :                     Real64 cos_pow(1.0);
    1457       93030 :                     for (int CoefNum = 1; CoefNum <= 6; ++CoefNum) {
    1458       79740 :                         cos_pow *= CosPhi;
    1459       79740 :                         tsolPhiFit(IPhi) += thisConstruct.TransSolBeamCoef(CoefNum) * cos_pow;
    1460       79740 :                         tvisPhiFit(IPhi) += thisConstruct.TransVisBeamCoef(CoefNum) * cos_pow;
    1461             :                     }
    1462             :                 }
    1463        1329 :             }
    1464             : 
    1465        1348 :             if (ShadeOn) W5LsqFit(CosPhiIndepVar, solabsShadePhi, 6, 1, TotalIPhi, thisConstruct.AbsBeamShadeCoef);
    1466             : 
    1467             :         } // End of loop over constructions
    1468             : 
    1469             :         // Get effective glass and shade/blind emissivities for windows that have interior blind or
    1470             :         // shade. These are used to calculate zone MRT contribution from window when
    1471             :         // interior blind/shade is deployed.
    1472             : 
    1473             :         // Loop for ordinary windows
    1474       46816 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1475       46023 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    1476       46023 :             if (!surf.HeatTransSurf) continue;
    1477       44369 :             if (!state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    1478        6216 :             if (state.dataSurface->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) continue; // Irrelevant for Complex Fen
    1479        6216 :             if (state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) continue;      // not required
    1480        6213 :             ConstrNumSh = surf.activeShadedConstruction;
    1481        6213 :             if (ConstrNumSh == 0) continue;
    1482         149 :             TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    1483         149 :             IntShade = false;
    1484         149 :             IntBlind = false;
    1485         149 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild *>(
    1486         149 :                 state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay)));
    1487         149 :             assert(thisMaterial != nullptr);
    1488         149 :             if (thisMaterial->group == Material::Group::Shade) {
    1489          48 :                 IntShade = true;
    1490          48 :                 ShadeLayPtr = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay);
    1491             :             }
    1492         149 :             if (thisMaterial->group == Material::Group::WindowBlind) {
    1493          34 :                 IntBlind = true;
    1494          34 :                 BlNum = thisMaterial->BlindDataPtr;
    1495             :             }
    1496             : 
    1497         149 :             if (IntShade || IntBlind) {
    1498         444 :                 for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
    1499         442 :                     if (IntShade || IntBlind) {
    1500         442 :                         EpsGlIR = dynamic_cast<Material::MaterialChild const *>(
    1501         442 :                                       state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1)))
    1502             :                                       ->AbsorpThermalBack;
    1503         442 :                         RhoGlIR = 1 - EpsGlIR;
    1504             :                     }
    1505         442 :                     if (IntShade) {
    1506          48 :                         auto const *thisMaterialShade = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(ShadeLayPtr));
    1507          48 :                         TauShIR = thisMaterialShade->TransThermal;
    1508          48 :                         EpsShIR = thisMaterialShade->AbsorpThermal;
    1509          48 :                         RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
    1510          48 :                         state.dataSurface->SurfaceWindow(SurfNum).EffShBlindEmiss[1] =
    1511          48 :                             EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
    1512          48 :                         state.dataSurface->SurfaceWindow(SurfNum).EffGlassEmiss[1] = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
    1513             :                     }
    1514         442 :                     if (IntBlind) {
    1515         394 :                         auto const &blind = state.dataMaterial->Blind(BlNum);
    1516         394 :                         TauShIR = blind.IRFrontTrans(ISlatAng);
    1517         394 :                         EpsShIR = blind.IRBackEmiss(ISlatAng);
    1518         394 :                         RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
    1519         394 :                         state.dataSurface->SurfaceWindow(SurfNum).EffShBlindEmiss[ISlatAng] =
    1520         394 :                             EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
    1521         394 :                         state.dataSurface->SurfaceWindow(SurfNum).EffGlassEmiss[ISlatAng] = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
    1522             :                     }
    1523             :                     // Loop over remaining slat angles only if blind with movable slats
    1524         442 :                     if (IntShade) break; // Loop over remaining slat angles only if blind
    1525         394 :                     if (IntBlind) {
    1526         394 :                         auto const &blind = state.dataMaterial->Blind(BlNum);
    1527             : 
    1528         394 :                         if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
    1529             :                     }
    1530             :                 } // End of slat angle loop
    1531             :             }     // End of check if interior shade or interior blind
    1532             :         }         // End of surface loop
    1533             : 
    1534       46816 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1535       46023 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    1536       46023 :             if (surf.Construction <= 0) continue;
    1537       44387 :             auto const &construct = state.dataConstruction->Construct(surf.Construction);
    1538       44387 :             if (!construct.TypeIsWindow) continue;
    1539             : 
    1540             :             // Total thickness of glazing system (used in calculation of inside reveal reflection/absorption
    1541        6216 :             state.dataSurface->SurfWinTotGlazingThickness(SurfNum) = 0.0;
    1542       16548 :             for (int LayNum = 1; LayNum <= construct.TotLayers; ++LayNum) {
    1543       10332 :                 state.dataSurface->SurfWinTotGlazingThickness(SurfNum) += state.dataMaterial->Material(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        6216 :             Rectangle = false;
    1559        6216 :             Triangle = false;
    1560        6216 :             if (surf.Sides == 3) Triangle = true;
    1561        6216 :             if (surf.Sides == 4) Rectangle = true;
    1562        6216 :             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        6214 :                 W3 = surf.Vertex(2);
    1566        6214 :                 W2 = surf.Vertex(3);
    1567        6214 :                 W1 = surf.Vertex(4);
    1568           2 :             } else if (Triangle) {
    1569           2 :                 W3 = surf.Vertex(2);
    1570           2 :                 W2 = surf.Vertex(3);
    1571           2 :                 W1 = surf.Vertex(1);
    1572             :             }
    1573        6216 :             W21 = W1 - W2;
    1574        6216 :             W23 = W3 - W2;
    1575        6216 :             if (Rectangle) {
    1576        6214 :                 state.dataSurface->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 2.0;
    1577           2 :             } else if (Triangle) {
    1578           2 :                 state.dataSurface->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 3.0;
    1579             :             }
    1580             :         } // End of surface loop
    1581             : 
    1582         793 :         ReportGlass(state);
    1583         793 :     } // InitGlassOpticalCalculations()
    1584             : 
    1585             :     //*****************************************************************************************
    1586             : 
    1587         793 :     void W5InitGlassParameters(EnergyPlusData &state)
    1588             :     {
    1589             :         // Initializes variables used in the window optical and thermal calculation.
    1590             : 
    1591             :         int ConstrNum;        // Construction number
    1592             :         int FrDivNum;         // Pointer to frame/divider
    1593             :         Real64 FrWidth;       // Window frame width {m}
    1594             :         Real64 FrEdgeWidth;   // Frame edge width {m}
    1595             :         Real64 DivWidth;      // Window divider width {m}
    1596             :         Real64 DivEdgeWidth;  // Divider edge width {m}
    1597             :         Real64 GlHeight;      // Height of glazed part of window {m}
    1598             :         Real64 GlWidth;       // Width of glazed part of window {m}
    1599             :         int NumHorDividers;   // Number of horizontal divider elements
    1600             :         int NumVertDividers;  // Number of vertical divider elements
    1601             :         int BaseSurfNum;      // Base surface number
    1602             :         int MatNum;           // Material number
    1603             :         int DifOverrideCount; // Count the number of SolarDiffusing material overrides
    1604             : 
    1605         793 :         auto &wm = state.dataWindowManager;
    1606             : 
    1607        6820 :         for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
    1608        6027 :             auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
    1609        6027 :             if (thisConstruct.FromWindow5DataFile) continue;
    1610        6022 :             if (thisConstruct.WindowTypeBSDF) continue;
    1611        6009 :             thisConstruct.TransDiff = 0.0;
    1612        6009 :             thisConstruct.TransDiffVis = 0.0;
    1613        6009 :             thisConstruct.AbsDiffBackShade = 0.0;
    1614        6009 :             thisConstruct.ShadeAbsorpThermal = 0.0;
    1615        6009 :             thisConstruct.ReflectSolDiffBack = 0.0;
    1616        6009 :             thisConstruct.ReflectSolDiffFront = 0.0;
    1617        6009 :             thisConstruct.ReflectVisDiffFront = 0.0;
    1618        6009 :             thisConstruct.AbsBeamShadeCoef = 0.0;
    1619        6009 :             thisConstruct.TransSolBeamCoef = 0.0;
    1620        6009 :             thisConstruct.ReflSolBeamFrontCoef = 0.0;
    1621        6009 :             thisConstruct.ReflSolBeamBackCoef = 0.0;
    1622        6009 :             thisConstruct.TransVisBeamCoef = 0.0;
    1623        6009 :             thisConstruct.AbsDiff = 0.0;
    1624        6009 :             thisConstruct.AbsDiffBack = 0.0;
    1625       48244 :             for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
    1626      295645 :                 for (int index = 1; index <= DataSurfaces::MaxPolyCoeff; ++index) {
    1627      253410 :                     state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamCoef(Layer)(index) = 0.0;
    1628      253410 :                     state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamBackCoef(Layer)(index) = 0.0;
    1629             :                 }
    1630             :             }
    1631             :         }
    1632             : 
    1633       46816 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1634             :             // For a window with shading device, get number of shaded construction and, if window
    1635             :             // has a blind (interior, exterior or between glass), get blind data pointer.
    1636       46023 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    1637       46023 :             if (surf.HasShadeControl) {
    1638         294 :                 for (int winShadCtrl : surf.windowShadingControlList) {
    1639         153 :                     WinShadingType ShadingType = state.dataSurface->WindowShadingControl(winShadCtrl).ShadingType;
    1640         153 :                     if (ShadingType == WinShadingType::ExtScreen) {
    1641             :                         //     Count number of exterior window screens, initialize in InitGlassOpticalCalculations after returning
    1642             :                         //     from this subroutine. The blind structure is initialized first and then the screen structure is initialized.
    1643           8 :                         ++state.dataHeatBal->NumScreens;
    1644           8 :                         break; // only need to find the first window shading control since they should be identical
    1645             :                     }
    1646         149 :                 }
    1647             :             }
    1648             :         }
    1649             : 
    1650             :         // Set some static exterior-window frame and divider SurfaceWindow values
    1651             :         // from values in FrameDivider derived type
    1652       46816 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1653       46023 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    1654       46023 :             if (surf.FrameDivider == 0) continue;
    1655             : 
    1656         381 :             auto &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
    1657         381 :             auto const &frdiv = state.dataSurface->FrameDivider(surf.FrameDivider);
    1658             : 
    1659         381 :             FrWidth = frdiv.FrameWidth;
    1660         381 :             GlHeight = surf.Height;
    1661         381 :             GlWidth = surf.Width;
    1662         381 :             NumVertDividers = frdiv.VertDividers;
    1663         381 :             NumHorDividers = frdiv.HorDividers;
    1664         381 :             BaseSurfNum = surf.BaseSurf;
    1665         381 :             state.dataSurface->SurfWinFrameConductance(SurfNum) = frdiv.FrameConductance;
    1666         381 :             state.dataSurface->SurfWinFrameSolAbsorp(SurfNum) = frdiv.FrameSolAbsorp;
    1667         381 :             state.dataSurface->SurfWinFrameVisAbsorp(SurfNum) = frdiv.FrameVisAbsorp;
    1668         381 :             state.dataSurface->SurfWinFrameEmis(SurfNum) = frdiv.FrameEmis;
    1669         381 :             state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) = frdiv.FrEdgeToCenterGlCondRatio;
    1670         381 :             state.dataSurface->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::DividedLite;
    1671         381 :             if (frdiv.DividerType == DataSurfaces::FrameDividerType::Suspended)
    1672          11 :                 state.dataSurface->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::Suspended;
    1673         381 :             DivWidth = frdiv.DividerWidth;
    1674         381 :             state.dataSurface->SurfWinDividerConductance(SurfNum) = frdiv.DividerConductance;
    1675         381 :             state.dataSurface->SurfWinDividerSolAbsorp(SurfNum) = frdiv.DividerSolAbsorp;
    1676         381 :             state.dataSurface->SurfWinDividerVisAbsorp(SurfNum) = frdiv.DividerVisAbsorp;
    1677         381 :             state.dataSurface->SurfWinDividerEmis(SurfNum) = frdiv.DividerEmis;
    1678         381 :             state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) = frdiv.DivEdgeToCenterGlCondRatio;
    1679             : 
    1680         381 :             state.dataSurface->SurfWinOutsideRevealSolAbs(SurfNum) = frdiv.OutsideRevealSolAbs;
    1681         381 :             state.dataSurface->SurfWinInsideSillDepth(SurfNum) = frdiv.InsideSillDepth;
    1682         381 :             state.dataSurface->SurfWinInsideReveal(SurfNum) = frdiv.InsideReveal;
    1683         381 :             state.dataSurface->SurfWinInsideSillSolAbs(SurfNum) = frdiv.InsideSillSolAbs;
    1684         381 :             state.dataSurface->SurfWinInsideRevealSolAbs(SurfNum) = frdiv.InsideRevealSolAbs;
    1685             : 
    1686         381 :             FrEdgeWidth = frdiv.FrameEdgeWidth;
    1687         381 :             DivEdgeWidth = frdiv.DividerEdgeWidth;
    1688         381 :             state.dataSurface->SurfWinFrameEdgeArea(SurfNum) =
    1689         381 :                 2 * FrEdgeWidth * (GlHeight - FrEdgeWidth - NumHorDividers * DivWidth + GlWidth - FrEdgeWidth - NumVertDividers * DivWidth);
    1690         381 :             state.dataSurface->SurfWinDividerEdgeArea(SurfNum) =
    1691         762 :                 2 * DivEdgeWidth * (NumHorDividers * (GlWidth - 2 * FrEdgeWidth) + NumVertDividers * (GlHeight - 2 * FrEdgeWidth)) -
    1692         381 :                 NumHorDividers * NumVertDividers * (4 * pow_2(DivEdgeWidth) + 4 * FrEdgeWidth * DivWidth);
    1693         381 :             surfWin.centerGlassArea =
    1694         381 :                 surf.Area - state.dataSurface->SurfWinFrameEdgeArea(SurfNum) - state.dataSurface->SurfWinDividerEdgeArea(SurfNum);
    1695         381 :             surfWin.edgeGlassCorrFac =
    1696         381 :                 (state.dataSurface->SurfWinFrameEdgeArea(SurfNum) * state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) +
    1697         381 :                  state.dataSurface->SurfWinDividerEdgeArea(SurfNum) * state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) +
    1698         762 :                  surfWin.centerGlassArea) /
    1699         381 :                 (state.dataSurface->SurfWinFrameEdgeArea(SurfNum) + state.dataSurface->SurfWinDividerEdgeArea(SurfNum) + surfWin.centerGlassArea);
    1700             :         } // for (SurfNum)
    1701             : 
    1702             :         // Set SolarDiffusing to true for exterior windows that have a construction with an innermost diffusing glass layer
    1703         793 :         DifOverrideCount = 0;
    1704       46816 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1705       46023 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    1706       46023 :             state.dataSurface->SurfWinSolarDiffusing(SurfNum) = false;
    1707       52223 :             if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != ExternalEnvironment ||
    1708        6200 :                 state.dataSurface->SurfWinStormWinConstr(SurfNum) != 0)
    1709       39824 :                 continue;
    1710             : 
    1711        6199 :             ConstrNum = surf.Construction;
    1712        6199 :             MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
    1713        6199 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(MatNum));
    1714        6199 :             assert(thisMaterial != nullptr);
    1715             : 
    1716        6199 :             if (!thisMaterial->SolarDiffusing) continue;
    1717             : 
    1718           0 :             if (!surf.HasShadeControl) {
    1719           0 :                 state.dataSurface->SurfWinSolarDiffusing(SurfNum) = true;
    1720             :             } else { // There is a shading control
    1721           0 :                 if (state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) {
    1722           0 :                     state.dataSurface->SurfWinSolarDiffusing(SurfNum) = true;
    1723             :                 } else {
    1724           0 :                     state.dataSurface->SurfWinSolarDiffusing(SurfNum) = false;
    1725           0 :                     ++DifOverrideCount;
    1726           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    1727           0 :                         ShowWarningError(state,
    1728           0 :                                          format("W5InitGlassParameters: Window=\"{}\" has interior material with Solar Diffusing=Yes, but "
    1729             :                                                 "existing Window Shading Device sets Diffusing=No.",
    1730           0 :                                                 surf.Name));
    1731             :                     }
    1732             :                 }
    1733             :             }
    1734             :         } // for (SurfNum)
    1735             : 
    1736         793 :         if (DifOverrideCount > 0) {
    1737           0 :             if (!state.dataGlobal->DisplayExtraWarnings) {
    1738           0 :                 ShowWarningError(state,
    1739           0 :                                  format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
    1740             :                                         DifOverrideCount));
    1741             :             } else {
    1742           0 :                 ShowMessage(state,
    1743           0 :                             format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
    1744             :                                    DifOverrideCount));
    1745             :             }
    1746             :         }
    1747         793 :     } // W5InitGlassParameters()
    1748             : 
    1749             :     //****************************************************************************
    1750             :     // WINDOW 5 Optical Calculation Subroutines
    1751             :     //****************************************************************************
    1752             : 
    1753       39830 :     void SystemSpectralPropertiesAtPhi(EnergyPlusData &state,
    1754             :                                        int const iquasi,   // When there is no spectral data, this is the wavelength
    1755             :                                        int const ngllayer, // Number of glass layers in construction
    1756             :                                        Real64 const wlbot, // Lowest and highest wavelength considered
    1757             :                                        Real64 const wltop,
    1758             :                                        std::array<int, maxGlassLayers> const &numpt,
    1759             :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &wlt,
    1760             :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &tPhi,
    1761             :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rfPhi,
    1762             :                                        std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rbPhi,
    1763             :                                        std::array<Real64, nume> &stPhi,
    1764             :                                        std::array<Real64, nume> &srfPhi,
    1765             :                                        std::array<Real64, nume> &srbPhi,
    1766             :                                        Array2D<Real64> &saPhi)
    1767             :     {
    1768             : 
    1769             :         // SUBROUTINE INFORMATION:
    1770             :         //       AUTHOR         Adapted by F.Winkelmann from WINDOW 5
    1771             :         //                      subroutine opcalc
    1772             :         //       DATE WRITTEN   August 1999
    1773             :         //       MODIFIED       na
    1774             :         //       RE-ENGINEERED  na
    1775             : 
    1776             :         // PURPOSE OF THIS SUBROUTINE:
    1777             :         // For a particular angle of incidence, calculates system properties
    1778             :         // for a multi-layer glazing for each wavelength in the solar spectrum.
    1779             :         // Handles the special case of one or more layers that do not have spectral data.
    1780             : 
    1781             :         // Returns, for a particular angle of incidence:
    1782             :         //   stPhi     transmissivity of system at each wavelength in swl
    1783             :         //   srfPhi    front reflectance of system at each wavelength in swl
    1784             :         //   srbPhi    back reflectance of system at each wavelength in swl
    1785             :         //   sabsPhi   absorptance by layer at each wavelength in swl
    1786             : 
    1787       39830 :         Array1D<Real64> sabsPhi(5); // System solar absorptance in each glass layer for
    1788             :         //   particular angle of incidence
    1789             : 
    1790             :         // transmittance at angle of incidence
    1791       39830 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tadjPhi = {0.0};
    1792             :         // front reflectance at angle of incidence
    1793       39830 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfadjPhi = {0.0};
    1794             :         // back reflectance at angle of incidence
    1795       39830 :         std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbadjPhi = {0.0};
    1796             : 
    1797       39830 :         auto &wm = state.dataWindowManager;
    1798             :         // For each glass layer find tPhi, rfPhi, and rbPhi at each wavelength
    1799             : 
    1800       98430 :         for (int in = 1; in <= ngllayer; ++in) {
    1801     6328800 :             for (int iwl = 1; iwl <= nume; ++iwl) {
    1802     6270200 :                 Real64 wl = wm->wle[iwl - 1];
    1803     6270200 :                 if (wl < wlbot || wl > wltop) continue;
    1804             :                 // In the following numpt is the number of spectral data points for each layer;
    1805             :                 // numpt = 2 if there is no spectral data for a layer.
    1806     4949720 :                 if (numpt[in - 1] <= 2) {
    1807     4477020 :                     tadjPhi[in - 1][iwl - 1] = tPhi[in - 1][iquasi - 1];
    1808     4477020 :                     rfadjPhi[in - 1][iwl - 1] = rfPhi[in - 1][iquasi - 1];
    1809     4477020 :                     rbadjPhi[in - 1][iwl - 1] = rbPhi[in - 1][iquasi - 1];
    1810             :                 } else {
    1811             :                     // Interpolate to get properties at the solar spectrum wavelengths
    1812      472700 :                     tadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], tPhi[in - 1], numpt[in - 1], wl);
    1813      472700 :                     rfadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rfPhi[in - 1], numpt[in - 1], wl);
    1814      472700 :                     rbadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rbPhi[in - 1], numpt[in - 1], wl);
    1815             :                 }
    1816             :             }
    1817             :         }
    1818             : 
    1819             :         // Calculate system properties at each wavelength
    1820     4301640 :         for (int j = 1; j <= nume; ++j) {
    1821     4261810 :             Real64 wl = wm->wle[j - 1];
    1822     4261810 :             if (wl < wlbot || wl > wltop) continue;
    1823             : 
    1824             :             // Set diagonal of matrix for subroutine SystemPropertiesAtLambdaAndPhi
    1825     8284890 :             for (int i = 1; i <= ngllayer; ++i) {
    1826     4949720 :                 wm->top[i - 1][i - 1] = tadjPhi[i - 1][j - 1];
    1827     4949720 :                 wm->rfop[i - 1][i - 1] = rfadjPhi[i - 1][j - 1];
    1828     4949720 :                 wm->rbop[i - 1][i - 1] = rbadjPhi[i - 1][j - 1];
    1829             :             }
    1830             : 
    1831             :             // Calculate glazing system properties
    1832     3335170 :             if (ngllayer == 1) { // Single-layer system
    1833     1899520 :                 stPhi[j - 1] = wm->top[0][0];
    1834     1899520 :                 srfPhi[j - 1] = wm->rfop[0][0];
    1835     1899520 :                 srbPhi[j - 1] = wm->rbop[0][0];
    1836     1899520 :                 sabsPhi(1) = 1.0 - stPhi[j - 1] - srfPhi[j - 1];
    1837             :             } else { // Multilayer system
    1838             :                 // Get glazing system properties stPhi, etc., at this wavelength and incidence angle
    1839     1435650 :                 SystemPropertiesAtLambdaAndPhi(state, ngllayer, stPhi[j - 1], srfPhi[j - 1], srbPhi[j - 1], sabsPhi);
    1840             :             }
    1841             : 
    1842     8284890 :             for (int i = 1; i <= ngllayer; ++i) {
    1843     4949720 :                 saPhi(i, j) = sabsPhi(i);
    1844             :             }
    1845             : 
    1846             :         } // End of wavelength loop
    1847       39830 :     }     // SystemSpectralPropertiesAtPhi()
    1848             : 
    1849             :     //************************************************************************
    1850             : 
    1851     1435650 :     void SystemPropertiesAtLambdaAndPhi(EnergyPlusData &state,
    1852             :                                         int const n, // Number of glass layers
    1853             :                                         Real64 &tt,  // System transmittance
    1854             :                                         Real64 &rft, // System front and back reflectance
    1855             :                                         Real64 &rbt,
    1856             :                                         Array1A<Real64> aft // System absorptance of each glass layer
    1857             :     )
    1858             :     {
    1859             : 
    1860             :         // SUBROUTINE INFORMATION:
    1861             :         //       AUTHOR         Adapted by F. Winkelmann from WINDOW 5
    1862             :         //                      subroutine op
    1863             :         //       DATE WRITTEN   August 1999
    1864             :         //       MODIFIED       na
    1865             :         //       RE-ENGINEERED  na
    1866             : 
    1867             :         // PURPOSE OF THIS SUBROUTINE:
    1868             :         // For a given angle of incidence, finds the overall properties of
    1869             :         // of a series of layers at a particular wavelength
    1870             : 
    1871             :         // Argument array dimensioning
    1872     1435650 :         aft.dim(5);
    1873             : 
    1874             :         Real64 denom; // Intermediate variables
    1875             :         Real64 denom1;
    1876             :         Real64 denom2;
    1877             :         Real64 t0; // Transmittance, back reflectance and front
    1878             :         Real64 rb0;
    1879             :         Real64 rf0;
    1880             :         //   reflectance variables
    1881             :         Real64 af; // Front and back absorptance variables
    1882             :         Real64 ab;
    1883             : 
    1884     1435650 :         auto &wm = state.dataWindowManager;
    1885             :         // Calculate perimeter elements of rt matrix
    1886     3050200 :         for (int i = 1; i <= n - 1; ++i) {
    1887     3422940 :             for (int j = i + 1; j <= n; ++j) {
    1888     1808390 :                 denom = 1.0 - wm->rfop[j - 1][j - 1] * wm->rbop[i - 1][j - 2];
    1889     1808390 :                 if (denom == 0.0) {
    1890      180839 :                     wm->top[j - 1][i - 1] = 0.0;
    1891      180839 :                     wm->rfop[j - 1][i - 1] = 1.0;
    1892      180839 :                     wm->rbop[i - 1][j - 1] = 1.0;
    1893             :                 } else {
    1894     1627551 :                     wm->top[j - 1][i - 1] = wm->top[j - 2][i - 1] * wm->top[j - 1][j - 1] / denom;
    1895     1627551 :                     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;
    1896     1627551 :                     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;
    1897             :                 }
    1898             :             }
    1899             :         }
    1900             :         // System properties: transmittance, front and back reflectance
    1901     1435650 :         tt = wm->top[n - 1][0];
    1902     1435650 :         rft = wm->rfop[n - 1][0];
    1903     1435650 :         rbt = wm->rbop[0][n - 1];
    1904             : 
    1905             :         // Absorptance in each layer
    1906     4485850 :         for (int j = 1; j <= n; ++j) {
    1907     3050200 :             if (j == 1) {
    1908     1435650 :                 t0 = 1.0;
    1909     1435650 :                 rb0 = 0.0;
    1910             :             } else {
    1911     1614550 :                 t0 = wm->top[j - 2][0];
    1912     1614550 :                 rb0 = wm->rbop[0][j - 2];
    1913             :             }
    1914             : 
    1915     3050200 :             if (j == n) {
    1916     1435650 :                 rf0 = 0.0;
    1917             :             } else {
    1918     1614550 :                 rf0 = wm->rfop[n - 1][j];
    1919             :             }
    1920             : 
    1921     3050200 :             af = 1.0 - wm->top[j - 1][j - 1] - wm->rfop[j - 1][j - 1];
    1922     3050200 :             ab = 1.0 - wm->top[j - 1][j - 1] - wm->rbop[j - 1][j - 1];
    1923     3050200 :             denom1 = 1.0 - wm->rfop[n - 1][j - 1] * rb0;
    1924     3050200 :             denom2 = 1.0 - wm->rbop[0][j - 1] * rf0;
    1925             : 
    1926     3050200 :             if (denom1 == 0.0 || denom2 == 0.0) {
    1927      305020 :                 aft(j) = 0.0;
    1928             :             } else {
    1929     2745180 :                 aft(j) = (t0 * af) / denom1 + (wm->top[j - 1][0] * rf0 * ab) / denom2;
    1930             :             }
    1931             :         }
    1932     1435650 :     } // SystemPropertiesAtLambdaAndPhi()
    1933             : 
    1934       80700 :     Real64 solarSpectrumAverage(EnergyPlusData &state, gsl::span<Real64 const> p)
    1935             :     {
    1936       80700 :         Real64 num = 0.0;
    1937       80700 :         Real64 denom = 0.0;
    1938       80700 :         auto &wm = state.dataWindowManager;
    1939             : 
    1940     8634900 :         for (int i = 1; i <= nume - 1; ++i) {
    1941     8554200 :             Real64 const esol = (wm->wle[i] - wm->wle[i - 1]) * 0.5 * (wm->e[i - 1] + wm->e[i]);
    1942     8554200 :             num += 0.5 * (p[i - 1] + p[i]) * esol;
    1943     8554200 :             denom += esol;
    1944             :         }
    1945       80700 :         return num / denom; // dangerous, doesn't check for zero denominator
    1946             :     }
    1947             : 
    1948       40440 :     Real64 visibleSpectrumAverage(EnergyPlusData &state, gsl::span<Real64 const> p)
    1949             :     {
    1950             :         //       AUTHOR         Adapted by F.Winkelmann from WINDOW 5
    1951             :         //                      subroutine w4vis
    1952             :         //       DATE WRITTEN   August 1999
    1953             : 
    1954             :         // Calculates visible average of property p by weighting with solar
    1955             :         // spectral irradiance, e, and photopic response, y30
    1956             : 
    1957       40440 :         Real64 num = 0.0;
    1958       40440 :         Real64 denom = 0.0;
    1959       40440 :         Real64 y30new = 0.0;
    1960       40440 :         Real64 y30ils1 = 0.0;
    1961             : 
    1962       40440 :         auto &wm = state.dataWindowManager;
    1963             : 
    1964     4327080 :         for (int i = 2; i <= nume; ++i) { // Autodesk:BoundsViolation e|wle|p(i-1) @ i=1: Changed start index from 1 to 2: wle
    1965             :             // values prevented this violation from occurring in practice
    1966             :             // Restrict to visible range
    1967     4286640 :             if (wm->wle[i - 1] >= 0.37 && wm->wle[i - 1] <= 0.78) {
    1968     1415400 :                 y30new = Interpolate(wm->wlt3, wm->y30, numt3, wm->wle[i - 1]);
    1969     1415400 :                 Real64 evis = wm->e[i - 2] * 0.5 * (y30new + y30ils1) * (wm->wle[i - 1] - wm->wle[i - 2]);
    1970     1415400 :                 num += 0.5 * (p[i - 1] + p[i - 2]) * evis;
    1971     1415400 :                 denom += evis;
    1972     1415400 :                 y30ils1 = y30new;
    1973             :             }
    1974             :         }
    1975       40440 :         return num / denom; // dangerous, doesn't check for zero denominator
    1976             :     }
    1977             : 
    1978     2833500 :     Real64 Interpolate(gsl::span<Real64 const> x, // Array of data points for independent variable
    1979             :                        gsl::span<Real64 const> y, // Array of data points for dependent variable
    1980             :                        int const npts,            // Number of data pairs
    1981             :                        Real64 const xin           // Given value of x
    1982             :     )
    1983             :     {
    1984             : 
    1985             :         // SUBROUTINE INFORMATION:
    1986             :         //       AUTHOR         Adapted by F.Winkelmann from WINDOW 5 subroutine interp
    1987             :         //       DATE WRITTEN   August 1999
    1988             :         //       MODIFIED       na
    1989             :         //       RE-ENGINEERED  na
    1990             : 
    1991             :         // PURPOSE OF THIS SUBROUTINE:
    1992             :         // Linearly interpolates between data points. Outputs yout, interpolated
    1993             :         // value of y corresponding to xin
    1994             : 
    1995   170882220 :         for (int i = 1; i <= npts; ++i) {
    1996   170869440 :             if (xin <= x[i - 1]) {
    1997     2820720 :                 if (i - 1 == 0) {
    1998       93780 :                     return y[0];
    1999             :                 } else {
    2000     2726940 :                     return y[i - 2] + (y[i - 1] - y[i - 2]) * (xin - x[i - 2]) / (x[i - 1] - x[i - 2]);
    2001             :                 }
    2002             :             }
    2003             :         }
    2004             : 
    2005             :         // Past the end of the array, so return endpoint
    2006       12780 :         return y[npts - 1];
    2007             :     }
    2008             : 
    2009             :     //***********************************************************************************
    2010             :     // Window Thermal Calculation Subroutines
    2011             :     //***********************************************************************************
    2012             : 
    2013    24123715 :     void CalcWindowHeatBalance(EnergyPlusData &state,
    2014             :                                int const SurfNum,          // Surface number
    2015             :                                Real64 const HextConvCoeff, // Outside air film conductance coefficient
    2016             :                                Real64 &SurfInsideTemp,     // Inside window surface temperature
    2017             :                                Real64 &SurfOutsideTemp     // Outside surface temperature (C)
    2018             :     )
    2019             :     {
    2020             :         // SUBROUTINE INFORMATION:
    2021             :         //       AUTHOR         S. Vidanovic
    2022             :         //       DATE WRITTEN   June 2016
    2023             :         //       MODIFIED       na
    2024             :         //       RE-ENGINEERED  na
    2025             :         //
    2026             :         // PURPOSE OF THIS SUBROUTINE:
    2027             :         // Subroutine to direct whether to use exterior or interior window routines
    2028    24123715 :         auto &wm = state.dataWindowManager;
    2029             : 
    2030    24123715 :         if (state.dataGlobal->KickOffSizing || state.dataGlobal->KickOffSimulation) return;
    2031             : 
    2032    24014701 :         if (wm->inExtWindowModel->isExternalLibraryModel()) {
    2033        4032 :             CalcWindowHeatBalanceExternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
    2034             :         } else {
    2035    24010669 :             CalcWindowHeatBalanceInternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
    2036             :         }
    2037             :     }
    2038             : 
    2039    24010669 :     void CalcWindowHeatBalanceInternalRoutines(EnergyPlusData &state,
    2040             :                                                int const SurfNum,          // Surface number
    2041             :                                                Real64 const HextConvCoeff, // Outside air film conductance coefficient
    2042             :                                                Real64 &SurfInsideTemp,     // Inside window surface temperature
    2043             :                                                Real64 &SurfOutsideTemp     // Outside surface temperature (C)
    2044             :     )
    2045             :     {
    2046             : 
    2047             :         // SUBROUTINE INFORMATION:
    2048             :         //       AUTHOR         F. Winkelmann
    2049             :         //       DATE WRITTEN   November 1999
    2050             :         //       MODIFIED       FW, July 2000 (call better solution method)
    2051             :         //                      FW, June 2001 (handle window blinds)
    2052             :         //                      FW, Dec  2002 (add between-glass shades and blinds)
    2053             :         //                      FW, Mar  2003 (extend condensation flag to airflow windows)
    2054             :         //                      CC, Jul  2003 (set the reference temperatures for inside surface heat balance
    2055             :         //                                    depending on convection algorithms and/or air models used)
    2056             :         //                      FW, Sep  2003 (increment ZoneWinHeatGain only for exterior windows)
    2057             :         //                      RR, May  2006 (add exterior window screen)
    2058             :         //                      TH, Dec  2008 (add thermochromic windows)
    2059             :         //       RE-ENGINEERED  na
    2060             : 
    2061             :         // PURPOSE OF THIS SUBROUTINE:
    2062             :         // Sets up information needed to calculate the window thermal behavior.
    2063             :         // Calls SolveForWindowTemperatures, which calculates the inside and outside
    2064             :         // face temperature of each glass layer by solving the heat balance
    2065             :         // equations on each face. Also calls CalcWinFrameAndDividerTemps,
    2066             :         // which calculates the outside and inside face temperatures of the
    2067             :         // window frame and divider if either of these are present.
    2068             :         // The resulting inside face temperature of the inner glass pane and the
    2069             :         // inside surface temperatures of frame and divider are used in the zone
    2070             :         // heat balance calculation. The inside face temperature of an interior shade
    2071             :         // or blind, if present, and the natural convection air flow between the
    2072             :         // shade/blind and inside glass face also appear in the zone heat balance calculation.
    2073             :         // The logical variable NRSolution is currently set to false, which means
    2074             :         // that the Newton-Raphson solution method for the glass layer heat balance
    2075             :         // is not used (because it sometimes didn't converge for 3- and 4-pane
    2076             :         // constructions with one or more low-emissivity layers). Instead, a more
    2077             :         // robust solution method is used that successively solves linearized heat
    2078             :         // balance equations until convergence is reached (see SolveForWindowTemperatures).
    2079             :         // CalcWindowHeatBalance is called by CalcHeatBalanceInsideSurface once each
    2080             :         // time step for each window.
    2081             : 
    2082             :         // Using/Aliasing
    2083             :         using namespace DataBSDFWindow;
    2084             :         using Psychrometrics::PsyCpAirFnW;
    2085             :         using Psychrometrics::PsyTdpFnWPb;
    2086             :         // unused0909  USE DataEnvironment, ONLY: CurMnDyHr
    2087             :         using ScheduleManager::GetCurrentScheduleValue;
    2088             :         using WindowComplexManager::CalcComplexWindowThermal;
    2089             :         using WindowEquivalentLayer::EQLWindowSurfaceHeatBalance;
    2090             : 
    2091             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    2092             :         // (temperature of innermost face) [C]
    2093             : 
    2094             :         int BlNum;      // Window blind number
    2095             :         int SurfNumAdj; // An interzone surface's number in the adjacent zone
    2096             :         int ZoneNumAdj; // An interzone surface's adjacent zone number
    2097             :         int TotLay;     // Total number of layers in a construction
    2098             :         //   (sum of solid layers and gap layers)
    2099             :         int TotGlassLay;          // Total number of glass layers in a construction
    2100             :         int Lay;                  // Layer number
    2101             :         int LayPtr;               // Material number for a layer
    2102             :         WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position
    2103             :         int k;                    // Layer counter
    2104             :         // REAL(r64) :: tsky                         ! Sky temperature [K]
    2105             :         int ShadeLayPtr; // Material number corresponding to a shade layer
    2106             :         Real64 dth1;     // Temperature difference across glass layers [K]
    2107             :         Real64 dth2;
    2108             :         Real64 dth3;
    2109             :         Real64 dth4;
    2110             :         Real64 EffShBlEmiss;    // Effective interior shade or blind emissivity
    2111             :         Real64 EffGlEmiss;      // Effective inside glass emissivity when interior shade or blind
    2112             :         Real64 RoomHumRat;      // Room air humidity ratio
    2113             :         Real64 RoomDewPoint;    // Room air dewpoint temperature (C)
    2114             :         Real64 InsideGlassTemp; // Temperature of room side of innermost glass layer (C)
    2115             :         Real64 Tleft;           // For airflow windows, temperature of the glass faces adjacent
    2116             :         Real64 Tright;
    2117             : 
    2118             :         Real64 SrdSurfTempAbs; // Absolute temperature of a surrounding surface
    2119             :         Real64 OutSrdIR;       // LWR from surrouding srfs
    2120             : 
    2121             :         // New variables for thermochromic windows calc
    2122             :         Real64 locTCSpecTemp;  // The temperature corresponding to the specified optical properties of the TC layer
    2123             :         Real64 locTCLayerTemp; // TC layer temperature at each time step. C
    2124             : 
    2125    24010669 :         auto &wm = state.dataWindowManager;
    2126             : 
    2127    24010669 :         Real64 dT0(0.0);
    2128    24010669 :         Real64 dT1(0.0);
    2129             :         Real64 SurfOutsideEmiss; // temporary for result of outside surface emissivity
    2130             :         Real64 Tsout;            // temporary for result of outside surface temp in Kelvin
    2131             :         int temp;
    2132             : 
    2133    24010669 :         Array1D<Real64> deltaTemp(100, 0.0);
    2134    24010669 :         Array1D_int iMinDT(1, 0);
    2135    24010669 :         Array1D_int IDConst(100, 0);
    2136             : 
    2137             :         // Shorthand references
    2138    24010669 :         auto &window = state.dataSurface->SurfaceWindow(SurfNum);
    2139    24010669 :         auto &surface = state.dataSurface->Surface(SurfNum);
    2140    24010669 :         int ConstrNum = state.dataSurface->SurfActiveConstruction(SurfNum);
    2141    24010669 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(surface.Zone);
    2142             : 
    2143    24010669 :         if (state.dataSurface->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) {
    2144             : 
    2145       37968 :             temp = 0;
    2146             : 
    2147             :             // Simon: Complex fenestration state works only with tarcog
    2148       37968 :             CalcComplexWindowThermal(
    2149             :                 state, SurfNum, temp, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
    2150             : 
    2151       37968 :             TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    2152       37968 :             wm->ngllayer = state.dataConstruction->Construct(ConstrNum).TotSolidLayers; // Simon: This is necessary to keep for frame calculations
    2153             :             // Simon: need to transfer surface temperatures because of frames calculation
    2154             : 
    2155      250992 :             for (int i = 1; i <= 2 * state.dataConstruction->Construct(ConstrNum).TotSolidLayers; ++i) {
    2156      213024 :                 wm->thetas[i - 1] = window.thetaFace[i];
    2157             :             }
    2158       37968 :             wm->hcout = HextConvCoeff;
    2159       37968 :             wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
    2160       37968 :             wm->tin = thisZoneHB.MAT + Constant::Kelvin; // Inside air temperature
    2161             : 
    2162             :             // This is code repeating and it is necessary to calculate report variables.  Do not know
    2163             :             // how to solve this in more elegant way :(
    2164       37968 :             if (surface.ExtWind) {             // Window is exposed to wind (and possibly rain)
    2165       37968 :                 if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
    2166           0 :                     wm->tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
    2167             :                 } else { // Dry
    2168       37968 :                     wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2169             :                 }
    2170             :             } else { // Window not exposed to wind
    2171           0 :                 wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2172             :             }
    2173             : 
    2174       37968 :             wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
    2175       37968 :             wm->Outir = surface.ViewFactorSkyIR *
    2176       37968 :                             (state.dataSurface->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
    2177       37968 :                              (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
    2178       37968 :                         surface.ViewFactorGroundIR * wm->Ebout;
    2179             : 
    2180    23972701 :         } else if (state.dataSurface->SurfWinWindowModelType(SurfNum) == WindowModel::EQL) {
    2181             : 
    2182        8064 :             EQLWindowSurfaceHeatBalance(
    2183             :                 state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
    2184        8064 :             wm->hcout = HextConvCoeff;
    2185             :             // Required for report variables calculations.
    2186        8064 :             if (surface.ExtWind) {             // Window is exposed to wind (and possibly rain)
    2187        8064 :                 if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
    2188           0 :                     wm->tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
    2189             :                 } else { // Dry
    2190        8064 :                     wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2191             :                 }
    2192             :             } else { // Window not exposed to wind
    2193           0 :                 wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2194             :             }
    2195             : 
    2196             :         } else { // regular window, not BSDF, not EQL Window
    2197             :             // Added for thermochromic windows
    2198    23964637 :             wm->locTCFlag = (state.dataConstruction->Construct(ConstrNum).TCFlag == 1);
    2199             : 
    2200    23964637 :             if (wm->locTCFlag) {
    2201             :                 auto const *thisMaterial =
    2202        4032 :                     dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).TCLayer));
    2203        4032 :                 assert(thisMaterial != nullptr);
    2204        4032 :                 locTCSpecTemp = thisMaterial->SpecTemp;
    2205        4032 :                 state.dataSurface->SurfWinSpecTemp(SurfNum) = locTCSpecTemp;
    2206             :                 // Check to see whether needs to switch to a new TC window construction
    2207        4032 :                 locTCLayerTemp = state.dataSurface->SurfWinTCLayerTemp(SurfNum);
    2208        4032 :                 dT0 = std::abs(locTCLayerTemp - locTCSpecTemp);
    2209        4032 :                 if (dT0 >= 1) {
    2210             :                     // Find the TC construction that is closed to the TCLayerTemp
    2211        2509 :                     int i = 0;
    2212        2509 :                     deltaTemp = 0.0;
    2213        2509 :                     IDConst = 0;
    2214       82797 :                     for (int k = 1; k <= state.dataHeatBal->TotConstructs; ++k) {
    2215       80288 :                         if (state.dataConstruction->Construct(k).TCMasterConst == state.dataConstruction->Construct(ConstrNum).TCMasterConst) {
    2216       50180 :                             dT1 = std::abs(locTCLayerTemp - dynamic_cast<Material::MaterialChild *>(
    2217       50180 :                                                                 state.dataMaterial->Material(state.dataConstruction->Construct(k).TCLayer))
    2218       50180 :                                                                 ->SpecTemp);
    2219       50180 :                             if (dT1 < dT0) {
    2220         327 :                                 ++i;
    2221         327 :                                 deltaTemp(i) = dT1;
    2222         327 :                                 IDConst(i) = k;
    2223             :                             }
    2224             :                         }
    2225             :                     }
    2226        2509 :                     if (i >= 1) {
    2227             :                         // Find the closest item
    2228         313 :                         iMinDT = minloc(deltaTemp, deltaTemp > 0.0);
    2229             :                         // Use the new TC window construction
    2230         313 :                         ConstrNum = IDConst(iMinDT(1));
    2231         313 :                         surface.Construction = ConstrNum;
    2232         313 :                         state.dataSurface->SurfActiveConstruction(SurfNum) = ConstrNum;
    2233         313 :                         state.dataSurface->SurfWinSpecTemp(SurfNum) =
    2234         313 :                             dynamic_cast<Material::MaterialChild *>(
    2235         313 :                                 state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).TCLayer))
    2236         313 :                                 ->SpecTemp;
    2237             :                     }
    2238             :                 }
    2239             :             }
    2240             :             // end new TC code
    2241             : 
    2242    23964637 :             TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
    2243    23964637 :             TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    2244    23964637 :             wm->ngllayer = TotGlassLay;
    2245    23964637 :             wm->nglface = 2 * wm->ngllayer;
    2246    23964637 :             ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    2247    23964637 :             wm->tilt = surface.Tilt;
    2248    23964637 :             wm->tiltr = wm->tilt * Constant::DegToRadians;
    2249    23964637 :             SurfNumAdj = surface.ExtBoundCond;
    2250    23964637 :             wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum); // Room-side surface convective film conductance
    2251    23964637 :             Real64 RefAirTemp = state.dataSurface->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
    2252    23964637 :             state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = RefAirTemp;
    2253    23964637 :             wm->tin = RefAirTemp + Constant::Kelvin; // Inside air temperature
    2254             : 
    2255             :             // Reset hcin if necessary since too small a value sometimes causes non-convergence
    2256             :             // of window layer heat balance solution.
    2257    23964637 :             if (state.dataSurface->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) {
    2258             :                 // may be redundent now, check is also in HeatBalanceConvectionCoeffs.cc
    2259    23964637 :                 if (wm->hcin <= state.dataHeatBal->LowHConvLimit) {
    2260             :                     //  hcin = 3.076d0  !BG this is rather high value and abrupt change. changed to set to lower limit
    2261       23159 :                     wm->hcin = state.dataHeatBal->LowHConvLimit;
    2262       23159 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = wm->hcin; // store for accurate reporting.
    2263             :                 }
    2264             :             }
    2265             : 
    2266             :             // IR incident on window from zone surfaces and high-temp radiant sources
    2267    23964637 :             wm->Rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
    2268             : 
    2269             :             // Short-wave radiation (from interior and exterior solar and zone lights)
    2270             :             // absorbed at each face. Assumes equal split between faces of short-wave absorbed in glass layer.
    2271             : 
    2272    54910169 :             for (int IGlass = 1; IGlass <= TotGlassLay; ++IGlass) {
    2273    30945532 :                 wm->AbsRadGlassFace[2 * IGlass - 2] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
    2274    30945532 :                 wm->AbsRadGlassFace[2 * IGlass - 1] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
    2275             :             }
    2276             : 
    2277             :             // IR from zone internal gains (lights, equipment and people) absorbed on zone-side face
    2278             :             // (assumes inside glass layer is opaque to IR, so no contribution to other layers)
    2279    23964637 :             wm->AbsRadGlassFace[2 * TotGlassLay - 1] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum);
    2280             : 
    2281             :             // Fill the layer properties needed for the thermal calculation.
    2282             :             // For switchable glazing it is assumed that thermal properties, such
    2283             :             // as surface emissivity, are the same for the unswitched and switched state,
    2284             :             // so the thermal properties of the unswitched state are used.
    2285             :             // For windows with a blind or shade it is assumed
    2286             :             // that the blind or shade does not affect the thermal properties of the glazing,
    2287             :             // so the thermal properties of the construction without the blind or shade are used.
    2288             : 
    2289             :             // The layer and face numbering are as follows (for the triple glazing case):
    2290             :             // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
    2291             :             //   layer and 3 is the inside (room-facing) layer;
    2292             :             // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
    2293             :             //   outside (front) face of glass layer 1, face 2 is the inside (back)
    2294             :             //   face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
    2295             :             //   inner face of glass layer 2, etc.
    2296             :             // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
    2297             :             //   and gap layer 2 is between glass layers 2 and 3.
    2298             :             // If an exterior, interior or between-glass blind or shade is in place, 7 and 8
    2299             :             //   are the blind/shade faces, from outside to inside. If an exterior or interior
    2300             :             //   blind/shade is in place, gap layer 3 is between the blind/shade and adjacent
    2301             :             //   glass layer and is assumed to be air.
    2302             :             // Between-glass blind/shade is modeled only for double and triple glazing.
    2303             :             //   For double glazing, gap 1 is between glass 1 and blind/shade and gap 2 is between
    2304             :             //   blind/shade and glass 2.
    2305             :             //   For triple glazing, the blind/shade is assumed to be between the inner two glass
    2306             :             //   layers, i.e., between glass layers 2 and 3. In this case gap 1 is between glass 1
    2307             :             //   and glass 2, gap 2 is between glass 2 and blind/shade, and gap 3 is between
    2308             :             //   blind/shade and glass 3.
    2309             : 
    2310    23964637 :             int IConst = ConstrNum;
    2311    23964637 :             if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
    2312      186115 :                 IConst = state.dataSurface->SurfWinActiveShadedConstruction(SurfNum);
    2313             :             }
    2314    23964637 :             TotLay = state.dataConstruction->Construct(IConst).TotLayers;
    2315    23964637 :             int IGlass = 0;
    2316    23964637 :             int IGap = 0;
    2317             : 
    2318             :             // Fill window layer properties needed for window layer heat balance calculation
    2319             : 
    2320    62094049 :             for (int Lay = 1; Lay <= TotLay; ++Lay) {
    2321    38129412 :                 LayPtr = state.dataConstruction->Construct(IConst).LayerPoint(Lay);
    2322    38129412 :                 auto const *mat = state.dataMaterial->Material(LayPtr);
    2323             : 
    2324    38129412 :                 if ((mat->group == Material::Group::WindowGlass) || (mat->group == Material::Group::WindowSimpleGlazing)) {
    2325    30945532 :                     ++IGlass;
    2326    30945532 :                     wm->thick[IGlass - 1] = mat->Thickness;
    2327    30945532 :                     wm->scon[IGlass - 1] = mat->Conductivity / mat->Thickness;
    2328    30945532 :                     wm->emis[2 * IGlass - 2] = mat->AbsorpThermalFront;
    2329    30945532 :                     wm->emis[2 * IGlass - 1] = mat->AbsorpThermalBack;
    2330    30945532 :                     wm->tir[2 * IGlass - 2] = mat->TransThermal;
    2331    30945532 :                     wm->tir[2 * IGlass - 1] = mat->TransThermal;
    2332             :                 }
    2333             : 
    2334    38129412 :                 if (mat->group == Material::Group::Shade || mat->group == Material::Group::WindowBlind || mat->group == Material::Group::Screen) {
    2335      186115 :                     if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag))
    2336      147791 :                         ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers);
    2337      186115 :                     if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1);
    2338      186115 :                     if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    2339       16870 :                         ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3);
    2340       16870 :                         if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5);
    2341             :                     }
    2342      186115 :                     auto const *matShade = state.dataMaterial->Material(ShadeLayPtr);
    2343      186115 :                     assert(matShade != nullptr);
    2344      186115 :                     if (ANY_SHADE_SCREEN(ShadeFlag)) {
    2345             :                         // Shade or screen on
    2346       49460 :                         if (state.dataGlobal
    2347       49460 :                                 ->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values
    2348           0 :                             if (matShade->group == Material::Group::WindowBlind) {
    2349           0 :                                 ShowSevereError(
    2350             :                                     state,
    2351           0 :                                     format("CalcWindowHeatBalance: ShadeFlag indicates Shade but Blind=\"{}\" is being used.", matShade->Name));
    2352           0 :                                 ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
    2353           0 :                                 ShowFatalError(state, "Preceding condition terminates program.");
    2354             :                             }
    2355             :                         }
    2356       49460 :                         wm->thick[TotGlassLay] = matShade->Thickness;
    2357       49460 :                         wm->scon[TotGlassLay] = matShade->Conductivity / matShade->Thickness;
    2358       49460 :                         if (ShadeFlag == WinShadingType::ExtScreen) {
    2359        5376 :                             auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
    2360        5376 :                             assert(matScreen != nullptr);
    2361        5376 :                             wm->emis[wm->nglface] = matScreen->AbsorpThermalFront;
    2362        5376 :                             wm->tir[wm->nglface] = matScreen->DfTrans;
    2363        5376 :                             wm->tir[wm->nglface + 1] = matScreen->DfTrans;
    2364             :                         } else {
    2365       44084 :                             wm->emis[wm->nglface] = matShade->AbsorpThermal;
    2366       44084 :                             wm->tir[wm->nglface] = matShade->TransThermal;
    2367       44084 :                             wm->tir[wm->nglface + 1] = matShade->TransThermal;
    2368             :                         }
    2369       49460 :                         wm->emis[wm->nglface + 1] = matShade->AbsorpThermal;
    2370             : 
    2371             :                     } else {
    2372      136655 :                         if (state.dataGlobal
    2373      136655 :                                 ->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values
    2374      123047 :                             if (matShade->group == Material::Group::Shade || matShade->group == Material::Group::Screen) {
    2375           0 :                                 ShowSevereError(state,
    2376           0 :                                                 format("CalcWindowHeatBalance: ShadeFlag indicates Blind but Shade/Screen=\"{}\" is being used.",
    2377           0 :                                                        matShade->Name));
    2378           0 :                                 ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
    2379           0 :                                 ShowFatalError(state, "Preceding condition terminates program.");
    2380             :                             }
    2381             :                         }
    2382             :                         // Blind on
    2383      136655 :                         BlNum = state.dataSurface->SurfWinBlindNumber(SurfNum);
    2384      136655 :                         auto const &blind = state.dataMaterial->Blind(BlNum);
    2385      136655 :                         wm->thick[TotGlassLay] = blind.SlatThickness;
    2386      136655 :                         wm->scon[TotGlassLay] = blind.SlatConductivity / blind.SlatThickness;
    2387             : 
    2388      136655 :                         if (state.dataSurface->SurfWinMovableSlats(SurfNum)) {
    2389        3122 :                             int slatAngIndex = state.dataSurface->SurfWinSlatsAngIndex(SurfNum);
    2390        3122 :                             int slatAngIndex2 = std::min(Material::MaxSlatAngs, slatAngIndex + 1);
    2391             : 
    2392        3122 :                             Real64 interpFac = state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum);
    2393        3122 :                             wm->emis[wm->nglface] = General::Interp(blind.IRFrontEmiss(slatAngIndex), blind.IRFrontEmiss(slatAngIndex2), interpFac);
    2394        3122 :                             wm->emis[wm->nglface + 1] = General::Interp(blind.IRBackEmiss(slatAngIndex), blind.IRBackEmiss(slatAngIndex2), interpFac);
    2395        3122 :                             wm->tir[wm->nglface] = General::Interp(blind.IRFrontTrans(slatAngIndex), blind.IRFrontTrans(slatAngIndex2), interpFac);
    2396        3122 :                             wm->tir[wm->nglface + 1] = General::Interp(blind.IRBackTrans(slatAngIndex), blind.IRBackTrans(slatAngIndex2), interpFac);
    2397             :                         } else {
    2398      133533 :                             wm->emis[wm->nglface] = blind.IRFrontEmiss(1);
    2399      133533 :                             wm->emis[wm->nglface + 1] = blind.IRBackEmiss(1);
    2400      133533 :                             wm->tir[wm->nglface] = blind.IRFrontTrans(1);
    2401      133533 :                             wm->tir[wm->nglface + 1] = blind.IRBackTrans(1);
    2402             :                         }
    2403             :                     }
    2404             :                 }
    2405             : 
    2406    38129412 :                 if (mat->group == Material::Group::WindowGas || mat->group == Material::Group::WindowGasMixture) {
    2407     6997765 :                     ++IGap;
    2408     6997765 :                     auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(LayPtr));
    2409     6997765 :                     assert(matGas != nullptr);
    2410     6997765 :                     wm->gaps[IGap - 1].width = matGas->Thickness;
    2411     6997765 :                     wm->gaps[IGap - 1].numGases = matGas->numGases;
    2412    14051978 :                     for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
    2413     7054213 :                         wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
    2414     7054213 :                         wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
    2415             :                     }
    2416             :                 }
    2417             : 
    2418             :             } // End of loop over glass, gap and blind/shade layers in a window construction
    2419             : 
    2420    23964637 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2421             :                 // Interior or exterior blind, shade or screen is on.
    2422             :                 // Fill gap between blind/shade and adjacent glass with air properties.
    2423      169245 :                 ++IGap;
    2424      169245 :                 if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) // Interior or exterior shade
    2425       36020 :                     wm->gaps[IGap - 1].width =
    2426       36020 :                         dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(ShadeLayPtr))->WinShadeToGlassDist;
    2427      133225 :                 else if (ShadeFlag == WinShadingType::ExtScreen) {
    2428        5376 :                     wm->gaps[IGap - 1].width = dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(ShadeLayPtr))->toGlassDist;
    2429             :                 } else { // Interior or exterior blind
    2430      127849 :                     wm->gaps[IGap - 1].width = state.dataMaterial->Blind(state.dataSurface->SurfWinBlindNumber(SurfNum)).BlindToGlassDist;
    2431             :                 }
    2432      169245 :                 wm->gaps[IGap - 1].numGases = 1;
    2433             : 
    2434      169245 :                 wm->gaps[IGap - 1].gases[0] = Material::gases[(int)Material::GasType::Air];
    2435      169245 :                 wm->gaps[IGap - 1].gasFracts[0] = 1;
    2436             :             }
    2437             : 
    2438             :             // Exterior convection coefficient, exterior air temperature and IR radiance
    2439             :             // of exterior surround. Depend on whether window is interzone (in an interzone
    2440             :             // wall or exterior (in an exterior wall).
    2441             : 
    2442    23964637 :             wm->hcout = HextConvCoeff; // Exterior convection coefficient is passed in from outer routine
    2443             :             // tsky = SkyTemp + TKelvin
    2444             : 
    2445    23964637 :             if (SurfNumAdj > 0) { // Interzone window
    2446             : 
    2447       27072 :                 ZoneNumAdj = state.dataSurface->Surface(SurfNumAdj).Zone;
    2448       27072 :                 Real64 RefAirTemp = state.dataSurface->Surface(SurfNumAdj).getInsideAirTemperature(state, SurfNumAdj);
    2449       27072 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNumAdj) = RefAirTemp;
    2450       27072 :                 wm->tout = RefAirTemp + Constant::Kelvin; // outside air temperature
    2451             : 
    2452             :                 // Add long-wave radiation from adjacent zone absorbed by glass layer closest to the adjacent zone.
    2453       27072 :                 wm->AbsRadGlassFace[0] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNumAdj);
    2454             : 
    2455             :                 // The IR radiance of this window's "exterior" surround is the IR radiance
    2456             :                 // from surfaces and high-temp radiant sources in the adjacent zone
    2457             : 
    2458       27072 :                 wm->Outir = state.dataSurface->SurfWinIRfromParentZone(SurfNumAdj) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNumAdj);
    2459             : 
    2460             :             } else { // Exterior window (Ext BoundCond = 0)
    2461             :                 // Calculate LWR from surrounding surfaces if defined for an exterior window
    2462    23937565 :                 OutSrdIR = 0;
    2463    23937565 :                 if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
    2464      133056 :                     if (state.dataSurface->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
    2465        2688 :                         SrdSurfTempAbs = surface.SrdSurfTemp + Constant::Kelvin;
    2466        2688 :                         OutSrdIR = Constant::StefanBoltzmann * surface.ViewFactorSrdSurfs * pow_4(SrdSurfTempAbs);
    2467             :                     }
    2468             :                 }
    2469    23937565 :                 if (surface.ExtWind) {             // Window is exposed to wind (and possibly rain)
    2470    23937565 :                     if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
    2471        5844 :                         wm->tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
    2472             :                     } else { // Dry
    2473    23931721 :                         wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2474             :                     }
    2475             :                 } else { // Window not exposed to wind
    2476           0 :                     wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
    2477             :                 }
    2478    23937565 :                 wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
    2479    23937565 :                 wm->Outir = surface.ViewFactorSkyIR *
    2480    23937565 :                                 (state.dataSurface->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
    2481    23937565 :                                  (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
    2482    23937565 :                             surface.ViewFactorGroundIR * wm->Ebout + OutSrdIR;
    2483             :             }
    2484             : 
    2485             :             // Factors used in window layer temperature solution
    2486    23964637 :             if (wm->ngllayer >= 2) {
    2487     6837855 :                 wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    2488     6837855 :                 wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    2489     6837855 :                 wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
    2490             :             }
    2491             : 
    2492    23964637 :             if (wm->ngllayer >= 3) {
    2493       92352 :                 wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    2494       92352 :                 wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    2495       92352 :                 wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
    2496             :             }
    2497             : 
    2498    23964637 :             if (wm->ngllayer == 4) {
    2499       50688 :                 wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    2500       50688 :                 wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    2501       50688 :                 wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
    2502             :             }
    2503             : 
    2504    23964637 :             wm->thetas = {0.0};
    2505    23964637 :             wm->thetasPrev = {0.0};
    2506    23964637 :             wm->fvec = {0.0};
    2507             : 
    2508             :             // Calculate window face temperatures
    2509             : 
    2510    23964637 :             SolveForWindowTemperatures(state, SurfNum);
    2511             : 
    2512             :             // Temperature difference across glass layers (for debugging)
    2513             : 
    2514    23964637 :             dth1 = wm->thetas[1] - wm->thetas[0];
    2515    23964637 :             dth2 = wm->thetas[3] - wm->thetas[2];
    2516    23964637 :             dth3 = wm->thetas[5] - wm->thetas[4];
    2517    23964637 :             dth4 = wm->thetas[7] - wm->thetas[6];
    2518             : 
    2519    23964637 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    2520      147791 :                 SurfInsideTemp = wm->thetas[2 * wm->ngllayer + 1] - Constant::Kelvin;
    2521      147791 :                 if (state.dataSurface->SurfWinMovableSlats(SurfNum)) {
    2522             :                     EffShBlEmiss =
    2523        2569 :                         General::Interp(window.EffShBlindEmiss[state.dataSurface->SurfWinSlatsAngIndex(SurfNum)],
    2524        2569 :                                         window.EffShBlindEmiss[std::min(Material::MaxSlatAngs, state.dataSurface->SurfWinSlatsAngIndex(SurfNum) + 1)],
    2525        2569 :                                         state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum));
    2526             :                     EffGlEmiss =
    2527        2569 :                         General::Interp(window.EffGlassEmiss[state.dataSurface->SurfWinSlatsAngIndex(SurfNum)],
    2528        5138 :                                         window.EffGlassEmiss[std::min(Material::MaxSlatAngs, state.dataSurface->SurfWinSlatsAngIndex(SurfNum) + 1)],
    2529        2569 :                                         state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum));
    2530             :                 } else {
    2531      145222 :                     EffShBlEmiss = state.dataSurface->SurfaceWindow(SurfNum).EffShBlindEmiss[1];
    2532      145222 :                     EffGlEmiss = state.dataSurface->SurfaceWindow(SurfNum).EffGlassEmiss[1];
    2533             :                 }
    2534      147791 :                 state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
    2535      147791 :                     (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin)) /
    2536      147791 :                     (EffShBlEmiss + EffGlEmiss);
    2537             :             } else {
    2538    23816846 :                 SurfInsideTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
    2539             :             }
    2540    23964637 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2541       21454 :                 SurfOutsideTemp = wm->thetas[2 * wm->ngllayer] - Constant::Kelvin; // this index looks suspicious (CR 8202)
    2542             :                 // SurfOutsideEmiss = emis(1)  ! this index should be coordinated with previous line
    2543       21454 :                 SurfOutsideEmiss = wm->emis[2 * wm->ngllayer]; // fix for CR 8202
    2544             :             } else {
    2545    23943183 :                 SurfOutsideEmiss = wm->emis[0];
    2546    23943183 :                 SurfOutsideTemp = wm->thetas[0] - Constant::Kelvin;
    2547             :             }
    2548             : 
    2549             :             // Save temperatures for use next time step
    2550             : 
    2551    86227931 :             for (int k = 1; k <= wm->nglfacep; ++k) {
    2552    62263294 :                 window.thetaFace[k] = wm->thetas[k - 1];
    2553             :             }
    2554             : 
    2555             :             // Added TH 12/23/2008 for thermochromic windows to save the current TC layer temperature
    2556    23964637 :             if (wm->locTCFlag) {
    2557        8064 :                 state.dataSurface->SurfWinTCLayerTemp(SurfNum) = (wm->thetas[2 * state.dataConstruction->Construct(ConstrNum).TCGlassID - 2] +
    2558        4032 :                                                                   wm->thetas[2 * state.dataConstruction->Construct(ConstrNum).TCGlassID - 1]) /
    2559        4032 :                                                                      2 -
    2560             :                                                                  Constant::Kelvin; // degree C
    2561             :             }
    2562             :         } // regular window, not BSDF, not EQL
    2563             : 
    2564             :         // Set condensation flag to 1 if condensation expected to occur on the innermost glass face,
    2565             :         // or, for airflow windows, on either or the two glass faces in the airflow gap
    2566    24010669 :         if (!state.dataConstruction->Construct(surface.Construction).WindowTypeEQL) {
    2567    24002605 :             InsideGlassTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
    2568    24002605 :             RoomHumRat = thisZoneHB.airHumRat;
    2569    24002605 :             RoomDewPoint = PsyTdpFnWPb(state, RoomHumRat, state.dataEnvrn->OutBaroPress);
    2570    24002605 :             state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 0;
    2571    24002605 :             if (InsideGlassTemp < RoomDewPoint) state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
    2572             :             // If airflow window, is there condensation on either glass face of the airflow gap?
    2573    24002605 :             if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    2574       16128 :                 Tleft = wm->thetas[2 * wm->ngllayer - 3] - Constant::Kelvin;
    2575       16128 :                 Tright = wm->thetas[2 * wm->ngllayer - 2] - Constant::Kelvin;
    2576       16128 :                 if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    2577       16128 :                     if (Tleft < RoomDewPoint || Tright < RoomDewPoint) state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
    2578           0 :                 } else if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Outdoor) {
    2579           0 :                     if (Tleft < state.dataEnvrn->OutDewPointTemp || Tright < state.dataEnvrn->OutDewPointTemp)
    2580           0 :                         state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
    2581             :                 }
    2582             :             }
    2583             : 
    2584             :             // Do frame and divider calculation
    2585    24002605 :             if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0 || state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0)
    2586      656496 :                 CalcWinFrameAndDividerTemps(state, SurfNum, wm->tout, wm->tin, wm->hcout, wm->hcin, wm->Outir, ConstrNum);
    2587    24002605 :             if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
    2588      656496 :                 state.dataSurface->SurfWinInsideFrameCondensationFlag(SurfNum) = 0;
    2589      656496 :                 if (state.dataSurface->SurfWinFrameTempIn(SurfNum) < RoomDewPoint) state.dataSurface->SurfWinInsideFrameCondensationFlag(SurfNum) = 1;
    2590             :             }
    2591    24002605 :             if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0) {
    2592      327888 :                 state.dataSurface->SurfWinInsideDividerCondensationFlag(SurfNum) = 0;
    2593      327888 :                 if (state.dataSurface->SurfWinDividerTempIn(SurfNum) < RoomDewPoint)
    2594       71289 :                     state.dataSurface->SurfWinInsideDividerCondensationFlag(SurfNum) = 1;
    2595             :             }
    2596             :         }
    2597             :         // update exterior environment surface heat loss reporting
    2598    24010669 :         Tsout = SurfOutsideTemp + Constant::Kelvin;
    2599    24010669 :         state.dataHeatBalSurf->SurfQdotConvOutPerArea(SurfNum) = -wm->hcout * (Tsout - wm->tout);
    2600             : 
    2601    24010669 :         Real64 const Tsout_4(pow_4(Tsout)); // Tuned To reduce pow calls and redundancies
    2602    24010669 :         Real64 const Tout_4(pow_4(wm->tout));
    2603    24010669 :         Real64 const emiss_sigma_product(SurfOutsideEmiss * Constant::StefanBoltzmann);
    2604    24010669 :         Real64 rad_out_lw_srd_per_area = 0;
    2605             : 
    2606    24010669 :         if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
    2607      133056 :             if (state.dataSurface->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
    2608             :                 // update SurfHSrdSurfExt if the windows has exterior shade or blind
    2609        2688 :                 state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) =
    2610        2688 :                     Convect::SurroundingSurfacesRadCoeffAverage(state, SurfNum, Tsout, SurfOutsideEmiss);
    2611        2688 :                 rad_out_lw_srd_per_area = state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) * (surface.SrdSurfTemp - SurfOutsideTemp);
    2612             :             }
    2613             :         }
    2614             : 
    2615             :         Real64 const rad_out_air_per_area =
    2616    24010669 :             -emiss_sigma_product * (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * surface.ViewFactorSkyIR * (Tsout_4 - Tout_4);
    2617    24010669 :         Real64 const rad_out_ground_per_area = -emiss_sigma_product * surface.ViewFactorGroundIR * (Tsout_4 - Tout_4);
    2618    24010669 :         Real64 const rad_out_sky_per_area = -emiss_sigma_product * state.dataSurface->SurfAirSkyRadSplit(SurfNum) * surface.ViewFactorSkyIR *
    2619    24010669 :                                             (Tsout_4 - pow_4(state.dataEnvrn->SkyTempKelvin));
    2620    24010669 :         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;
    2621             : 
    2622    24010669 :         state.dataHeatBalSurf->SurfHAirExt(SurfNum) = rad_out_air_per_area / (Tsout - wm->tout);
    2623    24010669 :         state.dataHeatBalSurf->SurfQRadLWOutSrdSurfs(SurfNum) = rad_out_lw_srd_per_area;
    2624    24010669 :         state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(SurfNum) = rad_out_per_area;
    2625    24010669 :     } // CalcWindowHeatBalanceInternalRoutines()
    2626             : 
    2627             :     //****************************************************************************
    2628             : 
    2629           0 :     void WindowHeatBalanceEquations(EnergyPlusData &state, int const SurfNum) // Surface number
    2630             :     {
    2631             : 
    2632             :         // SUBROUTINE INFORMATION:
    2633             :         //       AUTHOR         F. Winkelmann
    2634             :         //       DATE WRITTEN   February 2000
    2635             :         //       MODIFIED       na
    2636             :         //       RE-ENGINEERED  na
    2637             : 
    2638             :         // PURPOSE OF THIS SUBROUTINE:
    2639             :         // Evaluates heat balance functions at each glass face.
    2640             :         // Also evaluates Jacobian.
    2641             :         // Currently limited to three glass layers.
    2642             : 
    2643           0 :         Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance
    2644             :         Real64 gr;                            // Gap gas Grashof number
    2645             :         Real64 con;                           // Gap gas conductivity
    2646             :         Real64 pr;                            // Gap gas Prandtl number
    2647             :         Real64 nu;                            // Gap gas Nusselt number
    2648             :         Real64 thetas_2_3_4;
    2649             :         Real64 thetas_4_5_4;
    2650             :         Real64 thetas_6_7_4;
    2651             : 
    2652           0 :         auto &wm = state.dataWindowManager;
    2653           0 :         auto const &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
    2654             : 
    2655             :         // Have to zero fvec each time since LUdecompostion and LUsolution may
    2656             :         // add values to this array in unexpected places
    2657             : 
    2658           0 :         wm->fvec = {0.0};
    2659             : 
    2660           0 :         switch (wm->ngllayer) {
    2661             : 
    2662           0 :         case 1: { // single pane
    2663           0 :             wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
    2664           0 :                           wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
    2665           0 :             wm->fvec[1] = wm->Rmir * wm->emis[1] - wm->emis[1] * Constant::StefanBoltzmann * pow_4(wm->thetas[1]) +
    2666           0 :                           wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + wm->hcin * (wm->tin - wm->thetas[1]) + wm->AbsRadGlassFace[1];
    2667           0 :         } break;
    2668           0 :         case 2: { // double pane
    2669           0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2670           0 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2671           0 :             hgap(1) = (con / wm->gaps[0].width * nu) * surfWin.edgeGlassCorrFac;
    2672             : 
    2673           0 :             wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
    2674           0 :                           wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
    2675           0 :             thetas_2_3_4 = pow_4(wm->thetas[1]) - pow_4(wm->thetas[2]);
    2676           0 :             wm->fvec[1] = wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + hgap(1) * (wm->thetas[2] - wm->thetas[1]) + wm->A23 * thetas_2_3_4 +
    2677           0 :                           wm->AbsRadGlassFace[1];
    2678           0 :             wm->fvec[2] = hgap(1) * (wm->thetas[1] - wm->thetas[2]) + wm->scon[1] * (wm->thetas[3] - wm->thetas[2]) - wm->A23 * thetas_2_3_4 +
    2679           0 :                           wm->AbsRadGlassFace[2];
    2680           0 :             wm->fvec[3] = wm->Rmir * wm->emis[3] - wm->emis[3] * Constant::StefanBoltzmann * pow_4(wm->thetas[3]) +
    2681           0 :                           wm->scon[1] * (wm->thetas[2] - wm->thetas[3]) + wm->hcin * (wm->tin - wm->thetas[3]) + wm->AbsRadGlassFace[3];
    2682           0 :         } break;
    2683           0 :         case 3: { // Triple Pane
    2684           0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2685           0 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2686           0 :             hgap(1) = con / wm->gaps[0].width * nu * surfWin.edgeGlassCorrFac;
    2687             : 
    2688           0 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2689           0 :             NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2690           0 :             hgap(2) = con / wm->gaps[1].width * nu * surfWin.edgeGlassCorrFac;
    2691             : 
    2692           0 :             thetas_2_3_4 = pow_4(wm->thetas[1]) - pow_4(wm->thetas[2]);
    2693           0 :             thetas_4_5_4 = pow_4(wm->thetas[3]) - pow_4(wm->thetas[4]);
    2694           0 :             wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
    2695           0 :                           wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
    2696           0 :             wm->fvec[1] = wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + hgap(1) * (wm->thetas[2] - wm->thetas[1]) + wm->A23 * thetas_2_3_4 +
    2697           0 :                           wm->AbsRadGlassFace[1];
    2698           0 :             wm->fvec[2] = hgap(1) * (wm->thetas[1] - wm->thetas[2]) + wm->scon[1] * (wm->thetas[3] - wm->thetas[2]) - wm->A23 * thetas_2_3_4 +
    2699           0 :                           wm->AbsRadGlassFace[2];
    2700           0 :             wm->fvec[3] = wm->scon[1] * (wm->thetas[2] - wm->thetas[3]) + hgap(2) * (wm->thetas[4] - wm->thetas[3]) + wm->A45 * thetas_4_5_4 +
    2701           0 :                           wm->AbsRadGlassFace[3];
    2702           0 :             wm->fvec[4] = hgap(2) * (wm->thetas[3] - wm->thetas[4]) + wm->scon[2] * (wm->thetas[5] - wm->thetas[4]) - wm->A45 * thetas_4_5_4 +
    2703           0 :                           wm->AbsRadGlassFace[4];
    2704           0 :             wm->fvec[5] = wm->Rmir * wm->emis[5] - wm->emis[5] * Constant::StefanBoltzmann * pow_4(wm->thetas[5]) +
    2705           0 :                           wm->scon[2] * (wm->thetas[4] - wm->thetas[5]) + wm->hcin * (wm->tin - wm->thetas[5]) + wm->AbsRadGlassFace[5];
    2706           0 :         } break;
    2707           0 :         case 4: { // Quad Pane
    2708           0 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2709           0 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2710           0 :             hgap(1) = con / wm->gaps[0].width * nu * surfWin.edgeGlassCorrFac;
    2711             : 
    2712           0 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2713           0 :             NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2714           0 :             hgap(2) = con / wm->gaps[1].width * nu * surfWin.edgeGlassCorrFac;
    2715             : 
    2716           0 :             WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
    2717           0 :             NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
    2718           0 :             hgap(3) = con / wm->gaps[2].width * nu * surfWin.edgeGlassCorrFac;
    2719             : 
    2720           0 :             thetas_2_3_4 = pow_4(wm->thetas[1]) - pow_4(wm->thetas[2]);
    2721           0 :             thetas_4_5_4 = pow_4(wm->thetas[3]) - pow_4(wm->thetas[4]);
    2722           0 :             thetas_6_7_4 = pow_4(wm->thetas[5]) - pow_4(wm->thetas[6]);
    2723           0 :             wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
    2724           0 :                           wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
    2725           0 :             wm->fvec[1] = wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + hgap(1) * (wm->thetas[2] - wm->thetas[1]) + wm->A23 * thetas_2_3_4 +
    2726           0 :                           wm->AbsRadGlassFace[1];
    2727           0 :             wm->fvec[2] = hgap(1) * (wm->thetas[1] - wm->thetas[2]) + wm->scon[1] * (wm->thetas[3] - wm->thetas[2]) - wm->A23 * thetas_2_3_4 +
    2728           0 :                           wm->AbsRadGlassFace[2];
    2729           0 :             wm->fvec[3] = wm->scon[1] * (wm->thetas[2] - wm->thetas[3]) + hgap(2) * (wm->thetas[4] - wm->thetas[3]) + wm->A45 * thetas_4_5_4 +
    2730           0 :                           wm->AbsRadGlassFace[3];
    2731           0 :             wm->fvec[4] = hgap(2) * (wm->thetas[3] - wm->thetas[4]) + wm->scon[2] * (wm->thetas[5] - wm->thetas[4]) - wm->A45 * thetas_4_5_4 +
    2732           0 :                           wm->AbsRadGlassFace[4];
    2733           0 :             wm->fvec[5] = wm->scon[2] * (wm->thetas[4] - wm->thetas[5]) + hgap(3) * (wm->thetas[6] - wm->thetas[5]) + wm->A67 * thetas_6_7_4 +
    2734           0 :                           wm->AbsRadGlassFace[5];
    2735           0 :             wm->fvec[6] = hgap(3) * (wm->thetas[5] - wm->thetas[6]) + wm->scon[3] * (wm->thetas[7] - wm->thetas[6]) - wm->A67 * thetas_6_7_4 +
    2736           0 :                           wm->AbsRadGlassFace[6];
    2737           0 :             wm->fvec[7] = wm->Rmir * wm->emis[7] - wm->emis[7] * Constant::StefanBoltzmann * pow_4(wm->thetas[7]) +
    2738           0 :                           wm->scon[3] * (wm->thetas[6] - wm->thetas[7]) + wm->hcin * (wm->tin - wm->thetas[7]) + wm->AbsRadGlassFace[7];
    2739           0 :         } break;
    2740             :         } // switch
    2741           0 :     }     // WindowHeatBalanceEquations()
    2742             : 
    2743             :     //****************************************************************************
    2744             : 
    2745       15358 :     void GetHeatBalanceEqCoefMatrixSimple(EnergyPlusData &state,
    2746             :                                           int const nglasslayer,     // Number of glass layers
    2747             :                                           Array1D<Real64> const &hr, // Radiative conductance (W/m2-K)
    2748             :                                           Array1A<Real64> &hgap,     // Gap gas conductive conductance (W/m2-K)
    2749             :                                           Array2D<Real64> &Aface,    // Coefficient in equation Aface*thetas = Bface
    2750             :                                           Array1D<Real64> &Bface     // Coefficient in equation Aface*thetas = Bface
    2751             :     )
    2752             :     {
    2753             :         Real64 gr;  // Grashof number of gas in a gap
    2754             :         Real64 con; // Gap gas conductivity
    2755             :         Real64 pr;  // Gap gas Prandtl number
    2756             :         Real64 nu;  // Gap gas Nusselt number
    2757             : 
    2758       15358 :         auto &wm = state.dataWindowManager;
    2759             : 
    2760       15358 :         if (nglasslayer == 1) {
    2761        8223 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2762        8223 :             Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
    2763             : 
    2764        8223 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2765        8223 :             Aface(2, 1) = -wm->scon[0];
    2766        8223 :             Aface(1, 2) = -wm->scon[0];
    2767        8223 :             Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
    2768             : 
    2769        7135 :         } else if (nglasslayer == 2) {
    2770        6017 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2771        6017 :             NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2772        6017 :             hgap(1) = con / wm->gaps[0].width * nu;
    2773             : 
    2774        6017 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2775        6017 :             Bface(2) = wm->AbsRadGlassFace[1];
    2776        6017 :             Bface(3) = wm->AbsRadGlassFace[2];
    2777        6017 :             Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
    2778             : 
    2779        6017 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2780        6017 :             Aface(2, 1) = -wm->scon[0];
    2781             : 
    2782        6017 :             Aface(1, 2) = -wm->scon[0];
    2783        6017 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2784        6017 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2785             : 
    2786        6017 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2787        6017 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2788        6017 :             Aface(4, 3) = -wm->scon[1];
    2789             : 
    2790        6017 :             Aface(3, 4) = -wm->scon[1];
    2791        6017 :             Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
    2792             : 
    2793        1118 :         } else if (nglasslayer == 3) {
    2794        1037 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2795        1037 :             NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2796        1037 :             hgap(1) = con / wm->gaps[0].width * nu;
    2797             : 
    2798        1037 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2799        1037 :             NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2800        1037 :             hgap(2) = con / wm->gaps[1].width * nu;
    2801             : 
    2802        1037 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2803        1037 :             Bface(2) = wm->AbsRadGlassFace[1];
    2804        1037 :             Bface(3) = wm->AbsRadGlassFace[2];
    2805        1037 :             Bface(4) = wm->AbsRadGlassFace[3];
    2806        1037 :             Bface(5) = wm->AbsRadGlassFace[4];
    2807        1037 :             Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
    2808             : 
    2809        1037 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2810        1037 :             Aface(2, 1) = -wm->scon[0];
    2811             : 
    2812        1037 :             Aface(1, 2) = -wm->scon[0];
    2813        1037 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2814        1037 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2815             : 
    2816        1037 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2817        1037 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2818        1037 :             Aface(4, 3) = -wm->scon[1];
    2819             : 
    2820        1037 :             Aface(3, 4) = -wm->scon[1];
    2821        1037 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    2822        1037 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    2823             : 
    2824        1037 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    2825        1037 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    2826        1037 :             Aface(6, 5) = -wm->scon[2];
    2827             : 
    2828        1037 :             Aface(5, 6) = -wm->scon[2];
    2829        1037 :             Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
    2830             : 
    2831          81 :         } else if (nglasslayer == 4) {
    2832          81 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2833          81 :             NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2834          81 :             hgap(1) = con / wm->gaps[0].width * nu;
    2835             : 
    2836          81 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    2837          81 :             NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    2838          81 :             hgap(2) = con / wm->gaps[1].width * nu;
    2839             : 
    2840          81 :             WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
    2841          81 :             NusseltNumber(state, 0, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
    2842          81 :             hgap(3) = con / wm->gaps[2].width * nu;
    2843             : 
    2844          81 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2845          81 :             Bface(2) = wm->AbsRadGlassFace[1];
    2846          81 :             Bface(3) = wm->AbsRadGlassFace[2];
    2847          81 :             Bface(4) = wm->AbsRadGlassFace[3];
    2848          81 :             Bface(5) = wm->AbsRadGlassFace[4];
    2849          81 :             Bface(6) = wm->AbsRadGlassFace[5];
    2850          81 :             Bface(7) = wm->AbsRadGlassFace[6];
    2851          81 :             Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
    2852             : 
    2853          81 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2854          81 :             Aface(2, 1) = -wm->scon[0];
    2855             : 
    2856          81 :             Aface(1, 2) = -wm->scon[0];
    2857          81 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    2858          81 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    2859             : 
    2860          81 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    2861          81 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    2862          81 :             Aface(4, 3) = -wm->scon[1];
    2863             : 
    2864          81 :             Aface(3, 4) = -wm->scon[1];
    2865          81 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    2866          81 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    2867             : 
    2868          81 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    2869          81 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    2870          81 :             Aface(6, 5) = -wm->scon[2];
    2871             : 
    2872          81 :             Aface(5, 6) = -wm->scon[2];
    2873          81 :             Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
    2874          81 :             Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
    2875             : 
    2876          81 :             Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
    2877          81 :             Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
    2878          81 :             Aface(8, 7) = -wm->scon[3];
    2879             : 
    2880          81 :             Aface(7, 8) = -wm->scon[3];
    2881          81 :             Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
    2882             :         }
    2883       15358 :     } // GetHeatBalanceEqCoefMatrixSimple()
    2884             : 
    2885    44666044 :     void GetHeatBalanceEqCoefMatrix(EnergyPlusData &state,
    2886             :                                     int const SurfNum,
    2887             :                                     int const nglasslayer,
    2888             :                                     WinShadingType const ShadeFlag,
    2889             :                                     Real64 const sconsh,
    2890             :                                     Real64 const TauShIR,
    2891             :                                     Real64 const EpsShIR1,
    2892             :                                     Real64 const EpsShIR2,
    2893             :                                     Real64 const RhoShIR1,
    2894             :                                     Real64 const RhoShIR2,
    2895             :                                     Real64 const ShGlReflFacIR,
    2896             :                                     Real64 const RhoGlIR1,
    2897             :                                     Real64 const RhoGlIR2,
    2898             :                                     Real64 const hcv,             // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
    2899             :                                     Real64 const TGapNew,         // Current-iteration average air temp in airflow gap (K)
    2900             :                                     Real64 const TAirflowGapNew,  // Average air temp in airflow gap between glass panes (K)
    2901             :                                     Real64 const hcvAirflowGap,   // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
    2902             :                                     Array1A<Real64> const &hcvBG, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
    2903             :                                     Array1A<Real64> const &TGapNewBG,
    2904             :                                     Array1A<Real64> const &AbsRadShadeFace,
    2905             :                                     Array1D<Real64> const &hr,
    2906             :                                     Array2D<Real64> &Aface,
    2907             :                                     Array1D<Real64> &Bface)
    2908             :     {
    2909    44666044 :         auto &wm = state.dataWindowManager;
    2910             : 
    2911             :         Real64 gr;  // Grashof number of gas in a gap
    2912             :         Real64 con; // Gap gas conductivity
    2913             :         Real64 pr;  // Gap gas Prandtl number
    2914             :         Real64 nu;  // Gap gas Nusselt number
    2915             : 
    2916             :         Real64 FacRhoIR25;         // Intermediate variable
    2917             :         Real64 FacRhoIR63;         // Intermediate variable
    2918             :         Real64 RhoIRfp;            // Intermediate variable
    2919             :         Real64 RhoIRbp;            // Intermediate variable
    2920             :         Real64 FacRhoIR2fp;        // Intermediate variable
    2921             :         Real64 FacRhoIR3bp;        // Intermediate variable
    2922             :         Real64 FacRhoIR2fpRhoIR63; // Intermediate variable
    2923             :         Real64 FacRhoIR3bpRhoIR25; // Intermediate variable
    2924             :         Real64 FacRhoIR47;         // Intermediate variable
    2925             :         Real64 FacRhoIR85;         // Intermediate variable
    2926             :         Real64 FacRhoIR4fp;        // Intermediate variable
    2927             :         Real64 FacRhoIR5bp;        // Intermediate variable
    2928             :         Real64 FacRhoIR4fpRhoIR85; // Intermediate variable
    2929             :         Real64 FacRhoIR5bpRhoIR47; // Intermediate variable
    2930             : 
    2931    44666044 :         Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance (W/m2-K)
    2932             : 
    2933    44666044 :         auto const &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
    2934             : 
    2935    44666044 :         if (nglasslayer == 1) {
    2936    30910820 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2937    30910820 :             Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
    2938             : 
    2939    30910820 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2940    30910820 :             Aface(2, 1) = -wm->scon[0];
    2941    30910820 :             Aface(1, 2) = -wm->scon[0];
    2942    30910820 :             Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
    2943             : 
    2944    30910820 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    2945             :                 // interior shade, single pane
    2946             :                 //            ||   ||
    2947             :                 //  outside  1||2 3||4
    2948             :                 //            ||   ||
    2949             :                 //            gl  bl/sh/sc
    2950      503397 :                 Bface(2) = wm->Rmir * wm->emis[1] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[1];
    2951      503397 :                 Bface(3) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    2952      503397 :                 Bface(4) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    2953             : 
    2954      503397 :                 Aface(2, 2) = hr(2) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[0] + hcv;
    2955      503397 :                 Aface(3, 2) = -wm->emis[1] * hr(3) / ShGlReflFacIR;
    2956      503397 :                 Aface(2, 3) = -hr(2) * EpsShIR1 / ShGlReflFacIR;
    2957      503397 :                 Aface(3, 3) = hr(3) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    2958      503397 :                 Aface(4, 3) = -sconsh;
    2959      503397 :                 Aface(3, 4) = -sconsh;
    2960      503397 :                 Aface(4, 4) = hr(4) + sconsh + wm->hcin;
    2961             :             }
    2962             : 
    2963    30910820 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    2964             :                 // exterior shade, single pane
    2965             :                 //           ||      ||
    2966             :                 //  outside 3||4    1||2
    2967             :                 //           ||      ||
    2968             :                 //        bl/sh/sc   gl
    2969       72296 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    2970       72296 :                 Bface(3) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    2971       72296 :                 Bface(4) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    2972             : 
    2973       72296 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    2974       72296 :                 Aface(4, 1) = -wm->emis[0] * hr(4) / ShGlReflFacIR;
    2975       72296 :                 Aface(3, 3) = hr(3) + sconsh + wm->hcout;
    2976       72296 :                 Aface(4, 3) = -sconsh;
    2977       72296 :                 Aface(1, 4) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    2978       72296 :                 Aface(3, 4) = -sconsh;
    2979       72296 :                 Aface(4, 4) = hr(4) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    2980             :             }
    2981             : 
    2982    13755224 :         } else if (nglasslayer == 2) {
    2983    13525048 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    2984    13525048 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    2985    13525048 :             hgap(1) = con / wm->gaps[0].width * nu;
    2986    13525048 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    2987     1523789 :                 wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
    2988     1523789 :                 hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
    2989             :             }
    2990             : 
    2991    13525048 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    2992    13525048 :             Bface(2) = wm->AbsRadGlassFace[1];
    2993    13525048 :             Bface(3) = wm->AbsRadGlassFace[2];
    2994    13525048 :             Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
    2995             : 
    2996    13525048 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    2997    13525048 :             Aface(2, 1) = -wm->scon[0];
    2998             : 
    2999    13525048 :             Aface(1, 2) = -wm->scon[0];
    3000    13525048 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    3001    13525048 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    3002             : 
    3003    13525048 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    3004    13525048 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    3005    13525048 :             Aface(4, 3) = -wm->scon[1];
    3006             : 
    3007    13525048 :             Aface(3, 4) = -wm->scon[1];
    3008    13525048 :             Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
    3009             : 
    3010    13525048 :             if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    3011        8052 :                 Bface(2) = wm->AbsRadGlassFace[1] + hcvAirflowGap * TAirflowGapNew;
    3012        8052 :                 Bface(3) = wm->AbsRadGlassFace[2] + hcvAirflowGap * TAirflowGapNew;
    3013        8052 :                 Aface(2, 2) = wm->scon[0] + hcvAirflowGap - wm->A23P * hr(2);
    3014        8052 :                 Aface(3, 2) = -wm->A32P * hr(3);
    3015        8052 :                 Aface(2, 3) = wm->A23P * hr(2);
    3016        8052 :                 Aface(3, 3) = hcvAirflowGap + wm->scon[1] + wm->A32P * hr(3);
    3017             :             }
    3018             : 
    3019    13525048 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3020       90082 :                 Bface(4) = wm->Rmir * wm->emis[3] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[3];
    3021       90082 :                 Bface(5) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    3022       90082 :                 Bface(6) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    3023             : 
    3024       90082 :                 Aface(4, 4) = hr(4) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[1] + hcv;
    3025       90082 :                 Aface(5, 4) = -wm->emis[3] * hr(5) / ShGlReflFacIR;
    3026       90082 :                 Aface(4, 5) = -hr(4) * EpsShIR1 / ShGlReflFacIR;
    3027       90082 :                 Aface(5, 5) = hr(5) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    3028       90082 :                 Aface(6, 5) = -sconsh;
    3029       90082 :                 Aface(5, 6) = -sconsh;
    3030       90082 :                 Aface(6, 6) = hr(6) + sconsh + wm->hcin;
    3031             :             }
    3032             : 
    3033    13525048 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    3034      103926 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    3035      103926 :                 Bface(5) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    3036      103926 :                 Bface(6) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    3037             : 
    3038      103926 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    3039      103926 :                 Aface(6, 1) = -wm->emis[0] * hr(6) / ShGlReflFacIR;
    3040      103926 :                 Aface(5, 5) = hr(5) + sconsh + wm->hcout;
    3041      103926 :                 Aface(6, 5) = -sconsh;
    3042      103926 :                 Aface(1, 6) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    3043      103926 :                 Aface(5, 6) = -sconsh;
    3044      103926 :                 Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    3045             :             }
    3046             : 
    3047    13525048 :             if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    3048       61025 :                 Array1D<Real64> RhoIR(6); // Face IR reflectance
    3049             : 
    3050      427175 :                 for (int i = 1; i <= 6; ++i) {
    3051      366150 :                     RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
    3052             :                 }
    3053       61025 :                 FacRhoIR25 = 1.0 - RhoIR(2) * RhoIR(5);
    3054       61025 :                 FacRhoIR63 = 1.0 - RhoIR(6) * RhoIR(3);
    3055       61025 :                 Real64 const tir_5_squared(pow_2(wm->tir[4]));
    3056       61025 :                 RhoIRfp = RhoIR(5) + tir_5_squared * RhoIR(3) / FacRhoIR63;
    3057       61025 :                 RhoIRbp = RhoIR(6) + tir_5_squared * RhoIR(2) / FacRhoIR25;
    3058       61025 :                 FacRhoIR2fp = 1.0 - RhoIRfp * RhoIR(2);
    3059       61025 :                 FacRhoIR3bp = 1.0 - RhoIRbp * RhoIR(3);
    3060       61025 :                 FacRhoIR2fpRhoIR63 = FacRhoIR2fp * FacRhoIR63;
    3061       61025 :                 FacRhoIR3bpRhoIR25 = FacRhoIR3bp * FacRhoIR25;
    3062       61025 :                 Aface(2, 2) = wm->scon[0] + hcvBG(1) + hr(2) * (1 - RhoIRfp * (wm->emis[1] + RhoIR(2))) / FacRhoIR2fp;
    3063       61025 :                 Aface(3, 2) = -wm->emis[1] * hr(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
    3064       61025 :                 Aface(5, 2) = -wm->emis[1] * hr(5) / FacRhoIR2fp;
    3065       61025 :                 Aface(6, 2) = -wm->emis[1] * hr(6) * RhoIR(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
    3066       61025 :                 Bface(2) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[1];
    3067       61025 :                 Aface(2, 3) = -wm->emis[2] * hr(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
    3068       61025 :                 Aface(3, 3) = wm->scon[1] + hcvBG(2) + hr(3) * (1 - RhoIRbp * (wm->emis[2] + RhoIR(3))) / FacRhoIR3bp;
    3069       61025 :                 Aface(5, 3) = -wm->emis[2] * hr(5) * RhoIR(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
    3070       61025 :                 Aface(6, 3) = -wm->emis[2] * hr(6) / FacRhoIR3bp;
    3071       61025 :                 Bface(3) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[2];
    3072       61025 :                 Aface(2, 5) = -wm->emis[4] * hr(2) / FacRhoIR2fp;
    3073       61025 :                 Aface(3, 5) = -hr(3) * wm->tir[4] * RhoIR(2) * wm->emis[4] / FacRhoIR2fpRhoIR63;
    3074       61025 :                 Aface(5, 5) = sconsh + hcvBG(1) + hr(5) * (1 - RhoIR(2) * wm->emis[4] / FacRhoIR2fp);
    3075       61025 :                 Aface(6, 5) = -sconsh - hr(6) * RhoIR(2) * wm->tir[4] * RhoIR(3) * wm->emis[4] / FacRhoIR2fpRhoIR63;
    3076       61025 :                 Bface(5) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
    3077       61025 :                 Aface(2, 6) = -hr(2) * wm->tir[4] * RhoIR(3) * wm->emis[5] / FacRhoIR3bpRhoIR25;
    3078       61025 :                 Aface(3, 6) = -wm->emis[5] * hr(3) / FacRhoIR3bp;
    3079       61025 :                 Aface(5, 6) = -sconsh - hr(5) * RhoIR(3) * wm->tir[4] * RhoIR(2) * wm->emis[5] / FacRhoIR3bpRhoIR25;
    3080       61025 :                 Aface(6, 6) = sconsh + hcvBG(2) + hr(6) * (1 - RhoIR(3) * wm->emis[5] / FacRhoIR3bp);
    3081       61025 :                 Bface(6) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
    3082       61025 :             }
    3083             : 
    3084      230176 :         } else if (nglasslayer == 3) {
    3085      123739 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    3086      123739 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    3087      123739 :             hgap(1) = con / wm->gaps[0].width * nu;
    3088      123739 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3089       15026 :                 wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
    3090       15026 :                 hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
    3091             :             }
    3092             : 
    3093      123739 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    3094      123739 :             NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    3095      123739 :             hgap(2) = con / wm->gaps[1].width * nu;
    3096      123739 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3097       15026 :                 wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
    3098       15026 :                 hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
    3099             :             }
    3100             : 
    3101      123739 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    3102      123739 :             Bface(2) = wm->AbsRadGlassFace[1];
    3103      123739 :             Bface(3) = wm->AbsRadGlassFace[2];
    3104      123739 :             Bface(4) = wm->AbsRadGlassFace[3];
    3105      123739 :             Bface(5) = wm->AbsRadGlassFace[4];
    3106      123739 :             Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
    3107             : 
    3108      123739 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    3109      123739 :             Aface(2, 1) = -wm->scon[0];
    3110             : 
    3111      123739 :             Aface(1, 2) = -wm->scon[0];
    3112      123739 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    3113      123739 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    3114             : 
    3115      123739 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    3116      123739 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    3117      123739 :             Aface(4, 3) = -wm->scon[1];
    3118             : 
    3119      123739 :             Aface(3, 4) = -wm->scon[1];
    3120      123739 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    3121      123739 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    3122             : 
    3123      123739 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    3124      123739 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    3125      123739 :             Aface(6, 5) = -wm->scon[2];
    3126             : 
    3127      123739 :             Aface(5, 6) = -wm->scon[2];
    3128      123739 :             Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
    3129             : 
    3130      123739 :             if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    3131        8375 :                 Bface(4) = wm->AbsRadGlassFace[3] + hcvAirflowGap * TAirflowGapNew;
    3132        8375 :                 Bface(5) = wm->AbsRadGlassFace[4] + hcvAirflowGap * TAirflowGapNew;
    3133        8375 :                 Aface(4, 4) = wm->scon[1] + hcvAirflowGap - wm->A45P * hr(4);
    3134        8375 :                 Aface(5, 4) = -wm->A54P * hr(5);
    3135        8375 :                 Aface(4, 5) = wm->A45P * hr(4);
    3136        8375 :                 Aface(5, 5) = hcvAirflowGap + wm->scon[2] + wm->A54P * hr(5);
    3137             :             }
    3138             : 
    3139      123739 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3140        6560 :                 Bface(6) = wm->Rmir * wm->emis[5] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[5];
    3141        6560 :                 Bface(7) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    3142        6560 :                 Bface(8) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    3143             : 
    3144        6560 :                 Aface(6, 6) = hr(6) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[2] + hcv;
    3145        6560 :                 Aface(7, 6) = -wm->emis[5] * hr(7) / ShGlReflFacIR;
    3146        6560 :                 Aface(6, 7) = -hr(6) * EpsShIR1 / ShGlReflFacIR;
    3147        6560 :                 Aface(7, 7) = hr(7) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    3148        6560 :                 Aface(8, 7) = -sconsh;
    3149        6560 :                 Aface(7, 8) = -sconsh;
    3150        6560 :                 Aface(8, 8) = hr(8) + sconsh + wm->hcin;
    3151      117179 :             } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    3152           0 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    3153           0 :                 Bface(7) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    3154           0 :                 Bface(8) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    3155             : 
    3156           0 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    3157           0 :                 Aface(8, 1) = -wm->emis[0] * hr(8) / ShGlReflFacIR;
    3158           0 :                 Aface(7, 7) = hr(7) + sconsh + wm->hcout;
    3159           0 :                 Aface(8, 7) = -sconsh;
    3160           0 :                 Aface(1, 8) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    3161           0 :                 Aface(7, 8) = -sconsh;
    3162           0 :                 Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    3163      117179 :             } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    3164       47421 :                 Array1D<Real64> RhoIR(8); // Face IR reflectance
    3165      426789 :                 for (int i = 1; i <= 8; ++i) {
    3166      379368 :                     RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
    3167             :                 }
    3168       47421 :                 FacRhoIR47 = 1 - RhoIR(4) * RhoIR(7);
    3169       47421 :                 FacRhoIR85 = 1 - RhoIR(8) * RhoIR(5);
    3170       47421 :                 Real64 const tir_7_squared(pow_2(wm->tir[6]));
    3171       47421 :                 RhoIRfp = RhoIR(7) + tir_7_squared * RhoIR(5) / FacRhoIR85;
    3172       47421 :                 RhoIRbp = RhoIR(8) + tir_7_squared * RhoIR(4) / FacRhoIR47;
    3173       47421 :                 FacRhoIR4fp = 1 - RhoIRfp * RhoIR(4);
    3174       47421 :                 FacRhoIR5bp = 1 - RhoIRbp * RhoIR(5);
    3175       47421 :                 FacRhoIR4fpRhoIR85 = FacRhoIR4fp * FacRhoIR85;
    3176       47421 :                 FacRhoIR5bpRhoIR47 = FacRhoIR5bp * FacRhoIR47;
    3177       47421 :                 Aface(4, 4) = wm->scon[1] + hcvBG(1) + hr(4) * (1 - RhoIRfp * (wm->emis[3] + RhoIR(4))) / FacRhoIR4fp;
    3178       47421 :                 Aface(5, 4) = -wm->emis[3] * hr(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
    3179       47421 :                 Aface(7, 4) = -wm->emis[3] * hr(7) / FacRhoIR4fp;
    3180       47421 :                 Aface(8, 4) = -wm->emis[3] * hr(8) * RhoIR(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
    3181       47421 :                 Bface(4) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[3];
    3182       47421 :                 Aface(4, 5) = -wm->emis[4] * hr(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
    3183       47421 :                 Aface(5, 5) = wm->scon[2] + hcvBG(2) + hr(5) * (1 - RhoIRbp * (wm->emis[4] + RhoIR(5))) / FacRhoIR5bp;
    3184       47421 :                 Aface(7, 5) = -wm->emis[4] * hr(7) * RhoIR(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
    3185       47421 :                 Aface(8, 5) = -wm->emis[4] * hr(8) / FacRhoIR5bp;
    3186       47421 :                 Bface(5) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[4];
    3187       47421 :                 Aface(4, 7) = -wm->emis[6] * hr(4) / FacRhoIR4fp;
    3188       47421 :                 Aface(5, 7) = -hr(5) * wm->tir[6] * RhoIR(4) * wm->emis[6] / FacRhoIR4fpRhoIR85;
    3189       47421 :                 Aface(7, 7) = sconsh + hcvBG(1) + hr(7) * (1 - RhoIR(4) * wm->emis[6] / FacRhoIR4fp);
    3190       47421 :                 Aface(8, 7) = -sconsh - hr(8) * RhoIR(4) * wm->tir[6] * RhoIR(5) * wm->emis[6] / FacRhoIR4fpRhoIR85;
    3191       47421 :                 Bface(7) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
    3192       47421 :                 Aface(4, 8) = -hr(4) * wm->tir[6] * RhoIR(5) * wm->emis[7] / FacRhoIR5bpRhoIR47;
    3193       47421 :                 Aface(5, 8) = -wm->emis[7] * hr(5) / FacRhoIR5bp;
    3194       47421 :                 Aface(7, 8) = -sconsh - hr(7) * RhoIR(5) * wm->tir[6] * RhoIR(4) * wm->emis[7] / FacRhoIR5bpRhoIR47;
    3195       47421 :                 Aface(8, 8) = sconsh + hcvBG(2) + hr(8) * (1 - RhoIR(5) * wm->emis[7] / FacRhoIR5bp);
    3196       47421 :                 Bface(8) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
    3197       47421 :             }
    3198             : 
    3199      106437 :         } else if (nglasslayer == 4) {
    3200      106437 :             WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
    3201      106437 :             NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
    3202      106437 :             hgap(1) = con / wm->gaps[0].width * nu;
    3203      106437 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3204           0 :                 wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
    3205           0 :                 hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
    3206             :             }
    3207             : 
    3208      106437 :             WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
    3209      106437 :             NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
    3210      106437 :             hgap(2) = con / wm->gaps[1].width * nu;
    3211      106437 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3212           0 :                 wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
    3213           0 :                 hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
    3214             :             }
    3215             : 
    3216      106437 :             WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
    3217      106437 :             NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
    3218      106437 :             hgap(3) = con / wm->gaps[2].width * nu;
    3219      106437 :             if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
    3220           0 :                 wm->hrgap[2] = 0.5 * std::abs(wm->A67) * pow_3(wm->thetas[5] + wm->thetas[6]);
    3221           0 :                 hgap(3) = hgap(3) * surfWin.edgeGlassCorrFac + wm->hrgap[2] * (surfWin.edgeGlassCorrFac - 1.0);
    3222             :             }
    3223      106437 :             Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
    3224      106437 :             Bface(2) = wm->AbsRadGlassFace[1];
    3225      106437 :             Bface(3) = wm->AbsRadGlassFace[2];
    3226      106437 :             Bface(4) = wm->AbsRadGlassFace[3];
    3227      106437 :             Bface(5) = wm->AbsRadGlassFace[4];
    3228      106437 :             Bface(6) = wm->AbsRadGlassFace[5];
    3229      106437 :             Bface(7) = wm->AbsRadGlassFace[6];
    3230      106437 :             Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
    3231             : 
    3232      106437 :             Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
    3233      106437 :             Aface(2, 1) = -wm->scon[0];
    3234             : 
    3235      106437 :             Aface(1, 2) = -wm->scon[0];
    3236      106437 :             Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
    3237      106437 :             Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
    3238             : 
    3239      106437 :             Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
    3240      106437 :             Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
    3241      106437 :             Aface(4, 3) = -wm->scon[1];
    3242             : 
    3243      106437 :             Aface(3, 4) = -wm->scon[1];
    3244      106437 :             Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
    3245      106437 :             Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
    3246             : 
    3247      106437 :             Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
    3248      106437 :             Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
    3249      106437 :             Aface(6, 5) = -wm->scon[2];
    3250             : 
    3251      106437 :             Aface(5, 6) = -wm->scon[2];
    3252      106437 :             Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
    3253      106437 :             Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
    3254             : 
    3255      106437 :             Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
    3256      106437 :             Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
    3257      106437 :             Aface(8, 7) = -wm->scon[3];
    3258             : 
    3259      106437 :             Aface(7, 8) = -wm->scon[3];
    3260      106437 :             Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
    3261             : 
    3262      106437 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3263           0 :                 Bface(8) = wm->Rmir * wm->emis[7] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[7];
    3264           0 :                 Bface(9) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
    3265           0 :                 Bface(10) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
    3266             : 
    3267           0 :                 Aface(8, 8) = hr(8) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[3] + hcv;
    3268           0 :                 Aface(9, 8) = -wm->emis[7] * hr(9) / ShGlReflFacIR;
    3269           0 :                 Aface(8, 9) = -hr(8) * EpsShIR1 / ShGlReflFacIR;
    3270           0 :                 Aface(9, 9) = hr(9) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
    3271           0 :                 Aface(10, 9) = -sconsh;
    3272           0 :                 Aface(9, 10) = -sconsh;
    3273           0 :                 Aface(10, 10) = hr(10) + sconsh + wm->hcin;
    3274             :             }
    3275             : 
    3276      106437 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    3277           0 :                 Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
    3278           0 :                 Bface(9) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
    3279           0 :                 Bface(10) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
    3280             : 
    3281           0 :                 Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
    3282           0 :                 Aface(10, 1) = -wm->emis[0] * hr(10) / ShGlReflFacIR;
    3283           0 :                 Aface(9, 9) = hr(9) + sconsh + wm->hcout;
    3284           0 :                 Aface(10, 9) = -sconsh;
    3285           0 :                 Aface(1, 10) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
    3286           0 :                 Aface(9, 10) = -sconsh;
    3287           0 :                 Aface(10, 10) = hr(10) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
    3288             :             }
    3289             : 
    3290             :         } else {
    3291           0 :             ShowFatalError(state, format("SolveForWindowTemperatures: Invalid number of Glass Layers={}, up to 4 allowed.", wm->ngllayer));
    3292             :         }
    3293    44666044 :     } // GetHeatBalanceEqCoefMatrix()
    3294             : 
    3295    23964637 :     void SolveForWindowTemperatures(EnergyPlusData &state, int const SurfNum) // Surface number
    3296             :     {
    3297             : 
    3298             :         // SUBROUTINE INFORMATION:
    3299             :         //       AUTHOR         F. Winkelmann
    3300             :         //       DATE WRITTEN   July 2000
    3301             :         //       MODIFIED       Oct 2000, FW: modify edge-of-glass correction to account
    3302             :         //                       for gap radiative conductance affects
    3303             :         //                      Feb 2001, FW: add interior or exterior shade to layer
    3304             :         //                       heat balance calculation.
    3305             :         //                      Mar 2001, FW: relax error tolerance if MaxIterations reached.
    3306             :         //                      Jun 2001, FW: add interior or exterior blind
    3307             :         //                      Nov 2002, FW: add relaxation on face temperatures
    3308             :         //                       to improve convergence for multipane cases where outer pane
    3309             :         //                       has high solar absorptance: temp --> 0.5*(temp + previous temp);
    3310             :         //                       also, increase MaxIterations from 50 to 100.
    3311             :         //                      Dec 2002, FW: add between-glass shade/blind for double and triple glazing.
    3312             :         //                      Mar 2003, FW: remove redundant relaxation on radiative conductances
    3313             :         //                      Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02 to enhance
    3314             :         //                                    convergence in difficult cases.
    3315             :         //                      June 2003, FW: correct the expression for convective gain to zone air
    3316             :         //                       from airflow windows with airflow destination = InsideAir. Previously
    3317             :         //                       convective gain of air as it passed through gap was used, which is correct
    3318             :         //                       for airflow source = InsideAir but incorrect for airflow source = OutsideAir.
    3319             :         //                       Save SurfaceWindow%TAirflowGapOutlet for use in calculating convective heat
    3320             :         //                       gain to return air when airflow source = InsideAir, destination = ReturnAir.
    3321             :         //                      Dec 2003, FW: enhance converge for difficult cases by increasing relaxation
    3322             :         //                       in layer surface temperatures for iterations > MaxIterations/4
    3323             :         //                      May 2006, RR: add exterior window screen
    3324             :         //                      January 2009, BG: inserted call to recalc inside face convection inside iteration loop
    3325             :         //                        per ISO 15099 Section 8.3.2.2
    3326             :         //       RE-ENGINEERED  na
    3327             : 
    3328             :         // PURPOSE OF THIS SUBROUTINE:
    3329             :         // Evaluates the coefficients Aface and Bface in the system of linear
    3330             :         // algebraic equations
    3331             :         //     Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglfacep, j=1,nglfacep
    3332             :         // where
    3333             :         // nglface  = number of glass faces (= 2 * number of glass layers), or, if shade or blind is present,
    3334             :         // nglgacep = number of glass faces + 2
    3335             :         // thetas(j) = temperature of face j
    3336             :         // If an interior, exterior or between-glass shade or blind, or exterior screen is present
    3337             :         // the face numbering is as follows:
    3338             :         //   1 to 2*nglface are glass faces, from outside to inside;
    3339             :         //   2*nglface+1 and 2*nglface+2 are the shade or blind faces, from outside to inside
    3340             :         // For example, the following diagram shows the face number for an exterior shade, screen or blind
    3341             :         // on double glazing:
    3342             :         //     ||   ||   ||
    3343             :         //    5||6 1||2 3||4
    3344             :         //     ||   ||   ||
    3345             :         // bl/sh/sc gl   gl
    3346             : 
    3347             :         // And for a between-glass shade/blind in triple glazing:
    3348             :         //     ||   ||   ||   ||
    3349             :         //    1||2 3||4 7||8 5||6
    3350             :         //     ||   ||   ||   ||
    3351             :         //     gl   gl  bl/sh gl
    3352             : 
    3353             :         // METHODOLOGY EMPLOYED:
    3354             :         // The Aface and Bface coefficients are determined by the equations for
    3355             :         // heat balance at the glass and shade/blind faces. The system of linear equations is solved
    3356             :         // by LU decomposition.
    3357             : 
    3358             :         // Using/Aliasing
    3359             :         using Convect::CalcISO15099WindowIntConvCoeff;
    3360             :         using Psychrometrics::PsyCpAirFnW;
    3361             :         using Psychrometrics::PsyHFnTdbW;
    3362             :         using Psychrometrics::PsyRhoAirFnPbTdbW;
    3363             :         using Psychrometrics::PsyTdbFnHW;
    3364             : 
    3365    23964637 :         constexpr int MaxIterations(100); // Maximum allowed number of iterations (increased 9/01 from 15 to 50,
    3366             :         //   increased 11/02 from 50 to 100)
    3367    23964637 :         constexpr Real64 errtemptol(0.02); // Tolerance on errtemp for convergence (increased from 0.01, 3/4/03)
    3368             : 
    3369             :         int ZoneNum; // Zone number corresponding to SurfNum
    3370             :         int d;       // +1 if number of row interchanges is even,
    3371             :         // -1 if odd (in LU decomposition
    3372             : 
    3373    23964637 :         auto &wm = state.dataWindowManager;
    3374             : 
    3375    23964637 :         int iter = 0;                    // Iteration number
    3376    23964637 :         Real64 errtemp = 0.0;            // Absolute value of sum of face temperature differences between iterations, divided by number of faces
    3377    23964637 :         Real64 VGap = 0.0;               // Air velocity in gap between glass and shade/blind (m/s)
    3378    23964637 :         Real64 VAirflowGap = 0.0;        // Air velocity in airflow gap between glass panes (m/s)
    3379    23964637 :         Real64 VGapPrev = 0.0;           // Value of VGap from previous iteration
    3380    23964637 :         Real64 TGapNew = 0.0;            // Average air temp in gap between glass and shade/blind (K)
    3381    23964637 :         Real64 TAirflowGapNew = 0.0;     // Average air temp in airflow gap between glass panes (K)
    3382    23964637 :         Real64 TGapOutlet = 0.0;         // Temperature of air leaving gap between glass and shade/blind (K)
    3383    23964637 :         Real64 TAirflowGapOutlet = 0.0;  // Temperature of air leaving airflow gap between glass panes (K)
    3384    23964637 :         Real64 TAirflowGapOutletC = 0.0; // Temperature of air leaving airflow gap between glass panes (C)
    3385    23964637 :         Real64 hcv = 0.0;                // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
    3386    23964637 :         Real64 hcvAirflowGap = 0.0;      // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
    3387    23964637 :         Real64 hcvPrev = 0.0;            // Value of hcv from previous iteration
    3388    23964637 :         Real64 ConvHeatFlowForced = 0.0; // Convective heat flow from forced airflow gap (W)
    3389    23964637 :         Real64 ShGlReflFacIR = 0.0;      // Factor for long-wave inter-reflection between shade/blind and adjacent glass
    3390    23964637 :         Real64 RhoGlIR1 = 0.0;           // Long-wave reflectance of glass surface facing shade/blind; 1=exterior shade/blind,
    3391    23964637 :         Real64 RhoGlIR2 = 0.0;
    3392             :         //  2=exterior shade/blind
    3393    23964637 :         Real64 EpsShIR1 = 0.0; // Long-wave emissivity of shade/blind surface facing glass; 1=interior shade/blind,
    3394    23964637 :         Real64 EpsShIR2 = 0.0;
    3395             :         //  2=interior shade/blind
    3396    23964637 :         Real64 RhoShIR1 = 0.0; // Long-wave reflectance of shade/blind surface facing glass; 1=interior shade/blind,
    3397    23964637 :         Real64 RhoShIR2 = 0.0;
    3398             :         //  2=exterior shade/blind
    3399    23964637 :         Real64 TauShIR = 0.0; // Long-wave transmittance of isolated shade/blind
    3400    23964637 :         Real64 sconsh = 0.0;  // shade/blind conductance (W/m2-K)
    3401             : 
    3402    23964637 :         WinShadingType ShadeFlag = WinShadingType::NoShade; // Shading flag
    3403             :         //  radiation from lights and zone equipment absorbed by faces of shade/blind (W/m2)
    3404    23964637 :         Real64 ShadeArea = 0.0; // shade/blind area (m2)
    3405             :         // Real64 CondHeatGainGlass = 0.0; // Conduction through inner glass layer, outside to inside (W)
    3406             :         // Real64 CondHeatGainShade = 0.0; // Conduction through shade/blind, outside to inside (W)
    3407             :         //  shade/blind is present. Zero if shade/blind has zero IR transmittance (W)
    3408             :         // Real64 IncidentSolar = 0.0;         // Solar incident on outside of window (W)
    3409    23964637 :         Real64 TotAirflowGap = 0.0;  // Total volumetric airflow through window gap (m3/s)
    3410    23964637 :         Real64 CpAirOutlet = 0.0;    // Heat capacity of air from window gap (J/kg-K)
    3411    23964637 :         Real64 CpAirZone = 0.0;      // Heat capacity of zone air (J/kg-K)
    3412    23964637 :         Real64 InletAirHumRat = 0.0; // Humidity ratio of air from window gap entering fan
    3413    23964637 :         int InsideFaceIndex = 0;     // intermediate variable for index of inside face in thetas
    3414             : 
    3415    23964637 :         Array1D<Real64> hr = Array1D<Real64>(2 * maxGlassLayers); // Radiative conductance (W/m2-K)
    3416    23964637 :         Array1D<Real64> AbsRadShadeFace(2);                       // Solar radiation, short-wave radiation from lights, and long-wave
    3417    23964637 :         Array1D<Real64> TGapNewBG(2);                             // For between-glass shade/blind, average gas temp in gaps on either
    3418             :         //  side of shade/blind (K)
    3419    23964637 :         Array1D<Real64> hcvBG(2); // For between-glass shade/blind, convection coefficient from gap glass or
    3420             :         //  shade/blind to gap gas on either side of shade/blind (W/m2-K)
    3421             : 
    3422    47929274 :         Array2D<Real64> Aface(2 * maxGlassLayers, 2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
    3423    23964637 :         Array1D<Real64> Bface(2 * maxGlassLayers);                     // Coefficient in equation Aface*thetas = Bface
    3424    23964637 :         Array1D_int indx(2 * maxGlassLayers);                          // Vector of row permutations in LU decomposition
    3425             : 
    3426    23964637 :         wm->nglfacep = wm->nglface;
    3427    23964637 :         ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    3428    23964637 :         ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
    3429    23964637 :         AbsRadShadeFace = 0.0;
    3430             : 
    3431    23964637 :         if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
    3432      186115 :             wm->nglfacep = wm->nglface + 2;
    3433      186115 :             AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(state, SurfNum);
    3434      186115 :             AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(state, SurfNum);
    3435      186115 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsRadShadeFace(2) += state.dataSurface->SurfWinIntLWAbsByShade(SurfNum);
    3436      186115 :             sconsh = wm->scon[wm->ngllayer];
    3437      186115 :             TauShIR = wm->tir[wm->nglface];
    3438      186115 :             EpsShIR1 = wm->emis[wm->nglface];
    3439      186115 :             EpsShIR2 = wm->emis[wm->nglface + 1];
    3440      186115 :             RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
    3441      186115 :             RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
    3442      186115 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3443      147791 :                 RhoGlIR2 = 1.0 - wm->emis[2 * wm->ngllayer - 1];
    3444      147791 :                 ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
    3445       38324 :             } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
    3446       21454 :                 RhoGlIR1 = 1.0 - wm->emis[0];
    3447       21454 :                 ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2;
    3448             :             }
    3449             :         } // End of check if shade or blind is on
    3450             : 
    3451             :         // Initialize face temperatures.
    3452             : 
    3453    23964637 :         StartingWindowTemps(state, SurfNum, AbsRadShadeFace);
    3454             : 
    3455    23964637 :         hcvPrev = 0.0;
    3456    23964637 :         VGapPrev = 0.0;
    3457             : 
    3458             :         // Calculate radiative conductances
    3459             : 
    3460    23964637 :         errtemp = errtemptol * 2.0;
    3461             : 
    3462    68630681 :         while (iter < MaxIterations && errtemp > errtemptol) {
    3463             : 
    3464   163951220 :             for (int i = 1; i <= wm->nglfacep; ++i) {
    3465   119285176 :                 hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
    3466             :                 // Following line is redundant since thetas is being relaxed;
    3467             :                 // removed by FCW, 3/4/03
    3468             :                 //! fw if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
    3469             :             }
    3470             : 
    3471             :             // call for new interior film coeff (since it is temperature dependent) if using Detailed inside coef model
    3472    44666044 :             if (((state.dataSurface->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) &&
    3473    54759300 :                  (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo == Convect::HcInt::ASHRAETARP)) ||
    3474    10093256 :                 (state.dataSurface->surfIntConv(SurfNum).model == Convect::HcInt::ASHRAETARP)) {
    3475             :                 // coef model is "detailed" and not prescribed by user
    3476             :                 // need to find inside face index, varies with shade/blind etc.
    3477    34572788 :                 if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3478      600039 :                     InsideFaceIndex = wm->nglfacep;
    3479             :                 } else {
    3480    33972749 :                     InsideFaceIndex = wm->nglface;
    3481             :                 }
    3482    34572788 :                 CalcISO15099WindowIntConvCoeff(state, SurfNum, wm->thetas[InsideFaceIndex - 1] - Constant::Kelvin, wm->tin - Constant::Kelvin);
    3483    34572788 :                 wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
    3484             :             }
    3485             : 
    3486    44666044 :             Aface = 0.0;
    3487    44666044 :             Bface = 0.0;
    3488             : 
    3489             :             // If interior or exterior shade or blind is present, get heat transfer
    3490             :             // coefficient from glass and shade/blind to gap between glass and shade/blind,
    3491             :             // effective gap air temperature, velocity of air in gap and gap outlet temperature.
    3492             : 
    3493    44666044 :             if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3494      776261 :                 ExtOrIntShadeNaturalFlow(
    3495      776261 :                     state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum));
    3496      776261 :                 if (iter >= 1) {
    3497      607016 :                     hcv = 0.5 * (hcvPrev + hcv);
    3498      607016 :                     VGap = 0.5 * (VGapPrev + VGap);
    3499             :                 }
    3500      776261 :                 hcvPrev = hcv;
    3501      776261 :                 VGapPrev = VGap;
    3502             :             }
    3503             : 
    3504    44666044 :             TAirflowGapOutlet = 0.0;
    3505             :             // If between-glass shade or blind is not present and this is an airflow window
    3506             :             // (i.e., with forced airflow in the gap for double glass or in the inner gap for triple glass)
    3507             :             // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and
    3508             :             // convective heat flow from gap.
    3509             : 
    3510    44666044 :             if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    3511       16427 :                 BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced);
    3512             :             }
    3513             : 
    3514             :             // If between-glass shade or blind is present, get convective heat transfer
    3515             :             // coefficients from glass and shade/blind to the two gaps on either side of the shade/blind.
    3516             :             // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the
    3517             :             // convective heat flows from the gaps.
    3518             : 
    3519    44666044 :             if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    3520      108446 :                 if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps
    3521       88448 :                     BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG);
    3522             :                 } else { // Forced convection in gaps
    3523       19998 :                     BetweenGlassShadeForcedFlow(state, SurfNum, iter, VGap, TGapNewBG, TAirflowGapOutlet, hcvBG, ConvHeatFlowForced);
    3524             :                 }
    3525             :             }
    3526             : 
    3527    44666044 :             ++iter;
    3528             : 
    3529             :             // Calculations based on number of glass layers
    3530    89332088 :             GetHeatBalanceEqCoefMatrix(state,
    3531             :                                        SurfNum,
    3532    44666044 :                                        wm->ngllayer,
    3533             :                                        ShadeFlag,
    3534             :                                        sconsh,
    3535             :                                        TauShIR,
    3536             :                                        EpsShIR1,
    3537             :                                        EpsShIR2,
    3538             :                                        RhoShIR1,
    3539             :                                        RhoShIR2,
    3540             :                                        ShGlReflFacIR,
    3541             :                                        RhoGlIR1,
    3542             :                                        RhoGlIR2,
    3543             :                                        hcv,
    3544             :                                        TGapNew,
    3545             :                                        TAirflowGapNew,
    3546             :                                        hcvAirflowGap,
    3547             :                                        hcvBG,
    3548             :                                        TGapNewBG,
    3549             :                                        AbsRadShadeFace,
    3550             :                                        hr,
    3551             :                                        Aface,
    3552             :                                        Bface);
    3553    44666044 :             LUdecomposition(state, Aface, wm->nglfacep, indx, d); // Note that these routines change Aface;
    3554    44666044 :             LUsolution(state, Aface, wm->nglfacep, indx, Bface);  // face temperatures are returned in Bface
    3555             : 
    3556   163951220 :             for (int i = 1; i <= wm->nglfacep; ++i) {
    3557   119285176 :                 wm->thetasPrev[i - 1] = wm->thetas[i - 1];
    3558   119285176 :                 if (iter < MaxIterations / 4) {
    3559   119285144 :                     wm->thetas[i - 1] = 0.5 * wm->thetas[i - 1] + 0.5 * Bface(i);
    3560             :                 } else {
    3561          32 :                     wm->thetas[i - 1] = 0.75 * wm->thetas[i - 1] + 0.25 * Bface(i);
    3562             :                 }
    3563             :             }
    3564             : 
    3565    44666044 :             errtemp = 0.0;
    3566   163951220 :             for (int i = 1; i <= wm->nglfacep; ++i) {
    3567   119285176 :                 errtemp += std::abs(wm->thetas[i - 1] - wm->thetasPrev[i - 1]);
    3568             :             }
    3569    44666044 :             errtemp /= wm->nglfacep;
    3570             :         }
    3571             : 
    3572    23964637 :         state.dataSurface->SurfWinWindowCalcIterationsRep(SurfNum) = iter;
    3573             : 
    3574             :         // We have reached iteration limit or we have converged. If we have reached the
    3575             :         // iteration limit the following test relaxes the convergence tolerance.
    3576             :         // If we have converged (errtemp <= errtemptol) the following test has not effect.
    3577             : 
    3578    23964637 :         if (errtemp < 10 * errtemptol) {
    3579             : 
    3580             :             // Window heat balance solution has converged.
    3581             : 
    3582             :             // For interior shade, add convective gain from glass/shade gap air flow to zone convective gain;
    3583             :             // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for
    3584             :             // contribution of frame and divider.
    3585             :             // IncidentSolar = state.dataSurface->Surface(SurfNum).Area * state.dataHeatBal->SurfQRadSWOutIncident(SurfNum);
    3586    23964637 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3587             :                 // Interior shade or blind
    3588             :                 // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection
    3589             :                 //   from air exiting gap, convection from zone-side of shade/blind, net IR to zone from shade and net IR to
    3590             :                 //   zone from the glass adjacent to the shade/blind (zero if shade/blind IR transmittance is zero).
    3591             :                 // Following assumes glazed area = window area (i.e., dividers ignored) in calculating
    3592             :                 //   IR to zone from glass when interior shade/blind is present.
    3593      147791 :                 ShadeArea = state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum);
    3594             :                 // CondHeatGainShade = ShadeArea * sconsh *
    3595             :                 //                     (wm->thetas(wm->nglfacep - 1) -
    3596             :                 //                     wm->thetas[wm->nglfacep-1]);
    3597      147791 :                 state.dataSurface->SurfWinGainIRShadeToZoneRep(SurfNum) =
    3598      147791 :                     ShadeArea * EpsShIR2 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 1]) - wm->Rmir) +
    3599      147791 :                     EpsShIR1 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 2]) - wm->Rmir) * RhoGlIR2 * TauShIR / ShGlReflFacIR;
    3600      147791 :                 state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) =
    3601      147791 :                     ShadeArea * (wm->emis[2 * wm->ngllayer - 1] * TauShIR / ShGlReflFacIR) *
    3602      147791 :                     (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
    3603      147791 :                 state.dataSurface->SurfWinGainConvShadeToZoneRep(SurfNum) = ShadeArea * wm->hcin * (wm->thetas[wm->nglfacep - 1] - wm->tin);
    3604      147791 :                 state.dataSurface->SurfWinHeatGain(SurfNum) =
    3605      147791 :                     state.dataSurface->SurfWinTransSolar(SurfNum) + state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum) +
    3606      147791 :                     state.dataSurface->SurfWinGainConvShadeToZoneRep(SurfNum) + state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) +
    3607      147791 :                     state.dataSurface->SurfWinGainIRShadeToZoneRep(SurfNum);
    3608             :             } else {
    3609             :                 // Interior shade or blind not present; innermost layer is glass
    3610             :                 // CondHeatGainGlass = state.dataSurface->Surface(SurfNum).Area * wm->scon(wm->ngllayer) *
    3611             :                 //                     (wm->thetas(2 * wm->ngllayer - 1) -
    3612             :                 //                     wm->thetas[2 * wm->ngllayer - 1]);
    3613    23816846 :                 state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) =
    3614    23816846 :                     state.dataSurface->Surface(SurfNum).Area * wm->emis[2 * wm->ngllayer - 1] *
    3615    23816846 :                     (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
    3616    23816846 :                 state.dataSurface->SurfWinGainConvGlazToZoneRep(SurfNum) =
    3617    23816846 :                     state.dataSurface->Surface(SurfNum).Area * wm->hcin * (wm->thetas[2 * wm->ngllayer - 1] - wm->tin);
    3618    47633692 :                 state.dataSurface->SurfWinHeatGain(SurfNum) = state.dataSurface->SurfWinTransSolar(SurfNum) +
    3619    23816846 :                                                               state.dataSurface->SurfWinGainConvGlazToZoneRep(SurfNum) +
    3620    23816846 :                                                               state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum);
    3621             :             }
    3622             : 
    3623             :             // Add convective heat gain from airflow window
    3624             :             // Note: effect of fan heat on gap outlet temperature is neglected since fan power (based
    3625             :             // on pressure drop through the gap) is extremely small
    3626             : 
    3627    23964637 :             state.dataSurface->SurfWinGapConvHtFlowRep(SurfNum) = 0.0;
    3628    23964637 :             state.dataSurface->SurfWinGapConvHtFlowRepEnergy(SurfNum) = 0.0;
    3629    23964637 :             TotAirflowGap = state.dataSurface->SurfWinAirflowThisTS(SurfNum) * state.dataSurface->Surface(SurfNum).Width;
    3630    23964637 :             TAirflowGapOutletC = TAirflowGapOutlet - Constant::Kelvin;
    3631    23964637 :             state.dataSurface->SurfWinTAirflowGapOutlet(SurfNum) = TAirflowGapOutletC;
    3632    23964637 :             if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    3633       16128 :                 state.dataSurface->SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowForced;
    3634       16128 :                 state.dataSurface->SurfWinGapConvHtFlowRepEnergy(SurfNum) =
    3635       16128 :                     state.dataSurface->SurfWinGapConvHtFlowRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    3636             :                 // Add heat from gap airflow to zone air if destination is inside air; save the heat gain to return
    3637             :                 // air in case it needs to be sent to the zone (due to no return air determined in HVAC simulation)
    3638       32256 :                 if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor ||
    3639       16128 :                     state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Return) {
    3640           0 :                     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    3641           0 :                     if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    3642           0 :                         InletAirHumRat = thisZoneHB.airHumRat;
    3643             :                     } else { // AirflowSource = outside air
    3644           0 :                         InletAirHumRat = state.dataEnvrn->OutHumRat;
    3645             :                     }
    3646           0 :                     Real64 ZoneTemp = thisZoneHB.MAT; // this should be Tin (account for different reference temps)
    3647           0 :                     CpAirOutlet = PsyCpAirFnW(InletAirHumRat);
    3648           0 :                     CpAirZone = PsyCpAirFnW(thisZoneHB.airHumRat);
    3649           0 :                     state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum) =
    3650           0 :                         TotAirflowGap * (CpAirOutlet * (TAirflowGapOutletC)-CpAirZone * ZoneTemp);
    3651           0 :                     if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor) {
    3652           0 :                         state.dataSurface->SurfWinHeatGain(SurfNum) += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
    3653             :                     }
    3654             :                 }
    3655             :                 // For AirflowDestination = ReturnAir in a controlled (i.e., conditioned) zone with return air, see CalcZoneLeavingConditions
    3656             :                 // for calculation of modification of return-air temperature due to airflow from window gaps into return air.
    3657             :             }
    3658             : 
    3659             :             // Correct WinHeatGain for interior diffuse shortwave (solar and shortwave from lights) transmitted
    3660             :             // back out window
    3661    23964637 :             int const ConstrNum = state.dataSurface->SurfActiveConstruction(SurfNum);
    3662    23964637 :             int const ConstrNumSh = state.dataSurface->SurfWinActiveShadedConstruction(SurfNum);
    3663             : 
    3664    23964637 :             Real64 reflDiff = 0.0; // Diffuse shortwave back reflectance
    3665    23964637 :             if (NOT_SHADED(ShadeFlag)) {
    3666    23706736 :                 reflDiff = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack;
    3667      257901 :             } else if (ANY_SHADE_SCREEN(ShadeFlag)) {
    3668       49460 :                 reflDiff = state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack;
    3669      208441 :             } else if (ANY_BLIND(ShadeFlag)) {
    3670      136655 :                 if (state.dataSurface->SurfWinMovableSlats(SurfNum)) {
    3671        9366 :                     reflDiff = General::Interp(
    3672        3122 :                         state.dataConstruction->Construct(ConstrNumSh).BlReflectSolDiffBack(state.dataSurface->SurfWinSlatsAngIndex(SurfNum)),
    3673        3122 :                         state.dataConstruction->Construct(ConstrNumSh)
    3674        6244 :                             .BlTransDiff(std::min(Material::MaxSlatAngs, state.dataSurface->SurfWinSlatsAngIndex(SurfNum) + 1)),
    3675        3122 :                         state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum));
    3676             :                 } else {
    3677      133533 :                     reflDiff = state.dataConstruction->Construct(ConstrNumSh).BlReflectSolDiffBack(1);
    3678             :                 }
    3679       71786 :             } else if (ShadeFlag == WinShadingType::SwitchableGlazing) {
    3680       71786 :                 reflDiff = InterpSw(state.dataSurface->SurfWinSwitchingFactor(SurfNum),
    3681       71786 :                                     state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack,
    3682       71786 :                                     state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack);
    3683             :             }
    3684             :             // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is?  LKL (9/2012)
    3685    23964637 :             state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) =
    3686    23964637 :                 state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(SurfNum).SolarEnclIndex) * state.dataSurface->Surface(SurfNum).Area *
    3687    47929274 :                     (1 - reflDiff) +
    3688    23964637 :                 state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
    3689    23964637 :             state.dataSurface->SurfWinHeatGain(SurfNum) -=
    3690    23964637 :                 (state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) +
    3691    23964637 :                  state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * state.dataSurface->Surface(SurfNum).Area);
    3692             : 
    3693    23964637 :             if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
    3694      186115 :                 state.dataSurface->SurfWinShadingAbsorbedSolar(SurfNum) =
    3695      186115 :                     (state.dataSurface->SurfWinExtBeamAbsByShade(SurfNum) + state.dataSurface->SurfWinExtDiffAbsByShade(SurfNum)) *
    3696      186115 :                     (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum));
    3697      186115 :                 state.dataSurface->SurfWinShadingAbsorbedSolarEnergy(SurfNum) =
    3698      186115 :                     state.dataSurface->SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    3699             :             }
    3700    23964637 :             if (state.dataEnvrn->SunIsUp) {
    3701             : 
    3702    12130790 :                 state.dataSurface->SurfWinSysSolTransmittance(SurfNum) =
    3703    12130790 :                     state.dataSurface->SurfWinTransSolar(SurfNum) /
    3704    12130790 :                     (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) *
    3705    12130790 :                          (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum)) +
    3706             :                      0.0001);
    3707    12130790 :                 state.dataSurface->SurfWinSysSolAbsorptance(SurfNum) =
    3708    12130790 :                     (state.dataHeatBal->SurfWinQRadSWwinAbsTot(SurfNum) + state.dataSurface->SurfWinShadingAbsorbedSolar(SurfNum)) /
    3709    12130790 :                     (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) *
    3710    12130790 :                          (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum)) +
    3711             :                      0.0001);
    3712    12130790 :                 state.dataSurface->SurfWinSysSolReflectance(SurfNum) =
    3713    12130790 :                     1.0 - state.dataSurface->SurfWinSysSolTransmittance(SurfNum) - state.dataSurface->SurfWinSysSolAbsorptance(SurfNum);
    3714             :             } else {
    3715    11833847 :                 state.dataSurface->SurfWinSysSolTransmittance(SurfNum) = 0.0;
    3716    11833847 :                 state.dataSurface->SurfWinSysSolAbsorptance(SurfNum) = 0.0;
    3717    11833847 :                 state.dataSurface->SurfWinSysSolReflectance(SurfNum) = 0.0;
    3718             :             }
    3719             : 
    3720             :             // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps)
    3721    23964637 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag))
    3722      169245 :                 state.dataSurface->SurfWinConvCoeffWithShade(SurfNum) = hcv;
    3723             :         } else {
    3724             :             // No convergence after MaxIterations even with relaxed error tolerance
    3725           0 :             ShowSevereError(state, format("Convergence error in SolveForWindowTemperatures for window {}", state.dataSurface->Surface(SurfNum).Name));
    3726           0 :             ShowContinueErrorTimeStamp(state, "");
    3727             : 
    3728           0 :             if (state.dataGlobal->DisplayExtraWarnings) {
    3729             :                 // report out temperatures
    3730           0 :                 for (int i = 1; i <= wm->nglfacep; ++i) {
    3731           0 :                     ShowContinueError(state,
    3732           0 :                                       format("Glazing face index = {} ; new temperature ={:.4R}C  ; previous temperature = {:.4R}C",
    3733             :                                              i,
    3734           0 :                                              wm->thetas[i - 1] - Constant::Kelvin,
    3735           0 :                                              wm->thetasPrev[i - 1] - Constant::Kelvin));
    3736             :                 }
    3737             :             }
    3738             : 
    3739           0 :             ShowFatalError(state,
    3740           0 :                            format("Program halted because of convergence error in SolveForWindowTemperatures for window {}",
    3741           0 :                                   state.dataSurface->Surface(SurfNum).Name));
    3742             :         }
    3743    23964637 :     } // SolveForWindowTemperatures()
    3744             : 
    3745             :     //****************************************************************************
    3746             : 
    3747      776261 :     void ExtOrIntShadeNaturalFlow(EnergyPlusData &state,
    3748             :                                   int const SurfNum,  // Surface number
    3749             :                                   int const iter,     // Iteration number for glass heat balance calculation
    3750             :                                   Real64 &VGap,       // Air velocity in glass-shade/blind gap (m/s)
    3751             :                                   Real64 &TGapNew,    // Current-iteration average air temp in glass-shade/blind gap (K)
    3752             :                                   Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
    3753             :                                   Real64 &hcv,        // Convection coefficient from gap glass or shade to gap air (W/m2-K)
    3754             :                                   Real64 &QConvGap    // Convective heat gain from glass-shade/blind gap for interior shade (W)
    3755             :     )
    3756             :     {
    3757             : 
    3758             :         // SUBROUTINE INFORMATION:
    3759             :         //       AUTHOR         F. Winkelmann
    3760             :         //       DATE WRITTEN   December 2000
    3761             :         //       MODIFIED       June 2001: add window blinds
    3762             :         //                      May 2006 (RR): add exterior window screens
    3763             :         //       RE-ENGINEERED  na
    3764             : 
    3765             :         // PURPOSE OF THIS SUBROUTINE:
    3766             :         // Called by SolveForWindowTemperatures for windows that have an interior
    3767             :         // or exterior blind or shade in place.
    3768             :         // Solves for air flow in gap between glass and shade/blind.
    3769             :         // Finds temperature of gap air and coefficient for convective heat transfer
    3770             :         // from glass to gap air and shade/blind to gap air.
    3771             : 
    3772             :         // METHODOLOGY EMPLOYED:
    3773             :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    3774             :         // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
    3775             : 
    3776             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    3777             :         //   air flow or bottom for downward air flow (K)
    3778             : 
    3779             :         int ConstrNumSh;  // Shaded construction number
    3780             :         int MatNumSh;     // Material number of shade/blind layer
    3781             :         int nglassfaces;  // Number of glass faces in contruction
    3782             :         Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
    3783             :         //   air flow or top for downward air flow (K)
    3784             :         Real64 TGlassFace; // Temperature of glass surface facing glass-shade/blind gap (K)
    3785             :         Real64 TShadeFace; // Temperature of shade surface facing glass-shade/blind gap (K)
    3786             :         Real64 hGapStill;  // Still-air glass-shade/blind gap conduction/convection coeff (W/m2-K)
    3787             :         Real64 TGapOld;    // Previous-iteration average air temp in glass-shade/blind gap (K)
    3788             :         Real64 GapHeight;  // Vertical length of glass-shade/blind gap (m)
    3789             :         Real64 GapDepth;   // Distance from shade to glass (m)
    3790             :         Real64 RhoAir;     // Density of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
    3791             :         Real64 RhoTRef;    // Density of glass-shade/blind air at reference temp = KelvinConv (kg/m3)
    3792             :         Real64 ViscAir;    // Viscosity of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
    3793             :         Real64 AGap;       // Cross sectional area of glass-shade/blind gap (m2); for vertical window, this
    3794             :         //   is in horizontal plane normal to window.
    3795             :         Real64 ATopGap; // Area of the top and bottom openings (m2)
    3796             :         Real64 ABotGap;
    3797             :         Real64 ALeftGap; // Area of the left and right openings (m2)
    3798             :         Real64 ARightGap;
    3799             :         Real64 AHolesGap; // Area of the holes in the shade (assumed homogeneously
    3800             :         //   distributed) (m2)
    3801             :         Real64 ATopLRH; // Intermediate variables
    3802             :         Real64 ABotLRH;
    3803             :         Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
    3804             :         Real64 AEqOutlet;
    3805             :         Real64 Zinlet; // Inlet and outlet pressure loss factors
    3806             :         Real64 Zoutlet;
    3807             :         Real64 AVGap;         // Coeff. of VGap**2 term in pressure balance equation
    3808             :         Real64 BVGap;         // Coeff. of VGap term in pressure balance equation
    3809             :         Real64 CVGap;         // VGap-independent term in pressure balance equation
    3810             :         Real64 GapHeightChar; // Characteristic height of the gap air temperature profile (m)
    3811             :         Real64 TAve;          // Average of TGlass and TShade (K)
    3812             :         // REAL(r64)            :: AirProps(8)         ! Air properties
    3813             :         int TotGaps;              // Glass/glass gaps + glass-shade/blind gap
    3814             :         Real64 con;               // Gap conductivity and derivative
    3815             :         Real64 gr;                // glass-shade/blind gap Grashof number
    3816             :         Real64 pr;                // glass-shade/blind gap Prandtl number
    3817             :         Real64 nu;                // glass-shade/blind gap Nusselt number
    3818             :         WinShadingType ShadeFlag; // Shading flag
    3819             :         int BlNum;                // Blind number
    3820             : 
    3821      776261 :         auto &wm = state.dataWindowManager;
    3822             :         // Air properties
    3823             :         //               Dens  dDens/dT  Con    dCon/dT   Vis    dVis/dT Prandtl dPrandtl/dT
    3824             :         // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72,   1.8d-3  /
    3825             : 
    3826      776261 :         ConstrNumSh = state.dataSurface->SurfWinActiveShadedConstruction(SurfNum);
    3827      776261 :         ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    3828      776261 :         nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
    3829      776261 :         TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
    3830             : 
    3831      776261 :         if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind
    3832      600039 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces);
    3833      600039 :             TGapInlet = wm->tin;
    3834      600039 :             TGlassFace = wm->thetas[nglassfaces - 1];
    3835      600039 :             TShadeFace = wm->thetas[nglassfaces];
    3836             :         } else { // Exterior shade, screen or blind
    3837      176222 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
    3838      176222 :             TGapInlet = wm->tout;
    3839      176222 :             TGlassFace = wm->thetas[0];
    3840      176222 :             TShadeFace = wm->thetas[nglassfaces + 1];
    3841             :         }
    3842      776261 :         TAve = 0.5 * (TGlassFace + TShadeFace);
    3843             : 
    3844      776261 :         if (iter == 0) {
    3845      169245 :             TGapOld = 0.5 * (TAve + TGapInlet);
    3846             :         } else {
    3847      607016 :             TGapOld = TGapNew;
    3848             :         }
    3849             : 
    3850             :         // Conductance of gap between glass and shade assuming gap is sealed
    3851      776261 :         WindowGasConductance(state, TGlassFace, TShadeFace, TotGaps, con, pr, gr);
    3852      776261 :         NusseltNumber(state, SurfNum, TGlassFace, TShadeFace, TotGaps, gr, pr, nu);
    3853      776261 :         hGapStill = con / wm->gaps[TotGaps - 1].width * nu;
    3854             : 
    3855             :         // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
    3856             :         // there is no air flow thru gap
    3857             : 
    3858      776261 :         if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) < 0.0872) {
    3859           0 :             VGap = 0.0;
    3860           0 :             hcv = 2.0 * hGapStill;
    3861           0 :             QConvGap = 0.0;
    3862           0 :             TGapNew = TAve;
    3863           0 :             TGapOutlet = TAve;
    3864           0 :             return;
    3865             :         }
    3866             : 
    3867      776261 :         GapHeight = state.dataSurface->Surface(SurfNum).Height;
    3868             : 
    3869      776261 :         if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) {
    3870      194498 :             auto const *matShade = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(MatNumSh));
    3871      194498 :             assert(matShade != nullptr);
    3872             :             // Shade or Screen on
    3873      194498 :             GapDepth = matShade->WinShadeToGlassDist;
    3874      194498 :             AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
    3875      194498 :             ATopGap = matShade->WinShadeTopOpeningMult * AGap;
    3876      194498 :             ABotGap = matShade->WinShadeBottomOpeningMult * AGap;
    3877      194498 :             ALeftGap = matShade->WinShadeLeftOpeningMult * GapHeight * GapDepth;
    3878      194498 :             ARightGap = matShade->WinShadeRightOpeningMult * GapHeight * GapDepth;
    3879      194498 :             AHolesGap = matShade->WinShadeAirFlowPermeability * GapHeight * state.dataSurface->Surface(SurfNum).Width;
    3880      776261 :         } else if (ShadeFlag == WinShadingType::ExtScreen) {
    3881       97106 :             auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(MatNumSh));
    3882       97106 :             assert(matScreen != nullptr);
    3883             :             // Shade or Screen on
    3884       97106 :             GapDepth = matScreen->toGlassDist;
    3885       97106 :             AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
    3886       97106 :             ATopGap = matScreen->topOpeningMult * AGap;
    3887       97106 :             ABotGap = matScreen->bottomOpeningMult * AGap;
    3888       97106 :             ALeftGap = matScreen->leftOpeningMult * GapHeight * GapDepth;
    3889       97106 :             ARightGap = matScreen->rightOpeningMult * GapHeight * GapDepth;
    3890       97106 :             AHolesGap = matScreen->airFlowPermeability * GapHeight * state.dataSurface->Surface(SurfNum).Width;
    3891             :         } else {
    3892             :             // Blind on
    3893      484657 :             BlNum = state.dataSurface->SurfWinBlindNumber(SurfNum);
    3894      484657 :             auto const &blind = state.dataMaterial->Blind(BlNum);
    3895      484657 :             GapDepth = blind.BlindToGlassDist;
    3896      484657 :             AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
    3897      484657 :             ATopGap = blind.BlindTopOpeningMult * AGap;
    3898      484657 :             ABotGap = blind.BlindBottomOpeningMult * AGap;
    3899      484657 :             ALeftGap = blind.BlindLeftOpeningMult * GapHeight * GapDepth;
    3900      484657 :             ARightGap = blind.BlindRightOpeningMult * GapHeight * GapDepth;
    3901      484657 :             AHolesGap = state.dataSurface->SurfWinBlindAirFlowPermeability(SurfNum) * GapHeight * state.dataSurface->Surface(SurfNum).Width;
    3902             :         }
    3903             : 
    3904      776261 :         RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
    3905      776261 :         ViscAir = wm->AirProps[4] + wm->AirProps[5] * (TGapOld - Constant::Kelvin);
    3906             :         // The factor 12 in the next line is based on the solution of steady laminar flow between fixed
    3907             :         // parallel plates given in Sec. 6.9.1 of Fundamentals of Fluid Mechanics, Munson/Young/Okishi, Third Edition
    3908             :         // Update, John Wiley & Sons, 1998; ISO 15099 has 8 for this factor, which is for flow through a tube.
    3909      776261 :         BVGap = 12.0 * ViscAir * GapHeight / pow_2(GapDepth);
    3910             :         // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
    3911             :         // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
    3912             :         // bottom and top but possibly open at left side, right side and/or in-shade/blind)
    3913      776261 :         ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    3914      776261 :         ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    3915      776261 :         if (TGapOld > TGapInlet) {
    3916      366845 :             AEqInlet = ABotGap + ATopLRH;
    3917      366845 :             AEqOutlet = ATopGap + ABotLRH;
    3918             :         } else {
    3919      409416 :             AEqOutlet = ABotGap + ATopLRH;
    3920      409416 :             AEqInlet = ATopGap + ABotLRH;
    3921             :         }
    3922             :         // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
    3923             :         // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
    3924             :         // when there is no inlet and/or outlet for air. This then reduces to the
    3925             :         // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
    3926      776261 :         Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
    3927      776261 :         Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
    3928      776261 :         AVGap = 0.5 * RhoAir * (1 + Zinlet + Zoutlet);
    3929      776261 :         RhoTRef = wm->AirProps[0] * Constant::Kelvin;
    3930      776261 :         CVGap = RhoTRef * 9.81 * GapHeight * state.dataSurface->Surface(SurfNum).SinTilt * (TGapOld - TGapInlet) / (TGapOld * TGapInlet);
    3931             : 
    3932             :         // Solution of quadratic equation in VGap
    3933      776261 :         VGap = (std::sqrt(pow_2(BVGap) + std::abs(4.0 * AVGap * CVGap)) - BVGap) / (2.0 * AVGap);
    3934      776261 :         hcv = 2.0 * hGapStill + 4.0 * VGap;
    3935      776261 :         GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
    3936             :         // The following avoids divide by zero and exponential underflow
    3937      776261 :         if (GapHeightChar == 0.0) {
    3938           0 :             TGapOutlet = TAve;
    3939      776261 :         } else if ((GapHeight / GapHeightChar) > 15.0) {
    3940       67499 :             TGapOutlet = TAve;
    3941             :         } else {
    3942      708762 :             TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
    3943             :         }
    3944      776261 :         TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
    3945             : 
    3946             :         // Convective heat flow from gap to room air for interior shade or blind
    3947      776261 :         if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    3948      600039 :             RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
    3949      600039 :             QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
    3950             :             // Exclude convection to gap due to divider, if present; divider convection handled
    3951             :             // separately in CalcWinFrameAndDividerTemps
    3952      600039 :             QConvGap *= 0.5 * (1.0 + state.dataSurface->Surface(SurfNum).Area /
    3953      600039 :                                          (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum)));
    3954             :         }
    3955             :     }
    3956             : 
    3957             :     //****************************************************************************
    3958             : 
    3959       88448 :     void BetweenGlassShadeNaturalFlow(EnergyPlusData &state,
    3960             :                                       int const SurfNum,       // Surface number
    3961             :                                       int const iter,          // Iteration number for glass heat balance calculation
    3962             :                                       Real64 &VGap,            // Gas velocity in gaps (m/s)
    3963             :                                       Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
    3964             :                                       Array1A<Real64> hcv      // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
    3965             :     )
    3966             :     {
    3967             : 
    3968             :         // SUBROUTINE INFORMATION:
    3969             :         //       AUTHOR         F. Winkelmann
    3970             :         //       DATE WRITTEN   December 2002
    3971             :         //       MODIFIED       na
    3972             :         //       RE-ENGINEERED  na
    3973             : 
    3974             :         // PURPOSE OF THIS SUBROUTINE:
    3975             :         // Called by SolveForWindowTemperatures for windows that have a
    3976             :         // between-glass shade or blind in place.
    3977             :         // Solves for gas flow in the two gaps on either side of shade/blind.
    3978             :         // Finds average temperature of gas in the two gaps, and the coefficient
    3979             :         // for convective heat transfer from glass to gap gas and shade/blind to gap gas
    3980             :         // for the two gaps. The two gaps are assumed to have the same depth so that the
    3981             :         // gas velocity due to natural convection is the same in the two gaps.
    3982             :         // The Between-glass shade/blind is between the two glass layers of double glazing
    3983             :         // or between the two inner glass layers of triple glazing. The quadruple glazing
    3984             :         // case is not considered.
    3985             : 
    3986             :         // METHODOLOGY EMPLOYED:
    3987             :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    3988             :         // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
    3989             : 
    3990             :         // Argument array dimensioning
    3991       88448 :         TGapNew.dim(2);
    3992       88448 :         hcv.dim(2);
    3993             : 
    3994             :         int ConstrNumSh; // Shaded construction number
    3995             :         int MatNumSh;    // Material number of shade/blind layer
    3996             :         int nglassfaces; // Number of glass faces in contruction
    3997             :         // In the following, "gaps" refer to the gaps on either side of the shade/blind
    3998       88448 :         Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
    3999       88448 :         Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
    4000       88448 :         Array1D<Real64> hGapStill(2);  // Still-air conduction/convection coeffs for the gaps (W/m2-K)
    4001       88448 :         Array1D<Real64> TGapOld(2);    // Previous-iteration average gas temp in gaps (K)
    4002             :         Real64 GapHeight;              // Vertical length of glass-shade/blind gap (m)
    4003             :         Real64 GapDepth;               // Distance from shade/blind to glass; assumed same for both gaps (m)
    4004       88448 :         Array1D<Real64> RhoGas(2);     // Density of gap gas at a temperature of TGapOld (kg/m3)
    4005             :         Real64 RhoTRef;                // Density of gap gas at reference temp = KelvinConvK (kg/m3)
    4006       88448 :         Array1D<Real64> ViscGas(2);    // Viscosity of gap gas at a temperature of TGapOld (kg/m3)
    4007             :         Real64 RhoGasZero;             // Gas density at KelvinConvK
    4008             :         Real64 ViscGasZero;            // Gas viscosity at KelvinConvK (not used)
    4009             :         Real64 AGap;                   // Cross sectional area of gaps (m2); for vertical window, this
    4010             :         //   is in horizontal plane normal to window.
    4011             :         Real64 ATopGap; // Area of the top and bottom openings of shade/blind (m2)
    4012             :         Real64 ABotGap;
    4013             :         Real64 ALeftGap; // Area of the left and right openings of shade/blind (m2)
    4014             :         Real64 ARightGap;
    4015             :         Real64 AHolesGap; // Area of the holes in the shade/blind (assumed homogeneously
    4016             :         //   distributed) (m2)
    4017             :         Real64 ATopLRH; // Intermediate variables
    4018             :         Real64 ABotLRH;
    4019             :         Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
    4020             :         Real64 AEqOutlet;
    4021             :         Real64 Zinlet; // Inlet and outlet pressure loss factors
    4022             :         Real64 Zoutlet;
    4023             :         Real64 AVGap;                     // Coeff. of VGap**2 term in pressure balance equation
    4024             :         Real64 BVGap;                     // Coeff. of VGap term in pressure balance equation
    4025             :         Real64 CVGap;                     // VGap-independent term in pressure balance equation
    4026       88448 :         Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap gas temperature profile (m)
    4027       88448 :         Array1D<Real64> EpsChar(2);       // EXP(-GapHeight/GapHeightChar(IGap))
    4028       88448 :         Array1D<Real64> TAve(2);          // Average of TGlass and TShade for the gaps (K)
    4029             :         Real64 con;                       // Gap gas conductivity and derivative
    4030             :         Real64 gr;                        // Gap gas Grashof number
    4031             :         Real64 pr;                        // Gap gas Prandtl number
    4032             :         Real64 nu;                        // Gap gas Nusselt number
    4033             :         WinShadingType ShadeFlag;         // Shading flag
    4034             :         int BlNum;                        // Blind number
    4035             :         int IGapInc;                      // Gap increment (0 or 1)
    4036             : 
    4037       88448 :         auto &wm = state.dataWindowManager;
    4038             : 
    4039       88448 :         ConstrNumSh = state.dataSurface->Surface(SurfNum).activeShadedConstruction;
    4040       88448 :         ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    4041       88448 :         nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
    4042             : 
    4043       88448 :         if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
    4044       51044 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
    4045       51044 :             IGapInc = 0;
    4046      153132 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4047      102088 :                 TGlassFace(IGap) = wm->thetas[IGap];
    4048      102088 :                 TShadeFace(IGap) = wm->thetas[IGap + 3];
    4049             :             }
    4050             :         } else { // Triple glazing
    4051       37404 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
    4052       37404 :             IGapInc = 1;
    4053      112212 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4054       74808 :                 TGlassFace(IGap) = wm->thetas[IGap + 2];
    4055       74808 :                 TShadeFace(IGap) = wm->thetas[IGap + 5];
    4056             :             }
    4057             :         }
    4058       88448 :         auto const *thisMaterialShade = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(MatNumSh));
    4059             : 
    4060      265344 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    4061      176896 :             TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
    4062      176896 :             if (iter == 0) {
    4063       17612 :                 TGapOld(IGap) = TAve(IGap);
    4064             :             } else {
    4065      159284 :                 TGapOld(IGap) = TGapNew(IGap);
    4066             :             }
    4067             :             // Conductance of gaps on either side of shade/blind assuming gaps are sealed
    4068      176896 :             WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
    4069      176896 :             NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
    4070      176896 :             hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
    4071             :         }
    4072             : 
    4073             :         // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
    4074             :         // there is no air flow thru gap
    4075             : 
    4076       88448 :         if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) < 0.0872) {
    4077           0 :             VGap = 0.0;
    4078           0 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4079           0 :                 hcv(IGap) = 2.0 * hGapStill(IGap);
    4080           0 :                 TGapNew(IGap) = TAve(IGap);
    4081             :             }
    4082           0 :             return;
    4083             :         }
    4084             : 
    4085       88448 :         GapHeight = state.dataSurface->Surface(SurfNum).Height;
    4086       88448 :         GapDepth = wm->gaps[IGapInc].width;
    4087       88448 :         AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
    4088             : 
    4089       88448 :         if (ShadeFlag == WinShadingType::BGShade) {
    4090             :             // Shade on
    4091       46151 :             ATopGap = thisMaterialShade->WinShadeTopOpeningMult * AGap;
    4092       46151 :             ABotGap = thisMaterialShade->WinShadeBottomOpeningMult * AGap;
    4093       46151 :             ALeftGap = thisMaterialShade->WinShadeLeftOpeningMult * GapHeight * GapDepth;
    4094       46151 :             ARightGap = thisMaterialShade->WinShadeRightOpeningMult * GapHeight * GapDepth;
    4095       46151 :             AHolesGap = thisMaterialShade->WinShadeAirFlowPermeability * GapHeight * state.dataSurface->Surface(SurfNum).Width;
    4096             :         } else {
    4097             :             // Blind on
    4098       42297 :             BlNum = state.dataSurface->SurfWinBlindNumber(SurfNum);
    4099       42297 :             auto const &blind = state.dataMaterial->Blind(BlNum);
    4100       42297 :             ATopGap = blind.BlindTopOpeningMult * AGap;
    4101       42297 :             ABotGap = blind.BlindBottomOpeningMult * AGap;
    4102       42297 :             ALeftGap = blind.BlindLeftOpeningMult * GapHeight * GapDepth;
    4103       42297 :             ARightGap = blind.BlindRightOpeningMult * GapHeight * GapDepth;
    4104       42297 :             AHolesGap = state.dataSurface->SurfWinBlindAirFlowPermeability(SurfNum) * GapHeight * state.dataSurface->Surface(SurfNum).Width;
    4105             :         }
    4106             : 
    4107      265344 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    4108      176896 :             WindowGasPropertiesAtTemp(state, TGapOld(IGap), IGap + IGapInc, RhoGas(IGap), ViscGas(IGap));
    4109             :         }
    4110             : 
    4111       88448 :         BVGap = 12.0 * (ViscGas(1) + ViscGas(2)) * GapHeight / pow_2(GapDepth);
    4112             :         // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
    4113             :         // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
    4114             :         // bottom and top but possibly open at left side, right side and/or in shade/blind)
    4115       88448 :         ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    4116       88448 :         ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
    4117       88448 :         AEqInlet = ABotGap + ATopLRH;
    4118       88448 :         AEqOutlet = ATopGap + ABotLRH;
    4119             : 
    4120             :         // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
    4121             :         // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
    4122             :         // when there is no inlet and/or outlet for air. This then reduces to the
    4123             :         // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
    4124       88448 :         Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
    4125       88448 :         Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
    4126       88448 :         AVGap = 0.5 * (RhoGas(1) + RhoGas(2)) * (1.0 + Zinlet + Zoutlet);
    4127       88448 :         WindowGasPropertiesAtTemp(state, Constant::Kelvin, 1 + IGapInc, RhoGasZero, ViscGasZero);
    4128       88448 :         RhoTRef = RhoGasZero * Constant::Kelvin;
    4129       88448 :         CVGap = RhoTRef * 9.81 * GapHeight * state.dataSurface->Surface(SurfNum).SinTilt * (TGapOld(1) - TGapOld(2)) / (TGapOld(1) * TGapOld(2));
    4130             : 
    4131             :         // Solution of quadratic equation in VGap
    4132             : 
    4133       88448 :         VGap = (std::sqrt(pow_2(BVGap) + std::abs(4 * AVGap * CVGap)) - BVGap) / (2 * AVGap);
    4134             : 
    4135      265344 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    4136      176896 :             hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
    4137      176896 :             GapHeightChar(IGap) = RhoGas(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
    4138             :             // The following avoids divide by zero and exponential underflow
    4139      176896 :             if (GapHeightChar(IGap) == 0.0) {
    4140           0 :                 EpsChar(IGap) = 0.0;
    4141      176896 :             } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
    4142        8938 :                 EpsChar(IGap) = 0.0;
    4143             :             } else {
    4144      167958 :                 EpsChar(IGap) = std::exp(-GapHeight / GapHeightChar(IGap));
    4145             :             }
    4146             :         }
    4147             : 
    4148      176896 :         TGapNew(1) =
    4149       88448 :             TAve(1) - (TAve(1) - TAve(2)) * (GapHeightChar(1) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
    4150             : 
    4151      176896 :         TGapNew(2) =
    4152       88448 :             TAve(2) - (TAve(2) - TAve(1)) * (GapHeightChar(2) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
    4153       88448 :     }
    4154             : 
    4155             :     //****************************************************************************
    4156             : 
    4157       16427 :     void BetweenGlassForcedFlow(EnergyPlusData &state,
    4158             :                                 int const SurfNum,  // Surface number
    4159             :                                 int const iter,     // Iteration number for glass heat balance calculation
    4160             :                                 Real64 &VGap,       // Air velocity in airflow gap (m/s)
    4161             :                                 Real64 &TGapNew,    // Current-iteration average air temp in airflow gap (K)
    4162             :                                 Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
    4163             :                                 Real64 &hcv,        // Convection coefficient from gap glass faces to gap air (W/m2-K)
    4164             :                                 Real64 &QConvGap    // Convective heat gain from air flow gap (W)
    4165             :     )
    4166             :     {
    4167             : 
    4168             :         // SUBROUTINE INFORMATION:
    4169             :         //       AUTHOR         F. Winkelmann
    4170             :         //       DATE WRITTEN   February 2003
    4171             :         //       MODIFIED       na
    4172             :         //       RE-ENGINEERED  na
    4173             : 
    4174             :         // PURPOSE OF THIS SUBROUTINE:
    4175             :         // Called by SolveForWindowTemperatures for "airflow windows",i.e., windows
    4176             :         // with forced airflow in one of the gaps between layers of glass. Based on
    4177             :         // the velocity of airflow through gap, finds effective temperature of gap air,
    4178             :         // convective heat transfer coefficient from glass to gap air,
    4179             :         // the gap outlet temperature, and the outlet convective heat flow.
    4180             : 
    4181             :         // Called only for double and triple glazing. For triple glazing the airflow
    4182             :         // is assumed to be between the inner two layers of glass (glass layers 2 and 3).
    4183             : 
    4184             :         // METHODOLOGY EMPLOYED:
    4185             :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    4186             :         // Detailed Calculations"
    4187             : 
    4188             :         // Using/Aliasing
    4189             :         using ScheduleManager::GetCurrentScheduleValue;
    4190             : 
    4191             :         // Locals
    4192             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    4193             :         //   air flow or bottom for downward air flow (K)
    4194             : 
    4195             :         int ConstrNum;    // Construction number of surface
    4196             :         int NGlass;       // Number of glass layers in construction
    4197             :         int GapNum;       // Number of airflow gap
    4198             :         Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
    4199             :         //   air flow or top for downward air flow (K)
    4200             :         Real64 TGlassFace1; // Temperature of left-hand glass surface facing airflow gap (K)
    4201             :         Real64 TGlassFace2; // Temperature of right-hand glass surface facing airflow gap (K)
    4202             :         Real64 hGapStill;   // Still-air gap conduction/convection coeff (W/m2-K)
    4203             :         Real64 TGapOld;     // Previous-iteration average air temp in airflow gap (K)
    4204             :         Real64 GapHeight;   // Vertical length of airflow gap (m)
    4205             :         Real64 GapDepth;    // Thickness of airflow gap (m)
    4206             :         Real64 RhoAir;      // Density of airflow gap air at a temperature of TGapOld (kg/m3)
    4207             :         Real64 AGap;        // Cross sectional area of airflow gap (m2); for vertical window, this
    4208             :         //   is in horizontal plane normal to window.
    4209             :         Real64 GapHeightChar; // Characteristic height of the airflow gap air temperature profile (m)
    4210             :         Real64 TAve;          // Average of TGlassFace1 and TGlassFace2 (K)
    4211             :         // REAL(r64)            :: AirProps(8)         ! Air properties
    4212             :         Real64 con; // Gap conductivity and derivative
    4213             :         Real64 gr;  // Gap air Grashof number
    4214             :         Real64 pr;  // Gap air Prandtl number
    4215             :         Real64 nu;  // Gap air Nusselt number
    4216             : 
    4217             :         // Air properties
    4218             :         //               Dens  dDens/dT  Con    dCon/dT   Vis    dVis/dT Prandtl dPrandtl/dT
    4219             :         // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72,   1.8d-3  /
    4220             : 
    4221       16427 :         auto &wm = state.dataWindowManager;
    4222             : 
    4223       16427 :         ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
    4224       16427 :         NGlass = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    4225       16427 :         TGlassFace1 = wm->thetas[2 * NGlass - 3];
    4226       16427 :         TGlassFace2 = wm->thetas[2 * NGlass - 2];
    4227       16427 :         GapNum = NGlass - 1;
    4228       16427 :         TAve = 0.5 * (TGlassFace1 + TGlassFace2);
    4229             : 
    4230       16427 :         if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    4231       16427 :             TGapInlet = wm->tin; // Source is inside air
    4232             :         } else {
    4233           0 :             TGapInlet = wm->tout; // Source is outside air
    4234             :         }
    4235             : 
    4236       16427 :         if (iter == 0) {
    4237        8064 :             TGapOld = 0.5 * (TAve + TGapInlet);
    4238             :         } else {
    4239        8363 :             TGapOld = TGapNew;
    4240             :         }
    4241             : 
    4242             :         // Conductance of gap assuming it is sealed
    4243       16427 :         WindowGasConductance(state, TGlassFace1, TGlassFace2, GapNum, con, pr, gr);
    4244       16427 :         NusseltNumber(state, SurfNum, TGlassFace1, TGlassFace2, GapNum, gr, pr, nu);
    4245       16427 :         hGapStill = con / wm->gaps[GapNum - 1].width * nu;
    4246       16427 :         GapHeight = state.dataSurface->Surface(SurfNum).Height;
    4247       16427 :         GapDepth = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * NGlass - 2))->Thickness;
    4248       16427 :         AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
    4249       16427 :         VGap = state.dataSurface->SurfWinAirflowThisTS(SurfNum) / GapDepth;
    4250       16427 :         hcv = 2.0 * hGapStill + 4.0 * VGap;
    4251       16427 :         RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
    4252       16427 :         GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
    4253             :         // The following avoids divide by zero and exponential underflow
    4254       16427 :         if (GapHeightChar == 0.0) {
    4255           0 :             TGapOutlet = TAve;
    4256       16427 :         } else if ((GapHeight / GapHeightChar) > 15.0) {
    4257           0 :             TGapOutlet = TAve;
    4258             :         } else {
    4259       16427 :             TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
    4260             :         }
    4261       16427 :         TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
    4262             :         // Convective heat flow from gap [W]
    4263       16427 :         RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
    4264       16427 :         QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
    4265       16427 :     } // BetweenGlassForcedFlow()
    4266             : 
    4267             :     //****************************************************************************
    4268             : 
    4269       19998 :     void BetweenGlassShadeForcedFlow(EnergyPlusData &state,
    4270             :                                      int const SurfNum,       // Surface number
    4271             :                                      int const iter,          // Iteration number for glass heat balance calculation
    4272             :                                      Real64 &VGap,            // Air velocity in each gap (m/s)
    4273             :                                      Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
    4274             :                                      Real64 &TGapOutletAve,   // Average of TGapOutlet(1) and TGapOutlet(2) (K)
    4275             :                                      Array1A<Real64> hcv,     // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
    4276             :                                      Real64 &QConvTot         // Sum of convective heat flow from gaps (W)
    4277             :     )
    4278             :     {
    4279             : 
    4280             :         // SUBROUTINE INFORMATION:
    4281             :         //       AUTHOR         F. Winkelmann
    4282             :         //       DATE WRITTEN   February 2003
    4283             :         //       MODIFIED       na
    4284             :         //       RE-ENGINEERED  na
    4285             : 
    4286             :         // PURPOSE OF THIS SUBROUTINE:
    4287             :         // Called by SolveForWindowTemperatures for airflow windows with a
    4288             :         // between-glass shade or blind over which fan-forced air flows.
    4289             :         // Based on the air flow velocity (which is assumed to be the same in the
    4290             :         // gaps on either side of the shade/blind), finds, for each gap: the average
    4291             :         // air temperature, the shade/blind or glass surface to air convective heat
    4292             :         // transfer coefficient, the gap outlet temperature, and the outlet convective heat flow.
    4293             : 
    4294             :         // Called only for double and triple glazing. For triple glazing the airflow
    4295             :         // is assumed to be between the inner two layers of glass (glass layers 2 and 3),
    4296             :         // between which the shade/blind is located.
    4297             : 
    4298             :         // METHODOLOGY EMPLOYED:
    4299             :         // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
    4300             :         // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
    4301             : 
    4302             :         // Argument array dimensioning
    4303       19998 :         TGapNew.dim(2);
    4304       19998 :         hcv.dim(2);
    4305             : 
    4306             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4307             :         int ConstrNumSh; // Shaded construction number
    4308             :         int MatNumSh;    // Material number of shade/blind layer
    4309             :         // In the following, "gaps" refer to the gaps on either side of the shade/blind
    4310       19998 :         Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
    4311       19998 :         Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
    4312       19998 :         Array1D<Real64> hGapStill(2);  // Still-air conduction/convection coeffs for the gaps (W/m2-K)
    4313       19998 :         Array1D<Real64> TGapOld(2);    // Previous-iteration average gas temp in gaps (K)
    4314             :         Real64 GapHeight;              // Vertical length of glass-shade/blind gap (m)
    4315             :         Real64 GapDepth;               // Distance from shade/blind to glass; assumed same for both gaps (m)
    4316       19998 :         Array1D<Real64> RhoAir(2);     // Density of gap air (kg/m3)
    4317             :         Real64 AGap;                   // Cross sectional area of each gap (m2); for vertical window, this
    4318             :         //   is in horizontal plane normal to window.
    4319             :         Real64 TGapInlet;                 // Gap inlet air temperature (K)
    4320       19998 :         Array1D<Real64> TGapOutlet(2);    // Gap outlet air temperature (K)
    4321       19998 :         Array1D<Real64> QConvGap(2);      // Convective heat flow from each gap (W)
    4322       19998 :         Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap air temperature profile (m)
    4323       19998 :         Array1D<Real64> TAve(2);          // Average of TGlass and TShade for the gaps (K)
    4324             :         Real64 con;                       // Gap air conductivity and derivative
    4325             :         Real64 gr;                        // Gap air Grashof number
    4326             :         Real64 pr;                        // Gap air Prandtl number
    4327             :         Real64 nu;                        // Gap air Nusselt number
    4328             :         WinShadingType ShadeFlag;         // Shading flag
    4329             :         int IGapInc;                      // Gap increment; =0, double glass, =1, triple glass
    4330             :         // REAL(r64)            :: AirProps(8)         ! Air properties
    4331             : 
    4332       19998 :         auto &wm = state.dataWindowManager;
    4333             : 
    4334             :         // Air properties
    4335             :         //               Dens  dDens/dT  Con    dCon/dT   Vis    dVis/dT Prandtl dPrandtl/dT
    4336             :         // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72,   1.8d-3  /
    4337             : 
    4338       19998 :         ConstrNumSh = state.dataSurface->Surface(SurfNum).activeShadedConstruction;
    4339       19998 :         ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    4340             : 
    4341       19998 :         if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
    4342        9981 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
    4343        9981 :             IGapInc = 0;
    4344       29943 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4345       19962 :                 TGlassFace(IGap) = wm->thetas[IGap];
    4346       19962 :                 TShadeFace(IGap) = wm->thetas[IGap + 3];
    4347             :             }
    4348             :         } else { // Triple glazing
    4349       10017 :             MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
    4350       10017 :             IGapInc = 1;
    4351       30051 :             for (int IGap = 1; IGap <= 2; ++IGap) {
    4352       20034 :                 TGlassFace(IGap) = wm->thetas[IGap + 2];
    4353       20034 :                 TShadeFace(IGap) = wm->thetas[IGap + 5];
    4354             :             }
    4355             :         }
    4356             : 
    4357       19998 :         if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
    4358       19998 :             TGapInlet = wm->tin;
    4359             :         } else {
    4360           0 :             TGapInlet = wm->tout;
    4361             :         }
    4362             : 
    4363       19998 :         GapHeight = state.dataSurface->Surface(SurfNum).Height;
    4364       19998 :         GapDepth = wm->gaps[IGapInc].width;
    4365       19998 :         AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
    4366             :         // Factor of 2 below assumes gaps on either side of shade/blind have same depth
    4367       19998 :         VGap = state.dataSurface->SurfWinAirflowThisTS(SurfNum) / (2.0 * GapDepth);
    4368             : 
    4369       59994 :         for (int IGap = 1; IGap <= 2; ++IGap) {
    4370       39996 :             TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
    4371       39996 :             if (iter == 0) {
    4372       16128 :                 TGapOld(IGap) = TAve(IGap);
    4373             :             } else {
    4374       23868 :                 TGapOld(IGap) = TGapNew(IGap);
    4375             :             }
    4376             :             // Conductance of gaps on either side of shade/blind assuming gaps are sealed
    4377       39996 :             WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
    4378       39996 :             NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
    4379       39996 :             hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
    4380             :             // Shade/blind or glass surface to air convection coefficient
    4381       39996 :             hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
    4382       39996 :             RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapOld(IGap) - Constant::Kelvin);
    4383       39996 :             hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
    4384       39996 :             GapHeightChar(IGap) = RhoAir(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
    4385             :             // The following avoids divide by zero and exponential underflow
    4386       39996 :             if (GapHeightChar(IGap) == 0.0) {
    4387           0 :                 TGapOutlet(IGap) = TAve(IGap);
    4388       39996 :             } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
    4389           0 :                 TGapOutlet(IGap) = TAve(IGap);
    4390             :             } else {
    4391       39996 :                 TGapOutlet(IGap) = TAve(IGap) - (TAve(IGap) - TGapInlet) * std::exp(-GapHeight / GapHeightChar(IGap));
    4392             :             }
    4393       39996 :             TGapNew(IGap) = TAve(IGap) - (GapHeightChar(IGap) / GapHeight) * (TGapOutlet(IGap) - TGapInlet);
    4394             :             // Convective heat flow from gap [W]
    4395       39996 :             RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapNew(IGap) - Constant::Kelvin);
    4396       39996 :             QConvGap(IGap) = RhoAir(IGap) * AGap * VGap * 1008.0 * (TGapOutlet(IGap) - TGapInlet);
    4397             :         }
    4398             : 
    4399       19998 :         QConvTot = QConvGap(1) + QConvGap(2);
    4400       19998 :         TGapOutletAve = 0.5 * (TGapOutlet(1) + TGapOutlet(2));
    4401       19998 :     } // BetweenGlassShadeForcedFlow()
    4402             : 
    4403             :     //****************************************************************************
    4404             : 
    4405    44766113 :     void LUdecomposition(EnergyPlusData &state,
    4406             :                          Array2<Real64> &ajac, // As input: matrix to be decomposed;
    4407             :                          int const n,          // Dimension of matrix
    4408             :                          Array1D_int &indx,    // Vector of row permutations
    4409             :                          int &d                // +1 if even number of row interchange is even, -1
    4410             :     )
    4411             :     {
    4412             : 
    4413             :         // SUBROUTINE INFORMATION:
    4414             :         //       AUTHOR         F. Winkelmann, adapted from Numerical Recipes
    4415             :         //       DATE WRITTEN   February 2000
    4416             :         //       MODIFIED       na
    4417             :         //       RE-ENGINEERED  na
    4418             : 
    4419             :         // PURPOSE OF THIS SUBROUTINE:
    4420             :         // Performs LU decomposition of a matrix.
    4421             : 
    4422             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    4423             :         //   as output: decomposed matrix
    4424             :         //   if odd
    4425             : 
    4426             :         int imax; // Temporary variable
    4427             :         //   as output: decomposed matrix
    4428             : 
    4429             :         Real64 aamax; // Absolute value of largest element of matrix
    4430             : 
    4431    44766113 :         assert(n <= 10);                   // vv sizing
    4432    44766113 :         std::array<Real64, 10> vv = {0.0}; // Stores the implicit scaling of each row
    4433             : 
    4434    44766113 :         d = 1;
    4435   164437517 :         for (int i = 1; i <= n; ++i) {
    4436   119671404 :             Real64 aamax = 0.0;
    4437   486029524 :             for (int j = 1; j <= n; ++j) {
    4438   366358120 :                 if (std::abs(ajac(j, i)) > aamax) aamax = std::abs(ajac(j, i));
    4439             :             }
    4440   119671404 :             if (aamax == 0.0) ShowFatalError(state, "Singular matrix in LUdecomposition, window calculations");
    4441   119671404 :             vv[i - 1] = 1.0 / aamax;
    4442             :         }
    4443   164437517 :         for (int j = 1; j <= n; ++j) {
    4444   243014762 :             for (int i = 1; i <= j - 1; ++i) {
    4445   123343358 :                 Real64 sum = ajac(j, i);
    4446   194593606 :                 for (int k = 1; k <= i - 1; ++k) {
    4447    71250248 :                     sum -= ajac(k, i) * ajac(j, k);
    4448             :                 }
    4449   123343358 :                 ajac(j, i) = sum;
    4450             :             }
    4451   119671404 :             aamax = 0.0;
    4452   362686166 :             for (int i = j; i <= n; ++i) {
    4453   243014762 :                 Real64 sum = ajac(j, i);
    4454   437608368 :                 for (int k = 1; k <= j - 1; ++k) {
    4455   194593606 :                     sum -= ajac(k, i) * ajac(j, k);
    4456             :                 }
    4457   243014762 :                 ajac(j, i) = sum;
    4458   243014762 :                 Real64 dum = vv[i - 1] * std::abs(sum);
    4459   243014762 :                 if (dum >= aamax) {
    4460   120100354 :                     imax = i;
    4461   120100354 :                     aamax = dum;
    4462             :                 }
    4463             :             }
    4464   119671404 :             if (j != imax) {
    4465     2490498 :                 for (int k = 1; k <= n; ++k) {
    4466     2061548 :                     Real64 dum = ajac(k, imax);
    4467     2061548 :                     ajac(k, imax) = ajac(k, j);
    4468     2061548 :                     ajac(k, j) = dum;
    4469             :                 }
    4470      428950 :                 d = -d;
    4471      428950 :                 vv[imax - 1] = vv[j - 1];
    4472             :             }
    4473   119671404 :             indx(j) = imax;
    4474   119671404 :             if (ajac(j, j) == 0.0) ajac(j, j) = Constant::rTinyValue;
    4475   119671404 :             if (j != n) {
    4476    74905291 :                 Real64 dum = 1.0 / ajac(j, j);
    4477   198248649 :                 for (int i = j + 1; i <= n; ++i) {
    4478   123343358 :                     ajac(j, i) *= dum;
    4479             :                 }
    4480             :             }
    4481             :         }
    4482    44766113 :     } // LUdecomposition()
    4483             : 
    4484             :     //**************************************************************************
    4485             : 
    4486    45020246 :     void LUsolution(EnergyPlusData &state,
    4487             :                     Array2<Real64> const &a, // Matrix and vector in a.x = b;
    4488             :                     int const n,             // Dimension of a and b
    4489             :                     Array1D_int const &indx, // Vector of row permutations
    4490             :                     Array1D<Real64> &b       // Matrix and vector in a.x = b;
    4491             :     )
    4492             :     {
    4493             : 
    4494             :         // SUBROUTINE INFORMATION:
    4495             :         //       AUTHOR         F. Winkelmann, adapted from Numerical Recipes
    4496             :         //       DATE WRITTEN   February 2000
    4497             :         //       MODIFIED       na
    4498             :         //       RE-ENGINEERED  na
    4499             : 
    4500             :         // PURPOSE OF THIS SUBROUTINE:
    4501             :         // Solves set of linear equations a.x = b
    4502             : 
    4503             :         // Locals
    4504             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    4505             :         //   b is also output as the solution, x
    4506             :         //   b is also output as the solution, x
    4507             : 
    4508             :         int ii; // Intermediate variables
    4509             :         int ll;
    4510             :         Real64 sum; // Summation variable
    4511             : 
    4512    45020246 :         ii = 0;
    4513   165708182 :         for (int i = 1; i <= n; ++i) {
    4514   120687936 :             ll = indx(i);
    4515   120687936 :             sum = b(ll);
    4516   120687936 :             b(ll) = b(i);
    4517   120687936 :             if (ii != 0) {
    4518   198841626 :                 for (int j = ii; j <= i - 1; ++j) {
    4519   123682202 :                     sum -= a(j, i) * b(j);
    4520             :                 }
    4521    45528512 :             } else if (sum != 0.0) {
    4522    45020246 :                 ii = i;
    4523             :             }
    4524   120687936 :             b(i) = sum;
    4525             :         }
    4526   165708182 :         for (int i = n; i >= 1; --i) {
    4527   120687936 :             sum = b(i);
    4528   245556092 :             for (int j = i + 1; j <= n; ++j) {
    4529   124868156 :                 sum -= a(j, i) * b(j);
    4530             :             }
    4531   120687936 :             b(i) = sum / a(i, i);
    4532             :         }
    4533    45020246 :     } // LUsolution()
    4534             : 
    4535             :     //******************************************************************************
    4536             : 
    4537    15109751 :     void WindowGasConductance(EnergyPlusData &state,
    4538             :                               Real64 const tleft,  // Temperature of gap surface closest to outside (K)
    4539             :                               Real64 const tright, // Temperature of gap surface closest to zone (K)
    4540             :                               int const IGap,      // Gap number
    4541             :                               Real64 &con,         // Gap gas conductance (W/m2-K)
    4542             :                               Real64 &pr,          // Gap gas Prandtl number
    4543             :                               Real64 &gr           // Gap gas Grashof number
    4544             :     )
    4545             :     {
    4546             : 
    4547             :         // SUBROUTINE INFORMATION:
    4548             :         //       AUTHOR         Adapted by Fred Winkelmann from Window5 subroutine gasses
    4549             :         //       DATE WRITTEN   September 2001
    4550             :         //       MODIFIED       na
    4551             :         //       RE-ENGINEERED  na
    4552             : 
    4553             :         // PURPOSE OF THIS SUBROUTINE:
    4554             :         // Find the coefficient of convective/conductive heat transfer in the gas-filled gap
    4555             :         // between isothermal solid layers. The gap may be filled with a single gas or a gas mixture.
    4556             : 
    4557             :         // METHODOLOGY EMPLOYED:
    4558             :         // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
    4559             :         // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
    4560             :         // The equation numbers below correspond to those in the standard.
    4561             : 
    4562             :         // REFERENCES:
    4563             :         // Window5 source code; ISO 15099
    4564             : 
    4565    15109751 :         constexpr Real64 pres(1.0e5);     // Gap gas pressure (Pa)
    4566    15109751 :         constexpr Real64 gaslaw(8314.51); // Molar gas constant (J/kMol-K)
    4567    15109751 :         Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
    4568             : 
    4569             :         int NMix;      // Number of gases in a mixture
    4570             :         Real64 molmix; // Molecular weight of mixture
    4571             : 
    4572    15109751 :         auto &wm = state.dataWindowManager;
    4573             : 
    4574             :         Real64 kpmix; // Monotonic thermal conductivity of mixture
    4575             :         Real64 kdpmix;
    4576             :         Real64 kmix;      // For accumulating conductance of gas mixture
    4577             :         Real64 mumix;     // For accumulating viscosity of gas mixture
    4578    15109751 :         Real64 visc(0.0); // Dynamic viscosity of mixture at tmean (g/m-s)
    4579    15109751 :         Real64 cp(0.0);   // Specific heat of mixture at tmean (J/m3-K)
    4580    15109751 :         Real64 dens(0.0); // Density of mixture at tmean (kg/m3)
    4581             :         Real64 cpmixm;    // Gives cp when divided by molmix
    4582             :         Real64 phimup;    // Numerator factor
    4583             :         Real64 downer;    // Denominator factor
    4584             :         Real64 psiup;     // Numerator factor
    4585             :         Real64 psiterm;   // Factor
    4586             :         Real64 phikup;    // Numerator factor
    4587             :         Real64 rhomix;    // Density of gas mixture (kg/m3)
    4588             : 
    4589    15109751 :         std::array<Real64, 10> mukpdwn = {0.0}; // Denominator term
    4590    15109751 :         std::array<Real64, 10> kpdown = {0.0};  // Denominator terms
    4591    15109751 :         std::array<Real64, 10> kdpdown = {0.0};
    4592             :         // Conductivity term accounting for additional energy moved by the diffusional transport of internal energy in polyatomic gases.
    4593    15109751 :         std::array<Real64, 10> kdblprm = {0.0};
    4594    15109751 :         std::array<Real64, 10> frct = {0.0};   // Fraction of each gas in a mixture
    4595    15109751 :         std::array<Real64, 10> kprime = {0.0}; // Monotonic thermal conductivity
    4596             : 
    4597    15109751 :         std::array<Real64, 10> fvis = {0.0};  // Viscosity of each gas in a mixture (g/m-s)
    4598    15109751 :         std::array<Real64, 10> fcon = {0.0};  // Conductance of each gas in a mixture (W/m2-K)
    4599    15109751 :         std::array<Real64, 10> fdens = {0.0}; // Density of each gas in a mixture (kg/m3)
    4600    15109751 :         std::array<Real64, 10> fcp = {0.0};   // Specific heat of each gas in a mixture (J/m3-K)
    4601             : 
    4602             :         // Autodesk:Logic Either assert NMix>0 or handle NMix<=0 in logic so that con and locals guar. initialized before use
    4603    15109751 :         NMix = wm->gaps[IGap - 1].numGases;
    4604             : 
    4605    30346895 :         for (int IMix = 0; IMix < NMix; ++IMix) {
    4606    15237144 :             frct[IMix] = wm->gaps[IGap - 1].gasFracts[IMix];
    4607             :         }
    4608             : 
    4609    15109751 :         Real64 const tmean(0.5 * (tleft + tright)); // Average gap gas temperature (K)
    4610    15109751 :         Real64 const tmean_2(pow_2(tmean));
    4611             : 
    4612    15109751 :         auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
    4613    15109751 :         fcon[0] = wmgas0.con.c0 + wmgas0.con.c1 * tmean + wmgas0.con.c2 * tmean_2;
    4614    15109751 :         fvis[0] = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
    4615    15109751 :         fcp[0] = wmgas0.cp.c0 + wmgas0.cp.c1 * tmean + wmgas0.cp.c2 * tmean_2;
    4616    15109751 :         fdens[0] = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
    4617             :         //  rho=(presure*molecweight)/(gasconst*tmean)
    4618             : 
    4619    15109751 :         if (NMix == 1) { // Single gas
    4620    14982358 :             con = fcon[0];
    4621    14982358 :             visc = fvis[0];
    4622    14982358 :             cp = fcp[0];
    4623    14982358 :             dens = fdens[0];
    4624      127393 :         } else if (NMix > 1) {                                   // Multiple gases; calculate mixture properties
    4625      127393 :             molmix = frct[0] * wmgas0.wght;                      // initialize eq. 56
    4626      127393 :             cpmixm = molmix * fcp[0];                            // initialize eq. 58
    4627      127393 :             kprime[0] = 3.75 * (gaslaw / wmgas0.wght) * fvis[0]; // eq. 67
    4628      127393 :             kdblprm[0] = fcon[0] - kprime[0];                    // eq. 67
    4629             : 
    4630             :             // Initialize summations for eqns 60-66
    4631      127393 :             mumix = 0.0;
    4632      127393 :             kpmix = 0.0;
    4633      127393 :             kdpmix = 0.0;
    4634      127393 :             mukpdwn[0] = 1.0;
    4635      127393 :             kpdown[0] = 1.0;
    4636      127393 :             kdpdown[0] = 1.0;
    4637             : 
    4638             :             // Calculate properties of mixture constituents
    4639      254786 :             for (int i = 2; i <= NMix; ++i) {
    4640      127393 :                 auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
    4641             : 
    4642      127393 :                 fcon[i - 1] = wmgas.con.c0 + wmgas.con.c1 * tmean + wmgas.con.c2 * tmean_2;
    4643      127393 :                 fvis[i - 1] = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
    4644      127393 :                 fcp[i - 1] = wmgas.cp.c0 + wmgas.cp.c1 * tmean + wmgas.cp.c2 * tmean_2;
    4645      127393 :                 fdens[i - 1] = pres * wmgas.wght / (gaslaw * tmean);
    4646      127393 :                 molmix += frct[i - 1] * wmgas.wght;                       // eq. 56
    4647      127393 :                 cpmixm += frct[i - 1] * fcp[i - 1] * wmgas.wght;          // eq. 58-59
    4648      127393 :                 kprime[i - 1] = 3.75 * gaslaw / wmgas.wght * fvis[i - 1]; // eq. 67
    4649      127393 :                 kdblprm[i - 1] = fcon[i - 1] - kprime[i - 1];             // eq. 68
    4650      127393 :                 mukpdwn[i - 1] = 1.0;                                     // initialize denomonator of eq. 60
    4651      127393 :                 kpdown[i - 1] = 1.0;                                      // initialize denomonator of eq. 63
    4652      127393 :                 kdpdown[i - 1] = 1.0;                                     // initialize denomonator of eq. 65
    4653             :             }
    4654             : 
    4655      382179 :             for (int i = 1; i <= NMix; ++i) {
    4656      254786 :                 auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
    4657             : 
    4658      764358 :                 for (int j = 1; j <= NMix; ++j) {
    4659      509572 :                     auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
    4660             : 
    4661             :                     // numerator of equation 61
    4662      509572 :                     phimup = pow_2(1.0 + std::sqrt(fvis[i - 1] / fvis[j - 1]) * root_4(wmgasJ.wght / wmgasI.wght));
    4663             :                     // denomonator of eq. 61, 64 and 66
    4664      509572 :                     downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
    4665             :                     // calculate the denominator of eq. 60
    4666      509572 :                     if (i != j) mukpdwn[i - 1] += phimup / downer * frct[j - 1] / frct[i - 1];
    4667             :                     // numerator of eq. 64; psiterm is the multiplied term in backets
    4668      509572 :                     psiup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
    4669      509572 :                     psiterm = 1.0 + 2.41 * (wmgasI.wght - wmgasJ.wght) * (wmgasI.wght - 0.142 * wmgasJ.wght) / pow_2(wmgasI.wght + wmgasJ.wght);
    4670             :                     // using the common denominator, downer, calculate the denominator for eq. 63
    4671      509572 :                     if (i != j) kpdown[i - 1] += psiup * (psiterm / downer) * (frct[j - 1] / frct[i - 1]);
    4672             :                     // calculate the numerator of eq. 66
    4673      509572 :                     phikup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
    4674             :                     // using the common denominator, downer, calculate the denomonator for eq. 65
    4675      509572 :                     if (i != j) kdpdown[i - 1] += (phikup / downer) * (frct[j - 1] / frct[i - 1]);
    4676             :                 }
    4677      254786 :                 mumix += fvis[i - 1] / mukpdwn[i - 1];     // eq. 60
    4678      254786 :                 kpmix += kprime[i - 1] / kpdown[i - 1];    // eq. 63
    4679      254786 :                 kdpmix += kdblprm[i - 1] / kdpdown[i - 1]; // eq. 65
    4680             :             }
    4681             : 
    4682             :             // Calculate the density of the mixture assuming an ideal gas
    4683      127393 :             rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
    4684      127393 :             kmix = kpmix + kdpmix;                     // eq. 68-a
    4685             : 
    4686             :             // Final mixture properties
    4687      127393 :             visc = mumix;
    4688      127393 :             con = kmix;
    4689      127393 :             dens = rhomix;
    4690      127393 :             cp = cpmixm / molmix;
    4691             : 
    4692             :         } else {
    4693           0 :             assert(false);
    4694             :         } // End of check if single or multiple gases in gap
    4695             : 
    4696    15109751 :         pr = cp * visc / con;
    4697    15109751 :         gr = 9.807 * pow_3(wm->gaps[IGap - 1].width) * std::abs(tleft - tright) * pow_2(dens) / (tmean * pow_2(visc));
    4698    15109751 :     } // WindowGasConductance()
    4699             : 
    4700             :     //******************************************************************************
    4701             : 
    4702      265344 :     void WindowGasPropertiesAtTemp(EnergyPlusData &state,
    4703             :                                    Real64 const tmean, // Temperature of gas in gap (K)
    4704             :                                    int const IGap,     // Gap number
    4705             :                                    Real64 &dens,       // Gap gas density at tmean (kg/m3)
    4706             :                                    Real64 &visc        // Gap gas dynamic viscosity at tmean (g/m-s)
    4707             :     )
    4708             :     {
    4709             : 
    4710             :         // SUBROUTINE INFORMATION:
    4711             :         //       AUTHOR         F. Winkelmann
    4712             :         //       DATE WRITTEN   December 2002
    4713             :         //       MODIFIED       na
    4714             :         //       RE-ENGINEERED  na
    4715             : 
    4716             :         // PURPOSE OF THIS SUBROUTINE:
    4717             :         // Finds the density and viscosity of the gas in a gap at a particular temperature.
    4718             :         // The gap may be filled with a single gas or a gas mixture.
    4719             :         // Based on Subroutine WindowGasConductance.
    4720             : 
    4721             :         // METHODOLOGY EMPLOYED:
    4722             :         // See Subr. WindowGasConductance
    4723             : 
    4724             :         // REFERENCES:
    4725             :         // See Subr. WindowGasConductance
    4726             : 
    4727      265344 :         Real64 constexpr pres(1.0e5);     // Gap gas pressure (Pa)
    4728      265344 :         Real64 constexpr gaslaw(8314.51); // Molar gas constant (J/kMol-K)
    4729      265344 :         Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
    4730             : 
    4731             :         int NMix;                    // Number of gases in a mixture
    4732             :         Real64 molmix;               // Molecular weight of mixture
    4733      265344 :         Array1D<Real64> mukpdwn(10); // Denominator term
    4734             :         Real64 mumix;                // For accumulating viscosity of gas mixture
    4735             :         Real64 phimup;               // Numerator factor
    4736             :         Real64 downer;               // Denominator factor
    4737             :         Real64 rhomix;               // Density of gas mixture (kg/m3)
    4738      265344 :         Array1D<Real64> frct(10);    // Fraction of each gas in a mixture
    4739      265344 :         Array1D<Real64> fvis(10);    // Viscosity of each gas in a mixture (g/m-s)
    4740      265344 :         Array1D<Real64> fdens(10);   // Density of each gas in a mixture (kg/m3)
    4741             : 
    4742      265344 :         auto &wm = state.dataWindowManager;
    4743             : 
    4744      265344 :         NMix = wm->gaps[IGap - 1].numGases;
    4745             : 
    4746      530688 :         for (int IMix = 1; IMix <= NMix; ++IMix) {
    4747      265344 :             frct(IMix) = wm->gaps[IGap - 1].gasFracts[IMix - 1];
    4748             :         }
    4749             : 
    4750      265344 :         Real64 const tmean_2(pow_2(tmean));
    4751      265344 :         auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
    4752      265344 :         fvis(1) = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
    4753      265344 :         fdens(1) = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
    4754             :         //  rho=(presure*molecweight)/(gasconst*tmean)
    4755      265344 :         if (NMix == 1) { // Single gas
    4756      265344 :             visc = fvis(1);
    4757      265344 :             dens = fdens(1);
    4758             :         } else {                            // Multiple gases; calculate mixture properties
    4759           0 :             molmix = frct(1) * wmgas0.wght; // initialize eq. 56
    4760             : 
    4761             :             // Initialize summations for eqns 60-66
    4762           0 :             mumix = 0.0;
    4763           0 :             mukpdwn(1) = 1.0;
    4764             : 
    4765             :             // Calculate properties of mixture constituents
    4766           0 :             for (int i = 2; i <= NMix; ++i) {
    4767           0 :                 auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
    4768           0 :                 fvis(i) = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
    4769           0 :                 fdens(i) = pres * wmgas.wght / (gaslaw * tmean);
    4770           0 :                 molmix += frct(i) * wmgas.wght; // eq. 56
    4771           0 :                 mukpdwn(i) = 1.0;               // initialize denomonator of eq. 60
    4772             :             }
    4773             : 
    4774           0 :             for (int i = 1; i <= NMix; ++i) {
    4775           0 :                 auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
    4776           0 :                 for (int j = 1; j <= NMix; ++j) {
    4777           0 :                     auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
    4778             :                     // numerator of equation 61
    4779           0 :                     phimup = pow_2(1.0 + std::sqrt(fvis(i) / fvis(j)) * root_4(wmgasJ.wght / wmgasI.wght));
    4780             :                     // denomonator of eq. 61, 64 and 66
    4781           0 :                     downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
    4782             :                     // calculate the denominator of eq. 60
    4783           0 :                     if (i != j) mukpdwn(i) += phimup / downer * frct(j) / frct(i);
    4784             :                 }
    4785           0 :                 mumix += fvis(i) / mukpdwn(i); // eq. 60
    4786             :             }
    4787             : 
    4788             :             // Calculate the density of the mixture assuming an ideal gas
    4789           0 :             rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
    4790             : 
    4791             :             // Final mixture properties
    4792           0 :             visc = mumix;
    4793           0 :             dens = rhomix;
    4794             : 
    4795             :         } // End of check if single or multiple gases in gap
    4796      265344 :     }     // WindowGasPropertiesAtTemp()
    4797             : 
    4798             :     //********************************************************************************
    4799             : 
    4800    23964637 :     void StartingWindowTemps(EnergyPlusData &state,
    4801             :                              int const SurfNum,          // Surface number
    4802             :                              Array1A<Real64> AbsRadShade // Short-wave radiation absorbed by shade/blind faces
    4803             :     )
    4804             :     {
    4805             : 
    4806             :         // SUBROUTINE INFORMATION:
    4807             :         //       AUTHOR         F. Winkelmann
    4808             :         //       DATE WRITTEN   January 2000
    4809             :         //       MODIFIED       March 2003, FW: add rough calc of increase above ambient of
    4810             :         //                        initial shade/blind temperature when shade/blind deployed
    4811             :         //                        after having been off.
    4812             :         //                      Jan 2004, FW: take into account whether storm window was added
    4813             :         //                        or removed in the current time step.
    4814             :         //       RE-ENGINEERED  na
    4815             : 
    4816             :         // PURPOSE OF THIS SUBROUTINE:
    4817             :         // Initializes face temperature distribution prior to iteration
    4818             : 
    4819             :         // Argument array dimensioning
    4820    23964637 :         AbsRadShade.dim(2);
    4821             : 
    4822    23964637 :         constexpr Real64 hrad(5.3);    // Typical radiative conductance (W/m2-K)
    4823    23964637 :         constexpr Real64 resgap(0.21); // Typical gap resistance (m2-K/W)
    4824             : 
    4825             :         WinShadingType ShadeFlag;   // Shading flag
    4826    23964637 :         Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
    4827             :         // inside or outside air film, or gap
    4828             :         Real64 restot; // Total window resistance including outside
    4829             :         //   and inside air films (m2-K/W)
    4830             :         Real64 temdiff;          // Inside/outside air temperature difference (K)
    4831             :         Real64 ressum;           // Resistance sum (m2-K/W)
    4832             :         int StormWinFlagPrevDay; // Previous time step value (day) of storm window flag
    4833             :         int StormWinFlagThisDay; // Current time step value (day) of storm window flag
    4834             :         int nglfacePrevDay;      // Previous time step value (dya) of number of glass faces (may differ
    4835             :         //   current time step value, nglface, if storm window was
    4836             :         //   added or removed during the current time step).
    4837             : 
    4838    23964637 :         auto &wm = state.dataWindowManager;
    4839             : 
    4840    23964637 :         StormWinFlagPrevDay = state.dataSurface->SurfWinStormWinFlagPrevDay(SurfNum);
    4841    23964637 :         StormWinFlagThisDay = state.dataSurface->SurfWinStormWinFlag(SurfNum);
    4842             : 
    4843    23964637 :         if (state.dataGlobal->BeginEnvrnFlag || (StormWinFlagThisDay != StormWinFlagPrevDay)) {
    4844             : 
    4845             :             // Guess values of glass face temperatures based on a simple resistance-network solution
    4846             :             // that (1) ignores short- and long-wave radiation (from lights and zone equipment) absorbed
    4847             :             // by the glass faces, and (2) assumes zero glass resistance. Absorbed solar is also ignored
    4848             :             // since the tests on BeginEnvrnFlag and storm window transition can be true only at midnight.
    4849             :             // Interaction with shade or blind, if one of these is present, is ignored. See below for
    4850             :             // separate calculation of shade/blind temperature.
    4851             : 
    4852       26656 :             rguess(1) = 1.0 / (wm->hcout + hrad);
    4853       26656 :             rguess(wm->nglface + 1) = 1.0 / (wm->hcin + hrad);
    4854             : 
    4855       61890 :             for (int i = 2; i <= wm->nglface; i += 2) {
    4856       35234 :                 rguess(i) = 1.0 / wm->scon[i / 2 - 1];
    4857       35234 :                 if (i < wm->nglface) rguess(i + 1) = resgap;
    4858             :             }
    4859             : 
    4860       26656 :             restot = 0.0;
    4861      123780 :             for (int i = 1; i <= wm->nglface + 1; ++i) {
    4862       97124 :                 restot += rguess(i);
    4863             :             }
    4864             : 
    4865       26656 :             temdiff = wm->tin - wm->tout;
    4866       26656 :             if (std::abs(temdiff) < 0.5) temdiff = 2.0;
    4867             : 
    4868       26656 :             ressum = 0.0;
    4869       97124 :             for (int i = 1; i <= wm->nglface; ++i) {
    4870       70468 :                 ressum += rguess(i);
    4871       70468 :                 wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
    4872             :             }
    4873             : 
    4874             :         } else {
    4875             :             // Use previous time step values
    4876    85758577 :             for (int i = 1; i <= wm->nglface; ++i) {
    4877    61820596 :                 wm->thetas[i - 1] = state.dataSurface->SurfaceWindow(SurfNum).thetaFace[i];
    4878             :             }
    4879             :         }
    4880             : 
    4881             :         // Initialize face temperatures of shade or blind, if present
    4882             : 
    4883    23964637 :         ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    4884    23964637 :         if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum)) ||
    4885    23816852 :             state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade ||
    4886    71582263 :             state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind ||
    4887    23800774 :             ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum))) {
    4888             :             // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps.
    4889             :             // Note that if shade or blind is NOT on in the current TS the following two
    4890             :             // temperature values, although calculated here, are not used. The shade/blind face numbers
    4891             :             // during the previous time step depend on whether a storm window glass layer was added to
    4892             :             // or removed from the window during the current time step.
    4893      180717 :             nglfacePrevDay = wm->nglface;
    4894      180717 :             if (StormWinFlagPrevDay == 0 && StormWinFlagThisDay == 1) nglfacePrevDay = wm->nglface - 2;
    4895      180717 :             if (StormWinFlagPrevDay == 1 && StormWinFlagThisDay == 0) nglfacePrevDay = wm->nglface + 2;
    4896      180717 :             wm->thetas[wm->nglface] = state.dataSurface->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 1];
    4897      180717 :             wm->thetas[wm->nglface + 1] = state.dataSurface->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 2];
    4898             :         } else {
    4899             :             // No shade or blind previous time step; guess starting values of shade/blind
    4900             :             // taking into account short- and long-wave radiation (from solar, lights and zone equipment)
    4901             :             // absorbed by shade/blind faces. Face temps are assumed to be the same and
    4902             :             // equal to shade/blind temp. For interior shade/blind, air temp on either side is
    4903             :             // assumed to be the same and equal to tin; for exterior blind it is assumed to be
    4904             :             // equal to tout. For between-glass shade/blind it is assumed to be equal to the
    4905             :             // average temperature of the adjacent glass faces.
    4906             : 
    4907    23783920 :             if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
    4908        4477 :                 wm->thetas[wm->nglface] = wm->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcin + hrad));
    4909        4477 :                 wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4910    23779443 :             } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) {
    4911        1107 :                 wm->thetas[wm->nglface] = wm->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcout + hrad));
    4912        1107 :                 wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4913    23778336 :             } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    4914             :                 // Between-glass shade/blind allowed only for double and triple glazing.
    4915             :                 // The factor 16.0 below is based on a combined convective/radiative heat transfer
    4916             :                 // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F.
    4917          30 :                 if (wm->nglface == 4) { // double glazing
    4918          22 :                     wm->thetas[wm->nglface] = 0.5 * (wm->thetas[1] + wm->thetas[2]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
    4919          22 :                     wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4920             :                 } else { // triple glazing
    4921           8 :                     wm->thetas[wm->nglface] = 0.5 * (wm->thetas[3] + wm->thetas[4]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
    4922           8 :                     wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
    4923             :                 }
    4924             :             }
    4925             :         }
    4926    23964637 :     } // StartingWindowTemps()
    4927             : 
    4928             :     //****************************************************************************
    4929             : 
    4930    15109751 :     void NusseltNumber(EnergyPlusData &state,
    4931             :                        int const SurfNum, // Surface number
    4932             :                        Real64 const tso,  // Temperature of gap surface closest to outside (K)
    4933             :                        Real64 const tsi,  // Temperature of gap surface closest to zone (K)
    4934             :                        int const IGap,    // Gap number
    4935             :                        Real64 const gr,   // Gap gas Grashof number
    4936             :                        Real64 const pr,   // Gap gas Prandtl number
    4937             :                        Real64 &gnu        // Gap gas Nusselt number
    4938             :     )
    4939             :     {
    4940             : 
    4941             :         // SUBROUTINE INFORMATION:
    4942             :         //       AUTHOR         Adapted by Fred Winkelmann from Window5 subroutine nusselt
    4943             :         //       DATE WRITTEN   September 2001
    4944             :         //       MODIFIED       na
    4945             :         //       RE-ENGINEERED  na
    4946             : 
    4947             :         // PURPOSE OF THIS SUBROUTINE:
    4948             :         // Finds the Nusselt number for gas-filled gaps between isothermal solid layers.
    4949             :         // The gap may be filled with a single gas or a gas mixture.
    4950             : 
    4951             :         // METHODOLOGY EMPLOYED:
    4952             :         // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
    4953             :         // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
    4954             :         // The equation numbers below correspond to those in the standard.
    4955             : 
    4956             :         // REFERENCES:
    4957             :         // Window5 source code; ISO 15099
    4958             : 
    4959             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4960             :         Real64 asp;    // Aspect ratio: window height to gap width
    4961             :         Real64 ra;     // Rayleigh number
    4962             :         Real64 gnu901; // Nusselt number temporary variables for
    4963             :         Real64 gnu902;
    4964             :         Real64 gnu90;
    4965             :         Real64 gnu601;
    4966             :         Real64 gnu602; // different tilt and Ra ranges
    4967             :         Real64 gnu60;
    4968             :         Real64 gnu601a;
    4969             :         Real64 gnua;
    4970             :         Real64 gnub;
    4971             :         Real64 cra; // Temporary variables
    4972             :         Real64 a;
    4973             :         Real64 b;
    4974             :         Real64 g;
    4975             :         Real64 ang;
    4976             : 
    4977    15109751 :         auto &wm = state.dataWindowManager;
    4978             : 
    4979    15109751 :         if (SurfNum > 0) {
    4980    15101417 :             asp = state.dataSurface->Surface(SurfNum).Height / wm->gaps[IGap - 1].width;
    4981             :         } else { // SurfNum = 0 when NusseltNumber is called from CalcNominalWindowCond, which applies to a
    4982             :             // particular construction. So window height is not known and we assume 5 ft (1.524 m)
    4983        8334 :             asp = 1.524 / wm->gaps[IGap - 1].width;
    4984             :         }
    4985             : 
    4986    15109751 :         wm->tiltr = wm->tilt * Constant::DegToRadians;
    4987    15109751 :         ra = gr * pr;
    4988             :         //! fw if (ra > 2.0e6): error that outside range of Rayleigh number?
    4989             : 
    4990    15109751 :         if (ra <= 1.0e4) gnu901 = 1.0 + 1.7596678e-10 * std::pow(ra, 2.2984755); // eq. 51
    4991    15109751 :         if (ra > 1.0e4 && ra <= 5.0e4) gnu901 = 0.028154 * std::pow(ra, 0.4134); // eq. 50
    4992    15109751 :         if (ra > 5.0e4) gnu901 = 0.0673838 * std::pow(ra, 1.0 / 3.0);            // eq. 49
    4993             : 
    4994    15109751 :         gnu902 = 0.242 * std::pow(ra / asp, 0.272); // eq. 52
    4995    15109751 :         gnu90 = max(gnu901, gnu902);
    4996             : 
    4997    15109751 :         if (tso > tsi) {                                     // window heated from above
    4998     4773408 :             gnu = 1.0 + (gnu90 - 1.0) * std::sin(wm->tiltr); // eq. 53
    4999             :         } else {                                             // window heated from below
    5000    10336343 :             if (wm->tilt >= 60.0) {
    5001     9205926 :                 if (ra >= 0.001) {
    5002     9183516 :                     g = 0.5 * std::pow(1.0 + std::pow(ra / 3160.0, 20.6), -0.1); // eq. 47
    5003             :                 } else {
    5004       22410 :                     g = 0.5;
    5005             :                 }
    5006     9205926 :                 gnu601a = 1.0 + pow_7(0.0936 * std::pow(ra, 0.314) / (1.0 + g)); // eq. 45
    5007     9205926 :                 gnu601 = std::pow(gnu601a, 0.142857);
    5008             : 
    5009             :                 // For any aspect ratio
    5010     9205926 :                 gnu602 = (0.104 + 0.175 / asp) * std::pow(ra, 0.283); // eq. 46
    5011     9205926 :                 gnu60 = max(gnu601, gnu602);
    5012             : 
    5013             :                 // linear interpolation for layers inclined at angles between 60 and 90 deg
    5014     9205926 :                 gnu = ((90.0 - wm->tilt) * gnu60 + (wm->tilt - 60.0) * gnu90) / 30.0;
    5015             :             }
    5016    10336343 :             if (wm->tilt < 60.0) { // eq. 42
    5017     1130417 :                 cra = ra * std::cos(wm->tiltr);
    5018     1130417 :                 a = 1.0 - 1708.0 / cra;
    5019     1130417 :                 b = std::pow(cra / 5830.0, 0.33333) - 1.0;
    5020     1130417 :                 gnua = (std::abs(a) + a) / 2.0;
    5021     1130417 :                 gnub = (std::abs(b) + b) / 2.0;
    5022     1130417 :                 ang = 1708.0 * std::pow(std::sin(1.8 * wm->tiltr), 1.6);
    5023     1130417 :                 gnu = 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
    5024             :             }
    5025             :         }
    5026    15109751 :     } // NusseltNumber()
    5027             : 
    5028             :     //*******************************************************************************************************
    5029             : 
    5030      913900 :     void TransAndReflAtPhi(Real64 const cs,                // Cosine of incidence angle
    5031             :                            Real64 const tf0,               // Transmittance at zero incidence angle
    5032             :                            Real64 const rf0,               // Front reflectance at zero incidence angle
    5033             :                            Real64 const rb0,               // Back reflectance at zero incidence angle
    5034             :                            Real64 &tfp,                    // Transmittance at cs
    5035             :                            Real64 &rfp,                    // Front reflectance at cs
    5036             :                            Real64 &rbp,                    // Back reflectance at cs
    5037             :                            bool const SimpleGlazingSystem, // .TRUE. if simple block model being used
    5038             :                            Real64 const SimpleGlazingSHGC, // SHGC value to use in alternate model for simple glazing system
    5039             :                            Real64 const SimpleGlazingU     // U-factor value to use in alternate model for simple glazing system
    5040             :     )
    5041             :     {
    5042             : 
    5043             :         // SUBROUTINE INFORMATION:
    5044             :         //       AUTHOR         F. Winkelmann
    5045             :         //       DATE WRITTEN   January 2000
    5046             :         //       MODIFIED       5 June 2003, FCW: modify to correspond to WINDOW 4 and WINDOW 5.
    5047             :         //                      Original routine was based on the method in E.U. Finlayson et al,
    5048             :         //                      "WINDOW 4.0: Documentation of Calculation Procedures," LBL-33943,
    5049             :         //                      July 1993, which is not used in either WINDOW 4 or WINDOW 5.
    5050             :         //                      The current routine is based on ASHRAE Handbook of Fundamentals,
    5051             :         //                      2001, pp. 30.20-23, "Optical Properties of Single Glazing Layers."
    5052             :         //                      Original routine underpredicted transmittance at angles of
    5053             :         //                      incidence > 60 degrees.
    5054             :         //                      June 2009.  Brent Griffith.  add simple window correlation
    5055             :         //                                   newer model from LBNL windows group 5/15/2009
    5056             :         //       RE-ENGINEERED  na
    5057             : 
    5058             :         // PURPOSE OF THIS SUBROUTINE:
    5059             :         // For a single glazing layer, calculate transmittance and reflectance at an arbitrary
    5060             :         // angle of incidence given transmittance and reflectance at zero incidence angle.
    5061             : 
    5062             :         // REFERENCES:
    5063             :         // ASHRAE Handbook of Fundamentals, 2001, pp. 30.20-23,
    5064             :         // "Optical Properties of Single Glazing Layers."
    5065             : 
    5066             :         Real64 tfp1; // Transmittance at cs for each polarization
    5067             :         Real64 tfp2;
    5068             :         Real64 rfp1; // Front reflectance at cs for each polarization
    5069             :         Real64 rfp2;
    5070             :         Real64 rbp1; // Back reflectance at cs for each polarization
    5071             :         Real64 rbp2;
    5072             :         Real64 betaf; // Intermediate variables
    5073             :         Real64 betab;
    5074             :         Real64 r0f;
    5075             :         Real64 r0b;
    5076             :         Real64 abf;
    5077             :         Real64 abb;
    5078             :         Real64 ngf; // Front and back index of refraction
    5079             :         Real64 ngb;
    5080             :         Real64 cgf; // Intermediate variables
    5081             :         Real64 cgb;
    5082             :         Real64 rpf1; // Front and back air/glass interface reflectivity
    5083             :         Real64 rpb1;
    5084             :         Real64 tpf1;
    5085             :         Real64 tpb1;
    5086             :         //  and transmittivity for first polarization
    5087             :         Real64 rpf2; // Front and back air/glass interface reflectivity
    5088             :         Real64 rpb2;
    5089             :         Real64 tpf2;
    5090             :         Real64 tpb2;
    5091             :         //  and transmittivity for second polarization
    5092             :         Real64 tcl; // Transmittance and reflectance for clear glass
    5093             :         Real64 rcl;
    5094             :         Real64 tbnz; // Transmittance and reflectance for bronze glass
    5095             :         Real64 rbnz;
    5096             :         Real64 expmabfdivcgf;
    5097             :         Real64 expm2abfdivcgf;
    5098             :         Real64 expmabbdivcgb;
    5099             : 
    5100             :         Real64 testval; // temporary value for calculations
    5101             :         Real64 tmp1;    // temporary value for calculations
    5102             :         Real64 tmp2;    // temporary value for calculations
    5103             :         Real64 tmp3;    // temporary value for calculations
    5104             :         Real64 tmp4;    // temporary value for calculations
    5105             :         Real64 tmp5;    // temporary value for calculations
    5106             :         Real64 tmp6;    // temporary value for calculations
    5107             :         Real64 tmp7;    // temporary value for calculations
    5108             :         Real64 tmp8;    // temporary value for calculations
    5109             :         Real64 tmp9;    // temporary value for calculations
    5110             : 
    5111      913900 :         if (SimpleGlazingSystem) { // use alternate angular dependence model for block model of simple glazing input
    5112             : 
    5113        5280 :             Real64 const cs_2(pow_2(cs));
    5114        5280 :             Real64 const cs_3(pow_3(cs));
    5115        5280 :             Real64 const cs_4(pow_4(cs));
    5116        5280 :             Real64 TransCurveA = 0.00 + 3.36 * cs - 3.85 * cs_2 + 1.49 * cs_3 + 0.01 * cs_4;
    5117        5280 :             Real64 TransCurveB = 0.00 + 2.83 * cs - 2.42 * cs_2 + 0.04 * cs_3 + 0.55 * cs_4;
    5118        5280 :             Real64 TransCurveC = 0.00 + 2.45 * cs - 1.58 * cs_2 - 0.64 * cs_3 + 0.77 * cs_4;
    5119        5280 :             Real64 TransCurveD = 0.00 + 2.85 * cs - 2.58 * cs_2 + 0.40 * cs_3 + 0.35 * cs_4;
    5120        5280 :             Real64 TransCurveE = 0.00 + 1.51 * cs + 2.49 * cs_2 - 5.87 * cs_3 + 2.88 * cs_4;
    5121        5280 :             Real64 TransCurveF = 0.00 + 1.21 * cs + 3.14 * cs_2 - 6.37 * cs_3 + 3.03 * cs_4;
    5122        5280 :             Real64 TransCurveG = 0.00 + 1.09 * cs + 3.54 * cs_2 - 6.84 * cs_3 + 3.23 * cs_4;
    5123        5280 :             Real64 TransCurveH = 0.00 + 0.98 * cs + 3.83 * cs_2 - 7.13 * cs_3 + 3.33 * cs_4;
    5124        5280 :             Real64 TransCurveI = 0.00 + 0.79 * cs + 3.93 * cs_2 - 6.86 * cs_3 + 3.15 * cs_4;
    5125        5280 :             Real64 TransCurveJ = 0.00 + 0.08 * cs + 6.02 * cs_2 - 8.84 * cs_3 + 3.74 * cs_4;
    5126        5280 :             Real64 TransCurveFGHI = (TransCurveF + TransCurveG + TransCurveH + TransCurveI) / 4.0;
    5127        5280 :             Real64 TransCurveFH = (TransCurveF + TransCurveH) / 2.0;
    5128        5280 :             Real64 TransCurveBDCD = (TransCurveB + TransCurveD + TransCurveC + TransCurveD) / 4.0;
    5129             : 
    5130        5280 :             Real64 ReflectCurveA = 1.00 - 0.70 * cs + 2.57 * cs_2 - 3.20 * cs_3 + 1.33 * cs_4 - TransCurveA;
    5131        5280 :             Real64 ReflectCurveB = 1.00 - 1.87 * cs + 6.50 * cs_2 - 7.86 * cs_3 + 3.23 * cs_4 - TransCurveB;
    5132        5280 :             Real64 ReflectCurveC = 1.00 - 2.52 * cs + 8.40 * cs_2 - 9.86 * cs_3 + 3.99 * cs_4 - TransCurveC;
    5133        5280 :             Real64 ReflectCurveD = 1.00 - 1.85 * cs + 6.40 * cs_2 - 7.64 * cs_3 + 3.11 * cs_4 - TransCurveD;
    5134        5280 :             Real64 ReflectCurveE = 1.00 - 1.57 * cs + 5.60 * cs_2 - 6.82 * cs_3 + 2.80 * cs_4 - TransCurveE;
    5135        5280 :             Real64 ReflectCurveF = 1.00 - 3.15 * cs + 10.98 * cs_2 - 13.14 * cs_3 + 5.32 * cs_4 - TransCurveF;
    5136        5280 :             Real64 ReflectCurveG = 1.00 - 3.25 * cs + 11.32 * cs_2 - 13.54 * cs_3 + 5.49 * cs_4 - TransCurveG;
    5137        5280 :             Real64 ReflectCurveH = 1.00 - 3.39 * cs + 11.70 * cs_2 - 13.94 * cs_3 + 5.64 * cs_4 - TransCurveH;
    5138        5280 :             Real64 ReflectCurveI = 1.00 - 4.06 * cs + 13.55 * cs_2 - 15.74 * cs_3 + 6.27 * cs_4 - TransCurveI;
    5139        5280 :             Real64 ReflectCurveJ = 1.00 - 4.35 * cs + 14.27 * cs_2 - 16.32 * cs_3 + 6.39 * cs_4 - TransCurveJ;
    5140             : 
    5141        5280 :             Real64 ReflectCurveFGHI = (ReflectCurveF + ReflectCurveG + ReflectCurveH + ReflectCurveI) / 4.0;
    5142        5280 :             Real64 ReflectCurveFH = (ReflectCurveF + ReflectCurveH) / 2.0;
    5143        5280 :             Real64 ReflectCurveBDCD = (ReflectCurveB + ReflectCurveD + ReflectCurveC + ReflectCurveD) / 4.0;
    5144             : 
    5145        5280 :             Real64 TransTmp(0.0);
    5146        5280 :             Real64 ReflectTmp(0.0);
    5147             : 
    5148        5280 :             if (SimpleGlazingU < 1.4195) { // cell 1, 2, or 3
    5149          80 :                 if (SimpleGlazingSHGC > 0.45) {
    5150             :                     // cell # 1
    5151             :                     // Curve E
    5152          80 :                     TransTmp = TransCurveE;
    5153          80 :                     ReflectTmp = ReflectCurveE;
    5154             : 
    5155           0 :                 } else if ((0.35 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    5156             :                     // cell # 2
    5157             :                     // 2 way interpolation between Curve E and Curve J
    5158           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, TransCurveJ, TransCurveE);
    5159           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, ReflectCurveJ, ReflectCurveE);
    5160             : 
    5161           0 :                 } else if (SimpleGlazingSHGC < 0.35) {
    5162             :                     // cell # 3
    5163             :                     // Curve J
    5164           0 :                     TransTmp = TransCurveJ;
    5165           0 :                     ReflectTmp = ReflectCurveJ;
    5166             :                 }
    5167             : 
    5168        5200 :             } else if ((1.4195 <= SimpleGlazingU) && (SimpleGlazingU <= 1.7034)) { // cell 4, 5 , 6, 7, 8, 9, or 10
    5169           0 :                 if (SimpleGlazingSHGC > 0.55) {
    5170             :                     // cell # 4
    5171             :                     // Curve E
    5172           0 :                     TransTmp = TransCurveE;
    5173           0 :                     ReflectTmp = ReflectCurveE;
    5174             : 
    5175           0 :                 } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
    5176             :                     // cell # 5
    5177             :                     // 4 way interpolation between Curve E , Curve E, Curve E and Curve FGHI
    5178             : 
    5179           0 :                     TransTmp = InterpolateBetweenFourValues(
    5180             :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, TransCurveE, TransCurveE, TransCurveFGHI, TransCurveE);
    5181           0 :                     ReflectTmp = InterpolateBetweenFourValues(
    5182             :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, ReflectCurveE, ReflectCurveE, ReflectCurveFGHI, ReflectCurveE);
    5183             : 
    5184           0 :                 } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
    5185             :                     // cell # 6
    5186             :                     // 2 way interpolation between Curve E and Curve FGHI
    5187           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveE, TransCurveFGHI);
    5188           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveE, ReflectCurveFGHI);
    5189             : 
    5190           0 :                 } else if ((0.35 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    5191             :                     // cell # 7
    5192             :                     // 4 way interpolation between Curve E , Curve FGHI, Curve J and Curve FGHI
    5193           0 :                     TransTmp = InterpolateBetweenFourValues(
    5194             :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.35, 0.45, TransCurveJ, TransCurveE, TransCurveFGHI, TransCurveFGHI);
    5195           0 :                     ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
    5196             :                                                               SimpleGlazingSHGC,
    5197             :                                                               1.4195,
    5198             :                                                               1.7034,
    5199             :                                                               0.35,
    5200             :                                                               0.45,
    5201             :                                                               ReflectCurveJ,
    5202             :                                                               ReflectCurveE,
    5203             :                                                               ReflectCurveFGHI,
    5204             :                                                               ReflectCurveFGHI);
    5205             : 
    5206           0 :                 } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.35)) {
    5207             :                     // cell # 8
    5208             :                     // 2 way interpolation between Curve J and Curve FGHI
    5209           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFGHI);
    5210           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFGHI);
    5211             : 
    5212           0 :                 } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
    5213             :                     // cell # 9
    5214             :                     // 4 way interpolation between Curve J, Curve FGHI, Curve J and Curve FH
    5215           0 :                     TransTmp = InterpolateBetweenFourValues(
    5216             :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, TransCurveJ, TransCurveJ, TransCurveFH, TransCurveFGHI);
    5217           0 :                     ReflectTmp = InterpolateBetweenFourValues(
    5218             :                         SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, ReflectCurveJ, ReflectCurveJ, ReflectCurveFH, ReflectCurveFGHI);
    5219             : 
    5220           0 :                 } else if (SimpleGlazingSHGC <= 0.25) {
    5221             :                     // cell # 10
    5222             :                     // 2 way interpolation between Curve J and Curve FH
    5223           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFH);
    5224           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFH);
    5225             :                 }
    5226        5200 :             } else if ((1.7034 < SimpleGlazingU) && (SimpleGlazingU < 3.4068)) { // cell 11, 12, 13, 14, or 15
    5227        5040 :                 if (SimpleGlazingSHGC > 0.55) {
    5228             :                     // cell # 11
    5229             :                     // Curve E
    5230         400 :                     TransTmp = TransCurveE;
    5231         400 :                     ReflectTmp = ReflectCurveE;
    5232             : 
    5233        4640 :                 } else if ((0.5 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
    5234             :                     // cell # 12
    5235             :                     // 2 way interpolation between Curve E and Curve FGHI
    5236          40 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, TransCurveFGHI, TransCurveE);
    5237          40 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, ReflectCurveFGHI, ReflectCurveE);
    5238             : 
    5239        4600 :                 } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.5)) {
    5240             :                     // cell # 13
    5241             :                     // Curve FGHI
    5242        4600 :                     TransTmp = TransCurveFGHI;
    5243        4600 :                     ReflectTmp = ReflectCurveFGHI;
    5244             : 
    5245           0 :                 } else if ((0.25 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
    5246             :                     // cell # 14
    5247             :                     // 2 way interpolation between Curve FGHI and Curve FH
    5248           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, TransCurveFH, TransCurveFGHI);
    5249           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, ReflectCurveFH, ReflectCurveFGHI);
    5250             : 
    5251           0 :                 } else if (SimpleGlazingSHGC < 0.25) {
    5252             :                     // cell # 15
    5253             :                     // Curve FH
    5254           0 :                     TransTmp = TransCurveFH;
    5255           0 :                     ReflectTmp = ReflectCurveFH;
    5256             :                 }
    5257             : 
    5258         160 :             } else if ((3.4068 <= SimpleGlazingU) && (SimpleGlazingU <= 4.5424)) { // cell 16, 17, 18, 19, 20, 21, 22, or 23
    5259          80 :                 if (SimpleGlazingSHGC > 0.65) {
    5260             :                     // cell # 16
    5261             :                     // 2 way interpolation between Curve E and Curve A
    5262           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveA);
    5263           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveA);
    5264             : 
    5265          80 :                 } else if ((0.6 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
    5266             :                     // cell # 17
    5267             :                     // 4 way interpolation between Curve E , Curve E, Curve A, and Curve BDCD
    5268           0 :                     TransTmp = InterpolateBetweenFourValues(
    5269             :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, TransCurveE, TransCurveE, TransCurveBDCD, TransCurveA);
    5270           0 :                     ReflectTmp = InterpolateBetweenFourValues(
    5271             :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, ReflectCurveE, ReflectCurveE, ReflectCurveBDCD, ReflectCurveA);
    5272             : 
    5273          80 :                 } else if ((0.55 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.6)) {
    5274             :                     // cell # 18
    5275             :                     // 2 way interpolation between Curve E and Curve BDCD
    5276           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveBDCD);
    5277           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveBDCD);
    5278             : 
    5279          80 :                 } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
    5280             :                     // cell # 19
    5281             :                     // 4 way interpolation between Curve E , Curve FGHI, Curve BDCD and Curve BDCD
    5282          40 :                     TransTmp = InterpolateBetweenFourValues(
    5283             :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.5, 0.55, TransCurveFGHI, TransCurveE, TransCurveBDCD, TransCurveBDCD);
    5284          40 :                     ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
    5285             :                                                               SimpleGlazingSHGC,
    5286             :                                                               3.4068,
    5287             :                                                               4.5424,
    5288             :                                                               0.5,
    5289             :                                                               0.55,
    5290             :                                                               ReflectCurveFGHI,
    5291             :                                                               ReflectCurveE,
    5292             :                                                               ReflectCurveBDCD,
    5293             :                                                               ReflectCurveBDCD);
    5294             : 
    5295          40 :                 } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
    5296             :                     // cell # 20
    5297             :                     // 2 way interpolation between Curve FGHI and Curve BDCD
    5298           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFGHI, TransCurveBDCD);
    5299           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFGHI, ReflectCurveBDCD);
    5300             : 
    5301          40 :                 } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    5302             :                     // cell # 21
    5303             :                     // 4 way interpolation between Curve FGHI, Curve FGHI, Curve BDCD, and Curve D
    5304          40 :                     TransTmp = InterpolateBetweenFourValues(
    5305             :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.3, 0.45, TransCurveFGHI, TransCurveFGHI, TransCurveD, TransCurveBDCD);
    5306          40 :                     ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
    5307             :                                                               SimpleGlazingSHGC,
    5308             :                                                               3.4068,
    5309             :                                                               4.5424,
    5310             :                                                               0.3,
    5311             :                                                               0.45,
    5312             :                                                               ReflectCurveFGHI,
    5313             :                                                               ReflectCurveFGHI,
    5314             :                                                               ReflectCurveD,
    5315             :                                                               ReflectCurveBDCD);
    5316             : 
    5317           0 :                 } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
    5318             :                     // cell # 22
    5319             :                     // 4 way interpolation between Curve FGHI, Curve FH, Curve D, and Curve D
    5320           0 :                     TransTmp = InterpolateBetweenFourValues(
    5321             :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, TransCurveFH, TransCurveFGHI, TransCurveD, TransCurveD);
    5322           0 :                     ReflectTmp = InterpolateBetweenFourValues(
    5323             :                         SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, ReflectCurveFH, ReflectCurveFGHI, ReflectCurveD, ReflectCurveD);
    5324             : 
    5325           0 :                 } else if (SimpleGlazingSHGC <= 0.25) {
    5326             :                     // cell # 23
    5327             :                     // 2 way interpolation between Curve FH and Curve D
    5328           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFH, TransCurveD);
    5329           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFH, ReflectCurveD);
    5330             :                 }
    5331          80 :             } else if (SimpleGlazingU > 4.5424) { // cell 24, 25, 26, 27, or 28
    5332          80 :                 if (SimpleGlazingSHGC > 0.65) {
    5333             :                     // cell # 24
    5334             :                     // Curve A
    5335          80 :                     TransTmp = TransCurveA;
    5336          80 :                     ReflectTmp = ReflectCurveA;
    5337           0 :                 } else if ((0.6 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
    5338             :                     // cell # 25
    5339             :                     // 2 way interpolation between Curve A and Curve BDCD
    5340           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, TransCurveBDCD, TransCurveA);
    5341           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, ReflectCurveBDCD, ReflectCurveA);
    5342             : 
    5343           0 :                 } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.6)) {
    5344             :                     // cell # 26
    5345             :                     // Curve BDCD
    5346           0 :                     TransTmp = TransCurveBDCD;
    5347           0 :                     ReflectTmp = ReflectCurveBDCD;
    5348             : 
    5349           0 :                 } else if ((0.3 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
    5350             :                     // cell # 27
    5351             :                     // 2 way interpolation between Curve BDCD and Curve D
    5352           0 :                     TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, TransCurveD, TransCurveBDCD);
    5353           0 :                     ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, ReflectCurveD, ReflectCurveBDCD);
    5354             : 
    5355           0 :                 } else if (SimpleGlazingSHGC < 0.3) {
    5356             :                     // cell # 28
    5357             :                     // Curve D
    5358           0 :                     TransTmp = TransCurveD;
    5359           0 :                     ReflectTmp = ReflectCurveD;
    5360             : 
    5361             :                 } else {
    5362           0 :                     assert(false);
    5363             :                 }
    5364             :             } else {
    5365           0 :                 assert(false);
    5366             :             }
    5367             : 
    5368        5280 :             if (cs == 1.0) { // at 0 deg incident, TransTmp and ReflectTmp should be 1.0
    5369         528 :                 TransTmp = 1.0;
    5370         528 :                 ReflectTmp = 0.0;
    5371             :             }
    5372             : 
    5373             :             // now apply normalization factors to zero incidence angle properties
    5374        5280 :             tfp = tf0 * TransTmp;
    5375        5280 :             tfp = max(min(1.0, tfp), 0.0);
    5376             : 
    5377        5280 :             rfp = rf0 * (1. - ReflectTmp) + ReflectTmp;
    5378        5280 :             rfp = max(min(0.9999 - tfp, rfp), 0.0);
    5379             : 
    5380        5280 :             rbp = rfp;
    5381             : 
    5382      908620 :         } else if (tf0 <= 0.0) {
    5383             :             // This is an opaque window.  For all angles, set transmittance to 0; set reflectance to that at zero incidence angle.
    5384           0 :             tfp = 0.0;
    5385           0 :             rfp = rf0;
    5386           0 :             rbp = rb0;
    5387             :         } else {
    5388             : 
    5389      908620 :             betaf = pow_2(tf0) - pow_2(rf0) + 2.0 * rf0 + 1.0;
    5390      908620 :             betab = pow_2(tf0) - pow_2(rb0) + 2.0 * rb0 + 1.0;
    5391      908620 :             r0f = (betaf - std::sqrt(pow_2(betaf) - 4.0 * (2.0 - rf0) * rf0)) / (2.0 * (2.0 - rf0));
    5392      908620 :             r0b = (betab - std::sqrt(pow_2(betab) - 4.0 * (2.0 - rb0) * rb0)) / (2.0 * (2.0 - rb0));
    5393             : 
    5394      908620 :             tmp1 = std::abs(r0f - r0b);
    5395      908620 :             if (tmp1 != 0.0) {
    5396      264420 :                 testval = std::abs(r0f - r0b) / (r0f + r0b);
    5397             :             } else {
    5398      644200 :                 testval = 0.0;
    5399             :             }
    5400             : 
    5401      908620 :             if (testval < 0.001) { // CR8830, CR8942, implications of relaxation of glazing properties CR8413
    5402             :                 // UNCOATED GLASS
    5403      654700 :                 tmp1 = r0f * tf0;
    5404      654700 :                 if (tmp1 != 0.0) {
    5405      654700 :                     abf = std::log(tmp1 / (rf0 - r0f));
    5406             :                 } else {
    5407           0 :                     abf = 0.0;
    5408             :                 }
    5409      654700 :                 tmp2 = r0b * tf0;
    5410      654700 :                 if (tmp2 != 0.0) {
    5411      654700 :                     abb = std::log(tmp2 / (rb0 - r0b));
    5412             :                 } else {
    5413           0 :                     abb = 0.0;
    5414             :                 }
    5415      654700 :                 ngf = (1.0 + std::sqrt(r0f)) / (1.0 - std::sqrt(r0f));
    5416      654700 :                 ngb = (1.0 + std::sqrt(r0b)) / (1.0 - std::sqrt(r0b));
    5417      654700 :                 cgf = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngf));
    5418      654700 :                 cgb = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngb));
    5419      654700 :                 tmp3 = ngf * cs - cgf;
    5420      654700 :                 if (tmp3 != 0.0) {
    5421      654700 :                     rpf1 = pow_2(tmp3 / (ngf * cs + cgf));
    5422             :                 } else {
    5423           0 :                     rpf1 = 0.0;
    5424             :                 }
    5425      654700 :                 tmp4 = ngf * cgf - cs;
    5426      654700 :                 if (tmp4 != 0.0) {
    5427      654700 :                     rpf2 = pow_2(tmp4 / (ngf * cgf + cs));
    5428             :                 } else {
    5429           0 :                     rpf2 = 0.0;
    5430             :                 }
    5431      654700 :                 tpf1 = 1 - rpf1;
    5432      654700 :                 tpf2 = 1 - rpf2;
    5433      654700 :                 tmp5 = ngb * cs - cgb;
    5434      654700 :                 if (tmp5 != 0.0) {
    5435      654700 :                     rpb1 = pow_2(tmp5 / (ngb * cs + cgb));
    5436             :                 } else {
    5437           0 :                     rpb1 = 0.0;
    5438             :                 }
    5439      654700 :                 tmp6 = ngb * cgb - cs;
    5440      654700 :                 if (tmp6 != 0.0) {
    5441      654700 :                     rpb2 = pow_2(tmp6 / (ngb * cgb + cs));
    5442             :                 } else {
    5443           0 :                     rpb2 = 0.0;
    5444             :                 }
    5445      654700 :                 tpb1 = 1 - rpf1;
    5446      654700 :                 tpb2 = 1 - rpf2;
    5447      654700 :                 tmp7 = -abf;
    5448      654700 :                 if (cgf != 0.0) {
    5449      654700 :                     expmabfdivcgf = std::exp(tmp7 / cgf);
    5450             :                 } else {
    5451           0 :                     expmabfdivcgf = 0.0;
    5452             :                 }
    5453      654700 :                 tmp8 = -2.0 * abf;
    5454      654700 :                 if (cgf != 0.0) {
    5455      654700 :                     expm2abfdivcgf = std::exp(tmp8 / cgf);
    5456             :                 } else {
    5457           0 :                     expm2abfdivcgf = 0.0;
    5458             :                 }
    5459      654700 :                 if (tpf1 != 0.0) {
    5460      589230 :                     tfp1 = pow_2(tpf1) * expmabfdivcgf / (1.0 - pow_2(rpf1) * expm2abfdivcgf);
    5461             :                 } else {
    5462       65470 :                     tfp1 = 0.0;
    5463             :                 }
    5464      654700 :                 rfp1 = rpf1 * (1.0 + tfp1 * expmabfdivcgf);
    5465      654700 :                 if (tpf2 != 0.0) {
    5466      589230 :                     tfp2 = pow_2(tpf2) * expmabfdivcgf / (1.0 - pow_2(rpf2) * expm2abfdivcgf);
    5467             :                 } else {
    5468       65470 :                     tfp2 = 0.0;
    5469             :                 }
    5470      654700 :                 rfp2 = rpf2 * (1.0 + tfp2 * expmabfdivcgf);
    5471      654700 :                 tfp = 0.5 * (tfp1 + tfp2);
    5472      654700 :                 rfp = 0.5 * (rfp1 + rfp2);
    5473      654700 :                 tmp9 = -abb;
    5474      654700 :                 if (tmp9 != 0.0) {
    5475      654700 :                     expmabbdivcgb = std::exp(tmp9 / cgb);
    5476             :                 } else {
    5477           0 :                     expmabbdivcgb = 0.0;
    5478             :                 }
    5479      654700 :                 rbp1 = rpb1 * (1.0 + tfp1 * expmabbdivcgb);
    5480      654700 :                 rbp2 = rpb2 * (1.0 + tfp2 * expmabbdivcgb);
    5481      654700 :                 rbp = 0.5 * (rbp1 + rbp2);
    5482             :             } else {
    5483             :                 // COATED GLASS
    5484      253920 :                 if (tf0 > 0.645) {
    5485             :                     // Use clear glass angular distribution.
    5486             :                     // Normalized clear glass transmittance and reflectance distribution
    5487      144900 :                     if (cs > 0.999) { // Angle of incidence = 0 deg
    5488       14490 :                         tcl = 1.0;
    5489       14490 :                         rcl = 0.0;
    5490      130410 :                     } else if (cs < 0.001) { // Angle of incidence = 90 deg
    5491       14490 :                         tcl = 0.0;
    5492       14490 :                         rcl = 1.0;
    5493             :                     } else {
    5494      115920 :                         tcl = -0.0015 + (3.355 + (-3.840 + (1.460 + 0.0288 * cs) * cs) * cs) * cs;
    5495      115920 :                         rcl = 0.999 + (-0.563 + (2.043 + (-2.532 + 1.054 * cs) * cs) * cs) * cs - tcl;
    5496             :                     }
    5497      144900 :                     tfp = tf0 * tcl;
    5498      144900 :                     rfp = rf0 * (1.0 - rcl) + rcl;
    5499      144900 :                     rbp = rb0 * (1.0 - rcl) + rcl;
    5500             :                 } else {
    5501             :                     // Use bronze glass angular distribution.
    5502             :                     // Normalized bronze tinted glass transmittance and reflectance distribution
    5503      109020 :                     if (cs > 0.999) { // Angle of incidence = 0 deg
    5504       10902 :                         tbnz = 1.0;
    5505       10902 :                         rbnz = 0.0;
    5506       98118 :                     } else if (cs < 0.001) { // Angle of incidence = 90 deg
    5507       10902 :                         tbnz = 0.0;
    5508       10902 :                         rbnz = 1.0;
    5509             :                     } else {
    5510       87216 :                         tbnz = -0.002 + (2.813 + (-2.341 + (-0.05725 + 0.599 * cs) * cs) * cs) * cs;
    5511       87216 :                         rbnz = 0.997 + (-1.868 + (6.513 + (-7.862 + 3.225 * cs) * cs) * cs) * cs - tbnz;
    5512             :                     }
    5513      109020 :                     tfp = tf0 * tbnz;
    5514      109020 :                     rfp = rf0 * (1.0 - rbnz) + rbnz;
    5515      109020 :                     rbp = rb0 * (1.0 - rbnz) + rbnz;
    5516             :                 }
    5517             :             }
    5518             :         }
    5519             : 
    5520             :         // total absorptance cannot be negative
    5521      913900 :         assert(1.0 - rfp - tfp >= -1e6);
    5522      913900 :         assert(1.0 - rbp - tfp >= -1e6);
    5523      913900 :     } // TransAndReflAtPhi()
    5524             : 
    5525          80 :     Real64 InterpolateBetweenTwoValues(Real64 const X, Real64 const X0, Real64 const X1, Real64 const F0, Real64 const F1)
    5526             :     {
    5527             : 
    5528             :         // FUNCTION INFORMATION:
    5529             :         //       AUTHOR         Brent Griffith
    5530             :         //       DATE WRITTEN   June 2009
    5531             :         //       MODIFIED       na
    5532             :         //       RE-ENGINEERED  na
    5533             : 
    5534             :         // PURPOSE OF THIS FUNCTION:
    5535             :         // Interpolate between two results
    5536             : 
    5537             :         // METHODOLOGY EMPLOYED:
    5538             :         // linear interpolation
    5539             : 
    5540             :         Real64 InterpResult;
    5541             : 
    5542          80 :         InterpResult = F0 + ((X - X0) / (X1 - X0)) * (F1 - F0);
    5543          80 :         return InterpResult;
    5544             :     } // InterpolateBetweenTwoValues()
    5545             : 
    5546         160 :     Real64 InterpolateBetweenFourValues(Real64 const X,
    5547             :                                         Real64 const Y,
    5548             :                                         Real64 const X1,
    5549             :                                         Real64 const X2,
    5550             :                                         Real64 const Y1,
    5551             :                                         Real64 const Y2,
    5552             :                                         Real64 const Fx1y1,
    5553             :                                         Real64 const Fx1y2,
    5554             :                                         Real64 const Fx2y1,
    5555             :                                         Real64 const Fx2y2)
    5556             :     {
    5557             : 
    5558             :         // FUNCTION INFORMATION:
    5559             :         //       AUTHOR         Brent Griffith
    5560             :         //       DATE WRITTEN   June 2009
    5561             :         //       MODIFIED       na
    5562             :         //       RE-ENGINEERED  na
    5563             : 
    5564             :         // PURPOSE OF THIS FUNCTION:
    5565             :         // Interpolate between four results.
    5566             : 
    5567             :         // METHODOLOGY EMPLOYED:
    5568             :         // bilinear interpolation (approximate)
    5569             : 
    5570             :         // REFERENCES:
    5571             :         // http://en.wikipedia.org/wiki/Bilinear_interpolation
    5572             : 
    5573             :         // Return value
    5574             :         Real64 InterpResult;
    5575             : 
    5576         160 :         InterpResult = (Fx1y1 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y2 - Y) + (Fx2y1 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y2 - Y) +
    5577         160 :                        (Fx1y2 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y - Y1) + (Fx2y2 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y - Y1);
    5578         160 :         return InterpResult;
    5579             :     } // InterpolateBetweenFourValues()
    5580             : 
    5581             :     //**************************************************************************
    5582             : 
    5583       23444 :     void W5LsqFit(Array1S<Real64> const IndepVar, // Independent variables
    5584             :                   Array1S<Real64> const DepVar,   // Dependent variables
    5585             :                   int const N,                    // Order of polynomial
    5586             :                   int const N1,                   // First and last data points used
    5587             :                   int const N2,
    5588             :                   Array1S<Real64> CoeffsCurve // Polynomial coeffients from fit
    5589             :     )
    5590             :     {
    5591             : 
    5592             :         // SUBROUTINE INFORMATION:
    5593             :         //       AUTHOR         George Walton
    5594             :         //       DATE WRITTEN   April 1976
    5595             :         //       MODIFIED       November 1999 F.Winkelmann
    5596             :         //       RE-ENGINEERED  na
    5597             : 
    5598             :         // PURPOSE OF THIS SUBROUTINE:
    5599             :         // Does least squares fit for coefficients of a polynomial
    5600             :         // that gives a window property, such as transmittance, as a function of
    5601             :         // the cosine of the angle of incidence. The polynomial is of the
    5602             :         // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
    5603             :         // Adapted from BLAST subroutine LSQFIT.
    5604             : 
    5605       46888 :         Array2D<Real64> A(6, 6);  // Least squares derivative matrix
    5606       23444 :         Array1D<Real64> B(6);     // Least squares derivative vector
    5607       46888 :         Array2D<Real64> D(6, 16); // Powers of independent variable
    5608             :         Real64 ACON;              // Intermediate variables
    5609             :         Real64 SUM;
    5610             :         int KP1;
    5611             :         int LP1;
    5612             :         int NM1;
    5613             : 
    5614             :         // Set up least squares matrix
    5615      257884 :         for (int M = N1; M <= N2; ++M) {
    5616      234440 :             D(1, M) = IndepVar(M);
    5617             :         }
    5618             : 
    5619      140664 :         for (int i = 2; i <= N; ++i) {
    5620     1289420 :             for (int M = N1; M <= N2; ++M) {
    5621     1172200 :                 D(i, M) = D(i - 1, M) * IndepVar(M);
    5622             :             }
    5623             :         }
    5624             : 
    5625      164108 :         for (int i = 1; i <= N; ++i) {
    5626      140664 :             SUM = 0.0;
    5627     1547304 :             for (int M = N1; M <= N2; ++M) {
    5628     1406640 :                 SUM += DepVar(M) * D(i, M);
    5629             :             }
    5630      140664 :             B(i) = SUM;
    5631      984648 :             for (int j = 1; j <= N; ++j) {
    5632      843984 :                 SUM = 0.0;
    5633     9283824 :                 for (int M = N1; M <= N2; ++M) {
    5634     8439840 :                     SUM += D(i, M) * D(j, M);
    5635             :                 }
    5636      843984 :                 A(j, i) = SUM;
    5637      843984 :                 A(i, j) = SUM;
    5638             :             }
    5639             :         }
    5640             : 
    5641             :         // Solve the simultaneous equations using Gauss elimination
    5642       23444 :         NM1 = N - 1;
    5643      140664 :         for (int K = 1; K <= NM1; ++K) {
    5644      117220 :             KP1 = K + 1;
    5645      468880 :             for (int i = KP1; i <= N; ++i) {
    5646      351660 :                 ACON = A(K, i) / A(K, K);
    5647      351660 :                 B(i) -= B(K) * ACON;
    5648     1992740 :                 for (int j = K; j <= N; ++j) {
    5649     1641080 :                     A(j, i) -= A(j, K) * ACON;
    5650             :                 }
    5651             :             }
    5652             :         }
    5653             : 
    5654             :         // Perform back substituion
    5655       23444 :         CoeffsCurve(N) = B(N) / A(N, N);
    5656       23444 :         LP1 = N;
    5657       23444 :         int L = N - 1;
    5658             : 
    5659      140664 :         while (L > 0) {
    5660      117220 :             SUM = 0.0;
    5661      468880 :             for (int j = LP1; j <= N; ++j) {
    5662      351660 :                 SUM += A(j, L) * CoeffsCurve(j);
    5663             :             }
    5664      117220 :             CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
    5665      117220 :             LP1 = L;
    5666      117220 :             --L;
    5667             :         }
    5668       23444 :     } // W5LsqFit()
    5669             : 
    5670             :     //********************************************************************************
    5671             : 
    5672           0 :     void W5LsqFit2(Array1A<Real64> const IndepVar, // Independent variables
    5673             :                    Array1A<Real64> const DepVar,   // Dependent variables
    5674             :                    int const N,                    // Order of polynomial
    5675             :                    int const N1,                   // First and last data points used
    5676             :                    int const N2,
    5677             :                    Array1A<Real64> CoeffsCurve // Polynomial coefficients from fit
    5678             :     )
    5679             :     {
    5680             : 
    5681             :         // SUBROUTINE INFORMATION:
    5682             :         //       AUTHOR         George Walton
    5683             :         //       DATE WRITTEN   April 1976
    5684             :         //       MODIFIED       November 1999 F.Winkelmann
    5685             :         //                      May 2001 F. Winkelmann, to do 19 indep. variables
    5686             :         //       RE-ENGINEERED  na
    5687             : 
    5688             :         // PURPOSE OF THIS SUBROUTINE:
    5689             :         // Does least squares fit for coefficients of a polynomial
    5690             :         // that gives a window property, such as transmittance, as a function of
    5691             :         // the cosine of the angle of incidence. The polynomial is of the
    5692             :         // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
    5693             :         // Adapted from BLAST subroutine LSQFIT.
    5694             : 
    5695             :         // Argument array dimensioning
    5696           0 :         IndepVar.dim(19);
    5697           0 :         DepVar.dim(19);
    5698           0 :         CoeffsCurve.dim(6);
    5699             : 
    5700           0 :         Array2D<Real64> A(6, 6);  // Least squares derivative matrix
    5701           0 :         Array1D<Real64> B(6);     // Least squares derivative vector
    5702           0 :         Array2D<Real64> D(6, 16); // Powers of independent variable
    5703             :         Real64 ACON;              // Intermediate variables
    5704             :         Real64 SUM;
    5705             :         int KP1;
    5706             :         int LP1;
    5707             :         int NM1;
    5708             : 
    5709             :         // Set up least squares matrix
    5710           0 :         for (int M = N1; M <= N2; ++M) {
    5711           0 :             D(1, M) = IndepVar(M);
    5712             :         }
    5713             : 
    5714           0 :         for (int i = 2; i <= N; ++i) {
    5715           0 :             for (int M = N1; M <= N2; ++M) {
    5716           0 :                 D(i, M) = D(i - 1, M) * IndepVar(M);
    5717             :             }
    5718             :         }
    5719             : 
    5720           0 :         for (int i = 1; i <= N; ++i) {
    5721           0 :             SUM = 0.0;
    5722           0 :             for (int M = N1; M <= N2; ++M) {
    5723           0 :                 SUM += DepVar(M) * D(i, M);
    5724             :             }
    5725           0 :             B(i) = SUM;
    5726           0 :             for (int j = 1; j <= N; ++j) {
    5727           0 :                 SUM = 0.0;
    5728           0 :                 for (int M = N1; M <= N2; ++M) {
    5729           0 :                     SUM += D(i, M) * D(j, M);
    5730             :                 }
    5731           0 :                 A(j, i) = SUM;
    5732           0 :                 A(i, j) = SUM;
    5733             :             }
    5734             :         }
    5735             : 
    5736             :         // Solve the simultaneous equations using Gauss elimination
    5737           0 :         NM1 = N - 1;
    5738           0 :         for (int K = 1; K <= NM1; ++K) {
    5739           0 :             KP1 = K + 1;
    5740           0 :             for (int i = KP1; i <= N; ++i) {
    5741           0 :                 ACON = A(K, i) / A(K, K);
    5742           0 :                 B(i) -= B(K) * ACON;
    5743           0 :                 for (int j = K; j <= N; ++j) {
    5744           0 :                     A(j, i) -= A(j, K) * ACON;
    5745             :                 }
    5746             :             }
    5747             :         }
    5748             : 
    5749             :         // Perform back substituion
    5750           0 :         CoeffsCurve(N) = B(N) / A(N, N);
    5751           0 :         LP1 = N;
    5752           0 :         int L = N - 1;
    5753             : 
    5754           0 :         while (L > 0) {
    5755           0 :             SUM = 0.0;
    5756           0 :             for (int j = LP1; j <= N; ++j) {
    5757           0 :                 SUM += A(j, L) * CoeffsCurve(j);
    5758             :             }
    5759           0 :             CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
    5760           0 :             LP1 = L;
    5761           0 :             --L;
    5762             :         }
    5763           0 :     } // W5LsqFit2()
    5764             : 
    5765             :     //***********************************************************************
    5766             : 
    5767       24930 :     Real64 DiffuseAverage(Array1S<Real64> const PropertyValue) // Property value at angles of incidence
    5768             :     {
    5769             : 
    5770             :         // FUNCTION INFORMATION:
    5771             :         //       AUTHOR         Fred Winkelmann
    5772             :         //       DATE WRITTEN   November 1999
    5773             :         //       MODIFIED       na
    5774             :         //       RE-ENGINEERED  na
    5775             : 
    5776             :         // PURPOSE OF THIS FUNCTION:
    5777             :         // Calculate value of property, such as transmittance, for hemispherical
    5778             :         // diffuse radiation from property values at angles of incidence from
    5779             :         // 0 to 90 degrees in 10 degree increments.
    5780             : 
    5781             :         // METHODOLOGY EMPLOYED:
    5782             :         // By Simpson's rule, evaluates the integral from 0 to 90 deg of
    5783             :         // 2*PropertyValue(phi)*cos(phi)*sin(phi)*dphi (which is same as
    5784             :         // PropertyValue(phi)*sin(2*phi)*dphi)
    5785             : 
    5786             :         // Return value
    5787             :         Real64 DiffuseAverage;
    5788             : 
    5789             :         // Locals
    5790             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    5791             :         // 0,10,20,...,80,90 degress
    5792             : 
    5793       24930 :         Real64 const DPhiR(10.0 * Constant::DegToRadians); // Half of 10-deg incidence angle increment (radians)
    5794             : 
    5795       24930 :         DiffuseAverage = 0.0;
    5796      249300 :         for (int IPhi = 1; IPhi <= 9; ++IPhi) {
    5797      224370 :             DiffuseAverage +=
    5798      224370 :                 0.5 * DPhiR * (PropertyValue(IPhi) * std::sin(2.0 * (IPhi - 1) * DPhiR) + PropertyValue(IPhi + 1) * std::sin(2.0 * IPhi * DPhiR));
    5799             :         }
    5800       24930 :         if (DiffuseAverage < 0.0) DiffuseAverage = 0.0;
    5801             : 
    5802       24930 :         return DiffuseAverage;
    5803             :     } // DiffuseAverage()
    5804             : 
    5805             :     //*************************************************************************************
    5806             : 
    5807        2244 :     Real64 DiffuseAverageProfAngGnd(Array1S<Real64> const Property) // Property value vs. profile angle
    5808             :     {
    5809             : 
    5810             :         // FUNCTION INFORMATION:
    5811             :         //       AUTHOR         Fred Winkelmann
    5812             :         //       DATE WRITTEN   January 2004
    5813             :         //       MODIFIED       na
    5814             :         //       RE-ENGINEERED  na
    5815             : 
    5816             :         // PURPOSE OF THIS FUNCTION:
    5817             :         // Calculates diffuse average of Property, such as blind transmittance, over profile angles
    5818             :         // corresponding to (upgoing) radiation from the ground.
    5819             : 
    5820             :         // METHODOLOGY EMPLOYED:
    5821             :         // Integration by Simpson's rule assuming uniform radiance distribution.
    5822             : 
    5823             :         // Return value
    5824             :         Real64 DiffuseAverageProfAngGnd;
    5825             : 
    5826             :         Real64 Phi;  // Profile angle (radians)
    5827             :         Real64 DPhi; // Phi increment
    5828             :         Real64 Sum;  // Sums
    5829             :         Real64 SumDenom;
    5830             : 
    5831        2244 :         Sum = 0.0;
    5832        2244 :         SumDenom = 0.0;
    5833        2244 :         DPhi = 5.0 * Constant::DegToRadians;
    5834             : 
    5835             :         // Integrate from -90 to 0 deg
    5836       42636 :         for (int IPhi = 1; IPhi <= (Material::MaxProfAngs / 2); ++IPhi) {
    5837       40392 :             Phi = -Constant::PiOvr2 + (IPhi - 0.5) * DPhi;
    5838       40392 :             Sum += std::cos(Phi) * DPhi * InterpProfAng(Phi, Property);
    5839       40392 :             SumDenom += std::cos(Phi) * DPhi;
    5840             :         }
    5841             : 
    5842        2244 :         DiffuseAverageProfAngGnd = Sum / SumDenom;
    5843        2244 :         if (DiffuseAverageProfAngGnd < 0.0) DiffuseAverageProfAngGnd = 0.0;
    5844             : 
    5845        2244 :         return DiffuseAverageProfAngGnd;
    5846             :     } // DiffuseAverageProfAngGnd()
    5847             : 
    5848             :     //*************************************************************************************
    5849             : 
    5850        2244 :     Real64 DiffuseAverageProfAngSky(Array1S<Real64> const Property) // Property value vs. profile angle
    5851             :     {
    5852             : 
    5853             :         // FUNCTION INFORMATION:
    5854             :         //       AUTHOR         Fred Winkelmann
    5855             :         //       DATE WRITTEN   January 2004
    5856             :         //       MODIFIED       na
    5857             :         //       RE-ENGINEERED  na
    5858             : 
    5859             :         // PURPOSE OF THIS FUNCTION:
    5860             :         // Calculates diffuse average of Property, such as blind transmittance, over profile angles
    5861             :         // corresponding to (downgoing) radiation from the sky.
    5862             : 
    5863             :         // METHODOLOGY EMPLOYED:
    5864             :         // Integration by Simpson's rule assuming uniform radiance distribution.
    5865             : 
    5866             :         // Return value
    5867             :         Real64 DiffuseAverageProfAngSky;
    5868             : 
    5869             :         Real64 Phi;  // Profile angle (radians)
    5870             :         Real64 DPhi; // Phi increment
    5871             :         Real64 Sum;  // Sums
    5872             :         Real64 SumDenom;
    5873             : 
    5874        2244 :         Sum = 0.0;
    5875        2244 :         SumDenom = 0.0;
    5876        2244 :         DPhi = 5.0 * Constant::DegToRadians;
    5877             : 
    5878             :         // Integrate from 0 to 90 deg
    5879       42636 :         for (int IPhi = (Material::MaxProfAngs / 2) + 1; IPhi <= Material::MaxProfAngs - 1; ++IPhi) {
    5880       40392 :             Phi = -Constant::PiOvr2 + (IPhi - 0.5) * DPhi;
    5881       40392 :             Sum += std::cos(Phi) * DPhi * InterpProfAng(Phi, Property);
    5882       40392 :             SumDenom += std::cos(Phi) * DPhi;
    5883             :         }
    5884             : 
    5885        2244 :         DiffuseAverageProfAngSky = Sum / SumDenom;
    5886        2244 :         if (DiffuseAverageProfAngSky < 0.0) DiffuseAverageProfAngSky = 0.0;
    5887             : 
    5888        2244 :         return DiffuseAverageProfAngSky;
    5889             :     } // DiffuseAverageProfAngSky()
    5890             : 
    5891             :     //*************************************************************************************
    5892             : 
    5893      656496 :     void CalcWinFrameAndDividerTemps(EnergyPlusData &state,
    5894             :                                      int const SurfNum,     // Surface number
    5895             :                                      Real64 const tout,     // Outside air temperature (K)
    5896             :                                      Real64 const tin,      // Inside air temperature (K)
    5897             :                                      Real64 const HOutConv, // Outside convective air film conductance (W/m2-K)
    5898             :                                      Real64 const HInConv,  // Inside convective air film conductance (W/m2-K)
    5899             :                                      Real64 const Outir,    // Exterior IR irradiance from sky and ground
    5900             :                                      int const ConstrNum    // Construction number of window
    5901             :     )
    5902             :     {
    5903             : 
    5904             :         // SUBROUTINE INFORMATION:
    5905             :         //       AUTHOR         F. Winkelmann
    5906             :         //       DATE WRITTEN   May 2000
    5907             :         //       MODIFIED       Aug 2000, FCW: Add effect of frame and divider projections
    5908             :         //                      Jun 2001, FCW: Add frame/divider contribution to WinHeatGain
    5909             :         //                      Aug 2003, FCW: Fix calculation of divider outside temp: frame
    5910             :         //                       inside temp was being used instead of divider inside temp
    5911             :         //       RE-ENGINEERED  na
    5912             : 
    5913             :         // PURPOSE OF THIS SUBROUTINE:
    5914             :         // Calculates window frame divider face temperatures from a linearized
    5915             :         // heat balance on the inside and outside faces
    5916             : 
    5917             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5918             :         Real64 HInRad;            // Inside radiative conductance (W/m2-K)
    5919             :         Real64 HOutRad;           // Outside radiative conductance (W/m2-K)
    5920             :         int FrDivNum;             // Frame/divider number
    5921             :         Real64 TInRad;            // Inside radiative temperature (K)
    5922             :         Real64 TInRadFr;          // Effective inside radiative temperature for frame (K)
    5923             :         Real64 TInRadDiv;         // Effective inside radiative temperature for divider (K)
    5924             :         Real64 TOutRad;           // Outside radiative temperature (K)
    5925             :         Real64 TOutRadFr;         // Effective outside radiative temperature for frame (K)
    5926             :         Real64 TOutRadDiv;        // Effective outside radiative temperature for divider (K)
    5927             :         WinShadingType ShadeFlag; // Window shading flag
    5928             :         Real64 FrameCon;          // Frame conductance (W/m2-K)
    5929             : 
    5930             :         Real64 Afac; // Intermediate calculation variables
    5931             :         Real64 Bfac;
    5932             :         Real64 Dfac;
    5933             :         Real64 Efac;
    5934             :         DataSurfaces::FrameDividerType DivType; // Divider type
    5935             :         Real64 DivCon;                          // Divider conductance (W/m2-K)
    5936             :         Real64 DivEmisIn;                       // Inside divider emissivity
    5937             :         Real64 DivEmisOut;                      // Outside divider emissivity
    5938             : 
    5939             :         Real64 ProjCorrFrOut; // Outside correction factor for absorbed radiation
    5940             :         //   for frame with outside projection
    5941             :         Real64 ProjCorrFrIn; // Inside correction factor for absorbed radiation
    5942             :         //   for frame with inside projection
    5943             :         Real64 HOutConvFr; // Effective outside convective coeff for frame
    5944             :         //   with outside projection (W/m2-K)
    5945             :         Real64 HOutConvDiv; // Effective outside convective coeff for divider
    5946             :         //   with outside projection (W/m2-K)
    5947             :         Real64 HInConvFr; // Effective inside convective coeff for frame
    5948             :         //   with inside projection (W/m2-K)
    5949             :         Real64 HInConvDiv; // Effective inside convective coeff for divider
    5950             :         //   with inside projection (W/m2-K)
    5951             :         Real64 EmisGlassOut; // Outside surface emissivity of window glazing
    5952             :         Real64 EmisGlassIn;  // Inside surface emissivity of window glazing
    5953             :         int TotGlassLayers;  // Total number of glass layers
    5954             :         int TotLayers;       // Total number of layers in unshaded construction
    5955             :         // Real64 DivTempOut;          // Outside surface divider temperature (K)
    5956             :         Real64 FrameHeatGain; // Heat gain to zone from frame (W)
    5957             :         // Real64 FrameHeatTransfer;   // Heat tansfer through frame (W)
    5958             :         // Real64 ProjCorrWinHeatGain; // Inside projection correction to IR from divider to zone
    5959             :         //   for window heat gain calculation
    5960             :         Real64 DividerHeatGain; // Heat gain to zone from divider (W)
    5961             :         // Real64 DividerHeatTransfer; // Heat transfer through divider (W)
    5962             : 
    5963      656496 :         auto const &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
    5964             : 
    5965      656496 :         TInRad = root_4(state.dataSurface->SurfWinIRfromParentZone(SurfNum) / Constant::StefanBoltzmann);
    5966      656496 :         TOutRad = root_4(Outir / Constant::StefanBoltzmann);
    5967      656496 :         ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    5968      656496 :         FrDivNum = state.dataSurface->Surface(SurfNum).FrameDivider;
    5969      656496 :         auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
    5970      656496 :         TotLayers = thisConstruct.TotLayers;
    5971      656496 :         TotGlassLayers = thisConstruct.TotSolidLayers;
    5972      656496 :         EmisGlassOut = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(thisConstruct.LayerPoint(1)))->AbsorpThermalFront;
    5973      656496 :         EmisGlassIn =
    5974      656496 :             dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(thisConstruct.LayerPoint(TotLayers)))->AbsorpThermalBack;
    5975      656496 :         FrameHeatGain = 0.0;
    5976      656496 :         DividerHeatGain = 0.0;
    5977      656496 :         state.dataSurface->SurfWinFrameHeatGain(SurfNum) = 0.0;
    5978      656496 :         state.dataSurface->SurfWinFrameHeatLoss(SurfNum) = 0.0;
    5979      656496 :         state.dataSurface->SurfWinDividerHeatGain(SurfNum) = 0.0;
    5980      656496 :         state.dataSurface->SurfWinDividerHeatLoss(SurfNum) = 0.0;
    5981             : 
    5982      656496 :         if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
    5983             :             // Window has a frame. Note that if a shade, screen or blind is present it covers only the glazed part of the
    5984             :             // window and is assumed not to shadow long- or short-wave radiation incident on the frame elements.
    5985      656496 :             ProjCorrFrOut = state.dataSurface->SurfWinProjCorrFrOut(SurfNum);
    5986      656496 :             ProjCorrFrIn = state.dataSurface->SurfWinProjCorrFrIn(SurfNum);
    5987      656496 :             TOutRadFr = TOutRad * root_4((1.0 + 0.5 * ProjCorrFrOut) / (1.0 + ProjCorrFrOut));
    5988      656496 :             TInRadFr = TInRad * root_4((1.0 + 0.5 * ProjCorrFrIn) / (1.0 + ProjCorrFrIn));
    5989      656496 :             FrameCon = state.dataSurface->SurfWinFrameConductance(SurfNum);
    5990      656496 :             HInRad = 0.5 * state.dataSurface->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
    5991      656496 :                      pow_3(TInRadFr + state.dataSurface->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin);
    5992      656496 :             HInConvFr = HInConv;
    5993      656496 :             HOutRad = 0.5 * state.dataSurface->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
    5994      656496 :                       pow_3(TOutRadFr + state.dataSurface->SurfWinFrameTempSurfOut(SurfNum) + Constant::Kelvin);
    5995      656496 :             HOutConvFr = HOutConv;
    5996      656496 :             auto const &frdiv = state.dataSurface->FrameDivider(FrDivNum);
    5997      656496 :             if (frdiv.FrameProjectionOut > 0.0) {
    5998      524016 :                 HOutRad *= (1.0 + ProjCorrFrOut);
    5999      524016 :                 HOutConvFr = HOutConv * (1.0 + ProjCorrFrOut);
    6000             :                 // Add long-wave from outside window surface absorbed by frame outside projection
    6001     1048032 :                 state.dataSurface->SurfWinFrameQRadOutAbs(SurfNum) += 0.5 * state.dataSurface->SurfWinProjCorrFrOut(SurfNum) * frdiv.FrameEmis *
    6002      524016 :                                                                       EmisGlassOut * Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
    6003             :             }
    6004      656496 :             if (frdiv.FrameProjectionIn > 0.0) {
    6005      524016 :                 HInRad *= (1.0 + ProjCorrFrIn);
    6006      524016 :                 HInConvFr = HInConv * (1.0 + ProjCorrFrIn);
    6007             :                 // Add long-wave from inside window surface absorbed by frame inside projection
    6008     1048032 :                 state.dataSurface->SurfWinFrameQRadInAbs(SurfNum) += 0.5 * state.dataSurface->SurfWinProjCorrFrIn(SurfNum) * frdiv.FrameEmis *
    6009      524016 :                                                                      EmisGlassIn * Constant::StefanBoltzmann *
    6010      524016 :                                                                      pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
    6011             :             }
    6012      656496 :             Afac = (HOutRad * TOutRadFr + HOutConvFr * tout + state.dataSurface->SurfWinFrameQRadOutAbs(SurfNum)) / (HOutRad + FrameCon + HOutConvFr);
    6013      656496 :             Bfac = FrameCon / (HOutRad + FrameCon + HOutConvFr);
    6014      656496 :             Dfac = (HInRad * TInRadFr + HInConvFr * tin + state.dataSurface->SurfWinFrameQRadInAbs(SurfNum)) / (HInRad + FrameCon + HInConvFr);
    6015      656496 :             Efac = FrameCon / (HInRad + FrameCon + HInConvFr);
    6016      656496 :             state.dataSurface->SurfWinFrameTempIn(SurfNum) = (Dfac + Efac * Afac) / (1.0 - Efac * Bfac) - Constant::Kelvin;
    6017      656496 :             state.dataSurface->SurfWinFrameTempSurfOut(SurfNum) =
    6018      656496 :                 Afac + Bfac * (state.dataSurface->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
    6019             :             // Heat gain to zone from frame
    6020             : 
    6021             :             // FrameHeatTransfer = state.dataSurface->SurfWinFrameArea(SurfNum) * FrameCon *
    6022             :             //                     (state.dataSurface->SurfWinFrameTempSurfOut(SurfNum) - state.dataSurface->SurfWinFrameTempIn(SurfNum));
    6023      656496 :             FrameHeatGain = state.dataSurface->SurfWinFrameArea(SurfNum) * (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)) *
    6024      656496 :                             (HInConvFr * (state.dataSurface->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin - tin));
    6025             : 
    6026      656496 :             if (FrameHeatGain > 0.0) {
    6027      124274 :                 state.dataSurface->SurfWinFrameHeatGain(SurfNum) = FrameHeatGain;
    6028             :             } else {
    6029      532222 :                 state.dataSurface->SurfWinFrameHeatLoss(SurfNum) = std::abs(FrameHeatGain);
    6030             :             }
    6031             : 
    6032      656496 :             state.dataSurface->SurfWinHeatGain(SurfNum) += FrameHeatGain;
    6033      656496 :             state.dataSurface->SurfWinGainFrameDividerToZoneRep(SurfNum) = FrameHeatGain;
    6034             :         } // End of check if window has a frame
    6035             : 
    6036      656496 :         if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 && state.dataSurface->SurfWinStormWinFlag(SurfNum) < 1) {
    6037             :             // Window has divider. Note that if the window has a storm window layer in place (StormWinFlag = 1)
    6038             :             // the divider heat transfer calculation is not done.
    6039             : 
    6040      327888 :             DivType = state.dataSurface->SurfWinDividerType(SurfNum);
    6041      327888 :             DivCon = state.dataSurface->SurfWinDividerConductance(SurfNum);
    6042             : 
    6043      327888 :             if (DivType == DataSurfaces::FrameDividerType::DividedLite) { // Divided lite
    6044      298416 :                 DivEmisIn = state.dataSurface->SurfWinDividerEmis(SurfNum);
    6045      298416 :                 DivEmisOut = DivEmisIn;
    6046             :             } else { // Suspended (between-glass) divider
    6047       29472 :                 DivEmisOut = state.dataMaterial->Material(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
    6048       29472 :                 DivEmisIn = state.dataMaterial->Material(thisConstruct.LayerPoint(thisConstruct.TotLayers))->AbsorpThermalBack;
    6049             :             }
    6050             : 
    6051      327888 :             TOutRadDiv = TOutRad * root_4((1.0 + state.dataSurface->SurfWinProjCorrDivOut(SurfNum)) /
    6052      327888 :                                           (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivOut(SurfNum)));
    6053      327888 :             TInRadDiv = TInRad * root_4((1.0 + state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) /
    6054      327888 :                                         (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)));
    6055      327888 :             HInRad =
    6056      327888 :                 0.5 * DivEmisIn * Constant::StefanBoltzmann * pow_3(TInRadDiv + state.dataSurface->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin);
    6057      655776 :             HOutRad = 0.5 * DivEmisOut * Constant::StefanBoltzmann *
    6058      327888 :                       pow_3(TOutRadDiv + state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin);
    6059      327888 :             HOutConvDiv = HOutConv;
    6060      327888 :             auto const &frdiv = state.dataSurface->FrameDivider(FrDivNum);
    6061      327888 :             if (frdiv.DividerProjectionOut > 0.0) {
    6062      225072 :                 HOutRad *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivOut(SurfNum));
    6063      225072 :                 if (state.dataSurface->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade)
    6064           0 :                     HOutConvDiv = state.dataSurface->SurfWinConvCoeffWithShade(SurfNum);
    6065      225072 :                 HOutConvDiv *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivOut(SurfNum));
    6066             :                 // Add long-wave from outside window surface absorbed by divider outside projection
    6067      450144 :                 state.dataSurface->SurfWinDividerQRadOutAbs(SurfNum) += state.dataSurface->SurfWinProjCorrDivOut(SurfNum) * frdiv.DividerEmis *
    6068      225072 :                                                                         EmisGlassOut * Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
    6069             :             }
    6070             : 
    6071      327888 :             HInConvDiv = HInConv;
    6072             : 
    6073      327888 :             if (frdiv.DividerProjectionIn > 0.0) {
    6074      225072 :                 HInRad *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum));
    6075      225072 :                 if (state.dataSurface->SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade)
    6076           0 :                     HInConvDiv = state.dataSurface->SurfWinConvCoeffWithShade(SurfNum);
    6077      225072 :                 HInConvDiv *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum));
    6078             :                 // Add long-wave from inside window surface absorbed by divider inside projection
    6079      450144 :                 state.dataSurface->SurfWinDividerQRadInAbs(SurfNum) += state.dataSurface->SurfWinProjCorrDivIn(SurfNum) * frdiv.DividerEmis *
    6080      225072 :                                                                        EmisGlassIn * Constant::StefanBoltzmann *
    6081      225072 :                                                                        pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
    6082             :             }
    6083      327888 :             Afac =
    6084      327888 :                 (HOutRad * TOutRadDiv + HOutConvDiv * tout + state.dataSurface->SurfWinDividerQRadOutAbs(SurfNum)) / (HOutRad + DivCon + HOutConvDiv);
    6085      327888 :             Bfac = DivCon / (HOutRad + DivCon + HOutConvDiv);
    6086      327888 :             Dfac = (HInRad * TInRadDiv + HInConvDiv * tin + state.dataSurface->SurfWinDividerQRadInAbs(SurfNum)) / (HInRad + DivCon + HInConvDiv);
    6087      327888 :             Efac = DivCon / (HInRad + DivCon + HInConvDiv);
    6088      327888 :             state.dataSurface->SurfWinDividerTempIn(SurfNum) = (Dfac + Efac * Afac) / (1 - Efac * Bfac) - Constant::Kelvin;
    6089      327888 :             state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) =
    6090      327888 :                 Afac + Bfac * (state.dataSurface->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
    6091             :             // Contribution of divider to window heat gain
    6092             :             // ProjCorrWinHeatGain = 1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum);
    6093             : 
    6094      327888 :             DividerHeatGain = state.dataSurface->SurfWinDividerArea(SurfNum) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) *
    6095      327888 :                               (HInConvDiv * (state.dataSurface->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin - tin));
    6096             :             // DividerHeatTransfer = state.dataSurface->SurfWinDividerArea(SurfNum) * DivCon *
    6097             :             //                      (state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) - state.dataSurface->SurfWinDividerTempIn(SurfNum));
    6098             : 
    6099      327888 :             if (DividerHeatGain > 0.0) {
    6100       57657 :                 state.dataSurface->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
    6101             :             } else {
    6102      270231 :                 state.dataSurface->SurfWinDividerHeatLoss(SurfNum) = std::abs(DividerHeatGain);
    6103             :             }
    6104      327888 :             state.dataSurface->SurfWinHeatGain(SurfNum) += DividerHeatGain;
    6105      327888 :             state.dataSurface->SurfWinGainFrameDividerToZoneRep(SurfNum) += DividerHeatGain;
    6106             :             // If interior shade is present it is assumed that both the convective and IR radiative gain
    6107             :             // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
    6108             :             // interaction between divider and shade is ignored due to the difficulty of calculating this interaction
    6109             :             // at the same time that the interaction between glass and shade is calculated.
    6110      327888 :             if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum)))
    6111         742 :                 state.dataSurface->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
    6112             :             // DivTempOut = state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin;
    6113             :         } // End of check if window has dividers
    6114      656496 :     }     // CalcWinFrameAndDividerTemps()
    6115             : 
    6116             :     //************************************************************************************
    6117             : 
    6118        2676 :     void CalcNominalWindowCond(EnergyPlusData &state,
    6119             :                                int const ConstrNum,        // Construction number
    6120             :                                int const WinterSummerFlag, // 1=winter, 2=summer
    6121             :                                Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
    6122             :                                Real64 &SHGC,               // Nominal center-of-glass solar heat gain coefficient for
    6123             :                                Real64 &TSolNorm,           // Overall beam solar transmittance at normal incidence
    6124             :                                Real64 &TVisNorm,           // Overall beam visible transmittance at normal incidence
    6125             :                                int &errFlag                // Error flag
    6126             :     )
    6127             :     {
    6128             : 
    6129             :         // SUBROUTINE INFORMATION:
    6130             :         //       AUTHOR         F. Winkelmann
    6131             :         //       DATE WRITTEN   September 2000
    6132             :         //       MODIFIED       Oct 2000, FW: add solar heat gain coefficient
    6133             :         //                      June 2001, FW: account for blinds; change summer outside air
    6134             :         //                       temp from 35.0C to 31.7C to correspond to ASHRAE value
    6135             :         //                      Feb 2003, FW: add comments that this routine is not called for
    6136             :         //                       between-glass shade/blind constructions.
    6137             :         //                      May 2006, RR: account for screens
    6138             :         //                      Oct 2007, LKL: change temps to match Window 5 values
    6139             :         //                      Feb 2009, BG: Changes for CR7682 (SHGC)
    6140             :         //       RE-ENGINEERED  na
    6141             : 
    6142             :         // PURPOSE OF THIS SUBROUTINE:
    6143             :         // Calculates nominal center-of-glass U-value and solar heat gain coefficient
    6144             :         // (SHGC) of a window construction for ASHRAE winter and summer conditions.
    6145             :         // Winter:
    6146             :         // Inside air temperature = 21.C (69.80F)
    6147             :         // Outside air temperature = -18C (-.4F)
    6148             :         // Windspeed = 5.5 m/s (12.3 mph)
    6149             :         // No solar radiation
    6150             :         // Replaced Winter:
    6151             :         // Inside air temperature = 21.1C (70F)
    6152             :         // Outside air temperature = -17.8C (0F)
    6153             :         // Windspeed = 6.71 m/s (15 mph)
    6154             :         // No solar radiation
    6155             :         // Summer:
    6156             :         // Inside air temperature = 24C (75.2F)
    6157             :         // Outside air temperature = 32C (89.6F)
    6158             :         // Windspeed = 2.8 m/s (6.2 mph)
    6159             :         // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
    6160             :         // Replaced Summer:
    6161             :         // Inside air temperature = 24C (75.2F) ! BG changed again Feb. 2009 by 0.1 (per Window5 team)
    6162             :         // Outside air temperature = 31.7C (89F)
    6163             :         // Windspeed = 3.35 m/s (7.5 mph)
    6164             :         // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
    6165             :         // The window's inside surround is assumed to be a black body at the inside air temp.
    6166             :         // The window's outside surround is assumed t be a black body at the outside air temp.
    6167             :         // Note that in this routine we use a value of 26 W/m2 for the outside convective
    6168             :         // air film conductance for 5.5 m/s (12.3 mph) wind speed.
    6169             :         // This is the value used in Window 5 and is also the value for which the center-of-glass
    6170             :         // conductances in the EnergyPlus window construction reference data set were calculated.
    6171             :         // However, in the time step loop we will have different values of outside film
    6172             :         // conductance depending on that time step's wind speed, wind direction, surface-to-air temp difference,
    6173             :         // etc.(see subroutine InitExteriorConvectionCoeff).
    6174             :         // This routine will return an error and exit for window constructions with between-glass shade or blind
    6175             :         // until a method is worked out to determine the nominal conductance and SHGC in this case.
    6176             :         // If an interior or exterior shade or blind is present in the construction,
    6177             :         // the conductance calculation does not include the effect of the shade or blind.
    6178             :         // This is because in this case the conductance depends on the natural convective
    6179             :         // air flow in the shade/glass, screen/glass or blind/glass channel, which in turn is highly dependent
    6180             :         // on window height and other parameters that are not part of the construction definition.
    6181             :         // Therefore, the reported conductance value will be too high for windows with a tightly fitting
    6182             :         // shade, screen or blind with a relatively high thermal resistance.
    6183             :         // For SHGC calculation, all solar absorbed by interior blind or shade is assumed
    6184             :         // to go into zone air. (This is not true in general; the fraction of this absorbed solar that
    6185             :         // is conducted back out is accounted for in the time-step glazing calculation.)
    6186             :         // For CR 7682, the SHGC calculations were changed to model the absorbed solar arriving at the middle of the layer
    6187             :         // rather than at the outer face of the layer.  The resistances changed by one half the glazing layer, or 0.5/scon(n).
    6188             :         // (CR 7682 also changed WindowTempsForNominalCond to include absorbed solar, a bigger change)
    6189             : 
    6190             :         // Using/Aliasing
    6191             :         using General::POLYF;
    6192             : 
    6193             :         // Locals
    6194             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    6195             :         //   normal incidence beam solar radiation
    6196             : 
    6197             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6198             :         int TotLay; // Total number of layers in a construction
    6199             :         //   (sum of solid layers and gap layers)
    6200             :         int TotGlassLay; // Total number of glass layers in a construction
    6201             :         int Lay;         // Layer number
    6202             :         int LayPtr;      // Material number for a layer
    6203             : 
    6204             :         Real64 BeamSolarInc; // Incident beam radiation at zero angle of incidence (W/m2)
    6205             :                              //        Real64 hOutRad;      // Radiative conductance of outside and inside airfilm [W/m2-K]
    6206             :                              //        Real64 hInRad;
    6207             :                              //        Real64 rOut; // Combined radiative and conductive outside and inside film
    6208             :                              //        Real64 rIn;
    6209             :         //   resistance [m2-K/W]
    6210             :         Array1D<Real64> hgap(
    6211        2676 :             maxGlassLayers);      // Conductive gap conductance [W/m2-K]
    6212             :                                   //        Array1D<Real64> hGapTot(5);     // Combined radiative and conductive gap conductance [W/m2-K]
    6213             :                                   //        Real64 Rbare;                   // Nominal center-of-glass resistance without air films [m2-K/W]
    6214             :         WinShadingType ShadeFlag; // Shading flag
    6215             :         Real64 ShadeRes;          // Thermal resistance of shade
    6216             :         int MatOutside;           // Material number of outside layer of construction
    6217             :         int MatInside;            // Material number of inside layer of construction
    6218             :         int MatShade;             // Material number of shade layer
    6219        2676 :         Array1D<Real64> AbsBeamNorm(maxGlassLayers); // Beam absorptance at normal incidence for each glass layer
    6220             :         Real64 AbsBeamShadeNorm;                     // Shade solar absorptance at normal incidence
    6221             :         int ConstrNum1;                              // Construction counter
    6222             :         int ConstrNumBare;                           // Construction without shading device
    6223             :         int BlNum;                                   // Blind number
    6224             :         int ScNum;                                   // Screen number
    6225             :         bool VarSlats;                               // True if slats in blind are variable angle
    6226             :         Real64 SlatAng;                              // Slat angle (rad)
    6227             :         int LayPtrSh;                                // Layer pointer of blind
    6228             :         Real64 TBmBm;                                // Bare glass normal incidence beam-beam transmittance
    6229             :         Real64 TBmBmVis;
    6230             :         Real64 TBlBmBm; // Normal incidence blind beam-beam transmittance
    6231             :         Real64 TScBmBm; // Screen incident beam-beam transmittance
    6232             :         Real64 TScBmBmVis;
    6233             :         Real64 TBmBmBl; // TBmBm * TBlBmBm, TBmBmVis * TBlBmBm
    6234             :         Real64 TBmBmBlVis;
    6235             :         Real64 RGlDiffBack; // Bare glass back sol/vis reflectance
    6236             :         Real64 RGlDiffBackVis;
    6237             :         Real64 RGlDiffFront; // Bare glass front sol/vis reflectance
    6238             :         Real64 RGlDiffFrontVis;
    6239             :         Real64 RhoBlFront; // Blind normal front beam-diffuse sol/vis reflectance
    6240             :         Real64 RhoBlFrontVis;
    6241             :         Real64 RhoBlBack; // Blind normal back beam-diffuse sol/vis reflectance
    6242             :         Real64 RhoBlBackVis;
    6243             :         Real64 RScBack; // Screen back beam-diffuse sol/vis reflectance (same as front)
    6244             :         Real64 RScBackVis;
    6245             :         Real64 AbsBlFront;     // Blind normal front beam solar absorptance
    6246             :         Real64 AbsBlBack;      // Blind normal back beam solar absorptance
    6247             :         Real64 RhoBlDiffFront; // Blind front diffuse-diffuse sol/vis reflectance
    6248             :         Real64 RhoBlDiffFrontVis;
    6249             :         Real64 AbsBlDiffFront; // Blind front diffuse solar absorptance
    6250             :         Real64 AbsBlDiffBack;  // Blind back diffuse solar absorptance
    6251             :         Real64 RGlFront;       // Bare glass normal front beam sol/vis reflectance
    6252             :         Real64 RGlFrontVis;
    6253             :         Real64 RhoBlDiffBack; // Blind back diffuse-diffuse sol/vis reflectance
    6254             :         Real64 RhoBlDiffBackVis;
    6255             :         Real64 RScDifBack; // Screen back diffuse-diffuse sol/vis reflectance (doesn't change with sun angle)
    6256             :         Real64 RScDifBackVis;
    6257             :         Real64 TBlBmDif; // Blind front normal beam-diffuse sol/vis transmittance
    6258             :         Real64 TBlBmDifVis;
    6259             :         Real64 TBlDifDif; // Blind front diffuse-diffuse sol/vis transmittance
    6260             :         Real64 TBlDifDifVis;
    6261             :         Real64 TScBmDif; // Screen front beam-diffuse sol/vis transmittance
    6262             :         Real64 TScBmDifVis;
    6263             :         Real64 TDif; // Bare glass diffuse sol/vis transmittance
    6264             :         Real64 TDifVis;
    6265             :         Real64 AGlDiffBack; // Back diffuse solar absorptance of a glass layer
    6266             : 
    6267        2676 :         auto &wm = state.dataWindowManager;
    6268             :         // Autodesk:Uninit Initialize variables used uninitialized
    6269             :         //        Rbare = 0.0; // Autodesk:Uninit Force default initialization
    6270             : 
    6271        2676 :         NominalConductance = 0.0;
    6272        2676 :         errFlag = 0;
    6273        2676 :         TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
    6274        2676 :         TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    6275        2676 :         wm->ngllayer = TotGlassLay; // Autodesk:Uninit This routine needs to check/enforce 1<=ngllayer<=4
    6276             :         // EPTeam - believe that is done on input.
    6277        2676 :         wm->nglface = 2 * wm->ngllayer;
    6278        2676 :         wm->tilt = 90.0; // Assume vertical window
    6279             : 
    6280        2676 :         if (WinterSummerFlag == 1) { // Winter
    6281             :             // LKL Oct 2007:  According to Window5, Winter environmental conditions are:
    6282        1350 :             wm->tin = 294.15;  // Inside air temperature (69.8F, 21.C)
    6283        1350 :             wm->tout = 255.15; // Outside air temperature (-.4F, -18C)
    6284        1350 :             wm->hcout = 26.0;  // Outside convective film conductance for 5.5 m/s (12.3 mph) wind speed
    6285             :             // (the value used in Window 5)
    6286             :             //  tin = 294.26   ! Inside air temperature (70F, 21.1C)
    6287             :             //  tout = 255.35  ! Outside air temperature (0F, -17.8C)
    6288             :             //  hcout = 25.47  ! Outside convective film conductance for 6.71 m/s (15 mph) wind speed
    6289             :             //                 ! (the value used in Window 4)
    6290        1350 :             BeamSolarInc = 0.0;
    6291             :         } else { // Summer
    6292             :             // LKL Oct 2007: According to Window5, Summer environmental conditions are:
    6293             :             // tin = 297.05d0   ! Inside air temperature (75.2F, 24C)
    6294             :             // BG Feb. 2009: According to Window5 Expert Christian Kohler, it is exactly 24C or 297.15
    6295        1326 :             wm->tin = 297.15;
    6296        1326 :             wm->tout = 305.15; // Outside air temperature (89.6F, 32C)
    6297        1326 :             wm->hcout = 15.0;  // Outside convective film conductance for 2.8 m/s (6.2 mph) wind speed
    6298             :             // (the value used in Window 5)
    6299             :             //  tin = 297.05   ! Inside air temperature (75F, 23.9C)
    6300             :             //  !tout = 308.15  ! Outside air temperature (95F, 35.0C)
    6301             :             //  ! Changed 6/20/01 by FCW to make consistent with Window 4 and 5.
    6302             :             //  tout = 304.82  ! Outside air temperature (89F, 31.7C)
    6303             :             //  hcout = 18.86  ! Outside convective film conductance for 3.35 m/s (7.5 mph) wind speed
    6304             :             //                 ! (average of Window 4 0 m/s and 6.71 m/s values)
    6305        1326 :             BeamSolarInc = 783.0;
    6306             :         }
    6307             : 
    6308             :         // IR incident on inside of glazing (inside surround assumed to be
    6309             :         // a black body at inside air temperature)
    6310        2676 :         wm->Rmir = Constant::StefanBoltzmann * pow_4(wm->tin);
    6311             : 
    6312             :         // IR incident on outside of glazing
    6313             :         // (outside surround is assumed to be a black body at outside air temperature)
    6314        2676 :         wm->Outir = Constant::StefanBoltzmann * pow_4(wm->tout);
    6315             : 
    6316             :         // Determine whether construction has an exterior or interior shade or blind
    6317        2676 :         ShadeFlag = WinShadingType::NoShade;
    6318        2676 :         ShadeRes = 0.0;
    6319        2676 :         MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
    6320        2676 :         MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
    6321        2676 :         if (state.dataMaterial->Material(MatOutside)->group == Material::Group::Shade) { // Exterior shade present
    6322           5 :             MatShade = MatOutside;
    6323           5 :             ShadeFlag = WinShadingType::ExtShade;
    6324             :             // Set glazing outside convection coefficient to Window 4 still-air value
    6325           5 :             wm->hcout = 12.25;
    6326        2671 :         } else if (state.dataMaterial->Material(MatOutside)->group == Material::Group::Screen) { // Exterior screen present
    6327           4 :             MatShade = MatOutside;
    6328           4 :             ShadeFlag = WinShadingType::ExtScreen;
    6329           4 :             wm->hcout = 12.25;
    6330        2667 :         } else if (state.dataMaterial->Material(MatOutside)->group == Material::Group::WindowBlind) { // Exterior blind present
    6331           4 :             MatShade = MatOutside;
    6332           4 :             ShadeFlag = WinShadingType::ExtBlind;
    6333           4 :             BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(MatShade))->BlindDataPtr;
    6334           4 :             wm->hcout = 12.25;
    6335        2663 :         } else if (state.dataMaterial->Material(MatInside)->group == Material::Group::Shade) { // Interior shade present
    6336          40 :             MatShade = MatInside;
    6337          40 :             ShadeFlag = WinShadingType::IntShade;
    6338        2623 :         } else if (state.dataMaterial->Material(MatInside)->group == Material::Group::WindowBlind) { // Interior blind present
    6339          23 :             MatShade = MatInside;
    6340          23 :             BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(MatShade))->BlindDataPtr;
    6341          23 :             ShadeFlag = WinShadingType::IntBlind;
    6342        2600 :         } else if (TotGlassLay == 2) {
    6343         982 :             if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Shade)
    6344           1 :                 ShadeFlag = WinShadingType::BGShade;
    6345         982 :             if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::WindowBlind)
    6346           2 :                 ShadeFlag = WinShadingType::BGBlind;
    6347        1618 :         } else if (TotGlassLay == 3) {
    6348         132 :             if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Shade)
    6349           1 :                 ShadeFlag = WinShadingType::BGShade;
    6350         132 :             if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::WindowBlind)
    6351           1 :                 ShadeFlag = WinShadingType::BGBlind;
    6352             :         }
    6353             : 
    6354        2676 :         if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
    6355           5 :             errFlag = 2;
    6356           5 :             return;
    6357             :         }
    6358             : 
    6359        2671 :         TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef);
    6360        2671 :         TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef);
    6361        2671 :         AbsBeamShadeNorm = 0.0;
    6362        2671 :         if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { // Exterior or interior shade on
    6363          45 :             AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef);
    6364             :             // Exterior blind or screen or interior blind on
    6365        2626 :         } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) {
    6366             :             // Find unshaded construction that goes with this construction w/blind or screen
    6367          31 :             ConstrNumBare = 0;
    6368         197 :             for (int ConstrNum1 = 1; ConstrNum1 <= state.dataHeatBal->TotConstructs; ++ConstrNum1) {
    6369         197 :                 if (ConstrNum1 != ConstrNum && state.dataConstruction->Construct(ConstrNum1).TypeIsWindow &&
    6370         429 :                     state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum1).TotSolidLayers &&
    6371          35 :                     state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum).TotGlassLayers) {
    6372             :                     // We have an unshaded window construction with the same number of glass layers as ConstrNum;
    6373             :                     // see if the glass and gas layers match
    6374          33 :                     ConstrNumBare = ConstrNum1;
    6375          70 :                     for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) {
    6376          37 :                         LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay);
    6377          37 :                         if (ShadeFlag == WinShadingType::IntBlind) { // The shaded construction has an interior blind
    6378          23 :                             LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    6379             :                         } else { // The shaded construction has an exterior blind or screen
    6380          14 :                             LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1);
    6381             :                         }
    6382          37 :                         if (LayPtrSh != LayPtr) ConstrNumBare = 0;
    6383             :                     }
    6384          33 :                     if (ConstrNumBare != 0) break;
    6385             :                 }
    6386             :             }
    6387          31 :             if (ConstrNumBare == 0) {
    6388             :                 // No matching bare construction found for this construction with blind or screen
    6389           0 :                 errFlag = 1;
    6390           0 :                 return;
    6391             :             }
    6392             : 
    6393          31 :             auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6394          31 :             TBmBm = POLYF(1.0, constructBare.TransSolBeamCoef);
    6395          31 :             TBmBmVis = POLYF(1.0, constructBare.TransVisBeamCoef);
    6396          31 :             if (ShadeFlag == WinShadingType::ExtScreen) {
    6397             :                 //   Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond)
    6398             :                 //   Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties
    6399           4 :                 auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(MatShade));
    6400           4 :                 assert(matScreen != nullptr);
    6401           4 :                 auto const &btar = matScreen->btars[0][0];
    6402           4 :                 TScBmBm = btar.BmTrans;
    6403           4 :                 TScBmBmVis = btar.BmTransVis;
    6404           4 :                 TScBmDif = btar.DfTrans;
    6405           4 :                 TScBmDifVis = btar.DfTransVis;
    6406           4 :                 TDif = constructBare.TransDiff;
    6407           4 :                 TDifVis = constructBare.TransDiffVis;
    6408           4 :                 RScBack = matScreen->ShadeRef;
    6409           4 :                 RScBackVis = matScreen->ShadeRefVis;
    6410           4 :                 RScDifBack = matScreen->DfRef;
    6411           4 :                 RScDifBackVis = matScreen->DfRefVis;
    6412           4 :                 RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6413           4 :                 RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6414           4 :                 RGlDiffFront = constructBare.ReflectSolDiffFront;
    6415           4 :                 RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
    6416           4 :                 TSolNorm = TScBmBm * (TBmBm + TDif * RGlFront * RScBack / (1 - RGlDiffFront * RScDifBack)) +
    6417           4 :                            TScBmDif * TDif / (1 - RGlDiffFront * RScDifBack);
    6418           4 :                 TVisNorm = TScBmBmVis * (TBmBmVis + TDifVis * RGlFrontVis * RScBackVis / (1 - RGlDiffFrontVis * RScDifBackVis)) +
    6419           4 :                            TScBmDifVis * TDifVis / (1 - RGlDiffFrontVis * RScDifBackVis);
    6420             :             } else {
    6421          27 :                 auto const &blind = state.dataMaterial->Blind(BlNum);
    6422          27 :                 VarSlats = false;
    6423          27 :                 if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Variable) VarSlats = true;
    6424          27 :                 SlatAng = blind.SlatAngle * Constant::DegToRadians;
    6425          27 :                 TBlBmBm = BlindBeamBeamTrans(0.0, SlatAng, blind.SlatWidth, blind.SlatSeparation, blind.SlatThickness);
    6426          27 :                 TBmBmBl = TBmBm * TBlBmBm;
    6427          27 :                 TBmBmBlVis = TBmBmVis * TBlBmBm;
    6428          27 :                 TBlBmDif = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamDiffTrans);
    6429          27 :                 TBlBmDifVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.VisFrontBeamDiffTrans);
    6430          27 :                 TDif = constructBare.TransDiff;
    6431          27 :                 TDifVis = constructBare.TransDiffVis;
    6432          27 :                 if (ShadeFlag == WinShadingType::IntBlind) {
    6433          23 :                     RGlDiffBack = constructBare.ReflectSolDiffBack;
    6434          23 :                     RGlDiffBackVis = constructBare.ReflectVisDiffBack;
    6435          23 :                     RhoBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamDiffRefl);
    6436          23 :                     RhoBlFrontVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.VisFrontBeamDiffRefl);
    6437          23 :                     AbsBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamAbs);
    6438          23 :                     RhoBlDiffFront = InterpSlatAng(SlatAng, VarSlats, blind.SolFrontDiffDiffRefl);
    6439          23 :                     RhoBlDiffFrontVis = InterpSlatAng(SlatAng, VarSlats, blind.VisFrontDiffDiffRefl);
    6440          23 :                     AbsBlDiffFront = InterpSlatAng(SlatAng, VarSlats, blind.SolFrontDiffAbs);
    6441          23 :                     AbsBeamShadeNorm = TBmBm * (AbsBlFront + RhoBlFront * RGlDiffBack * AbsBlDiffFront / (1.0 - RhoBlDiffFront * RGlDiffBack));
    6442          23 :                     TBlDifDif = InterpSlatAng(SlatAng, VarSlats, blind.SolFrontDiffDiffTrans);
    6443          23 :                     TBlDifDifVis = InterpSlatAng(SlatAng, VarSlats, blind.VisFrontDiffDiffTrans);
    6444          23 :                     TSolNorm = TBmBm * (TBlBmBm + TBlBmDif + TBlDifDif * RhoBlFront * RGlDiffBack / (1.0 - RhoBlDiffFront * RGlDiffBack));
    6445             :                     //     use of TBlBmBm here is correct, visible and IR transmittance are the same (reference deleted CR6925 on 3/20/2006)
    6446          23 :                     TVisNorm = TBmBmVis *
    6447          23 :                                (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis));
    6448             :                 } // (IntBlind)
    6449          27 :                 if (ShadeFlag == WinShadingType::ExtBlind) {
    6450           4 :                     TBlBmBm = BlindBeamBeamTrans(0.0, SlatAng, blind.SlatWidth, blind.SlatSeparation, blind.SlatThickness);
    6451           4 :                     RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6452           4 :                     RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
    6453           4 :                     AbsBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamAbs);
    6454           4 :                     AbsBlBack = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolBackBeamAbs);
    6455           4 :                     AbsBlDiffBack = InterpSlatAng(SlatAng, VarSlats, blind.SolBackDiffAbs);
    6456           4 :                     RGlDiffFront = constructBare.ReflectSolDiffFront;
    6457           4 :                     RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
    6458           4 :                     RhoBlDiffBack = InterpSlatAng(SlatAng, VarSlats, blind.SolBackDiffDiffRefl);
    6459           4 :                     RhoBlDiffBackVis = InterpSlatAng(SlatAng, VarSlats, blind.VisBackDiffDiffRefl);
    6460           4 :                     RhoBlBack = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolBackBeamDiffRefl);
    6461           4 :                     RhoBlBackVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolBackBeamDiffRefl);
    6462           4 :                     AbsBeamShadeNorm =
    6463           4 :                         AbsBlFront + AbsBlBack * RGlFront * TBlBmBm +
    6464           4 :                         (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDif);
    6465           4 :                     RGlDiffFront = constructBare.ReflectSolDiffFront;
    6466           4 :                     TSolNorm = TBlBmBm * (TBmBm + TDif * RGlFront * RhoBlBack / (1 - RGlDiffFront * RhoBlDiffBack)) +
    6467           4 :                                TBlBmDif * TDif / (1.0 - RGlDiffFront * RhoBlDiffBack);
    6468           4 :                     TVisNorm = TBlBmBm * (TBmBmVis + TDifVis * RGlFrontVis * RhoBlBackVis / (1 - RGlDiffFrontVis * RhoBlDiffBackVis)) +
    6469           4 :                                TBlBmDifVis * TDifVis / (1.0 - RGlDiffFrontVis * RhoBlDiffBackVis);
    6470             :                 } // (ExtBlind)
    6471             :             }     // (Screen or Blind)
    6472             :         }         // (Shade, Blind, or Screen)
    6473             : 
    6474             :         // Fill the layer properties needed for the thermal calculation.
    6475             : 
    6476             :         // The layer and face numbering are as follows (for the triple glazing case):
    6477             :         // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
    6478             :         //   layer and 3 is the inside (room-facing) layer;
    6479             :         // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
    6480             :         //   outside (front) face of glass layer 1, face 2 is the inside (back)
    6481             :         //   face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
    6482             :         //   inner face of glass layer 2, etc.
    6483             :         // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
    6484             :         //   and gap layer 2 is between glass layers 2 and 3.
    6485             : 
    6486        2671 :         int IGlass = 0;
    6487        2671 :         int IGap = 0;
    6488             : 
    6489        8062 :         for (int Lay = 1; Lay <= TotLay; ++Lay) {
    6490        5391 :             LayPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    6491        5391 :             auto const *mat = state.dataMaterial->Material(LayPtr);
    6492             : 
    6493        5391 :             if ((mat->group == Material::Group::WindowGlass) || (mat->group == Material::Group::WindowSimpleGlazing)) {
    6494        3979 :                 auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    6495        3979 :                 assert(thisMaterial != nullptr);
    6496             : 
    6497        3979 :                 ++IGlass;
    6498        3979 :                 wm->thick[IGlass - 1] = thisMaterial->Thickness;
    6499        3979 :                 wm->scon[IGlass - 1] = thisMaterial->Conductivity / thisMaterial->Thickness;
    6500        3979 :                 wm->emis[2 * IGlass - 2] = thisMaterial->AbsorpThermalFront;
    6501        3979 :                 wm->emis[2 * IGlass - 1] = thisMaterial->AbsorpThermalBack;
    6502        3979 :                 wm->tir[2 * IGlass - 2] = thisMaterial->TransThermal;
    6503        3979 :                 wm->tir[2 * IGlass - 1] = thisMaterial->TransThermal;
    6504        3979 :                 AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef(IGlass));
    6505        3979 :                 if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on
    6506          23 :                     auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6507          23 :                     AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
    6508          23 :                     AGlDiffBack = constructBare.AbsDiffBack(IGlass);
    6509          23 :                     AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack);
    6510        3956 :                 } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on
    6511           4 :                     auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6512           4 :                     AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
    6513           8 :                     AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) *
    6514           4 :                                                                               constructBare.AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack);
    6515        3952 :                 } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on
    6516           6 :                     auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
    6517           6 :                     AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
    6518          12 :                     AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * constructBare.AbsDiff(IGlass) /
    6519           6 :                                                                               (1.0 - RGlDiffFront * RScDifBack);
    6520             :                 }
    6521        3979 :                 wm->AbsRadGlassFace[2 * IGlass - 2] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
    6522        3979 :                 wm->AbsRadGlassFace[2 * IGlass - 1] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
    6523             :             }
    6524        5391 :             if (mat->group == Material::Group::WindowGas || mat->group == Material::Group::WindowGasMixture ||
    6525        4098 :                 mat->group == Material::Group::ComplexWindowGap) { // Gap layer
    6526        1322 :                 ++IGap;
    6527             :                 // Simon: Need to re-reference gas data in casee of complex fenestration gap
    6528        1322 :                 if (mat->group == Material::Group::ComplexWindowGap) {
    6529          29 :                     auto const *matCW = dynamic_cast<Material::MaterialChild const *>(mat);
    6530          29 :                     assert(matCW != nullptr);
    6531          29 :                     LayPtr = matCW->GasPointer;
    6532             :                 }
    6533        1322 :                 auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(LayPtr));
    6534        1322 :                 assert(matGas != nullptr);
    6535        1322 :                 wm->gaps[IGap - 1].width = matGas->Thickness;
    6536        1322 :                 wm->gaps[IGap - 1].numGases = matGas->numGases;
    6537        2680 :                 for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
    6538        1358 :                     wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
    6539        1358 :                     wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
    6540             :                 }
    6541             :             }
    6542             :         } // for (Lay)
    6543             : 
    6544             :         // Factors used in glass temperature solution
    6545        2671 :         if (wm->ngllayer >= 2) {
    6546        1152 :             wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    6547        1152 :             wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
    6548        1152 :             wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
    6549             :         }
    6550             : 
    6551        2671 :         if (wm->ngllayer >= 3) {
    6552         144 :             wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    6553         144 :             wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
    6554         144 :             wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
    6555             :         }
    6556             : 
    6557        2671 :         if (wm->ngllayer == 4) {
    6558          12 :             wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    6559          12 :             wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
    6560          12 :             wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
    6561             :         }
    6562             : 
    6563        2671 :         wm->thetas = {0.0};
    6564             : 
    6565        2671 :         WindowTempsForNominalCond(state, ConstrNum, hgap, 1.0);
    6566             : 
    6567        2671 :         if (!ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsBeamShadeNorm = 0.0;
    6568             : 
    6569             :         // Get center-of-glass conductance and solar heat gain coefficient
    6570             :         // including inside and outside air films
    6571        2671 :         Real64 inputU = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->SimpleWindowUfactor;
    6572             : 
    6573             :         // Calculate the NominalConductance glazing only (before adjusted)
    6574        2671 :         EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
    6575             : 
    6576        2671 :         if (WinterSummerFlag == 1) {
    6577        1345 :             state.dataHeatBal->NominalUBeforeAdjusted(ConstrNum) = NominalConductance;
    6578        1345 :             if (inputU > 0) {                  // only compute adjustment ratio when there is valid user input U
    6579         132 :                 Real64 wettedAreaAdjRatio = 1; // Adjustment ratio for the wetted area
    6580         132 :                 Real64 hcoutRated = wm->hcout;
    6581             :                 // Adjustment ratio applies to convective film coefficients when input U value is above the limit of the simple glazing nominal U
    6582             :                 // Representing the nominal highly conductive frame effects. Solved iteratively.
    6583         132 :                 Real64 adjLower = 1.0;
    6584         132 :                 Real64 adjUpper = 2.0;
    6585         132 :                 int MaxIter = 100;
    6586         148 :                 while (std::abs(inputU - NominalConductance) > 0.01 && MaxIter > 0) {
    6587          16 :                     wettedAreaAdjRatio = (adjLower + adjUpper) / 2;
    6588          16 :                     WindowTempsForNominalCond(
    6589             :                         state, ConstrNum, hgap, wettedAreaAdjRatio); // reeval hcout at each iteration, hcin is not linear to wetted area
    6590          16 :                     wm->hcout = hcoutRated * wettedAreaAdjRatio;     // reeval hcout
    6591          16 :                     EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
    6592          16 :                     if (NominalConductance < inputU) {
    6593           5 :                         adjLower = wettedAreaAdjRatio;
    6594             :                     } else {
    6595          11 :                         adjUpper = wettedAreaAdjRatio;
    6596             :                     }
    6597          16 :                     MaxIter -= 1;
    6598             :                 }
    6599         132 :                 state.dataHeatBal->CoeffAdjRatio(ConstrNum) = wettedAreaAdjRatio;
    6600             :             }
    6601             :         }
    6602             : 
    6603             :         // EPTeam - again -- believe that is enforced in input //Autodesk But this routine is not self-protecting: Add as an assert
    6604             : 
    6605             :         // init the surface convective and radiative adjustment ratio
    6606       34141 :         for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    6607       62988 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    6608       31518 :                 auto &thisSpace = state.dataHeatBal->space(spaceNum);
    6609       31518 :                 int const firstSurfWin = thisSpace.WindowSurfaceFirst;
    6610       31518 :                 int const lastSurfWin = thisSpace.WindowSurfaceLast;
    6611      101025 :                 for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
    6612       69507 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
    6613       69475 :                         int ConstrNum2 = state.dataSurface->Surface(SurfNum).Construction;
    6614       69475 :                         state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum) = state.dataHeatBal->CoeffAdjRatio(ConstrNum2);
    6615             :                     }
    6616             :                 }
    6617       31470 :             }
    6618             :         }
    6619             : 
    6620             :         // Need to add variables writing here since this routine will override previously calcualted values from WinCalc-Engine
    6621        2671 :         if (wm->inExtWindowModel->isExternalLibraryModel()) {
    6622           3 :             TSolNorm = GetSolarTransDirectHemispherical(state, ConstrNum);
    6623           3 :             TVisNorm = GetVisibleTransDirectHemispherical(state, ConstrNum);
    6624             :         }
    6625        2681 :     } // CalcNominalWindowCond()
    6626             : 
    6627        2687 :     void EvalNominalWindowCond(EnergyPlusData &state,
    6628             :                                Real64 const AbsBeamShadeNorm,     // Shade solar absorptance at normal incidence
    6629             :                                Array1D<Real64> const AbsBeamNorm, // Beam absorptance at normal incidence for each glass layer
    6630             :                                Array1D<Real64> const hgap,        // Conductive gap conductance [W/m2-K]
    6631             :                                Real64 &NominalConductance,        // Nominal center-of-glass conductance, including air films
    6632             :                                Real64 &SHGC,                      // Nominal center-of-glass solar heat gain coefficient for
    6633             :                                Real64 &TSolNorm                   // Overall beam solar transmittance at normal incidence
    6634             :     )
    6635             :     {
    6636        2687 :         Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
    6637             : 
    6638        2687 :         auto &wm = state.dataWindowManager;
    6639        2687 :         Real64 hOutRad = wm->emis[0] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tout + wm->thetas[0]);
    6640        2687 :         Real64 rOut = 1.0 / (hOutRad + wm->hcout);
    6641        2687 :         Real64 hInRad = wm->emis[wm->nglface - 1] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tin + wm->thetas[wm->nglface - 1]);
    6642        2687 :         Real64 rIn = 1.0 / (hInRad + wm->hcin);
    6643        2687 :         Real64 Rbare = 0;
    6644             : 
    6645        2687 :         switch (wm->ngllayer) {
    6646             :         // the switch cases here are just the integer number of layers, not exactly "magic" numbers 1, 2, 3. and 4.
    6647        1535 :         case 1: {
    6648        1535 :             Rbare = 1.0 / wm->scon[0];
    6649        1535 :             wm->Rtot = rOut + Rbare + rIn;
    6650        1535 :             SHGC = AbsBeamNorm(1) * (rOut + (0.5 / wm->scon[0])) / wm->Rtot; // BG changed for CR7682 (solar absorbed in middle of layer)
    6651        1535 :             SHGC += AbsBeamShadeNorm;
    6652        1535 :             SHGC += TSolNorm;
    6653        1535 :         } break;
    6654             : 
    6655        1008 :         case 2: {
    6656        1008 :             hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
    6657        1008 :             Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1];
    6658        1008 :             wm->Rtot = rOut + Rbare + rIn;
    6659        1008 :             SHGC = AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
    6660        1008 :                    AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot; // CR7682
    6661        1008 :             SHGC += AbsBeamShadeNorm;
    6662        1008 :             SHGC += TSolNorm;
    6663        1008 :         } break;
    6664             : 
    6665         132 :         case 3: {
    6666         132 :             hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
    6667         132 :             hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
    6668         132 :             Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2];
    6669         132 :             wm->Rtot = rOut + Rbare + rIn;
    6670         132 :             SHGC =
    6671         132 :                 AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
    6672         132 :                 AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
    6673         132 :                 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;
    6674         132 :             SHGC += AbsBeamShadeNorm;
    6675         132 :             SHGC += TSolNorm;
    6676         132 :         } break;
    6677             : 
    6678          12 :         case 4: {
    6679          12 :             hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
    6680          12 :             hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
    6681          12 :             hGapTot(3) = hgap(3) + std::abs(wm->A67) * 0.5 * pow_3(wm->thetas[5] + wm->thetas[6]);
    6682          12 :             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) +
    6683          12 :                     1.0 / wm->scon[3];
    6684          12 :             wm->Rtot = rOut + Rbare + rIn;
    6685          12 :             SHGC =
    6686          12 :                 AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
    6687          12 :                 AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
    6688          12 :                 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 +
    6689          12 :                 AbsBeamNorm(4) *
    6690          12 :                     (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) +
    6691          12 :                      0.5 / wm->scon[3]) /
    6692          12 :                     wm->Rtot; // CR7682
    6693          12 :             SHGC += AbsBeamShadeNorm;
    6694          12 :             SHGC += TSolNorm;
    6695          12 :         } break;
    6696           0 :         default:
    6697           0 :             break;
    6698             :         }
    6699        2687 :         NominalConductance = 1.0 / (rOut + Rbare + rIn);
    6700        2687 :     } // EvalNominalWindowCond()
    6701             : 
    6702             :     //****************************************************************************
    6703             : 
    6704        2687 :     void WindowTempsForNominalCond(EnergyPlusData &state,
    6705             :                                    int const ConstrNum,  // Construction number
    6706             :                                    Array1A<Real64> hgap, // Gap gas conductive conductance (W/m2-K)
    6707             :                                    Real64 const adjRatio // adjusment Ratio to hcin
    6708             :     )
    6709             :     {
    6710             : 
    6711             :         // SUBROUTINE INFORMATION:
    6712             :         //       AUTHOR         F. Winkelmann
    6713             :         //       DATE WRITTEN   September 2000
    6714             :         //       MODIFIED       Nov 2002, FW: increase MaxIterations from 15 to 100, add face
    6715             :         //                       temperature relaxation, and increase convergence tolerance by
    6716             :         //                       a factor of 10 if no convergence after MaxIterations,
    6717             :         //                       all for consistency with SolveForWindowTemperatures.
    6718             :         //                      Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02;
    6719             :         //                       remove redundant relaxation on radiative conductances (both of
    6720             :         //                       these were also done in SolveForWindowTemperatures).
    6721             :         //                      Jan 2009, BG: changed interior convection coefficient correlation to match
    6722             :         //                       ISO 15099.
    6723             :         //                      Feb 2009, BG: extended coefficient to include absorbed radiation
    6724             :         //                       to cover summer conditions for SHGC determination.
    6725             :         //       RE-ENGINEERED  na
    6726             : 
    6727             :         // PURPOSE OF THIS SUBROUTINE:
    6728             :         // This is a shortened form of SolveForWindowTemperatures tailored
    6729             :         // for calculation of the nominal center-of-glass U-value for a window
    6730             :         // construction at ASHRAE winter conditions and for determining conditions at
    6731             :         // summer conditions for calculationg SHGC.
    6732             :         // Evaluates the coefficients Aface and Bface in the system of linear
    6733             :         // algebraic equations
    6734             :         //     Sum    [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglface
    6735             :         //  j=1,nglface
    6736             :         // where
    6737             :         // nglface = number of glass faces (= 2 * number of layers) and
    6738             :         // thetas(j) = temperature of face j
    6739             : 
    6740             :         // METHODOLOGY EMPLOYED:
    6741             :         // The Aface and Bface coefficients are determined by the equations for
    6742             :         // heat balance at the glass faces. The system of linear equations is solved
    6743             :         // by LU decomposition.
    6744             : 
    6745             :         using Psychrometrics::PsyRhoAirFnPbTdbW;
    6746             : 
    6747             :         // Argument array dimensioning
    6748        2687 :         hgap.dim(5);
    6749             : 
    6750        2687 :         int constexpr MaxIterations(100);  // Maximum allowed number of iterations
    6751        2687 :         Real64 constexpr errtemptol(0.02); // Tolerance on errtemp for convergence
    6752             :         static constexpr std::string_view RoutineName("WindowTempsForNominalCond");
    6753             : 
    6754        2687 :         Array1D<Real64> hr(10); // Radiative conductance (W/m2-K)
    6755             :         Real64 hcinprev;        // Value of hcin from previous iteration
    6756             :         int d;                  // +1 if number of row interchanges is even,
    6757             :         // -1 if odd (in LU decomposition)
    6758        2687 :         Array1D_int indx(10);          // Vector of row permutations in LU decomposition
    6759        5374 :         Array2D<Real64> Aface(10, 10); // Coefficient in equation Aface*thetas = Bface
    6760        2687 :         Array1D<Real64> Bface(10);     // Coefficient in equation Aface*thetas = Bface
    6761             :         int iter;                      // Iteration number
    6762             :         Real64 errtemp;                // Absolute value of sum of face temperature differences
    6763             :         //   between iterations, divided by number of faces
    6764             :         Real64 TmeanFilm;       // mean film temperature
    6765             :         Real64 TmeanFilmKelvin; // mean film temperature for property evaluation
    6766             :         Real64 rho;             // density of (apparently dry) air [kg/m3]
    6767             :         Real64 g;               // acceleration due to gravity [m/s2]
    6768             :         Real64 Height;          // window cavity height [m]
    6769             :         Real64 Cp;              // specific heat of air [J/kg-K]
    6770             :         Real64 lambda;          // thermal conductivity of air [W/m-K]
    6771             :         Real64 mu;              // dynamic viscosity of air [kg/m-s]
    6772             :         Real64 RaH;             // Rayleigh number for cavity height [ Non dim]
    6773             :         Real64 TiltDeg;         // glazing tilt in degrees
    6774             :         Real64 sineTilt;        // sine of glazing tilt
    6775             :         Real64 Nuint;           // Nusselt number for interior surface convection
    6776             : 
    6777        2687 :         auto &wm = state.dataWindowManager;
    6778             : 
    6779        2687 :         iter = 0;
    6780             : 
    6781             :         // Initialize face temperatures
    6782        2687 :         StartingWinTempsForNominalCond(state);
    6783             : 
    6784             :         // Calculate radiative conductance
    6785        2687 :         errtemp = errtemptol * 2.0;
    6786             : 
    6787        2687 :         TiltDeg = 90.0;
    6788             : 
    6789        2687 :         sineTilt = std::sin(TiltDeg * Constant::DegToRadians); // degrees as arg
    6790             : 
    6791       18045 :         while (iter < MaxIterations && errtemp > errtemptol) {
    6792       62742 :             for (int i = 1; i <= wm->nglface; ++i) {
    6793       47384 :                 hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
    6794             :                 //! fw 3/4/03 if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
    6795             :             }
    6796             : 
    6797       15358 :             Aface = 0.0;
    6798       15358 :             Bface = 0.0;
    6799             : 
    6800             :             // Inside convective film conductance for vertical window
    6801       15358 :             if (iter >= 1) {
    6802       12671 :                 hcinprev = wm->hcin;
    6803             :             }
    6804             :             // CR7670 BG this next correlation was used for hcin but is not "standard" for windows
    6805             :             //  hcin = 1.31d0*((ABS(thetas(nglface)-tin))**0.3333d0)
    6806             :             // Begin calculating for ISO 15099 method.
    6807             :             // mean film temperature
    6808       15358 :             TmeanFilmKelvin = wm->tin + 0.25 * (wm->thetas[wm->nglface - 1] - wm->tin); // eq. 133 in ISO 15099
    6809       15358 :             TmeanFilm = TmeanFilmKelvin - 273.15;
    6810             :             // the following properties are constants or linear relations for "standard" type reporting
    6811       15358 :             rho = PsyRhoAirFnPbTdbW(state, 101325.0, TmeanFilm, 0.0, RoutineName); // dry air assumption
    6812       15358 :             g = 9.81;
    6813       15358 :             Height = 1.0; // standard window rating practice is to use 1 meter (rather than actual)
    6814             : 
    6815       15358 :             lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // Table B.1 in ISO 15099
    6816       15358 :             mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin;     // Table B.2 in ISO 15099
    6817       15358 :             Cp = 1002.737 + 1.2324E-2 * TmeanFilmKelvin;   // Table B.3 in ISO 15099
    6818             : 
    6819             :             // eq 132 in ISO 15099
    6820       15358 :             RaH = (pow_2(rho) * pow_3(Height) * g * Cp * (std::abs(wm->thetas[wm->nglface - 1] - wm->tin))) / (TmeanFilmKelvin * mu * lambda);
    6821             : 
    6822       15358 :             Nuint = 0.56 * root_4(RaH * sineTilt); // eq. 135 in ISO 15099 (only need this one because tilt is 90 deg
    6823             : 
    6824       15358 :             wm->hcin = Nuint * lambda / Height;
    6825             : 
    6826             :             // End calculations for ISO 15099 method.
    6827             : 
    6828       15358 :             if (iter >= 1) wm->hcin = 0.5 * (hcinprev + wm->hcin);
    6829             : 
    6830       15358 :             wm->hcin *= adjRatio;
    6831             : 
    6832       15358 :             ++iter;
    6833             : 
    6834       15358 :             GetHeatBalanceEqCoefMatrixSimple(state, wm->ngllayer, hr, hgap, Aface, Bface);
    6835             : 
    6836       15358 :             LUdecomposition(state, Aface, wm->nglface, indx, d); // Note that these routines change Aface;
    6837       15358 :             LUsolution(state, Aface, wm->nglface, indx, Bface);  // face temperatures are returned in Bface
    6838             : 
    6839       15358 :             errtemp = 0.0;
    6840       62742 :             for (int i = 1; i <= wm->nglface; ++i) {
    6841       47384 :                 errtemp += std::abs(wm->thetas[i - 1] - Bface(i)) / wm->nglface;
    6842             :             }
    6843             : 
    6844       62742 :             for (int i = 1; i <= wm->nglface; ++i) {
    6845       47384 :                 wm->thetas[i - 1] = 0.5 * (wm->thetas[i - 1] + Bface(i));
    6846             :             }
    6847             :         }
    6848             : 
    6849             :         // No convergence after MaxIterations; and/or error tolerance
    6850        2687 :         if (errtemp >= 10 * errtemptol) {
    6851             :             // Fatal error: didn't converge
    6852           0 :             ShowFatalError(
    6853             :                 state,
    6854           0 :                 format("Convergence error in WindowTempsForNominalCond for construction {}", state.dataConstruction->Construct(ConstrNum).Name));
    6855             :         }
    6856        2687 :     } // WindowTempsForNominalCond()
    6857             : 
    6858             :     //****************************************************************************
    6859             : 
    6860        2687 :     void StartingWinTempsForNominalCond(EnergyPlusData &state)
    6861             :     {
    6862             : 
    6863             :         // SUBROUTINE INFORMATION:
    6864             :         //       AUTHOR         F. Winkelmann
    6865             :         //       DATE WRITTEN   September 2000
    6866             :         //       MODIFIED       na
    6867             :         //       RE-ENGINEERED  na
    6868             : 
    6869             :         // PURPOSE OF THIS SUBROUTINE:
    6870             :         // Initializes face temperature distribution prior to iteration.
    6871             :         // This is a shortened form of StartingWindowTemps for use in calculating
    6872             :         // the nominal center-of-glass U-value.
    6873             : 
    6874        2687 :         Real64 constexpr hrad(5.3);           // Typical radiative conductance (W/m2-K)
    6875        2687 :         Real64 constexpr hcinStartValue(3.2); // Starting value for inside air film convective
    6876             :         //   conductance (estimated for typical double glazing
    6877             :         //   using 1.31(dT**0.333), where dT =
    6878             :         //   room air temp - inside surface temp = 14.2K)
    6879        2687 :         Real64 constexpr resgap(0.21); // Typical gap resistance (m2-K/W)
    6880             : 
    6881        2687 :         Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
    6882             :         // inside or outside air film, or gap
    6883             :         Real64 restot; // Total window resistance including outside
    6884             :         //   and inside air films (m2-K/W)
    6885             :         Real64 temdiff; // Inside/outside air temperature difference (K)
    6886             :         Real64 ressum;  // Resistance sum (m2-K/W)
    6887             : 
    6888        2687 :         auto &wm = state.dataWindowManager;
    6889             : 
    6890        2687 :         rguess(1) = 1.0 / (wm->hcout + hrad);
    6891        2687 :         rguess(wm->nglface + 1) = 1.0 / (hcinStartValue + hrad);
    6892             : 
    6893        6682 :         for (int i = 2; i <= wm->nglface; i += 2) {
    6894        3995 :             rguess(i) = 1.0 / wm->scon[i / 2 - 1];
    6895        3995 :             if (i < wm->nglface) rguess(i + 1) = resgap;
    6896             :         }
    6897        2687 :         restot = 0.0;
    6898             : 
    6899       13364 :         for (int i = 1; i <= wm->nglface + 1; ++i) {
    6900       10677 :             restot += rguess(i);
    6901             :         }
    6902             : 
    6903        2687 :         temdiff = wm->tin - wm->tout;
    6904        2687 :         if (std::abs(temdiff) < 0.5) temdiff = 2.0;
    6905        2687 :         ressum = 0.0;
    6906             : 
    6907       10677 :         for (int i = 1; i <= wm->nglface; ++i) {
    6908        7990 :             ressum += rguess(i);
    6909        7990 :             wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
    6910             :         }
    6911        2687 :     } // StartingWinTempsForNominalCond()
    6912             : 
    6913             :     //****************************************************************************
    6914             : 
    6915         793 :     void ReportGlass(EnergyPlusData &state)
    6916             :     {
    6917             : 
    6918             :         // SUBROUTINE INFORMATION:
    6919             :         //       AUTHOR         Linda K. Lawrie
    6920             :         //       DATE WRITTEN   March 2000
    6921             :         //       MODIFIED       na
    6922             :         //       RE-ENGINEERED  na
    6923             : 
    6924             :         // PURPOSE OF THIS SUBROUTINE:
    6925             :         // This routine gives a detailed report to the user about
    6926             :         // the calculation parameters for windows and their associated
    6927             :         // materials.
    6928             : 
    6929             :         using General::POLYF;
    6930             : 
    6931             :         using General::ScanForReports;
    6932             :         using WindowComplexManager::CalcComplexWindowThermal;
    6933             :         using WindowComplexManager::UpdateComplexWindows;
    6934             : 
    6935         793 :         static Array1D_string const Roughness({0, 5}, {"VeryRough", "Rough", "MediumRough", "MediumSmooth", "Smooth", "VerySmooth"});
    6936             : 
    6937         793 :         Real64 TempVar(0.0); // just temporary usage for complex fenestration
    6938             : 
    6939             :         int ThisNum;
    6940             :         int Layer;
    6941             :         int BlNum;                       // Blind number
    6942             :         Real64 NominalConductanceWinter; // Nominal center-of-glass conductance of a window construction
    6943             :         // for ASHRAE winter conditions (W/m2-K):
    6944             :         // Inside air temperature = 21.1C (70F)
    6945             :         // Outside air temperature = -17.8C (0F)
    6946             :         // Windspeed = 6.71 m/s (15 mph)
    6947             :         // No solar radiation
    6948             :         Real64 NominalConductanceSummer; // Nominal center-of-glass conductance of a window construction
    6949             :         // for ASHRAE summer conditions (W/m2-K):
    6950             :         // Inside air temperature = 23.9C (75F)
    6951             :         // Outside air temperature = 35.0C (95F)
    6952             :         // Windspeed = 3.35 m/s (7.5 mph)
    6953             :         // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
    6954         793 :         Real64 SHGCWinter(0.0); // Center-of-glass solar heat gain coefficient for ASHRAE
    6955         793 :         Real64 SHGCSummer(0.0);
    6956             :         // winter and summer conditions
    6957             :         Real64 TransSolNorm;        // Window construction solar transmittance at normal incidence
    6958             :         Real64 TransVisNorm;        // Window construction visible transmittance at normal incidence
    6959             :         int errFlag;                // Error flag
    6960         793 :         std::string SolarDiffusing; // 'Yes' if glass is solar diffusing; otherwise 'No' (clear glass)
    6961         793 :         std::string SpectralDataName;
    6962         793 :         std::string OpticalDataType;
    6963         793 :         std::string SlateOrientation;
    6964             : 
    6965         793 :         auto &wm = state.dataWindowManager;
    6966             : 
    6967         793 :         ScanForReports(state, "Constructions", wm->DoReport, "Constructions");
    6968             : 
    6969         793 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    6970         793 :                         state.dataConstruction->Construct.end(),
    6971        4515 :                         [](Construction::ConstructionProps const &e) { return e.TypeIsWindow; }))
    6972         696 :             wm->HasWindows = true;
    6973         793 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    6974         793 :                         state.dataConstruction->Construct.end(),
    6975        6023 :                         [](Construction::ConstructionProps const &e) { return e.WindowTypeBSDF; }))
    6976           9 :             wm->HasComplexWindows = true; // Yes, this is a bit different than actually using them.
    6977         793 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    6978         793 :                         state.dataConstruction->Construct.end(),
    6979        6025 :                         [](Construction::ConstructionProps const &e) { return e.WindowTypeEQL; }))
    6980           1 :             wm->HasEQLWindows = true; // for reporting purpose only
    6981         793 :         if (wm->DoReport && (wm->HasWindows || wm->HasComplexWindows || wm->HasEQLWindows)) {
    6982             :             //                                      Write Descriptions
    6983         268 :             print(state.files.eio,
    6984             :                   "{}\n",
    6985             :                   "! <WindowConstruction>,Construction Name,Index,#Layers,Roughness,Conductance {W/m2-K},Conductance (Before Adjusted) {W/m2-K},"
    6986             :                   "Convection Coefficient Adjustment Ratio,SHGC,"
    6987             :                   "Solar Transmittance at Normal Incidence,Visible Transmittance at Normal Incidence");
    6988         268 :             if ((state.dataHeatBal->TotSimpleWindow > 0) || (state.dataHeatBal->W5GlsMat > 0) || (state.dataHeatBal->W5GlsMatAlt > 0))
    6989         262 :                 print(state.files.eio,
    6990             :                       "{}\n",
    6991             :                       "! <WindowMaterial:Glazing>, Material Name, Optical Data Type, Spectral Data Set Name, "
    6992             :                       "Thickness {m}, Solar Transmittance,Front Solar Reflectance, Back Solar Reflectance, Visible "
    6993             :                       "Transmittance, Front Visible Reflectance,Back Visible Reflectance,Infrared Transmittance, "
    6994             :                       "Front Thermal Emissivity, Back Thermal Emissivity,Conductivity {W/m-K},Dirt Factor,Solar "
    6995             :                       "Diffusing");
    6996         268 :             if ((state.dataHeatBal->W5GasMat > 0) || (state.dataHeatBal->W5GasMatMixture > 0))
    6997          87 :                 print(state.files.eio, "{}\n", "! <WindowMaterial:Gas>,Material Name,GasType,Thickness {m}");
    6998         268 :             if (state.dataHeatBal->TotShades > 0)
    6999           7 :                 print(state.files.eio,
    7000             :                       "{}\n",
    7001             :                       "! <WindowMaterial:Shade>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
    7002             :                       "Absorptance,Transmittance,Visible Transmittance,Shade Reflectance");
    7003         268 :             if (state.dataHeatBal->TotScreens > 0)
    7004           2 :                 print(state.files.eio,
    7005             :                       "{}\n",
    7006             :                       "! <WindowMaterial:Screen>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
    7007             :                       "Absorptance,Transmittance,Reflectance,Visible Reflectance,Diffuse Reflectance,Diffuse Visible "
    7008             :                       "Reflectance,Screen Material Diameter To Spacing Ratio,Screen To GlassDistance {m}");
    7009         268 :             if (state.dataHeatBal->TotBlinds > 0)
    7010          16 :                 print(state.files.eio,
    7011             :                       "{}\n",
    7012             :                       "! <WindowMaterial:Blind>,Material Name,Slat Width {m},Slat Separation {m},Slat Thickness "
    7013             :                       "{m},Slat Angle {deg},Slat Beam Solar Transmittance,Slat Beam Solar Front Reflectance,Blind To "
    7014             :                       "Glass Distance {m}");
    7015             : 
    7016         268 :             if (wm->HasComplexWindows)
    7017           8 :                 print(state.files.eio,
    7018             :                       "{}\n",
    7019             :                       "! <WindowConstruction:Complex>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC"
    7020             :                       "NFRC Product Type,Assembly U-Factor {W/m2-K},Assembly SHGC,Assembly Visible Transmittance");
    7021             : 
    7022         268 :             if (wm->HasEQLWindows)
    7023           1 :                 print(state.files.eio,
    7024             :                       "{}\n",
    7025             :                       "! <Construction:WindowEquivalentLayer>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC, "
    7026             :                       "Solar Transmittance at Normal Incidence");
    7027         268 :             if (state.dataHeatBal->W5GlsMatEQL > 0)
    7028           1 :                 print(state.files.eio,
    7029             :                       "{}\n",
    7030             :                       "! <WindowMaterial:Glazing:EquivalentLayer>, Material Name, Optical Data Type, Spectral Data "
    7031             :                       "Set Name, Front Side Beam-Beam Solar Transmittance, Back Side Beam-Beam Solar Transmittance, "
    7032             :                       "Front Side Beam-Beam Solar Reflectance, Back Side Beam-Beam Solar Reflectance, Front Side "
    7033             :                       "Beam-Diffuse Solar Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side "
    7034             :                       "Beam-Diffuse Solar Reflectance, Back Side Beam-Diffuse Solar Reflectance, Diffuse-Diffuse "
    7035             :                       "Solar Transmittance, Front Side Diffuse-Diffuse Solar Reflectance, Back Side Diffuse-Diffuse "
    7036             :                       "Solar Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
    7037             :                       "Emissivity");
    7038         268 :             if (state.dataHeatBal->TotShadesEQL > 0)
    7039           1 :                 print(state.files.eio,
    7040             :                       "{}\n",
    7041             :                       "! <WindowMaterial:Shade:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
    7042             :                       "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
    7043             :                       "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
    7044             :                       "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
    7045             :                       "Infrared Emissivity, Back Side Infrared Emissivity");
    7046             : 
    7047         268 :             if (state.dataHeatBal->TotDrapesEQL > 0)
    7048           0 :                 print(state.files.eio,
    7049             :                       "{}\n",
    7050             :                       "! <WindowMaterial:Drape:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
    7051             :                       "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
    7052             :                       "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
    7053             :                       "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
    7054             :                       "Infrared Emissivity, Back Side Infrared Emissivity, Width of Pleated Fabric, Length of Pleated "
    7055             :                       "Fabric");
    7056             : 
    7057         268 :             if (state.dataHeatBal->TotBlindsEQL > 0)
    7058           0 :                 print(state.files.eio,
    7059             :                       "{}\n",
    7060             :                       "! <WindowMaterial:Blind:EquivalentLayer>, Material Name, Slat Orientation, Slat Width, Slat "
    7061             :                       "Separation, Slat Crown, Slat Angle, Front Side Slate Beam-Diffuse Solar Transmittance, Back "
    7062             :                       "Side Slate Beam-Diffuse Solar Transmittance, Front Side Slate Beam-Diffuse Solar Reflectance, "
    7063             :                       "Back Side Slate Beam-Diffuse Solar Reflectance, Slat Diffuse-Diffuse Solar Transmittance, "
    7064             :                       "Front Side Slat Diffuse-Diffuse Solar Reflectance, Back Side Slat Diffuse-Diffuse Solar "
    7065             :                       "Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
    7066             :                       "Emissivity, Slat Angle Control");
    7067         268 :             if (state.dataHeatBal->TotScreensEQL > 0)
    7068           1 :                 print(state.files.eio,
    7069             :                       "{}\n",
    7070             :                       "! <WindowMaterial:Screen:EquivalentLayer>, Material Name, Screen Beam-Beam Solar "
    7071             :                       "Transmittance, Screen Beam-Diffuse Solar Transmittance, Screen Beam-Diffuse Solar Reflectance, "
    7072             :                       "Screen Infrared Transmittance, Screen Infrared Emissivity, Screen Wire Spacing, Screen Wire "
    7073             :                       "Diameter");
    7074         268 :             if (state.dataHeatBal->W5GapMatEQL > 0)
    7075           1 :                 print(state.files.eio, "{}\n", "! <WindowMaterial:Gap:EquivalentLayer>, Material Name, GasType, Gap Thickness {m}, Gap Vent Type");
    7076             : 
    7077        3095 :             for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
    7078        2827 :                 auto &construct = state.dataConstruction->Construct(ThisNum);
    7079        2827 :                 if (construct.WindowTypeBSDF) {
    7080             : 
    7081          11 :                     int i = ThisNum;
    7082          11 :                     CalcComplexWindowThermal(state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Winter);
    7083          11 :                     CalcComplexWindowThermal(state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Summer);
    7084             : 
    7085             :                     static constexpr std::string_view Format_800(" WindowConstruction:Complex,{},{},{},{:.3R},{:.3R}\n");
    7086          11 :                     print(state.files.eio,
    7087             :                           Format_800,
    7088          11 :                           construct.Name,
    7089             :                           ThisNum,
    7090          11 :                           construct.TotSolidLayers,
    7091          11 :                           state.dataHeatBal->NominalU(ThisNum),
    7092          11 :                           construct.SummerSHGC);
    7093             : 
    7094        2816 :                 } else if (construct.TypeIsWindow) {
    7095             :                     // Calculate for ASHRAE winter and summer conditions:
    7096             :                     // (1) nominal center-of-glass conductance, including inside and outside air films,
    7097             :                     // (2) solar heat gain coefficient (SHGC),
    7098             :                     // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
    7099             : 
    7100         675 :                     if (construct.WindowTypeEQL) {
    7101             :                         // for equivalent layer Window already calculated
    7102             :                         // NominalU(ThisNum)=NominalConductanceWinter
    7103             :                         // Save the SHGC for later use in tabular report IVRS
    7104             :                         // Construct(ThisNum)%SummerSHGC = SHGCSummer
    7105           3 :                         construct.VisTransNorm = 0.0; // TODO list
    7106             : 
    7107             :                         static constexpr std::string_view Format_799(" Construction:WindowEquivalentLayer,{},{},{},{:.3R},{:.3R},{:.3R}\n");
    7108           3 :                         print(state.files.eio,
    7109             :                               Format_799,
    7110           3 :                               construct.Name,
    7111             :                               ThisNum,
    7112           3 :                               construct.TotSolidLayers,
    7113           3 :                               state.dataHeatBal->NominalU(ThisNum),
    7114           3 :                               construct.SummerSHGC,
    7115           3 :                               construct.SolTransNorm);
    7116             : 
    7117             :                     } else {
    7118             : 
    7119         672 :                         CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
    7120             : 
    7121         672 :                         if (errFlag == 1) {
    7122           0 :                             ShowWarningError(state, format("Window construction {} has an interior or exterior blind", construct.Name));
    7123           0 :                             ShowContinueError(state, "but the corresponding construction without the blind cannot be found.");
    7124           0 :                             ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
    7125           0 :                             continue;
    7126             :                         }
    7127             : 
    7128             :                         // Skip constructions with between-glass shade/blind until method is worked out to determine
    7129             :                         // nominal conductance and SHGC.
    7130             : 
    7131         672 :                         if (errFlag == 2) {
    7132           5 :                             ShowWarningError(state, format("Window construction {} has a between-glass shade or blind", construct.Name));
    7133           5 :                             ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
    7134           5 :                             continue;
    7135             :                         }
    7136             : 
    7137         667 :                         state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
    7138         667 :                         if (!construct.WindowTypeEQL) {
    7139         667 :                             CalcNominalWindowCond(state, ThisNum, 2, NominalConductanceSummer, SHGCSummer, TransSolNorm, TransVisNorm, errFlag);
    7140             :                         }
    7141             :                         // Save the SHGC for later use in tabular report IVRS
    7142         667 :                         construct.SummerSHGC = SHGCSummer;
    7143         667 :                         construct.VisTransNorm = TransVisNorm;
    7144         667 :                         construct.SolTransNorm = TransSolNorm;
    7145             : 
    7146             :                         static constexpr std::string_view Format_700(" WindowConstruction,{},{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    7147        1334 :                         print(state.files.eio,
    7148             :                               Format_700,
    7149         667 :                               construct.Name,
    7150             :                               ThisNum,
    7151         667 :                               construct.TotLayers,
    7152         667 :                               Roughness(static_cast<int>(construct.OutsideRoughness)),
    7153             :                               NominalConductanceWinter,
    7154         667 :                               state.dataHeatBal->NominalUBeforeAdjusted(ThisNum),
    7155         667 :                               state.dataHeatBal->CoeffAdjRatio(ThisNum),
    7156             :                               SHGCSummer,
    7157             :                               TransSolNorm,
    7158             :                               TransVisNorm);
    7159             :                     }
    7160             :                     //    Write(OutputFileConstrainParams, 705)  TRIM(Construct(ThisNum)%Name), SHGCSummer ,TransVisNorm
    7161             : 
    7162        2099 :                     for (int i = 1; i <= construct.TotLayers; ++i) {
    7163        1429 :                         Layer = construct.LayerPoint(i);
    7164        1429 :                         auto const *mat = state.dataMaterial->Material(Layer);
    7165             : 
    7166        1429 :                         switch (mat->group) {
    7167         347 :                         case Material::Group::WindowGas: {
    7168         347 :                             auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
    7169         347 :                             assert(matGas != nullptr);
    7170             :                             static constexpr std::string_view Format_702(" WindowMaterial:Gas,{},{},{:.3R}\n");
    7171         347 :                             print(state.files.eio, Format_702, matGas->Name, Material::gasTypeNames[(int)matGas->gases[0].type], matGas->Thickness);
    7172             :                             //! fw CASE(WindowGasMixture)
    7173         347 :                         } break;
    7174          18 :                         case Material::Group::Shade: {
    7175          18 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7176          18 :                             assert(thisMaterial != nullptr);
    7177             : 
    7178             :                             static constexpr std::string_view Format_703(" WindowMaterial:Shade,,{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    7179          18 :                             print(state.files.eio,
    7180             :                                   Format_703,
    7181          18 :                                   thisMaterial->Name,
    7182          18 :                                   thisMaterial->Thickness,
    7183          18 :                                   thisMaterial->Conductivity,
    7184          18 :                                   thisMaterial->AbsorpThermal,
    7185          18 :                                   thisMaterial->Trans,
    7186          18 :                                   thisMaterial->TransVis,
    7187          18 :                                   thisMaterial->ReflectShade);
    7188          18 :                         } break;
    7189          13 :                         case Material::Group::WindowBlind: {
    7190          13 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7191          13 :                             assert(thisMaterial != nullptr);
    7192          13 :                             BlNum = thisMaterial->BlindDataPtr;
    7193          13 :                             auto const &blind = state.dataMaterial->Blind(BlNum);
    7194             :                             static constexpr std::string_view Format_704(
    7195             :                                 " WindowMaterial:Blind,{},{:.4R},{:.4R},{:.4R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
    7196          13 :                             print(state.files.eio,
    7197             :                                   Format_704,
    7198          13 :                                   thisMaterial->Name,
    7199          13 :                                   blind.SlatWidth,
    7200          13 :                                   blind.SlatSeparation,
    7201          13 :                                   blind.SlatThickness,
    7202          13 :                                   blind.SlatAngle,
    7203          13 :                                   blind.SlatTransSolBeamDiff,
    7204          13 :                                   blind.SlatFrontReflSolBeamDiff,
    7205          13 :                                   blind.BlindToGlassDist);
    7206          13 :                         } break;
    7207           2 :                         case Material::Group::Screen: {
    7208           2 :                             auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(mat);
    7209           2 :                             assert(matScreen != nullptr);
    7210           2 :                             auto const &btar = matScreen->btars[0][0]; // AR: Going with normal incidence here
    7211             : 
    7212             :                             static constexpr std::string_view Format_706 =
    7213             :                                 " WindowMaterial:Screen,{},{:.5R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n";
    7214             : 
    7215             :                             // AR: assuming normal incidence
    7216           2 :                             print(state.files.eio,
    7217             :                                   Format_706,
    7218           2 :                                   matScreen->Name,
    7219           2 :                                   matScreen->Thickness,
    7220           2 :                                   matScreen->Conductivity,
    7221           2 :                                   matScreen->AbsorpThermal,
    7222           2 :                                   btar.BmTrans,
    7223           2 :                                   btar.RefSolFront,
    7224           2 :                                   btar.RefVisFront,
    7225           2 :                                   matScreen->DfRef,
    7226           2 :                                   matScreen->DfRefVis,
    7227           2 :                                   matScreen->diameterToSpacingRatio,
    7228           2 :                                   matScreen->toGlassDist);
    7229           2 :                         } break;
    7230        1022 :                         case Material::Group::WindowGlass:
    7231             :                         case Material::Group::WindowSimpleGlazing: {
    7232        1022 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7233        1022 :                             assert(thisMaterial != nullptr);
    7234        1022 :                             SolarDiffusing = "No";
    7235        1022 :                             if (thisMaterial->SolarDiffusing) SolarDiffusing = "Yes";
    7236        1022 :                             OpticalDataType = "SpectralAverage";
    7237        1022 :                             SpectralDataName = "";
    7238        1022 :                             if (thisMaterial->GlassSpectralDataPtr > 0) {
    7239         181 :                                 OpticalDataType = "Spectral";
    7240         181 :                                 SpectralDataName = state.dataHeatBal->SpectralData(thisMaterial->GlassSpectralDataPtr).Name;
    7241             :                             }
    7242        1022 :                             if (thisMaterial->GlassSpectralAndAngle) {
    7243           0 :                                 OpticalDataType = "SpectralAndAngle";
    7244           0 :                                 SpectralDataName = state.dataCurveManager->PerfCurve(thisMaterial->GlassSpecAngTransDataPtr)->Name + ", " +
    7245           0 :                                                    state.dataCurveManager->PerfCurve(thisMaterial->GlassSpecAngFRefleDataPtr)->Name + ", " +
    7246           0 :                                                    state.dataCurveManager->PerfCurve(thisMaterial->GlassSpecAngBRefleDataPtr)->Name;
    7247             :                             }
    7248             :                             static constexpr std::string_view Format_707(
    7249             :                                 " WindowMaterial:Glazing,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{"
    7250             :                                 ":.5R},{:.5R},{:.5R},{:.5R},{:.5R},{}\n");
    7251        1022 :                             print(state.files.eio,
    7252             :                                   Format_707,
    7253        1022 :                                   thisMaterial->Name,
    7254             :                                   OpticalDataType,
    7255             :                                   SpectralDataName,
    7256        1022 :                                   thisMaterial->Thickness,
    7257        1022 :                                   thisMaterial->Trans,
    7258        1022 :                                   thisMaterial->ReflectSolBeamFront,
    7259        1022 :                                   thisMaterial->ReflectSolBeamBack,
    7260        1022 :                                   thisMaterial->TransVis,
    7261        1022 :                                   thisMaterial->ReflectVisBeamFront,
    7262        1022 :                                   thisMaterial->ReflectVisBeamBack,
    7263        1022 :                                   thisMaterial->TransThermal,
    7264        1022 :                                   thisMaterial->AbsorpThermalFront,
    7265        1022 :                                   thisMaterial->AbsorpThermalBack,
    7266        1022 :                                   thisMaterial->Conductivity,
    7267        1022 :                                   thisMaterial->GlassTransDirtFactor,
    7268             :                                   SolarDiffusing);
    7269        1022 :                         } break;
    7270           8 :                         case Material::Group::GlassEquivalentLayer: {
    7271           8 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7272           8 :                             assert(thisMaterial != nullptr);
    7273           8 :                             OpticalDataType = "SpectralAverage";
    7274           8 :                             SpectralDataName = "";
    7275             :                             static constexpr std::string_view Format_708(
    7276             :                                 " WindowMaterial:Glazing:EquivalentLayer,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}"
    7277             :                                 ",{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}\n");
    7278           8 :                             print(state.files.eio,
    7279             :                                   Format_708,
    7280           8 :                                   thisMaterial->Name,
    7281             :                                   OpticalDataType,
    7282             :                                   SpectralDataName,
    7283           8 :                                   thisMaterial->TausFrontBeamBeam,
    7284           8 :                                   thisMaterial->TausBackBeamBeam,
    7285           8 :                                   thisMaterial->ReflFrontBeamBeam,
    7286           8 :                                   thisMaterial->ReflBackBeamBeam,
    7287           8 :                                   thisMaterial->TausFrontBeamDiff,
    7288           8 :                                   thisMaterial->TausBackBeamDiff,
    7289           8 :                                   thisMaterial->ReflFrontBeamDiff,
    7290           8 :                                   thisMaterial->ReflBackBeamDiff,
    7291           8 :                                   thisMaterial->TausDiffDiff,
    7292           8 :                                   thisMaterial->ReflFrontDiffDiff,
    7293           8 :                                   thisMaterial->ReflBackDiffDiff,
    7294           8 :                                   thisMaterial->TausThermal,
    7295           8 :                                   thisMaterial->EmissThermalFront,
    7296           8 :                                   thisMaterial->EmissThermalBack);
    7297           8 :                         } break;
    7298           2 :                         case Material::Group::ShadeEquivalentLayer: {
    7299           2 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7300           2 :                             assert(thisMaterial != nullptr);
    7301             :                             static constexpr std::string_view Format_709(
    7302             :                                 " WindowMaterial:Shade:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}\n");
    7303           2 :                             print(state.files.eio,
    7304             :                                   Format_709,
    7305           2 :                                   thisMaterial->Name,
    7306           2 :                                   thisMaterial->TausFrontBeamBeam,
    7307           2 :                                   thisMaterial->TausBackBeamBeam,
    7308           2 :                                   thisMaterial->TausFrontBeamDiff,
    7309           2 :                                   thisMaterial->TausBackBeamDiff,
    7310           2 :                                   thisMaterial->ReflFrontBeamDiff,
    7311           2 :                                   thisMaterial->ReflBackBeamDiff,
    7312           2 :                                   thisMaterial->TausThermal,
    7313           2 :                                   thisMaterial->EmissThermalFront,
    7314           2 :                                   thisMaterial->EmissThermalBack);
    7315           2 :                         } break;
    7316           0 :                         case Material::Group::DrapeEquivalentLayer: {
    7317           0 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7318           0 :                             assert(thisMaterial != nullptr);
    7319             :                             static constexpr std::string_view Format_710(
    7320             :                                 " WindowMaterial:Drape:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},"
    7321             :                                 "{:.4R},{:.4R},{:.5R},{:.5R}\n");
    7322           0 :                             print(state.files.eio,
    7323             :                                   Format_710,
    7324           0 :                                   thisMaterial->Name,
    7325           0 :                                   thisMaterial->TausFrontBeamBeam,
    7326           0 :                                   thisMaterial->TausFrontBeamDiff,
    7327           0 :                                   thisMaterial->TausBackBeamDiff,
    7328           0 :                                   thisMaterial->ReflFrontBeamDiff,
    7329           0 :                                   thisMaterial->ReflBackBeamDiff,
    7330           0 :                                   thisMaterial->TausThermal,
    7331           0 :                                   thisMaterial->EmissThermalFront,
    7332           0 :                                   thisMaterial->EmissThermalBack,
    7333           0 :                                   thisMaterial->PleatedDrapeWidth,
    7334           0 :                                   thisMaterial->PleatedDrapeLength);
    7335           0 :                         } break;
    7336           1 :                         case Material::Group::ScreenEquivalentLayer: {
    7337           1 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7338           1 :                             assert(thisMaterial != nullptr);
    7339             :                             static constexpr std::string_view Format_711(
    7340             :                                 " WindowMaterial:Screen:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}"
    7341             :                                 ",{:.4R},{:.4R},{:.5R},{:.5R}\n");
    7342           1 :                             print(state.files.eio,
    7343             :                                   Format_711,
    7344           1 :                                   thisMaterial->Name,
    7345           1 :                                   thisMaterial->TausFrontBeamBeam,
    7346           1 :                                   thisMaterial->TausFrontBeamDiff,
    7347           1 :                                   thisMaterial->TausBackBeamDiff,
    7348           1 :                                   thisMaterial->ReflFrontBeamDiff,
    7349           1 :                                   thisMaterial->ReflBackBeamDiff,
    7350           1 :                                   thisMaterial->TausThermal,
    7351           1 :                                   thisMaterial->EmissThermalFront,
    7352           1 :                                   thisMaterial->EmissThermalBack,
    7353           1 :                                   thisMaterial->ScreenWireSpacing,
    7354           1 :                                   thisMaterial->ScreenWireDiameter);
    7355           1 :                         } break;
    7356           0 :                         case Material::Group::BlindEquivalentLayer: {
    7357           0 :                             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
    7358           0 :                             assert(thisMaterial != nullptr);
    7359           0 :                             SlateOrientation = "Horizontal";
    7360           0 :                             if (thisMaterial->SlatOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
    7361           0 :                                 SlateOrientation = "Vertical";
    7362             :                             }
    7363             :                             // Formats
    7364             :                             static constexpr std::string_view Format_712(
    7365             :                                 " WindowMaterial:Blind:EquivalentLayer,{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:."
    7366             :                                 "5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}");
    7367           0 :                             print(state.files.eio,
    7368             :                                   Format_712,
    7369           0 :                                   thisMaterial->Name,
    7370             :                                   SlateOrientation,
    7371           0 :                                   thisMaterial->SlatWidth,
    7372           0 :                                   thisMaterial->SlatSeparation,
    7373           0 :                                   thisMaterial->SlatCrown,
    7374           0 :                                   thisMaterial->SlatAngle,
    7375           0 :                                   thisMaterial->TausFrontBeamDiff,
    7376           0 :                                   thisMaterial->TausBackBeamDiff,
    7377           0 :                                   thisMaterial->ReflFrontBeamDiff,
    7378           0 :                                   thisMaterial->ReflBackBeamDiff,
    7379           0 :                                   thisMaterial->TausDiffDiff,
    7380           0 :                                   thisMaterial->ReflFrontDiffDiff,
    7381           0 :                                   thisMaterial->ReflBackDiffDiff,
    7382           0 :                                   thisMaterial->TausThermal,
    7383           0 :                                   thisMaterial->EmissThermalFront,
    7384           0 :                                   thisMaterial->EmissThermalBack);
    7385           0 :                         } break;
    7386           8 :                         case Material::Group::GapEquivalentLayer: {
    7387           8 :                             auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
    7388           8 :                             assert(matGas != nullptr);
    7389             :                             static constexpr std::string_view Format_713(" WindowMaterial:Gap:EquivalentLayer,{},{},{:.3R},{}\n");
    7390           8 :                             print(state.files.eio,
    7391             :                                   Format_713,
    7392           8 :                                   matGas->Name,
    7393           8 :                                   Material::gasTypeNames[(int)matGas->gases[0].type],
    7394           8 :                                   matGas->Thickness,
    7395           8 :                                   Material::gapVentTypeNames[(int)matGas->gapVentType]);
    7396           8 :                         } break;
    7397           8 :                         default:
    7398           8 :                             break;
    7399             :                         }
    7400             :                     } // for (i)
    7401             :                 }     // if (construct.TypeIsWindow)
    7402             :             }         // for (ThisNum)
    7403             : 
    7404         525 :         } else if (wm->HasWindows) {
    7405             : 
    7406        3407 :             for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
    7407        2979 :                 auto &construct = state.dataConstruction->Construct(ThisNum);
    7408        2979 :                 if (!construct.TypeIsWindow) continue;
    7409         678 :                 if (construct.WindowTypeEQL) continue; // skip if equivalent layer window
    7410             : 
    7411             :                 // Calculate for ASHRAE winter and summer conditions: (1)nominal center-of-glass conductance,
    7412             :                 // (2) solar heat gain coefficient (SHGC), including inside and outside air films,
    7413             :                 // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
    7414             : 
    7415         678 :                 CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
    7416         678 :                 if (errFlag == 1 || errFlag == 2) continue;
    7417         678 :                 state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
    7418             :                 // Need to have this because of window assembly reports (Simon)
    7419         678 :                 construct.SummerSHGC = SHGCSummer;
    7420         678 :                 construct.VisTransNorm = TransVisNorm;
    7421             :             }
    7422             :         }
    7423         793 :     } // ReportGlass()
    7424             : 
    7425             :     //*************************************************************************************
    7426             : 
    7427          18 :     void CalcWindowBlindProperties(EnergyPlusData &state)
    7428             :     {
    7429             : 
    7430             :         // SUBROUTINE INFORMATION:
    7431             :         //       AUTHOR         Hans Simmler
    7432             :         //       DATE WRITTEN   July-Aug 1995
    7433             :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    7434             :         //                      Dec 2001 (FCW): add variable slat angle
    7435             :         //       RE-ENGINEERED  na
    7436             : 
    7437             :         // PURPOSE OF THIS SUBROUTINE:
    7438             :         // Calculates solar-optical properties of a window blind
    7439             :         // from slat properties and solar profile angle. Assumes flat slats.
    7440             : 
    7441             :         // METHODOLOGY EMPLOYED:
    7442             :         // The solar profile angle is varied from -90 to +90 deg and slat angle is varied from 0 to 180deg,
    7443             :         // covering the full range of possible profile angles and slat angles.
    7444             :         // (The profile angle is defined as the angle of incidence when the radiation
    7445             :         // source is located in a plane that (1)is perpendicular to the  plane of the blinds [which is
    7446             :         // the same as the window plane] and (2) contains the slat normal vector.)
    7447             : 
    7448             :         // In the time-step calculation,the blind properties vs. profile angle and slat angle
    7449             :         // that are calculated here will be applicable to windows and slats
    7450             :         // of arbitrary orientation, and to arbitrary sun positions, as long as the appropiate
    7451             :         // profile angle is used. The slat angle for a particular window with blinds is determined
    7452             :         // each time step in subroutine WindowShadingManager on the basis of user-specified
    7453             :         // slat control options.
    7454             : 
    7455             :         // REFERENCES:
    7456             :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    7457             :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    7458             : 
    7459             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7460             : 
    7461          18 :         Array1D<Real64> bld_pr(15);                        // Slat properties
    7462          18 :         Array1D<Real64> st_lay(16);                        // Solar-optical blind/glazing system properties
    7463             :         Real64 sun_el;                                     // Solar profile angle (radians)
    7464          18 :         Array1D<Real64> sun_el_deg(Material::MaxProfAngs); // Solar profile angle (deg) corresponding to sun_el values
    7465             :         Real64 bld_el;                                     // Slat angle (elevation of slat normal vector in plane
    7466             :         //  perpendicular to window and containing the slat normal vector) (radians)
    7467             :         int IProfAng; // Profile angle index
    7468             : 
    7469          39 :         for (int BlindNum = 1; BlindNum <= state.dataHeatBal->TotBlinds; ++BlindNum) {
    7470          21 :             auto &blind = state.dataMaterial->Blind(BlindNum);
    7471             : 
    7472          21 :             bld_pr(2) = blind.SlatWidth;
    7473          21 :             bld_pr(3) = blind.SlatSeparation;
    7474             : 
    7475          63 :             for (int ISolVis = 1; ISolVis <= 2; ++ISolVis) {
    7476          42 :                 if (ISolVis == 1) { // For solar calculation
    7477          21 :                     bld_pr(4) = 0.0;
    7478          21 :                     bld_pr(5) = 0.0;
    7479          21 :                     bld_pr(6) = 0.0;
    7480          21 :                     bld_pr(7) = blind.SlatTransSolBeamDiff;
    7481          21 :                     bld_pr(8) = blind.SlatFrontReflSolBeamDiff;
    7482          21 :                     bld_pr(9) = blind.SlatBackReflSolBeamDiff;
    7483          21 :                     bld_pr(10) = blind.SlatTransSolDiffDiff;
    7484          21 :                     bld_pr(11) = blind.SlatFrontReflSolDiffDiff;
    7485          21 :                     bld_pr(12) = blind.SlatBackReflSolDiffDiff;
    7486             :                 } else { // For visible calculation
    7487          21 :                     bld_pr(4) = 0.0;
    7488          21 :                     bld_pr(5) = 0.0;
    7489          21 :                     bld_pr(6) = 0.0;
    7490          21 :                     bld_pr(7) = blind.SlatTransVisBeamDiff;
    7491          21 :                     bld_pr(8) = blind.SlatFrontReflVisBeamDiff;
    7492          21 :                     bld_pr(9) = blind.SlatBackReflVisBeamDiff;
    7493          21 :                     bld_pr(10) = blind.SlatTransVisDiffDiff;
    7494          21 :                     bld_pr(11) = blind.SlatFrontReflVisDiffDiff;
    7495          21 :                     bld_pr(12) = blind.SlatBackReflVisDiffDiff;
    7496             :                 }
    7497             :                 // For IR calculation
    7498          42 :                 bld_pr(13) = blind.SlatTransIR;
    7499          42 :                 bld_pr(14) = blind.SlatFrontEmissIR;
    7500          42 :                 bld_pr(15) = blind.SlatBackEmissIR;
    7501             : 
    7502             :                 // Calculate diffuse properties of blind. If blind has variable slat angle, &
    7503             :                 // vary slat angle from 0 to 180 deg in 10-deg steps (for Material::MaxSlatAngs = 19).
    7504             :                 // If blind has fixed slat angle, calculate properties at that angle only.
    7505             : 
    7506        1128 :                 for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
    7507             : 
    7508        1122 :                     st_lay = 0.0;
    7509        1122 :                     if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) {
    7510          36 :                         bld_el = blind.SlatAngle * Constant::DegToRadians;
    7511             :                     } else {                                                                    // Variable slat angle
    7512        1086 :                         bld_el = (Constant::Pi / (Material::MaxSlatAngs - 1)) * (ISlatAng - 1); // 0 <= bld_el <= 180 deg
    7513             :                     }
    7514        1122 :                     BlindOpticsDiffuse(state, BlindNum, ISolVis, bld_pr, bld_el, st_lay);
    7515             : 
    7516        1122 :                     if (ISolVis == 1) { // Fill blind diffuse solar and IR properties
    7517         561 :                         blind.SolFrontDiffDiffTrans(ISlatAng) = st_lay(9);
    7518         561 :                         blind.SolFrontDiffDiffRefl(ISlatAng) = st_lay(10);
    7519         561 :                         blind.SolBackDiffDiffTrans(ISlatAng) = st_lay(11);
    7520         561 :                         blind.SolBackDiffDiffRefl(ISlatAng) = st_lay(12);
    7521         561 :                         blind.SolFrontDiffAbs(ISlatAng) = max(0.0, 1.0 - st_lay(9) - st_lay(10));
    7522         561 :                         blind.SolBackDiffAbs(ISlatAng) = max(0.0, 1.0 - st_lay(11) - st_lay(12));
    7523         561 :                         blind.IRFrontTrans(ISlatAng) = st_lay(13);
    7524         561 :                         blind.IRFrontEmiss(ISlatAng) = st_lay(14);
    7525         561 :                         blind.IRBackTrans(ISlatAng) = st_lay(13);
    7526         561 :                         blind.IRBackEmiss(ISlatAng) = st_lay(15);
    7527             :                     } else { // Fill blind diffuse visible properties
    7528         561 :                         blind.VisFrontDiffDiffTrans(ISlatAng) = st_lay(9);
    7529         561 :                         blind.VisFrontDiffDiffRefl(ISlatAng) = st_lay(10);
    7530         561 :                         blind.VisBackDiffDiffTrans(ISlatAng) = st_lay(11);
    7531         561 :                         blind.VisBackDiffDiffRefl(ISlatAng) = st_lay(12);
    7532             :                     }
    7533             : 
    7534        1122 :                     if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
    7535             :                 } // End of slat angle loop
    7536             : 
    7537             :                 // Calculate beam properties of blind. Vary profile angle from -90 to +90 deg in 5-deg steps.
    7538             :                 // If blind has variable slat angle, vary slat angle from 0 to 180 deg in 10-deg steps
    7539             :                 // (for Material::MaxSlatAngs = 19). If blind has fixed slat angle, calculate properties at that angle only.
    7540             : 
    7541        1596 :                 for (int IProfAng = 1; IProfAng <= Material::MaxProfAngs; ++IProfAng) {
    7542        1554 :                     sun_el = -Constant::Pi / 2.0 + (Constant::Pi / 36.0) * (IProfAng - 1);
    7543        1554 :                     sun_el_deg(IProfAng) = 57.2958 * sun_el;
    7544             : 
    7545       41736 :                     for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
    7546       41514 :                         st_lay = 0.0;
    7547       41514 :                         if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) {
    7548        1332 :                             bld_el = blind.SlatAngle * Constant::DegToRadians;
    7549             :                         } else {                                                                    // Variable slat angle
    7550       40182 :                             bld_el = (Constant::Pi / (Material::MaxSlatAngs - 1)) * (ISlatAng - 1); // 0 <= bld_el <= 180 deg
    7551             :                         }
    7552             : 
    7553             :                         // Beam solar-optical properties of blind for given profile angle and slat angle
    7554             : 
    7555       41514 :                         BlindOpticsBeam(state, BlindNum, bld_pr, bld_el, sun_el, st_lay);
    7556             : 
    7557       41514 :                         if (ISolVis == 1) { // Fill blind beam solar properties
    7558       20757 :                             blind.SolFrontBeamBeamTrans(ISlatAng, IProfAng) = st_lay(1);
    7559       20757 :                             blind.SolFrontBeamBeamRefl(ISlatAng, IProfAng) = st_lay(2);
    7560       20757 :                             blind.SolBackBeamBeamTrans(ISlatAng, IProfAng) = st_lay(3);
    7561       20757 :                             blind.SolBackBeamBeamRefl(ISlatAng, IProfAng) = st_lay(4);
    7562       20757 :                             blind.SolFrontBeamDiffTrans(ISlatAng, IProfAng) = st_lay(5);
    7563       20757 :                             blind.SolFrontBeamDiffRefl(ISlatAng, IProfAng) = st_lay(6);
    7564       20757 :                             blind.SolBackBeamDiffTrans(ISlatAng, IProfAng) = st_lay(7);
    7565       20757 :                             blind.SolBackBeamDiffRefl(ISlatAng, IProfAng) = st_lay(8);
    7566       20757 :                             blind.SolFrontBeamAbs(ISlatAng, IProfAng) = max(0.0, 1.0 - st_lay(6) - st_lay(1) - st_lay(5));
    7567       20757 :                             blind.SolBackBeamAbs(ISlatAng, IProfAng) = max(0.0, 1.0 - st_lay(7) - st_lay(3) - st_lay(8));
    7568             : 
    7569             :                         } else { // Fill blind beam visible properties
    7570       20757 :                             blind.VisFrontBeamBeamTrans(ISlatAng, IProfAng) = st_lay(1);
    7571       20757 :                             blind.VisFrontBeamBeamRefl(ISlatAng, IProfAng) = st_lay(2);
    7572       20757 :                             blind.VisBackBeamBeamTrans(ISlatAng, IProfAng) = st_lay(3);
    7573       20757 :                             blind.VisBackBeamBeamRefl(ISlatAng, IProfAng) = st_lay(4);
    7574       20757 :                             blind.VisFrontBeamDiffTrans(ISlatAng, IProfAng) = st_lay(5);
    7575       20757 :                             blind.VisFrontBeamDiffRefl(ISlatAng, IProfAng) = st_lay(6);
    7576       20757 :                             blind.VisBackBeamDiffTrans(ISlatAng, IProfAng) = st_lay(7);
    7577       20757 :                             blind.VisBackBeamDiffRefl(ISlatAng, IProfAng) = st_lay(8);
    7578             :                         }
    7579             : 
    7580       41514 :                         if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
    7581             :                     } // End of loop over slat angles
    7582             :                 }     // End of loop over profile angles
    7583             : 
    7584          42 :                 if (ISolVis == 1) {
    7585         564 :                     for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
    7586        1122 :                         blind.SolFrontDiffDiffTransGnd(ISlatAng) =
    7587        1122 :                             DiffuseAverageProfAngGnd(blind.SolFrontBeamBeamTrans(ISlatAng, {1, Material::MaxProfAngs})) +
    7588         561 :                             DiffuseAverageProfAngGnd(blind.SolFrontBeamDiffTrans(ISlatAng, {1, Material::MaxProfAngs}));
    7589        1122 :                         blind.SolFrontDiffDiffTransSky(ISlatAng) =
    7590        1122 :                             DiffuseAverageProfAngSky(blind.SolFrontBeamBeamTrans(ISlatAng, {1, Material::MaxProfAngs})) +
    7591         561 :                             DiffuseAverageProfAngSky(blind.SolFrontBeamDiffTrans(ISlatAng, {1, Material::MaxProfAngs}));
    7592         561 :                         blind.SolFrontDiffAbsGnd(ISlatAng) = DiffuseAverageProfAngGnd(blind.SolFrontBeamAbs(ISlatAng, {1, Material::MaxProfAngs}));
    7593         561 :                         blind.SolFrontDiffAbsSky(ISlatAng) = DiffuseAverageProfAngSky(blind.SolFrontBeamAbs(ISlatAng, {1, Material::MaxProfAngs}));
    7594        1122 :                         blind.SolFrontDiffDiffReflGnd(ISlatAng) =
    7595         561 :                             DiffuseAverageProfAngGnd(blind.SolFrontBeamDiffRefl(ISlatAng, {1, Material::MaxProfAngs}));
    7596        1122 :                         blind.SolFrontDiffDiffReflSky(ISlatAng) =
    7597         561 :                             DiffuseAverageProfAngSky(blind.SolFrontBeamDiffRefl(ISlatAng, {1, Material::MaxProfAngs}));
    7598             : 
    7599             :                         // TH 2/17/2010. Added. Loop only for movable slat blinds
    7600         561 :                         if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
    7601             :                     }
    7602             :                 }
    7603             : 
    7604             :             } // End of loop over solar vs. visible properties
    7605             : 
    7606             :         } // End of loop over blinds
    7607          18 :     }     // CalcWindowBlindProperties()
    7608             : 
    7609             :     //*************************************************************************************
    7610             : 
    7611           2 :     void CalcWindowScreenProperties(EnergyPlusData &state)
    7612             :     {
    7613             : 
    7614             :         // SUBROUTINE INFORMATION:
    7615             :         //       AUTHOR         Richard Raustad
    7616             :         //       DATE WRITTEN   April 2006
    7617             :         //       MODIFIED       na
    7618             :         //       RE-ENGINEERED  na
    7619             : 
    7620             :         // PURPOSE OF THIS SUBROUTINE:
    7621             :         // Initialize static properties of window screens.
    7622             : 
    7623             :         // METHODOLOGY EMPLOYED:
    7624             :         // Loop through all surfaces to determine which window has an exterior screen. Static
    7625             :         // variables are defined here, dynamic variables are calculated in CalcScreenTransmittance.
    7626             : 
    7627             :         // Locals
    7628             :         // SUBROUTINE PARAMETER DEFINITIONS:
    7629           2 :         int constexpr M(18);
    7630           2 :         int constexpr N(18);
    7631             : 
    7632             :         int ScreenNum;        // Index to each screen used on exterior of window
    7633             :         int ConstrNumSh;      // Index to shaded construction
    7634             :         int MatNum;           // Index to material number
    7635             :         Real64 SumTrans;      // Integration variable for transmittance
    7636             :         Real64 SumTransVis;   // Integration variable for visible transmittance
    7637             :         Real64 SumReflect;    // Integration variable for reflectance
    7638             :         Real64 SumReflectVis; // Integration variable for visible reflectance
    7639             :         Real64 SumArea;       // Integration variable for area of quarter hemisphere
    7640             :         bool FoundMaterial;   // Flag to avoid printing screen transmittance data multiple times when Material:WindowScreen
    7641             :         // is used on multiple surfaces
    7642             :         bool PrintTransMap; // Flag used to print transmittance map
    7643             : 
    7644           2 :         ScreenNum = 0;
    7645             : 
    7646             :         // Pre-calculate these constants
    7647           2 :         std::vector<Real64> sunAzimuth;
    7648           2 :         std::vector<Real64> sin_sunAzimuth;
    7649           2 :         std::vector<Real64> cos_sunAzimuth;
    7650           2 :         std::vector<Real64> sunAltitude;
    7651           2 :         std::vector<Real64> sin_sunAltitude;
    7652           2 :         std::vector<Real64> cos_sunAltitude;
    7653           2 :         std::vector<Real64> skyArea;      // Area of integration
    7654           2 :         Array2D<Real64> relativeAzimuth;  // Relative azimuth angle of sun with respect to surface outward normal
    7655           2 :         Array2D<Real64> relativeAltitude; // Relative altitude angle of sun with respect to surface outward normal
    7656             : 
    7657           2 :         relativeAzimuth.allocate(N, M);
    7658           2 :         relativeAltitude.allocate(N, M);
    7659             : 
    7660          38 :         for (int j = 0; j <= N - 1; ++j) {
    7661          36 :             Real64 currAzimuth = (90.0 / N) * j * Constant::DegToRadians;
    7662          36 :             sunAzimuth.push_back(currAzimuth); // Azimuth angle of sun during integration
    7663          36 :             sin_sunAzimuth.push_back(std::sin(currAzimuth));
    7664          36 :             cos_sunAzimuth.push_back(std::cos(currAzimuth));
    7665             :         }
    7666             : 
    7667          38 :         for (int i = 0; i <= M - 1; ++i) {
    7668          36 :             Real64 currAltitude = (90.0 / M) * i * Constant::DegToRadians;
    7669          36 :             sunAltitude.push_back(currAltitude); // Altitude angle of sun during integration
    7670          36 :             sin_sunAltitude.push_back(std::sin(currAltitude));
    7671          36 :             cos_sunAltitude.push_back(std::cos(currAltitude));
    7672          36 :             skyArea.push_back(sin_sunAltitude[i] * cos_sunAltitude[i]);
    7673             :         }
    7674             : 
    7675          38 :         for (int j = 1; j <= N; ++j) {
    7676         684 :             for (int i = 1; i <= M; ++i) {
    7677             :                 // Integrate transmittance using coordinate transform
    7678         648 :                 relativeAzimuth(i, j) = std::asin(sin_sunAltitude[i - 1] * cos_sunAzimuth[j - 1]);        // phi prime
    7679         648 :                 relativeAltitude(i, j) = std::atan(std::tan(sunAltitude[i - 1]) * sin_sunAzimuth[j - 1]); // alpha
    7680             :             }
    7681             :         }
    7682             : 
    7683           2 :         PrintTransMap = false;
    7684             : 
    7685         192 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    7686         190 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    7687             : 
    7688         216 :             if (!surf.HasShadeControl) continue;
    7689             : 
    7690          28 :             if (state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl).ShadingType != WinShadingType::ExtScreen) continue;
    7691             : 
    7692           8 :             ConstrNumSh = surf.activeShadedConstruction;
    7693           8 :             MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
    7694           8 :             auto *matScreen = dynamic_cast<Material::MaterialScreen *>(state.dataMaterial->Material(MatNum));
    7695           8 :             assert(matScreen != nullptr);
    7696           8 :             state.dataSurface->SurfaceWindow(SurfNum).screenNum = MatNum;
    7697             : 
    7698           8 :             if (matScreen->isUsed) continue; // Has already been initalized
    7699             : 
    7700           2 :             matScreen->isUsed = true;
    7701           2 :             if (matScreen->mapDegResolution > 0) PrintTransMap = true;
    7702             : 
    7703             :             //     If a screen material is used more than once, the Material structure's screen data pointer holds the screen number
    7704             :             //     of the last window surface. Use this method to access the screen parameter's only for static variables such as
    7705             :             //     diffuse properties (InitGlassOpticalCalculations). For all cases where the screen properties are a function of
    7706             :             //     sun azimuth and altitude angles, use the Screens structure.
    7707             :             //     Invert calculation done in GetMaterialInput to find Diameter to Spacing ratio (Props(7)/Props(6))
    7708             :             //     dataMaterial.Material(MaterNum)%Trans = (1 - MaterialProps(7)/MaterialProps(6))**2.0
    7709           2 :             matScreen->diameterToSpacingRatio = 1.0 - std::sqrt(matScreen->Trans);
    7710             : 
    7711             :             // Reflectance of screen material only
    7712           2 :             matScreen->CylinderRef = matScreen->ShadeRef / (1 - matScreen->Trans);
    7713           2 :             matScreen->CylinderRefVis = matScreen->ShadeRefVis / (1 - matScreen->Trans);
    7714             : 
    7715             :             //     Integrate the transmittance over a quarter hemisphere for use in diffuse calculations
    7716           2 :             SumTrans = 0.0;
    7717           2 :             SumTransVis = 0.0;
    7718           2 :             SumReflect = 0.0;
    7719           2 :             SumReflectVis = 0.0;
    7720           2 :             SumArea = 0.0;
    7721             :             //     Integration over quarter hemisphere in polar coordinates and converting to rectangular to call screen model.
    7722             :             //     Proceed in reverse order such that the last calculation yields zero sun angle to window screen normal (angles=0,0).
    7723             :             //     The properties calculated at zero sun angle are then used elsewhere prior to the start of the actual simulation.
    7724             : 
    7725           2 :             Material::ScreenBmTransAbsRef btar;
    7726             : 
    7727          38 :             for (int j = N; j >= 1; --j) {
    7728         684 :                 for (int i = M; i >= 1; --i) {
    7729             :                     // Integrate transmittance using coordinate transform
    7730             :                     // TODO: switch to interpolation?
    7731         648 :                     CalcScreenTransmittance(state, matScreen, relativeAltitude(i, j), relativeAzimuth(i, j), btar);
    7732         648 :                     SumTrans += (btar.BmTrans + btar.DfTrans) * skyArea[i - 1];
    7733         648 :                     SumTransVis += (btar.BmTransVis + btar.DfTransVis) * skyArea[i - 1];
    7734         648 :                     SumReflect += btar.RefSolFront * skyArea[i - 1];
    7735         648 :                     SumReflectVis += btar.RefVisFront * skyArea[i - 1];
    7736         648 :                     SumArea += skyArea[i - 1];
    7737             :                 }
    7738             :             }
    7739             : 
    7740             :             // Reflectance of overall screen including openings and scattered transmittance
    7741           2 :             matScreen->ShadeRef = matScreen->CylinderRef * (1.0 - (btar.BmTrans + btar.DfTrans));
    7742           2 :             matScreen->ShadeRefVis = matScreen->CylinderRefVis * (1.0 - (btar.BmTransVis + btar.DfTransVis));
    7743             : 
    7744           2 :             if (SumArea != 0) {
    7745           2 :                 matScreen->DfTrans = SumTrans / SumArea;
    7746           2 :                 matScreen->DfTransVis = SumTransVis / SumArea;
    7747           2 :                 matScreen->DfRef = SumReflect / SumArea;
    7748           2 :                 matScreen->DfRefVis = SumReflectVis / SumArea;
    7749             :             }
    7750           2 :             matScreen->DfAbs = max(0.0, (1.0 - matScreen->DfTrans - matScreen->DfRef));
    7751             : 
    7752           2 :             matScreen->AbsorpThermalBack = matScreen->DfAbs;
    7753           2 :             matScreen->AbsorpThermalFront = matScreen->DfAbs;
    7754           2 :             matScreen->ReflectSolBeamFront = matScreen->DfRef;
    7755           2 :             matScreen->ReflectSolBeamBack = matScreen->DfRef;
    7756             : 
    7757             :             // Initialize incident-angle dependent beam matrix (will interpolate from this)
    7758          76 :             for (int ip = 0; ip < Material::maxIPhi; ++ip) {
    7759          74 :                 Real64 Phi = ip * matScreen->dPhi;
    7760        2812 :                 for (int it = 0; it < Material::maxITheta; ++it) {
    7761        2738 :                     Real64 Theta = it * matScreen->dTheta;
    7762        2738 :                     CalcScreenTransmittance(state, matScreen, Phi, Theta, matScreen->btars[ip][it]);
    7763             :                 }
    7764             :             }
    7765             : 
    7766             :         } // for (SurfNum)
    7767             : 
    7768             :         // Write transmittance versus direct normal angle to csv file
    7769             : 
    7770           2 :         if (PrintTransMap) {
    7771             :             // Fortran version did not have error handling in case of file open failure. This one does.
    7772             :             // Which is correct?
    7773           4 :             auto screenCsvFile = state.files.screenCsv.open(state, "CalcWindowScreenComponents", state.files.outputControl.screen);
    7774             : 
    7775             :             //  WRITE(ScreenTransUnitNo,*)' '
    7776          41 :             for (auto *mat : state.dataMaterial->Material) {
    7777             : 
    7778          39 :                 if (mat->group != Material::Group::Screen) continue;
    7779           2 :                 if (!mat->isUsed) continue;
    7780             : 
    7781           2 :                 auto *screen = dynamic_cast<Material::MaterialScreen *>(mat);
    7782           2 :                 assert(screen != nullptr);
    7783             : 
    7784             :                 //   Do not print transmittance map if angle increment is equal to 0
    7785           2 :                 if (screen->mapDegResolution == 0) continue;
    7786             : 
    7787           2 :                 int maxIPrint = int(90 / screen->mapDegResolution);
    7788             : 
    7789           2 :                 print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
    7790           2 :                 print(screenCsvFile,
    7791             :                       "Tabular data for beam solar transmittance at varying \"relative\" azimuth (row) and "
    7792             :                       "altitude (column) angles (deg) [relative to surface normal].\n");
    7793          40 :                 for (int it = maxIPrint; it >= 0; --it) {
    7794          38 :                     print(screenCsvFile, ",{}", it * screen->mapDegResolution);
    7795             :                 }
    7796           2 :                 print(screenCsvFile, "\n");
    7797             : 
    7798          40 :                 for (int it = 0; it <= maxIPrint; ++it) {
    7799          38 :                     print(screenCsvFile, "{}", it * screen->mapDegResolution);
    7800         760 :                     for (int ip = maxIPrint; ip >= 0; --ip) {
    7801         722 :                         Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
    7802         722 :                         Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
    7803             :                         int ip1, ip2, it1, it2;
    7804             :                         General::BilinearInterpCoeffs coeffs;
    7805         722 :                         Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
    7806         722 :                         GetBilinearInterpCoeffs(
    7807         722 :                             phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
    7808         722 :                         Real64 bmTrans = BilinearInterp(screen->btars[ip1][it1].BmTrans,
    7809         722 :                                                         screen->btars[ip1][it2].BmTrans,
    7810         722 :                                                         screen->btars[ip2][it1].BmTrans,
    7811         722 :                                                         screen->btars[ip2][it2].BmTrans,
    7812         722 :                                                         coeffs);
    7813             :                         // bmTrans = screen->btars[ip][it].BmTrans;
    7814         722 :                         print(screenCsvFile, ",{:.6R}", bmTrans);
    7815             :                     }
    7816          38 :                     print(screenCsvFile, "\n");
    7817             :                 }
    7818           2 :                 print(screenCsvFile, "\n\n");
    7819             : 
    7820           2 :                 print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
    7821           2 :                 print(screenCsvFile,
    7822             :                       "Tabular data for scattered solar transmittance at varying \"relative\" azimuth (row) and "
    7823             :                       "altitude (column) angles (deg) [relative to surface normal].\n");
    7824             : 
    7825          40 :                 for (int it = 0; it <= maxIPrint; ++it) {
    7826          38 :                     print(screenCsvFile, ",{}", it * screen->mapDegResolution);
    7827             :                 }
    7828           2 :                 print(screenCsvFile, "\n");
    7829             : 
    7830          40 :                 for (int it = 0; it <= maxIPrint; ++it) {
    7831          38 :                     print(screenCsvFile, "{}", it * screen->mapDegResolution);
    7832         760 :                     for (int ip = 0; ip <= maxIPrint; ++ip) {
    7833         722 :                         Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
    7834         722 :                         Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
    7835             :                         int ip1, ip2, it1, it2;
    7836             :                         General::BilinearInterpCoeffs coeffs;
    7837         722 :                         Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
    7838         722 :                         GetBilinearInterpCoeffs(
    7839         722 :                             phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
    7840         722 :                         Real64 dfTrans = BilinearInterp(screen->btars[ip1][it1].DfTrans,
    7841         722 :                                                         screen->btars[ip1][it2].DfTrans,
    7842         722 :                                                         screen->btars[ip2][it1].DfTrans,
    7843         722 :                                                         screen->btars[ip2][it2].DfTrans,
    7844         722 :                                                         coeffs);
    7845             : 
    7846             :                         // dfTrans = screen->btars[ip][it].DfTrans;
    7847         722 :                         print(screenCsvFile, ",{:.6R}", dfTrans);
    7848             :                     }
    7849          38 :                     print(screenCsvFile, "\n");
    7850             :                 }
    7851           2 :                 print(screenCsvFile, "\n\n");
    7852           2 :             }
    7853           2 :         } // if (PrintTransMap)
    7854           2 :     }     // CalcWindowScreenProperties()
    7855             : 
    7856        1122 :     void BlindOpticsDiffuse(EnergyPlusData &state,
    7857             :                             int const BlindNum,      // Blind number
    7858             :                             int const ISolVis,       // 1 = solar and IR calculation; 2 = visible calculation
    7859             :                             Array1A<Real64> const c, // Slat properties
    7860             :                             Real64 const b_el,       // Slat elevation (radians)
    7861             :                             Array1A<Real64> p        // Blind properties
    7862             :     )
    7863             :     {
    7864             : 
    7865             :         // SUBROUTINE INFORMATION:
    7866             :         //       AUTHOR         Hans Simmler
    7867             :         //       DATE WRITTEN   July-Aug 1995
    7868             :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    7869             :         //                      Aug 2002 (FCW): make corrections so that calculations are consistent with
    7870             :         //                       G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
    7871             :         //                      interchanged in F, so that
    7872             :         //                       G(i) = Sum over j of J(j)*F(i,j), which is wrong.
    7873             :         //                      This change was made to resolve discrepancies between EnergyPlus results
    7874             :         //                      and blind transmittance measurements made at Oklahoma State Univ.
    7875             :         //                      Feb 2004 (FCW): modify slat edge correction calc to avoid possible divide by zero
    7876             :         //       RE-ENGINEERED  na
    7877             : 
    7878             :         // PURPOSE OF THIS SUBROUTINE:
    7879             :         // From the slat properties, calculates the diffuse solar, diffuse visible and IR
    7880             :         // transmission and reflection properties of a window blind.
    7881             : 
    7882             :         // METHODOLOGY EMPLOYED:
    7883             :         // na
    7884             : 
    7885             :         // REFERENCES:
    7886             :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    7887             :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    7888             : 
    7889             :         // Argument array dimensioning
    7890        1122 :         c.dim(15);
    7891        1122 :         p.dim(16);
    7892             : 
    7893             :         Real64 ri; // Front and back IR slat reflectance
    7894             :         Real64 rib;
    7895             :         Real64 phib;                     // Elevation of slat normal vector (radians)
    7896             :         Real64 phis;                     // Source elevation (radians)
    7897             :         Real64 delphis;                  // Angle increment for integration over source distribution (radians)
    7898        1122 :         Array1D<Real64> fEdgeSource(10); // Slat edge correction factor vs source elevation
    7899        1122 :         Array1D<Real64> fEdgeA(2);       // Average slat edge correction factor for upper and lower quadrants
    7900             :         //  seen by window blind
    7901             :         Real64 gamma; // phib - phis
    7902             :         int Iphis;    // Source elevation counter
    7903             :         int IUpDown;  // =1 for source in upper quadrant, =2 for source in lower quadrant
    7904             :         Real64 fEdge; // Slat edge correction factor
    7905             :         Real64 fEdge1;
    7906        1122 :         Array1D<Real64> j(6);       // Slat section radiosity vector
    7907        1122 :         Array1D<Real64> G(6);       // Slat section irradiance vector
    7908        1122 :         Array1D<Real64> Q(6);       // Slat section radiance vector
    7909        2244 :         Array2D<Real64> F(6, 6);    // View factor array
    7910        2244 :         Array2D<Real64> X(4, 4);    // Exchange matrix
    7911        2244 :         Array2D<Real64> Xinv(4, 4); // Inverse of exchange matrix
    7912             :         int k;                      // Array indices
    7913             :         int m;
    7914        1122 :         Array1D_int indx(4);     // LU decomposition indices
    7915             :         Real64 BlindIRreflFront; // Blind front IR reflectance
    7916             :         Real64 BlindIRreflBack;  // Blind back IR reflectance
    7917             : 
    7918             :         // The slat input properties are:
    7919             :         // c(1)    0. (unused)
    7920             :         // c(2)    Slat width (m)
    7921             :         // c(3)    Slat separation (m)
    7922             :         // c(4)    0. (unused)
    7923             :         // c(5)    0. (unused)
    7924             :         // c(6)    0. (unused)
    7925             :         //      The following are solar or visible properties
    7926             :         // c(7)    trans beam-diff
    7927             :         // c(8)    refl front beam-diff
    7928             :         // c(9)    refl back beam-diff
    7929             :         // c(10)   trans diff-diff
    7930             :         // c(11)   refl front diff-diff
    7931             :         // c(12)   refl back diff-diff
    7932             :         //      The following are hemispherical thermal IR properties
    7933             :         // c(13)   trans diff-diff
    7934             :         // c(14)   emiss front diff
    7935             :         // c(15)   emiss back diff
    7936             : 
    7937             :         // The calculated blind properties are:
    7938             :         //      The following are solar or visible properties
    7939             :         // p(1)    trans front beam-beam
    7940             :         // p(2)    refl front beam-beam
    7941             :         // p(3)    trans back beam-beam
    7942             :         // p(4)    refl back beam-beam
    7943             :         // p(5)    trans front beam-diff
    7944             :         // p(6)    refl front beam-diff
    7945             :         // p(7)    trans back beam-diff
    7946             :         // p(8)    refl back beam-diff
    7947             :         // p(9)    trans front diff-diff
    7948             :         // p(10)   refl front diff-diff
    7949             :         // p(11)   trans back diff-diff
    7950             :         // p(12)   refl back diff-diff
    7951             :         //      The following are IR properties
    7952             :         // p(13)   IR trans front (same as IR trans back)
    7953             :         // p(14)   IR emissivity front
    7954             :         // p(15)   IR emissivity back
    7955             :         // p(16)   0.0 (unused)
    7956             : 
    7957        1122 :         auto &blind = state.dataMaterial->Blind(BlindNum);
    7958             :         //     Calculate view factors between slat sections (slat is divided longitudinally into two equal parts)
    7959             : 
    7960        1122 :         ViewFac(c(2), c(3), b_el, Constant::PiOvr2, F);
    7961             : 
    7962             :         //     Set up exchange matrix X for diffuse properties
    7963             : 
    7964        3366 :         for (int k = 3; k <= 5; k += 2) {
    7965       11220 :             for (int m = 3; m <= 6; ++m) {
    7966        8976 :                 X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
    7967        8976 :                 X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
    7968             :             }
    7969             :         }
    7970             : 
    7971        5610 :         for (int k = 1; k <= 4; ++k) {
    7972        4488 :             ++X(k, k);
    7973             :         }
    7974             : 
    7975        1122 :         indx = 0;
    7976        1122 :         InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
    7977             : 
    7978             :         //---------Calculate diffuse short-wave properties for the front side of the blind
    7979             : 
    7980             :         //     Sources
    7981             : 
    7982        1122 :         Q(3) = c(12) * F(3, 1) + c(10) * F(4, 1);
    7983        1122 :         Q(4) = c(10) * F(3, 1) + c(11) * F(4, 1);
    7984        1122 :         Q(5) = c(12) * F(5, 1) + c(10) * F(6, 1);
    7985        1122 :         Q(6) = c(10) * F(5, 1) + c(11) * F(6, 1);
    7986             : 
    7987             :         //     Radiosities
    7988             : 
    7989        1122 :         j(1) = 1.0;
    7990        1122 :         j(2) = 0.0;
    7991        5610 :         for (int k = 3; k <= 6; ++k) {
    7992        4488 :             j(k) = 0.0;
    7993       22440 :             for (int m = 3; m <= 6; ++m) {
    7994       17952 :                 j(k) += Xinv(m - 2, k - 2) * Q(m);
    7995             :             }
    7996             :         }
    7997             : 
    7998             :         //     Irradiances
    7999             : 
    8000        7854 :         for (int k = 1; k <= 6; ++k) {
    8001        6732 :             G(k) = 0.0;
    8002       47124 :             for (int m = 1; m <= 6; ++m) {
    8003             :                 // G(k)=G(k)+F(k,m)*J(m)
    8004       40392 :                 G(k) += j(m) * F(k, m);
    8005             :             }
    8006             :         }
    8007             : 
    8008             :         //     Slat edge correction factor
    8009        1122 :         phib = b_el;
    8010        1122 :         delphis = Constant::PiOvr2 / 10.0;
    8011        3366 :         for (int IUpDown = 1; IUpDown <= 2; ++IUpDown) {
    8012       24684 :             for (int Iphis = 1; Iphis <= 10; ++Iphis) {
    8013       22440 :                 phis = -(Iphis - 0.5) * delphis;
    8014       22440 :                 if (IUpDown == 2) phis = (Iphis - 0.5) * delphis;
    8015       22440 :                 fEdgeSource(Iphis) = 0.0;
    8016       22440 :                 fEdge1 = 0.0;
    8017       22440 :                 gamma = phib - phis;
    8018       22440 :                 if (std::abs(std::sin(gamma)) > 0.01) {
    8019       22200 :                     if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
    8020       10720 :                         (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
    8021       16620 :                         fEdge1 = blind.SlatThickness * std::abs(std::sin(gamma)) /
    8022       16620 :                                  ((blind.SlatSeparation + blind.SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
    8023             :                     }
    8024       22200 :                     fEdgeSource(Iphis) = min(1.0, std::abs(fEdge1));
    8025             :                 }
    8026             :             }
    8027        2244 :             fEdgeA(IUpDown) = DiffuseAverage(fEdgeSource);
    8028             :         }
    8029        1122 :         fEdge = 0.5 * (fEdgeA(1) + fEdgeA(2));
    8030             : 
    8031             :         //     Front diffuse-diffuse transmittance (transmittance of slat edge assumed zero)
    8032        1122 :         p(9) = G(2) * (1.0 - fEdge);
    8033             : 
    8034             :         //     Front diffuse-diffuse reflectance (edge of slat is assumed to have same diffuse
    8035             :         //     reflectance as front side of slat, c(11))
    8036        1122 :         p(10) = G(1) * (1.0 - fEdge) + fEdge * c(11);
    8037             : 
    8038             :         //-----------Calculate diffuse short-wave properties for the back side of the blind
    8039             : 
    8040             :         //     Sources
    8041             : 
    8042        1122 :         Q(3) = c(12) * F(3, 2) + c(10) * F(4, 2);
    8043        1122 :         Q(4) = c(10) * F(3, 2) + c(11) * F(4, 2);
    8044        1122 :         Q(5) = c(12) * F(5, 2) + c(10) * F(6, 2);
    8045        1122 :         Q(6) = c(10) * F(5, 2) + c(11) * F(6, 2);
    8046             : 
    8047             :         //     Radiosities
    8048             : 
    8049        1122 :         j(1) = 0.0;
    8050        1122 :         j(2) = 1.0;
    8051        5610 :         for (int k = 3; k <= 6; ++k) {
    8052        4488 :             j(k) = 0.0;
    8053       22440 :             for (int m = 3; m <= 6; ++m) {
    8054       17952 :                 j(k) += Xinv(m - 2, k - 2) * Q(m);
    8055             :             }
    8056             :         }
    8057             : 
    8058             :         //     Irradiances
    8059             : 
    8060        7854 :         for (int k = 1; k <= 6; ++k) {
    8061        6732 :             G(k) = 0.0;
    8062       47124 :             for (int m = 1; m <= 6; ++m) {
    8063             :                 // G(k)=G(k)+F(k,m)*J(m)
    8064       40392 :                 G(k) += j(m) * F(k, m);
    8065             :             }
    8066             :         }
    8067             : 
    8068             :         //     Back diffuse-diffuse transmittance
    8069        1122 :         p(11) = G(1) * (1.0 - fEdge);
    8070             : 
    8071             :         //     Back hemi-hemi reflectance
    8072        1122 :         p(12) = G(2) * (1.0 - fEdge) + fEdge * c(11);
    8073             : 
    8074        1122 :         if (ISolVis == 1) {
    8075             : 
    8076             :             //-----------Calculate IR properties of the blind
    8077             :             //           (use same set of view factors as for diffuse short-wave properties)
    8078             : 
    8079             :             //     Front and back slat IR reflectances
    8080         561 :             ri = 1 - c(13) - c(14);
    8081         561 :             rib = 1 - c(13) - c(15);
    8082             : 
    8083             :             //     Set up exchange matrix X for diffuse properties
    8084             : 
    8085        1683 :             for (int k = 3; k <= 5; k += 2) {
    8086        5610 :                 for (int m = 3; m <= 6; ++m) {
    8087        4488 :                     X(m - 2, k - 2) = -rib * F(k, m) - c(13) * F(k + 1, m);
    8088        4488 :                     X(m - 2, k - 1) = -c(13) * F(k, m) - ri * F(k + 1, m);
    8089             :                 }
    8090             :             }
    8091             : 
    8092        2805 :             for (int k = 1; k <= 4; ++k) {
    8093        2244 :                 ++X(k, k);
    8094             :             }
    8095             : 
    8096         561 :             indx = 0;
    8097         561 :             InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
    8098             : 
    8099             :             //---------Calculate diffuse IR properties for the FRONT side of the blind
    8100             : 
    8101             :             //     Sources
    8102             : 
    8103         561 :             Q(3) = rib * F(3, 1) + c(13) * F(4, 1);
    8104         561 :             Q(4) = c(13) * F(3, 1) + ri * F(4, 1);
    8105         561 :             Q(5) = rib * F(5, 1) + c(13) * F(6, 1);
    8106         561 :             Q(6) = c(13) * F(5, 1) + ri * F(6, 1);
    8107             : 
    8108             :             //     Radiosities
    8109             : 
    8110         561 :             j(1) = 1.0;
    8111         561 :             j(2) = 0.0;
    8112        2805 :             for (int k = 3; k <= 6; ++k) {
    8113        2244 :                 j(k) = 0.0;
    8114       11220 :                 for (int m = 3; m <= 6; ++m) {
    8115        8976 :                     j(k) += Xinv(m - 2, k - 2) * Q(m);
    8116             :                 }
    8117             :             }
    8118             : 
    8119             :             //     Irradiances
    8120        3927 :             for (int k = 1; k <= 6; ++k) {
    8121        3366 :                 G(k) = 0.0;
    8122       23562 :                 for (int m = 1; m <= 6; ++m) {
    8123             :                     // G(k)=G(k)+F(k,m)*J(m)
    8124       20196 :                     G(k) += j(m) * F(k, m);
    8125             :                 }
    8126             :             }
    8127             : 
    8128             :             //     Front diffuse-diffuse IR transmittance (transmittance of slat edge assumed zero)
    8129         561 :             p(13) = G(2) * (1.0 - fEdge);
    8130             : 
    8131             :             //     Front diffuse-diffuse IR reflectance (edge of slat is assumed to have same IR
    8132             :             //     reflectance as front side of slat, ri)
    8133         561 :             BlindIRreflFront = G(1) * (1.0 - fEdge) + fEdge * ri;
    8134             : 
    8135             :             //     Front IR emissivity
    8136         561 :             p(14) = max(0.0001, 1.0 - p(13) - BlindIRreflFront);
    8137             : 
    8138             :             //-----------Calculate diffuse IR properties for the BACK side of the blind
    8139             : 
    8140             :             //     Sources
    8141             : 
    8142         561 :             Q(3) = rib * F(3, 2) + c(13) * F(4, 2);
    8143         561 :             Q(4) = c(13) * F(3, 2) + ri * F(4, 2);
    8144         561 :             Q(5) = rib * F(5, 2) + c(13) * F(6, 2);
    8145         561 :             Q(6) = c(13) * F(5, 2) + ri * F(6, 2);
    8146             : 
    8147             :             //     Radiosities
    8148             : 
    8149         561 :             j(1) = 0.0;
    8150         561 :             j(2) = 1.0;
    8151        2805 :             for (int k = 3; k <= 6; ++k) {
    8152        2244 :                 j(k) = 0.0;
    8153       11220 :                 for (int m = 3; m <= 6; ++m) {
    8154        8976 :                     j(k) += Xinv(m - 2, k - 2) * Q(m);
    8155             :                 }
    8156             :             }
    8157             : 
    8158             :             //     Irradiances
    8159             : 
    8160        3927 :             for (int k = 1; k <= 6; ++k) {
    8161        3366 :                 G(k) = 0.0;
    8162       23562 :                 for (int m = 1; m <= 6; ++m) {
    8163             :                     // G(k)=G(k)+F(k,m)*J(m)
    8164       20196 :                     G(k) += j(m) * F(k, m);
    8165             :                 }
    8166             :             }
    8167             : 
    8168             :             //     Back diffuse-diffuse IR reflectance
    8169         561 :             BlindIRreflBack = G(2) * (1.0 - fEdge) + fEdge * ri;
    8170             : 
    8171             :             //     Back IR emissivity
    8172         561 :             p(15) = max(0.0001, 1.0 - p(13) - BlindIRreflBack);
    8173             : 
    8174             :         } // End of IR properties calculation
    8175        1122 :     }     // BlindOpticsDiffuse()
    8176             : 
    8177             :     //**********************************************************************************************
    8178             : 
    8179       41514 :     void BlindOpticsBeam(EnergyPlusData &state,
    8180             :                          int const BlindNum,      // Blind number
    8181             :                          Array1A<Real64> const c, // Slat properties (equivalent to BLD_PR)
    8182             :                          Real64 const b_el,       // Slat elevation (radians)
    8183             :                          Real64 const s_el,       // Solar profile angle (radians)
    8184             :                          Array1A<Real64> p        // Blind properties (equivalent to ST_LAY)
    8185             :     )
    8186             :     {
    8187             : 
    8188             :         // SUBROUTINE INFORMATION:
    8189             :         //       AUTHOR         Hans Simmler
    8190             :         //       DATE WRITTEN   July-Aug 1995
    8191             :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    8192             :         //                      Aug 2002 (FCW): make corrections so that calculations are consistent with
    8193             :         //                       G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
    8194             :         //                      interchanged in F, so that
    8195             :         //                       G(i) = Sum over j of J(j)*F(i,j), which is wrong.
    8196             :         //                      This change was made to resolve discrepancies between EnergyPlus results
    8197             :         //                      and blind transmittance measurements made at Oklahoma State Univ.
    8198             :         //       RE-ENGINEERED  na
    8199             : 
    8200             :         // PURPOSE OF THIS SUBROUTINE:
    8201             :         //     Calculates the beam radiation properties of a
    8202             :         //     window blind consisting of flat slats with known material properties.
    8203             :         //     The calculation for the reverse direction is done with the radiation source
    8204             :         //     reflected at the window plane.
    8205             : 
    8206             :         // REFERENCES:
    8207             :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    8208             :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    8209             : 
    8210             :         // Argument array dimensioning
    8211       41514 :         c.dim(15);
    8212       41514 :         p.dim(16);
    8213             : 
    8214             :         struct BlindInputs
    8215             :         {
    8216             :             Real64 slatWidth;
    8217             :             Real64 slatSeparation;
    8218             :             Real64 BmDfTrans;
    8219             :             Real64 BmDfRefFront;
    8220             :             Real64 BmDfRefBack;
    8221             :             Real64 DfDfTrans;
    8222             :             Real64 DfDfRefFront;
    8223             :             Real64 DfDfRefBack;
    8224             :             Real64 DfDfTransIR;
    8225             :             Real64 DfEmissFront;
    8226             :             Real64 DfEmissBack;
    8227             :         };
    8228             : 
    8229             :         // The slat input properties are:
    8230             :         // c(1)    0. (unused)
    8231             :         // c(2)    Slat width (m)
    8232             :         // c(3)    Slat separation (m)
    8233             :         // c(4)    0. (unused)
    8234             :         // c(5)    0. (unused)
    8235             :         // c(6)    0. (unused)
    8236             :         //      The following are solar or visible properties
    8237             :         // c(7)    trans beam-diff
    8238             :         // c(8)    refl front beam-diff
    8239             :         // c(9)    refl back beam-diff
    8240             :         // c(10)   trans diff-diff
    8241             :         // c(11)   refl front diff-diff
    8242             :         // c(12)   refl back diff-diff
    8243             :         //      The following are hemispherical thermal IR properties
    8244             :         // c(13)   trans diff-diff
    8245             :         // c(14)   emiss front diff
    8246             :         // c(15)   emiss back diff
    8247             : 
    8248             :         struct BlindOutputs
    8249             :         {
    8250             :             Real64 BmBmTransFront;
    8251             :             Real64 BmBmRefFront;
    8252             :             Real64 BmBmTransBack;
    8253             :             Real64 BmBmRefBack;
    8254             :             Real64 BmDfTransFront;
    8255             :             Real64 BmDfRefFront;
    8256             :             Real64 BmDfTransBack;
    8257             :             Real64 BmDfRefBack;
    8258             :             Real64 DfDfTransFront;
    8259             :             Real64 DfDfRefFront;
    8260             :             Real64 DfDfTransBack;
    8261             :             Real64 DfDfRefBack;
    8262             : 
    8263             :             Real64 TransFrontIR;
    8264             :             Real64 TransBackIR;
    8265             :             Real64 EmissFrontIR;
    8266             :             Real64 EmissBackIR;
    8267             :         };
    8268             : 
    8269             :         // The calculated blind properties are:
    8270             :         //      The following are solar or visible properties
    8271             :         // p(1)    trans front beam-beam
    8272             :         // p(2)    refl front beam-beam
    8273             :         // p(3)    trans back beam-beam
    8274             :         // p(4)    refl back beam-beam
    8275             :         // p(5)    trans front beam-diff
    8276             :         // p(6)    refl front beam-diff
    8277             :         // p(7)    trans back beam-diff
    8278             :         // p(8)    refl back beam-diff
    8279             :         // p(9)    trans front diff-diff
    8280             :         // p(10)   refl front diff-diff
    8281             :         // p(11)   trans back diff-diff
    8282             :         // p(12)   refl back diff-diff
    8283             :         //      The following are IR properties
    8284             :         // p(13)   IR trans front (same as IR trans back)
    8285             :         // p(14)   IR emissivity front
    8286             :         // p(15)   IR emissivity back
    8287             :         // p(16)   0.0 (unused)
    8288             : 
    8289             :         Real64 phib;                // Elevation angle of normal vector to front of slat (0 to pi radians)
    8290             :         Real64 phis;                // Elevation angle of source vector; same as "profile angle" (-pi/2 to pi/2 radians)
    8291             :         Real64 gamma;               // phib - phis (radians)
    8292       41514 :         Array1D<Real64> j(6);       // Slat surface section radiosity vector
    8293       41514 :         Array1D<Real64> G(6);       // Slat surface section irradiance vector
    8294       41514 :         Array1D<Real64> Q(6);       // Slat surface section source vector
    8295       83028 :         Array2D<Real64> F(6, 6);    // View factor array
    8296       83028 :         Array2D<Real64> X(4, 4);    // X*J = Q
    8297       83028 :         Array2D<Real64> Xinv(4, 4); // J = Xinv*Q
    8298             :         Real64 fEdge;               // Slat edge correction factor
    8299             :         Real64 fEdge1;
    8300       41514 :         Array1D_int indx(4); // Indices for LU decomposition
    8301             : 
    8302       41514 :         auto const &blind = state.dataMaterial->Blind(BlindNum);
    8303             : 
    8304       41514 :         p = 0.0;
    8305             : 
    8306             :         //     Elevation of radiation source; source is assumed to be in a plane that
    8307             :         //     (1) contains the slat outward normal and (2) is perpendicular to plane of the blinds.
    8308       41514 :         phis = s_el;
    8309             : 
    8310             :         //     Elevation of slat outward normal
    8311       41514 :         phib = b_el;
    8312             : 
    8313             :         //     Loop twice for front and back side properties of blind
    8314      124542 :         for (int i = 0; i <= 2; i += 2) {
    8315             : 
    8316             :             //       For back-side properties, reflect the source position so that it is the mirror
    8317             :             //       image of the original source position, where the "mirror" is in the plane of the
    8318             :             //       blinds. This is equivalent to keeping the original source position but rotating
    8319             :             //       the slats so that the original slat angle (e.g., 45 deg) becomes 180 - original slat
    8320             :             //       angle (135 deg).
    8321             : 
    8322       83028 :             if (i == 2) {
    8323       41514 :                 phib = Constant::Pi - phib;
    8324             :             }
    8325             : 
    8326             :             //       Correction factor that accounts for finite thickness of slats. It is used to modify the
    8327             :             //       blind transmittance and reflectance to account for reflection and absorption by the
    8328             :             //       edge of the slat. fEdge is ratio of area subtended by edge of slat
    8329             :             //       to area between tops of adjacent slats.
    8330             : 
    8331       83028 :             fEdge = 0.0;
    8332       83028 :             fEdge1 = 0.0;
    8333       83028 :             gamma = phib - phis;
    8334       83028 :             if (std::abs(std::sin(gamma)) > 0.01) {
    8335       82500 :                 if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
    8336       41040 :                     (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
    8337       61116 :                     fEdge1 = blind.SlatThickness * std::abs(std::sin(gamma)) /
    8338       61116 :                              ((blind.SlatSeparation + blind.SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
    8339             :                 }
    8340       82500 :                 fEdge = min(1.0, std::abs(fEdge1));
    8341             :             }
    8342             : 
    8343             :             //       Direct-to-direct transmittance (portion of beam that passes between slats without
    8344             :             //       without touching them
    8345             : 
    8346       83028 :             p(1 + i) = BlindBeamBeamTrans(phis, phib, blind.SlatWidth, blind.SlatSeparation, blind.SlatThickness);
    8347             :             //       Direct-to-direct reflectance; this is zero for now since all reflection is assumed to be diffuse.
    8348       83028 :             p(2 + i) = 0.0;
    8349             : 
    8350             :             //       View factors between slat sections for calculating direct-to-diffuse transmittance and reflectance
    8351       83028 :             ViewFac(c(2), c(3), phib, phis, F);
    8352             : 
    8353             :             //       Set up exchange matrix X for calculating direct-to-diffuse properties
    8354             : 
    8355      249084 :             for (int k = 3; k <= 5; k += 2) {
    8356      830280 :                 for (int m = 3; m <= 6; ++m) {
    8357      664224 :                     X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
    8358      664224 :                     X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
    8359             :                 }
    8360             :             }
    8361             : 
    8362      415140 :             for (int k = 1; k <= 4; ++k) {
    8363      332112 :                 ++X(k, k);
    8364             :             }
    8365             : 
    8366       83028 :             indx = 0;
    8367             :             // In the following, note that InvertMatrix changes X
    8368       83028 :             InvertMatrix(state, X, Xinv, indx, 4);
    8369             : 
    8370             :             //       Set up sources for direct-diffuse slat properties
    8371       83028 :             if (std::abs(phis - phib) <= Constant::PiOvr2) { // Beam hits front of slat
    8372       41706 :                 Q(3) = c(4) + c(7);                          // beam-beam trans of slat + beam-diff trans of slat
    8373       41706 :                 Q(4) = c(5) + c(8);                          // front beam-beam refl of slat + front beam-diff refl of slat
    8374             :             } else {                                         // Beam hits back of slat
    8375       41322 :                 Q(3) = c(6) + c(9);                          // back beam-beam refl of slat  + back beam-diff refl of slat
    8376       41322 :                 Q(4) = c(4) + c(7);                          // beam-beam trans of slat + beam-diff trans of slat
    8377             :             }
    8378             : 
    8379             :             //       Correct for fraction of beam that is not directly transmitted; 1 - this fraction is
    8380             :             //       the fraction of the incoming beam that is incident on the front or back surfaces of the slats.
    8381       83028 :             Q(3) *= (1.0 - p(1 + i));
    8382       83028 :             Q(4) *= (1.0 - p(1 + i));
    8383             : 
    8384             :             //       Radiosities (radiance of slat sections)
    8385       83028 :             j(1) = 0.0;
    8386       83028 :             j(2) = 0.0;
    8387      415140 :             for (int k = 3; k <= 6; ++k) {
    8388      332112 :                 j(k) = 0.0;
    8389      996336 :                 for (int m = 3; m <= 4; ++m) {
    8390      664224 :                     j(k) += Xinv(m - 2, k - 2) * Q(m);
    8391             :                 }
    8392             :             }
    8393             : 
    8394             :             //       Irradiance on slat sections
    8395      581196 :             for (int k = 1; k <= 6; ++k) {
    8396      498168 :                 G(k) = 0.0;
    8397     2490840 :                 for (int m = 3; m <= 6; ++m) {
    8398     1992672 :                     G(k) += j(m) * F(k, m);
    8399             :                 }
    8400             :             }
    8401             : 
    8402             :             //       Direct-to-diffuse transmittance
    8403       83028 :             p(5 + i) = G(2) * (1.0 - fEdge);
    8404             : 
    8405             :             //       Direct-to-diffuse reflectance (assuming the edge reflectance is the same as the
    8406             :             //       reflectance of the front side of the slat, C(8))
    8407       83028 :             p(6 + i) = G(1) * (1.0 - fEdge) + fEdge * c(8);
    8408             : 
    8409             :         } // End of loop over front and back side properties of blind
    8410       41514 :     }     // BlindOpticsBeam()
    8411             : 
    8412       80784 :     Real64 InterpProfAng(Real64 const ProfAng,           // Profile angle (rad)
    8413             :                          Array1S<Real64> const PropArray // Array of blind properties
    8414             :     )
    8415             :     {
    8416             : 
    8417             :         // SUBROUTINE INFORMATION:
    8418             :         //       AUTHOR         Fred Winkelmann
    8419             :         //       DATE WRITTEN   May 2001
    8420             :         //       MODIFIED       na
    8421             :         //       RE-ENGINEERED  na
    8422             : 
    8423             :         // PURPOSE OF THIS SUBROUTINE:
    8424             :         // Does profile-angle interpolation of window blind solar-thermal properties
    8425             : 
    8426             :         // METHODOLOGY EMPLOYED:
    8427             :         // Linear interpolation.
    8428             : 
    8429             :         // DeltaAng = Pi/36
    8430       80784 :         if (ProfAng > Constant::PiOvr2 || ProfAng < -Constant::PiOvr2) {
    8431           0 :             return 0.0;
    8432             :         } else {
    8433       80784 :             Real64 constexpr DeltaAngRad(Constant::Pi / 36.0);                                             // Profile angle increment (rad)
    8434       80784 :             int IAlpha = 1 + int((ProfAng + Constant::PiOvr2) / DeltaAngRad);                              // Profile angle index
    8435       80784 :             Real64 InterpFac = (ProfAng - (-Constant::PiOvr2 + DeltaAngRad * (IAlpha - 1))) / DeltaAngRad; // Interpolation factor
    8436       80784 :             return (1.0 - InterpFac) * PropArray(IAlpha) + InterpFac * PropArray(IAlpha + 1);
    8437             :         }
    8438             :     } // InterpProfAng()
    8439             : 
    8440        5527 :     Real64 InterpSlatAng(Real64 const SlatAng,           // Slat angle (rad)
    8441             :                          bool const VarSlats,            // True if slat angle is variable
    8442             :                          Array1S<Real64> const PropArray // Array of blind properties as function of slat angle
    8443             :     )
    8444             :     {
    8445             : 
    8446             :         // SUBROUTINE INFORMATION:
    8447             :         //       AUTHOR         Fred Winkelmann
    8448             :         //       DATE WRITTEN   Dec 2001
    8449             :         //       MODIFIED       na
    8450             :         //       RE-ENGINEERED  na
    8451             : 
    8452             :         // PURPOSE OF THIS SUBROUTINE:
    8453             :         // Does slat-angle interpolation of window blind solar-thermal properties that
    8454             :         // do not depend on profile angle
    8455             : 
    8456             :         // METHODOLOGY EMPLOYED:
    8457             :         // Linear interpolation.
    8458             : 
    8459        5527 :         if (VarSlats) { // Variable-angle slats
    8460          21 :             Real64 SlatAng1 = std::clamp(SlatAng, 0.0, Constant::Pi);
    8461             :             static Real64 constexpr DeltaAng(Constant::Pi / (double(Material::MaxSlatAngs) - 1.0));
    8462             :             static Real64 constexpr DeltaAng_inv((double(Material::MaxSlatAngs) - 1.0) / Constant::Pi);
    8463          21 :             int IBeta = 1 + int(SlatAng1 * DeltaAng_inv);                          // Slat angle index
    8464          21 :             Real64 InterpFac = (SlatAng1 - DeltaAng * (IBeta - 1)) * DeltaAng_inv; // Interpolation factor
    8465          21 :             return PropArray(IBeta) + InterpFac * (PropArray(min(Material::MaxSlatAngs, IBeta + 1)) - PropArray(IBeta));
    8466             :         } else { // Fixed-angle slats or shade
    8467        5506 :             return PropArray(1);
    8468             :         }
    8469             :     } // InterpSlatAng()
    8470             : 
    8471         139 :     Real64 InterpProfSlatAng(Real64 const ProfAng,           // Profile angle (rad)
    8472             :                              Real64 const SlatAng,           // Slat angle (rad)
    8473             :                              bool const VarSlats,            // True if variable-angle slats
    8474             :                              Array2A<Real64> const PropArray // Array of blind properties
    8475             :     )
    8476             :     {
    8477             : 
    8478             :         // SUBROUTINE INFORMATION:
    8479             :         //       AUTHOR         Fred Winkelmann
    8480             :         //       DATE WRITTEN   Dec 2001
    8481             :         //       MODIFIED       na
    8482             :         //       RE-ENGINEERED  na
    8483             : 
    8484             :         // PURPOSE OF THIS SUBROUTINE:
    8485             :         // Does simultaneous profile-angle and slat-angle interpolation of window
    8486             :         // blind solar-thermal properties that depend on profile angle and slat angle
    8487             : 
    8488             :         // METHODOLOGY EMPLOYED:
    8489             :         // Linear interpolation.
    8490             : 
    8491             :         // Argument array dimensioning
    8492         139 :         PropArray.dim(Material::MaxSlatAngs, Material::MaxProfAngs);
    8493             : 
    8494         139 :         Real64 SlatAng1 = std::clamp(SlatAng, 0.0, Constant::Pi);
    8495             : 
    8496             :         // This is not correct, fixed 2/17/2010
    8497             :         // ProfAng1 = MIN(MAX(SlatAng,-PiOvr2),PiOvr2)
    8498         139 :         Real64 ProfAng1 = std::clamp(ProfAng, -Constant::PiOvr2, Constant::PiOvr2);
    8499             : 
    8500         139 :         Real64 constexpr DeltaProfAng(Constant::Pi / 36.0);
    8501         139 :         int IAlpha = int((ProfAng1 + Constant::PiOvr2) / DeltaProfAng) + 1;                               // Profile angle index
    8502         139 :         Real64 ProfAngRatio = (ProfAng1 + Constant::PiOvr2 - (IAlpha - 1) * DeltaProfAng) / DeltaProfAng; // Profile angle interpolation factor
    8503             : 
    8504             :         Real64 Val1;
    8505             :         Real64 Val2;
    8506         139 :         if (VarSlats) { // Variable-angle slats: interpolate in profile angle and slat angle
    8507          27 :             Real64 constexpr DeltaSlatAng(Constant::Pi / (double(Material::MaxSlatAngs) - 1.0));
    8508          27 :             int IBeta = int(SlatAng1 / DeltaSlatAng) + 1;                                 // Slat angle index
    8509          27 :             Real64 SlatAngRatio = (SlatAng1 - (IBeta - 1) * DeltaSlatAng) / DeltaSlatAng; // Slat angle interpolation factor
    8510          27 :             Val1 = PropArray(IBeta, IAlpha); // Property values at points enclosing the given ProfAngle and SlatAngle
    8511          27 :             Val2 = PropArray(min(Material::MaxSlatAngs, IBeta + 1), IAlpha);
    8512          27 :             Real64 Val3 = PropArray(IBeta, min(Material::MaxProfAngs, IAlpha + 1));
    8513          27 :             Real64 Val4 = PropArray(min(Material::MaxSlatAngs, IBeta + 1), min(Material::MaxProfAngs, IAlpha + 1));
    8514          27 :             Real64 ValA = Val1 + SlatAngRatio * (Val2 - Val1); // Property values at given SlatAngle to be interpolated in profile angle
    8515          27 :             Real64 ValB = Val3 + SlatAngRatio * (Val4 - Val3);
    8516          27 :             return ValA + ProfAngRatio * (ValB - ValA);
    8517             :         } else { // Fixed-angle slats: interpolate only in profile angle
    8518         112 :             Val1 = PropArray(1, IAlpha);
    8519         112 :             Val2 = PropArray(1, min(Material::MaxProfAngs, IAlpha + 1));
    8520         112 :             return Val1 + ProfAngRatio * (Val2 - Val1);
    8521             :         }
    8522             :     } // InterpProfSlatAng()
    8523             : 
    8524      161907 :     Real64 BlindBeamBeamTrans(Real64 const ProfAng,        // Solar profile angle (rad)
    8525             :                               Real64 const SlatAng,        // Slat angle (rad)
    8526             :                               Real64 const SlatWidth,      // Slat width (m)
    8527             :                               Real64 const SlatSeparation, // Slat separation (distance between surfaces of adjacent slats) (m)
    8528             :                               Real64 const SlatThickness   // Slat thickness (m)
    8529             :     )
    8530             :     {
    8531             : 
    8532             :         // FUNCTION INFORMATION:
    8533             :         //       AUTHOR         Fred Winkelmann
    8534             :         //       DATE WRITTEN   Jan 2002
    8535             :         //       MODIFIED       na
    8536             :         //       RE-ENGINEERED  na
    8537             : 
    8538             :         // PURPOSE OF THIS SUBROUTINE:
    8539             :         // Calculates beam-to-beam transmittance of a window blind
    8540             : 
    8541             :         // METHODOLOGY EMPLOYED:
    8542             :         // Based on solar profile angle and slat geometry
    8543             : 
    8544      161907 :         Real64 CosProfAng = std::cos(ProfAng); // Cosine of profile angle
    8545      161907 :         Real64 gamma = SlatAng - ProfAng;
    8546      161907 :         Real64 wbar = SlatSeparation;
    8547      161907 :         if (CosProfAng != 0.0) wbar = SlatWidth * std::cos(gamma) / CosProfAng;
    8548      161907 :         Real64 BlindBeamBeamTrans = max(0.0, 1.0 - std::abs(wbar / SlatSeparation));
    8549             : 
    8550      161907 :         if (BlindBeamBeamTrans > 0.0) {
    8551             : 
    8552             :             // Correction factor that accounts for finite thickness of slats. It is used to modify the
    8553             :             // blind transmittance to account for reflection and absorption by the slat edges.
    8554             :             // fEdge is ratio of area subtended by edge of slat to area between tops of adjacent slats.
    8555             : 
    8556       27850 :             Real64 fEdge = 0.0; // Slat edge correction factor
    8557       27850 :             Real64 fEdge1 = 0.0;
    8558       27850 :             if (std::abs(std::sin(gamma)) > 0.01) {
    8559       27850 :                 if ((SlatAng > 0.0 && SlatAng <= Constant::PiOvr2 && ProfAng <= SlatAng) ||
    8560       14022 :                     (SlatAng > Constant::PiOvr2 && SlatAng <= Constant::Pi && ProfAng > -(Constant::Pi - SlatAng)))
    8561       27850 :                     fEdge1 =
    8562       27850 :                         SlatThickness * std::abs(std::sin(gamma)) / ((SlatSeparation + SlatThickness / std::abs(std::sin(SlatAng))) * CosProfAng);
    8563       27850 :                 fEdge = min(1.0, std::abs(fEdge1));
    8564             :             }
    8565       27850 :             BlindBeamBeamTrans *= (1.0 - fEdge);
    8566             :         }
    8567             : 
    8568      161907 :         return BlindBeamBeamTrans;
    8569             :     } // BlindBeamBeamTrans()
    8570             : 
    8571             :     //********************************************************************************************
    8572             : 
    8573       84150 :     void ViewFac(Real64 const s,    // Slat width (m)
    8574             :                  Real64 const h,    // Distance between faces of adjacent slats (m)
    8575             :                  Real64 const phib, // Elevation angle of normal to slat (radians)
    8576             :                  Real64 const phis, // Profile angle of radiation source (radians)
    8577             :                  Array2A<Real64> F  // View factor array
    8578             :     )
    8579             :     {
    8580             : 
    8581             :         // SUBROUTINE INFORMATION:
    8582             :         //       AUTHOR         Hans Simmler
    8583             :         //       DATE WRITTEN   July-Aug 1995
    8584             :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    8585             :         //                      Apr 2002 (FCW): prevent sqrt of small negative argument
    8586             :         //       RE-ENGINEERED  na
    8587             : 
    8588             :         // PURPOSE OF THIS SUBROUTINE:
    8589             :         //     Calculates the view factors between sections of adjacent slats,
    8590             :         //     where each slat is divided longitudinally into two equal sections whose
    8591             :         //     dimensions depend on source profile angle and slat geometry. The view
    8592             :         //     factors are used in BlindOpticsBeam and BlindOpticsDiffuse to determine blind
    8593             :         //     transmittance and reflectance for short-wave and long-wave radiation.
    8594             : 
    8595             :         // METHODOLOGY EMPLOYED:
    8596             :         //     Uses expressions for view factor between flat strips with a common edge
    8597             :         //     and flat strips displaced from one another. See engineering documentation.
    8598             : 
    8599             :         // REFERENCES:
    8600             :         // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
    8601             :         // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
    8602             : 
    8603             :         // Argument array dimensioning
    8604       84150 :         F.dim(6, 6);
    8605             : 
    8606       84150 :         Array1D<Real64> L(6); // Length of slat sections: L1 = L2 = h; L3, L5 = length
    8607             :         Real64 L3;
    8608             :         Real64 L5;
    8609             :         //  of upper slat sections; L4, L6 = length of lower slat
    8610             :         //  slat sections (m)
    8611             :         Real64 d1; // Slat geometry variables (m)
    8612             :         Real64 d2;
    8613             :         Real64 d3;
    8614             :         Real64 d4;
    8615             :         Real64 d5;
    8616             :         Real64 d6;
    8617             :         Real64 h2; // h**2
    8618             :         Real64 ht; // 2*h
    8619             :         Real64 w;  // Slat geometry variable (m)
    8620             :         Real64 a;  // Intermediate variable (m)
    8621             :         Real64 co; // Cosine of source profile angle
    8622             : 
    8623       84150 :         h2 = pow_2(h);
    8624       84150 :         ht = 2.0 * h;
    8625       84150 :         co = std::cos(phis);
    8626       84150 :         if (std::abs(co) < 0.001) co = 0.0;
    8627       84150 :         w = ht;
    8628       84150 :         if (co != 0.0) w = s * std::cos(phib - phis) / co;
    8629       84150 :         L3 = s * h / std::abs(w);
    8630       84150 :         if (L3 > s) L3 = s;
    8631       84150 :         L5 = s - L3;
    8632       84150 :         a = ht * std::cos(phib);
    8633             :         // MAX(0.,...) in the following prevents small negative argument for sqrt
    8634       84150 :         d1 = std::sqrt(max(0.0, s * s + h2 + a * s));
    8635       84150 :         d2 = std::sqrt(max(0.0, s * s + h2 - a * s));
    8636       84150 :         d3 = std::sqrt(max(0.0, L3 * L3 + h2 + a * L3));
    8637       84150 :         d4 = std::sqrt(max(0.0, L3 * L3 + h2 - a * L3));
    8638       84150 :         d5 = std::sqrt(max(0.0, L5 * L5 + h2 - a * L5));
    8639       84150 :         d6 = std::sqrt(max(0.0, L5 * L5 + h2 + a * L5));
    8640      589050 :         for (int i = 1; i <= 6; ++i) {
    8641      504900 :             F(i, i) = 0.0;
    8642             :         }
    8643       84150 :         F(1, 1) = 0.0;
    8644       84150 :         F(2, 1) = (d1 + d2 - 2.0 * s) / ht;
    8645       84150 :         F(3, 1) = (h + L3 - d3) / ht;
    8646       84150 :         F(4, 1) = (h + L3 - d4) / ht;
    8647       84150 :         F(5, 1) = (L5 + d3 - d1) / ht;
    8648       84150 :         F(6, 1) = (L5 + d4 - d2) / ht;
    8649       84150 :         F(3, 2) = (L3 + d5 - d2) / ht;
    8650       84150 :         F(4, 2) = (L3 + d6 - d1) / ht;
    8651       84150 :         F(5, 2) = (h + L5 - d5) / ht;
    8652       84150 :         F(6, 2) = (h + L5 - d6) / ht;
    8653       84150 :         F(4, 3) = (d3 + d4 - ht) / (2.0 * L3);
    8654       84150 :         F(5, 3) = 0.0;
    8655       84150 :         F(6, 3) = (d2 + h - d4 - d5) / (2.0 * L3);
    8656       84150 :         F(5, 4) = (d1 + h - d3 - d6) / (2.0 * L3);
    8657       84150 :         F(6, 4) = 0.0;
    8658       84150 :         F(6, 5) = 0.0;
    8659       84150 :         if (L5 > 0.0) F(6, 5) = (d5 + d6 - ht) / (2.0 * L5);
    8660       84150 :         L(1) = h;
    8661       84150 :         L(2) = h;
    8662       84150 :         L(3) = L3;
    8663       84150 :         L(4) = L3;
    8664       84150 :         L(5) = L5;
    8665       84150 :         L(6) = L5;
    8666      504900 :         for (int i = 2; i <= 6; ++i) {
    8667     1683000 :             for (int j = 1; j <= i - 1; ++j) {
    8668     1262250 :                 F(j, i) = 0.0;
    8669     1262250 :                 if (L(i) > 0.0) F(j, i) = F(i, j) * L(j) / L(i);
    8670             :             }
    8671             :         }
    8672       84150 :     } // ViewFac()
    8673             : 
    8674             :     //*****************************************************************************************
    8675             : 
    8676       84711 :     void InvertMatrix(EnergyPlusData &state,
    8677             :                       Array2D<Real64> &a, // Matrix to be inverted
    8678             :                       Array2D<Real64> &y, // Inverse of matrix a
    8679             :                       Array1D_int &indx,  // Index vector for LU decomposition
    8680             :                       int const n)
    8681             :     {
    8682             : 
    8683             :         // SUBROUTINE INFORMATION:
    8684             :         //       AUTHOR         Hans Simmler
    8685             :         //       DATE WRITTEN   July-Aug 1995
    8686             :         //       MODIFIED       Aug 2001 (FCW): adapt to EnergyPlus
    8687             :         //       RE-ENGINEERED  na
    8688             : 
    8689             :         // PURPOSE OF THIS SUBROUTINE:
    8690             :         //     Inverts a matrix.
    8691             : 
    8692             :         // METHODOLOGY EMPLOYED:
    8693             :         //     Uses LU decomposition.
    8694             : 
    8695       84711 :         Array1D<Real64> tmp(n);
    8696             : 
    8697             :         int d;
    8698             : 
    8699       84711 :         y = 0.0;
    8700      423555 :         for (int i = 1; i <= n; ++i) {
    8701      338844 :             y(i, i) = 1.0;
    8702             :         }
    8703       84711 :         indx = 0;
    8704             : 
    8705       84711 :         LUdecomposition(state, a, n, indx, d);
    8706             : 
    8707      423555 :         for (int j = 1; j <= n; ++j) {
    8708      338844 :             tmp = 0.0;
    8709      338844 :             tmp(j) = 1;
    8710      338844 :             LUsolution(state, a, n, indx, tmp);
    8711     1694220 :             for (int i = 1; i <= n; ++i)
    8712     1355376 :                 y(j, i) = tmp(i);
    8713             :         }
    8714       84711 :     } // InvertMatrix()
    8715             : 
    8716             :     // added for custom solar or visible spectrum
    8717             : 
    8718         796 :     void CheckAndReadCustomSprectrumData(EnergyPlusData &state)
    8719             :     {
    8720             : 
    8721             :         // SUBROUTINE INFORMATION:
    8722             :         //       AUTHOR         T. Hong
    8723             :         //       DATE WRITTEN   August 2013
    8724             :         //       MODIFIED
    8725             :         //       RE-ENGINEERED  na
    8726             : 
    8727             :         // PURPOSE OF THIS SUBROUTINE:
    8728             :         // Check, read, and assign the custom solar or visible spectrum to:
    8729             :         //  solar: nume, wle(nume), e(nume). nume = 107
    8730             :         //  visible: numt3, wlt3(numt3), y30(numt3). numt3 = 81
    8731             :         // Three related IDD objects:
    8732             :         //  EnergyManagementSystem:ConstructionIndexVariable
    8733             :         //  Site:SolarAndVisibleSpectrum, Site:SpectrumData
    8734             : 
    8735             :         // METHODOLOGY EMPLOYED:
    8736             :         // Overwriting the default values
    8737             : 
    8738             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8739         796 :         bool ErrorsFound(false); // If errors detected in input
    8740             :         int NumAlphas;           // Number of Alphas for each GetobjectItem call
    8741             :         int NumNumbers;          // Number of Numbers for each GetobjectItem call
    8742             :         int NumArgs;
    8743             :         int IOStatus;
    8744         796 :         Array1D_string cAlphaArgs;    // Alpha input items for object
    8745         796 :         Array1D<Real64> rNumericArgs; // Numeric input items for object
    8746             : 
    8747         796 :         std::string cCurrentModuleObject;
    8748         796 :         std::string cSolarSpectrum;
    8749         796 :         std::string cVisibleSpectrum;
    8750         796 :         int iSolarSpectrum(0);
    8751         796 :         int iVisibleSpectrum(0);
    8752         796 :         int NumSiteSpectrum(0);
    8753             :         int Loop;
    8754             :         int iTmp;
    8755             : 
    8756         796 :         auto &wm = state.dataWindowManager;
    8757             : 
    8758         796 :         if (wm->RunMeOnceFlag) return;
    8759             : 
    8760             :         // Step 1 - check whether there is custom solar or visible spectrum
    8761         796 :         cCurrentModuleObject = "Site:SolarAndVisibleSpectrum";
    8762         796 :         NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    8763             : 
    8764             :         // no custom spectrum data, done!
    8765         796 :         if (NumSiteSpectrum == 0) {
    8766         795 :             wm->RunMeOnceFlag = true;
    8767         795 :             return;
    8768             :         }
    8769             : 
    8770             :         // read custom spectrum data from Site:SolarAndVisibleSpectrum
    8771           1 :         if (NumSiteSpectrum > 1) { // throw error
    8772           0 :             ShowSevereError(state, format("Only one {} object is allowed", cCurrentModuleObject));
    8773           0 :             ErrorsFound = true;
    8774             :         }
    8775             : 
    8776           1 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
    8777           1 :         cAlphaArgs.allocate(NumAlphas);
    8778           1 :         rNumericArgs.dimension(NumNumbers, 0.0);
    8779             : 
    8780           1 :         if (NumSiteSpectrum == 1) {
    8781           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8782             :                                                                      cCurrentModuleObject,
    8783             :                                                                      1,
    8784           1 :                                                                      state.dataIPShortCut->cAlphaArgs,
    8785             :                                                                      NumAlphas,
    8786           1 :                                                                      state.dataIPShortCut->rNumericArgs,
    8787             :                                                                      NumNumbers,
    8788             :                                                                      IOStatus);
    8789             : 
    8790             :             // use default spectrum data, done!
    8791           1 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "Default")) {
    8792           0 :                 wm->RunMeOnceFlag = true;
    8793           0 :                 return;
    8794             :             }
    8795             : 
    8796             :             // now read custom solar and visible spectrum data
    8797           1 :             cSolarSpectrum = state.dataIPShortCut->cAlphaArgs(3);
    8798           1 :             cVisibleSpectrum = state.dataIPShortCut->cAlphaArgs(4);
    8799             : 
    8800           1 :             cCurrentModuleObject = "Site:SpectrumData";
    8801           1 :             NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    8802           1 :             if (NumSiteSpectrum == 0) { // throw error
    8803           0 :                 ShowSevereError(state, format("No {} object is found", cCurrentModuleObject));
    8804           0 :                 ErrorsFound = true;
    8805             :             }
    8806             : 
    8807           1 :             cAlphaArgs.deallocate();
    8808           1 :             rNumericArgs.deallocate();
    8809             : 
    8810           1 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
    8811           1 :             cAlphaArgs.allocate(NumAlphas);
    8812           1 :             rNumericArgs.dimension(NumNumbers, 0.0);
    8813             : 
    8814           1 :             iSolarSpectrum = 0;
    8815           1 :             iVisibleSpectrum = 0;
    8816           2 :             for (int Loop = 1; Loop <= NumSiteSpectrum; ++Loop) {
    8817             :                 // Step 2 - read user-defined spectrum data
    8818           4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8819             :                                                                          cCurrentModuleObject,
    8820             :                                                                          Loop,
    8821           2 :                                                                          state.dataIPShortCut->cAlphaArgs,
    8822             :                                                                          NumAlphas,
    8823           2 :                                                                          state.dataIPShortCut->rNumericArgs,
    8824             :                                                                          NumNumbers,
    8825             :                                                                          IOStatus);
    8826           2 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cSolarSpectrum)) {
    8827           1 :                     iSolarSpectrum = Loop;
    8828             :                     // overwrite the default solar spectrum
    8829           1 :                     if (NumNumbers > 2 * nume) {
    8830           0 :                         ShowSevereError(
    8831             :                             state,
    8832           0 :                             format("Solar spectrum data pair is more than 107 - {} - {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    8833           0 :                         ErrorsFound = true;
    8834             :                     } else {
    8835             :                         // Step 3 - overwrite default solar spectrum data
    8836         108 :                         for (int iTmp = 1; iTmp <= nume; ++iTmp) {
    8837         107 :                             if (iTmp <= NumNumbers / 2) {
    8838         107 :                                 wm->wle[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
    8839         107 :                                 wm->e[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
    8840             :                             } else {
    8841           0 :                                 wm->wle[iTmp - 1] = 0.0;
    8842           0 :                                 wm->e[iTmp - 1] = 0.0;
    8843             :                             }
    8844             :                         }
    8845             :                     }
    8846             :                 }
    8847           2 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cVisibleSpectrum)) {
    8848           1 :                     iVisibleSpectrum = Loop;
    8849             :                     // overwrite the default solar spectrum
    8850           1 :                     if (NumNumbers > 2 * numt3) {
    8851           0 :                         ShowSevereError(state,
    8852           0 :                                         format("Visible spectrum data pair is more than 81 - {} - {}",
    8853             :                                                cCurrentModuleObject,
    8854           0 :                                                state.dataIPShortCut->cAlphaArgs(1)));
    8855           0 :                         ErrorsFound = true;
    8856             :                     } else {
    8857             :                         // Step 3 - overwrite default visible spectrum data
    8858          82 :                         for (int iTmp = 1; iTmp <= numt3; ++iTmp) {
    8859          81 :                             if (iTmp <= NumNumbers / 2) {
    8860          81 :                                 wm->wlt3[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
    8861          81 :                                 wm->y30[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
    8862             :                             } else {
    8863           0 :                                 wm->wlt3[iTmp - 1] = 0.0;
    8864           0 :                                 wm->y30[iTmp - 1] = 0.0;
    8865             :                             }
    8866             :                         }
    8867             :                     }
    8868             :                 }
    8869           2 :                 if ((iSolarSpectrum > 0) && (iVisibleSpectrum > 0)) break;
    8870             :             }
    8871             :         }
    8872             : 
    8873           1 :         cAlphaArgs.deallocate();
    8874           1 :         rNumericArgs.deallocate();
    8875             : 
    8876           1 :         if (ErrorsFound) {
    8877           0 :             ShowFatalError(state, "Errors found in processing input for user-defined solar/visible spectrum");
    8878             :         }
    8879             : 
    8880           1 :         wm->RunMeOnceFlag = true;
    8881        3976 :     } // CheckAndReadCustomSpectrumData()
    8882             : 
    8883             :     //*****************************************************************************************
    8884             : 
    8885         796 :     void initWindowModel(EnergyPlusData &state)
    8886             :     {
    8887         796 :         const std::string objectName = "WindowsCalculationEngine";
    8888         796 :         auto &wm = state.dataWindowManager;
    8889         796 :         wm->inExtWindowModel = CWindowModel::WindowModelFactory(state, objectName);
    8890         796 :         wm->winOpticalModel = CWindowOpticalModel::WindowOpticalModelFactory(state);
    8891         796 :     } // InitWindowModel()
    8892             : 
    8893             :     //*****************************************************************************************
    8894             : 
    8895             : } // namespace Window
    8896             : 
    8897             : } // namespace EnergyPlus

Generated by: LCOV version 1.14