LCOV - code coverage report
Current view: top level - EnergyPlus - DaylightingManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 3607 5039 71.6 %
Date: 2023-01-17 19:17:23 Functions: 65 69 94.2 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <algorithm>
      50             : #include <cassert>
      51             : #include <cmath>
      52             : #include <string>
      53             : 
      54             : // ObjexxFCL Headers
      55             : #include <ObjexxFCL/Array.functions.hh>
      56             : #include <ObjexxFCL/Fmath.hh>
      57             : #include <ObjexxFCL/Vector2.hh>
      58             : #include <ObjexxFCL/Vector3.hh>
      59             : #include <ObjexxFCL/Vector4.hh>
      60             : #include <ObjexxFCL/member.functions.hh>
      61             : #include <ObjexxFCL/random.hh>
      62             : #include <ObjexxFCL/string.functions.hh>
      63             : 
      64             : // EnergyPlus Headers
      65             : #include <EnergyPlus/DElightManagerF.hh>
      66             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      67             : #include <EnergyPlus/DataBSDFWindow.hh>
      68             : #include <EnergyPlus/DataDElight.hh>
      69             : #include <EnergyPlus/DataDaylighting.hh>
      70             : #include <EnergyPlus/DataDaylightingDevices.hh>
      71             : #include <EnergyPlus/DataEnvironment.hh>
      72             : #include <EnergyPlus/DataErrorTracking.hh>
      73             : #include <EnergyPlus/DataHeatBalance.hh>
      74             : #include <EnergyPlus/DataIPShortCuts.hh>
      75             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      76             : #include <EnergyPlus/DataStringGlobals.hh>
      77             : #include <EnergyPlus/DataSurfaces.hh>
      78             : #include <EnergyPlus/DataSystemVariables.hh>
      79             : #include <EnergyPlus/DataViewFactorInformation.hh>
      80             : #include <EnergyPlus/DaylightingDevices.hh>
      81             : #include <EnergyPlus/DaylightingManager.hh>
      82             : #include <EnergyPlus/DisplayRoutines.hh>
      83             : #include <EnergyPlus/FileSystem.hh>
      84             : #include <EnergyPlus/General.hh>
      85             : #include <EnergyPlus/HeatBalanceManager.hh>
      86             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      87             : #include <EnergyPlus/InternalHeatGains.hh>
      88             : #include <EnergyPlus/OutputProcessor.hh>
      89             : #include <EnergyPlus/OutputReportPredefined.hh>
      90             : #include <EnergyPlus/PierceSurface.hh>
      91             : #include <EnergyPlus/SQLiteProcedures.hh>
      92             : #include <EnergyPlus/ScheduleManager.hh>
      93             : #include <EnergyPlus/SolarReflectionManager.hh>
      94             : #include <EnergyPlus/SolarShading.hh>
      95             : #include <EnergyPlus/SurfaceOctree.hh>
      96             : #include <EnergyPlus/UtilityRoutines.hh>
      97             : #include <EnergyPlus/WindowComplexManager.hh>
      98             : 
      99             : namespace EnergyPlus::DaylightingManager {
     100             : 
     101             : // MODULE INFORMATION
     102             : //       AUTHOR         Fred Winkelmann
     103             : //       DATE WRITTEN   July 1997, December 1998
     104             : //       MODIFIED       Oct 2004; LKL -- Efficiencies and code restructure
     105             : //                      Aug 2012: BG -- Added availability schedule
     106             : //       RE-ENGINEERED  na
     107             : 
     108             : // PURPOSE OF THIS MODULE:
     109             : // Manages the daylighting calculations for each thermal zone that has an associated
     110             : // Daylighting:Controls object.
     111             : 
     112             : // Includes calculation of interior daylight illuminance and glare
     113             : // from each of the windows in a zone, control of window shading devices
     114             : // to reduce glare, and control of overhead electric lighting in response
     115             : // to interior daylight illuminance level at one or two user-specified
     116             : // reference points at which sensors are located.
     117             : 
     118             : // METHODOLOGY EMPLOYED:
     119             : // REFERENCES:
     120             : // "Daylighting Calculation in DOE-2," F.C.Winkelmann, LBL-11353, May 1983
     121             : // "Daylighting Simulation in the DOE-2 Building Energy Analysis Program,"
     122             : // F.C. Winkelmann and S. Selkowitz, Energy and Buildings 8(1985)271-286
     123             : 
     124             : // OTHER NOTES:
     125             : // This module was created from DOE-2.1E subroutines.
     126             : 
     127             : // Correspondence between DOE-2.1E and EnergyPlus subroutine names:
     128             : 
     129             : // DOE-2.1E    EnergyPlus                      In Module           Called from Module
     130             : // DAVREF      DayltgAveInteriorReflectance    DaylightingManager DaylightingManager
     131             : // DCOF        CalcDayltgCoefficients          DaylightingManager DaylightingManager
     132             : // DCROSS      DayltgCrossProduct              DaylightingManager DaylightingManager
     133             : // DEXTIL      DayltgCurrentExtHorizIllum      WeatherManager     WeatherManager
     134             : // DGLARE      DayltgGlare                     DaylightingManager DaylightingManager
     135             : // DHILL       DayltgExtHorizIllum             DaylightingManager DaylightingManager
     136             : // DHITSH      DayltgHitObstruction            DaylightingManager DaylightingManager
     137             : // DINTIL      DayltgInteriorIllum             DaylightingManager HeatBalanceSurfaceManager
     138             : // DLTSYS      DayltgElecLightingControl       DaylightingManager HeatBalanceSurfaceManager
     139             : // DNSOL       not used
     140             : // DPFAC       DayltgPositionFactor            DaylightingManager DaylightingManager
     141             : // DPIERC      PierceSurface                   PierceSurface      DaylightingManager
     142             : // DREFLT      DayltgInterReflectedIllum       DaylightingManager DaylightingManager
     143             : // DSKYLU      DayltgSkyLuminance              DaylightingManager DaylightingManager
     144             : // DTHLIM      DayltgAzimuthLimits             DaylightingManager DaylightingManager
     145             : // DLUMEF      DayltgLuminousEfficacy          WeatherManager     WeatherManager
     146             : 
     147             : // Using/Aliasing
     148             : using namespace DataHeatBalance;
     149             : using namespace DataSurfaces;
     150             : 
     151         284 : void DayltgAveInteriorReflectance(EnergyPlusData &state, int const enclNum) // Enclosure number
     152             : {
     153             : 
     154             :     // SUBROUTINE INFORMATION:
     155             :     //       AUTHOR         Fred Winkelmann
     156             :     //       DATE WRITTEN   July 1997
     157             :     //       MODIFIED       Mar 2004, FCW: add calculation of following SurfaceWindow variables:
     158             :     //                        EnclAreaMinusThisSurf, EnclAreaReflProdMinusThisSurf, RhoCeilingWall,
     159             :     //                        RhoFloorWall, FractionUpgoing. Add calculation of ZoneDaylight%floorVisRefl.
     160             : 
     161             :     // PURPOSE OF THIS SUBROUTINE:
     162             :     // Called by CalcDayltgCoefficients for each daylit zone. Determines total
     163             :     // area and area-weighted average visible reflectance of
     164             :     // all inside faces of the surfaces of a zone.  In addition, finds
     165             :     // area and average reflectance of interzone, underground and exterior
     166             :     // heat-transfer surfaces in the following categories: floor (tilt > 170 deg),
     167             :     // ceiling (tilt < 10 deg), and wall (10 < tilt < 170 deg).
     168             :     // The window reflectance values used here assume the windows have no shading
     169             :     // devices. This information is used in the calculation of the
     170             :     // internally-reflected daylighting component.
     171             : 
     172             :     // Finds total number of exterior windows in the space.
     173             : 
     174             :     // REFERENCES:
     175             :     // Based on DOE-2.1E subroutine DAVREF
     176             : 
     177             :     SurfaceClass IType; // Surface type/class
     178             :     Real64 AREA;        // Inside surface area (m2)
     179             :     Real64 AInsTot;     // Total inside surface area of an enclosure (m2)
     180             :     Real64 ARHTOT;      // Sum over surfaces of AREA*(inside visible reflectance) (m2)
     181             :     int ITILT;          // Surface tilt category (1 = floor, 2 = wall, 3 = ceiling)
     182             :     int IT;             // Tilt index
     183             :     Real64 ATWL;        // Opaque surface area (m2)
     184             :     Real64 ARHTWL;      // ATWL times inside visible reflectance of surface (m2)
     185             :     Real64 ETA;         // Ratio of floor-to-window-center height and average floor-to-ceiling height
     186             : 
     187             :     // Total inside surface area, including windows
     188         284 :     AInsTot = 0.0;
     189             :     // Sum of products of inside surface area * vis reflectance
     190         284 :     ARHTOT = 0.0;
     191             :     // Area sum and area * reflectance sum for different orientations
     192         284 :     state.dataDaylightingManager->AR = 0.0;
     193         284 :     state.dataDaylightingManager->ARH = 0.0;
     194             :     // Loop over surfaces in the zone's enclosure
     195             : 
     196         284 :     auto &thisEnclosure(state.dataViewFactor->EnclSolInfo(enclNum));
     197        3414 :     for (int ISurf : thisEnclosure.SurfacePtr) {
     198        3130 :         IType = state.dataSurface->Surface(ISurf).Class;
     199             :         // Error if window has multiplier > 1 since this causes incorrect illuminance calc
     200        3130 :         if (IType == SurfaceClass::Window && state.dataSurface->Surface(ISurf).Multiplier > 1.0) {
     201           0 :             if (thisEnclosure.TotalEnclosureDaylRefPoints > 0) {
     202           0 :                 ShowSevereError(state,
     203           0 :                                 "DayltgAveInteriorReflectance: Multiplier > 1.0 for window " + state.dataSurface->Surface(ISurf).Name +
     204           0 :                                     " in Zone=" + state.dataSurface->Surface(ISurf).ZoneName);
     205           0 :                 ShowContinueError(state, "...not allowed since it is in a zone or enclosure with daylighting.");
     206           0 :                 ShowFatalError(state, "Program terminates due to preceding conditions.");
     207             :             } else {
     208           0 :                 ShowSevereError(state,
     209           0 :                                 "DayltgAveInteriorReflectance: Multiplier > 1.0 for window " + state.dataSurface->Surface(ISurf).Name +
     210           0 :                                     " in Zone=" + state.dataSurface->Surface(ISurf).ZoneName);
     211           0 :                 ShowContinueError(state, "...an adjacent Zone has daylighting. Simulation cannot proceed.");
     212           0 :                 ShowFatalError(state, "Program terminates due to preceding conditions.");
     213             :             }
     214             :         }
     215        3130 :         if (IType == SurfaceClass::Wall || IType == SurfaceClass::Floor || IType == SurfaceClass::Roof || IType == SurfaceClass::Window ||
     216             :             IType == SurfaceClass::Door) {
     217        2889 :             AREA = state.dataSurface->Surface(ISurf).Area;
     218             :             // In following, FrameArea and DividerArea can be non-zero only for exterior windows
     219        5778 :             AInsTot += AREA + state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) +
     220        2889 :                        state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf));
     221        8667 :             ARHTOT += AREA * state.dataConstruction->Construct(state.dataSurface->Surface(ISurf).Construction).ReflectVisDiffBack +
     222        5778 :                       state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) *
     223        5778 :                           (1.0 - state.dataSurface->SurfWinFrameSolAbsorp(ISurf)) +
     224        5778 :                       state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf)) *
     225        2889 :                           (1.0 - state.dataSurface->SurfWinDividerSolAbsorp(ISurf));
     226        2889 :             ITILT = 3;                                                                                                      // Ceiling
     227        2889 :             if (state.dataSurface->Surface(ISurf).Tilt > 10.0 && state.dataSurface->Surface(ISurf).Tilt < 170.0) ITILT = 2; // Wall
     228        2889 :             if (state.dataSurface->Surface(ISurf).Tilt >= 170.0) ITILT = 1;                                                 // Floor
     229        2889 :             state.dataDaylightingManager->AR(ITILT) +=
     230        5778 :                 AREA + state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) +
     231        2889 :                 state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf));
     232        2889 :             state.dataDaylightingManager->ARH(ITILT) +=
     233        5778 :                 AREA * state.dataConstruction->Construct(state.dataSurface->Surface(ISurf).Construction).ReflectVisDiffBack +
     234        5778 :                 state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) *
     235        5778 :                     (1.0 - state.dataSurface->SurfWinFrameSolAbsorp(ISurf)) +
     236        5778 :                 state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf)) *
     237        2889 :                     (1.0 - state.dataSurface->SurfWinDividerSolAbsorp(ISurf));
     238             :         }
     239             :     }
     240             : 
     241             :     // Average inside surface reflectance of enclosure
     242         284 :     if (AInsTot <= 0.0) {
     243           0 :         ShowSevereError(state, "DayltgAveInteriorReflectance: Total opaque surface area is <=0.0 in solar enclosure=" + thisEnclosure.Name);
     244           0 :         ShowFatalError(state, "Program terminates due to preceding conditions.");
     245             :     }
     246         284 :     state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect = ARHTOT / AInsTot;
     247             :     // Total inside surface area of enclosure
     248         284 :     state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea = AInsTot;
     249             :     // Average floor visible reflectance
     250         284 :     state.dataDaylightingData->enclDaylight(enclNum).floorVisRefl =
     251         284 :         state.dataDaylightingManager->ARH(3) / (state.dataDaylightingManager->AR(3) + 1.e-6);
     252             : 
     253        3414 :     for (int ISurf : thisEnclosure.SurfacePtr) {
     254        3130 :         IType = state.dataSurface->Surface(ISurf).Class;
     255        3130 :         if (IType == SurfaceClass::Wall || IType == SurfaceClass::Floor || IType == SurfaceClass::Roof) {
     256             :             // Remove this surface from the space inside surface area and area*reflectivity
     257             :             // The resulting areas are AP(ITILT). The resulting area*reflectivity is ARHP(ITILT).
     258             :             // Initialize gross area of surface (including subsurfaces)
     259        1842 :             ATWL = state.dataSurface->Surface(ISurf).Area; // This is the surface area less subsurfaces
     260             :             // Area * reflectance for this surface, excluding attached windows and doors
     261        3684 :             ARHTWL = state.dataSurface->Surface(ISurf).Area *
     262        1842 :                      state.dataConstruction->Construct(state.dataSurface->Surface(ISurf).Construction).ReflectVisDiffBack;
     263             :             // Tilt index
     264        1842 :             if (state.dataSurface->Surface(ISurf).Tilt > 45.0 && state.dataSurface->Surface(ISurf).Tilt < 135.0) {
     265        1232 :                 ITILT = 2; // Wall
     266         610 :             } else if (state.dataSurface->Surface(ISurf).Tilt >= 135.0) {
     267         316 :                 ITILT = 1; // Floor
     268             :             } else {
     269         294 :                 ITILT = 3; // Ceiling
     270             :             }
     271             :             // Loop over windows and doors on this wall
     272       23547 :             for (int IWinDr : thisEnclosure.SurfacePtr) {
     273       58956 :                 if ((state.dataSurface->Surface(IWinDr).Class == SurfaceClass::Window ||
     274       29330 :                      state.dataSurface->Surface(IWinDr).Class == SurfaceClass::Door) &&
     275        7625 :                     state.dataSurface->Surface(IWinDr).BaseSurf == ISurf) {
     276        3141 :                     ATWL += state.dataSurface->Surface(IWinDr).Area +
     277        2094 :                             state.dataSurface->SurfWinFrameArea(IWinDr) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(IWinDr)) +
     278        1047 :                             state.dataSurface->SurfWinDividerArea(IWinDr) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(IWinDr));
     279        3141 :                     ARHTWL += state.dataSurface->Surface(IWinDr).Area *
     280        2094 :                                   state.dataConstruction->Construct(state.dataSurface->Surface(IWinDr).Construction).ReflectVisDiffBack +
     281        2094 :                               state.dataSurface->SurfWinFrameArea(IWinDr) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(IWinDr)) *
     282        2094 :                                   (1.0 - state.dataSurface->SurfWinFrameSolAbsorp(IWinDr)) +
     283        2094 :                               state.dataSurface->SurfWinDividerArea(IWinDr) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(IWinDr)) *
     284        1047 :                                   (1.0 - state.dataSurface->SurfWinDividerSolAbsorp(IWinDr));
     285             :                 }
     286             :             }
     287             :             // Inside surface area of floor, walls and ceilings, minus surface ISurf and its subsurfaces
     288        7368 :             for (IT = 1; IT <= 3; ++IT) {
     289        5526 :                 if (IT == ITILT) {
     290        1842 :                     state.dataDaylightingManager->AP(IT) = state.dataDaylightingManager->AR(IT) - ATWL;
     291        1842 :                     state.dataDaylightingManager->ARHP(IT) = state.dataDaylightingManager->ARH(IT) - ARHTWL;
     292             :                 } else {
     293        3684 :                     state.dataDaylightingManager->AP(IT) = state.dataDaylightingManager->AR(IT);
     294        3684 :                     state.dataDaylightingManager->ARHP(IT) = state.dataDaylightingManager->ARH(IT);
     295             :                 }
     296             :             }
     297        1842 :             state.dataSurface->SurfaceWindow(ISurf).EnclAreaMinusThisSurf = state.dataDaylightingManager->AP;
     298        1842 :             state.dataSurface->SurfaceWindow(ISurf).EnclAreaReflProdMinusThisSurf = state.dataDaylightingManager->ARHP;
     299             :         }
     300             :     } // End of loop over opaque surfaces in enclosure
     301             : 
     302        3414 :     for (int IWin : thisEnclosure.SurfacePtr) {
     303        3130 :         if (state.dataSurface->Surface(IWin).Class == SurfaceClass::Window) {
     304         841 :             int ISurf = state.dataSurface->Surface(IWin).BaseSurf;
     305         841 :             int zoneNum = state.dataSurface->Surface(IWin).Zone;
     306             :             // Ratio of floor-to-window-center height and average floor-to-ceiling height
     307         841 :             ETA = max(0.0,
     308             :                       min(1.0,
     309        1682 :                           (state.dataSurface->SurfaceWindow(IWin).WinCenter(3) - state.dataHeatBal->Zone(zoneNum).OriginZ) *
     310        1682 :                               state.dataHeatBal->Zone(zoneNum).FloorArea / state.dataHeatBal->Zone(zoneNum).Volume));
     311         841 :             state.dataDaylightingManager->AP = state.dataSurface->SurfaceWindow(ISurf).EnclAreaMinusThisSurf;
     312         841 :             state.dataDaylightingManager->ARHP = state.dataSurface->SurfaceWindow(ISurf).EnclAreaReflProdMinusThisSurf;
     313             :             // Average reflectance seen by light moving up (RhoCeilingWall) and down (RhoFloorWall)
     314             :             // across horizontal plane through center of window
     315         841 :             state.dataSurface->SurfWinRhoCeilingWall(IWin) =
     316        1682 :                 (state.dataDaylightingManager->ARHP(2) * (1.0 - ETA) + state.dataDaylightingManager->ARHP(3)) /
     317         841 :                 (state.dataDaylightingManager->AP(2) * (1.0 - ETA) + state.dataDaylightingManager->AP(3) + 1.0e-5);
     318        1682 :             state.dataSurface->SurfWinRhoFloorWall(IWin) = (state.dataDaylightingManager->ARHP(2) * ETA + state.dataDaylightingManager->ARHP(1)) /
     319         841 :                                                            (state.dataDaylightingManager->AP(2) * ETA + state.dataDaylightingManager->AP(1) + 1.e-9);
     320             : 
     321             :             // Angle factor for windows with diffusing shades. SurfaceWindow(IWin)%FractionUpgoing is
     322             :             // fraction of light from the shade that goes up toward ceiling and upper part of walls.
     323             :             // 1 - SurfaceWindow(IWin)%FractionUpgoing is fraction that goes down toward floor and lower part of walls.
     324         841 :             state.dataSurface->SurfWinFractionUpgoing(IWin) = state.dataSurface->Surface(IWin).Tilt / 180.0;
     325             : 
     326             :             // Daylighting shelf simplification:  All light goes up to the ceiling regardless of orientation of shelf
     327         841 :             if (state.dataSurface->SurfDaylightingShelfInd(IWin) > 0) {
     328           1 :                 if (state.dataDaylightingDevicesData->Shelf(state.dataSurface->SurfDaylightingShelfInd(IWin)).InSurf > 0)
     329           1 :                     state.dataSurface->SurfWinFractionUpgoing(IWin) = 1.0;
     330             :             }
     331             :         }
     332             :     }
     333         284 : }
     334             : 
     335       14330 : void CalcDayltgCoefficients(EnergyPlusData &state)
     336             : {
     337             : 
     338             :     // SUBROUTINE INFORMATION:
     339             :     //       AUTHOR         Fred Winkelmann
     340             :     //       DATE WRITTEN   July 1997
     341             :     //       MODIFIED       FW, Jan 2002: add variable slat angle blinds
     342             :     //                      FW, Mar 2002: add triangular windows
     343             :     //                      FW, Oct 2002: remove warning on window discretization relative to
     344             :     //                                    reference point distance to window plane
     345             :     //                      FW, Jan 2003: add between-glass shades and blinds
     346             :     //                      FW, Apr 2003: initialize shading type to 'NOSHADE' in window loop
     347             :     //                      PE, May 2003: add light pipes (tubular daylighting devices)
     348             :     //                      FW, Jul 2003: account for possible non-zero transmittance of
     349             :     //                                    shading surfaces (previously all shading surfaces were
     350             :     //                                    assumed to be opaque)
     351             :     //                      PE, Aug 2003: add daylighting shelves
     352             :     //                      FW, Sep 2003: write the bare-window overcast sky daylight factors to the eio file
     353             :     //                      FW, Nov 2003: add exterior beam and sky solar diffuse reflection from obstructions;
     354             :     //                                    add beam solar and sky solar reflection from ground with obstructions.
     355             :     //                      FW, Nov 2003: change expression for NDIVX, NDIVY (no. of window elements in X,Y) to
     356             :     //                                    round up to nearest integer rather than down
     357             :     //                      FW, Nov 2003: add specular reflection of beam solar from obstructions
     358             :     //                      RJH, Jan 2004: add alternative daylighting analysis using DElight
     359             :     //                                     All modifications demarked with RJH (Rob Hitchcock)
     360             :     //                      FW, Feb 2004: add daylighting through interior windows
     361             :     //                      FW, Apr 2004: add light well efficiency that multiplies glazing transmittance
     362             :     //                      FW, Apr 2004: add diffusing glazing
     363             :     //                      RJH, Jul 2004: add error handling for warnings/errors returned from DElight
     364             :     //                      LKL, Oct 2004: Separate "map" and "ref" point calculations -- move some input routines to
     365             :     //                                     separate routines.
     366             :     //       RE-ENGINEERED  na
     367             : 
     368             :     // PURPOSE OF THIS SUBROUTINE:
     369             :     // Calculates daylighting factors for later use in the time-step loop.
     370             : 
     371             :     // METHODOLOGY EMPLOYED:
     372             : 
     373             :     // For each combination of exterior window and reference point in a zone,
     374             :     // calculates daylighting factors (interior illuminance / exterior illuminance)
     375             :     // and glare factors for clear and overcast skies and for windows with and
     376             :     // without shading devices. These factors are calculated for each hourly
     377             :     // sun position for design days and for selected days throughout the year.
     378             : 
     379             :     // If a target zone has one or more interior windows, also calculates daylighting
     380             :     // factors for the target zone that are associated with exterior windows in adjacent
     381             :     // zones that share interior windows with the target zone.
     382             : 
     383             :     // The daylight illuminance at a reference point from a window is determined
     384             :     // by dividing the window into rectangular elements and calculating the illuminance
     385             :     // reaching the reference point directly from each element. The illumination
     386             :     // from an element can come from the sky or ground if the window is unshaded, or from
     387             :     // a shading device illuminated by solar radiation. Also considered are the
     388             :     // illuminance contribution from interreflection among the zone's interior surfaces
     389             :     // and sunlight striking the reference point.
     390             : 
     391             :     // In calculating sky-related interior illuminance and luminance quantities,
     392             :     // the sky luminance for the different sky types are determined from distributions
     393             :     // in which the zenith luminance is normalized to 1.0 cd/m2. Similarly, sun-related
     394             :     // illuminance and luminance quantities are based on beam normal solar illuminance
     395             :     // normalized to 1.0 lux.
     396             :     // The daylight and glare factors calculated in this subroutine are used in DayltgInteriorIllum
     397             :     // to get the daylight illuminance and glare at each time step.
     398             :     // Based on this information and user-input lighting setpoint and type of lighting
     399             :     // control system, DayltgElecLightingControl then determines how much the overhead electric lighting
     400             :     // can be reduced.
     401             : 
     402             :     // REFERENCES:
     403             :     // Based on DOE-2.1E subroutine DCOF.
     404             : 
     405             :     //    int IHR;        // Hour of day counter
     406             :     //    int IWin;       // Window counter
     407             :     //    int loop;       // DO loop indices
     408             :     Real64 DaylFac; // sky daylight factor at ref pt i
     409             : 
     410             :     // added for output all daylight factors
     411             :     Real64 DFClrSky;
     412             :     Real64 DFClrTbSky;
     413             :     Real64 DFIntSky;
     414             :     Real64 DFOcSky;
     415             : 
     416             :     Real64 SlatAngle;
     417             :     int ISA;
     418             :     int ISlatAngle;
     419             : 
     420       14330 :     if (state.dataDaylightingManager->CalcDayltghCoefficients_firstTime) {
     421         771 :         GetDaylightingParametersInput(state);
     422         771 :         CheckTDDsAndLightShelvesInDaylitZones(state);
     423         771 :         AssociateWindowShadingControlWithDaylighting(state);
     424         771 :         state.dataDaylightingManager->CalcDayltghCoefficients_firstTime = false;
     425             :     } // End of check if firstTime
     426             : 
     427             :     // Find the total number of exterior windows associated with all Daylighting:Detailed enclosures.
     428             :     // An exterior window is associated with such a enclosure if (1) it is an exterior window in the enclosure, or
     429             :     // (2) it is an exterior window in an adjacent enclosure that shares an interior window with the enclosure.
     430             :     // Note that exterior windows in category (2) may be counted more than once if an adjacent enclosure
     431             :     // is adjacent to more than one daylit enclosure with which the adjacent enclosure shares interior windows.
     432             :     // If there are no interior windows in a building, than TotWindowsWithDayl is just the total number of
     433             :     // exterior windows in Daylighting:Detailed enclosures. Note that it is possible for a
     434             :     // Daylighting:Detailed enclosure to have zero exterior windows of its own, but it may have an interior
     435             :     // through which daylight passes from adjacent enclosures with exterior windows.
     436       28658 :     if ((int)state.dataDaylightingData->DaylRefPt.size() == 0) return;
     437         507 :     if (state.dataGlobal->BeginSimFlag) {
     438          62 :         state.dataDaylightingManager->TotWindowsWithDayl = 0;
     439         770 :         for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
     440         708 :             state.dataDaylightingManager->TotWindowsWithDayl += state.dataDaylightingData->enclDaylight(enclNum).NumOfDayltgExtWins;
     441             :         }
     442             :     }
     443             : 
     444         507 :     if (state.dataDaylightingManager->TotWindowsWithDayl == 0) return;
     445             : 
     446             :     //-----------------------------------------!
     447             :     // Detailed daylighting factor calculation !
     448             :     //-----------------------------------------!
     449         507 :     if (!state.dataSysVars->DetailedSolarTimestepIntegration && !state.dataGlobal->KickOffSizing && !state.dataGlobal->KickOffSimulation) {
     450         200 :         if (state.dataGlobal->WarmupFlag) {
     451         200 :             DisplayString(state, "Calculating Detailed Daylighting Factors, Start Date=" + state.dataEnvrn->CurMnDy);
     452             :         } else {
     453           0 :             DisplayString(state, "Updating Detailed Daylighting Factors, Start Date=" + state.dataEnvrn->CurMnDy);
     454             :         }
     455             :     }
     456             : 
     457         507 :     if (state.dataGlobal->BeginSimFlag) {
     458             : 
     459             :         // Find minimum solid angle subtended by an interior window in Daylighting:Detailed zones.
     460             :         // Used in calculating daylighting through interior windows.
     461          62 :         CalcMinIntWinSolidAngs(state);
     462             : 
     463             :         // Warning if detailed daylighting has been requested for a zone with no associated exterior windows.
     464         770 :         for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
     465         708 :             auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
     466         708 :             if (thisEnclDaylight.NumOfDayltgExtWins == 0 && thisEnclDaylight.TotalExtWindows == 0) {
     467         244 :                 for (int daylightCtrlNum : thisEnclDaylight.daylightControlIndexes) {
     468           0 :                     if (state.dataDaylightingData->daylightControl(daylightCtrlNum).TotalDaylRefPoints > 0) {
     469           0 :                         ShowWarningError(state,
     470           0 :                                          "Detailed daylighting will not be done for Daylighting:Controls=" +
     471           0 :                                              state.dataDaylightingData->daylightControl(daylightCtrlNum).Name);
     472           0 :                         ShowContinueError(state, "because it has no associated exterior windows.");
     473             :                     }
     474             :                 }
     475             :             }
     476             : 
     477             :             // Find area and reflectance quantities used in calculating inter-reflected illuminance.
     478             :             // TH 9/10/2009. Need to calculate for zones without daylighting controls (TotalDaylRefPoints = 0)
     479             :             // but with adjacent zones having daylighting controls.
     480         708 :             if ((thisEnclDaylight.NumOfDayltgExtWins > 0) || thisEnclDaylight.adjEnclHasDayltgCtrl) {
     481         284 :                 DayltgAveInteriorReflectance(state, enclNum);
     482             :             }
     483             :         }
     484             :     }
     485             : 
     486             :     // Zero daylighting factor arrays
     487         507 :     if ((int)state.dataDaylightingDevicesData->TDDPipe.size() > 0) {
     488           5 :         if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
     489           5 :             state.dataDaylightingManager->TDDTransVisBeam = 0.0;
     490           5 :             state.dataDaylightingManager->TDDFluxInc = 0.0;
     491           5 :             state.dataDaylightingManager->TDDFluxTrans = 0.0;
     492             :         } else {
     493           0 :             state.dataDaylightingManager->TDDTransVisBeam(state.dataGlobal->HourOfDay, {1, (int)state.dataDaylightingDevicesData->TDDPipe.size()}) =
     494           0 :                 0.0;
     495           0 :             state.dataDaylightingManager->TDDFluxInc(
     496           0 :                 state.dataGlobal->HourOfDay, {1, 4}, {1, (int)state.dataDaylightingDevicesData->TDDPipe.size()}) = 0.0;
     497           0 :             state.dataDaylightingManager->TDDFluxTrans(
     498           0 :                 state.dataGlobal->HourOfDay, {1, 4}, {1, (int)state.dataDaylightingDevicesData->TDDPipe.size()}) = 0.0;
     499             :         }
     500             :     }
     501             : 
     502         507 :     if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
     503         507 :         if (state.dataGlobal->BeginDayFlag) {
     504             :             // Calculate hourly sun angles, clear sky zenith luminance, and exterior horizontal illuminance
     505         507 :             state.dataDaylightingManager->PHSUN = 0.0;
     506         507 :             state.dataDaylightingManager->SPHSUN = 0.0;
     507         507 :             state.dataDaylightingManager->CPHSUN = 0.0;
     508         507 :             state.dataDaylightingManager->THSUN = 0.0;
     509             : 
     510         507 :             state.dataDaylightingManager->PHSUNHR = 0.0;
     511         507 :             state.dataDaylightingManager->SPHSUNHR = 0.0;
     512         507 :             state.dataDaylightingManager->CPHSUNHR = 0.0;
     513         507 :             state.dataDaylightingManager->THSUNHR = 0.0;
     514         507 :             state.dataDaylightingManager->GILSK = 0.0;
     515         507 :             state.dataDaylightingManager->GILSU = 0.0;
     516       12675 :             for (int IHR = 1; IHR <= 24; ++IHR) {
     517       12168 :                 if (state.dataSurface->SurfSunCosHourly(IHR)(3) < DataEnvironment::SunIsUpValue)
     518        7830 :                     continue; // Skip if sun is below horizon //Autodesk SurfSunCosHourly was uninitialized here
     519        4338 :                 state.dataDaylightingManager->PHSUN = DataGlobalConstants::PiOvr2 - std::acos(state.dataSurface->SurfSunCosHourly(IHR)(3));
     520        4338 :                 state.dataDaylightingManager->PHSUNHR(IHR) = state.dataDaylightingManager->PHSUN;
     521        4338 :                 state.dataDaylightingManager->SPHSUNHR(IHR) = std::sin(state.dataDaylightingManager->PHSUN);
     522        4338 :                 state.dataDaylightingManager->CPHSUNHR(IHR) = std::cos(state.dataDaylightingManager->PHSUN);
     523        4338 :                 state.dataDaylightingManager->THSUNHR(IHR) =
     524        4338 :                     std::atan2(state.dataSurface->SurfSunCosHourly(IHR)(2), state.dataSurface->SurfSunCosHourly(IHR)(1));
     525             :                 // Get exterior horizontal illuminance from sky and sun
     526        4338 :                 state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(IHR);
     527        4338 :                 state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(IHR);
     528        4338 :                 state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(IHR);
     529        4338 :                 DayltgExtHorizIllum(state, state.dataDaylightingManager->GILSK(IHR, 1), state.dataDaylightingManager->GILSU(IHR));
     530             :             }
     531             :         }
     532             :     } else { // timestep integrated calculations
     533           0 :         state.dataDaylightingManager->PHSUN = 0.0;
     534           0 :         state.dataDaylightingManager->SPHSUN = 0.0;
     535           0 :         state.dataDaylightingManager->CPHSUN = 0.0;
     536           0 :         state.dataDaylightingManager->THSUN = 0.0;
     537             : 
     538           0 :         state.dataDaylightingManager->PHSUNHR(state.dataGlobal->HourOfDay) = 0.0;
     539           0 :         state.dataDaylightingManager->SPHSUNHR(state.dataGlobal->HourOfDay) = 0.0;
     540           0 :         state.dataDaylightingManager->CPHSUNHR(state.dataGlobal->HourOfDay) = 0.0;
     541           0 :         state.dataDaylightingManager->THSUNHR(state.dataGlobal->HourOfDay) = 0.0;
     542           0 :         state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, {1, 4}) = 0.0;
     543           0 :         state.dataDaylightingManager->GILSU(state.dataGlobal->HourOfDay) = 0.0;
     544           0 :         if (!(state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(3) < DataEnvironment::SunIsUpValue)) { // Skip if sun is below horizon
     545           0 :             state.dataDaylightingManager->PHSUN =
     546           0 :                 DataGlobalConstants::PiOvr2 - std::acos(state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(3));
     547           0 :             state.dataDaylightingManager->PHSUNHR(state.dataGlobal->HourOfDay) = state.dataDaylightingManager->PHSUN;
     548           0 :             state.dataDaylightingManager->SPHSUNHR(state.dataGlobal->HourOfDay) = std::sin(state.dataDaylightingManager->PHSUN);
     549           0 :             state.dataDaylightingManager->CPHSUNHR(state.dataGlobal->HourOfDay) = std::cos(state.dataDaylightingManager->PHSUN);
     550           0 :             state.dataDaylightingManager->THSUNHR(state.dataGlobal->HourOfDay) =
     551           0 :                 std::atan2(state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(2),
     552           0 :                            state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(1));
     553             :             // Get exterior horizontal illuminance from sky and sun
     554           0 :             state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(state.dataGlobal->HourOfDay);
     555           0 :             state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(state.dataGlobal->HourOfDay);
     556           0 :             state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(state.dataGlobal->HourOfDay);
     557           0 :             DayltgExtHorizIllum(state,
     558           0 :                                 state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, 1),
     559           0 :                                 state.dataDaylightingManager->GILSU(state.dataGlobal->HourOfDay));
     560             :         }
     561             :     }
     562             : 
     563         507 :     CalcDayltgCoeffsRefMapPoints(state);
     564             : 
     565         507 :     if (state.dataDaylightingManager->doSkyReporting) {
     566         239 :         if (!state.dataGlobal->KickOffSizing && !state.dataGlobal->KickOffSimulation) {
     567          62 :             if (state.dataDaylightingManager->FirstTimeDaylFacCalc && state.dataDaylightingManager->TotWindowsWithDayl > 0) {
     568             :                 // Write the bare-window four sky daylight factors at noon time to the eio file; this is done only
     569             :                 // for first time that daylight factors are calculated and so is insensitive to possible variation
     570             :                 // due to change in ground reflectance from month to month, or change in storm window status.
     571             :                 static constexpr std::string_view Format_700(
     572             :                     "! <Sky Daylight Factors>, Sky Type, MonthAndDay, Daylighting Control Name, Enclosure Name, "
     573             :                     "Window Name, Reference Point, Daylight Factor\n");
     574          62 :                 print(state.files.eio, Format_700);
     575         349 :                 for (int controlNum = 1; controlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++controlNum) {
     576         287 :                     auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
     577         287 :                     int enclNum = thisDaylightControl.enclIndex;
     578         287 :                     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
     579             : 
     580         287 :                     if (thisEnclDaylight.NumOfDayltgExtWins == 0 || !thisEnclDaylight.hasSplitFluxDaylighting) continue;
     581        1126 :                     for (int windowCounter = 1; windowCounter <= thisEnclDaylight.NumOfDayltgExtWins; ++windowCounter) {
     582         842 :                         int windowSurfNum = thisEnclDaylight.DayltgExtWinSurfNums(windowCounter);
     583             :                         // For this report, do not include ext wins in zone adjacent to ZoneNum since the inter-reflected
     584             :                         // component will not be calculated for these windows until the time-step loop.
     585         842 :                         if (state.dataSurface->Surface(windowSurfNum).SolarEnclIndex == enclNum) {
     586             :                             // Output for each reference point, for each sky. Group by sky type first
     587        6728 :                             for (const DataDaylighting::SkyType &skyType : {DataDaylighting::SkyType::Clear,
     588             :                                                                             DataDaylighting::SkyType::ClearTurbid,
     589             :                                                                             DataDaylighting::SkyType::Intermediate,
     590         841 :                                                                             DataDaylighting::SkyType::Overcast}) {
     591        6728 :                                 std::string skyTypeString;
     592        3364 :                                 if (skyType == DataDaylighting::SkyType::Clear) {
     593         841 :                                     skyTypeString = "Clear Sky";
     594        2523 :                                 } else if (skyType == DataDaylighting::SkyType::ClearTurbid) {
     595         841 :                                     skyTypeString = "Clear Turbid Sky";
     596        1682 :                                 } else if (skyType == DataDaylighting::SkyType::Intermediate) {
     597         841 :                                     skyTypeString = "Intermediate Sky";
     598         841 :                                 } else if (skyType == DataDaylighting::SkyType::Overcast) {
     599         841 :                                     skyTypeString = "Overcast Sky";
     600             :                                     //} else {
     601             :                                     //    // Should never happen
     602             :                                     //    skyTypeString = "ERROR_SKY_TYPE_NOT_HANDLED";
     603             :                                 }
     604             : 
     605        9292 :                                 for (int refPtNum = 1; refPtNum <= thisDaylightControl.TotalDaylRefPoints; ++refPtNum) {
     606        5928 :                                     DaylFac = thisDaylightControl.DaylIllFacSky(12, 1, static_cast<int>(skyType), refPtNum, windowCounter);
     607       29640 :                                     print(state.files.eio,
     608             :                                           " Sky Daylight Factors,{},{},{},{},{},{},{:.4R}\n",
     609             :                                           skyTypeString,
     610        5928 :                                           state.dataEnvrn->CurMnDy,
     611             :                                           thisDaylightControl.Name,
     612        5928 :                                           state.dataViewFactor->EnclSolInfo(thisDaylightControl.enclIndex).Name,
     613        5928 :                                           state.dataSurface->Surface(windowSurfNum).Name,
     614        5928 :                                           state.dataDaylightingData->DaylRefPt(thisDaylightControl.DaylRefPtNum(refPtNum)).Name,
     615        5928 :                                           DaylFac);
     616             :                                 }
     617             :                             }
     618             :                         }
     619             :                     }
     620             :                 }
     621          62 :                 state.dataDaylightingManager->FirstTimeDaylFacCalc = false;
     622          62 :                 state.dataDaylightingManager->doSkyReporting = false;
     623             :             }
     624             :         }
     625             :     }
     626             : 
     627             :     // Skip if no daylight windows
     628         507 :     if (state.dataDaylightingManager->TotWindowsWithDayl == 0) return;
     629             : 
     630             :     // Skip if no request of reporting
     631         507 :     if ((!state.dataDaylightingData->DFSReportSizingDays) && (!state.dataDaylightingData->DFSReportAllShadowCalculationDays)) return;
     632             : 
     633             :     // Skip duplicate calls
     634           9 :     if (state.dataGlobal->KickOffSizing) return;
     635           7 :     if (state.dataGlobal->DoingSizing) return;
     636           5 :     if (state.dataGlobal->KickOffSimulation) return;
     637             : 
     638           2 :     if (state.dataDaylightingData->DFSReportSizingDays) {
     639           2 :         if (state.dataGlobal->DoWeathSim && state.dataGlobal->DoDesDaySim) {
     640           0 :             if (state.dataGlobal->KindOfSim == DataGlobalConstants::KindOfSim::RunPeriodWeather) return;
     641             :         }
     642             :     }
     643             : 
     644           2 :     if (state.dataDaylightingData->DFSReportAllShadowCalculationDays) {
     645           0 :         if (state.dataGlobal->KindOfSim != DataGlobalConstants::KindOfSim::RunPeriodWeather) return;
     646             :     }
     647             : 
     648             :     // open a new file eplusout.dfs for saving the daylight factors
     649           2 :     if (state.dataDaylightingManager->CreateDFSReportFile) {
     650           1 :         InputOutputFile &dfs = state.files.dfs.ensure_open(state, "CalcDayltgCoefficients", state.files.outputControl.dfs);
     651           1 :         print(dfs, "{}\n", "This file contains daylight factors for all exterior windows of daylight enclosures.");
     652           1 :         print(dfs, "{}\n", "MonthAndDay,Enclosure Name,Zone Name,Window Name,Window State");
     653           1 :         print(dfs,
     654             :               "{}\n",
     655             :               "Hour,Reference Point,Daylight Factor for Clear Sky,Daylight Factor for Clear Turbid Sky,"
     656           1 :               "Daylight Factor for Intermediate Sky,Daylight Factor for Overcast Sky");
     657           1 :         state.dataDaylightingManager->CreateDFSReportFile = false;
     658             :     }
     659             : 
     660          26 :     for (int controlNum = 1; controlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++controlNum) {
     661          24 :         auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
     662          24 :         int enclNum = thisDaylightControl.enclIndex;
     663          24 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
     664          24 :         if (thisEnclDaylight.NumOfDayltgExtWins == 0) continue;
     665             : 
     666          48 :         for (int windowCounter = 1; windowCounter <= thisEnclDaylight.NumOfDayltgExtWins; ++windowCounter) {
     667          24 :             int windowSurfNum = thisEnclDaylight.DayltgExtWinSurfNums(windowCounter);
     668             : 
     669             :             // For this report, do not include ext wins in zone/enclosure adjacent to ZoneNum since the inter-reflected
     670             :             // component will not be calculated for these windows until the time-step loop.
     671          24 :             if (state.dataSurface->Surface(windowSurfNum).SolarEnclIndex == enclNum) {
     672             : 
     673          24 :                 if (state.dataSurface->SurfWinMovableSlats(windowSurfNum)) {
     674             :                     // variable slat angle - MaxSlatangle sets
     675           0 :                     ISA = MaxSlatAngs + 1;
     676          24 :                 } else if (state.dataSurface->Surface(windowSurfNum).HasShadeControl) {
     677             :                     // window shade or blind with fixed slat angle
     678           0 :                     ISA = 2;
     679             :                 } else {
     680             :                     // base window
     681          24 :                     ISA = 1;
     682             :                 }
     683             : 
     684             :                 // loop over each slat angle
     685          48 :                 for (ISlatAngle = 1; ISlatAngle <= ISA; ++ISlatAngle) {
     686          24 :                     if (ISlatAngle == 1) {
     687             :                         // base window without shades, screens, or blinds
     688         120 :                         print(state.files.dfs,
     689             :                               "{},{},{},{},Base Window\n",
     690          24 :                               state.dataEnvrn->CurMnDy,
     691          24 :                               state.dataViewFactor->EnclSolInfo(enclNum).Name,
     692          24 :                               state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).Name,
     693          48 :                               state.dataSurface->Surface(windowSurfNum).Name);
     694           0 :                     } else if (ISlatAngle == 2 && ISA == 2) {
     695             :                         // window shade or blind with fixed slat angle
     696           0 :                         print(state.files.dfs,
     697             :                               "{},{},{},{},Blind or Slat Applied\n",
     698           0 :                               state.dataEnvrn->CurMnDy,
     699           0 :                               state.dataViewFactor->EnclSolInfo(enclNum).Name,
     700           0 :                               state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).Name,
     701           0 :                               state.dataSurface->Surface(windowSurfNum).Name);
     702             :                     } else {
     703             :                         // blind with variable slat angle
     704           0 :                         SlatAngle = 180.0 / double(MaxSlatAngs - 1) * double(ISlatAngle - 2);
     705           0 :                         print(state.files.dfs,
     706             :                               "{},{},{},{},{:.1R}\n",
     707           0 :                               state.dataEnvrn->CurMnDy,
     708           0 :                               state.dataViewFactor->EnclSolInfo(enclNum).Name,
     709           0 :                               state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).Name,
     710           0 :                               state.dataSurface->Surface(windowSurfNum).Name,
     711           0 :                               SlatAngle);
     712             :                     }
     713             : 
     714         600 :                     for (int IHR = 1; IHR <= 24; ++IHR) {
     715             :                         // For each Daylight Reference Point
     716        1152 :                         for (int refPtNum = 1; refPtNum <= thisDaylightControl.TotalDaylRefPoints; ++refPtNum) {
     717         576 :                             DFClrSky = thisDaylightControl.DaylIllFacSky(
     718         576 :                                 IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::Clear), refPtNum, windowCounter);
     719         576 :                             DFClrTbSky = thisDaylightControl.DaylIllFacSky(
     720         576 :                                 IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::ClearTurbid), refPtNum, windowCounter);
     721         576 :                             DFIntSky = thisDaylightControl.DaylIllFacSky(
     722         576 :                                 IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::Intermediate), refPtNum, windowCounter);
     723         576 :                             DFOcSky = thisDaylightControl.DaylIllFacSky(
     724         576 :                                 IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::Overcast), refPtNum, windowCounter);
     725             : 
     726             :                             // write daylight factors - 4 sky types for each daylight ref point
     727        1152 :                             print(state.files.dfs,
     728             :                                   "{},{},{:.5R},{:.5R},{:.5R},{:.5R}\n",
     729             :                                   IHR,
     730         576 :                                   state.dataDaylightingData->DaylRefPt(thisDaylightControl.DaylRefPtNum(refPtNum)).Name,
     731             :                                   DFClrSky,
     732             :                                   DFClrTbSky,
     733             :                                   DFIntSky,
     734         576 :                                   DFOcSky);
     735             :                         } // for (refPtNum) Reference Point
     736             :                     }     // for (IHR) hour
     737             :                 }         // for (ISlatAngle) slat angle
     738             :             }             // if (SolarEnclIndex == enclNum)
     739             :         }                 // for (windowCounter) exterior windows in enclosure
     740             :     }                     // for (controlNum) daylighting control
     741             : }
     742             : 
     743         507 : void CalcDayltgCoeffsRefMapPoints(EnergyPlusData &state)
     744             : {
     745             : 
     746             :     // SUBROUTINE INFORMATION:
     747             :     //       AUTHOR         Linda Lawrie
     748             :     //       DATE WRITTEN   October 2004
     749             :     //       MODIFIED       May 2006 (RR): added exterior window screens
     750             :     //                      April 2012 (LKL); change to allow multiple maps per zone
     751             : 
     752             :     // PURPOSE OF THIS SUBROUTINE:
     753             :     // This subroutine does the daylighting coefficient calculation for the
     754             :     // daylighting and illuminance map reference points.
     755             : 
     756             :     bool ErrorsFound;
     757             : 
     758         507 :     if (state.dataDaylightingManager->VeryFirstTime) {
     759             :         // make sure all necessary surfaces match to pipes
     760          62 :         ErrorsFound = false;
     761         770 :         for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
     762        1547 :             for (int loopwin = 1; loopwin <= state.dataDaylightingData->enclDaylight(enclNum).NumOfDayltgExtWins; ++loopwin) {
     763         839 :                 int IWin = state.dataDaylightingData->enclDaylight(enclNum).DayltgExtWinSurfNums(loopwin);
     764         839 :                 if (state.dataSurface->SurfWinOriginalClass(IWin) != SurfaceClass::TDD_Diffuser) continue;
     765             :                 // Look up the TDD:DOME object
     766           2 :                 int PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
     767           2 :                 if (PipeNum == 0) {
     768           0 :                     ShowSevereError(state,
     769           0 :                                     "GetTDDInput: Surface=" + state.dataSurface->Surface(IWin).Name +
     770             :                                         ", TDD:Dome object does not reference a valid Diffuser object.");
     771           0 :                     ShowContinueError(state, "...needs DaylightingDevice:Tubular of same name as Surface.");
     772           0 :                     ErrorsFound = true;
     773             :                 }
     774             :             }
     775             :         }
     776             : 
     777          62 :         if (ErrorsFound) {
     778           0 :             ShowFatalError(state, "Not all TubularDaylightDome objects have corresponding DaylightingDevice:Tubular objects. Program terminates.");
     779             :         }
     780          62 :         state.dataDaylightingManager->VeryFirstTime = false;
     781             :     }
     782             : 
     783             :     // Calc for daylighting reference points for daylighting controls that use SplitFlux method
     784        3251 :     for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
     785        2744 :         if (state.dataDaylightingData->daylightControl(daylightCtrlNum).DaylightMethod != DataDaylighting::DaylightingMethod::SplitFlux) continue;
     786             :         // Skip enclosures with no exterior windows or in adjacent enclosure(s) with which an interior window is shared
     787        2729 :         if (state.dataDaylightingData->enclDaylight(state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex).NumOfDayltgExtWins == 0)
     788           0 :             continue;
     789        2729 :         CalcDayltgCoeffsRefPoints(state, daylightCtrlNum);
     790             :     }
     791         507 :     if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
     792             :         // Calc for illuminance maps
     793         134 :         if ((int)state.dataDaylightingData->IllumMap.size() > 0) {
     794          44 :             for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
     795          24 :                 int mapZoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
     796          24 :                 if (state.dataGlobal->WarmupFlag) {
     797          24 :                     DisplayString(state, "Calculating Daylighting Coefficients (Map Points), Zone=" + state.dataHeatBal->Zone(mapZoneNum).Name);
     798             :                 } else {
     799           0 :                     DisplayString(state, "Updating Daylighting Coefficients (Map Points), Zone=" + state.dataHeatBal->Zone(mapZoneNum).Name);
     800             :                 }
     801          24 :                 CalcDayltgCoeffsMapPoints(state, MapNum);
     802             :             }
     803             :         }
     804             :     }
     805         507 : }
     806             : 
     807        2729 : void CalcDayltgCoeffsRefPoints(EnergyPlusData &state, int const daylightCtrlNum)
     808             : {
     809             : 
     810             :     // SUBROUTINE INFORMATION:
     811             :     //       AUTHOR         Linda Lawrie
     812             :     //       DATE WRITTEN   April 2012
     813             :     //       MODIFIED       November 2012 (B. Griffith), refactor for detailed timestep integration and remove duplicate code
     814             :     //       RE-ENGINEERED  na
     815             : 
     816             :     // PURPOSE OF THIS SUBROUTINE:
     817             :     // Provides calculations for Daylighting Coefficients for daylighting reference points
     818             : 
     819             :     int IHR;       // Hour of day counter
     820             :     int NRF;       // Number of daylighting reference points in a zone
     821             :     int IL;        // Reference point counter
     822             :     Real64 AZVIEW; // Azimuth of view vector in absolute coord system for
     823             :     //  glare calculation (radians)
     824             :     int IConst;            // Construction counter
     825             :     int ICtrl;             // Window control counter
     826             :     int IWin;              // Window counter
     827             :     int IWin2;             // Secondary window counter (for TDD:DOME object, if exists)
     828             :     int InShelfSurf;       // Inside daylighting shelf surface number
     829             :     WinShadingType ShType; // Window shading type
     830             :     int BlNum;             // Window Blind Number
     831             :     int LSHCAL;            // Interior shade calculation flag: 0=not yet
     832             :     //  calculated, 1=already calculated
     833             :     int NWX;     // Number of window elements in x direction for dayltg calc
     834             :     int NWY;     // Number of window elements in y direction for dayltg calc
     835             :     int NWYlim;  // For triangle, largest NWY for a given IX
     836             :     int IX;      // Counter for window elements in the x direction
     837             :     int IY;      // Counter for window elements in the y direction
     838             :     Real64 COSB; // Cosine of angle between window outward normal and ray from
     839             :     //  reference point to window element
     840             :     Real64 PHRAY;  // Altitude of ray from reference point to window element (radians)
     841             :     Real64 THRAY;  // Azimuth of ray from reference point to window element (radians)
     842             :     Real64 DOMEGA; // Solid angle subtended by window element wrt reference point (steradians)
     843             :     Real64 TVISB;  // Visible transmittance of window for COSB angle of incidence (times light well
     844             :     //   efficiency, if appropriate)
     845             :     int ISunPos; // Sun position counter; used to avoid calculating various
     846             :     //  quantities that do not depend on sun position.
     847             :     Real64 ObTrans; // Product of solar transmittances of exterior obstructions hit by ray
     848             :     // from reference point through a window element
     849             :     int loopwin;                            // loop index for exterior windows associated with a daylit zone
     850             :     bool is_Rectangle;                      // True if window is rectangular
     851             :     bool is_Triangle;                       // True if window is triangular
     852             :     Real64 DWX;                             // Horizontal dimension of window element (m)
     853             :     Real64 DWY;                             // Vertical dimension of window element (m)
     854             :     Real64 DAXY;                            // Area of window element
     855             :     Real64 SkyObstructionMult;              // Ratio of obstructed to unobstructed sky diffuse at a ground point
     856             :     DataDaylighting::ExtWinType ExtWinType; // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
     857             :     int BRef;
     858             :     int ILB;
     859             :     bool hitIntObs;        // True iff interior obstruction hit
     860             :     bool hitExtObs;        // True iff ray from ref pt to ext win hits an exterior obstruction
     861             :     Real64 TVISIntWin;     // Visible transmittance of int win at COSBIntWin for light from ext win
     862             :     Real64 TVISIntWinDisk; // Visible transmittance of int win at COSBIntWin for sun
     863             : 
     864        2729 :     auto &W2 = state.dataDaylightingManager->W2;
     865        2729 :     auto &W3 = state.dataDaylightingManager->W3;
     866        2729 :     auto &W21 = state.dataDaylightingManager->W21;
     867        2729 :     auto &W23 = state.dataDaylightingManager->W23;
     868        2729 :     auto &RREF = state.dataDaylightingManager->RREF;
     869        2729 :     auto &RREF2 = state.dataDaylightingManager->RREF2;
     870        2729 :     auto &RWIN = state.dataDaylightingManager->RWIN;
     871        2729 :     auto &RWIN2 = state.dataDaylightingManager->RWIN2;
     872        2729 :     auto &Ray = state.dataDaylightingManager->Ray;
     873        2729 :     auto &WNORM2 = state.dataDaylightingManager->WNORM2;
     874        2729 :     auto &VIEWVC = state.dataDaylightingManager->VIEWVC;
     875        2729 :     auto &U2 = state.dataDaylightingManager->U2;
     876        2729 :     auto &U21 = state.dataDaylightingManager->U21;
     877        2729 :     auto &U23 = state.dataDaylightingManager->U23;
     878        2729 :     auto &VIEWVC2 = state.dataDaylightingManager->VIEWVC2;
     879             : 
     880             :     int WinEl; // Current window element
     881             : 
     882        2729 :     if (state.dataDaylightingManager->refFirstTime && (state.dataDaylightingData->maxRefPointsPerControl > 0)) {
     883          62 :         state.dataDaylightingManager->RefErrIndex.allocate(state.dataDaylightingData->maxRefPointsPerControl, state.dataSurface->TotSurfaces);
     884          62 :         state.dataDaylightingManager->RefErrIndex = 0;
     885          62 :         state.dataDaylightingManager->refFirstTime = false;
     886             :     }
     887             : 
     888        2729 :     auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
     889        2729 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex);
     890        2729 :     int zoneNum = thisDaylightControl.zoneIndex;
     891             :     // Azimuth of view vector in absolute coord sys
     892        5458 :     AZVIEW = (thisDaylightControl.ViewAzimuthForGlare + state.dataHeatBal->Zone(zoneNum).RelNorth + state.dataHeatBal->BuildingAzimuth +
     893        2729 :               state.dataHeatBal->BuildingRotationAppendixG) *
     894             :              DataGlobalConstants::DegToRadians;
     895             :     // View vector components in absolute coord sys
     896        2729 :     VIEWVC(1) = std::sin(AZVIEW);
     897        2729 :     VIEWVC(2) = std::cos(AZVIEW);
     898        2729 :     VIEWVC(3) = 0.0;
     899             : 
     900        2729 :     thisDaylightControl.DaylIllumAtRefPt = 0.0;  // Daylight illuminance at reference points (lux)
     901        2729 :     thisDaylightControl.GlareIndexAtRefPt = 0.0; // Glare index at reference points
     902        2729 :     thisDaylightControl.SolidAngAtRefPt = 0.0;
     903        2729 :     thisDaylightControl.SolidAngAtRefPtWtd = 0.0;
     904        2729 :     thisDaylightControl.IllumFromWinAtRefPt = 0.0;
     905        2729 :     thisDaylightControl.BackLumFromWinAtRefPt = 0.0;
     906        2729 :     thisDaylightControl.SourceLumFromWinAtRefPt = 0.0;
     907             : 
     908        2729 :     if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
     909             : 
     910        2729 :         thisDaylightControl.DaylIllFacSky = 0.0;
     911        2729 :         thisDaylightControl.DaylSourceFacSky = 0.0;
     912        2729 :         thisDaylightControl.DaylBackFacSky = 0.0;
     913        2729 :         thisDaylightControl.DaylIllFacSun = 0.0;
     914        2729 :         thisDaylightControl.DaylIllFacSunDisk = 0.0;
     915        2729 :         thisDaylightControl.DaylSourceFacSun = 0.0;
     916        2729 :         thisDaylightControl.DaylSourceFacSunDisk = 0.0;
     917        2729 :         thisDaylightControl.DaylBackFacSun = 0.0;
     918        2729 :         thisDaylightControl.DaylBackFacSunDisk = 0.0;
     919             :     } else {
     920           0 :         int numRefPts = thisDaylightControl.TotalDaylRefPoints;
     921           0 :         thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay,
     922           0 :                                           {1, state.dataSurface->actualMaxSlatAngs + 1},
     923             :                                           {1, 4},
     924             :                                           {1, numRefPts},
     925           0 :                                           {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
     926           0 :         thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay,
     927           0 :                                              {1, state.dataSurface->actualMaxSlatAngs + 1},
     928             :                                              {1, 4},
     929             :                                              {1, numRefPts},
     930           0 :                                              {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
     931           0 :         thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay,
     932           0 :                                            {1, state.dataSurface->actualMaxSlatAngs + 1},
     933             :                                            {1, 4},
     934             :                                            {1, numRefPts},
     935           0 :                                            {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
     936           0 :         thisDaylightControl.DaylIllFacSun(
     937           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
     938           0 :             0.0;
     939           0 :         thisDaylightControl.DaylIllFacSunDisk(
     940           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
     941           0 :             0.0;
     942           0 :         thisDaylightControl.DaylSourceFacSun(
     943           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
     944           0 :             0.0;
     945           0 :         thisDaylightControl.DaylSourceFacSunDisk(
     946           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
     947           0 :             0.0;
     948           0 :         thisDaylightControl.DaylBackFacSun(
     949           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
     950           0 :             0.0;
     951           0 :         thisDaylightControl.DaylBackFacSunDisk(
     952           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
     953           0 :             0.0;
     954             :     }
     955             : 
     956        2729 :     NRF = thisDaylightControl.TotalDaylRefPoints;
     957        2729 :     BRef = 0;
     958             : 
     959        7286 :     for (IL = 1; IL <= NRF; ++IL) {
     960             :         // Reference point in absolute coordinate system
     961        4557 :         RREF = thisDaylightControl.DaylRefPtAbsCoord({1, 3}, IL); // ( x, y, z )
     962             : 
     963             :         //           -------------
     964             :         // ---------- WINDOW LOOP ----------
     965             :         //           -------------
     966       19587 :         for (loopwin = 1; loopwin <= thisEnclDaylight.NumOfDayltgExtWins; ++loopwin) {
     967             : 
     968       15030 :             FigureDayltgCoeffsAtPointsSetupForWindow(state,
     969             :                                                      daylightCtrlNum,
     970             :                                                      IL,
     971             :                                                      loopwin,
     972             :                                                      DataDaylighting::CalledFor::RefPoint,
     973             :                                                      RREF,
     974             :                                                      VIEWVC,
     975             :                                                      IWin,
     976             :                                                      IWin2,
     977             :                                                      NWX,
     978             :                                                      NWY,
     979             :                                                      W2,
     980             :                                                      W3,
     981             :                                                      W21,
     982             :                                                      W23,
     983             :                                                      LSHCAL,
     984             :                                                      InShelfSurf,
     985             :                                                      ICtrl,
     986             :                                                      ShType,
     987             :                                                      BlNum,
     988             :                                                      WNORM2,
     989             :                                                      ExtWinType,
     990             :                                                      IConst,
     991             :                                                      RREF2,
     992             :                                                      DWX,
     993             :                                                      DWY,
     994             :                                                      DAXY,
     995             :                                                      U2,
     996             :                                                      U23,
     997             :                                                      U21,
     998             :                                                      VIEWVC2,
     999             :                                                      is_Rectangle,
    1000             :                                                      is_Triangle);
    1001             :             //           ---------------------
    1002             :             // ---------- WINDOW ELEMENT LOOP ----------
    1003             :             //           ---------------------
    1004             : 
    1005       15030 :             WinEl = 0;
    1006             : 
    1007      205236 :             for (IX = 1; IX <= NWX; ++IX) {
    1008      190206 :                 if (is_Rectangle) {
    1009      190206 :                     NWYlim = NWY;
    1010           0 :                 } else if (is_Triangle) {
    1011           0 :                     NWYlim = NWY - IX + 1;
    1012             :                 }
    1013             : 
    1014      768910 :                 for (IY = 1; IY <= NWYlim; ++IY) {
    1015             : 
    1016      578704 :                     ++WinEl;
    1017             : 
    1018      578704 :                     FigureDayltgCoeffsAtPointsForWindowElements(state,
    1019             :                                                                 daylightCtrlNum,
    1020             :                                                                 IL,
    1021             :                                                                 loopwin,
    1022             :                                                                 DataDaylighting::CalledFor::RefPoint,
    1023             :                                                                 WinEl,
    1024             :                                                                 IWin,
    1025             :                                                                 IWin2,
    1026             :                                                                 IX,
    1027             :                                                                 IY,
    1028             :                                                                 SkyObstructionMult,
    1029             :                                                                 W2,
    1030             :                                                                 W21,
    1031             :                                                                 W23,
    1032             :                                                                 RREF,
    1033             :                                                                 NWYlim,
    1034             :                                                                 VIEWVC2,
    1035             :                                                                 DWX,
    1036             :                                                                 DWY,
    1037             :                                                                 DAXY,
    1038             :                                                                 U2,
    1039             :                                                                 U23,
    1040             :                                                                 U21,
    1041             :                                                                 RWIN,
    1042             :                                                                 RWIN2,
    1043             :                                                                 Ray,
    1044             :                                                                 PHRAY,
    1045             :                                                                 LSHCAL,
    1046             :                                                                 COSB,
    1047             :                                                                 ObTrans,
    1048             :                                                                 TVISB,
    1049             :                                                                 DOMEGA,
    1050             :                                                                 THRAY,
    1051             :                                                                 hitIntObs,
    1052             :                                                                 hitExtObs,
    1053             :                                                                 WNORM2,
    1054             :                                                                 ExtWinType,
    1055             :                                                                 IConst,
    1056             :                                                                 RREF2,
    1057             :                                                                 is_Triangle,
    1058             :                                                                 TVISIntWin,
    1059             :                                                                 TVISIntWinDisk);
    1060             : 
    1061             :                     //           -------------------
    1062             :                     // ---------- SUN POSITION LOOP ----------
    1063             :                     //           -------------------
    1064             : 
    1065             :                     // Sun position counter. Used to avoid calculating various quantities
    1066             :                     // that do not depend on sun position.
    1067             : 
    1068      578704 :                     if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
    1069      578704 :                         ISunPos = 0;
    1070    14467600 :                         for (IHR = 1; IHR <= 24; ++IHR) {
    1071             : 
    1072    13888896 :                             FigureDayltgCoeffsAtPointsForSunPosition(state,
    1073             :                                                                      daylightCtrlNum,
    1074             :                                                                      IL,
    1075             :                                                                      IX,
    1076             :                                                                      NWX,
    1077             :                                                                      IY,
    1078             :                                                                      NWYlim,
    1079             :                                                                      WinEl,
    1080             :                                                                      IWin,
    1081             :                                                                      IWin2,
    1082             :                                                                      IHR,
    1083             :                                                                      ISunPos,
    1084             :                                                                      SkyObstructionMult,
    1085             :                                                                      RWIN2,
    1086             :                                                                      Ray,
    1087             :                                                                      PHRAY,
    1088             :                                                                      LSHCAL,
    1089             :                                                                      InShelfSurf,
    1090             :                                                                      COSB,
    1091             :                                                                      ObTrans,
    1092             :                                                                      TVISB,
    1093             :                                                                      DOMEGA,
    1094             :                                                                      ICtrl,
    1095             :                                                                      ShType,
    1096             :                                                                      BlNum,
    1097             :                                                                      THRAY,
    1098             :                                                                      WNORM2,
    1099             :                                                                      ExtWinType,
    1100             :                                                                      IConst,
    1101             :                                                                      AZVIEW,
    1102             :                                                                      RREF2,
    1103             :                                                                      hitIntObs,
    1104             :                                                                      hitExtObs,
    1105             :                                                                      DataDaylighting::CalledFor::RefPoint,
    1106             :                                                                      TVISIntWin,
    1107             :                                                                      TVISIntWinDisk);
    1108             : 
    1109             :                         }    // End of hourly sun position loop, IHR
    1110             :                     } else { // timestep integrated
    1111           0 :                         if (state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
    1112           0 :                             ISunPos = 0;
    1113           0 :                             state.dataDaylightingManager->MySunIsUpFlag = true;
    1114           0 :                         } else if (state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
    1115           0 :                             ISunPos = 1;
    1116           0 :                         } else if (!state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
    1117           0 :                             state.dataDaylightingManager->MySunIsUpFlag = false;
    1118           0 :                             ISunPos = -1;
    1119           0 :                         } else if (!state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
    1120           0 :                             ISunPos = -1;
    1121             :                         }
    1122             : 
    1123           0 :                         FigureDayltgCoeffsAtPointsForSunPosition(state,
    1124             :                                                                  daylightCtrlNum,
    1125             :                                                                  IL,
    1126             :                                                                  IX,
    1127             :                                                                  NWX,
    1128             :                                                                  IY,
    1129             :                                                                  NWYlim,
    1130             :                                                                  WinEl,
    1131             :                                                                  IWin,
    1132             :                                                                  IWin2,
    1133           0 :                                                                  state.dataGlobal->HourOfDay,
    1134             :                                                                  ISunPos,
    1135             :                                                                  SkyObstructionMult,
    1136             :                                                                  RWIN2,
    1137             :                                                                  Ray,
    1138             :                                                                  PHRAY,
    1139             :                                                                  LSHCAL,
    1140             :                                                                  InShelfSurf,
    1141             :                                                                  COSB,
    1142             :                                                                  ObTrans,
    1143             :                                                                  TVISB,
    1144             :                                                                  DOMEGA,
    1145             :                                                                  ICtrl,
    1146             :                                                                  ShType,
    1147             :                                                                  BlNum,
    1148             :                                                                  THRAY,
    1149             :                                                                  WNORM2,
    1150             :                                                                  ExtWinType,
    1151             :                                                                  IConst,
    1152             :                                                                  AZVIEW,
    1153             :                                                                  RREF2,
    1154             :                                                                  hitIntObs,
    1155             :                                                                  hitExtObs,
    1156             :                                                                  DataDaylighting::CalledFor::RefPoint,
    1157             :                                                                  TVISIntWin,
    1158             :                                                                  TVISIntWinDisk);
    1159             :                     }
    1160             : 
    1161             :                 } // End of window Y-element loop, IY
    1162             :             }     // End of window X-element loop, IX
    1163             : 
    1164             :             // Loop again over hourly sun positions and calculate daylight factors by adding
    1165             :             // direct and inter-reflected illum components, then dividing by exterior horiz illum.
    1166             :             // Also calculate corresponding glare factors.
    1167             : 
    1168       15030 :             ILB = BRef + IL;
    1169             : 
    1170       15030 :             if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
    1171       15030 :                 ISunPos = 0;
    1172      375750 :                 for (IHR = 1; IHR <= 24; ++IHR) {
    1173      360720 :                     FigureRefPointDayltgFactorsToAddIllums(state, daylightCtrlNum, ILB, IHR, ISunPos, IWin, loopwin, NWX, NWY, ICtrl);
    1174             : 
    1175             :                 } // End of sun position loop, IHR
    1176             :             } else {
    1177           0 :                 if (state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
    1178           0 :                     ISunPos = 0;
    1179           0 :                     state.dataDaylightingManager->MySunIsUpFlag = true;
    1180           0 :                 } else if (state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
    1181           0 :                     ISunPos = 1;
    1182           0 :                 } else if (!state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
    1183           0 :                     state.dataDaylightingManager->MySunIsUpFlag = false;
    1184           0 :                     ISunPos = -1;
    1185           0 :                 } else if (!state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
    1186           0 :                     ISunPos = -1;
    1187             :                 }
    1188           0 :                 FigureRefPointDayltgFactorsToAddIllums(
    1189           0 :                     state, daylightCtrlNum, ILB, state.dataGlobal->HourOfDay, ISunPos, IWin, loopwin, NWX, NWY, ICtrl);
    1190             :             }
    1191             :         } // End of window loop, loopwin - IWin
    1192             : 
    1193             :     } // End of reference point loop, IL
    1194        2729 : }
    1195             : 
    1196          24 : void CalcDayltgCoeffsMapPoints(EnergyPlusData &state, int const mapNum)
    1197             : {
    1198             : 
    1199             :     // SUBROUTINE INFORMATION:
    1200             :     //       AUTHOR         Linda Lawrie
    1201             :     //       DATE WRITTEN   April 2012
    1202             :     //       MODIFIED      November 2012 (B. Griffith), refactor for detailed timestep integration and remove duplicate code
    1203             :     //       RE-ENGINEERED  na
    1204             : 
    1205             :     // PURPOSE OF THIS SUBROUTINE:
    1206             :     // Provides calculations for Daylighting Coefficients for map illuminance points
    1207             : 
    1208             :     // METHODOLOGY EMPLOYED:
    1209             :     // Was previously part of CalcDayltgCoeffsRefMapPoints -- broken out to all multiple
    1210             :     // maps per zone
    1211             : 
    1212             :     //  In the following four variables, I=1 for clear sky, 2 for overcast.
    1213             :     int IHR;       // Hour of day counter
    1214             :     int numRefPts; // Number of daylighting reference points in a zone
    1215             :     int IL;        // Reference point counter
    1216             :     Real64 AZVIEW; // Azimuth of view vector in absolute coord system for
    1217             :     //  glare calculation (radians)
    1218             :     int IConst;            // Construction counter
    1219             :     int ICtrl;             // Window control counter
    1220             :     int IWin;              // Window counter
    1221             :     int IWin2;             // Secondary window counter (for TDD:DOME object, if exists)
    1222             :     int InShelfSurf;       // Inside daylighting shelf surface number
    1223             :     WinShadingType ShType; // Window shading type
    1224             :     int BlNum;             // Window Blind Number
    1225             :     int LSHCAL;            // Interior shade calculation flag: 0=not yet
    1226             :     //  calculated, 1=already calculated
    1227             :     int NWX;     // Number of window elements in x direction for dayltg calc
    1228             :     int NWY;     // Number of window elements in y direction for dayltg calc
    1229             :     int NWYlim;  // For triangle, largest NWY for a given IX
    1230             :     Real64 DWX;  // Horizontal dimension of window element (m)
    1231             :     Real64 DWY;  // Vertical dimension of window element (m)
    1232             :     int IX;      // Counter for window elements in the x direction
    1233             :     int IY;      // Counter for window elements in the y direction
    1234             :     Real64 COSB; // Cosine of angle between window outward normal and ray from
    1235             :     //  reference point to window element
    1236             :     Real64 PHRAY;  // Altitude of ray from reference point to window element (radians)
    1237             :     Real64 THRAY;  // Azimuth of ray from reference point to window element (radians)
    1238             :     Real64 DOMEGA; // Solid angle subtended by window element wrt reference point (steradians)
    1239             :     Real64 TVISB;  // Visible transmittance of window for COSB angle of incidence (times light well
    1240             :     //   efficiency, if appropriate)
    1241             :     int ISunPos; // Sun position counter; used to avoid calculating various
    1242             :     //  quantities that do not depend on sun position.
    1243             :     Real64 ObTrans; // Product of solar transmittances of exterior obstructions hit by ray
    1244             :     // from reference point through a window element
    1245             :     int loopwin;                            // loop index for exterior windows associated with a daylit zone
    1246             :     bool is_Rectangle;                      // True if window is rectangular
    1247             :     bool is_Triangle;                       // True if window is triangular
    1248             :     Real64 DAXY;                            // Area of window element
    1249             :     Real64 SkyObstructionMult;              // Ratio of obstructed to unobstructed sky diffuse at a ground point
    1250             :     DataDaylighting::ExtWinType ExtWinType; // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
    1251             :     int ILB;
    1252             :     bool hitIntObs;        // True iff interior obstruction hit
    1253             :     bool hitExtObs;        // True iff ray from ref pt to ext win hits an exterior obstruction
    1254             :     Real64 TVISIntWin;     // Visible transmittance of int win at COSBIntWin for light from ext win
    1255             :     Real64 TVISIntWinDisk; // Visible transmittance of int win at COSBIntWin for sun
    1256          24 :     auto &MySunIsUpFlag(state.dataDaylightingManager->CalcDayltgCoeffsMapPointsMySunIsUpFlag);
    1257             :     int WinEl; // window elements counter
    1258             : 
    1259          24 :     auto &W2 = state.dataDaylightingManager->W2;
    1260          24 :     auto &W3 = state.dataDaylightingManager->W3;
    1261          24 :     auto &W21 = state.dataDaylightingManager->W21;
    1262          24 :     auto &W23 = state.dataDaylightingManager->W23;
    1263          24 :     auto &RREF = state.dataDaylightingManager->RREF;
    1264          24 :     auto &RREF2 = state.dataDaylightingManager->RREF2;
    1265          24 :     auto &RWIN = state.dataDaylightingManager->RWIN;
    1266          24 :     auto &RWIN2 = state.dataDaylightingManager->RWIN2;
    1267          24 :     auto &Ray = state.dataDaylightingManager->Ray;
    1268          24 :     auto &WNORM2 = state.dataDaylightingManager->WNORM2;
    1269          24 :     auto &VIEWVC = state.dataDaylightingManager->VIEWVC;
    1270          24 :     auto &U2 = state.dataDaylightingManager->U2;
    1271          24 :     auto &U21 = state.dataDaylightingManager->U21;
    1272          24 :     auto &U23 = state.dataDaylightingManager->U23;
    1273          24 :     auto &VIEWVC2 = state.dataDaylightingManager->VIEWVC2;
    1274             : 
    1275          24 :     if (state.dataDaylightingManager->mapFirstTime && (int)state.dataDaylightingData->IllumMap.size() > 0) {
    1276           5 :         IL = -999;
    1277          12 :         for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
    1278           7 :             IL = max(IL, state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints);
    1279             :         }
    1280           5 :         state.dataDaylightingManager->MapErrIndex.dimension(IL, state.dataSurface->TotSurfaces, 0);
    1281           5 :         state.dataDaylightingManager->mapFirstTime = false;
    1282             :     }
    1283             : 
    1284          24 :     int enclNum = state.dataDaylightingData->IllumMapCalc(mapNum).enclIndex;
    1285          24 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
    1286             : 
    1287             :     // Azimuth of view vector in absolute coord sys - set to zero here, because glare isn't calculated for map points
    1288             :     // but these are arguments to some of the functions that are shared with regular reference points, so initalize here.
    1289          24 :     AZVIEW = 0.0;
    1290             :     // View vector components in absolute coord sys
    1291          24 :     VIEWVC(1) = 0.0;
    1292          24 :     VIEWVC(2) = 0.0;
    1293          24 :     VIEWVC(3) = 0.0;
    1294             : 
    1295          24 :     numRefPts = state.dataDaylightingData->IllumMapCalc(mapNum).TotalMapRefPoints;
    1296             : 
    1297          24 :     state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPt = 0.0; // Daylight illuminance at reference points (lux)
    1298          24 :     state.dataDaylightingData->IllumMapCalc(mapNum).IllumFromWinAtMapPt = 0.0;
    1299          24 :     if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
    1300          24 :         state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSky = 0.0;
    1301          24 :         state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSun = 0.0;
    1302          24 :         state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSunDisk = 0.0;
    1303             :     } else {
    1304           0 :         state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSky(state.dataGlobal->HourOfDay,
    1305           0 :                                                                       {1, state.dataSurface->actualMaxSlatAngs + 1},
    1306             :                                                                       {1, 4},
    1307             :                                                                       {1, numRefPts},
    1308           0 :                                                                       {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
    1309           0 :         state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSun(
    1310           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
    1311           0 :             0.0;
    1312           0 :         state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSunDisk(
    1313           0 :             state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
    1314           0 :             0.0;
    1315             :     }
    1316             : 
    1317        2124 :     for (IL = 1; IL <= numRefPts; ++IL) {
    1318             : 
    1319        2100 :         RREF = state.dataDaylightingData->IllumMapCalc(mapNum).MapRefPtAbsCoord({1, 3}, IL); // (x, y, z)
    1320             : 
    1321             :         //           -------------
    1322             :         // ---------- WINDOW LOOP ----------
    1323             :         //           -------------
    1324             : 
    1325       15500 :         for (loopwin = 1; loopwin <= thisEnclDaylight.NumOfDayltgExtWins; ++loopwin) {
    1326             : 
    1327             :             // daylightingCtrlNum parameter is unused for map points
    1328       13400 :             FigureDayltgCoeffsAtPointsSetupForWindow(state,
    1329             :                                                      0,
    1330             :                                                      IL,
    1331             :                                                      loopwin,
    1332             :                                                      DataDaylighting::CalledFor::MapPoint,
    1333             :                                                      RREF,
    1334             :                                                      VIEWVC,
    1335             :                                                      IWin,
    1336             :                                                      IWin2,
    1337             :                                                      NWX,
    1338             :                                                      NWY,
    1339             :                                                      W2,
    1340             :                                                      W3,
    1341             :                                                      W21,
    1342             :                                                      W23,
    1343             :                                                      LSHCAL,
    1344             :                                                      InShelfSurf,
    1345             :                                                      ICtrl,
    1346             :                                                      ShType,
    1347             :                                                      BlNum,
    1348             :                                                      WNORM2,
    1349             :                                                      ExtWinType,
    1350             :                                                      IConst,
    1351             :                                                      RREF2,
    1352             :                                                      DWX,
    1353             :                                                      DWY,
    1354             :                                                      DAXY,
    1355             :                                                      U2,
    1356             :                                                      U23,
    1357             :                                                      U21,
    1358             :                                                      VIEWVC2,
    1359             :                                                      is_Rectangle,
    1360             :                                                      is_Triangle,
    1361             :                                                      mapNum);
    1362             :             //           ---------------------
    1363             :             // ---------- WINDOW ELEMENT LOOP ----------
    1364             :             //           ---------------------
    1365       13400 :             WinEl = 0;
    1366             : 
    1367       84320 :             for (IX = 1; IX <= NWX; ++IX) {
    1368       70920 :                 if (is_Rectangle) {
    1369       70920 :                     NWYlim = NWY;
    1370           0 :                 } else if (is_Triangle) {
    1371           0 :                     NWYlim = NWY - IX + 1;
    1372             :                 }
    1373             : 
    1374     2230160 :                 for (IY = 1; IY <= NWYlim; ++IY) {
    1375             : 
    1376     2159240 :                     ++WinEl;
    1377             : 
    1378             :                     // daylightingCtrlNum parameter is unused for map points
    1379     2159240 :                     FigureDayltgCoeffsAtPointsForWindowElements(state,
    1380             :                                                                 0,
    1381             :                                                                 IL,
    1382             :                                                                 loopwin,
    1383             :                                                                 DataDaylighting::CalledFor::MapPoint,
    1384             :                                                                 WinEl,
    1385             :                                                                 IWin,
    1386             :                                                                 IWin2,
    1387             :                                                                 IX,
    1388             :                                                                 IY,
    1389             :                                                                 SkyObstructionMult,
    1390             :                                                                 W2,
    1391             :                                                                 W21,
    1392             :                                                                 W23,
    1393             :                                                                 RREF,
    1394             :                                                                 NWYlim,
    1395             :                                                                 VIEWVC2,
    1396             :                                                                 DWX,
    1397             :                                                                 DWY,
    1398             :                                                                 DAXY,
    1399             :                                                                 U2,
    1400             :                                                                 U23,
    1401             :                                                                 U21,
    1402             :                                                                 RWIN,
    1403             :                                                                 RWIN2,
    1404             :                                                                 Ray,
    1405             :                                                                 PHRAY,
    1406             :                                                                 LSHCAL,
    1407             :                                                                 COSB,
    1408             :                                                                 ObTrans,
    1409             :                                                                 TVISB,
    1410             :                                                                 DOMEGA,
    1411             :                                                                 THRAY,
    1412             :                                                                 hitIntObs,
    1413             :                                                                 hitExtObs,
    1414             :                                                                 WNORM2,
    1415             :                                                                 ExtWinType,
    1416             :                                                                 IConst,
    1417             :                                                                 RREF2,
    1418             :                                                                 is_Triangle,
    1419             :                                                                 TVISIntWin,
    1420             :                                                                 TVISIntWinDisk,
    1421             :                                                                 mapNum);
    1422             :                     //           -------------------
    1423             :                     // ---------- SUN POSITION LOOP ----------
    1424             :                     //           -------------------
    1425             : 
    1426             :                     // Sun position counter. Used to avoid calculating various quantities
    1427             :                     // that do not depend on sun position.
    1428     2159240 :                     if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
    1429     2159240 :                         ISunPos = 0;
    1430    53981000 :                         for (IHR = 1; IHR <= 24; ++IHR) {
    1431             :                             // daylightingCtrlNum parameter is unused for map points
    1432    51821760 :                             FigureDayltgCoeffsAtPointsForSunPosition(state,
    1433             :                                                                      0,
    1434             :                                                                      IL,
    1435             :                                                                      IX,
    1436             :                                                                      NWX,
    1437             :                                                                      IY,
    1438             :                                                                      NWYlim,
    1439             :                                                                      WinEl,
    1440             :                                                                      IWin,
    1441             :                                                                      IWin2,
    1442             :                                                                      IHR,
    1443             :                                                                      ISunPos,
    1444             :                                                                      SkyObstructionMult,
    1445             :                                                                      RWIN2,
    1446             :                                                                      Ray,
    1447             :                                                                      PHRAY,
    1448             :                                                                      LSHCAL,
    1449             :                                                                      InShelfSurf,
    1450             :                                                                      COSB,
    1451             :                                                                      ObTrans,
    1452             :                                                                      TVISB,
    1453             :                                                                      DOMEGA,
    1454             :                                                                      ICtrl,
    1455             :                                                                      ShType,
    1456             :                                                                      BlNum,
    1457             :                                                                      THRAY,
    1458             :                                                                      WNORM2,
    1459             :                                                                      ExtWinType,
    1460             :                                                                      IConst,
    1461             :                                                                      AZVIEW,
    1462             :                                                                      RREF2,
    1463             :                                                                      hitIntObs,
    1464             :                                                                      hitExtObs,
    1465             :                                                                      DataDaylighting::CalledFor::MapPoint,
    1466             :                                                                      TVISIntWin,
    1467             :                                                                      TVISIntWinDisk,
    1468             :                                                                      mapNum);
    1469             :                         } // End of hourly sun position loop, IHR
    1470             :                     } else {
    1471           0 :                         if (state.dataEnvrn->SunIsUp && !MySunIsUpFlag) {
    1472           0 :                             ISunPos = 0;
    1473           0 :                             MySunIsUpFlag = true;
    1474           0 :                         } else if (state.dataEnvrn->SunIsUp && MySunIsUpFlag) {
    1475           0 :                             ISunPos = 1;
    1476           0 :                         } else if (!state.dataEnvrn->SunIsUp && MySunIsUpFlag) {
    1477           0 :                             MySunIsUpFlag = false;
    1478           0 :                             ISunPos = -1;
    1479           0 :                         } else if (!state.dataEnvrn->SunIsUp && !MySunIsUpFlag) {
    1480           0 :                             ISunPos = -1;
    1481             :                         }
    1482             :                         // daylightingCtrlNum parameter is unused for map points
    1483           0 :                         FigureDayltgCoeffsAtPointsForSunPosition(state,
    1484             :                                                                  0,
    1485             :                                                                  IL,
    1486             :                                                                  IX,
    1487             :                                                                  NWX,
    1488             :                                                                  IY,
    1489             :                                                                  NWYlim,
    1490             :                                                                  WinEl,
    1491             :                                                                  IWin,
    1492             :                                                                  IWin2,
    1493           0 :                                                                  state.dataGlobal->HourOfDay,
    1494             :                                                                  ISunPos,
    1495             :                                                                  SkyObstructionMult,
    1496             :                                                                  RWIN2,
    1497             :                                                                  Ray,
    1498             :                                                                  PHRAY,
    1499             :                                                                  LSHCAL,
    1500             :                                                                  InShelfSurf,
    1501             :                                                                  COSB,
    1502             :                                                                  ObTrans,
    1503             :                                                                  TVISB,
    1504             :                                                                  DOMEGA,
    1505             :                                                                  ICtrl,
    1506             :                                                                  ShType,
    1507             :                                                                  BlNum,
    1508             :                                                                  THRAY,
    1509             :                                                                  WNORM2,
    1510             :                                                                  ExtWinType,
    1511             :                                                                  IConst,
    1512             :                                                                  AZVIEW,
    1513             :                                                                  RREF2,
    1514             :                                                                  hitIntObs,
    1515             :                                                                  hitExtObs,
    1516             :                                                                  DataDaylighting::CalledFor::MapPoint,
    1517             :                                                                  TVISIntWin,
    1518             :                                                                  TVISIntWinDisk,
    1519             :                                                                  mapNum);
    1520             :                     }
    1521             :                 } // End of window Y-element loop, IY
    1522             :             }     // End of window X-element loop, IX
    1523             : 
    1524       13400 :             if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
    1525             :                 // Loop again over hourly sun positions and calculate daylight factors by adding
    1526             :                 // direct and inter-reflected illum components, then dividing by exterior horiz illum.
    1527             :                 // Also calculate corresponding glare factors.
    1528       13400 :                 ILB = IL;
    1529      335000 :                 for (IHR = 1; IHR <= 24; ++IHR) {
    1530      321600 :                     FigureMapPointDayltgFactorsToAddIllums(state, mapNum, ILB, IHR, IWin, loopwin, ICtrl);
    1531             :                 } // End of sun position loop, IHR
    1532             :             } else {
    1533           0 :                 ILB = IL;
    1534           0 :                 FigureMapPointDayltgFactorsToAddIllums(state, mapNum, ILB, state.dataGlobal->HourOfDay, IWin, loopwin, ICtrl);
    1535             :             }
    1536             : 
    1537             :         } // End of window loop, loopwin - IWin
    1538             : 
    1539             :     } // End of reference point loop, IL
    1540          24 : }
    1541             : 
    1542       28430 : void FigureDayltgCoeffsAtPointsSetupForWindow(
    1543             :     EnergyPlusData &state,
    1544             :     int const daylightCtrlNum, // zero if called for map points
    1545             :     int const iRefPoint,
    1546             :     int const loopwin,
    1547             :     DataDaylighting::CalledFor const CalledFrom, // indicate  which type of routine called this routine
    1548             :     Vector3<Real64> const &RREF,                 // Location of a reference point in absolute coordinate system
    1549             :     Vector3<Real64> const &VIEWVC,               // View vector in absolute coordinate system
    1550             :     int &IWin,
    1551             :     int &IWin2,
    1552             :     int &NWX,
    1553             :     int &NWY,
    1554             :     Vector3<Real64> &W2,                     // Second vertex of window
    1555             :     Vector3<Real64> &W3,                     // Third vertex of window
    1556             :     Vector3<Real64> &W21,                    // Vector from window vertex 2 to window vertex 1
    1557             :     Vector3<Real64> &W23,                    // Vector from window vertex 2 to window vertex 3
    1558             :     int &LSHCAL,                             // Interior shade calculation flag:  0=not yet calculated, 1=already calculated
    1559             :     int &InShelfSurf,                        // Inside daylighting shelf surface number
    1560             :     int &ICtrl,                              // Window control counter
    1561             :     WinShadingType &ShType,                  // Window shading type
    1562             :     int &BlNum,                              // Window blind number
    1563             :     Vector3<Real64> &WNORM2,                 // Unit vector normal to window
    1564             :     DataDaylighting::ExtWinType &ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
    1565             :     int &IConst,                             // Construction counter
    1566             :     Vector3<Real64> &RREF2,                  // Location of virtual reference point in absolute coordinate system
    1567             :     Real64 &DWX,                             // Horizontal dimension of window element (m)
    1568             :     Real64 &DWY,                             // Vertical dimension of window element (m)
    1569             :     Real64 &DAXY,                            // Area of window element
    1570             :     Vector3<Real64> &U2,                     // Second vertex of window for TDD:DOME (if exists)
    1571             :     Vector3<Real64> &U23,                    // Vector from window vertex 2 to window vertex 3 for TDD:DOME (if exists)
    1572             :     Vector3<Real64> &U21,                    // Vector from window vertex 2 to window vertex 1 for TDD:DOME (if exists)
    1573             :     Vector3<Real64> &VIEWVC2,                // Virtual view vector in absolute coordinate system
    1574             :     bool &is_Rectangle,                      // True if window is rectangular
    1575             :     bool &is_Triangle,                       // True if window is triangular
    1576             :     int const MapNum)
    1577             : {
    1578             :     // SUBROUTINE INFORMATION:
    1579             :     //       AUTHOR         B. Griffith
    1580             :     //       DATE WRITTEN   November 2012, refactor from legacy code by Fred Winklemann
    1581             : 
    1582             :     // PURPOSE OF THIS SUBROUTINE:
    1583             :     // collect code to setup calculations for each window for daylighting coefficients
    1584             : 
    1585             :     // METHODOLOGY EMPLOYED:
    1586             :     // switch as need to serve both reference points and map points based on calledFrom
    1587             : 
    1588             :     int ShelfNum;     // Daylighting shelf object number
    1589             :     int IConstShaded; // Shaded construction counter
    1590             :     Real64 WW;        // Window width (m)
    1591             :     Real64 HW;        // Window height (m)
    1592             : 
    1593             :     int NDIVX;  // Number of window x divisions for daylighting calc
    1594             :     int NDIVY;  // Number of window y divisions for daylighting calc
    1595             :     Real64 ALF; // Distance from reference point to window plane (m)
    1596             :     Real64 D1a; // Projection of vector from window origin to reference
    1597             :     //  on window X  axis (m)
    1598             :     Real64 D1b; // Projection of vector from window origin to reference
    1599             :     //  on window Y axis (m)
    1600             :     Real64 SolidAngExtWin;    // Approx. solid angle subtended by an ext. window wrt ref pt
    1601             :     Real64 SolidAngMinIntWin; // Approx. smallest solid angle subtended by an int. window wrt ref pt
    1602             :     Real64 SolidAngRatio;     // Ratio of SolidAngExtWin and SolidAngMinIntWin
    1603             :     int PipeNum;              // TDD pipe object number
    1604             :     Real64 SinCornerAng;      // For triangle, sine of corner angle of window element
    1605             : 
    1606       28430 :     int zoneNum = 0; // zone number
    1607       28430 :     int enclNum = 0; // enclosure number
    1608             : 
    1609       28430 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    1610       15030 :         state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPt(loopwin, iRefPoint) = 0.0;
    1611       15030 :         state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPtWtd(loopwin, iRefPoint) = 0.0;
    1612       15030 :         zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
    1613       15030 :         enclNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex;
    1614       13400 :     } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    1615       13400 :         assert(MapNum > 0);
    1616       13400 :         zoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
    1617       13400 :         enclNum = state.dataDaylightingData->IllumMapCalc(MapNum).enclIndex;
    1618             :     }
    1619       28430 :     IWin = state.dataDaylightingData->enclDaylight(enclNum).DayltgExtWinSurfNums(loopwin);
    1620             : 
    1621       28430 :     if (state.dataSurface->Surface(state.dataSurface->Surface(IWin).BaseSurf).SolarEnclIndex == enclNum) {
    1622       28226 :         ExtWinType = DataDaylighting::ExtWinType::InZoneExtWin;
    1623             :     } else {
    1624         204 :         ExtWinType = DataDaylighting::ExtWinType::AdjZoneExtWin;
    1625             :     }
    1626             : 
    1627       28430 :     IConst = state.dataSurface->SurfActiveConstruction(IWin);
    1628             : 
    1629             :     // For thermochromic windows, the daylight and glare factors are calculated for a base window cosntruction
    1630             :     //  at base TC layer temperature. During each time step calculations at DayltgInteriorIllum,
    1631             :     //  DayltgInteriorMapIllum, and DayltgGlare, the daylight and glare factors are adjusted by the visible
    1632             :     //  transmittance ratio = VT of actual TC window based on last hour TC layer temperature / VT of the base TC window
    1633       28430 :     if (state.dataConstruction->Construct(IConst).TCFlag == 1) {
    1634             :         // For thermochromic windows, use the base window construction at base temperature of the TC layer
    1635           0 :         IConst = state.dataConstruction->Construct(IConst).TCMasterConst;
    1636             :     }
    1637             : 
    1638       28430 :     ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    1639       28430 :     ShType = WinShadingType::NoShade; // 'NOSHADE'
    1640       28430 :     BlNum = 0;
    1641             :     // ScNum = 0; //Unused Set but never used
    1642       28430 :     if (state.dataSurface->Surface(IWin).HasShadeControl) ShType = state.dataSurface->WindowShadingControl(ICtrl).ShadingType;
    1643       28430 :     BlNum = state.dataSurface->SurfWinBlindNumber(IWin);
    1644             :     // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used
    1645             : 
    1646       28430 :     ShelfNum = state.dataSurface->SurfDaylightingShelfInd(IWin);
    1647       28430 :     if (ShelfNum > 0) {
    1648         420 :         InShelfSurf = state.dataDaylightingDevicesData->Shelf(state.dataSurface->SurfDaylightingShelfInd(IWin))
    1649         210 :                           .InSurf; // Inside daylighting shelf present if > 0
    1650             :     } else {
    1651       28220 :         InShelfSurf = 0;
    1652             :     }
    1653             : 
    1654       28430 :     is_Rectangle = false;
    1655       28430 :     is_Triangle = false;
    1656       28430 :     if (state.dataSurface->Surface(IWin).Sides == 3) is_Triangle = true;
    1657       28430 :     if (state.dataSurface->Surface(IWin).Sides == 4) is_Rectangle = true;
    1658             : 
    1659       28430 :     if (is_Rectangle) {
    1660             :         // Vertices of window (numbered counter-clockwise starting at upper left as viewed
    1661             :         // from inside of room). Assumes original vertices are numbered counter-clockwise from
    1662             :         // upper left as viewed from outside.
    1663       28430 :         W3 = state.dataSurface->Surface(IWin).Vertex(2);
    1664       28430 :         W2 = state.dataSurface->Surface(IWin).Vertex(3);
    1665       28430 :         state.dataDaylightingManager->W1 = state.dataSurface->Surface(IWin).Vertex(4);
    1666           0 :     } else if (is_Triangle) {
    1667           0 :         W3 = state.dataSurface->Surface(IWin).Vertex(2);
    1668           0 :         W2 = state.dataSurface->Surface(IWin).Vertex(3);
    1669           0 :         state.dataDaylightingManager->W1 = state.dataSurface->Surface(IWin).Vertex(1);
    1670             :     }
    1671             : 
    1672             :     // Shade/blind calculation flag
    1673       28430 :     LSHCAL = 0;
    1674             : 
    1675             :     // Visible transmittance at normal incidence
    1676       28430 :     state.dataSurface->SurfWinVisTransSelected(IWin) =
    1677       28430 :         General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin);
    1678             :     // For windows with switchable glazing, ratio of visible transmittance at normal
    1679             :     // incidence for fully switched (dark) state to that of unswitched state
    1680       28430 :     state.dataSurface->SurfWinVisTransRatio(IWin) = 1.0;
    1681       28430 :     if (ICtrl > 0) {
    1682       12594 :         if (ShType == WinShadingType::SwitchableGlazing) {
    1683       12562 :             IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
    1684       12562 :             state.dataSurface->SurfWinVisTransRatio(IWin) =
    1685       12562 :                 General::SafeDivide(General::POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef),
    1686       12562 :                                     General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef));
    1687             :         }
    1688             :     }
    1689             : 
    1690             :     // Unit vectors from window vertex 2 to 1 and 2 to 3,
    1691             :     // center point of window, and vector from ref pt to center of window
    1692       28430 :     W21 = state.dataDaylightingManager->W1 - W2;
    1693       28430 :     W23 = W3 - W2;
    1694       28430 :     HW = W21.magnitude();
    1695       28430 :     WW = W23.magnitude();
    1696       28430 :     if (is_Rectangle) {
    1697       28430 :         state.dataDaylightingManager->WC = W2 + (W23 + W21) / 2.0;
    1698           0 :     } else if (is_Triangle) {
    1699           0 :         state.dataDaylightingManager->WC = W2 + (W23 + W21) / 3.0;
    1700             :     }
    1701       28430 :     state.dataSurface->SurfaceWindow(IWin).WinCenter = state.dataDaylightingManager->WC;
    1702       28430 :     state.dataDaylightingManager->REFWC = state.dataDaylightingManager->WC - RREF;
    1703             :     // Unit vectors
    1704       28430 :     W21 /= HW;
    1705       28430 :     W23 /= WW;
    1706             : 
    1707             :     // Unit vector normal to window (pointing away from room)
    1708       28430 :     state.dataDaylightingManager->WNORM = state.dataSurface->Surface(IWin).lcsz;
    1709             : 
    1710             :     // Initialize number of window elements
    1711       28430 :     NDIVX = 40;
    1712       28430 :     NDIVY = 40;
    1713             : 
    1714             :     // Distance from ref point to window plane
    1715       28430 :     ALF = std::abs(dot(state.dataDaylightingManager->WNORM, state.dataDaylightingManager->REFWC));
    1716       28430 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    1717             :         // Check if ref point to close to window due to input error (0.1524 m below is 0.5 ft)
    1718       15030 :         if (ALF < 0.1524 && ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin) {
    1719             :             // Ref pt is close to window plane. Get vector from window
    1720             :             // origin to projection of ref pt on window plane.
    1721           0 :             state.dataDaylightingManager->W2REF = RREF + ALF * state.dataDaylightingManager->WNORM - W2;
    1722             : 
    1723           0 :             D1a = dot(state.dataDaylightingManager->W2REF, W23);
    1724           0 :             D1b = dot(state.dataDaylightingManager->W2REF, W21);
    1725             : 
    1726             :             //            ! Error message if ref pt is too close to window.
    1727           0 :             if (D1a > 0.0 && D1b > 0.0 && D1b <= HW && D1a <= WW) {
    1728           0 :                 ShowSevereError(
    1729             :                     state,
    1730           0 :                     format("CalcDaylightCoeffRefPoints: Daylighting calculation cannot be done for Daylighting:Controls={} because reference point "
    1731             :                            "#{} is less than 0.15m (6\") from window plane {}",
    1732           0 :                            state.dataDaylightingData->daylightControl(daylightCtrlNum).Name,
    1733             :                            iRefPoint,
    1734           0 :                            state.dataSurface->Surface(IWin).Name));
    1735           0 :                 ShowContinueError(state, format("Distance=[{:.5R}]. This is too close; check position of reference point.", ALF));
    1736           0 :                 ShowFatalError(state, "Program terminates due to preceding condition.");
    1737             :             }
    1738       15030 :         } else if (ALF < 0.1524 && ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
    1739           0 :             if (state.dataDaylightingManager->RefErrIndex(iRefPoint, IWin) == 0) { // only show error message once
    1740           0 :                 ShowWarningError(state,
    1741           0 :                                  "CalcDaylightCoeffRefPoints: For Daylghting:Controls=\"" +
    1742           0 :                                      state.dataDaylightingData->daylightControl(daylightCtrlNum).Name + "\" External Window=\"" +
    1743           0 :                                      state.dataSurface->Surface(IWin).Name + "\"in Zone=\"" +
    1744           0 :                                      state.dataHeatBal->Zone(state.dataSurface->Surface(IWin).Zone).Name +
    1745             :                                      "\" reference point is less than 0.15m (6\") from window plane ");
    1746           0 :                 ShowContinueError(state,
    1747           0 :                                   format("Distance=[{:.1R} m] to ref point=[{:.1R},{:.1R},{:.1R}], Inaccuracy in Daylighting Calcs may result.",
    1748             :                                          ALF,
    1749           0 :                                          RREF(1),
    1750           0 :                                          RREF(2),
    1751           0 :                                          RREF(3)));
    1752           0 :                 state.dataDaylightingManager->RefErrIndex(iRefPoint, IWin) = 1;
    1753             :             }
    1754             :         }
    1755       13400 :     } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    1756       13400 :         if (ALF < 0.1524 && ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
    1757           0 :             if (state.dataDaylightingManager->MapErrIndex(iRefPoint, IWin) == 0) { // only show error message once
    1758           0 :                 ShowWarningError(state,
    1759           0 :                                  "CalcDaylightCoeffMapPoints: For Zone=\"" + state.dataHeatBal->Zone(zoneNum).Name + "\" External Window=\"" +
    1760           0 :                                      state.dataSurface->Surface(IWin).Name + "\"in Zone=\"" +
    1761           0 :                                      state.dataHeatBal->Zone(state.dataSurface->Surface(IWin).Zone).Name +
    1762             :                                      "\" map point is less than 0.15m (6\") from window plane ");
    1763           0 :                 ShowContinueError(
    1764             :                     state,
    1765           0 :                     format(
    1766           0 :                         "Distance=[{:.1R} m] map point=[{:.1R},{:.1R},{:.1R}], Inaccuracy in Map Calcs may result.", ALF, RREF(1), RREF(2), RREF(3)));
    1767           0 :                 state.dataDaylightingManager->MapErrIndex(iRefPoint, IWin) = 1;
    1768             :             }
    1769             :         }
    1770             :     }
    1771             :     // Number of window elements in X and Y for daylighting calculation
    1772       28430 :     if (ALF > 0.1524) {
    1773       27150 :         NDIVX = 1 + int(4.0 * WW / ALF);
    1774       27150 :         NDIVY = 1 + int(4.0 * HW / ALF);
    1775             :     }
    1776             : 
    1777       28430 :     if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
    1778             :         // Adjust number of exterior window elements to give acceptable number of rays through
    1779             :         // interior windows in the zone (for accuracy of interior window daylighting calculation)
    1780         408 :         SolidAngExtWin = General::SafeDivide(
    1781         204 :             ((state.dataSurface->Surface(IWin).Area + state.dataSurface->SurfWinDividerArea(IWin)) / state.dataSurface->Surface(IWin).Multiplier),
    1782             :             pow_2(ALF));
    1783         204 :         SolidAngMinIntWin = state.dataDaylightingData->enclDaylight(enclNum).MinIntWinSolidAng;
    1784         204 :         SolidAngRatio = max(1.0, SolidAngExtWin / SolidAngMinIntWin);
    1785         204 :         NDIVX *= std::sqrt(SolidAngRatio);
    1786         204 :         NDIVY *= std::sqrt(SolidAngRatio);
    1787             :     }
    1788             : 
    1789       28430 :     NWX = min(40, NDIVX);
    1790       28430 :     NWY = min(40, NDIVY);
    1791             : 
    1792             :     // Discretization of triangle is simpler if NWX = NWY
    1793       28430 :     if (is_Triangle) {
    1794           0 :         NWX = max(NWX, NWY);
    1795           0 :         NWY = NWX;
    1796             :     }
    1797             : 
    1798             :     // Edge lengths of window elements
    1799       28430 :     DWX = WW / NWX;
    1800       28430 :     DWY = HW / NWY;
    1801             : 
    1802             :     // Azimuth and altitude of window normal
    1803       28430 :     state.dataSurface->SurfWinPhi(IWin) = std::asin(state.dataDaylightingManager->WNORM(3));
    1804       28430 :     if (std::abs(state.dataDaylightingManager->WNORM(1)) > 1.0e-5 || std::abs(state.dataDaylightingManager->WNORM(2)) > 1.0e-5) {
    1805       22486 :         state.dataSurface->SurfWinTheta(IWin) = std::atan2(state.dataDaylightingManager->WNORM(2), state.dataDaylightingManager->WNORM(1));
    1806             :     } else {
    1807        5944 :         state.dataSurface->SurfWinTheta(IWin) = 0.0;
    1808             :     }
    1809             : 
    1810             :     // Recalculation of values for TDD:DOME
    1811       28430 :     if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
    1812             : 
    1813             :         // Look up the TDD:DOME object
    1814         420 :         PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
    1815         420 :         IWin2 = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome;
    1816             : 
    1817             :         // Calculate reference point coords relative to the diffuser coordinate system
    1818             :         // W21, W23, and WNORM are the unit vectors
    1819         420 :         state.dataDaylightingManager->REFD(1) = dot(state.dataDaylightingManager->REFWC, W21);
    1820         420 :         state.dataDaylightingManager->REFD(2) = dot(state.dataDaylightingManager->REFWC, W23);
    1821         420 :         state.dataDaylightingManager->REFD(3) = dot(state.dataDaylightingManager->REFWC, state.dataDaylightingManager->WNORM);
    1822             : 
    1823             :         // Calculate view vector coords relative to the diffuser coordinate system
    1824         420 :         state.dataDaylightingManager->VIEWVD(1) = dot(VIEWVC, W21);
    1825         420 :         state.dataDaylightingManager->VIEWVD(2) = dot(VIEWVC, W23);
    1826         420 :         state.dataDaylightingManager->VIEWVD(3) = dot(VIEWVC, state.dataDaylightingManager->WNORM);
    1827             : 
    1828         420 :         state.dataDaylightingManager->U3 = state.dataSurface->Surface(IWin2).Vertex(2);
    1829         420 :         U2 = state.dataSurface->Surface(IWin2).Vertex(3);
    1830             : 
    1831         420 :         if (state.dataSurface->Surface(IWin2).Sides == 4) {
    1832             :             // Vertices of window (numbered counter-clockwise starting
    1833             :             // at upper left as viewed from inside of room)
    1834             :             // Assumes original vertices are numbered counter-clockwise from
    1835             :             // upper left as viewed from outside.
    1836         420 :             state.dataDaylightingManager->U3 = state.dataSurface->Surface(IWin2).Vertex(2);
    1837         420 :             U2 = state.dataSurface->Surface(IWin2).Vertex(3);
    1838         420 :             state.dataDaylightingManager->U1 = state.dataSurface->Surface(IWin2).Vertex(4);
    1839           0 :         } else if (state.dataSurface->Surface(IWin2).Sides == 3) {
    1840           0 :             state.dataDaylightingManager->U3 = state.dataSurface->Surface(IWin2).Vertex(2);
    1841           0 :             U2 = state.dataSurface->Surface(IWin2).Vertex(3);
    1842           0 :             state.dataDaylightingManager->U1 = state.dataSurface->Surface(IWin2).Vertex(1);
    1843             :         }
    1844             : 
    1845             :         // Unit vectors from window vertex 2 to 1 and 2 to 3,
    1846             :         // center point of window, and vector from ref pt to center of window
    1847         420 :         U21 = state.dataDaylightingManager->U1 - U2;
    1848         420 :         U23 = state.dataDaylightingManager->U3 - U2;
    1849         420 :         HW = U21.magnitude();
    1850         420 :         WW = U23.magnitude();
    1851         420 :         if (state.dataSurface->Surface(IWin2).Sides == 4) {
    1852         420 :             state.dataDaylightingManager->WC = U2 + (U23 + U21) / 2.0;
    1853           0 :         } else if (state.dataSurface->Surface(IWin2).Sides == 3) {
    1854           0 :             state.dataDaylightingManager->WC = U2 + (U23 + U21) / 3.0;
    1855             :         }
    1856         420 :         state.dataSurface->SurfaceWindow(IWin2).WinCenter = state.dataDaylightingManager->WC;
    1857             :         // Unit vectors
    1858         420 :         U21 /= HW;
    1859         420 :         U23 /= WW;
    1860             : 
    1861             :         // Unit vector normal to dome (pointing away from TDD)
    1862             :         // These are specific to the exterior.
    1863             :         // NOTE:  Preserve WNORM for later in the code.
    1864         420 :         WNORM2 = cross(U21, U23).normalize();
    1865             : 
    1866             :         // Azimuth and altitude of dome normal
    1867             :         // These are specific to the exterior.
    1868         420 :         state.dataSurface->SurfWinPhi(IWin2) = std::asin(WNORM2(3));
    1869         420 :         if (std::abs(WNORM2(1)) > 1.0e-5 || std::abs(WNORM2(2)) > 1.0e-5) {
    1870         420 :             state.dataSurface->SurfWinTheta(IWin2) = std::atan2(WNORM2(2), WNORM2(1));
    1871             :         } else {
    1872           0 :             state.dataSurface->SurfWinTheta(IWin2) = 0.0;
    1873             :         }
    1874             : 
    1875             :         // Calculate new virtual reference point coords relative to dome coord system
    1876             :         // W21, W23, and WNORM2 are now the unit vectors for the dome coord system
    1877         840 :         state.dataDaylightingManager->REFWC = state.dataDaylightingManager->REFD(1) * U21 + state.dataDaylightingManager->REFD(2) * U23 +
    1878        1260 :                                               state.dataDaylightingManager->REFD(3) * WNORM2;
    1879         420 :         RREF2 = state.dataDaylightingManager->WC - state.dataDaylightingManager->REFWC;
    1880             : 
    1881             :         // Calculate new virtual view vector coords relative to dome coord system
    1882         420 :         VIEWVC2 = state.dataDaylightingManager->VIEWVD(1) * U21 + state.dataDaylightingManager->VIEWVD(2) * U23 +
    1883         840 :                   state.dataDaylightingManager->VIEWVD(3) * WNORM2;
    1884             : 
    1885             :         // Copy several values from the diffuser so that DayltgInterReflectedIllum works correctly
    1886             :         // These are specific to the interior.
    1887         420 :         state.dataSurface->SurfWinRhoCeilingWall(IWin2) = state.dataSurface->SurfWinRhoCeilingWall(IWin);
    1888         420 :         state.dataSurface->SurfWinRhoFloorWall(IWin2) = state.dataSurface->SurfWinRhoFloorWall(IWin);
    1889         420 :         state.dataSurface->SurfWinFractionUpgoing(IWin2) = state.dataSurface->SurfWinFractionUpgoing(IWin);
    1890         420 :         state.dataSurface->SurfWinGlazedFrac(IWin2) = state.dataSurface->SurfWinGlazedFrac(IWin);
    1891             : 
    1892             :     } else {
    1893             :         // This is not a TDD:DIFFUSER.  Make sure nothing is messed up for a regular window.
    1894       28010 :         IWin2 = IWin;
    1895       28010 :         WNORM2 = state.dataDaylightingManager->WNORM;
    1896       28010 :         RREF2 = RREF;
    1897       28010 :         VIEWVC2 = VIEWVC;
    1898             : 
    1899       28010 :         U2 = W2;
    1900       28010 :         U21 = W21;
    1901       28010 :         U23 = W23;
    1902             :     }
    1903             : 
    1904             :     // Initialize bsdf daylighting coefficients here.  Only one time initialization
    1905       28430 :     if (state.dataSurface->SurfWinWindowModelType(IWin) == WindowModel::BSDF) {
    1906          18 :         if (!state.dataBSDFWindow->ComplexWind(IWin).DaylightingInitialized) {
    1907          18 :             int NRefPts = 0;
    1908          18 :             if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    1909           0 :                 NRefPts = state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints;
    1910          18 :             } else if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    1911          18 :                 NRefPts = state.dataDaylightingData->daylightControl(daylightCtrlNum).TotalDaylRefPoints;
    1912             :             }
    1913          18 :             InitializeCFSDaylighting(state, daylightCtrlNum, IWin, NWX, NWY, RREF, NRefPts, iRefPoint, CalledFrom, MapNum);
    1914             :             // if ((WinEl == (NWX * NWY)).and.(CalledFrom == CalledForMapPoint).and.(NRefPts == iRefPoint)) then
    1915          18 :             if ((CalledFrom == DataDaylighting::CalledFor::MapPoint) && (NRefPts == iRefPoint)) {
    1916           0 :                 state.dataBSDFWindow->ComplexWind(IWin).DaylightingInitialized = true;
    1917             :             }
    1918             :         }
    1919             :     }
    1920             : 
    1921       28430 :     if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
    1922             :         // Initialize sky and sun components of direct illuminance (arrays EDIRSK, EDIRSU, EDIRSUdisk)
    1923             :         // and average window luminance (arrays AVWLSK, AVWLSU, AVWLSUdisk), at ref pt.
    1924       28430 :         state.dataDaylightingManager->EDIRSK = 0.0;
    1925       28430 :         state.dataDaylightingManager->EDIRSU = 0.0;
    1926       28430 :         state.dataDaylightingManager->EDIRSUdisk = 0.0;
    1927       28430 :         state.dataDaylightingManager->AVWLSK = 0.0;
    1928       28430 :         state.dataDaylightingManager->AVWLSU = 0.0;
    1929       28430 :         state.dataDaylightingManager->AVWLSUdisk = 0.0;
    1930             :     } else {
    1931           0 :         state.dataDaylightingManager->EDIRSK(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, 4}) = 0.0;
    1932           0 :         state.dataDaylightingManager->EDIRSU(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
    1933           0 :         state.dataDaylightingManager->EDIRSUdisk(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
    1934           0 :         state.dataDaylightingManager->AVWLSK(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, 4}) = 0.0;
    1935           0 :         state.dataDaylightingManager->AVWLSU(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
    1936           0 :         state.dataDaylightingManager->AVWLSUdisk(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
    1937             :     }
    1938       28430 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    1939             :         // Initialize solid angle subtended by window wrt ref pt
    1940             :         // and solid angle weighted by glare position factor
    1941       15030 :         state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPt(iRefPoint) = 0.0;
    1942       15030 :         state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint) = 0.0;
    1943             :     }
    1944             :     // Area of window element
    1945       28430 :     if (is_Rectangle) {
    1946       28430 :         DAXY = DWX * DWY;
    1947           0 :     } else if (is_Triangle) {
    1948           0 :         SinCornerAng = std::sqrt(1.0 - pow_2(dot(W21, W23)));
    1949           0 :         DAXY = DWX * DWY * SinCornerAng;
    1950             :     }
    1951       28430 : }
    1952             : 
    1953     2737944 : void FigureDayltgCoeffsAtPointsForWindowElements(
    1954             :     EnergyPlusData &state,
    1955             :     int const daylightCtrlNum, // Current daylighting control number (only used when called from RefPoint)
    1956             :     int const iRefPoint,
    1957             :     int const loopwin,
    1958             :     DataDaylighting::CalledFor const CalledFrom, // indicate  which type of routine called this routine
    1959             :     int const WinEl,                             // Current window element number
    1960             :     int const IWin,
    1961             :     int const IWin2,
    1962             :     int const iXelement,
    1963             :     int const iYelement,
    1964             :     Real64 &SkyObstructionMult,
    1965             :     Vector3<Real64> const &W2,                    // Second vertex of window
    1966             :     Vector3<Real64> const &W21,                   // Vector from window vertex 2 to window vertex 1
    1967             :     Vector3<Real64> const &W23,                   // Vector from window vertex 2 to window vertex 3
    1968             :     Vector3<Real64> const &RREF,                  // Location of a reference point in absolute coordinate system
    1969             :     int const NWYlim,                             // For triangle, largest NWY for a given IX
    1970             :     Vector3<Real64> const &VIEWVC2,               // Virtual view vector in absolute coordinate system
    1971             :     Real64 const DWX,                             // Horizontal dimension of window element (m)
    1972             :     Real64 const DWY,                             // Vertical dimension of window element (m)
    1973             :     Real64 const DAXY,                            // Area of window element
    1974             :     Vector3<Real64> const &U2,                    // Second vertex of window for TDD:DOME (if exists)
    1975             :     Vector3<Real64> const &U23,                   // Vector from window vertex 2 to window vertex 3 for TDD:DOME (if exists)
    1976             :     Vector3<Real64> const &U21,                   // Vector from window vertex 2 to window vertex 1 for TDD:DOME (if exists)
    1977             :     Vector3<Real64> &RWIN,                        // Center of a window element for TDD:DOME (if exists) in abs coord sys
    1978             :     Vector3<Real64> &RWIN2,                       // Center of a window element for TDD:DOME (if exists) in abs coord sys
    1979             :     Vector3<Real64> &Ray,                         // Unit vector along ray from reference point to window element
    1980             :     Real64 &PHRAY,                                // Altitude of ray from reference point to window element (radians)
    1981             :     int &LSHCAL,                                  // Interior shade calculation flag:  0=not yet calculated, 1=already calculated
    1982             :     Real64 &COSB,                                 // Cosine of angle between window outward normal and ray from reference point to window element
    1983             :     Real64 &ObTrans,                              // Product of solar transmittances of exterior obstructions hit by ray
    1984             :     Real64 &TVISB,                                // Visible transmittance of window for COSB angle of incidence (times light well
    1985             :     Real64 &DOMEGA,                               // Solid angle subtended by window element wrt reference point (steradians)
    1986             :     Real64 &THRAY,                                // Azimuth of ray from reference point to window element (radians)
    1987             :     bool &hitIntObs,                              // True iff interior obstruction hit
    1988             :     bool &hitExtObs,                              // True iff ray from ref pt to ext win hits an exterior obstruction
    1989             :     Vector3<Real64> const &WNORM2,                // Unit vector normal to window
    1990             :     DataDaylighting::ExtWinType const ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
    1991             :     int const IConst,                             // Construction counter
    1992             :     Vector3<Real64> const &RREF2,                 // Location of virtual reference point in absolute coordinate system
    1993             :     bool const is_Triangle,
    1994             :     Real64 &TVISIntWin,     // Visible transmittance of int win at COSBIntWin for light from ext win
    1995             :     Real64 &TVISIntWinDisk, // Visible transmittance of int win at COSBIntWin for sun
    1996             :     int const MapNum)
    1997             : {
    1998             : 
    1999             :     // SUBROUTINE INFORMATION:
    2000             :     //       AUTHOR         B. Griffith
    2001             :     //       DATE WRITTEN   November 2012, refactor from legacy code by Fred Winklemann
    2002             : 
    2003             :     // PURPOSE OF THIS SUBROUTINE:
    2004             :     // collect code to do calculations for each window element for daylighting coefficients
    2005             : 
    2006             :     // REFERENCES:
    2007             :     // switch as need to serve both reference points and map points based on calledFrom
    2008             : 
    2009             :     Real64 DIS;    // Distance between reference point and center of window element (m)
    2010             :     Real64 DAXY1;  // For triangle, area of window element at end of column
    2011             :     Real64 POSFAC; // Position factor for a window element / ref point / view vector combination
    2012             :     Real64 RR;     // Distance from ref point to intersection of view vector
    2013             :     //  and plane normal to view vector and window element (m)
    2014             :     Real64 ASQ; // Square of distance from above intersection to window element (m2)
    2015             :     Real64 YD;  // Vertical displacement of window element wrt ref point
    2016             :     Real64 XR;  // Horizontal displacement ratio
    2017             :     Real64 YR;  // Vertical displacement ratio
    2018             : 
    2019             :     int IntWinHitNum;  // Surface number of interior window that is intersected
    2020             :     bool hitIntWin;    // Ray from ref pt passes through interior window
    2021             :     int PipeNum;       // TDD pipe object number
    2022             :     Real64 COSBIntWin; // Cos of angle between int win outward normal and ray betw ref pt and
    2023             :     //  exterior window element or between ref pt and sun
    2024             : 
    2025             :     Real64 Alfa;   // Intermediate variable
    2026             :     Real64 Beta;   // Intermediate variable
    2027             :     Real64 HorDis; // Distance between ground hit point and proj'n of center
    2028             :     //  of window element onto ground (m)
    2029             : 
    2030             :     // Local complex fenestration variables
    2031             :     int CplxFenState;  // Current complex fenestration state
    2032     2737944 :     int NReflSurf = 0; // Number of blocked beams for complex fenestration
    2033             :     int ICplxFen;      // Complex fenestration counter
    2034             :     int RayIndex;
    2035             :     Real64 TransBeam; // Obstructions transmittance for incoming BSDF rays (temporary variable)
    2036             : 
    2037     2737944 :     ++LSHCAL;
    2038     2737944 :     SkyObstructionMult = 1.0;
    2039             : 
    2040             :     // Center of win element in absolute coord sys
    2041     2737944 :     RWIN = W2 + (double(iXelement) - 0.5) * W23 * DWX + (double(iYelement) - 0.5) * W21 * DWY;
    2042             : 
    2043             :     // Center of win element on TDD:DOME in absolute coord sys
    2044             :     // If no TDD, RWIN2 = RWIN
    2045     2737944 :     RWIN2 = U2 + (double(iXelement) - 0.5) * U23 * DWX + (double(iYelement) - 0.5) * U21 * DWY;
    2046             : 
    2047             :     // Distance between ref pt and window element
    2048     2737944 :     DIS = distance(RWIN, RREF);
    2049             : 
    2050             :     // Unit vector along ray from ref pt to element
    2051     2737944 :     Ray = (RWIN - RREF) / DIS;
    2052             : 
    2053             :     // Cosine of angle between ray and window outward normal
    2054     2737944 :     COSB = dot(WNORM2, Ray);
    2055             : 
    2056             :     // If COSB > 0, direct light from window can reach ref pt. Otherwise go to loop
    2057             :     // over sun position and calculate inter-reflected component of illuminance
    2058     2737944 :     if (COSB > 0.0) {
    2059             :         // Azimuth (-pi to pi) and altitude (-pi/2 to pi/2) of ray. Azimuth = 0 is along east.
    2060     2737944 :         PHRAY = std::asin(Ray(3));
    2061     2737944 :         if (std::abs(Ray(1)) > 1.0e-5 || std::abs(Ray(2)) > 1.0e-5) {
    2062     2737939 :             THRAY = std::atan2(Ray(2), Ray(1));
    2063             :         } else {
    2064           5 :             THRAY = 0.0;
    2065             :         }
    2066             : 
    2067             :         // Solid angle subtended by element wrt ref pt.
    2068     2737944 :         DAXY1 = DAXY;
    2069             :         // For triangle, at end of Y column only one half of parallelopiped's area contributes
    2070     2737944 :         if (is_Triangle && iYelement == NWYlim) DAXY1 = 0.5 * DAXY;
    2071     2737944 :         DOMEGA = DAXY1 * COSB / (DIS * DIS);
    2072             : 
    2073             :         // Calculate position factor (used in glare calculation) for this
    2074             :         // win element / ref pt / view-vector combination
    2075     2737944 :         POSFAC = 0.0;
    2076             : 
    2077             :         // Distance from ref pt to intersection of view vector and plane
    2078             :         // normal to view vector containing the window element
    2079             : 
    2080     2737944 :         if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2081      578704 :             RR = DIS * dot(Ray, VIEWVC2);
    2082      578704 :             if (RR > 0.0) {
    2083             :                 // Square of distance from above intersection point to win element
    2084      527227 :                 ASQ = DIS * DIS - RR * RR;
    2085             :                 // Vertical displacement of win element wrt ref pt
    2086      527227 :                 YD = RWIN2(3) - RREF2(3);
    2087             :                 // Horizontal and vertical displacement ratio and position factor
    2088      527227 :                 XR = std::sqrt(std::abs(ASQ - YD * YD)) / RR;
    2089      527227 :                 YR = std::abs(YD / RR);
    2090      527227 :                 POSFAC = DayltgGlarePositionFactor(XR, YR);
    2091             :             }
    2092             :         }
    2093             : 
    2094     2737944 :         hitIntObs = false;
    2095     2737944 :         IntWinHitNum = 0;
    2096     2737944 :         hitIntWin = false;
    2097     2737944 :         TVISIntWinDisk = 0.0; // Init Value
    2098     2737944 :         TVISIntWin = 0.0;
    2099             : 
    2100     2737944 :         if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
    2101             :             // Look up the TDD:DOME object
    2102         420 :             PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
    2103             :             // Unshaded visible transmittance of TDD for a single ray from sky/ground element
    2104         840 :             TVISB = DaylightingDevices::TransTDD(state, PipeNum, COSB, DataDaylightingDevices::RadType::VisibleBeam) *
    2105         420 :                     state.dataSurface->SurfWinGlazedFrac(IWin);
    2106             : 
    2107             :         } else { // Regular window
    2108     2737524 :             if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) {
    2109             :                 // Vis trans of glass for COSB incidence angle
    2110     8212140 :                 TVISB = General::POLYF(COSB, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
    2111     5474760 :                         state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    2112             :             } else {
    2113             :                 // Complex fenestration needs to use different equation for visible transmittance.  That will be calculated later
    2114             :                 // in the code since it depends on different incoming directions.  For now, just put zero to differentiate from
    2115             :                 // regular windows
    2116         144 :                 TVISB = 0.0;
    2117             :             }
    2118     2737524 :             if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
    2119       23680 :                 int zoneNum = 0;
    2120       23680 :                 if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2121          40 :                     zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
    2122       23640 :                 } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    2123       23640 :                     assert(MapNum > 0);
    2124       23640 :                     zoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
    2125             :                 }
    2126             :                 // Does ray pass through an interior window in zone (ZoneNum) containing the ref point?
    2127       47360 :                 for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2128       23680 :                     auto &thisSpace = state.dataHeatBal->space(spaceNum);
    2129       26948 :                     for (int IntWin = thisSpace.WindowSurfaceFirst; IntWin <= thisSpace.WindowSurfaceLast; ++IntWin) {
    2130       23680 :                         if (state.dataSurface->Surface(IntWin).ExtBoundCond >=
    2131             :                             1) { // in develop this was Surface(IntWin).Class == SurfaceClass::Window && Surface(IntWin).ExtBoundCond >= 1
    2132       47360 :                             if (state.dataSurface->Surface(state.dataSurface->Surface(IntWin).ExtBoundCond).Zone ==
    2133       23680 :                                 state.dataSurface->Surface(IWin).Zone) {
    2134       23680 :                                 PierceSurface(state, IntWin, RREF, Ray, state.dataDaylightingManager->HitPtIntWin, hitIntWin);
    2135       23680 :                                 if (hitIntWin) {
    2136       20412 :                                     IntWinHitNum = IntWin;
    2137       20412 :                                     COSBIntWin = dot(state.dataSurface->Surface(IntWin).OutNormVec, Ray);
    2138       20412 :                                     if (COSBIntWin <= 0.0) {
    2139           0 :                                         hitIntWin = false;
    2140           0 :                                         IntWinHitNum = 0;
    2141           0 :                                         continue;
    2142             :                                     }
    2143       20412 :                                     TVISIntWin = General::POLYF(
    2144             :                                         COSBIntWin,
    2145       20412 :                                         state.dataConstruction->Construct(state.dataSurface->Surface(IntWin).Construction).TransVisBeamCoef);
    2146       20412 :                                     TVISB *= TVISIntWin;
    2147       20412 :                                     break; // Ray passes thru interior window; exit from DO loop
    2148             :                                 }
    2149             :                             }
    2150             :                         }
    2151             :                     }
    2152             :                 } // End of loop over surfaces in zone ZoneNum
    2153             : 
    2154       23680 :                 if (!hitIntWin) {
    2155             :                     // Ray does not pass through an int win in ZoneNum. Therefore, it hits the opaque part
    2156             :                     // of a surface between ref point in ZoneNum and ext win element in adjacent zone.
    2157        3268 :                     hitIntObs = true;
    2158             :                 }
    2159             :             } // End of check if this is an ext win in an adjacent zone
    2160             :         }     // End of check if TDD:Diffuser or regular exterior window or complex fenestration
    2161             : 
    2162             :         // Check for interior obstructions
    2163     2737944 :         if (ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin && !hitIntObs) {
    2164             :             // Check for obstruction between reference point and window element
    2165             :             // Returns hitIntObs = true iff obstruction is hit
    2166             :             // (Example of interior obstruction is a wall in an L-shaped room that lies
    2167             :             // between reference point and window.)
    2168     2714264 :             DayltgHitInteriorObstruction(state, IWin, RREF, RWIN, hitIntObs);
    2169             :         }
    2170             : 
    2171     2737944 :         if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin && IntWinHitNum > 0 && !hitIntObs) {
    2172             :             // Check for obstruction between ref point and interior window through which ray passes
    2173       20412 :             DayltgHitInteriorObstruction(state, IntWinHitNum, RREF, state.dataDaylightingManager->HitPtIntWin, hitIntObs);
    2174       20412 :             if (!hitIntObs) {
    2175             :                 // Check for obstruction between intersection point on int window and ext win element
    2176       20412 :                 DayltgHitBetWinObstruction(state, IntWinHitNum, IWin, state.dataDaylightingManager->HitPtIntWin, RWIN, hitIntObs);
    2177             :             }
    2178             :         }
    2179     2737944 :         if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2180             :             // Glare calculations only done for regular reference points, not for maps
    2181      578704 :             if (!hitIntObs) {
    2182      578634 :                 if (ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin ||
    2183          40 :                     (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin && hitIntWin)) {
    2184             :                     // Increment solid angle subtended by portion of window above ref pt
    2185      578634 :                     state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPt(iRefPoint) += DOMEGA;
    2186      578634 :                     state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPt(loopwin, iRefPoint) += DOMEGA;
    2187             :                     // Increment position-factor-modified solid angle
    2188      578634 :                     state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint) += DOMEGA * POSFAC;
    2189      578634 :                     state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPtWtd(loopwin, iRefPoint) += DOMEGA * POSFAC;
    2190             :                 }
    2191             :             }
    2192             :         }
    2193     2737944 :         if (hitIntObs) ObTrans = 0.0;
    2194             : 
    2195     2737944 :         hitExtObs = false;
    2196     2737944 :         if (!hitIntObs) {
    2197             :             // No interior obstruction was hit.
    2198             :             // Check for exterior obstructions between window element and sky/ground.
    2199             :             // Get product of transmittances of obstructions hit by ray.
    2200             :             // ObTrans = 1.0 will be returned if no exterior obstructions are hit.
    2201             : 
    2202     2703358 :             if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) {
    2203             :                 // the IHR (now HourOfDay) here is/was not correct, this is outside of hour loop
    2204             :                 // the hour is used to query schedule for transmission , not sure what to do
    2205             :                 // it will work for detailed and never did work correctly before.
    2206     2703214 :                 DayltgHitObstruction(state, state.dataGlobal->HourOfDay, IWin2, RWIN2, Ray, ObTrans);
    2207     2703214 :                 if (ObTrans < 1.0) hitExtObs = true;
    2208             :             } else {
    2209             :                 // Transmittance from exterior obstruction surfaces is calculated here. This needs to be done for each timestep
    2210             :                 // in order to account for changes in exterior surface transmittances
    2211         144 :                 CplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
    2212         144 :                 if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2213         144 :                     NReflSurf = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).RefPoint(iRefPoint).NReflSurf(WinEl);
    2214           0 :                 } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    2215           0 :                     NReflSurf = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).IlluminanceMap(iRefPoint, MapNum).NReflSurf(WinEl);
    2216             :                 }
    2217         144 :                 for (ICplxFen = 1; ICplxFen <= NReflSurf; ++ICplxFen) {
    2218           0 :                     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2219           0 :                         RayIndex =
    2220           0 :                             state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).RefPoint(iRefPoint).RefSurfIndex(ICplxFen, WinEl);
    2221           0 :                     } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    2222           0 :                         RayIndex = state.dataBSDFWindow->ComplexWind(IWin)
    2223           0 :                                        .DaylghtGeom(CplxFenState)
    2224           0 :                                        .IlluminanceMap(iRefPoint, MapNum)
    2225           0 :                                        .RefSurfIndex(ICplxFen, WinEl);
    2226             :                     }
    2227           0 :                     state.dataDaylightingManager->RayVector = state.dataBSDFWindow->ComplexWind(IWin).Geom(CplxFenState).sInc(RayIndex);
    2228             :                     // It will get product of all transmittances
    2229           0 :                     DayltgHitObstruction(state, state.dataGlobal->HourOfDay, IWin, RWIN, state.dataDaylightingManager->RayVector, TransBeam);
    2230             :                     // IF (TransBeam > 0.0d0) ObTrans = TransBeam
    2231           0 :                     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2232           0 :                         state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).RefPoint(iRefPoint).TransOutSurf(ICplxFen, WinEl) =
    2233             :                             TransBeam;
    2234           0 :                     } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    2235           0 :                         state.dataBSDFWindow->ComplexWind(IWin)
    2236           0 :                             .DaylghtGeom(CplxFenState)
    2237           0 :                             .IlluminanceMap(iRefPoint, MapNum)
    2238           0 :                             .TransOutSurf(ICplxFen, WinEl) = TransBeam;
    2239             :                     }
    2240             :                 }
    2241             :                 // This will avoid obstruction multiplier calculations for non-CFS window
    2242         144 :                 ObTrans = 0.0;
    2243             :             }
    2244             :         }
    2245             : 
    2246     2737944 :         if (state.dataSurface->CalcSolRefl && PHRAY < 0.0 && ObTrans > 1.0e-6) {
    2247             :             // Calculate effect of obstructions on shading of sky diffuse reaching the ground point hit
    2248             :             // by the ray. This effect is given by the ratio SkyObstructionMult =
    2249             :             // (obstructed sky diffuse at ground point)/(unobstructed sky diffuse at ground point).
    2250             :             // This ratio is calculated for an isotropic sky.
    2251             :             // Ground point hit by the ray:
    2252          50 :             Alfa = std::acos(-Ray(3));
    2253          50 :             Beta = std::atan2(Ray(2), Ray(1));
    2254          50 :             HorDis = (RWIN2(3) - state.dataSurface->GroundLevelZ) * std::tan(Alfa);
    2255          50 :             state.dataDaylightingManager->GroundHitPt(3) = state.dataSurface->GroundLevelZ;
    2256          50 :             state.dataDaylightingManager->GroundHitPt(1) = RWIN2(1) + HorDis * std::cos(Beta);
    2257          50 :             state.dataDaylightingManager->GroundHitPt(2) = RWIN2(2) + HorDis * std::sin(Beta);
    2258             : 
    2259          50 :             SkyObstructionMult =
    2260          50 :                 CalcObstrMultiplier(state, state.dataDaylightingManager->GroundHitPt, AltAngStepsForSolReflCalc, AzimAngStepsForSolReflCalc);
    2261             :         } // End of check if solar reflection calculation is in effect
    2262             : 
    2263             :     } // End of check if COSB > 0
    2264     2737944 : }
    2265             : 
    2266          18 : void InitializeCFSDaylighting(EnergyPlusData &state,
    2267             :                               int const daylightCtrlNum,       // Current daylighting control number
    2268             :                               int const IWin,                  // Complex fenestration number
    2269             :                               int const NWX,                   // Number of horizontal divisions
    2270             :                               int const NWY,                   // Number of vertical divisions
    2271             :                               Vector3<Real64> const &RefPoint, // reference point coordinates
    2272             :                               int const NRefPts,               // Number of reference points
    2273             :                               int const iRefPoint,             // Reference points counter
    2274             :                               DataDaylighting::CalledFor const CalledFrom,
    2275             :                               int const MapNum)
    2276             : {
    2277             :     // SUBROUTINE INFORMATION:
    2278             :     //       AUTHOR         Simon Vidanovic
    2279             :     //       DATE WRITTEN   April 2013
    2280             :     //       MODIFIED       na
    2281             :     //       RE-ENGINEERED  na
    2282             : 
    2283             :     // PURPOSE OF THIS SUBROUTINE:
    2284             :     // For incoming BSDF window direction calculates whether bin is coming from sky, ground or reflected surface.
    2285             :     // Routine also calculates intersection points with ground and exterior reflection surfaces.
    2286             : 
    2287             :     int NumOfWinEl;  // Number of window elements
    2288             :     int CurFenState; // Current fenestration state
    2289             : 
    2290             :     Real64 DWX;       // Window element width
    2291             :     Real64 DWY;       // Window element height
    2292             :     Real64 WinElArea; // Window element area
    2293             : 
    2294          18 :     auto &W1 = state.dataDaylightingManager->W1;
    2295          18 :     auto &W2 = state.dataDaylightingManager->W2;
    2296          18 :     auto &W3 = state.dataDaylightingManager->W3;
    2297          18 :     auto &W21 = state.dataDaylightingManager->W21;
    2298          18 :     auto &W23 = state.dataDaylightingManager->W23;
    2299          18 :     auto &WNorm = state.dataDaylightingManager->WNorm; // unit vector from window (point towards outside)
    2300             : 
    2301             :     int NBasis;    // number of incident basis directions for current state
    2302             :     int NTrnBasis; // number of outgoing basis directions for current state
    2303             : 
    2304             :     // reference point variables
    2305             : 
    2306             :     // Position factor variables
    2307             :     Real64 AZVIEW; // Azimuth of view vector
    2308             : 
    2309             :     // Object Data
    2310          18 :     DataBSDFWindow::BSDFDaylghtPosition elPos; // altitude and azimuth of intersection element
    2311          36 :     Vector Vec;                                // temporary vector variable
    2312             : 
    2313          18 :     NumOfWinEl = NWX * NWY;
    2314             : 
    2315          18 :     DWX = state.dataSurface->Surface(IWin).Width / NWX;
    2316          18 :     DWY = state.dataSurface->Surface(IWin).Height / NWY;
    2317             : 
    2318          18 :     int zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
    2319          54 :     AZVIEW = (state.dataDaylightingData->daylightControl(daylightCtrlNum).ViewAzimuthForGlare + state.dataHeatBal->Zone(zoneNum).RelNorth +
    2320          36 :               state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) *
    2321             :              DataGlobalConstants::DegToRadians;
    2322             : 
    2323             :     // Perform necessary calculations for window coordinates and vectors.  This will be used to calculate centroids for
    2324             :     // each window element
    2325          18 :     W1 = 0.0;
    2326          18 :     W2 = 0.0;
    2327          18 :     W3 = 0.0;
    2328             : 
    2329          18 :     if (state.dataSurface->Surface(IWin).Sides == 4) {
    2330          18 :         W3 = state.dataSurface->Surface(IWin).Vertex(2);
    2331          18 :         W2 = state.dataSurface->Surface(IWin).Vertex(3);
    2332          18 :         W1 = state.dataSurface->Surface(IWin).Vertex(4);
    2333           0 :     } else if (state.dataSurface->Surface(IWin).Sides == 3) {
    2334           0 :         W3 = state.dataSurface->Surface(IWin).Vertex(2);
    2335           0 :         W2 = state.dataSurface->Surface(IWin).Vertex(3);
    2336           0 :         W1 = state.dataSurface->Surface(IWin).Vertex(1);
    2337             :     }
    2338             : 
    2339          18 :     W21 = W1 - W2;
    2340          18 :     W23 = W3 - W2;
    2341             : 
    2342          18 :     W21 /= state.dataSurface->Surface(IWin).Height;
    2343          18 :     W23 /= state.dataSurface->Surface(IWin).Width;
    2344             : 
    2345          18 :     WNorm = state.dataSurface->Surface(IWin).lcsz;
    2346             : 
    2347          18 :     WinElArea = DWX * DWY;
    2348          18 :     if (state.dataSurface->Surface(IWin).Sides == 3) {
    2349           0 :         WinElArea *= std::sqrt(1.0 - pow_2(dot(W21, W23)));
    2350             :     }
    2351             : 
    2352          18 :     if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    2353             : 
    2354           0 :         if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap)) {
    2355           0 :             state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap.allocate(NRefPts, (int)state.dataDaylightingData->IllumMap.size());
    2356             :         }
    2357             : 
    2358           0 :         AllocateForCFSRefPointsGeometry(state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum), NumOfWinEl);
    2359             : 
    2360          18 :     } else if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2361          18 :         if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).RefPoint)) {
    2362           2 :             state.dataBSDFWindow->ComplexWind(IWin).RefPoint.allocate(NRefPts);
    2363             :         }
    2364             : 
    2365          18 :         AllocateForCFSRefPointsGeometry(state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint), NumOfWinEl);
    2366             :     }
    2367             : 
    2368             :     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2369             :     //! Allocation for each complex fenestration state reference points
    2370             :     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2371          18 :     if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom)) {
    2372           2 :         state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom.allocate(state.dataBSDFWindow->ComplexWind(IWin).NumStates);
    2373             :     }
    2374             : 
    2375             :     // Calculation needs to be performed for each state
    2376          36 :     for (CurFenState = 1; CurFenState <= state.dataBSDFWindow->ComplexWind(IWin).NumStates; ++CurFenState) {
    2377          18 :         NBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurFenState).Inc.NBasis;
    2378          18 :         NTrnBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurFenState).Trn.NBasis;
    2379             : 
    2380          18 :         if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    2381           0 :             if ((int)state.dataDaylightingData->IllumMap.size() > 0) {
    2382             :                 // illuminance map for each state
    2383           0 :                 if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).IlluminanceMap)) {
    2384           0 :                     state.dataBSDFWindow->ComplexWind(IWin)
    2385           0 :                         .DaylghtGeom(CurFenState)
    2386           0 :                         .IlluminanceMap.allocate(NRefPts, (int)state.dataDaylightingData->IllumMap.size());
    2387             :                 }
    2388             : 
    2389           0 :                 AllocateForCFSRefPointsState(state,
    2390           0 :                                              state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).IlluminanceMap(iRefPoint, MapNum),
    2391             :                                              NumOfWinEl,
    2392             :                                              NBasis,
    2393             :                                              NTrnBasis);
    2394             : 
    2395           0 :                 InitializeCFSStateData(state,
    2396           0 :                                        state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).IlluminanceMap(iRefPoint, MapNum),
    2397           0 :                                        state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum),
    2398             :                                        daylightCtrlNum,
    2399             :                                        IWin,
    2400             :                                        RefPoint,
    2401             :                                        CurFenState,
    2402             :                                        NBasis,
    2403             :                                        NTrnBasis,
    2404             :                                        AZVIEW,
    2405             :                                        NWX,
    2406             :                                        NWY,
    2407             :                                        W2,
    2408             :                                        W21,
    2409             :                                        W23,
    2410             :                                        DWX,
    2411             :                                        DWY,
    2412             :                                        WNorm,
    2413             :                                        WinElArea);
    2414             :             }
    2415             : 
    2416          18 :         } else if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    2417          18 :             if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint)) {
    2418           2 :                 state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint.allocate(NRefPts);
    2419             :             }
    2420             : 
    2421          18 :             AllocateForCFSRefPointsState(
    2422          18 :                 state, state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint(iRefPoint), NumOfWinEl, NBasis, NTrnBasis);
    2423             : 
    2424          36 :             InitializeCFSStateData(state,
    2425          18 :                                    state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint(iRefPoint),
    2426          18 :                                    state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint),
    2427             :                                    daylightCtrlNum,
    2428             :                                    IWin,
    2429             :                                    RefPoint,
    2430             :                                    CurFenState,
    2431             :                                    NBasis,
    2432             :                                    NTrnBasis,
    2433             :                                    AZVIEW,
    2434             :                                    NWX,
    2435             :                                    NWY,
    2436             :                                    W2,
    2437             :                                    W21,
    2438             :                                    W23,
    2439             :                                    DWX,
    2440             :                                    DWY,
    2441             :                                    WNorm,
    2442             :                                    WinElArea);
    2443             :         }
    2444             :     }
    2445          18 : }
    2446             : 
    2447          18 : void InitializeCFSStateData(EnergyPlusData &state,
    2448             :                             DataBSDFWindow::BSDFRefPoints &StateRefPoint,
    2449             :                             DataBSDFWindow::BSDFRefPointsGeomDescr &DaylghtGeomDescr,
    2450             :                             [[maybe_unused]] int const daylightCtrlNum, // Current daylighting control number
    2451             :                             int const iWin,
    2452             :                             Vector3<Real64> const &RefPoint, // reference point
    2453             :                             int const CurFenState,
    2454             :                             int const NBasis,
    2455             :                             int const NTrnBasis,
    2456             :                             Real64 const AZVIEW,
    2457             :                             int const NWX,
    2458             :                             int const NWY,
    2459             :                             Vector3<Real64> const &W2,
    2460             :                             Vector3<Real64> const &W21,
    2461             :                             Vector3<Real64> const &W23,
    2462             :                             Real64 const DWX,
    2463             :                             Real64 const DWY,
    2464             :                             Vector3<Real64> const &WNorm, // unit vector from window (point towards outside)
    2465             :                             Real64 const WinElArea)
    2466             : {
    2467             :     // SUBROUTINE INFORMATION:
    2468             :     //       AUTHOR         Simon Vidanovic
    2469             :     //       DATE WRITTEN   June 2013
    2470             :     //       MODIFIED       na
    2471             :     //       RE-ENGINEERED  na
    2472             : 
    2473             :     // PURPOSE OF THIS SUBROUTINE:
    2474             :     // Initialize daylight state data for current
    2475             : 
    2476             :     // SUBROUTINE LOCAL VARIABLES
    2477             :     int curWinEl;
    2478             :     int IRay;
    2479             :     bool hit;
    2480             :     int TotHits;
    2481             :     int JSurf;
    2482             :     Real64 DotProd; // Temporary variable for manipulating dot product .dot.
    2483             :     int NSky;
    2484             :     int NGnd;
    2485             :     int NReflSurf;
    2486             :     int MaxTotHits;
    2487             :     int IX;
    2488             :     int IY;
    2489             :     Real64 LeastHitDsq; // dist^2 from window element center to hit point
    2490             :     Real64 HitDsq;
    2491             :     Real64 TransRSurf;
    2492             :     int I;
    2493             :     int J;
    2494             : 
    2495          18 :     auto &RWin = state.dataDaylightingManager->RWin;
    2496          18 :     auto &V = state.dataDaylightingManager->V;
    2497          18 :     auto &GroundHitPt = state.dataDaylightingManager->GroundHitPt;
    2498             : 
    2499             :     // temporary arrays for surfaces
    2500             :     // Each complex fenestration state can have different number of basis elements
    2501             :     // This is the reason for making these temporary arrays local
    2502          36 :     Array1D_int TmpSkyInd(NBasis, 0);                                         // Temporary sky index list
    2503          36 :     Array1D_int TmpGndInd(NBasis, 0);                                         // Temporary gnd index list
    2504          36 :     Array1D<Real64> TmpGndMultiplier(NBasis, 0.0);                            // Temporary ground obstruction multiplier
    2505          36 :     Array1D_int TmpRfSfInd(NBasis, 0);                                        // Temporary RefSurfIndex
    2506          36 :     Array1D_int TmpRfRyNH(NBasis, 0);                                         // Temporary RefRayNHits
    2507          36 :     Array2D_int TmpHSurfNo(state.dataSurface->TotSurfaces, NBasis, 0);        // Temporary HitSurfNo
    2508          36 :     Array2D<Real64> TmpHSurfDSq(state.dataSurface->TotSurfaces, NBasis, 0.0); // Temporary HitSurfDSq
    2509             : 
    2510             :     // Object Data
    2511          36 :     Vector Centroid;                                                                         // current window element centroid
    2512          36 :     Vector HitPt;                                                                            // surface hit point
    2513          36 :     Array1D<Vector> TmpGndPt(NBasis, Vector(0.0, 0.0, 0.0));                                 // Temporary ground intersection list
    2514          36 :     Array2D<Vector> TmpHitPt(state.dataSurface->TotSurfaces, NBasis, Vector(0.0, 0.0, 0.0)); // Temporary HitPt
    2515             : 
    2516          18 :     CFSRefPointPosFactor(state, RefPoint, StateRefPoint, iWin, CurFenState, NTrnBasis, AZVIEW);
    2517             : 
    2518          18 :     curWinEl = 0;
    2519             :     // loop through window elements. This will calculate sky, ground and reflection bins for each window element
    2520          54 :     for (IX = 1; IX <= NWX; ++IX) {
    2521         180 :         for (IY = 1; IY <= NWY; ++IY) {
    2522             : 
    2523         144 :             ++curWinEl;
    2524             : 
    2525             :             // centroid coordinates for current window element
    2526         144 :             Centroid = W2 + (double(IX) - 0.5) * W23 * DWX + (double(IY) - 0.5) * W21 * DWY;
    2527         144 :             RWin = Centroid;
    2528             : 
    2529         144 :             CFSRefPointSolidAngle(state, RefPoint, RWin, WNorm, StateRefPoint, DaylghtGeomDescr, iWin, CurFenState, NTrnBasis, curWinEl, WinElArea);
    2530             : 
    2531         144 :             NSky = 0;
    2532         144 :             NGnd = 0;
    2533         144 :             NReflSurf = 0;
    2534         144 :             MaxTotHits = 0;
    2535             :             // Calculation of potential surface obstruction for each incoming direction
    2536       21024 :             for (IRay = 1; IRay <= NBasis; ++IRay) {
    2537             : 
    2538       20880 :                 hit = false;
    2539       20880 :                 TotHits = 0;
    2540      187920 :                 for (JSurf = 1; JSurf <= state.dataSurface->TotSurfaces; ++JSurf) {
    2541             :                     // the following test will cycle on anything except exterior surfaces and shading surfaces
    2542      167040 :                     if (state.dataSurface->Surface(JSurf).HeatTransSurf && state.dataSurface->Surface(JSurf).ExtBoundCond != ExternalEnvironment)
    2543      125280 :                         continue;
    2544             :                     //  skip the base surface containing the window and any other subsurfaces of that surface
    2545       62640 :                     if (JSurf == state.dataSurface->Surface(iWin).BaseSurf ||
    2546       20880 :                         state.dataSurface->Surface(JSurf).BaseSurf == state.dataSurface->Surface(iWin).BaseSurf)
    2547       41760 :                         continue;
    2548             :                     //  skip surfaces that face away from the window
    2549           0 :                     DotProd = dot(state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay),
    2550           0 :                                   state.dataSurface->Surface(JSurf).NewellSurfaceNormalVector);
    2551           0 :                     if (DotProd >= 0) continue;
    2552           0 :                     PierceSurface(state, JSurf, Centroid, state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay), HitPt, hit);
    2553           0 :                     if (!hit) continue; // Miss: Try next surface
    2554           0 :                     if (TotHits == 0) {
    2555             :                         // First hit for this ray
    2556           0 :                         TotHits = 1;
    2557           0 :                         ++NReflSurf;
    2558           0 :                         TmpRfSfInd(NReflSurf) = IRay;
    2559           0 :                         TmpRfRyNH(NReflSurf) = 1;
    2560           0 :                         TmpHSurfNo(1, NReflSurf) = JSurf;
    2561           0 :                         TmpHitPt(1, NReflSurf) = HitPt;
    2562           0 :                         V = HitPt - Centroid;                // vector array from window ctr to hit pt
    2563           0 :                         LeastHitDsq = V.magnitude_squared(); // dist^2 window ctr to hit pt
    2564           0 :                         TmpHSurfDSq(1, NReflSurf) = LeastHitDsq;
    2565           0 :                         if (!state.dataSurface->Surface(JSurf).HeatTransSurf && state.dataSurface->Surface(JSurf).SchedShadowSurfIndex != 0) {
    2566           0 :                             TransRSurf = 1.0; // If a shadowing surface may have a scheduled transmittance, treat it here as completely transparent
    2567             :                         } else {
    2568           0 :                             TransRSurf = 0.0;
    2569             :                         }
    2570             :                     } else {
    2571           0 :                         V = HitPt - Centroid;
    2572           0 :                         HitDsq = V.magnitude_squared();
    2573           0 :                         if (HitDsq >= LeastHitDsq) {
    2574           0 :                             if (TransRSurf > 0.0) { // forget the new hit if the closer hit is opaque
    2575           0 :                                 J = TotHits + 1;
    2576           0 :                                 if (TotHits > 1) {
    2577           0 :                                     for (I = 2; I <= TotHits; ++I) {
    2578           0 :                                         if (HitDsq < TmpHSurfDSq(I, NReflSurf)) {
    2579           0 :                                             J = I;
    2580           0 :                                             break;
    2581             :                                         }
    2582             :                                     }
    2583           0 :                                     if (!state.dataSurface->Surface(JSurf).HeatTransSurf &&
    2584           0 :                                         state.dataSurface->Surface(JSurf).SchedShadowSurfIndex == 0) {
    2585             :                                         //  The new hit is opaque, so we can drop all the hits further away
    2586           0 :                                         TmpHSurfNo(J, NReflSurf) = JSurf;
    2587           0 :                                         TmpHitPt(J, NReflSurf) = HitPt;
    2588           0 :                                         TmpHSurfDSq(J, NReflSurf) = HitDsq;
    2589           0 :                                         TotHits = J;
    2590             :                                     } else {
    2591             :                                         //  The new hit is scheduled (presumed transparent), so keep the more distant hits
    2592             :                                         //     Note that all the hists in the list will be transparent except the last,
    2593             :                                         //       which may be either transparent or opaque
    2594           0 :                                         if (TotHits >= J) {
    2595           0 :                                             for (I = TotHits; I >= J; --I) {
    2596           0 :                                                 TmpHSurfNo(I + 1, NReflSurf) = TmpHSurfNo(I, NReflSurf);
    2597           0 :                                                 TmpHitPt(I + 1, NReflSurf) = TmpHitPt(I, NReflSurf);
    2598           0 :                                                 TmpHSurfDSq(I + 1, NReflSurf) = TmpHSurfDSq(I, NReflSurf);
    2599             :                                             }
    2600           0 :                                             TmpHSurfNo(J, NReflSurf) = JSurf;
    2601           0 :                                             TmpHitPt(J, NReflSurf) = HitPt;
    2602           0 :                                             TmpHSurfDSq(J, NReflSurf) = HitDsq;
    2603           0 :                                             ++TotHits;
    2604             :                                         }
    2605             :                                     } // if (.NOT.Surface(JSurf)%HeatTransSurf .AND. Surface(JSurf)%SchedShadowSurfIndex == 0)  then
    2606             :                                 }     // if (TotHits > 1) then
    2607             :                             }         // if (TransRSurf  > 0.0d0) then
    2608             :                         } else {      // if (HitDsq >= LeastHitDsq) then
    2609             :                             //  A new closest hit.  If it is opaque, drop the current hit list,
    2610             :                             //    otherwise add it at the front
    2611           0 :                             LeastHitDsq = HitDsq;
    2612           0 :                             if (!state.dataSurface->Surface(JSurf).HeatTransSurf && state.dataSurface->Surface(JSurf).SchedShadowSurfIndex != 0) {
    2613           0 :                                 TransRSurf = 1.0; // New closest hit is transparent, keep the existing hit list
    2614           0 :                                 for (I = TotHits; I >= 1; --I) {
    2615           0 :                                     TmpHSurfNo(I + 1, NReflSurf) = TmpHSurfNo(I, NReflSurf);
    2616           0 :                                     TmpHitPt(I + 1, NReflSurf) = TmpHitPt(I, NReflSurf);
    2617           0 :                                     TmpHSurfDSq(I + 1, NReflSurf) = TmpHSurfDSq(I, NReflSurf);
    2618           0 :                                     ++TotHits;
    2619             :                                 }
    2620             :                             } else {
    2621           0 :                                 TransRSurf = 0.0; // New closest hit is opaque, drop the existing hit list
    2622           0 :                                 TotHits = 1;
    2623             :                             }
    2624           0 :                             TmpHSurfNo(1, NReflSurf) = JSurf; // In either case the new hit is put in position 1
    2625           0 :                             TmpHitPt(1, NReflSurf) = HitPt;
    2626           0 :                             TmpHSurfDSq(1, NReflSurf) = LeastHitDsq;
    2627             :                         }
    2628             :                     }
    2629             :                 } // do JSurf = 1, TotSurfaces
    2630       20880 :                 if (TotHits <= 0) {
    2631             :                     // This ray reached the sky or ground unobstructed
    2632       20880 :                     if (state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).z < 0.0) {
    2633             :                         // A ground ray
    2634        9216 :                         ++NGnd;
    2635        9216 :                         TmpGndInd(NGnd) = IRay;
    2636       27648 :                         TmpGndPt(NGnd).x = Centroid.x - (state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).x /
    2637       18432 :                                                          state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).z) *
    2638        9216 :                                                             Centroid.z;
    2639       27648 :                         TmpGndPt(NGnd).y = Centroid.y - (state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).y /
    2640       18432 :                                                          state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).z) *
    2641        9216 :                                                             Centroid.z;
    2642        9216 :                         TmpGndPt(NGnd).z = 0.0;
    2643             : 
    2644             :                         // for solar reflectance calculations, need to precalculate obstruction multipliers
    2645        9216 :                         if (state.dataSurface->CalcSolRefl) {
    2646        9216 :                             GroundHitPt = TmpGndPt(NGnd);
    2647        9216 :                             TmpGndMultiplier(NGnd) = CalcObstrMultiplier(state, GroundHitPt, AltAngStepsForSolReflCalc, AzimAngStepsForSolReflCalc);
    2648             :                         }
    2649             :                     } else {
    2650             :                         // A sky ray
    2651       11664 :                         ++NSky;
    2652       11664 :                         TmpSkyInd(NSky) = IRay;
    2653             :                     }
    2654             :                 } else {
    2655             :                     // Save the number of hits for this ray
    2656           0 :                     TmpRfRyNH(NReflSurf) = TotHits;
    2657             :                 }
    2658       20880 :                 MaxTotHits = max(MaxTotHits, TotHits);
    2659             :             } // do IRay = 1, ComplexWind(IWin)%Geom(CurFenState)%Inc%NBasis
    2660             : 
    2661             :             // Fill up state data for current window element data
    2662         144 :             StateRefPoint.NSky(curWinEl) = NSky;
    2663         144 :             StateRefPoint.SkyIndex({1, NSky}, curWinEl) = TmpSkyInd({1, NSky});
    2664             : 
    2665         144 :             StateRefPoint.NGnd(curWinEl) = NGnd;
    2666         144 :             StateRefPoint.GndIndex({1, NGnd}, curWinEl) = TmpGndInd({1, NGnd});
    2667         144 :             StateRefPoint.GndPt({1, NGnd}, curWinEl) = TmpGndPt({1, NGnd});
    2668         144 :             StateRefPoint.GndObstrMultiplier({1, NGnd}, curWinEl) = TmpGndMultiplier({1, NGnd});
    2669             : 
    2670         144 :             StateRefPoint.NReflSurf(curWinEl) = NReflSurf;
    2671         144 :             StateRefPoint.RefSurfIndex({1, NReflSurf}, curWinEl) = TmpRfSfInd({1, NReflSurf});
    2672         144 :             StateRefPoint.RefRayNHits({1, NReflSurf}, curWinEl) = TmpRfRyNH({1, NReflSurf});
    2673         144 :             StateRefPoint.HitSurfNo({1, MaxTotHits}, {1, NReflSurf}, curWinEl) = TmpHSurfNo({1, MaxTotHits}, {1, NReflSurf});
    2674         144 :             StateRefPoint.HitSurfDSq({1, MaxTotHits}, {1, NReflSurf}, curWinEl) = TmpHSurfDSq({1, MaxTotHits}, {1, NReflSurf});
    2675         144 :             StateRefPoint.HitPt({1, MaxTotHits}, {1, NReflSurf}, curWinEl) = TmpHitPt({1, MaxTotHits}, {1, NReflSurf});
    2676             :         } // do IY = 1, NWY
    2677             :     }     // do IX = 1, NWX
    2678          18 : }
    2679             : 
    2680          18 : void AllocateForCFSRefPointsState(
    2681             :     EnergyPlusData &state, DataBSDFWindow::BSDFRefPoints &StateRefPoint, int const NumOfWinEl, int const NBasis, int const NTrnBasis)
    2682             : {
    2683             :     // SUBROUTINE INFORMATION:
    2684             :     //       AUTHOR         Simon Vidanovic
    2685             :     //       DATE WRITTEN   June 2013
    2686             :     //       MODIFIED       na
    2687             :     //       RE-ENGINEERED  na
    2688             : 
    2689             :     // PURPOSE OF THIS SUBROUTINE:
    2690             :     // Memory allocation for complex fenestration systems reference points geometry
    2691             : 
    2692          18 :     if (!allocated(StateRefPoint.NSky)) {
    2693           2 :         StateRefPoint.NSky.allocate(NumOfWinEl);
    2694           2 :         StateRefPoint.NSky = 0;
    2695             :     }
    2696             : 
    2697          18 :     if (!allocated(StateRefPoint.SkyIndex)) {
    2698           2 :         StateRefPoint.SkyIndex.allocate(NBasis, NumOfWinEl);
    2699           2 :         StateRefPoint.SkyIndex = 0;
    2700             :     }
    2701             : 
    2702          18 :     if (!allocated(StateRefPoint.NGnd)) {
    2703           2 :         StateRefPoint.NGnd.allocate(NumOfWinEl);
    2704           2 :         StateRefPoint.NGnd = 0;
    2705             :     }
    2706             : 
    2707          18 :     if (!allocated(StateRefPoint.GndIndex)) {
    2708           2 :         StateRefPoint.GndIndex.allocate(NBasis, NumOfWinEl);
    2709           2 :         StateRefPoint.GndIndex = 0;
    2710             :     }
    2711             : 
    2712          18 :     if (!allocated(StateRefPoint.GndPt)) {
    2713           2 :         StateRefPoint.GndPt.allocate(NBasis, NumOfWinEl);
    2714           2 :         StateRefPoint.GndPt = Vector(0.0, 0.0, 0.0);
    2715             :     }
    2716             : 
    2717          18 :     if (!allocated(StateRefPoint.GndObstrMultiplier)) {
    2718           2 :         StateRefPoint.GndObstrMultiplier.allocate(NBasis, NumOfWinEl);
    2719           2 :         StateRefPoint.GndObstrMultiplier = 0.0;
    2720             :     }
    2721             : 
    2722          18 :     if (!allocated(StateRefPoint.NReflSurf)) {
    2723           2 :         StateRefPoint.NReflSurf.allocate(NumOfWinEl);
    2724           2 :         StateRefPoint.NReflSurf = 0;
    2725             :     }
    2726             : 
    2727          18 :     if (!allocated(StateRefPoint.RefSurfIndex)) {
    2728           2 :         StateRefPoint.RefSurfIndex.allocate(NBasis, NumOfWinEl);
    2729           2 :         StateRefPoint.RefSurfIndex = 0;
    2730             :     }
    2731             : 
    2732          18 :     if (!allocated(StateRefPoint.TransOutSurf)) {
    2733           2 :         StateRefPoint.TransOutSurf.allocate(NBasis, NumOfWinEl);
    2734           2 :         StateRefPoint.TransOutSurf = 1.0;
    2735             :     }
    2736             : 
    2737          18 :     if (!allocated(StateRefPoint.RefRayNHits)) {
    2738           2 :         StateRefPoint.RefRayNHits.allocate(NBasis, NumOfWinEl);
    2739           2 :         StateRefPoint.RefRayNHits = 0;
    2740             :     }
    2741             : 
    2742          18 :     if (!allocated(StateRefPoint.HitSurfNo)) {
    2743           2 :         StateRefPoint.HitSurfNo.allocate(state.dataSurface->TotSurfaces, NBasis, NumOfWinEl);
    2744           2 :         StateRefPoint.HitSurfNo = 0;
    2745             :     }
    2746             : 
    2747          18 :     if (!allocated(StateRefPoint.HitSurfDSq)) {
    2748           2 :         StateRefPoint.HitSurfDSq.allocate(state.dataSurface->TotSurfaces, NBasis, NumOfWinEl);
    2749           2 :         StateRefPoint.HitSurfDSq = 0.0;
    2750             :     }
    2751             : 
    2752          18 :     if (!allocated(StateRefPoint.HitPt)) {
    2753           2 :         StateRefPoint.HitPt.allocate(state.dataSurface->TotSurfaces, NBasis, NumOfWinEl);
    2754           2 :         StateRefPoint.HitPt = Vector(0.0, 0.0, 0.0);
    2755             :     }
    2756             : 
    2757          18 :     if (!allocated(StateRefPoint.RefPointIndex)) {
    2758           2 :         StateRefPoint.RefPointIndex.allocate(NumOfWinEl);
    2759           2 :         StateRefPoint.RefPointIndex = 0;
    2760             :     }
    2761             : 
    2762          18 :     if (!allocated(StateRefPoint.RefPointIntersection)) {
    2763           2 :         StateRefPoint.RefPointIntersection.allocate(NTrnBasis);
    2764           2 :         StateRefPoint.RefPointIntersection = false;
    2765             :     }
    2766             : 
    2767          18 :     if (!allocated(StateRefPoint.RefPtIntPosFac)) {
    2768           2 :         StateRefPoint.RefPtIntPosFac.allocate(NTrnBasis);
    2769           2 :         StateRefPoint.RefPtIntPosFac = 0.0;
    2770             :     }
    2771          18 : }
    2772             : 
    2773          18 : void AllocateForCFSRefPointsGeometry(DataBSDFWindow::BSDFRefPointsGeomDescr &RefPointsGeomDescr, int const NumOfWinEl)
    2774             : {
    2775             :     // SUBROUTINE INFORMATION:
    2776             :     //       AUTHOR         Simon Vidanovic
    2777             :     //       DATE WRITTEN   June 2013
    2778             :     //       MODIFIED       na
    2779             :     //       RE-ENGINEERED  na
    2780             : 
    2781             :     // PURPOSE OF THIS SUBROUTINE:
    2782             :     // Memory allocation for complex fenestration systems reference points geometry
    2783             : 
    2784             :     // METHODOLOGY EMPLOYED:
    2785             :     // <description>
    2786             : 
    2787             :     // REFERENCES:
    2788             :     // na
    2789             : 
    2790             :     // Using/Aliasing
    2791             : 
    2792             :     // Locals
    2793             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    2794             :     // integer, intent(in) :: NRefPts
    2795             : 
    2796             :     // SUBROUTINE LOCAL VARIABLES
    2797             : 
    2798          18 :     if (!allocated(RefPointsGeomDescr.SolidAngle)) {
    2799           2 :         RefPointsGeomDescr.SolidAngle.allocate(NumOfWinEl);
    2800           2 :         RefPointsGeomDescr.SolidAngle = 0.0;
    2801             :     }
    2802             : 
    2803          18 :     if (!allocated(RefPointsGeomDescr.SolidAngleVec)) {
    2804           2 :         RefPointsGeomDescr.SolidAngleVec.allocate(NumOfWinEl);
    2805           2 :         RefPointsGeomDescr.SolidAngleVec = Vector(0.0, 0.0, 0.0);
    2806             :     }
    2807          18 : }
    2808             : 
    2809         144 : void CFSRefPointSolidAngle(EnergyPlusData &state,
    2810             :                            Vector3<Real64> const &RefPoint,
    2811             :                            Vector3<Real64> const &RWin,
    2812             :                            Vector3<Real64> const &WNorm,
    2813             :                            DataBSDFWindow::BSDFRefPoints &RefPointMap,
    2814             :                            DataBSDFWindow::BSDFRefPointsGeomDescr &RefPointGeomMap,
    2815             :                            int const iWin,
    2816             :                            int const CurFenState,
    2817             :                            int const NTrnBasis,
    2818             :                            int const curWinEl,
    2819             :                            Real64 const WinElArea)
    2820             : {
    2821             :     // SUBROUTINE INFORMATION:
    2822             :     //       AUTHOR         Simon Vidanovic
    2823             :     //       DATE WRITTEN   June 2013
    2824             :     //       MODIFIED       na
    2825             :     //       RE-ENGINEERED  na
    2826             : 
    2827             :     // PURPOSE OF THIS SUBROUTINE:
    2828             :     // Calculate position factor for given reference point.
    2829             : 
    2830             :     // SUBROUTINE LOCAL VARIABLES
    2831         144 :     auto &Ray = state.dataDaylightingManager->Ray;
    2832         144 :     auto &RayNorm = state.dataDaylightingManager->RayNorm;
    2833         144 :     auto &V = state.dataDaylightingManager->V;
    2834             :     Real64 BestMatch;
    2835             :     int iTrnRay;
    2836             :     Real64 temp;
    2837             :     Real64 Dist;
    2838             :     Real64 CosB;
    2839             : 
    2840             :     // calculate vector from center of window element to the current reference point
    2841         144 :     Ray = RefPoint - RWin;
    2842             : 
    2843             :     // figure out outgoing beam direction from current reference point
    2844         144 :     BestMatch = 0.0;
    2845       21024 :     for (iTrnRay = 1; iTrnRay <= NTrnBasis; ++iTrnRay) {
    2846       20880 :         V = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sTrn(iTrnRay);
    2847       20880 :         temp = dot(Ray, V);
    2848       20880 :         if (temp > BestMatch) {
    2849         702 :             BestMatch = temp;
    2850         702 :             RefPointMap.RefPointIndex(curWinEl) = iTrnRay;
    2851             :         }
    2852             :     }
    2853             : 
    2854             :     // calculate solid view angle
    2855         144 :     Dist = Ray.magnitude();
    2856         144 :     RayNorm = Ray / (-Dist);
    2857         144 :     RefPointGeomMap.SolidAngleVec(curWinEl) = RayNorm;
    2858         144 :     CosB = dot(WNorm, RayNorm);
    2859         144 :     RefPointGeomMap.SolidAngle(curWinEl) = WinElArea * CosB / (Dist * Dist);
    2860         144 : }
    2861             : 
    2862          18 : void CFSRefPointPosFactor(EnergyPlusData &state,
    2863             :                           Vector3<Real64> const &RefPoint,
    2864             :                           DataBSDFWindow::BSDFRefPoints &RefPointMap,
    2865             :                           int const iWin,
    2866             :                           int const CurFenState,
    2867             :                           int const NTrnBasis,
    2868             :                           Real64 const AZVIEW)
    2869             : {
    2870             :     // SUBROUTINE INFORMATION:
    2871             :     //       AUTHOR         Simon Vidanovic
    2872             :     //       DATE WRITTEN   June 2013
    2873             :     //       MODIFIED       na
    2874             :     //       RE-ENGINEERED  na
    2875             : 
    2876             :     // PURPOSE OF THIS SUBROUTINE:
    2877             :     // Calculate position factor for given reference point.
    2878             : 
    2879             :     // Using/Aliasing
    2880             :     using WindowComplexManager::DaylghtAltAndAzimuth;
    2881             : 
    2882             :     // SUBROUTINE LOCAL VARIABLES
    2883             :     int iTrnRay;
    2884             :     Real64 XR;
    2885             :     Real64 YR;
    2886          18 :     auto &V = state.dataDaylightingManager->V;
    2887          18 :     auto &InterPoint = state.dataDaylightingManager->InterPoint;
    2888             :     bool hit;
    2889             : 
    2890             :     // Object Data
    2891          18 :     DataBSDFWindow::BSDFDaylghtPosition elPos; // altitude and azimuth of intersection element
    2892             : 
    2893          18 :     auto const &sTrn(state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sTrn);
    2894        2628 :     for (iTrnRay = 1; iTrnRay <= NTrnBasis; ++iTrnRay) {
    2895        2610 :         V = sTrn(iTrnRay);
    2896        2610 :         V.negate();
    2897             :         PierceSurface(state, iWin, RefPoint, V, InterPoint, hit);
    2898        2610 :         if (hit) {
    2899         234 :             RefPointMap.RefPointIntersection(iTrnRay) = true;
    2900             : 
    2901         234 :             elPos = DaylghtAltAndAzimuth(V);
    2902             : 
    2903         234 :             XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - elPos.Azimuth) + 0.001);
    2904         234 :             YR = std::tan(elPos.Altitude + 0.001);
    2905         234 :             RefPointMap.RefPtIntPosFac(iTrnRay) = DayltgGlarePositionFactor(XR, YR);
    2906             :         }
    2907             :     }
    2908          18 : }
    2909             : 
    2910        9906 : Real64 CalcObstrMultiplier(EnergyPlusData &state,
    2911             :                            Vector3<Real64> const &GroundHitPt, // Coordinates of point that ray hits ground (m)
    2912             :                            int const AltSteps,                 // Number of steps in altitude angle for solar reflection calc
    2913             :                            int const AzimSteps                 // Number of steps in azimuth angle of solar reflection calc
    2914             : )
    2915             : {
    2916             : 
    2917             :     // SUBROUTINE INFORMATION:
    2918             :     //       AUTHOR         Simon Vidanovic
    2919             :     //       DATE WRITTEN   April 2013, refactor from legacy code by Fred Winklemann
    2920             :     //       MODIFIED       na
    2921             :     //       RE-ENGINEERED  na
    2922             : 
    2923             :     // PURPOSE OF THIS SUBROUTINE:
    2924             :     // collect code to do obstruction multiplier from ground point
    2925             : 
    2926             :     // METHODOLOGY EMPLOYED:
    2927             :     // Send rays upward from hit point and see which ones are unobstructed and so go to sky.
    2928             :     // Divide hemisphere centered at ground hit point into elements of altitude Phi and
    2929             :     // azimuth Theta and create upward-going ground ray unit vector at each Phi,Theta pair.
    2930             :     // Phi = 0 at the horizon; Phi = Pi/2 at the zenith.
    2931             : 
    2932             :     // USE STATEMENTS:
    2933             :     using DataSurfaces::AzimAngStepsForSolReflCalc;
    2934             : 
    2935             :     // Return value
    2936             :     Real64 ObstrMultiplier;
    2937             : 
    2938             :     // Locals
    2939             :     Real64 DPhi;        // Phi increment (radians)
    2940             :     Real64 DTheta;      // Theta increment (radians)
    2941             :     Real64 SkyGndUnObs; // Unobstructed sky irradiance at a ground point
    2942             :     Real64 SkyGndObs;   // Obstructed sky irradiance at a ground point
    2943             : 
    2944             :     Real64 Phi;   // Altitude  angle of ray from a ground point (radians)
    2945             :     Real64 SPhi;  // Sin of Phi
    2946             :     Real64 CPhi;  // cos of Phi
    2947             :     Real64 Theta; // Azimuth angle of ray from a ground point (radians)
    2948             : 
    2949             :     Real64 CosIncAngURay;                                              // Cosine of incidence angle of URay on ground plane
    2950             :     Real64 dOmegaGnd;                                                  // Solid angle element of ray from ground point (steradians)
    2951             :     Real64 IncAngSolidAngFac;                                          // CosIncAngURay*dOmegaGnd/Pi
    2952             :     bool hitObs;                                                       // True iff obstruction is hit
    2953        9906 :     auto &URay = state.dataDaylightingManager->URay;                   // Unit vector in (Phi,Theta) direction
    2954        9906 :     auto &ObsHitPt = state.dataDaylightingManager->ObsHitPt;           // Unit vector in (Phi,Theta) direction
    2955        9906 :     auto &AltSteps_last = state.dataDaylightingManager->AltSteps_last; // Unit vector in (Phi,Theta) direction
    2956        9906 :     auto &cos_Phi = state.dataDaylightingManager->cos_Phi;             // Unit vector in (Phi,Theta) direction
    2957        9906 :     auto &sin_Phi = state.dataDaylightingManager->sin_Phi;             // Unit vector in (Phi,Theta) direction
    2958        9906 :     auto &cos_Theta = state.dataDaylightingManager->cos_Theta;         // Unit vector in (Phi,Theta) direction
    2959        9906 :     auto &sin_Theta = state.dataDaylightingManager->sin_Theta;         // Unit vector in (Phi,Theta) direction
    2960        9906 :     auto &AzimSteps_last = state.dataDaylightingManager->AzimSteps_last;
    2961             : 
    2962        9906 :     assert(AzimSteps <= AzimAngStepsForSolReflCalc);
    2963             : 
    2964        9906 :     DPhi = DataGlobalConstants::PiOvr2 / (AltSteps / 2.0);
    2965        9906 :     DTheta = DataGlobalConstants::Pi / AzimSteps;
    2966        9906 :     SkyGndObs = 0.0;
    2967        9906 :     SkyGndUnObs = 0.0;
    2968             : 
    2969             :     // Tuned Precompute Phi trig table
    2970        9906 :     if (AltSteps != AltSteps_last) {
    2971          18 :         for (int IPhi = 1, IPhi_end = (AltSteps / 2); IPhi <= IPhi_end; ++IPhi) {
    2972          15 :             Phi = (IPhi - 0.5) * DPhi;
    2973          15 :             cos_Phi(IPhi) = std::cos(Phi);
    2974          15 :             sin_Phi(IPhi) = std::sin(Phi);
    2975             :         }
    2976           3 :         AltSteps_last = AltSteps;
    2977             :     }
    2978             :     // Tuned Precompute Theta trig table
    2979        9906 :     if (AzimSteps != AzimSteps_last) {
    2980          57 :         for (int ITheta = 1; ITheta <= 2 * AzimSteps; ++ITheta) {
    2981          54 :             Theta = (ITheta - 0.5) * DTheta;
    2982          54 :             cos_Theta(ITheta) = std::cos(Theta);
    2983          54 :             sin_Theta(ITheta) = std::sin(Theta);
    2984             :         }
    2985           3 :         AzimSteps_last = AzimSteps;
    2986             :     }
    2987             : 
    2988             :     // Altitude loop
    2989       59436 :     for (int IPhi = 1, IPhi_end = (AltSteps / 2); IPhi <= IPhi_end; ++IPhi) {
    2990       49530 :         SPhi = sin_Phi(IPhi);
    2991       49530 :         CPhi = cos_Phi(IPhi);
    2992             : 
    2993             :         // Third component of ground ray unit vector in (Theta,Phi) direction
    2994       49530 :         URay(3) = SPhi;
    2995       49530 :         dOmegaGnd = CPhi * DTheta * DPhi;
    2996             :         // Cosine of angle of incidence of ground ray on ground plane
    2997       49530 :         CosIncAngURay = SPhi;
    2998       49530 :         IncAngSolidAngFac = CosIncAngURay * dOmegaGnd / DataGlobalConstants::Pi;
    2999             :         // Azimuth loop
    3000      941070 :         for (int ITheta = 1; ITheta <= 2 * AzimSteps; ++ITheta) {
    3001      891540 :             URay(1) = CPhi * cos_Theta(ITheta);
    3002      891540 :             URay(2) = CPhi * sin_Theta(ITheta);
    3003      891540 :             SkyGndUnObs += IncAngSolidAngFac;
    3004             :             // Does this ground ray hit an obstruction?
    3005      891540 :             hitObs = false;
    3006      891540 :             if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
    3007             : 
    3008     1770233 :                 for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    3009             :                     PierceSurface(state, ObsSurfNum, GroundHitPt, URay, ObsHitPt, hitObs); // Check if ray pierces surface
    3010     1054441 :                     if (hitObs) break;
    3011             :                 }
    3012             : 
    3013             :             } else { // Surface octree search
    3014             : 
    3015             :                 // Lambda function for the octree to test for surface hit
    3016           0 :                 auto surfaceHit = [&GroundHitPt, &hitObs, &URay, &ObsHitPt](SurfaceData const &surface) -> bool {
    3017           0 :                     if (surface.IsShadowPossibleObstruction) {
    3018             :                         PierceSurface(surface, GroundHitPt, URay, ObsHitPt, hitObs); // Check if ray pierces surface
    3019           0 :                         return hitObs;                                               // Ray pierces surface
    3020             :                     } else {
    3021           0 :                         return false;
    3022             :                     }
    3023           0 :                 };
    3024             : 
    3025             :                 // Check octree surface candidates until a hit is found, if any
    3026           0 :                 Vector3<Real64> const URay_inv(SurfaceOctreeCube::safe_inverse(URay));
    3027           0 :                 state.dataHeatBalMgr->surfaceOctree.hasSurfaceRayIntersectsCube(GroundHitPt, URay, URay_inv, surfaceHit);
    3028             :             }
    3029             : 
    3030      891540 :             if (hitObs) continue; // Obstruction hit
    3031             :             // Sky is hit
    3032      715792 :             SkyGndObs += IncAngSolidAngFac;
    3033             :         } // End of azimuth loop
    3034             :     }     // End of altitude loop
    3035             : 
    3036             :     // in case ground point is surrounded by obstructions (SkyGndUnObs == 0), then multiplier will be equal to zero
    3037             :     // This should not happen anyway because in that case ray would not be able to reach ground point
    3038        9906 :     ObstrMultiplier = 0.0;
    3039             : 
    3040        9906 :     if (SkyGndUnObs != 0.0) {
    3041        9906 :         ObstrMultiplier = SkyGndObs / SkyGndUnObs;
    3042             :     }
    3043             : 
    3044        9906 :     return ObstrMultiplier;
    3045             : }
    3046             : 
    3047    65710656 : void FigureDayltgCoeffsAtPointsForSunPosition(
    3048             :     EnergyPlusData &state,
    3049             :     int const daylightCtrlNum, // Daylighting control index
    3050             :     int const iRefPoint,
    3051             :     int const iXelement,
    3052             :     int const NWX, // Number of window elements in x direction for dayltg calc
    3053             :     int const iYelement,
    3054             :     int const NWY,   // Number of window elements in y direction for dayltg calc
    3055             :     int const WinEl, // Current window element counter
    3056             :     int const IWin,
    3057             :     int const IWin2,
    3058             :     int const iHour,
    3059             :     int &ISunPos,
    3060             :     Real64 const SkyObstructionMult,
    3061             :     Vector3<Real64> const &RWIN2, // Center of a window element for TDD:DOME (if exists) in abs coord sys
    3062             :     Vector3<Real64> const &Ray,   // Unit vector along ray from reference point to window element
    3063             :     Real64 const PHRAY,           // Altitude of ray from reference point to window element (radians)
    3064             :     int const LSHCAL,             // Interior shade calculation flag:  0=not yet calculated, 1=already calculated
    3065             :     int const InShelfSurf,        // Inside daylighting shelf surface number
    3066             :     Real64 const COSB,            // Cosine of angle between window outward normal and ray from reference point to window element
    3067             :     Real64 const ObTrans,         // Product of solar transmittances of exterior obstructions hit by ray from reference point through a window element
    3068             :     Real64 const TVISB,           // Visible transmittance of window for COSB angle of incidence (times light well efficiency, if appropriate)
    3069             :     Real64 const DOMEGA,          // Solid angle subtended by window element wrt reference point (steradians)
    3070             :     int const ICtrl,              // Window control counter
    3071             :     WinShadingType const ShType,  // Window shading type
    3072             :     int const BlNum,              // Window blind number
    3073             :     Real64 const THRAY,           // Azimuth of ray from reference point to window element (radians)
    3074             :     Vector3<Real64> const &WNORM2,                // Unit vector normal to window
    3075             :     DataDaylighting::ExtWinType const ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
    3076             :     int const IConst,                             // Construction counter
    3077             :     Real64 const AZVIEW,                          // Azimuth of view vector in absolute coord system for glare calculation (radians)
    3078             :     Vector3<Real64> const &RREF2,                 // Location of virtual reference point in absolute coordinate system
    3079             :     bool const hitIntObs,                         // True iff interior obstruction hit
    3080             :     bool const hitExtObs,                         // True iff ray from ref pt to ext win hits an exterior obstruction
    3081             :     DataDaylighting::CalledFor const CalledFrom,  // indicate  which type of routine called this routine
    3082             :     Real64 &TVISIntWin,                           // Visible transmittance of int win at COSBIntWin for light from ext win
    3083             :     Real64 &TVISIntWinDisk,                       // Visible transmittance of int win at COSBIntWin for sun
    3084             :     int const MapNum)
    3085             : {
    3086             : 
    3087             :     // SUBROUTINE INFORMATION:
    3088             :     //       AUTHOR         B. Griffith
    3089             :     //       DATE WRITTEN   November 2012, refactor from legacy code by Fred Winklemann
    3090             :     //       MODIFIED       na
    3091             :     //       RE-ENGINEERED  na
    3092             : 
    3093             :     // PURPOSE OF THIS SUBROUTINE:
    3094             :     // collect code for calculations sun position aspects for daylighting coefficients
    3095             : 
    3096             :     // METHODOLOGY EMPLOYED:
    3097             :     // switch as need to serve both reference points and map points based on calledFrom
    3098             :     using General::POLYF;
    3099             : 
    3100    99651404 :     if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return;
    3101             : 
    3102             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3103    32161756 :     static Vector3<Real64> const RREF(0.0); // Location of a reference point in absolute coordinate system //Autodesk Was used uninitialized:
    3104             :                                             // Never set here // Made static for performance and const for now until issue addressed
    3105    32161756 :     auto &XEDIRSK = state.dataDaylightingManager->XEDIRSK;
    3106    32161756 :     auto &XAVWLSK = state.dataDaylightingManager->XAVWLSK;
    3107    32161756 :     auto &RAYCOS = state.dataDaylightingManager->RAYCOS;
    3108    32161756 :     auto &TransBmBmMult = state.dataDaylightingManager->TransBmBmMult;
    3109    32161756 :     auto &TransBmBmMultRefl = state.dataDaylightingManager->TransBmBmMultRefl;
    3110    32161756 :     auto &HP = state.dataDaylightingManager->HP;
    3111             :     int JB;         // Slat angle counter
    3112             :     Real64 ProfAng; // Solar profile angle on a window (radians)
    3113             :     Real64 POSFAC;  // Position factor for a window element / ref point / view vector combination
    3114             :     Real64 XR;      // Horizontal displacement ratio
    3115             :     Real64 YR;      // Vertical displacement ratio
    3116             :     bool hit;       // True iff ray from ref point thru window element hits an obstruction
    3117             : 
    3118             :     Real64 ObTransDisk;     // Product of solar transmittances of exterior obstructions hit by ray from reference point to sun
    3119             :     Real64 LumAtHitPtFrSun; // Luminance at hit point of obstruction by reflection of direct light from sun (cd/m2)
    3120             :     int ISky;               // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
    3121             : 
    3122             :     Real64 ELUM;  // Sky or ground luminance (cd/m2)
    3123             :     Real64 DEDIR; // Illuminance contribution at reference point from window element (lux)
    3124             :     Real64 COSI;  // Cosine of angle between direct sun and window outward normal
    3125             :     bool hitWin;  // True iff ray passes thru window
    3126             :     Real64 TVISS; // Direct solar visible transmittance of window at given angle of incidence
    3127             :     //  (times light well efficiency, if appropriate)
    3128             :     Real64 XAVWL; // XAVWL*TVISS is contribution of window luminance from solar disk (cd/m2)
    3129             : 
    3130             :     Real64 SlatAng;                                                        // Blind slat angle (rad)
    3131             :     int NearestHitSurfNum;                                                 // Surface number of nearest obstruction
    3132             :     int NearestHitSurfNumX;                                                // Surface number to use when obstruction is a shadowing surface
    3133    32161756 :     auto &NearestHitPt = state.dataDaylightingManager->NearestHitPt;       // Hit point of ray on nearest obstruction
    3134    32161756 :     auto &GroundHitPt = state.dataDaylightingManager->GroundHitPt;         // Coordinates of point that ray hits ground (m)
    3135    32161756 :     auto &ObsHitPt = state.dataDaylightingManager->ObsHitPt;               // Coordinates of hit point on an obstruction (m)
    3136    32161756 :     auto &ReflNorm = state.dataDaylightingManager->ReflNorm;               // Normal vector to reflecting surface
    3137    32161756 :     auto &SunVecMir = state.dataDaylightingManager->SunVecMir;             // Sun ray mirrored in reflecting surface
    3138    32161756 :     auto &HitPtRefl = state.dataDaylightingManager->HitPtRefl;             // Point that ray hits reflecting surface
    3139    32161756 :     auto &HitPtObs = state.dataDaylightingManager->HitPtObs;               // Hit point on obstruction
    3140    32161756 :     auto &HitPtIntWinDisk = state.dataDaylightingManager->HitPtIntWinDisk; // Intersection point on an interior window for ray from ref pt to sun (m)
    3141             :     Real64 Alfa;                                                           // Intermediate variables
    3142             :     bool hitObs;                                                           // True iff obstruction is hit
    3143             :     Real64 ObsVisRefl;                                                     // Visible reflectance of obstruction
    3144             :     Real64 SkyReflVisLum;                                                  // Reflected sky luminance at hit point divided by
    3145             : 
    3146             :     int RecSurfNum;  // Receiving surface number
    3147             :     int ReflSurfNum; // Reflecting surface number
    3148             :     int ReflSurfNumX;
    3149             :     Real64 CosIncAngRefl;   // Cos of angle of incidence of beam on reflecting surface
    3150             :     Real64 CosIncAngRec;    // Cos of angle of incidence of reflected beam on receiving window
    3151             :     bool hitRefl;           // True iff ray hits reflecting surface
    3152             :     Real64 ReflDistanceSq;  // Distance squared between ref pt and hit point on reflecting surf (m^2)
    3153             :     Real64 ReflDistance;    // Distance between ref pt and hit point on reflecting surf (m)
    3154             :     bool hitObsRefl;        // True iff obstruction hit between ref pt and reflection point
    3155             :     int ReflSurfRecNum;     // Receiving surface number for a reflecting window
    3156             :     Real64 SpecReflectance; // Specular reflectance of a reflecting surface
    3157             :     Real64 TVisRefl;        // Bare window vis trans for reflected beam
    3158             :     //  (times light well efficiency, if appropriate)
    3159             :     Real64 PHSUNrefl; // Altitude angle of reflected sun (radians)
    3160             :     Real64 THSUNrefl; // Azimuth anggle of reflected sun (radians)
    3161             : 
    3162             :     bool hitIntWinDisk; // True iff ray from ref pt to sun passes thru an int window
    3163             :     bool hitIntObsDisk; // True iff ray from ref pt to sun hits an interior obstruction
    3164             :     //        bool hitExtObsDisk; // True iff ray from ref pt to sun hits an exterior obstruction //Unused Set but never
    3165             :     // used
    3166             : 
    3167             :     int IntWinDiskHitNum; // Surface number of int window intersected by ray betw ref pt and sun
    3168             :     Real64 COSBIntWin;    // Cos of angle between int win outward normal and ray betw ref pt and
    3169             :     //  exterior window element or between ref pt and sun
    3170             :     Real64 TVisIntWinMult;     // Interior window vis trans multiplier for ext win in adjacent zone
    3171             :     Real64 TVisIntWinDiskMult; // Interior window vis trans solar disk multiplier for ext win in adj zone
    3172             :     Real64 WindowSolidAngleDaylightPoint;
    3173             : 
    3174    32161756 :     ++ISunPos;
    3175             : 
    3176             :     // Altitude of sun (degrees)
    3177    32161756 :     state.dataDaylightingManager->PHSUN = state.dataDaylightingManager->PHSUNHR(iHour);
    3178    32161756 :     state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(iHour);
    3179    32161756 :     state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(iHour);
    3180             : 
    3181             :     // Azimuth of sun in absolute coord sys
    3182    32161756 :     state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(iHour);
    3183             : 
    3184             :     // First time through, call routine to calculate inter-reflected illuminance
    3185             :     // at reference point and luminance of window with shade, screen or blind.
    3186             : 
    3187             :     // Rob/TH - Not sure whether this call is necessary for interior zones with interior windows only.
    3188             :     //  new code would be -
    3189             :     // IF (LSHCAL == 1 .AND. ExtWinType /= AdjZoneExtWin) CALL DayltgInterReflectedIllum(ISunPos,IHR,ZoneNum,IWin2)
    3190    32161756 :     int enclNum = 0; // enclosure index
    3191    32161756 :     int zoneNum = 0; // zone index
    3192    32161756 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    3193     6250876 :         zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
    3194     6250876 :         enclNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex;
    3195    25910880 :     } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    3196    25910880 :         assert(MapNum > 0);
    3197    25910880 :         zoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
    3198    25910880 :         enclNum = state.dataDaylightingData->IllumMapCalc(MapNum).enclIndex;
    3199             :     }
    3200    32161756 :     if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) {
    3201    32160268 :         if (LSHCAL == 1) DayltgInterReflectedIllum(state, ISunPos, iHour, enclNum, IWin2);
    3202             :     } else {
    3203        1488 :         if (LSHCAL == 1) DayltgInterReflectedIllumComplexFenestration(state, IWin2, WinEl, iHour, daylightCtrlNum, iRefPoint, CalledFrom, MapNum);
    3204        1488 :         if (COSB <= 0.0) return;
    3205        1488 :         DayltgDirectIllumComplexFenestration(state, IWin, WinEl, iHour, iRefPoint, CalledFrom, MapNum);
    3206             :         // Call direct sun component only once since calculation is done for entire window
    3207        1488 :         if (WinEl == (NWX * NWY)) {
    3208         186 :             DayltgDirectSunDiskComplexFenestration(state, IWin2, iHour, iRefPoint, WinEl, AZVIEW, CalledFrom, MapNum);
    3209             :         }
    3210        1488 :         return;
    3211             :     }
    3212             : 
    3213             :     // Daylighting shelf simplification:  The shelf completely blocks all view of the window,
    3214             :     // only interrelflected illumination is allowed (see DayltgInterReflectedIllum above).
    3215             :     // Everything else in this loop has to do with direct luminance from the window.
    3216    32160268 :     if (InShelfSurf > 0) return;
    3217             : 
    3218    31769908 :     if (COSB <= 0.0) return;
    3219             : 
    3220    31769908 :     XEDIRSK = 0.0;
    3221             :     //        XEDIRSU = 0.0; //Unused Set but never used
    3222    31769908 :     XAVWLSK = 0.0;
    3223    31769908 :     Real64 const Ray_3(Ray(3));
    3224    31769908 :     Real64 const DOMEGA_Ray_3(DOMEGA * Ray_3);
    3225             : 
    3226             :     // Add contribution of this window element to glare and to
    3227             :     // direct illuminance at reference point
    3228             : 
    3229             :     // The I,J,K indices for sky and sun components of direct illuminance
    3230             :     // (EDIRSK, EDIRSU) and average window luminance (AVWLSK, AVWLSU) are:
    3231             :     // I=1 for clear sky, =2 Clear turbid, =3 Intermediate, =4 Overcast;
    3232             :     // J=1 for bare window, =2 for window with shade or fixed slat-angle blind;
    3233             :     //  = 2,3,...,MaxSlatAngs+1 for window with variable slat-angle blind;
    3234             :     // K = sun position index.
    3235             : 
    3236             :     // ----- CASE I -- BARE WINDOW (no shading device)
    3237             : 
    3238             :     // Beam solar and sky solar reflected from nearest obstruction.
    3239             :     // In the following hitIntObs == false  ==> no interior obstructions hit, and
    3240             :     //                  hitExtObs == true  ==> one or more exterior obstructions hit.
    3241    31769908 :     if (state.dataSurface->CalcSolRefl && !hitIntObs && hitExtObs) {
    3242             :         // One or more exterior obstructions was hit; get contribution of reflection
    3243             :         // from nearest obstruction.
    3244             :         // Find obstruction whose hit point is closest to this ray's window element
    3245           0 :         DayltgClosestObstruction(state, RWIN2, Ray, NearestHitSurfNum, NearestHitPt);
    3246           0 :         if (NearestHitSurfNum > 0) {
    3247             : 
    3248             :             // Beam solar reflected from nearest obstruction
    3249             : 
    3250           0 :             DayltgSurfaceLumFromSun(state, iHour, Ray, NearestHitSurfNum, NearestHitPt, LumAtHitPtFrSun);
    3251           0 :             state.dataDaylightingManager->AVWLSU(iHour, 1) += LumAtHitPtFrSun * TVISB;
    3252           0 :             if (PHRAY >= 0.0) state.dataDaylightingManager->EDIRSU(iHour, 1) += LumAtHitPtFrSun * DOMEGA_Ray_3 * TVISB;
    3253             : 
    3254             :             // Sky solar reflected from nearest obstruction
    3255             : 
    3256           0 :             int const ObsConstrNum = state.dataSurface->SurfActiveConstruction(NearestHitSurfNum);
    3257           0 :             if (ObsConstrNum > 0) {
    3258             :                 // Exterior building surface is nearest hit
    3259           0 :                 if (!state.dataConstruction->Construct(ObsConstrNum).TypeIsWindow) {
    3260             :                     // Obstruction is not a window, i.e., is an opaque surface
    3261           0 :                     ObsVisRefl = 1.0 - state.dataMaterial->Material(state.dataConstruction->Construct(ObsConstrNum).LayerPoint(1)).AbsorpVisible;
    3262             :                 } else {
    3263             :                     // Obstruction is a window; assume it is bare
    3264           0 :                     ObsVisRefl = state.dataConstruction->Construct(ObsConstrNum).ReflectVisDiffFront;
    3265             :                 }
    3266             :             } else {
    3267             :                 // Shadowing surface is nearest hit
    3268           0 :                 if (state.dataSurface->SurfDaylightingShelfInd(NearestHitSurfNum) > 0) {
    3269             :                     // This is a daylighting shelf, for which reflection is separately calculated
    3270           0 :                     ObsVisRefl = 0.0;
    3271             :                 } else {
    3272           0 :                     ObsVisRefl = state.dataSurface->SurfShadowDiffuseVisRefl(NearestHitSurfNum);
    3273           0 :                     if (state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum) > 0)
    3274           0 :                         ObsVisRefl +=
    3275           0 :                             state.dataSurface->SurfShadowGlazingFrac(NearestHitSurfNum) *
    3276           0 :                             state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum)).ReflectVisDiffFront;
    3277             :                 }
    3278             :             }
    3279           0 :             NearestHitSurfNumX = NearestHitSurfNum;
    3280             :             // Each shadowing surface has a "mirror" duplicate surface facing in the opposite direction.
    3281             :             // The following gets the correct side of a shadowing surface for reflection.
    3282           0 :             if (state.dataSurface->Surface(NearestHitSurfNum).IsShadowing) {
    3283           0 :                 if (dot(Ray, state.dataSurface->Surface(NearestHitSurfNum).OutNormVec) > 0.0) NearestHitSurfNumX = NearestHitSurfNum + 1;
    3284             :             }
    3285           0 :             if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
    3286           0 :                 state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    3287           0 :                 SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
    3288           0 :                                 state.dataSolarShading->SurfDifShdgRatioIsoSky(NearestHitSurfNumX) / DataGlobalConstants::Pi;
    3289             :             } else {
    3290           0 :                 SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
    3291           0 :                                 state.dataSolarShading->SurfDifShdgRatioIsoSkyHRTS(1, iHour, NearestHitSurfNumX) / DataGlobalConstants::Pi;
    3292             :             }
    3293           0 :             assert(equal_dimensions(state.dataDaylightingManager->AVWLSK, state.dataDaylightingManager->EDIRSK));
    3294           0 :             auto l2(state.dataDaylightingManager->GILSK.index(iHour, 1));
    3295           0 :             auto l3(state.dataDaylightingManager->AVWLSK.index(iHour, 1, 1));
    3296           0 :             for (ISky = 1; ISky <= 4; ++ISky, ++l2, ++l3) { // [ l2 ] == ( ISky, iHour ) // [ l3 ] == ( ISky, 1, iHour )
    3297           0 :                 XAVWLSK(ISky) = state.dataDaylightingManager->GILSK[l2] * SkyReflVisLum;
    3298           0 :                 state.dataDaylightingManager->AVWLSK[l3] += XAVWLSK(ISky) * TVISB;
    3299           0 :                 if (PHRAY >= 0.0) {
    3300           0 :                     XEDIRSK(ISky) = state.dataDaylightingManager->GILSK[l2] * SkyReflVisLum * DOMEGA_Ray_3;
    3301           0 :                     state.dataDaylightingManager->EDIRSK[l3] += XEDIRSK(ISky) * TVISB;
    3302             :                 }
    3303             :             }
    3304             :         }
    3305             :     } // End of check if solar reflection calculation is in effect
    3306             : 
    3307    31769908 :     if (ObTrans > 1.e-6) {
    3308             :         // Ray did not hit an obstruction or the transmittance product of hit obstructions is non-zero.
    3309             :         // Contribution of sky or ground luminance in cd/m2
    3310    30955888 :         if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
    3311             :             // Make all transmitted light diffuse for a TDD with a bare diffuser
    3312        2448 :             assert(equal_dimensions(state.dataDaylightingManager->AVWLSK, state.dataDaylightingManager->WLUMSK));
    3313        2448 :             assert(equal_dimensions(state.dataDaylightingManager->AVWLSK, state.dataDaylightingManager->EDIRSK));
    3314        2448 :             auto l3(state.dataDaylightingManager->AVWLSK.index(iHour, 1, 1));
    3315       12240 :             for (ISky = 1; ISky <= 4; ++ISky, ++l3) { // [ l3 ] == ( ISky, 1, iHour )
    3316        9792 :                 state.dataDaylightingManager->AVWLSK[l3] += state.dataDaylightingManager->WLUMSK[l3];
    3317        9792 :                 if (ISky == 1) {
    3318        2448 :                     state.dataDaylightingManager->AVWLSU(iHour, 1) += state.dataDaylightingManager->WLUMSU(iHour, 1);
    3319        2448 :                     state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += state.dataDaylightingManager->WLUMSUdisk(iHour, 1);
    3320             :                 }
    3321        9792 :                 if (PHRAY > 0.0) {
    3322        9792 :                     state.dataDaylightingManager->EDIRSK[l3] += state.dataDaylightingManager->WLUMSK[l3] * DOMEGA_Ray_3;
    3323        9792 :                     if (ISky == 1) state.dataDaylightingManager->EDIRSU(iHour, 1) += state.dataDaylightingManager->WLUMSU(iHour, 1) * DOMEGA_Ray_3;
    3324             :                 }
    3325             :             }
    3326             : 
    3327             :         } else { // Bare window
    3328             :             // Tuned Hoisted operations out of loop and linear indexing
    3329    30953440 :             if (state.dataSurface->CalcSolRefl) { // Coordinates of ground point hit by the ray
    3330         768 :                 Alfa = std::acos(-Ray_3);
    3331         768 :                 Real64 const Ray_1(Ray(1));
    3332         768 :                 Real64 const Ray_2(Ray(2));
    3333             :                 //                    Beta = std::atan2( Ray_2, Ray_1 ); //Unused Tuning below eliminated use
    3334         768 :                 Real64 HorDis((RWIN2(3) - state.dataSurface->GroundLevelZ) *
    3335         768 :                               std::tan(Alfa)); // Distance between ground hit point and proj'n of center
    3336         768 :                 GroundHitPt(3) = state.dataSurface->GroundLevelZ;
    3337             :                 // Tuned Replaced by below: sqrt is faster than sincos
    3338             :                 //                    GroundHitPt( 1 ) = RWIN2( 1 ) + HorDis * std::cos( Beta );
    3339             :                 //                    GroundHitPt( 2 ) = RWIN2( 2 ) + HorDis * std::sin( Beta );
    3340         768 :                 Real64 const Ray_r(std::sqrt(square(Ray_1) + square(Ray_2)));
    3341         768 :                 if (Ray_r > 0.0) {
    3342         768 :                     HorDis /= Ray_r;
    3343         768 :                     GroundHitPt(1) = RWIN2(1) + HorDis * Ray_1;
    3344         768 :                     GroundHitPt(2) = RWIN2(2) + HorDis * Ray_2;
    3345             :                 } else { // Treat as angle==0
    3346           0 :                     GroundHitPt(1) = RWIN2(1) + HorDis;
    3347           0 :                     GroundHitPt(2) = RWIN2(2);
    3348             :                 }
    3349             :             }
    3350    30953440 :             Real64 const GILSK_mult((state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi) * ObTrans * SkyObstructionMult);
    3351    30953440 :             Real64 const TVISB_ObTrans(TVISB * ObTrans);
    3352    30953440 :             Real64 const AVWLSU_add(TVISB_ObTrans * state.dataDaylightingManager->GILSU(iHour) *
    3353    30953440 :                                     (state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi));
    3354    61906880 :             Vector3<Real64> const SUNCOS_iHour(state.dataSurface->SurfSunCosHourly(iHour));
    3355    30953440 :             assert(equal_dimensions(state.dataDaylightingManager->EDIRSK, state.dataDaylightingManager->AVWLSK));
    3356    30953440 :             auto l(state.dataDaylightingManager->EDIRSK.index(iHour, 1, 1));
    3357   154767200 :             for (ISky = 1; ISky <= 4; ++ISky, ++l) { // [ l ] == ( iHour, 1, ISky )
    3358   123813760 :                 if (PHRAY > 0.0) {                   // Ray heads upward to sky
    3359   123472844 :                     ELUM = DayltgSkyLuminance(state, ISky, THRAY, PHRAY);
    3360   123472844 :                     XEDIRSK(ISky) = ELUM * DOMEGA_Ray_3;
    3361   123472844 :                     DEDIR = XEDIRSK(ISky) * TVISB;
    3362   123472844 :                     state.dataDaylightingManager->EDIRSK[l] += DEDIR * ObTrans;
    3363   123472844 :                     state.dataDaylightingManager->AVWLSK[l] += ELUM * TVISB_ObTrans;
    3364   123472844 :                     XAVWLSK(ISky) = ELUM * ObTrans;
    3365             :                 } else { // PHRAY <= 0.
    3366             :                     // Ray heads downward to ground.
    3367             :                     // Contribution from sky diffuse reflected from ground
    3368      340916 :                     XAVWLSK(ISky) = state.dataDaylightingManager->GILSK(iHour, ISky) * GILSK_mult;
    3369      340916 :                     state.dataDaylightingManager->AVWLSK[l] += TVISB * XAVWLSK(ISky);
    3370             :                     // Contribution from beam solar reflected from ground (beam reaching ground point
    3371             :                     // can be obstructed [SunObstructionMult < 1.0] if CalcSolRefl = .TRUE.)
    3372      340916 :                     if (ISky == 1) {
    3373             :                         // SunObstructionMult = 1.0; //Tuned
    3374       85229 :                         if (state.dataSurface->CalcSolRefl) { // Coordinates of ground point hit by the ray
    3375             :                             // Sun reaches ground point if vector from this point to the sun is unobstructed
    3376         240 :                             hitObs = false;
    3377        1155 :                             for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    3378             :                                 PierceSurface(state, ObsSurfNum, GroundHitPt, SUNCOS_iHour, ObsHitPt, hitObs);
    3379         942 :                                 if (hitObs) break;
    3380             :                             }
    3381             :                             // if ( hitObs ) SunObstructionMult = 0.0;
    3382         240 :                             if (!hitObs) state.dataDaylightingManager->AVWLSU(iHour, 1) += AVWLSU_add;
    3383             :                         } else {
    3384       84989 :                             state.dataDaylightingManager->AVWLSU(iHour, 1) += AVWLSU_add;
    3385             :                         }
    3386             :                     } // End of check if ISky = 1
    3387             :                 }     // End of check if ray is going up or down
    3388             :             }         // End of loop over sky types
    3389             :         }             // End of check if bare window or TDD:DIFFUSER
    3390             :     }                 // End of check if ObTrans > 1.E-6
    3391             : 
    3392             :     // Illuminance from beam solar (without interior reflection)
    3393             :     // Just run this once on the last pass
    3394    31769908 :     if (iXelement == NWX && iYelement == NWY) { // Last pass
    3395             : 
    3396             :         // Beam solar reaching reference point directly without exterior reflection
    3397             : 
    3398             :         // Unit vector from ref. pt. to sun
    3399      317368 :         RAYCOS(1) = state.dataDaylightingManager->CPHSUN * std::cos(state.dataDaylightingManager->THSUN);
    3400      317368 :         RAYCOS(2) = state.dataDaylightingManager->CPHSUN * std::sin(state.dataDaylightingManager->THSUN);
    3401      317368 :         RAYCOS(3) = state.dataDaylightingManager->SPHSUN;
    3402             : 
    3403             :         // Is sun on front side of exterior window?
    3404      317368 :         COSI = dot(WNORM2, RAYCOS);
    3405      317368 :         if (COSI > 0.0) {
    3406             : 
    3407             :             // Does RAYCOS pass thru exterior window? HP is point that RAYCOS intersects window plane.
    3408             :             PierceSurface(state, IWin2, RREF2, RAYCOS, HP, hitWin);
    3409      240911 :             hitIntObsDisk = false;
    3410      240911 :             if (hitWin) {
    3411        8373 :                 if (ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin) {
    3412             :                     // Check for interior obstructions between reference point and HP.
    3413        8147 :                     DayltgHitInteriorObstruction(state, IWin2, RREF2, HP, hitIntObsDisk);
    3414             :                 }
    3415        8373 :                 ObTransDisk = 0.0; // Init value
    3416             :                 // Init flag for vector from RP to sun passing through interior window
    3417        8373 :                 hitIntWinDisk = false;
    3418        8373 :                 if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) { // This block is for RPs in zones with interior windows
    3419             :                     // adjacent to zones with exterior windows
    3420             :                     // Does RAYCOS pass through interior window in zone containing RP?
    3421             :                     // Loop over zone surfaces looking for interior windows between reference point and sun
    3422         226 :                     auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    3423         452 :                     for (int spaceNum : thisZone.spaceIndexes) {
    3424         226 :                         auto &thisSpace = state.dataHeatBal->space(spaceNum);
    3425         452 :                         for (int IntWinDisk = thisSpace.WindowSurfaceFirst, IntWinDisk_end = thisSpace.WindowSurfaceLast;
    3426         452 :                              IntWinDisk <= IntWinDisk_end;
    3427             :                              ++IntWinDisk) {
    3428         226 :                             if (state.dataSurface->Surface(IntWinDisk).ExtBoundCond >= 1) {
    3429         452 :                                 if (state.dataSurface->Surface(state.dataSurface->Surface(IntWinDisk).ExtBoundCond).Zone ==
    3430         226 :                                     state.dataSurface->Surface(IWin2).Zone) {
    3431             :                                     PierceSurface(state, IntWinDisk, RREF, RAYCOS, HitPtIntWinDisk, hitIntWinDisk);
    3432         226 :                                     if (hitIntWinDisk) {
    3433           0 :                                         IntWinDiskHitNum = IntWinDisk;
    3434           0 :                                         COSBIntWin = dot(state.dataSurface->Surface(IntWinDisk).OutNormVec, RAYCOS);
    3435           0 :                                         if (COSBIntWin <= 0.0) {
    3436           0 :                                             hitIntWinDisk = false;
    3437           0 :                                             IntWinDiskHitNum = 0;
    3438           0 :                                             continue;
    3439             :                                         }
    3440           0 :                                         TVISIntWinDisk = POLYF(
    3441             :                                             COSBIntWin,
    3442           0 :                                             state.dataConstruction->Construct(state.dataSurface->Surface(IntWinDisk).Construction).TransVisBeamCoef);
    3443           0 :                                         break;
    3444             :                                     }
    3445             :                                 }
    3446             :                             }
    3447             :                         }
    3448             :                     }
    3449             : 
    3450         226 :                     if (!hitIntWinDisk) { // Vector from RP to sun does not pass through interior window
    3451         226 :                         ObTransDisk = 0.0;
    3452         226 :                         hit = true; //! fcw Is this needed?
    3453             :                     }
    3454             : 
    3455             :                     // Check for interior obstructions between ref point and interior window
    3456         226 :                     hitIntObsDisk = false;
    3457         226 :                     if (hitIntWinDisk) {
    3458           0 :                         DayltgHitInteriorObstruction(state, IntWinDiskHitNum, RREF, HitPtIntWinDisk, hitIntObsDisk);
    3459             :                         // If no obstruction between RP and hit int win, check for obstruction
    3460             :                         // between int win and ext win
    3461           0 :                         if (!hitIntObsDisk) {
    3462           0 :                             DayltgHitBetWinObstruction(state, IntWinDiskHitNum, IWin2, HitPtIntWinDisk, HP, hitIntObsDisk);
    3463             :                         }
    3464             :                     }
    3465         226 :                     if (hitIntObsDisk) ObTransDisk = 0.0;
    3466             :                 } // case where RP is in zone with interior window adjacent to zone with exterior window
    3467             : 
    3468             :                 //                    hitExtObsDisk = false; //Unused Set but never used
    3469             :                 // RJH 08-25-07 hitIntWinDisk should not be reset to false here, and should be tested below.
    3470             :                 // This is to correct logic flaw causing direct solar to reach adjacent zone refpt
    3471             :                 // when vector to sun does not pass through interior window
    3472             :                 // hitIntWinDisk = false
    3473        8373 :                 if (!hitIntObsDisk) { // No interior obstruction was hit
    3474             :                     // Net transmittance of exterior obstructions encountered by RAYCOS
    3475             :                     // ObTransDisk = 1.0 will be returned if no exterior obstructions are hit.
    3476        8369 :                     DayltgHitObstruction(state, iHour, IWin2, RREF2, RAYCOS, ObTransDisk);
    3477             :                     //                        if ( ObTransDisk < 1.0 ) hitExtObsDisk = true; //Unused Set but never used
    3478             :                     // RJH 08-26-07 However, if this is a case of interior window
    3479             :                     // and vector to sun does not pass through interior window
    3480             :                     // then reset ObTransDisk to 0.0 since it is the key test for adding
    3481             :                     // contribution of sun to RP below.
    3482        8369 :                     if ((ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) && (!hitIntWinDisk)) {
    3483         226 :                         ObTransDisk = 0.0;
    3484             :                     }
    3485             :                 }
    3486             : 
    3487             :                 // PETER: need side wall mounted TDD to test this
    3488             :                 // PETER: probably need to replace RREF2 with RWIN2
    3489             :                 // PETER: need to check for interior obstructions too.
    3490             : 
    3491        8373 :                 if (ObTransDisk > 1.e-6) {
    3492             : 
    3493             :                     // Sun reaches reference point;  increment illuminance.
    3494             :                     // Direct normal illuminance is normalized to 1.0
    3495             : 
    3496        7829 :                     if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
    3497             :                         // No beam is transmitted.  Takes care of TDD with a bare diffuser and all types of blinds.
    3498           0 :                         TVISS = 0.0;
    3499             :                     } else {
    3500             :                         // Beam transmittance for bare window and all types of blinds
    3501       15658 :                         TVISS = POLYF(COSI, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin) *
    3502        7829 :                                 state.dataSurface->SurfWinLightWellEff(IWin);
    3503        7829 :                         if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin && hitIntWinDisk) TVISS *= TVISIntWinDisk;
    3504             :                     }
    3505             : 
    3506        7829 :                     state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = RAYCOS(3) * TVISS * ObTransDisk; // Bare window
    3507             : 
    3508        7829 :                     TransBmBmMult = 0.0;
    3509        7829 :                     if (ANY_BLIND(ShType)) {
    3510           0 :                         ProfileAngle(state, IWin, RAYCOS, state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
    3511             :                         // Contribution of beam passing through slats and reaching reference point
    3512           0 :                         for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    3513             :                             // IF (.NOT.SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
    3514           0 :                             if (state.dataSurface->SurfWinMovableSlats(IWin)) {
    3515           0 :                                 SlatAng = (JB - 1) * DataGlobalConstants::Pi / (MaxSlatAngs - 1);
    3516             :                             } else {
    3517           0 :                                 SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
    3518             :                             }
    3519           0 :                             TransBmBmMult(JB) = General::BlindBeamBeamTrans(ProfAng,
    3520             :                                                                             SlatAng,
    3521           0 :                                                                             state.dataHeatBal->Blind(BlNum).SlatWidth,
    3522           0 :                                                                             state.dataHeatBal->Blind(BlNum).SlatSeparation,
    3523           0 :                                                                             state.dataHeatBal->Blind(BlNum).SlatThickness);
    3524           0 :                             state.dataDaylightingManager->EDIRSUdisk(iHour, JB + 1) = RAYCOS(3) * TVISS * TransBmBmMult(JB) * ObTransDisk;
    3525             : 
    3526             :                             // do this only once for fixed slat blinds
    3527           0 :                             if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
    3528             :                         }
    3529        7829 :                     } else if (ShType == WinShadingType::ExtScreen) {
    3530             :                         //                          pass angle from sun to window normal here using PHSUN and THSUN from above and surface angles
    3531             :                         //                          SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi
    3532             :                         //                          SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta
    3533           0 :                         CalcScreenTransmittance(state,
    3534             :                                                 IWin,
    3535           0 :                                                 (state.dataDaylightingManager->PHSUN - state.dataSurface->SurfWinPhi(IWin)),
    3536           0 :                                                 (state.dataDaylightingManager->THSUN - state.dataSurface->SurfWinTheta(IWin)));
    3537           0 :                         TransBmBmMult(1) = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTrans;
    3538           0 :                         state.dataDaylightingManager->EDIRSUdisk(iHour, 2) = RAYCOS(3) * TVISS * TransBmBmMult(1) * ObTransDisk;
    3539             :                     }
    3540             : 
    3541        7829 :                     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    3542             :                         // Glare from solar disk
    3543             : 
    3544             :                         // Position factor for sun (note that AZVIEW is wrt y-axis and THSUN is wrt
    3545             :                         // x-axis of absolute coordinate system.
    3546        5933 :                         XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - state.dataDaylightingManager->THSUN) + 0.001);
    3547        5933 :                         YR = std::tan(state.dataDaylightingManager->PHSUN + 0.001);
    3548        5933 :                         POSFAC = DayltgGlarePositionFactor(XR, YR);
    3549             : 
    3550        5933 :                         WindowSolidAngleDaylightPoint = state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint);
    3551             : 
    3552        5933 :                         if (POSFAC != 0.0 && WindowSolidAngleDaylightPoint > 0.000001) {
    3553             :                             // Increment window luminance.  Luminance of solar disk (cd/m2)
    3554             :                             // is 1.47*10^4*(direct normal solar illuminance) for direct normal solar
    3555             :                             // illuminance in lux (lumens/m2). For purposes of calculating daylight factors
    3556             :                             // direct normal solar illuminance = 1.0.
    3557             :                             // Solid angle subtended by sun is 0.000068 steradians
    3558             : 
    3559        3771 :                             XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(WindowSolidAngleDaylightPoint, 0.8);
    3560        3771 :                             state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = XAVWL * TVISS * ObTransDisk; // Bare window
    3561             : 
    3562        3771 :                             if (ANY_BLIND(ShType)) {
    3563           0 :                                 for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    3564             :                                     // IF (.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
    3565           0 :                                     state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) = XAVWL * TVISS * TransBmBmMult(JB) * ObTransDisk;
    3566           0 :                                     if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
    3567             :                                 }
    3568        3771 :                             } else if (ShType == WinShadingType::ExtScreen) {
    3569           0 :                                 state.dataDaylightingManager->AVWLSUdisk(iHour, 2) = XAVWL * TVISS * TransBmBmMult(1) * ObTransDisk;
    3570             :                             }
    3571             :                         } // Position Factor
    3572             :                     }
    3573             :                 } // Beam avoids all obstructions
    3574             :             }     // Beam passes thru window
    3575             :         }         // Sun on front side
    3576             : 
    3577             :         // Beam solar reaching reference point after beam-beam (specular) reflection from
    3578             :         // an exterior surface
    3579             : 
    3580      317368 :         if (state.dataSurface->CalcSolRefl) {
    3581             :             // Receiving surface number corresponding this window
    3582          96 :             RecSurfNum = state.dataSurface->SurfShadowRecSurfNum(IWin2);
    3583          96 :             if (RecSurfNum > 0) { // interior windows do not apply
    3584          96 :                 if (state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs > 0) {
    3585             :                     // This window has associated obstructions that could reflect beam onto the window
    3586         288 :                     for (int loop = 1, loop_end = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs; loop <= loop_end;
    3587             :                          ++loop) {
    3588         192 :                         ReflSurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop);
    3589         192 :                         ReflSurfNumX = ReflSurfNum;
    3590             :                         // Each shadowing surface has a "mirror" duplicate surface facing in the opposite direction.
    3591             :                         // The following gets the correct side of a shadowing surface for reflection.
    3592         192 :                         if (state.dataSurface->Surface(ReflSurfNum).IsShadowing) {
    3593         192 :                             if (dot(RAYCOS, state.dataSurface->Surface(ReflSurfNum).OutNormVec) < 0.0) ReflSurfNumX = ReflSurfNum + 1;
    3594             :                         }
    3595             :                         // Require that the surface can have specular reflection
    3596         384 :                         if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window ||
    3597         192 :                             state.dataSurface->SurfShadowGlazingFrac(ReflSurfNum) > 0.0) {
    3598           0 :                             ReflNorm = state.dataSurface->Surface(ReflSurfNumX).OutNormVec;
    3599             :                             // Vector to sun that is mirrored in obstruction
    3600           0 :                             SunVecMir = RAYCOS - 2.0 * dot(RAYCOS, ReflNorm) * ReflNorm;
    3601             :                             // Skip if reflecting surface is not sunlit
    3602           0 :                             if (state.dataHeatBal->SurfSunlitFrac(iHour, 1, ReflSurfNumX) < 0.01) continue;
    3603             :                             // Skip if altitude angle of mirrored sun is negative since reflected sun cannot
    3604             :                             // reach reference point in this case
    3605           0 :                             if (SunVecMir(3) <= 0.0) continue;
    3606             :                             // Cosine of incidence angle of reflected beam on window
    3607           0 :                             CosIncAngRec = dot(state.dataSurface->Surface(IWin2).OutNormVec, SunVecMir);
    3608           0 :                             if (CosIncAngRec <= 0.0) continue;
    3609             :                             // Does ray from ref. pt. along SunVecMir pass through window?
    3610             :                             PierceSurface(state, IWin2, RREF2, SunVecMir, HP, hitWin);
    3611           0 :                             if (!hitWin) continue; // Ray did not pass through window
    3612             :                             // Check if this ray hits interior obstructions
    3613           0 :                             DayltgHitInteriorObstruction(state, IWin2, RREF2, HP, hit);
    3614           0 :                             if (hit) continue; // Interior obstruction was hit
    3615             :                             // Does ray hit this reflecting surface?
    3616             :                             PierceSurface(state, ReflSurfNum, RREF2, SunVecMir, HitPtRefl, hitRefl);
    3617           0 :                             if (!hitRefl) continue; // Ray did not hit this reflecting surface
    3618           0 :                             ReflDistanceSq = distance_squared(HitPtRefl, RREF2);
    3619           0 :                             ReflDistance = std::sqrt(ReflDistanceSq);
    3620             :                             // Is ray from ref. pt. to reflection point (HitPtRefl) obstructed?
    3621           0 :                             hitObsRefl = false;
    3622           0 :                             for (int loop2 = 1, loop2_end = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs;
    3623           0 :                                  loop2 <= loop2_end;
    3624             :                                  ++loop2) {
    3625           0 :                                 int const ObsSurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop2);
    3626           0 :                                 if (ObsSurfNum == ReflSurfNum || ObsSurfNum == state.dataSurface->Surface(ReflSurfNum).BaseSurf) continue;
    3627             :                                 PierceSurface(state, ObsSurfNum, RREF2, SunVecMir, ReflDistance, HitPtObs, hitObs); // ReflDistance cutoff added
    3628           0 :                                 if (hitObs) { // => Could skip distance check (unless < vs <= ReflDistance really matters)
    3629           0 :                                     if (distance_squared(HitPtObs, RREF2) < ReflDistanceSq) { // Distance squared from ref pt to reflection point
    3630           0 :                                         hitObsRefl = true;
    3631           0 :                                         break;
    3632             :                                     }
    3633             :                                 }
    3634             :                             }
    3635           0 :                             if (hitObsRefl) continue; // Obstruction closer than reflection pt. was hit; go to next obstruction
    3636             :                             // There is no obstruction for this ray between ref pt and hit pt on reflecting surface.
    3637             :                             // See if ray from hit pt on reflecting surface to original (unmirrored) sun position is obstructed
    3638           0 :                             hitObs = false;
    3639           0 :                             if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window) {
    3640             :                                 // Reflecting surface is a window.
    3641             :                                 // Receiving surface number for this reflecting window.
    3642           0 :                                 ReflSurfRecNum = state.dataSurface->SurfShadowRecSurfNum(ReflSurfNum);
    3643           0 :                                 if (ReflSurfRecNum > 0) {
    3644             :                                     // Loop over possible obstructions for this reflecting window
    3645           0 :                                     for (int loop2 = 1, loop2_end = state.dataSolarReflectionManager->SolReflRecSurf(ReflSurfRecNum).NumPossibleObs;
    3646           0 :                                          loop2 <= loop2_end;
    3647             :                                          ++loop2) {
    3648             :                                         int const ObsSurfNum =
    3649           0 :                                             state.dataSolarReflectionManager->SolReflRecSurf(ReflSurfRecNum).PossibleObsSurfNums(loop2);
    3650             :                                         PierceSurface(state, ObsSurfNum, HitPtRefl, RAYCOS, HitPtObs, hitObs);
    3651           0 :                                         if (hitObs) break;
    3652             :                                     }
    3653             :                                 }
    3654             :                             } else {
    3655             :                                 // Reflecting surface is a building shade
    3656           0 :                                 for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    3657           0 :                                     if (ObsSurfNum == ReflSurfNum) continue;
    3658             :                                     PierceSurface(state, ObsSurfNum, HitPtRefl, RAYCOS, HitPtObs, hitObs);
    3659           0 :                                     if (hitObs) break;
    3660             :                                 }
    3661             :                             } // End of check if reflector is a window or shadowing surface
    3662             : 
    3663           0 :                             if (hitObs) continue; // Obstruction hit between reflection hit point and sun; go to next obstruction
    3664             : 
    3665             :                             // No obstructions. Calculate reflected beam illuminance at ref. pt. from this reflecting surface.
    3666           0 :                             SpecReflectance = 0.0;
    3667           0 :                             CosIncAngRefl = std::abs(dot(RAYCOS, ReflNorm));
    3668           0 :                             if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window) {
    3669           0 :                                 int const ConstrNumRefl = state.dataSurface->SurfActiveConstruction(ReflSurfNum);
    3670           0 :                                 SpecReflectance =
    3671           0 :                                     POLYF(std::abs(CosIncAngRefl), state.dataConstruction->Construct(ConstrNumRefl).ReflSolBeamFrontCoef);
    3672             :                             }
    3673           0 :                             if (state.dataSurface->Surface(ReflSurfNum).IsShadowing && state.dataSurface->SurfShadowGlazingConstruct(ReflSurfNum) > 0)
    3674           0 :                                 SpecReflectance = state.dataSurface->SurfShadowGlazingFrac(ReflSurfNum) *
    3675           0 :                                                   POLYF(std::abs(CosIncAngRefl),
    3676           0 :                                                         state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(ReflSurfNum))
    3677             :                                                             .ReflSolBeamFrontCoef);
    3678           0 :                             TVisRefl = POLYF(CosIncAngRec, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
    3679           0 :                                        state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    3680           0 :                             state.dataDaylightingManager->EDIRSUdisk(iHour, 1) += SunVecMir(3) * SpecReflectance * TVisRefl; // Bare window
    3681             : 
    3682           0 :                             TransBmBmMultRefl = 0.0;
    3683           0 :                             if (ANY_BLIND(ShType)) {
    3684           0 :                                 ProfileAngle(state, IWin, SunVecMir, state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
    3685             :                                 // Contribution of reflected beam passing through slats and reaching reference point
    3686           0 :                                 Real64 const Pi_SlatAng_fac(DataGlobalConstants::Pi / (MaxSlatAngs - 1));
    3687           0 :                                 for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    3688             :                                     // IF (.NOT.SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
    3689           0 :                                     if (state.dataSurface->SurfWinMovableSlats(IWin)) {
    3690           0 :                                         SlatAng = double(JB - 1) * Pi_SlatAng_fac;
    3691             :                                     } else {
    3692           0 :                                         SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
    3693             :                                     }
    3694           0 :                                     TransBmBmMultRefl(JB) = General::BlindBeamBeamTrans(ProfAng,
    3695             :                                                                                         SlatAng,
    3696           0 :                                                                                         state.dataHeatBal->Blind(BlNum).SlatWidth,
    3697           0 :                                                                                         state.dataHeatBal->Blind(BlNum).SlatSeparation,
    3698           0 :                                                                                         state.dataHeatBal->Blind(BlNum).SlatThickness);
    3699           0 :                                     state.dataDaylightingManager->EDIRSUdisk(iHour, JB + 1) +=
    3700           0 :                                         SunVecMir(3) * SpecReflectance * TVisRefl * TransBmBmMultRefl(JB);
    3701             : 
    3702           0 :                                     if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
    3703             :                                 }
    3704           0 :                             } else if (ShType == WinShadingType::ExtScreen) {
    3705             :                                 //                             pass angle from sun to window normal here using PHSUN and THSUN from above and
    3706             :                                 //                             surface angles SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi
    3707             :                                 //                             SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta
    3708           0 :                                 CalcScreenTransmittance(state,
    3709             :                                                         IWin,
    3710           0 :                                                         (state.dataDaylightingManager->PHSUN - state.dataSurface->SurfWinPhi(IWin)),
    3711           0 :                                                         (state.dataDaylightingManager->THSUN - state.dataSurface->SurfWinTheta(IWin)));
    3712           0 :                                 TransBmBmMultRefl(1) = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTrans;
    3713           0 :                                 state.dataDaylightingManager->EDIRSUdisk(iHour, 2) +=
    3714           0 :                                     SunVecMir(3) * SpecReflectance * TVisRefl * TransBmBmMultRefl(1);
    3715             :                             } // End of check if window has a blind or screen
    3716             : 
    3717             :                             // Glare from reflected solar disk
    3718             : 
    3719           0 :                             PHSUNrefl = SunVecMir(3);
    3720           0 :                             THSUNrefl = std::atan2(SunVecMir(2), SunVecMir(1));
    3721           0 :                             XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - THSUNrefl) + 0.001);
    3722           0 :                             YR = std::tan(PHSUNrefl + 0.001);
    3723           0 :                             POSFAC = DayltgGlarePositionFactor(XR, YR);
    3724           0 :                             if (POSFAC != 0.0 && state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint) > 0.000001) {
    3725           0 :                                 XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) /
    3726           0 :                                         std::pow(state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint), 0.8);
    3727           0 :                                 state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += XAVWL * TVisRefl * SpecReflectance; // Bare window
    3728           0 :                                 if (ANY_BLIND(ShType)) {
    3729           0 :                                     for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    3730             :                                         // IF(.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
    3731           0 :                                         state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) +=
    3732           0 :                                             XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(JB);
    3733           0 :                                         if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
    3734             :                                     }
    3735           0 :                                 } else if (ShType == WinShadingType::ExtScreen) {
    3736           0 :                                     state.dataDaylightingManager->AVWLSUdisk(iHour, 2) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(1);
    3737             :                                 }
    3738             :                             }
    3739             :                         } // End of check that obstruction can specularly reflect
    3740             :                     }     // End of loop over obstructions associated with this window
    3741             : 
    3742             :                 } // End of check if this window has associated obstructions
    3743             :             }     // End of check to see if this is exterior type window
    3744             :         }         // End of check if exterior reflection calculation is in effect
    3745             : 
    3746             :     } // Last pass
    3747             : 
    3748    31769908 :     if ((ICtrl > 0 && (ANY_BLIND(ShType) || ANY_SHADE_SCREEN(ShType))) || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
    3749             : 
    3750             :         // ----- CASE II -- WINDOW WITH SCREEN, SHADE, BLIND, OR DIFFUSING WINDOW
    3751             : 
    3752             :         // Interior window visible transmittance multiplier for exterior window in adjacent zone
    3753        6000 :         TVisIntWinMult = 1.0;
    3754        6000 :         TVisIntWinDiskMult = 1.0;
    3755        6000 :         if (state.dataSurface->Surface(IWin).SolarEnclIndex != state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex) {
    3756           0 :             TVisIntWinMult = TVISIntWin;
    3757           0 :             TVisIntWinDiskMult = TVISIntWinDisk;
    3758             :         }
    3759             : 
    3760        6000 :         Real64 const DOMEGA_Ray_3_TVisIntWinMult(DOMEGA_Ray_3 * TVisIntWinMult);
    3761       30000 :         for (ISky = 1; ISky <= 4; ++ISky) {
    3762       24000 :             for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    3763             :                 // IF (.NOT.SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
    3764       24000 :                 state.dataDaylightingManager->AVWLSK(iHour, JB + 1, ISky) +=
    3765       24000 :                     state.dataDaylightingManager->WLUMSK(iHour, JB + 1, ISky) * TVisIntWinMult;
    3766       24000 :                 if (ISky == 1) {
    3767        6000 :                     state.dataDaylightingManager->AVWLSU(iHour, JB + 1) += state.dataDaylightingManager->WLUMSU(iHour, JB + 1) * TVisIntWinMult;
    3768        6000 :                     state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) +=
    3769        6000 :                         state.dataDaylightingManager->WLUMSUdisk(iHour, JB + 1) * TVisIntWinDiskMult;
    3770             :                 }
    3771       24000 :                 if (PHRAY > 0.0) {
    3772       21792 :                     state.dataDaylightingManager->EDIRSK(iHour, JB + 1, ISky) +=
    3773       21792 :                         state.dataDaylightingManager->WLUMSK(iHour, JB + 1, ISky) * DOMEGA_Ray_3_TVisIntWinMult;
    3774       21792 :                     if (ISky == 1)
    3775        5448 :                         state.dataDaylightingManager->EDIRSU(iHour, JB + 1) +=
    3776        5448 :                             state.dataDaylightingManager->WLUMSU(iHour, JB + 1) * DOMEGA_Ray_3_TVisIntWinMult;
    3777             :                 }
    3778       24000 :                 if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
    3779             :             }
    3780             :         }
    3781             :     }
    3782             : }
    3783             : 
    3784      360720 : void FigureRefPointDayltgFactorsToAddIllums(EnergyPlusData &state,
    3785             :                                             int const daylightCtrlNum, // Current daylighting control number
    3786             :                                             int const iRefPoint,
    3787             :                                             int const iHour,
    3788             :                                             int &ISunPos,
    3789             :                                             int const IWin,
    3790             :                                             int const loopwin,
    3791             :                                             int const NWX,  // Number of window elements in x direction for dayltg calc
    3792             :                                             int const NWY,  // Number of window elements in y direction for dayltg calc
    3793             :                                             int const ICtrl // Window control counter
    3794             : )
    3795             : {
    3796             : 
    3797             :     // SUBROUTINE INFORMATION:
    3798             :     //       AUTHOR         B. Griffith, Oct 2012, derived from legacy code by Fred Winkelmann
    3799             :     //       DATE WRITTEN   Oct. 2012
    3800             :     //       MODIFIED       na
    3801             :     //       RE-ENGINEERED  na
    3802             : 
    3803             :     // PURPOSE OF THIS SUBROUTINE:
    3804             :     // calculation worker routine to fill daylighting coefficients
    3805             : 
    3806             :     // METHODOLOGY EMPLOYED:
    3807             :     // this version is just for reference points.
    3808             : 
    3809             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3810      360720 :     Real64 constexpr tmpDFCalc(0.05); // cut off illuminance (lux) for exterior horizontal in calculating the daylighting and glare factors
    3811             : 
    3812             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3813             :     int ISky;   // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
    3814             :     int JSH;    // Shading index: J=1 is unshaded window, J=2 is shaded window
    3815             :     Real64 VTR; // For switchable glazing, ratio of visible transmittance of fully-switched state to that of the unswitched state
    3816             : 
    3817      360720 :     if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return;
    3818             : 
    3819      159202 :     ++ISunPos;
    3820             : 
    3821             :     // Altitude of sun (degrees)
    3822      159202 :     state.dataDaylightingManager->PHSUN = state.dataDaylightingManager->PHSUNHR(iHour);
    3823      159202 :     state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(iHour);
    3824      159202 :     state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(iHour);
    3825             : 
    3826             :     // Azimuth of sun in absolute coord sys
    3827      159202 :     state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(iHour);
    3828             : 
    3829      159202 :     auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    3830      159202 :     int const enclNum = state.dataSurface->Surface(IWin).SolarEnclIndex;
    3831             : 
    3832      796010 :     for (ISky = 1; ISky <= 4; ++ISky) { // Loop over sky types
    3833             : 
    3834             :         // Loop over shading index (1=bare window; 2=diffusing glazing, shade, screen or fixed slat-angle blind;
    3835             :         // 2 to MaxSlatAngs+1 for variable slat-angle blind)
    3836             : 
    3837             :         // TH. 9/22/2009. CR 7625 - daylight illuminance spikes during some sunset hours due to the calculated sky and sun
    3838             :         //  related daylight factors > 1, which theoretically can occur when sun is perpendicular to the window
    3839             :         //  and interior surfaces with high visible reflectance.
    3840             :         // Added tmpDFCalc (default to 0.05 lux) as the cap for GILSK and GILSU in calculating the daylight factors
    3841             :         //  the assumption behind it is if exterior horizontal surface does not get daylight, spaces do not get daylight.
    3842             : 
    3843     1910424 :         for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
    3844     1910424 :             if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
    3845             : 
    3846     1273616 :             if (state.dataDaylightingManager->GILSK(iHour, ISky) > tmpDFCalc) {
    3847     1273616 :                 thisDaylightControl.DaylIllFacSky(iHour, JSH, ISky, iRefPoint, loopwin) =
    3848     2547232 :                     (state.dataDaylightingManager->EDIRSK(iHour, JSH, ISky) + state.dataDaylightingManager->EINTSK(iHour, JSH, ISky)) /
    3849     1273616 :                     state.dataDaylightingManager->GILSK(iHour, ISky);
    3850     1273616 :                 thisDaylightControl.DaylSourceFacSky(iHour, JSH, ISky, iRefPoint, loopwin) =
    3851     1273616 :                     state.dataDaylightingManager->AVWLSK(iHour, JSH, ISky) / (NWX * NWY * state.dataDaylightingManager->GILSK(iHour, ISky));
    3852     1273616 :                 thisDaylightControl.DaylBackFacSky(iHour, JSH, ISky, iRefPoint, loopwin) =
    3853     2547232 :                     state.dataDaylightingManager->EINTSK(iHour, JSH, ISky) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
    3854     1273616 :                     (DataGlobalConstants::Pi * state.dataDaylightingManager->GILSK(iHour, ISky));
    3855             :             } else {
    3856           0 :                 thisDaylightControl.DaylIllFacSky(iHour, JSH, ISky, iRefPoint, loopwin) = 0.0;
    3857           0 :                 thisDaylightControl.DaylSourceFacSky(iHour, JSH, ISky, iRefPoint, loopwin) = 0.0;
    3858           0 :                 thisDaylightControl.DaylBackFacSky(iHour, JSH, ISky, iRefPoint, loopwin) = 0.0;
    3859             :             }
    3860             : 
    3861     1273616 :             if (ISky == 1) {
    3862      318404 :                 if (state.dataDaylightingManager->GILSU(iHour) > tmpDFCalc) {
    3863      301326 :                     thisDaylightControl.DaylIllFacSun(iHour, JSH, iRefPoint, loopwin) =
    3864      602652 :                         (state.dataDaylightingManager->EDIRSU(iHour, JSH) + state.dataDaylightingManager->EINTSU(iHour, JSH)) /
    3865      301326 :                         (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
    3866      301326 :                     thisDaylightControl.DaylIllFacSunDisk(iHour, JSH, iRefPoint, loopwin) =
    3867      602652 :                         (state.dataDaylightingManager->EDIRSUdisk(iHour, JSH) + state.dataDaylightingManager->EINTSUdisk(iHour, JSH)) /
    3868      301326 :                         (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
    3869             : 
    3870      301326 :                     thisDaylightControl.DaylSourceFacSun(iHour, JSH, iRefPoint, loopwin) =
    3871      301326 :                         state.dataDaylightingManager->AVWLSU(iHour, JSH) / (NWX * NWY * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
    3872      301326 :                     thisDaylightControl.DaylSourceFacSunDisk(iHour, JSH, iRefPoint, loopwin) =
    3873      301326 :                         state.dataDaylightingManager->AVWLSUdisk(iHour, JSH) / (NWX * NWY * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
    3874             : 
    3875      301326 :                     thisDaylightControl.DaylBackFacSun(iHour, JSH, iRefPoint, loopwin) =
    3876      602652 :                         state.dataDaylightingManager->EINTSU(iHour, JSH) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
    3877      301326 :                         (DataGlobalConstants::Pi * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
    3878      301326 :                     thisDaylightControl.DaylBackFacSunDisk(iHour, JSH, iRefPoint, loopwin) =
    3879      602652 :                         state.dataDaylightingManager->EINTSUdisk(iHour, JSH) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
    3880      301326 :                         (DataGlobalConstants::Pi * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
    3881             :                 } else {
    3882       17078 :                     thisDaylightControl.DaylIllFacSun(iHour, JSH, iRefPoint, loopwin) = 0.0;
    3883       17078 :                     thisDaylightControl.DaylIllFacSunDisk(iHour, JSH, iRefPoint, loopwin) = 0.0;
    3884             : 
    3885       17078 :                     thisDaylightControl.DaylSourceFacSun(iHour, JSH, iRefPoint, loopwin) = 0.0;
    3886       17078 :                     thisDaylightControl.DaylSourceFacSunDisk(iHour, JSH, iRefPoint, loopwin) = 0.0;
    3887             : 
    3888       17078 :                     thisDaylightControl.DaylBackFacSun(iHour, JSH, iRefPoint, loopwin) = 0.0;
    3889       17078 :                     thisDaylightControl.DaylBackFacSunDisk(iHour, JSH, iRefPoint, loopwin) = 0.0;
    3890             :                 }
    3891             :             }
    3892             :         } // End of shading index loop, JSH
    3893             : 
    3894             :         // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location
    3895      636808 :         if (ICtrl > 0) {
    3896        8936 :             if (state.dataSurface->WindowShadingControl(ICtrl).ShadingType == WinShadingType::SwitchableGlazing) {
    3897        8360 :                 VTR = state.dataSurface->SurfWinVisTransRatio(IWin);
    3898        8360 :                 thisDaylightControl.DaylIllFacSky(iHour, 2, ISky, iRefPoint, loopwin) =
    3899        8360 :                     thisDaylightControl.DaylIllFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR;
    3900        8360 :                 thisDaylightControl.DaylSourceFacSky(iHour, 2, ISky, iRefPoint, loopwin) =
    3901        8360 :                     thisDaylightControl.DaylSourceFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR;
    3902        8360 :                 thisDaylightControl.DaylBackFacSky(iHour, 2, ISky, iRefPoint, loopwin) =
    3903        8360 :                     thisDaylightControl.DaylBackFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR;
    3904        8360 :                 if (ISky == 1) {
    3905        2090 :                     thisDaylightControl.DaylIllFacSun(iHour, 2, iRefPoint, loopwin) =
    3906        2090 :                         thisDaylightControl.DaylIllFacSun(iHour, 1, iRefPoint, loopwin) * VTR;
    3907        2090 :                     thisDaylightControl.DaylSourceFacSun(iHour, 2, iRefPoint, loopwin) =
    3908        2090 :                         thisDaylightControl.DaylSourceFacSun(iHour, 1, iRefPoint, loopwin) * VTR;
    3909        2090 :                     thisDaylightControl.DaylBackFacSun(iHour, 2, iRefPoint, loopwin) =
    3910        2090 :                         thisDaylightControl.DaylBackFacSun(iHour, 1, iRefPoint, loopwin) * VTR;
    3911        2090 :                     thisDaylightControl.DaylIllFacSunDisk(iHour, 2, iRefPoint, loopwin) =
    3912        2090 :                         thisDaylightControl.DaylIllFacSunDisk(iHour, 1, iRefPoint, loopwin) * VTR;
    3913        2090 :                     thisDaylightControl.DaylSourceFacSunDisk(iHour, 2, iRefPoint, loopwin) =
    3914        2090 :                         thisDaylightControl.DaylSourceFacSunDisk(iHour, 1, iRefPoint, loopwin) * VTR;
    3915        2090 :                     thisDaylightControl.DaylBackFacSunDisk(iHour, 2, iRefPoint, loopwin) =
    3916        2090 :                         thisDaylightControl.DaylBackFacSunDisk(iHour, 1, iRefPoint, loopwin) * VTR;
    3917             :                 }
    3918             :             }
    3919             :         } // ICtrl > 0
    3920             : 
    3921             :     } // End of sky type loop, ISky
    3922             : }
    3923             : 
    3924      321600 : void FigureMapPointDayltgFactorsToAddIllums(EnergyPlusData &state,
    3925             :                                             int const MapNum,
    3926             :                                             int const iMapPoint,
    3927             :                                             int const iHour,
    3928             :                                             int const IWin,
    3929             :                                             int const loopwin,
    3930             :                                             int const ICtrl // Window control counter
    3931             : )
    3932             : {
    3933             : 
    3934             :     // SUBROUTINE INFORMATION:
    3935             :     //       AUTHOR         B. Griffith, Oct 2012, derived from legacy code by Fred Winkelmann, Peter Ellis, Linda Lawrie
    3936             :     //       DATE WRITTEN   Nov. 2012
    3937             : 
    3938             :     // PURPOSE OF THIS SUBROUTINE:
    3939             :     // calculation worker routine to fill daylighting coefficients
    3940             : 
    3941             :     // METHODOLOGY EMPLOYED:
    3942             :     // this version is just for map points.
    3943             : 
    3944             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3945      321600 :     Real64 constexpr tmpDFCalc(0.05); // cut off illuminance (lux) for exterior horizontal in calculating
    3946             :     // the daylighting and glare factors
    3947             : 
    3948             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3949             :     int ISky;   // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
    3950             :     int JSH;    // Shading index: J=1 is unshaded window, J=2 is shaded window
    3951             :     Real64 VTR; // For switchable glazing, ratio of visible transmittance of
    3952             :     //  fully-switched state to that of the unswitched state
    3953             : 
    3954      321600 :     if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return;
    3955             : 
    3956      804000 :     for (ISky = 1; ISky <= 4; ++ISky) { // Loop over sky types
    3957             : 
    3958             :         // Loop over shading index (1=bare window; 2=diffusing glazing, shade, screen or fixed slat-angle blind;
    3959             :         // 2 to MaxSlatAngs+1 for variable slat-angle blind)
    3960             : 
    3961             :         // TH. 9/22/2009. CR 7625 - daylight illuminance spikes during some sunset hours due to the calculated sky and sun
    3962             :         //  related daylight factors > 1, which theoretically can occur when sun is perpendicular to the window
    3963             :         //  and interior surfaces with high visible reflectance.
    3964             :         // Added tmpDFCalc (default to 0.05 lux) as the cap for GILSK and GILSU in calculating the daylight factors
    3965             :         //  the assumption behind it is if exterior horizontal surface does not get daylight, spaces do not get daylight.
    3966             : 
    3967     1929600 :         for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
    3968     1929600 :             if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
    3969             : 
    3970     1286400 :             if (state.dataDaylightingManager->GILSK(iHour, ISky) > tmpDFCalc) {
    3971     1286400 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, JSH, ISky, iMapPoint, loopwin) =
    3972     2572800 :                     (state.dataDaylightingManager->EDIRSK(iHour, JSH, ISky) + state.dataDaylightingManager->EINTSK(iHour, JSH, ISky)) /
    3973     1286400 :                     state.dataDaylightingManager->GILSK(iHour, ISky);
    3974             :             } else {
    3975           0 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, JSH, ISky, iMapPoint, loopwin) = 0.0;
    3976             :             }
    3977             : 
    3978     1286400 :             if (ISky == 1) {
    3979      321600 :                 if (state.dataDaylightingManager->GILSU(iHour) > tmpDFCalc) {
    3980      308200 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, JSH, iMapPoint, loopwin) =
    3981      616400 :                         (state.dataDaylightingManager->EDIRSU(iHour, JSH) + state.dataDaylightingManager->EINTSU(iHour, JSH)) /
    3982      308200 :                         (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
    3983      308200 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, JSH, iMapPoint, loopwin) =
    3984      616400 :                         (state.dataDaylightingManager->EDIRSUdisk(iHour, JSH) + state.dataDaylightingManager->EINTSUdisk(iHour, JSH)) /
    3985      308200 :                         (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
    3986             : 
    3987             :                 } else {
    3988       13400 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, JSH, iMapPoint, loopwin) = 0.0;
    3989       13400 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, JSH, iMapPoint, loopwin) = 0.0;
    3990             :                 }
    3991             :             }
    3992             :         } // End of shading index loop, JSH
    3993             : 
    3994             :         // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location
    3995      643200 :         if (ICtrl > 0) {
    3996      585600 :             if (state.dataSurface->WindowShadingControl(ICtrl).ShadingType == WinShadingType::SwitchableGlazing) {
    3997      585600 :                 VTR = state.dataSurface->SurfWinVisTransRatio(IWin);
    3998      585600 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 2, ISky, iMapPoint, loopwin) =
    3999      585600 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 1, ISky, iMapPoint, loopwin) * VTR;
    4000      585600 :                 if (ISky == 1) {
    4001      146400 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, 2, iMapPoint, loopwin) =
    4002      146400 :                         state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, 1, iMapPoint, loopwin) * VTR;
    4003      146400 :                     state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, 2, iMapPoint, loopwin) =
    4004      146400 :                         state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, 1, iMapPoint, loopwin) * VTR;
    4005             :                 }
    4006             :             }
    4007             :         } // ICtrl > 0
    4008             : 
    4009             :     } // End of sky type loop, ISky
    4010             : }
    4011             : 
    4012         771 : void GetDaylightingParametersInput(EnergyPlusData &state)
    4013             : {
    4014             : 
    4015             :     // SUBROUTINE INFORMATION:
    4016             :     //       AUTHOR         Linda Lawrie
    4017             :     //       DATE WRITTEN   Oct 2004
    4018             : 
    4019             :     // PURPOSE OF THIS SUBROUTINE:
    4020             :     // This subroutine provides a simple structure to get all daylighting
    4021             :     // parameters.
    4022             : 
    4023             :     using namespace DElightManagerF; // Module for managing DElight subroutines
    4024             : 
    4025             :     int TotDaylightingControls; // Total Daylighting:Controls inputs (splitflux or delight type)
    4026             :     bool ErrorsFound;           // Error flag
    4027             :     Real64 dLatitude;           // double for argument passing
    4028             :     int iErrorFlag;             // Error Flag for warning/errors returned from DElight
    4029        1542 :     std::string cErrorMsg;      // Each DElight Error Message can be up to 200 characters long
    4030             :     bool bEndofErrFile;         // End of Error File flag
    4031             :     bool bRecordsOnErrFile;     // true if there are records on the error file
    4032             :     int NumReports;
    4033             :     int NumNames;
    4034             :     int NumNumbers;
    4035             :     int IOStat;
    4036             : 
    4037         771 :     if (!state.dataDaylightingManager->getDaylightingParametersInputFlag) return;
    4038         771 :     state.dataDaylightingManager->getDaylightingParametersInputFlag = false;
    4039             : 
    4040         771 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    4041         771 :     ErrorsFound = false;
    4042         771 :     cCurrentModuleObject = "Daylighting:Controls";
    4043         771 :     TotDaylightingControls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    4044         771 :     if (TotDaylightingControls > 0) {
    4045          62 :         state.dataDaylightingData->enclDaylight.allocate(state.dataViewFactor->NumOfSolarEnclosures);
    4046          62 :         GetInputDayliteRefPt(state, ErrorsFound);
    4047          62 :         GetDaylightingControls(state, ErrorsFound);
    4048          62 :         GeometryTransformForDaylighting(state);
    4049          62 :         GetInputIlluminanceMap(state, ErrorsFound);
    4050          62 :         GetLightWellData(state, ErrorsFound);
    4051          62 :         if (ErrorsFound) ShowFatalError(state, "Program terminated for above reasons, related to DAYLIGHTING");
    4052          62 :         DayltgSetupAdjZoneListsAndPointers(state);
    4053             :     }
    4054             : 
    4055         771 :     state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl = 0;
    4056         771 :     state.dataDaylightingManager->maxNumRefPtInAnyEncl = 0;
    4057             :     // Loop through all daylighting controls to find total reference points in each enclosure
    4058        1058 :     for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
    4059         287 :         int numRefPoints = state.dataDaylightingData->daylightControl(daylightCtrlNum).TotalDaylRefPoints;
    4060         287 :         state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl = max(numRefPoints, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    4061             :     }
    4062        5582 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
    4063        4811 :         state.dataDaylightingManager->maxNumRefPtInAnyEncl =
    4064        4811 :             max(state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints, state.dataDaylightingManager->maxNumRefPtInAnyEncl);
    4065             :     }
    4066             : 
    4067        6745 :     for (int SurfNum : state.dataSurface->AllHTWindowSurfaceList) {
    4068        5974 :         int const surfEnclNum = state.dataSurface->Surface(SurfNum).SolarEnclIndex;
    4069        5974 :         int const numEnclRefPoints = state.dataViewFactor->EnclSolInfo(surfEnclNum).TotalEnclosureDaylRefPoints;
    4070        5974 :         if (numEnclRefPoints > 0) {
    4071         842 :             if (!state.dataSurface->SurfWinSurfDayLightInit(SurfNum)) {
    4072         842 :                 state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt.allocate(numEnclRefPoints);
    4073         842 :                 state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt = 0.0;
    4074         842 :                 state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd.allocate(numEnclRefPoints);
    4075         842 :                 state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd = 0.0;
    4076         842 :                 state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt.allocate(2, numEnclRefPoints);
    4077         842 :                 state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt = 0.0;
    4078         842 :                 state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt.allocate(2, numEnclRefPoints);
    4079         842 :                 state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt = 0.0;
    4080         842 :                 state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt.allocate(2, numEnclRefPoints);
    4081         842 :                 state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt = 0.0;
    4082         842 :                 state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep.allocate(numEnclRefPoints);
    4083         842 :                 state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep = 0.0;
    4084         842 :                 state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep.allocate(numEnclRefPoints);
    4085         842 :                 state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep = 0.0;
    4086         842 :                 state.dataSurface->SurfWinSurfDayLightInit(SurfNum) = true;
    4087             :             }
    4088             :         } else {
    4089        5132 :             int SurfNumAdj = state.dataSurface->Surface(SurfNum).ExtBoundCond;
    4090        5132 :             if (SurfNumAdj > 0) {
    4091          13 :                 int const adjSurfEnclNum = state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex;
    4092          13 :                 int const numAdjEnclRefPoints = state.dataViewFactor->EnclSolInfo(adjSurfEnclNum).TotalEnclosureDaylRefPoints;
    4093          13 :                 if (numAdjEnclRefPoints > 0) {
    4094           1 :                     if (!state.dataSurface->SurfWinSurfDayLightInit(SurfNum)) {
    4095           1 :                         state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt.allocate(numAdjEnclRefPoints);
    4096           1 :                         state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt = 0.0;
    4097           1 :                         state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd.allocate(numAdjEnclRefPoints);
    4098           1 :                         state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd = 0.0;
    4099           1 :                         state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt.allocate(2, numAdjEnclRefPoints);
    4100           1 :                         state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt = 0.0;
    4101           1 :                         state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt.allocate(2, numAdjEnclRefPoints);
    4102           1 :                         state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt = 0.0;
    4103           1 :                         state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt.allocate(2, numAdjEnclRefPoints);
    4104           1 :                         state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt = 0.0;
    4105           1 :                         state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep.allocate(numAdjEnclRefPoints);
    4106           1 :                         state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep = 0.0;
    4107           1 :                         state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep.allocate(numAdjEnclRefPoints);
    4108           1 :                         state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep = 0.0;
    4109           1 :                         state.dataSurface->SurfWinSurfDayLightInit(SurfNum) = true;
    4110             :                     }
    4111             :                 }
    4112             :             }
    4113             :         }
    4114             : 
    4115        5974 :         if (state.dataSurface->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
    4116             : 
    4117        5960 :             if (state.dataSurface->Surface(SurfNum).HasShadeControl) {
    4118         143 :                 auto &thisSurfEnclosure(state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNum).SolarEnclIndex));
    4119         143 :                 if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(SurfNum).activeWindowShadingControl).GlareControlIsActive) {
    4120             :                     // Error if GlareControlIsActive but window is not in a Daylighting:Detailed zone
    4121          30 :                     if (thisSurfEnclosure.TotalEnclosureDaylRefPoints == 0) {
    4122           0 :                         ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
    4123           0 :                         ShowContinueError(state, "GlareControlIsActive = Yes but it is not in a Daylighting zone or enclosure.");
    4124           0 :                         ShowContinueError(state,
    4125           0 :                                           "Zone or enclosure indicated=" +
    4126           0 :                                               state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNum).SolarEnclIndex).Name);
    4127           0 :                         ErrorsFound = true;
    4128             :                     }
    4129             :                     // Error if GlareControlIsActive and window is in a Daylighting:Detailed zone/enclosure with
    4130             :                     // an interior window adjacent to another Daylighting:Detailed zone/enclosure
    4131          30 :                     if (thisSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
    4132         357 :                         for (int const intWin : thisSurfEnclosure.SurfacePtr) {
    4133         327 :                             int const SurfNumAdj = state.dataSurface->Surface(intWin).ExtBoundCond;
    4134         327 :                             if (state.dataSurface->Surface(intWin).Class == SurfaceClass::Window && SurfNumAdj > 0) {
    4135           0 :                                 auto &adjSurfEnclosure(state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex));
    4136           0 :                                 if (adjSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
    4137           0 :                                     ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
    4138           0 :                                     ShowContinueError(state, "GlareControlIsActive = Yes and is in a Daylighting zone or enclosure");
    4139           0 :                                     ShowContinueError(state, "that shares an interior window with another Daylighting zone or enclosure");
    4140           0 :                                     ShowContinueError(state, "Adjacent Zone or Enclosure indicated=" + adjSurfEnclosure.Name);
    4141           0 :                                     ErrorsFound = true;
    4142             :                                 }
    4143             :                             }
    4144             :                         }
    4145             :                     }
    4146             :                 }
    4147             : 
    4148         143 :                 if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(SurfNum).activeWindowShadingControl).shadingControlType ==
    4149             :                     WindowShadingControlType::MeetDaylIlumSetp) {
    4150             :                     // Error if window has shadingControlType = MeetDaylightingIlluminanceSetpoint &
    4151             :                     // but is not in a Daylighting:Detailed zone
    4152           2 :                     if (thisSurfEnclosure.TotalEnclosureDaylRefPoints == 0) {
    4153           0 :                         ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
    4154           0 :                         ShowContinueError(state, "MeetDaylightingIlluminanceSetpoint but it is not in a Daylighting zone or enclosure.");
    4155           0 :                         ShowContinueError(state, "Zone or enclosure indicated=" + thisSurfEnclosure.Name);
    4156           0 :                         ErrorsFound = true;
    4157             :                     }
    4158             :                     // Error if window has shadingControlType = MeetDaylightIlluminanceSetpoint and is in a &
    4159             :                     // Daylighting:Detailed zone with an interior window adjacent to another Daylighting:Detailed zone
    4160           2 :                     if (thisSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
    4161          22 :                         for (int const intWin : thisSurfEnclosure.SurfacePtr) {
    4162          20 :                             int const SurfNumAdj = state.dataSurface->Surface(intWin).ExtBoundCond;
    4163          20 :                             if (state.dataSurface->Surface(intWin).Class == SurfaceClass::Window && SurfNumAdj > 0) {
    4164           0 :                                 auto &adjSurfEnclosure(state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex));
    4165           0 :                                 if (adjSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
    4166           0 :                                     ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
    4167           0 :                                     ShowContinueError(state, "MeetDaylightIlluminanceSetpoint and is in a Daylighting zone or enclosure");
    4168           0 :                                     ShowContinueError(state, "that shares an interior window with another Daylighting zone or enclosure");
    4169           0 :                                     ShowContinueError(state, "Adjacent Zone or enclosure indicated=" + adjSurfEnclosure.Name);
    4170           0 :                                     ErrorsFound = true;
    4171             :                                 }
    4172             :                             }
    4173             :                         }
    4174             :                     }
    4175             :                 }
    4176             :             }
    4177             :         }
    4178             :     }
    4179             : 
    4180         771 :     if (!state.dataHeatBal->AnyAirBoundary) {
    4181       44365 :         for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
    4182       43597 :             if (state.dataSurface->Surface(SurfLoop).Class == SurfaceClass::Window && state.dataSurface->Surface(SurfLoop).ExtSolar) {
    4183        5940 :                 int const enclOfSurf = state.dataSurface->Surface(SurfLoop).SolarEnclIndex;
    4184       12716 :                 if (state.dataViewFactor->EnclSolInfo(enclOfSurf).TotalEnclosureDaylRefPoints > 0 &&
    4185        6776 :                     !state.dataViewFactor->EnclSolInfo(enclOfSurf).HasInterZoneWindow &&
    4186         836 :                     state.dataDaylightingData->enclDaylight(enclOfSurf).hasSplitFluxDaylighting) {
    4187        2305 :                     for (int refPtNum = 1; refPtNum <= state.dataViewFactor->EnclSolInfo(enclOfSurf).TotalEnclosureDaylRefPoints; ++refPtNum) {
    4188        7360 :                         SetupOutputVariable(state,
    4189        2944 :                                             format("Daylighting Window Reference Point {} Illuminance", refPtNum),
    4190             :                                             OutputProcessor::Unit::lux,
    4191        2944 :                                             state.dataSurface->SurfaceWindow(SurfLoop).IllumFromWinAtRefPtRep(refPtNum),
    4192             :                                             OutputProcessor::SOVTimeStepType::Zone,
    4193             :                                             OutputProcessor::SOVStoreType::Average,
    4194        1472 :                                             state.dataSurface->Surface(SurfLoop).Name);
    4195        7360 :                         SetupOutputVariable(state,
    4196        2944 :                                             format("Daylighting Window Reference Point {} View Luminance", refPtNum),
    4197             :                                             OutputProcessor::Unit::cd_m2,
    4198        2944 :                                             state.dataSurface->SurfaceWindow(SurfLoop).LumWinFromRefPtRep(refPtNum),
    4199             :                                             OutputProcessor::SOVTimeStepType::Zone,
    4200             :                                             OutputProcessor::SOVStoreType::Average,
    4201        1472 :                                             state.dataSurface->Surface(SurfLoop).Name);
    4202             :                     }
    4203             :                 }
    4204             :             }
    4205             :         }
    4206             :     } else {
    4207          18 :         for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
    4208         154 :             for (int const enclSurfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
    4209         139 :                 if (state.dataSurface->Surface(enclSurfNum).Class == SurfaceClass::Window && state.dataSurface->Surface(enclSurfNum).ExtSolar) {
    4210          39 :                     if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0 &&
    4211          21 :                         !state.dataViewFactor->EnclSolInfo(enclNum).HasInterZoneWindow &&
    4212           3 :                         state.dataDaylightingData->enclDaylight(enclNum).hasSplitFluxDaylighting) {
    4213           3 :                         int refPtCount = 0;
    4214           9 :                         for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
    4215          12 :                             for (int refPtNum = 1; refPtNum <= state.dataDaylightingData->daylightControl(controlNum).TotalDaylRefPoints;
    4216             :                                  ++refPtNum) {
    4217           6 :                                 ++refPtCount; // Count reference points across each daylighting control in the same enclosure
    4218             :                                 std::string const varKey =
    4219          12 :                                     state.dataSurface->Surface(enclSurfNum).Name + " to " +
    4220             :                                     state.dataDaylightingData
    4221           6 :                                         ->DaylRefPt(state.dataDaylightingData->daylightControl(controlNum).DaylRefPtNum(refPtNum))
    4222          18 :                                         .Name;
    4223          12 :                                 SetupOutputVariable(state,
    4224             :                                                     "Daylighting Window Reference Point Illuminance",
    4225             :                                                     OutputProcessor::Unit::lux,
    4226           6 :                                                     state.dataSurface->SurfaceWindow(enclSurfNum).IllumFromWinAtRefPtRep(refPtCount),
    4227             :                                                     OutputProcessor::SOVTimeStepType::Zone,
    4228             :                                                     OutputProcessor::SOVStoreType::Average,
    4229           6 :                                                     varKey);
    4230          12 :                                 SetupOutputVariable(state,
    4231             :                                                     "Daylighting Window Reference Point View Luminance",
    4232             :                                                     OutputProcessor::Unit::cd_m2,
    4233           6 :                                                     state.dataSurface->SurfaceWindow(enclSurfNum).LumWinFromRefPtRep(refPtCount),
    4234             :                                                     OutputProcessor::SOVTimeStepType::Zone,
    4235             :                                                     OutputProcessor::SOVStoreType::Average,
    4236           6 :                                                     varKey);
    4237             :                             }
    4238             :                         }
    4239             :                     }
    4240             :                 }
    4241             :             }
    4242             :         }
    4243             :     }
    4244             : 
    4245             :     // RJH DElight Modification Begin - Calls to DElight preprocessing subroutines
    4246         771 :     if (doesDayLightingUseDElight(state)) {
    4247           3 :         dLatitude = state.dataEnvrn->Latitude;
    4248           3 :         DisplayString(state, "Calculating DElight Daylighting Factors");
    4249           3 :         DElightInputGenerator(state);
    4250             :         // Init Error Flag to 0 (no Warnings or Errors)
    4251           3 :         DisplayString(state, "ReturnFrom DElightInputGenerator");
    4252           3 :         iErrorFlag = 0;
    4253           3 :         DisplayString(state, "Calculating DElight DaylightCoefficients");
    4254           3 :         GenerateDElightDaylightCoefficients(dLatitude, iErrorFlag);
    4255             :         // Check Error Flag for Warnings or Errors returning from DElight
    4256             :         // RJH 2008-03-07: open file for READWRITE and DELETE file after processing
    4257           3 :         DisplayString(state, "ReturnFrom DElight DaylightCoefficients Calc");
    4258           3 :         if (iErrorFlag != 0) {
    4259             :             // Open DElight Daylight Factors Error File for reading
    4260           0 :             auto iDElightErrorFile = state.files.outputDelightDfdmpFilePath.try_open(state.files.outputControl.delightdfdmp);
    4261             : 
    4262             :             // Sequentially read lines in DElight Daylight Factors Error File
    4263             :             // and process them using standard EPlus warning/error handling calls
    4264             :             // Process all error/warning messages first
    4265             :             // Then, if any error has occurred, ShowFatalError to terminate processing
    4266           0 :             bEndofErrFile = !iDElightErrorFile.good();
    4267           0 :             bRecordsOnErrFile = false;
    4268           0 :             while (!bEndofErrFile) {
    4269           0 :                 auto cErrorLine = iDElightErrorFile.readLine();
    4270           0 :                 if (cErrorLine.eof) {
    4271           0 :                     bEndofErrFile = true;
    4272           0 :                     continue;
    4273             :                 }
    4274           0 :                 bRecordsOnErrFile = true;
    4275             :                 // Is the current line a Warning message?
    4276           0 :                 if (has_prefix(cErrorLine.data, "WARNING: ")) {
    4277           0 :                     cErrorMsg = cErrorLine.data.substr(9);
    4278           0 :                     ShowWarningError(state, cErrorMsg);
    4279             :                 }
    4280             :                 // Is the current line an Error message?
    4281           0 :                 if (has_prefix(cErrorLine.data, "ERROR: ")) {
    4282           0 :                     cErrorMsg = cErrorLine.data.substr(7);
    4283           0 :                     ShowSevereError(state, cErrorMsg);
    4284           0 :                     iErrorFlag = 1;
    4285             :                 }
    4286             :             }
    4287             : 
    4288             :             // Close and Delete DElight Error File
    4289           0 :             if (iDElightErrorFile.is_open()) {
    4290           0 :                 iDElightErrorFile.close();
    4291           0 :                 FileSystem::removeFile(iDElightErrorFile.filePath);
    4292             :             }
    4293             : 
    4294             :             // If any DElight Error occurred then ShowFatalError to terminate
    4295           0 :             if (iErrorFlag > 0) {
    4296           0 :                 ErrorsFound = true;
    4297             :             }
    4298             :         } else {
    4299           3 :             if (FileSystem::fileExists(state.files.outputDelightDfdmpFilePath.filePath)) {
    4300           3 :                 FileSystem::removeFile(state.files.outputDelightDfdmpFilePath.filePath);
    4301             :             }
    4302             :         }
    4303             :     }
    4304             :     // RJH DElight Modification End - Calls to DElight preprocessing subroutines
    4305             : 
    4306             :     // TH 6/3/2010, added to report daylight factors
    4307         771 :     cCurrentModuleObject = "Output:DaylightFactors";
    4308         771 :     NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    4309         771 :     if (NumReports > 0) {
    4310           7 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4311             :                                                                  cCurrentModuleObject,
    4312             :                                                                  1,
    4313           1 :                                                                  state.dataIPShortCut->cAlphaArgs,
    4314             :                                                                  NumNames,
    4315           1 :                                                                  state.dataIPShortCut->rNumericArgs,
    4316             :                                                                  NumNumbers,
    4317             :                                                                  IOStat,
    4318           1 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    4319           1 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    4320           1 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    4321           1 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    4322           1 :         if (has_prefix(state.dataIPShortCut->cAlphaArgs(1), "SIZINGDAYS")) {
    4323           1 :             state.dataDaylightingData->DFSReportSizingDays = true;
    4324           0 :         } else if (has_prefix(state.dataIPShortCut->cAlphaArgs(1), "ALLSHADOWCALCULATIONDAYS")) {
    4325           0 :             state.dataDaylightingData->DFSReportAllShadowCalculationDays = true;
    4326             :         }
    4327             :     }
    4328             : 
    4329         771 :     if (ErrorsFound) ShowFatalError(state, "Program terminated for above reasons");
    4330             : }
    4331             : 
    4332          62 : void GetInputIlluminanceMap(EnergyPlusData &state, bool &ErrorsFound)
    4333             : {
    4334             :     // Perform the GetInput function for the Output:IlluminanceMap
    4335             :     // Glazer - June 2016 (moved from GetDaylightingControls)
    4336             :     using DataStringGlobals::CharComma;
    4337             :     using DataStringGlobals::CharSpace;
    4338             :     using DataStringGlobals::CharTab;
    4339             : 
    4340             :     int MapNum;
    4341             :     int IOStat;
    4342             :     int NumAlpha;
    4343             :     int NumNumber;
    4344             :     int MapStyleIn;
    4345             :     int AddMapPoints;
    4346             :     int RefPt;
    4347             :     int X;
    4348             :     int Y;
    4349             :     Real64 CosBldgRelNorth;         // Cosine of Building rotation
    4350             :     Real64 SinBldgRelNorth;         // Sine of Building rotation
    4351             :     Real64 CosZoneRelNorth;         // Cosine of Zone rotation
    4352             :     Real64 SinZoneRelNorth;         // Sine of Zone rotation
    4353          62 :     Real64 CosBldgRotAppGonly(0.0); // Cosine of the building rotation for appendix G only ( relative north )
    4354          62 :     Real64 SinBldgRotAppGonly(0.0); // Sine of the building rotation for appendix G only ( relative north )
    4355             :     Real64 Xb;                      // temp var for transformation calc
    4356             :     Real64 Yb;                      // temp var for transformation calc
    4357             :     Real64 Xo;
    4358             :     Real64 XnoRot;
    4359             :     Real64 Xtrans;
    4360             :     Real64 Yo;
    4361             :     Real64 YnoRot;
    4362             :     Real64 Ytrans;
    4363             :     bool doTransform;
    4364             :     Real64 OldAspectRatio;
    4365             :     Real64 NewAspectRatio;
    4366         124 :     Array1D_bool ZoneMsgDone;
    4367             : 
    4368          62 :     auto &Zone(state.dataHeatBal->Zone);
    4369             : 
    4370          62 :     CosBldgRelNorth =
    4371          62 :         std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
    4372          62 :     SinBldgRelNorth =
    4373          62 :         std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
    4374             :     // these are only for Building Rotation for Appendix G when using world coordinate system
    4375          62 :     CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
    4376          62 :     SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
    4377             : 
    4378          62 :     doTransform = false;
    4379          62 :     OldAspectRatio = 1.0;
    4380          62 :     NewAspectRatio = 1.0;
    4381             : 
    4382          62 :     CheckForGeometricTransform(state, doTransform, OldAspectRatio, NewAspectRatio);
    4383          62 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    4384          62 :     cCurrentModuleObject = "Output:IlluminanceMap";
    4385          62 :     int TotIllumMaps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    4386             : 
    4387          62 :     state.dataDaylightingData->IllumMap.allocate(TotIllumMaps);
    4388          62 :     state.dataDaylightingData->IllumMapCalc.allocate(TotIllumMaps);
    4389             : 
    4390          62 :     if (TotIllumMaps > 0) {
    4391          12 :         for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
    4392          49 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4393             :                                                                      cCurrentModuleObject,
    4394             :                                                                      MapNum,
    4395           7 :                                                                      state.dataIPShortCut->cAlphaArgs,
    4396             :                                                                      NumAlpha,
    4397           7 :                                                                      state.dataIPShortCut->rNumericArgs,
    4398             :                                                                      NumNumber,
    4399             :                                                                      IOStat,
    4400           7 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    4401           7 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    4402           7 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    4403           7 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    4404           7 :             state.dataDaylightingData->IllumMap(MapNum).Name = state.dataIPShortCut->cAlphaArgs(1);
    4405           7 :             state.dataDaylightingData->IllumMap(MapNum).zoneIndex = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), Zone);
    4406             : 
    4407           7 :             if (state.dataDaylightingData->IllumMap(MapNum).zoneIndex == 0) {
    4408           0 :                 ShowSevereError(state,
    4409           0 :                                 cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid " +
    4410           0 :                                     state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\".");
    4411           0 :                 ErrorsFound = true;
    4412             :             } else {
    4413             :                 // set enclosure index for first space in zone
    4414           7 :                 int zoneNum = state.dataDaylightingData->IllumMap(MapNum).zoneIndex;
    4415           7 :                 int enclNum = state.dataHeatBal->space(state.dataHeatBal->Zone(zoneNum).spaceIndexes(1)).solarEnclosureNum;
    4416           7 :                 state.dataDaylightingData->IllumMap(MapNum).enclIndex = enclNum;
    4417             :                 // check that all spaces in the zone are in the same enclosure
    4418           7 :                 for (int spaceCounter = 2; spaceCounter <= state.dataHeatBal->Zone(zoneNum).numSpaces; ++spaceCounter) {
    4419           0 :                     int spaceNum = state.dataHeatBal->Zone(zoneNum).spaceIndexes(spaceCounter);
    4420           0 :                     if (enclNum != state.dataHeatBal->space(spaceNum).solarEnclosureNum) {
    4421           0 :                         ShowSevereError(state,
    4422           0 :                                         cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
    4423             :                                             "\" All spaces in the zone must be in the same enclosure for daylighting illuminance maps.");
    4424           0 :                         ErrorsFound = true;
    4425           0 :                         break;
    4426             :                     }
    4427             :                 }
    4428             :             }
    4429             : 
    4430           7 :             state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex = state.dataDaylightingData->IllumMap(MapNum).zoneIndex;
    4431           7 :             state.dataDaylightingData->IllumMapCalc(MapNum).enclIndex = state.dataDaylightingData->IllumMap(MapNum).enclIndex;
    4432           7 :             state.dataDaylightingData->IllumMap(MapNum).Z = state.dataIPShortCut->rNumericArgs(1);
    4433             : 
    4434           7 :             state.dataDaylightingData->IllumMap(MapNum).Xmin = state.dataIPShortCut->rNumericArgs(2);
    4435           7 :             state.dataDaylightingData->IllumMap(MapNum).Xmax = state.dataIPShortCut->rNumericArgs(3);
    4436           7 :             if (state.dataIPShortCut->rNumericArgs(2) > state.dataIPShortCut->rNumericArgs(3)) {
    4437           0 :                 ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid entry.");
    4438           0 :                 ShowContinueError(state,
    4439           0 :                                   format("...{} {:.2R} must be <= {} {:.2R}.",
    4440           0 :                                          state.dataIPShortCut->cNumericFieldNames(2),
    4441           0 :                                          state.dataIPShortCut->rNumericArgs(2),
    4442           0 :                                          state.dataIPShortCut->cNumericFieldNames(3),
    4443           0 :                                          state.dataIPShortCut->rNumericArgs(3)));
    4444           0 :                 ErrorsFound = true;
    4445             :             }
    4446           7 :             state.dataDaylightingData->IllumMap(MapNum).Xnum = state.dataIPShortCut->rNumericArgs(4);
    4447           7 :             if (state.dataDaylightingData->IllumMap(MapNum).Xnum != 1) {
    4448           7 :                 state.dataDaylightingData->IllumMap(MapNum).Xinc =
    4449          14 :                     (state.dataDaylightingData->IllumMap(MapNum).Xmax - state.dataDaylightingData->IllumMap(MapNum).Xmin) /
    4450           7 :                     (state.dataDaylightingData->IllumMap(MapNum).Xnum - 1);
    4451             :             } else {
    4452           0 :                 state.dataDaylightingData->IllumMap(MapNum).Xinc = 0.0;
    4453             :             }
    4454             : 
    4455           7 :             state.dataDaylightingData->IllumMap(MapNum).Ymin = state.dataIPShortCut->rNumericArgs(5);
    4456           7 :             state.dataDaylightingData->IllumMap(MapNum).Ymax = state.dataIPShortCut->rNumericArgs(6);
    4457           7 :             if (state.dataIPShortCut->rNumericArgs(5) > state.dataIPShortCut->rNumericArgs(6)) {
    4458           0 :                 ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid entry.");
    4459           0 :                 ShowContinueError(state,
    4460           0 :                                   format("...{} {:.2R} must be <= {} {:.2R}.",
    4461           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
    4462           0 :                                          state.dataIPShortCut->rNumericArgs(5),
    4463           0 :                                          state.dataIPShortCut->cNumericFieldNames(6),
    4464           0 :                                          state.dataIPShortCut->rNumericArgs(6)));
    4465           0 :                 ErrorsFound = true;
    4466             :             }
    4467           7 :             state.dataDaylightingData->IllumMap(MapNum).Ynum = state.dataIPShortCut->rNumericArgs(7);
    4468           7 :             if (state.dataDaylightingData->IllumMap(MapNum).Ynum != 1) {
    4469           7 :                 state.dataDaylightingData->IllumMap(MapNum).Yinc =
    4470          14 :                     (state.dataDaylightingData->IllumMap(MapNum).Ymax - state.dataDaylightingData->IllumMap(MapNum).Ymin) /
    4471           7 :                     (state.dataDaylightingData->IllumMap(MapNum).Ynum - 1);
    4472             :             } else {
    4473           0 :                 state.dataDaylightingData->IllumMap(MapNum).Yinc = 0.0;
    4474             :             }
    4475           7 :             if (state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum >
    4476             :                 DataDaylighting::MaxMapRefPoints) {
    4477           0 :                 ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", too many map points specified.");
    4478           0 :                 ShowContinueError(state,
    4479           0 :                                   format("...{}[{}] * {}[{}].= [{}] must be <= [{}].",
    4480           0 :                                          state.dataIPShortCut->cNumericFieldNames(4),
    4481           0 :                                          state.dataDaylightingData->IllumMap(MapNum).Xnum,
    4482           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
    4483           0 :                                          state.dataDaylightingData->IllumMap(MapNum).Ynum,
    4484           0 :                                          state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum,
    4485           0 :                                          DataDaylighting::MaxMapRefPoints));
    4486           0 :                 ErrorsFound = true;
    4487             :             }
    4488             :         } // MapNum
    4489           5 :         cCurrentModuleObject = "OutputControl:IlluminanceMap:Style";
    4490           5 :         MapStyleIn = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    4491             : 
    4492           5 :         if (MapStyleIn == 0) {
    4493           4 :             state.dataIPShortCut->cAlphaArgs(1) = "COMMA";
    4494           4 :             state.dataDaylightingData->MapColSep = CharComma; // comma
    4495           1 :         } else if (MapStyleIn == 1) {
    4496           7 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4497             :                                                                      cCurrentModuleObject,
    4498             :                                                                      1,
    4499           1 :                                                                      state.dataIPShortCut->cAlphaArgs,
    4500             :                                                                      NumAlpha,
    4501           1 :                                                                      state.dataIPShortCut->rNumericArgs,
    4502             :                                                                      NumNumber,
    4503             :                                                                      IOStat,
    4504           1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    4505           1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    4506           1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    4507           1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    4508           1 :             if (state.dataIPShortCut->cAlphaArgs(1) == "COMMA") {
    4509           1 :                 state.dataDaylightingData->MapColSep = CharComma; // comma
    4510           0 :             } else if (state.dataIPShortCut->cAlphaArgs(1) == "TAB") {
    4511           0 :                 state.dataDaylightingData->MapColSep = CharTab; // tab
    4512           0 :             } else if (state.dataIPShortCut->cAlphaArgs(1) == "FIXED" || state.dataIPShortCut->cAlphaArgs(1) == "SPACE") {
    4513           0 :                 state.dataDaylightingData->MapColSep = CharSpace; // space
    4514             :             } else {
    4515           0 :                 state.dataDaylightingData->MapColSep = CharComma; // comma
    4516           0 :                 ShowWarningError(state,
    4517           0 :                                  cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
    4518           0 :                                      state.dataIPShortCut->cAlphaArgs(1) + "\", Commas will be used to separate fields.");
    4519           0 :                 state.dataIPShortCut->cAlphaArgs(1) = "COMMA";
    4520             :             }
    4521             :         }
    4522           5 :         print(state.files.eio, "! <Daylighting:Illuminance Maps>,#Maps,Style\n");
    4523           5 :         ConvertCaseToLower(state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cAlphaArgs(2));
    4524           5 :         state.dataIPShortCut->cAlphaArgs(1).erase(1);
    4525           5 :         state.dataIPShortCut->cAlphaArgs(1) += state.dataIPShortCut->cAlphaArgs(2).substr(1);
    4526           5 :         print(state.files.eio, "Daylighting:Illuminance Maps,{},{}\n", TotIllumMaps, state.dataIPShortCut->cAlphaArgs(1));
    4527             :     }
    4528             : 
    4529             :     // Check for illuminance maps associated with this zone
    4530          69 :     for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
    4531           7 :         if (state.dataDaylightingData->IllumMap(MapNum).zoneIndex > 0) {
    4532           7 :             auto &zone(Zone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex));
    4533             :             // Calc cos and sin of Zone Relative North values for later use in transforming Reference Point coordinates
    4534           7 :             CosZoneRelNorth = std::cos(-zone.RelNorth * DataGlobalConstants::DegToRadians);
    4535           7 :             SinZoneRelNorth = std::sin(-zone.RelNorth * DataGlobalConstants::DegToRadians);
    4536           7 :             if (state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum > 0) {
    4537             :                 // Add additional daylighting reference points for map
    4538           7 :                 AddMapPoints = state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum;
    4539           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints = AddMapPoints;
    4540           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord.allocate(3, AddMapPoints);
    4541           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord = 0.0;
    4542           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds.allocate(AddMapPoints);
    4543           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds = true;
    4544           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPt.allocate(AddMapPoints);
    4545           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPt = 0.0;
    4546           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr.allocate(AddMapPoints);
    4547           7 :                 state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr = 0.0;
    4548             : 
    4549           7 :                 if (AddMapPoints > DataDaylighting::MaxMapRefPoints) {
    4550           0 :                     ShowSevereError(state, "GetDaylighting Parameters: Total Map Reference points entered is greater than maximum allowed.");
    4551           0 :                     ShowContinueError(state, "Occurs in Zone=" + zone.Name);
    4552           0 :                     ShowContinueError(state,
    4553           0 :                                       format("Maximum reference points allowed={}, entered amount ( when error first occurred )={}",
    4554             :                                              DataDaylighting::MaxMapRefPoints,
    4555           0 :                                              AddMapPoints));
    4556           0 :                     ErrorsFound = true;
    4557           0 :                     break;
    4558             :                 }
    4559           7 :                 RefPt = 1;
    4560             :                 // Calc cos and sin of Zone Relative North values for later use in transforming Map Point coordinates
    4561             :                 // CosZoneRelNorth = std::cos( -zone.RelNorth * DegToRadians ); //Tuned These should not be changing
    4562             :                 // SinZoneRelNorth = std::sin( -zone.RelNorth * DegToRadians );
    4563           7 :                 if (state.dataDaylightingData->IllumMap(MapNum).Xnum != 1) {
    4564           7 :                     state.dataDaylightingData->IllumMap(MapNum).Xinc =
    4565          14 :                         (state.dataDaylightingData->IllumMap(MapNum).Xmax - state.dataDaylightingData->IllumMap(MapNum).Xmin) /
    4566           7 :                         (state.dataDaylightingData->IllumMap(MapNum).Xnum - 1);
    4567             :                 } else {
    4568           0 :                     state.dataDaylightingData->IllumMap(MapNum).Xinc = 0.0;
    4569             :                 }
    4570           7 :                 if (state.dataDaylightingData->IllumMap(MapNum).Ynum != 1) {
    4571           7 :                     state.dataDaylightingData->IllumMap(MapNum).Yinc =
    4572          14 :                         (state.dataDaylightingData->IllumMap(MapNum).Ymax - state.dataDaylightingData->IllumMap(MapNum).Ymin) /
    4573           7 :                         (state.dataDaylightingData->IllumMap(MapNum).Ynum - 1);
    4574             :                 } else {
    4575           0 :                     state.dataDaylightingData->IllumMap(MapNum).Yinc = 0.0;
    4576             :                 }
    4577             : 
    4578             :                 // Map points and increments are stored in AbsCoord and then that is operated on if relative coords entered.
    4579          77 :                 for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
    4580         620 :                     for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
    4581         550 :                         state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) =
    4582         550 :                             state.dataDaylightingData->IllumMap(MapNum).Xmin + (X - 1) * state.dataDaylightingData->IllumMap(MapNum).Xinc;
    4583         550 :                         state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) =
    4584         550 :                             state.dataDaylightingData->IllumMap(MapNum).Ymin + (Y - 1) * state.dataDaylightingData->IllumMap(MapNum).Yinc;
    4585         550 :                         state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) = state.dataDaylightingData->IllumMap(MapNum).Z;
    4586         550 :                         ++RefPt;
    4587             :                     }
    4588             :                 }
    4589           7 :                 RefPt = 1;
    4590          77 :                 for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
    4591         620 :                     for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
    4592         550 :                         if (!state.dataSurface->DaylRefWorldCoordSystem) {
    4593        1050 :                             Xb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) * CosZoneRelNorth -
    4594         700 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) * SinZoneRelNorth + zone.OriginX;
    4595        1050 :                             Yb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) * SinZoneRelNorth +
    4596         700 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) * CosZoneRelNorth + zone.OriginY;
    4597         350 :                             state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) = Xb * CosBldgRelNorth - Yb * SinBldgRelNorth;
    4598         350 :                             state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) = Xb * SinBldgRelNorth + Yb * CosBldgRelNorth;
    4599         350 :                             state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) += zone.OriginZ;
    4600         350 :                             if (doTransform) {
    4601           0 :                                 Xo = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(
    4602           0 :                                     1, RefPt); // world coordinates.... shifted by relative north angle...
    4603           0 :                                 Yo = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
    4604             :                                 // next derotate the building
    4605           0 :                                 XnoRot = Xo * CosBldgRelNorth + Yo * SinBldgRelNorth;
    4606           0 :                                 YnoRot = Yo * CosBldgRelNorth - Xo * SinBldgRelNorth;
    4607             :                                 // translate
    4608           0 :                                 Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
    4609           0 :                                 Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
    4610             :                                 // rerotate
    4611           0 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) =
    4612           0 :                                     Xtrans * CosBldgRelNorth - Ytrans * SinBldgRelNorth;
    4613             : 
    4614           0 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) =
    4615           0 :                                     Xtrans * SinBldgRelNorth + Ytrans * CosBldgRelNorth;
    4616             :                             }
    4617             :                         } else {
    4618         200 :                             Xb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt);
    4619         200 :                             Yb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
    4620         200 :                             state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) =
    4621         200 :                                 Xb * CosBldgRotAppGonly - Yb * SinBldgRotAppGonly;
    4622         200 :                             state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) =
    4623         200 :                                 Xb * SinBldgRotAppGonly + Yb * CosBldgRotAppGonly;
    4624             :                         }
    4625         550 :                         if (RefPt == 1) {
    4626           7 :                             state.dataDaylightingData->IllumMap(MapNum).Xmin =
    4627           7 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt);
    4628           7 :                             state.dataDaylightingData->IllumMap(MapNum).Ymin =
    4629           7 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
    4630           7 :                             state.dataDaylightingData->IllumMap(MapNum).Xmax =
    4631           7 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt);
    4632           7 :                             state.dataDaylightingData->IllumMap(MapNum).Ymax =
    4633           7 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
    4634           7 :                             state.dataDaylightingData->IllumMap(MapNum).Z =
    4635           7 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt);
    4636             :                         }
    4637         550 :                         state.dataDaylightingData->IllumMap(MapNum).Xmin =
    4638         550 :                             min(state.dataDaylightingData->IllumMap(MapNum).Xmin,
    4639         550 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt));
    4640         550 :                         state.dataDaylightingData->IllumMap(MapNum).Ymin =
    4641         550 :                             min(state.dataDaylightingData->IllumMap(MapNum).Ymin,
    4642         550 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
    4643         550 :                         state.dataDaylightingData->IllumMap(MapNum).Xmax =
    4644         550 :                             max(state.dataDaylightingData->IllumMap(MapNum).Xmax,
    4645         550 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt));
    4646         550 :                         state.dataDaylightingData->IllumMap(MapNum).Ymax =
    4647         550 :                             max(state.dataDaylightingData->IllumMap(MapNum).Ymax,
    4648         550 :                                 state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
    4649        1100 :                         if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) < zone.MinimumX &&
    4650         550 :                              (zone.MinimumX - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt)) > 0.001) ||
    4651         550 :                             (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) > zone.MaximumX &&
    4652         550 :                              (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) - zone.MaximumX) > 0.001) ||
    4653         550 :                             (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) < zone.MinimumY &&
    4654         550 :                              (zone.MinimumY - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt)) > 0.001) ||
    4655         550 :                             (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) > zone.MaximumY &&
    4656         550 :                              (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) - zone.MaximumY) > 0.001) ||
    4657         550 :                             (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) < zone.MinimumZ &&
    4658        1100 :                              (zone.MinimumZ - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt)) > 0.001) ||
    4659         550 :                             (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) > zone.MaximumZ &&
    4660           0 :                              (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) - zone.MaximumZ) > 0.001)) {
    4661           0 :                             state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt) = false;
    4662             :                         }
    4663             :                         // Test extremes of Map Points against Zone Min/Max
    4664         550 :                         if (RefPt == 1 || RefPt == state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints) {
    4665          42 :                             if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) < zone.MinimumX ||
    4666          14 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) > zone.MaximumX) &&
    4667           0 :                                 !state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt)) {
    4668           0 :                                 ShowWarningError(state,
    4669           0 :                                                  format("GetInputIlluminanceMap: Reference Map point #[{}], X Value outside Zone Min/Max X, Zone={}",
    4670             :                                                         RefPt,
    4671           0 :                                                         zone.Name));
    4672           0 :                                 ShowContinueError(state,
    4673           0 :                                                   format("...X Reference Point= {:.2R}, Zone Minimum X= {:.2R}, Zone Maximum X= {:.2R}",
    4674           0 :                                                          state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt),
    4675             :                                                          zone.MinimumX,
    4676           0 :                                                          zone.MaximumX));
    4677           0 :                                 if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) < zone.MinimumX) {
    4678           0 :                                     ShowContinueError(
    4679             :                                         state,
    4680           0 :                                         format("...X Reference Distance Outside MinimumX= {:.4R} m.",
    4681           0 :                                                zone.MinimumX - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt)));
    4682             :                                 } else {
    4683           0 :                                     ShowContinueError(
    4684             :                                         state,
    4685           0 :                                         format("...X Reference Distance Outside MaximumX= {:.4R} m.",
    4686           0 :                                                state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) - zone.MaximumX));
    4687             :                                 }
    4688             :                             }
    4689          42 :                             if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) < zone.MinimumY ||
    4690          14 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) > zone.MaximumY) &&
    4691           0 :                                 !state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt)) {
    4692           0 :                                 ShowWarningError(state,
    4693           0 :                                                  format("GetInputIlluminanceMap: Reference Map point #[{}], Y Value outside Zone Min/Max Y, Zone={}",
    4694             :                                                         RefPt,
    4695           0 :                                                         zone.Name));
    4696           0 :                                 ShowContinueError(state,
    4697           0 :                                                   format("...Y Reference Point= {:.2R}, Zone Minimum Y= {:.2R}, Zone Maximum Y= {:.2R}",
    4698           0 :                                                          state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt),
    4699             :                                                          zone.MinimumY,
    4700           0 :                                                          zone.MaximumY));
    4701           0 :                                 if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) < zone.MinimumY) {
    4702           0 :                                     ShowContinueError(
    4703             :                                         state,
    4704           0 :                                         format("...Y Reference Distance Outside MinimumY= {:.4R} m.",
    4705           0 :                                                zone.MinimumY - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt)));
    4706             :                                 } else {
    4707           0 :                                     ShowContinueError(
    4708             :                                         state,
    4709           0 :                                         format("...Y Reference Distance Outside MaximumY= {:.4R} m.",
    4710           0 :                                                state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) - zone.MaximumY));
    4711             :                                 }
    4712             :                             }
    4713          42 :                             if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) < zone.MinimumZ ||
    4714          14 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) > zone.MaximumZ) &&
    4715           0 :                                 !state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt)) {
    4716           0 :                                 ShowWarningError(state,
    4717           0 :                                                  format("GetInputIlluminanceMap: Reference Map point #[{}], Z Value outside Zone Min/Max Z, Zone={}",
    4718             :                                                         RefPt,
    4719           0 :                                                         zone.Name));
    4720           0 :                                 ShowContinueError(state,
    4721           0 :                                                   format("...Z Reference Point= {:.2R}, Zone Minimum Z= {:.2R}, Zone Maximum Z= {:.2R}",
    4722           0 :                                                          state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt),
    4723             :                                                          zone.MinimumZ,
    4724           0 :                                                          zone.MaximumZ));
    4725           0 :                                 if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) < zone.MinimumZ) {
    4726           0 :                                     ShowContinueError(
    4727             :                                         state,
    4728           0 :                                         format("...Z Reference Distance Outside MinimumZ= {:.4R} m.",
    4729           0 :                                                zone.MinimumZ - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt)));
    4730             :                                 } else {
    4731           0 :                                     ShowContinueError(
    4732             :                                         state,
    4733           0 :                                         format("...Z Reference Distance Outside MaximumZ= {:.4R} m.",
    4734           0 :                                                state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) - zone.MaximumZ));
    4735             :                                 }
    4736             :                             }
    4737             :                         }
    4738         550 :                         ++RefPt;
    4739             :                     } // X
    4740             :                 }     // Y
    4741             :             }
    4742             :         }
    4743             :     } // MapNum
    4744          62 :     ZoneMsgDone.dimension(state.dataGlobal->NumOfZones, false);
    4745          69 :     for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
    4746           7 :         if (state.dataDaylightingData->IllumMap(MapNum).zoneIndex == 0) continue;
    4747           7 :         int enclNum = state.dataDaylightingData->IllumMap(MapNum).enclIndex;
    4748           7 :         if (!state.dataDaylightingData->enclDaylight(enclNum).hasSplitFluxDaylighting &&
    4749           0 :             !ZoneMsgDone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex)) {
    4750           0 :             ShowSevereError(state,
    4751           0 :                             "Zone Name in Output:IlluminanceMap is not used for Daylighting:Controls=" +
    4752           0 :                                 Zone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex).Name);
    4753           0 :             ErrorsFound = true;
    4754             :         }
    4755             :     }
    4756          62 :     ZoneMsgDone.deallocate();
    4757             : 
    4758          62 :     if (TotIllumMaps > 0) {
    4759           5 :         print(state.files.eio,
    4760             :               "! <Daylighting:Illuminance Maps:Detail>,Name,Zone,XMin {{m}},XMax {{m}},Xinc {{m}},#X Points,YMin "
    4761           5 :               "{{m}},YMax {{m}},Yinc {{m}},#Y Points,Z {{m}}\n");
    4762             :     }
    4763          69 :     for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
    4764          84 :         print(state.files.eio,
    4765             :               "Daylighting:Illuminance Maps:Detail,{},{},{:.2R},{:.2R},{:.2R},{},{:.2R},{:.2R},{:.2R},{},{:.2R}\n",
    4766           7 :               state.dataDaylightingData->IllumMap(MapNum).Name,
    4767           7 :               Zone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex).Name,
    4768           7 :               state.dataDaylightingData->IllumMap(MapNum).Xmin,
    4769           7 :               state.dataDaylightingData->IllumMap(MapNum).Xmax,
    4770           7 :               state.dataDaylightingData->IllumMap(MapNum).Xinc,
    4771           7 :               state.dataDaylightingData->IllumMap(MapNum).Xnum,
    4772           7 :               state.dataDaylightingData->IllumMap(MapNum).Ymin,
    4773           7 :               state.dataDaylightingData->IllumMap(MapNum).Ymax,
    4774           7 :               state.dataDaylightingData->IllumMap(MapNum).Yinc,
    4775           7 :               state.dataDaylightingData->IllumMap(MapNum).Ynum,
    4776          14 :               state.dataDaylightingData->IllumMap(MapNum).Z);
    4777             :     }
    4778             : 
    4779          62 :     if (ErrorsFound) return;
    4780             : }
    4781             : 
    4782          62 : void GetDaylightingControls(EnergyPlusData &state, bool &ErrorsFound)
    4783             : {
    4784             :     //       AUTHOR         Fred Winkelmann
    4785             :     //       DATE WRITTEN   March 2002
    4786             :     //       MODIFIED       Glazer - July 2016 - Move geometry transformation portion, rearrange input, allow more than three reference points
    4787             :     // Obtain the user input data for Daylighting:Controls object in the input file.
    4788             : 
    4789             :     int IOStat;
    4790             :     int NumAlpha;
    4791             :     int NumNumber;
    4792             : 
    4793             :     // Smallest deviation from unity for the sum of all fractions
    4794             :     // Accept approx 4 to 8 ULP error (technically abs(1.0 + sumFracs) should be close to 2)
    4795             :     //   constexpr Real64 FractionTolerance(4 * std::numeric_limits<Real64>::epsilon());
    4796             :     // Instead, we use a 0.001 = 0.1% tolerance
    4797          62 :     constexpr Real64 FractionTolerance(0.001);
    4798          62 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    4799          62 :     cCurrentModuleObject = "Daylighting:Controls";
    4800          62 :     int totDaylightingControls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    4801          62 :     state.dataDaylightingData->daylightControl.allocate(totDaylightingControls);
    4802         124 :     Array1D<bool> spaceHasDaylightingControl;
    4803          62 :     spaceHasDaylightingControl.dimension(state.dataGlobal->numSpaces, false);
    4804             :     // Reset to zero in case this is called more than once in unit tests
    4805         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
    4806         708 :         state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints = 0;
    4807             :     }
    4808         349 :     for (int controlNum = 1; controlNum <= totDaylightingControls; ++controlNum) {
    4809         287 :         state.dataIPShortCut->cAlphaArgs = "";
    4810         287 :         state.dataIPShortCut->rNumericArgs = 0.0;
    4811        2009 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4812             :                                                                  cCurrentModuleObject,
    4813             :                                                                  controlNum,
    4814         287 :                                                                  state.dataIPShortCut->cAlphaArgs,
    4815             :                                                                  NumAlpha,
    4816         287 :                                                                  state.dataIPShortCut->rNumericArgs,
    4817             :                                                                  NumNumber,
    4818             :                                                                  IOStat,
    4819         287 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    4820         287 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    4821         287 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    4822         287 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    4823         287 :         auto &daylightControl(state.dataDaylightingData->daylightControl(controlNum));
    4824         287 :         daylightControl.Name = state.dataIPShortCut->cAlphaArgs(1);
    4825             : 
    4826             :         // Is it a space or zone name?
    4827         287 :         int const spaceNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->space);
    4828         287 :         if (spaceNum > 0) {
    4829         287 :             daylightControl.spaceIndex = spaceNum;
    4830         287 :             daylightControl.zoneIndex = state.dataHeatBal->space(spaceNum).zoneNum;
    4831         287 :             daylightControl.enclIndex = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
    4832             :             // Check if this is a duplicate
    4833         287 :             if (spaceHasDaylightingControl(spaceNum)) {
    4834           0 :                 ShowSevereError(state,
    4835           0 :                                 cCurrentModuleObject + "=\"" + daylightControl.Name + "\" Space=" + "=\"" + state.dataHeatBal->space(spaceNum).Name +
    4836           0 :                                     "\" already has a " + cCurrentModuleObject + " object assigned to it. Only one per Space is allowed.");
    4837           0 :                 ErrorsFound = true;
    4838           0 :                 continue;
    4839             :             }
    4840             :         } else {
    4841           0 :             int const zoneNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
    4842           0 :             if (zoneNum == 0) {
    4843           0 :                 ShowSevereError(state,
    4844           0 :                                 cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" +
    4845           0 :                                     state.dataIPShortCut->cAlphaArgs(2) + "\".");
    4846           0 :                 ErrorsFound = true;
    4847           0 :                 continue;
    4848             :             } else {
    4849           0 :                 daylightControl.zoneIndex = zoneNum;
    4850             : 
    4851             :                 // set enclosure index for first space in zone
    4852           0 :                 int enclNum = state.dataHeatBal->space(state.dataHeatBal->Zone(zoneNum).spaceIndexes(1)).solarEnclosureNum;
    4853           0 :                 daylightControl.enclIndex = enclNum;
    4854             :                 // check that all spaces in the zone are in the same enclosure
    4855           0 :                 for (int spaceCounter = 2; spaceCounter <= state.dataHeatBal->Zone(zoneNum).numSpaces; ++spaceCounter) {
    4856           0 :                     int zoneSpaceNum = state.dataHeatBal->Zone(zoneNum).spaceIndexes(spaceCounter);
    4857           0 :                     if (daylightControl.enclIndex != state.dataHeatBal->space(zoneSpaceNum).solarEnclosureNum) {
    4858           0 :                         ShowSevereError(state,
    4859           0 :                                         cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" +
    4860           0 :                                             state.dataIPShortCut->cAlphaArgs(2) +
    4861             :                                             "\" All spaces in the zone must be in the same enclosure for daylighting.");
    4862           0 :                         ErrorsFound = true;
    4863           0 :                         break;
    4864             :                     }
    4865             :                     // Check if this is a duplicate
    4866           0 :                     if (spaceHasDaylightingControl(zoneSpaceNum)) {
    4867           0 :                         ShowSevereError(state,
    4868           0 :                                         cCurrentModuleObject + "=\"" + daylightControl.Name + "\" Space=" + "=\"" +
    4869           0 :                                             state.dataHeatBal->space(zoneSpaceNum).Name + "\" already has a " + cCurrentModuleObject +
    4870             :                                             " object assigned to it. Only one per Space is allowed.");
    4871           0 :                         ErrorsFound = true;
    4872           0 :                         continue;
    4873             :                     }
    4874             :                 }
    4875             :             }
    4876             :         }
    4877             : 
    4878         287 :         state.dataDaylightingData->enclDaylight(daylightControl.enclIndex).daylightControlIndexes.emplace_back(controlNum);
    4879         287 :         daylightControl.ZoneName = state.dataHeatBal->Zone(daylightControl.zoneIndex).Name;
    4880             : 
    4881         287 :         if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(3), "SPLITFLUX")) { // Field: Daylighting Method
    4882         284 :             daylightControl.DaylightMethod = DataDaylighting::DaylightingMethod::SplitFlux;
    4883         284 :             state.dataDaylightingData->enclDaylight(daylightControl.enclIndex).hasSplitFluxDaylighting = true;
    4884           3 :         } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(3), "DELIGHT")) {
    4885           3 :             daylightControl.DaylightMethod = DataDaylighting::DaylightingMethod::DElight;
    4886           0 :         } else if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
    4887           0 :             daylightControl.DaylightMethod = DataDaylighting::DaylightingMethod::SplitFlux;
    4888           0 :             state.dataDaylightingData->enclDaylight(daylightControl.enclIndex).hasSplitFluxDaylighting = true;
    4889             :         } else {
    4890           0 :             ShowWarningError(state,
    4891           0 :                              "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + " = " + state.dataIPShortCut->cAlphaArgs(3) + ", occurs in " +
    4892           0 :                                  cCurrentModuleObject + "object for " + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1));
    4893           0 :             ShowContinueError(state, "SplitFlux assumed, and the simulation continues.");
    4894             :         }
    4895             : 
    4896         287 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) { // Field: Availability Schedule Name
    4897           5 :             daylightControl.AvailSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(4));
    4898           5 :             if (daylightControl.AvailSchedNum == 0) {
    4899           0 :                 ShowWarningError(state,
    4900           0 :                                  "Invalid " + state.dataIPShortCut->cAlphaFieldNames(4) + " = " + state.dataIPShortCut->cAlphaArgs(4) +
    4901           0 :                                      ", occurs in " + cCurrentModuleObject + "object for " + cCurrentModuleObject + "=\"" +
    4902           0 :                                      state.dataIPShortCut->cAlphaArgs(1));
    4903           0 :                 ShowContinueError(state, "Schedule was not found so controls will always be available, and the simulation continues.");
    4904           0 :                 daylightControl.AvailSchedNum = DataGlobalConstants::ScheduleAlwaysOn;
    4905             :             }
    4906             :         } else {
    4907         282 :             daylightControl.AvailSchedNum = DataGlobalConstants::ScheduleAlwaysOn;
    4908             :         }
    4909             : 
    4910         287 :         int typeNum = getEnumerationValue(DataDaylighting::LtgCtrlTypeNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(5)));
    4911         287 :         daylightControl.LightControlType = static_cast<DataDaylighting::LtgCtrlType>(typeNum);
    4912         287 :         if (daylightControl.LightControlType == DataDaylighting::LtgCtrlType::Invalid) {
    4913           0 :             ShowWarningError(state,
    4914           0 :                              "Invalid " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5) + ", occurs in " +
    4915           0 :                                  cCurrentModuleObject + "object for " + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1));
    4916           0 :             ShowContinueError(state, "Continuous assumed, and the simulation continues.");
    4917             :         }
    4918             : 
    4919         287 :         daylightControl.MinPowerFraction =
    4920         287 :             state.dataIPShortCut->rNumericArgs(1); // Field: Minimum Input Power Fraction for Continuous Dimming Control
    4921         287 :         daylightControl.MinLightFraction =
    4922         287 :             state.dataIPShortCut->rNumericArgs(2); // Field: Minimum Light Output Fraction for Continuous Dimming Control
    4923         287 :         daylightControl.LightControlSteps = state.dataIPShortCut->rNumericArgs(3); // Field: Number of Stepped Control Steps
    4924         287 :         daylightControl.LightControlProbability =
    4925         287 :             state.dataIPShortCut->rNumericArgs(4); // Field: Probability Lighting will be Reset When Needed in Manual Stepped Control
    4926             : 
    4927         287 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) { // Field: Glare Calculation Daylighting Reference Point Name
    4928         284 :             daylightControl.glareRefPtNumber =
    4929         284 :                 UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(6),
    4930         284 :                                                 state.dataDaylightingData->DaylRefPt,
    4931             :                                                 &DataDaylighting::RefPointData::Name); // Field: Glare Calculation Daylighting Reference Point Name
    4932         284 :             if (daylightControl.glareRefPtNumber == 0) {
    4933           0 :                 ShowSevereError(state,
    4934           0 :                                 cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(6) + "=\"" +
    4935           0 :                                     state.dataIPShortCut->cAlphaArgs(6) + "\" for object named: " + state.dataIPShortCut->cAlphaArgs(1));
    4936           0 :                 ErrorsFound = true;
    4937           0 :                 continue;
    4938             :             }
    4939           3 :         } else if (daylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
    4940           0 :             ShowWarningError(
    4941           0 :                 state, "No " + state.dataIPShortCut->cAlphaFieldNames(6) + " provided for object named: " + state.dataIPShortCut->cAlphaArgs(1));
    4942           0 :             ShowContinueError(state, "No glare calculation performed, and the simulation continues.");
    4943             :         }
    4944             : 
    4945         287 :         if (!state.dataIPShortCut->lNumericFieldBlanks(5)) {
    4946         285 :             daylightControl.ViewAzimuthForGlare =
    4947         285 :                 state.dataIPShortCut->rNumericArgs(5); // Field: Glare Calculation Azimuth Angle of View Direction Clockwise from Zone y-Axis
    4948             :         } else {
    4949           2 :             daylightControl.ViewAzimuthForGlare = 0.;
    4950             :         }
    4951             : 
    4952         287 :         daylightControl.MaxGlareallowed = state.dataIPShortCut->rNumericArgs(6);           // Field: Maximum Allowable Discomfort Glare Index
    4953         287 :         daylightControl.DElightGriddingResolution = state.dataIPShortCut->rNumericArgs(7); // Field: DElight Gridding Resolution
    4954             : 
    4955         287 :         int curTotalDaylRefPts = NumAlpha - 6; // first six alpha fields are not part of extensible group
    4956         287 :         daylightControl.TotalDaylRefPoints = curTotalDaylRefPts;
    4957         287 :         state.dataViewFactor->EnclSolInfo(daylightControl.enclIndex).TotalEnclosureDaylRefPoints += curTotalDaylRefPts;
    4958         287 :         state.dataDaylightingData->ZoneDaylight(daylightControl.zoneIndex).totRefPts += curTotalDaylRefPts;
    4959         287 :         state.dataDaylightingData->maxRefPointsPerControl = max(state.dataDaylightingData->maxRefPointsPerControl, curTotalDaylRefPts);
    4960         287 :         if ((NumNumber - 7) / 2 != daylightControl.TotalDaylRefPoints) {
    4961           0 :             ShowSevereError(state,
    4962           0 :                             cCurrentModuleObject + "The number of extensible numeric fields and alpha fields is inconsistent for: " +
    4963           0 :                                 state.dataIPShortCut->cAlphaArgs(1));
    4964           0 :             ShowContinueError(
    4965             :                 state,
    4966           0 :                 "For each field: " + state.dataIPShortCut->cAlphaFieldNames(NumAlpha) +
    4967             :                     " there needs to be the following fields: Fraction Controlled by Reference Point and Illuminance Setpoint at Reference Point");
    4968           0 :             ErrorsFound = true;
    4969             :         }
    4970         287 :         daylightControl.DaylRefPtNum.allocate(curTotalDaylRefPts);
    4971         287 :         daylightControl.FracZoneDaylit.allocate(curTotalDaylRefPts);
    4972         287 :         daylightControl.IllumSetPoint.allocate(curTotalDaylRefPts);
    4973         287 :         daylightControl.DaylIllumAtRefPt.allocate(curTotalDaylRefPts);
    4974         287 :         daylightControl.GlareIndexAtRefPt.allocate(curTotalDaylRefPts);
    4975         287 :         daylightControl.DaylRefPtAbsCoord.allocate(3, curTotalDaylRefPts);
    4976         287 :         daylightControl.DaylRefPtInBounds.allocate(curTotalDaylRefPts);
    4977         287 :         daylightControl.RefPtPowerReductionFactor.allocate(curTotalDaylRefPts);
    4978         287 :         daylightControl.BacLum.allocate(curTotalDaylRefPts);
    4979         287 :         daylightControl.TimeExceedingGlareIndexSPAtRefPt.allocate(curTotalDaylRefPts);
    4980         287 :         daylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt.allocate(curTotalDaylRefPts);
    4981             : 
    4982         753 :         for (int refPt = 1; refPt <= curTotalDaylRefPts; ++refPt) {
    4983         466 :             daylightControl.DaylRefPtNum(refPt) = 0;
    4984         466 :             daylightControl.FracZoneDaylit(refPt) = 0.0;
    4985         466 :             daylightControl.IllumSetPoint(refPt) = 0.0;
    4986         466 :             daylightControl.DaylIllumAtRefPt(refPt) = 0.0;
    4987         466 :             daylightControl.GlareIndexAtRefPt(refPt) = 0.0;
    4988         466 :             daylightControl.DaylRefPtInBounds(refPt) = true;
    4989         466 :             daylightControl.RefPtPowerReductionFactor(refPt) = 1.0;
    4990         466 :             daylightControl.BacLum(refPt) = 0.0;
    4991         466 :             daylightControl.TimeExceedingGlareIndexSPAtRefPt(refPt) = 0.0;
    4992         466 :             daylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(refPt) = 0.0;
    4993        1864 :             for (int coord = 1; coord <= 3; ++coord) {
    4994        1398 :                 daylightControl.DaylRefPtAbsCoord(coord, refPt) = 0.0;
    4995             :             }
    4996             :         }
    4997             : 
    4998         287 :         int countRefPts = 0;
    4999         753 :         for (int refPtNum = 1; refPtNum <= curTotalDaylRefPts; ++refPtNum) {
    5000         466 :             daylightControl.DaylRefPtNum(refPtNum) =
    5001         466 :                 UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(6 + refPtNum),
    5002         466 :                                                 state.dataDaylightingData->DaylRefPt,
    5003             :                                                 &DataDaylighting::RefPointData::Name); // Field: Daylighting Reference Point Name
    5004         466 :             if (daylightControl.DaylRefPtNum(refPtNum) == 0) {
    5005           0 :                 ShowSevereError(state,
    5006           0 :                                 cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(6 + refPtNum) + "=\"" +
    5007           0 :                                     state.dataIPShortCut->cAlphaArgs(6 + refPtNum) + "\" for object named: " + state.dataIPShortCut->cAlphaArgs(1));
    5008           0 :                 ErrorsFound = true;
    5009           0 :                 continue;
    5010             :             } else {
    5011         466 :                 ++countRefPts;
    5012             :             }
    5013         466 :             daylightControl.FracZoneDaylit(refPtNum) =
    5014         466 :                 state.dataIPShortCut->rNumericArgs(6 + refPtNum * 2); // Field: Fraction Controlled by Reference Point
    5015         466 :             daylightControl.IllumSetPoint(refPtNum) =
    5016         466 :                 state.dataIPShortCut->rNumericArgs(7 + refPtNum * 2); // Field: Illuminance Setpoint at Reference Point
    5017             : 
    5018         466 :             if (daylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
    5019        1840 :                 SetupOutputVariable(state,
    5020         920 :                                     format("Daylighting Reference Point {} Illuminance", refPtNum),
    5021             :                                     OutputProcessor::Unit::lux,
    5022         920 :                                     daylightControl.DaylIllumAtRefPt(refPtNum),
    5023             :                                     OutputProcessor::SOVTimeStepType::Zone,
    5024             :                                     OutputProcessor::SOVStoreType::Average,
    5025             :                                     daylightControl.Name);
    5026        1840 :                 SetupOutputVariable(state,
    5027         920 :                                     format("Daylighting Reference Point {} Daylight Illuminance Setpoint Exceeded Time", refPtNum),
    5028             :                                     OutputProcessor::Unit::hr,
    5029         920 :                                     daylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(refPtNum),
    5030             :                                     OutputProcessor::SOVTimeStepType::Zone,
    5031             :                                     OutputProcessor::SOVStoreType::Summed,
    5032             :                                     daylightControl.Name);
    5033        1840 :                 SetupOutputVariable(state,
    5034         920 :                                     format("Daylighting Reference Point {} Glare Index", refPtNum),
    5035             :                                     OutputProcessor::Unit::None,
    5036         920 :                                     daylightControl.GlareIndexAtRefPt(refPtNum),
    5037             :                                     OutputProcessor::SOVTimeStepType::Zone,
    5038             :                                     OutputProcessor::SOVStoreType::Average,
    5039             :                                     daylightControl.Name);
    5040        1840 :                 SetupOutputVariable(state,
    5041         920 :                                     format("Daylighting Reference Point {} Glare Index Setpoint Exceeded Time", refPtNum),
    5042             :                                     OutputProcessor::Unit::hr,
    5043         920 :                                     daylightControl.TimeExceedingGlareIndexSPAtRefPt(refPtNum),
    5044             :                                     OutputProcessor::SOVTimeStepType::Zone,
    5045             :                                     OutputProcessor::SOVStoreType::Summed,
    5046             :                                     daylightControl.Name);
    5047             :             }
    5048             :         }
    5049             :         // Register Error if 0 DElight RefPts have been input for valid DElight object
    5050         287 :         if (countRefPts < 1) {
    5051           0 :             ShowSevereError(state, "No Reference Points input for " + cCurrentModuleObject + " zone =" + daylightControl.ZoneName);
    5052           0 :             ErrorsFound = true;
    5053             :         }
    5054             : 
    5055         287 :         Real64 sumFracs = sum(daylightControl.FracZoneDaylit);
    5056         287 :         daylightControl.sumFracLights = sumFracs;
    5057         287 :         if ((1.0 - sumFracs) > FractionTolerance) {
    5058         166 :             ShowWarningError(state, "GetDaylightingControls: Fraction of zone or space controlled by the Daylighting reference points is < 1.0.");
    5059         498 :             ShowContinueError(state,
    5060         498 :                               format("..discovered in {}=\"{}\", only {:.3R} of the zone or space is controlled.",
    5061             :                                      cCurrentModuleObject,
    5062             :                                      daylightControl.Name,
    5063         498 :                                      sum(daylightControl.FracZoneDaylit)));
    5064         121 :         } else if ((sumFracs - 1.0) > FractionTolerance) {
    5065           0 :             ShowSevereError(state, "GetDaylightingControls: Fraction of zone or space controlled by the Daylighting reference points is > 1.0.");
    5066           0 :             ShowContinueError(state,
    5067           0 :                               format("..discovered in {}=\"{}\", trying to control {:.3R} of the zone or space.",
    5068             :                                      cCurrentModuleObject,
    5069             :                                      daylightControl.Name,
    5070           0 :                                      sum(daylightControl.FracZoneDaylit)));
    5071           0 :             ErrorsFound = true;
    5072             :         }
    5073             : 
    5074         287 :         if (daylightControl.LightControlType == DataDaylighting::LtgCtrlType::Stepped && daylightControl.LightControlSteps <= 0) {
    5075           0 :             ShowWarningError(state, "GetDaylightingControls: For Stepped Control, the number of steps must be > 0");
    5076           0 :             ShowContinueError(
    5077           0 :                 state, "..discovered in \"" + cCurrentModuleObject + "\" for Zone=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\", will use 1");
    5078           0 :             daylightControl.LightControlSteps = 1;
    5079             :         }
    5080         574 :         SetupOutputVariable(state,
    5081             :                             "Daylighting Lighting Power Multiplier",
    5082             :                             OutputProcessor::Unit::None,
    5083             :                             daylightControl.PowerReductionFactor,
    5084             :                             OutputProcessor::SOVTimeStepType::Zone,
    5085             :                             OutputProcessor::SOVStoreType::Average,
    5086         287 :                             daylightControl.Name);
    5087             :     }
    5088          62 : }
    5089             : 
    5090          62 : void GeometryTransformForDaylighting(EnergyPlusData &state)
    5091             : {
    5092             :     //       AUTHOR         Fred Winkelmann
    5093             :     //       DATE WRITTEN   March 2002
    5094             :     //       MODIFIED       Glazer - July 2016 - separated this from GetInput function
    5095             :     // For splitflux daylighting, transform the geometry
    5096             : 
    5097             :     using InternalHeatGains::CheckLightsReplaceableMinMaxForZone;
    5098             :     using InternalHeatGains::GetDesignLightingLevelForZone;
    5099             :     using namespace OutputReportPredefined;
    5100             :     using ScheduleManager::GetScheduleIndex;
    5101             : 
    5102             :     int refPtNum;
    5103         124 :     std::string refName;
    5104             :     Real64 CosBldgRelNorth;         // Cosine of Building rotation
    5105             :     Real64 SinBldgRelNorth;         // Sine of Building rotation
    5106             :     Real64 CosZoneRelNorth;         // Cosine of Zone rotation
    5107             :     Real64 SinZoneRelNorth;         // Sine of Zone rotation
    5108          62 :     Real64 CosBldgRotAppGonly(0.0); // Cosine of the building rotation for appendix G only ( relative north )
    5109          62 :     Real64 SinBldgRotAppGonly(0.0); // Sine of the building rotation for appendix G only ( relative north )
    5110             :     Real64 Xb;                      // temp var for transformation calc
    5111             :     Real64 Yb;                      // temp var for transformation calc
    5112             :     Real64 Xo;
    5113             :     Real64 XnoRot;
    5114             :     Real64 Xtrans;
    5115             :     Real64 Yo;
    5116             :     Real64 YnoRot;
    5117             :     Real64 Ytrans;
    5118             :     bool doTransform;
    5119             :     Real64 OldAspectRatio;
    5120             :     Real64 NewAspectRatio;
    5121             :     Real64 rLightLevel;
    5122             : 
    5123             :     // Calc cos and sin of Building Relative North values for later use in transforming Reference Point coordinates
    5124          62 :     CosBldgRelNorth =
    5125          62 :         std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
    5126          62 :     SinBldgRelNorth =
    5127          62 :         std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
    5128             :     // these are only for Building Rotation for Appendix G when using world coordinate system
    5129          62 :     CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
    5130          62 :     SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
    5131             : 
    5132          62 :     doTransform = false;
    5133          62 :     OldAspectRatio = 1.0;
    5134          62 :     NewAspectRatio = 1.0;
    5135             : 
    5136          62 :     CheckForGeometricTransform(state, doTransform, OldAspectRatio, NewAspectRatio);
    5137         349 :     for (int controlNum = 1; controlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++controlNum) {
    5138         287 :         auto &daylCntrl = state.dataDaylightingData->daylightControl(controlNum);
    5139         287 :         auto &zone(state.dataHeatBal->Zone(daylCntrl.zoneIndex));
    5140             : 
    5141             :         // Calc cos and sin of Zone Relative North values for later use in transforming Reference Point coordinates
    5142         287 :         CosZoneRelNorth = std::cos(-zone.RelNorth * DataGlobalConstants::DegToRadians);
    5143         287 :         SinZoneRelNorth = std::sin(-zone.RelNorth * DataGlobalConstants::DegToRadians);
    5144             : 
    5145         287 :         rLightLevel = GetDesignLightingLevelForZone(state, daylCntrl.zoneIndex);
    5146         287 :         CheckLightsReplaceableMinMaxForZone(state, daylCntrl.zoneIndex);
    5147             : 
    5148         753 :         for (refPtNum = 1; refPtNum <= daylCntrl.TotalDaylRefPoints; ++refPtNum) {
    5149         466 :             auto &curRefPt(state.dataDaylightingData->DaylRefPt(daylCntrl.DaylRefPtNum(refPtNum))); // get the active daylighting:referencepoint
    5150         466 :             curRefPt.indexToFracAndIllum = refPtNum; // back reference to the index to the ZoneDaylight structure arrays related to reference points
    5151         466 :             if (state.dataSurface->DaylRefWorldCoordSystem) {
    5152             :                 // transform only by appendix G rotation
    5153           7 :                 daylCntrl.DaylRefPtAbsCoord(1, refPtNum) = curRefPt.x * CosBldgRotAppGonly - curRefPt.y * SinBldgRotAppGonly;
    5154           7 :                 daylCntrl.DaylRefPtAbsCoord(2, refPtNum) = curRefPt.x * SinBldgRotAppGonly + curRefPt.y * CosBldgRotAppGonly;
    5155           7 :                 daylCntrl.DaylRefPtAbsCoord(3, refPtNum) = curRefPt.z;
    5156             :             } else {
    5157             :                 // Transform reference point coordinates into building coordinate system
    5158         459 :                 Xb = curRefPt.x * CosZoneRelNorth - curRefPt.y * SinZoneRelNorth + zone.OriginX;
    5159         459 :                 Yb = curRefPt.x * SinZoneRelNorth + curRefPt.y * CosZoneRelNorth + zone.OriginY;
    5160             :                 // Transform into World Coordinate System
    5161         459 :                 daylCntrl.DaylRefPtAbsCoord(1, refPtNum) = Xb * CosBldgRelNorth - Yb * SinBldgRelNorth;
    5162         459 :                 daylCntrl.DaylRefPtAbsCoord(2, refPtNum) = Xb * SinBldgRelNorth + Yb * CosBldgRelNorth;
    5163         459 :                 daylCntrl.DaylRefPtAbsCoord(3, refPtNum) = curRefPt.z + zone.OriginZ;
    5164         459 :                 if (doTransform) {
    5165           0 :                     Xo = daylCntrl.DaylRefPtAbsCoord(1, refPtNum); // world coordinates.... shifted by relative north angle...
    5166           0 :                     Yo = daylCntrl.DaylRefPtAbsCoord(2, refPtNum);
    5167             :                     // next derotate the building
    5168           0 :                     XnoRot = Xo * CosBldgRelNorth + Yo * SinBldgRelNorth;
    5169           0 :                     YnoRot = Yo * CosBldgRelNorth - Xo * SinBldgRelNorth;
    5170             :                     // translate
    5171           0 :                     Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
    5172           0 :                     Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
    5173             :                     // rerotate
    5174           0 :                     daylCntrl.DaylRefPtAbsCoord(1, refPtNum) = Xtrans * CosBldgRelNorth - Ytrans * SinBldgRelNorth;
    5175           0 :                     daylCntrl.DaylRefPtAbsCoord(2, refPtNum) = Xtrans * SinBldgRelNorth + Ytrans * CosBldgRelNorth;
    5176             :                 }
    5177             :             }
    5178         466 :             refName = curRefPt.Name;
    5179         466 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtZone, refName, daylCntrl.ZoneName);
    5180         466 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlName, refName, daylCntrl.Name);
    5181         466 :             if (daylCntrl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
    5182         460 :                 PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtKind, refName, "SplitFlux");
    5183             :             } else {
    5184           6 :                 PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtKind, refName, "DElight");
    5185             :             }
    5186             :             // ( 1=continuous, 2=stepped, 3=continuous/off )
    5187         466 :             if (daylCntrl.LightControlType == DataDaylighting::LtgCtrlType::Continuous) {
    5188          59 :                 PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlType, refName, "Continuous");
    5189         407 :             } else if (daylCntrl.LightControlType == DataDaylighting::LtgCtrlType::Stepped) {
    5190         129 :                 PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlType, refName, "Stepped");
    5191         278 :             } else if (daylCntrl.LightControlType == DataDaylighting::LtgCtrlType::ContinuousOff) {
    5192         278 :                 PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlType, refName, "Continuous/Off");
    5193             :             }
    5194         466 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtFrac, refName, daylCntrl.FracZoneDaylit(refPtNum));
    5195         466 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtWInst, refName, rLightLevel);
    5196         466 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtWCtrl, refName, rLightLevel * daylCntrl.FracZoneDaylit(refPtNum));
    5197             : 
    5198         466 :             if (daylCntrl.DaylRefPtAbsCoord(1, refPtNum) < zone.MinimumX || daylCntrl.DaylRefPtAbsCoord(1, refPtNum) > zone.MaximumX) {
    5199           0 :                 daylCntrl.DaylRefPtInBounds(refPtNum) = false;
    5200           0 :                 ShowWarningError(state, "GeometryTransformForDaylighting: Reference point X Value outside Zone Min/Max X, Zone=" + zone.Name);
    5201           0 :                 ShowContinueError(state,
    5202           0 :                                   format("...X Reference Point= {:.2R}, Zone Minimum X= {:.2R}, Zone Maximum X= {:.2R}",
    5203             :                                          daylCntrl.DaylRefPtAbsCoord(1, refPtNum),
    5204             :                                          zone.MinimumX,
    5205           0 :                                          zone.MaximumX));
    5206           0 :                 if (daylCntrl.DaylRefPtAbsCoord(1, refPtNum) < zone.MinimumX) {
    5207           0 :                     ShowContinueError(
    5208             :                         state,
    5209           0 :                         format("...X Reference Distance Outside MinimumX= {:.4R} m.", zone.MinimumX - daylCntrl.DaylRefPtAbsCoord(1, refPtNum)));
    5210             :                 } else {
    5211           0 :                     ShowContinueError(
    5212             :                         state,
    5213           0 :                         format("...X Reference Distance Outside MaximumX= {:.4R} m.", daylCntrl.DaylRefPtAbsCoord(1, refPtNum) - zone.MaximumX));
    5214             :                 }
    5215             :             }
    5216         466 :             if (daylCntrl.DaylRefPtAbsCoord(2, refPtNum) < zone.MinimumY || daylCntrl.DaylRefPtAbsCoord(2, refPtNum) > zone.MaximumY) {
    5217           0 :                 daylCntrl.DaylRefPtInBounds(refPtNum) = false;
    5218           0 :                 ShowWarningError(state, "GeometryTransformForDaylighting: Reference point Y Value outside Zone Min/Max Y, Zone=" + zone.Name);
    5219           0 :                 ShowContinueError(state,
    5220           0 :                                   format("...Y Reference Point= {:.2R}, Zone Minimum Y= {:.2R}, Zone Maximum Y= {:.2R}",
    5221             :                                          daylCntrl.DaylRefPtAbsCoord(2, refPtNum),
    5222             :                                          zone.MinimumY,
    5223           0 :                                          zone.MaximumY));
    5224           0 :                 if (daylCntrl.DaylRefPtAbsCoord(2, refPtNum) < zone.MinimumY) {
    5225           0 :                     ShowContinueError(
    5226             :                         state,
    5227           0 :                         format("...Y Reference Distance Outside MinimumY= {:.4R} m.", zone.MinimumY - daylCntrl.DaylRefPtAbsCoord(2, refPtNum)));
    5228             :                 } else {
    5229           0 :                     ShowContinueError(
    5230             :                         state,
    5231           0 :                         format("...Y Reference Distance Outside MaximumY= {:.4R} m.", daylCntrl.DaylRefPtAbsCoord(2, refPtNum) - zone.MaximumY));
    5232             :                 }
    5233             :             }
    5234         466 :             if (daylCntrl.DaylRefPtAbsCoord(3, refPtNum) < zone.MinimumZ || daylCntrl.DaylRefPtAbsCoord(3, refPtNum) > zone.MaximumZ) {
    5235           0 :                 daylCntrl.DaylRefPtInBounds(refPtNum) = false;
    5236           0 :                 ShowWarningError(state, "GeometryTransformForDaylighting: Reference point Z Value outside Zone Min/Max Z, Zone=" + zone.Name);
    5237           0 :                 ShowContinueError(state,
    5238           0 :                                   format("...Z Reference Point= {:.2R}, Zone Minimum Z= {:.2R}, Zone Maximum Z= {:.2R}",
    5239             :                                          daylCntrl.DaylRefPtAbsCoord(3, refPtNum),
    5240             :                                          zone.MinimumZ,
    5241           0 :                                          zone.MaximumZ));
    5242           0 :                 if (daylCntrl.DaylRefPtAbsCoord(3, refPtNum) < zone.MinimumZ) {
    5243           0 :                     ShowContinueError(
    5244             :                         state,
    5245           0 :                         format("...Z Reference Distance Outside MinimumZ= {:.4R} m.", zone.MinimumZ - daylCntrl.DaylRefPtAbsCoord(3, refPtNum)));
    5246             :                 } else {
    5247           0 :                     ShowContinueError(
    5248             :                         state,
    5249           0 :                         format("...Z Reference Distance Outside MaximumZ= {:.4R} m.", daylCntrl.DaylRefPtAbsCoord(3, refPtNum) - zone.MaximumZ));
    5250             :                 }
    5251             :             }
    5252             :         } // for (refPtNum) reference point
    5253             :     }     // for (controlNum) daylighting control
    5254          62 : }
    5255             : 
    5256          62 : void GetInputDayliteRefPt(EnergyPlusData &state, bool &ErrorsFound)
    5257             : {
    5258             :     // Perform GetInput function for the Daylighting:ReferencePoint object
    5259             :     // Glazer - July 2016
    5260             : 
    5261          62 :     int RefPtNum = 0;
    5262             :     int IOStat;
    5263             :     int NumAlpha;
    5264             :     int NumNumber;
    5265          62 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    5266          62 :     cCurrentModuleObject = "Daylighting:ReferencePoint";
    5267          62 :     int TotRefPoints = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    5268          62 :     state.dataDaylightingData->DaylRefPt.allocate(TotRefPoints);
    5269         528 :     for (auto &pt : state.dataDaylightingData->DaylRefPt) {
    5270        3262 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5271             :                                                                  cCurrentModuleObject,
    5272             :                                                                  ++RefPtNum,
    5273         466 :                                                                  state.dataIPShortCut->cAlphaArgs,
    5274             :                                                                  NumAlpha,
    5275         466 :                                                                  state.dataIPShortCut->rNumericArgs,
    5276             :                                                                  NumNumber,
    5277             :                                                                  IOStat,
    5278         466 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    5279         466 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    5280         466 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    5281         466 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    5282         466 :         pt.Name = state.dataIPShortCut->cAlphaArgs(1);
    5283         466 :         pt.ZoneNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
    5284         466 :         if (pt.ZoneNum == 0) {
    5285           0 :             int spaceNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->space);
    5286           0 :             if (spaceNum == 0) {
    5287           0 :                 ShowSevereError(state,
    5288           0 :                                 cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid " +
    5289           0 :                                     state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\".");
    5290           0 :                 ErrorsFound = true;
    5291             :             } else {
    5292           0 :                 pt.ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
    5293             :             }
    5294             :         }
    5295         466 :         pt.x = state.dataIPShortCut->rNumericArgs(1);
    5296         466 :         pt.y = state.dataIPShortCut->rNumericArgs(2);
    5297         466 :         pt.z = state.dataIPShortCut->rNumericArgs(3);
    5298             :     }
    5299          62 : }
    5300             : 
    5301        1025 : bool doesDayLightingUseDElight(EnergyPlusData &state)
    5302             : {
    5303        1306 :     for (auto &znDayl : state.dataDaylightingData->daylightControl) {
    5304         284 :         if (znDayl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight) {
    5305           3 :             return true;
    5306             :         }
    5307             :     }
    5308        1022 :     return false;
    5309             : }
    5310             : 
    5311         771 : void CheckTDDsAndLightShelvesInDaylitZones(EnergyPlusData &state)
    5312             : {
    5313             :     // SUBROUTINE INFORMATION:
    5314             :     //       AUTHOR         Brent Griffith
    5315             :     //       DATE WRITTEN   Dec 2007
    5316             :     //       MODIFIED       na
    5317             :     //       RE-ENGINEERED  na
    5318             : 
    5319             :     // PURPOSE OF THIS SUBROUTINE:
    5320             :     // This subroutine checks daylighting input for TDDs and light shelfs
    5321             :     //  which need to be checked after daylighting input has been read in (CR 7145)
    5322             :     //  (eventually this should be changed once/if implementations change to decouple from daylighting calcs so that
    5323             :     //  these devices can be used in models without daylighting controls
    5324             :     // CR 7145 was for TDDs, but also implenting check for light shelves, the other "daylighting device"
    5325             : 
    5326             :     // METHODOLOGY EMPLOYED:
    5327             :     // loop thru daylighting devices and check that their zones have daylight controls
    5328             : 
    5329             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5330             :     int PipeNum;  // TDD pipe object number
    5331             :     int ShelfNum; // light shelf object number
    5332             :     int SurfNum;  // daylight device surface number
    5333             :     bool ErrorsFound;
    5334             : 
    5335         771 :     ErrorsFound = false;
    5336             : 
    5337         773 :     for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
    5338           2 :         SurfNum = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser;
    5339           2 :         if (SurfNum > 0) {
    5340           2 :             int const pipeEnclNum = state.dataSurface->Surface(SurfNum).SolarEnclIndex;
    5341           2 :             if (state.dataViewFactor->EnclSolInfo(pipeEnclNum).TotalEnclosureDaylRefPoints == 0) {
    5342           0 :                 ShowWarningError(state,
    5343           0 :                                  "DaylightingDevice:Tubular = " + state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name +
    5344             :                                      ":  is not connected to a Zone that has Daylighting, no visible transmittance will be modeled through the "
    5345             :                                      "daylighting device.");
    5346             :             }
    5347             : 
    5348             :         } else { // SurfNum == 0
    5349             :             // should not come here (would have already been caught in TDD get input), but is an error
    5350           0 :             ShowSevereError(
    5351           0 :                 state, "DaylightingDevice:Tubular = " + state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name + ":  Diffuser surface not found ");
    5352           0 :             ErrorsFound = true;
    5353             :         }
    5354             :     } // PipeNum
    5355             : 
    5356         772 :     for (ShelfNum = 1; ShelfNum <= (int)state.dataDaylightingDevicesData->Shelf.size(); ++ShelfNum) {
    5357           1 :         SurfNum = state.dataDaylightingDevicesData->Shelf(ShelfNum).Window;
    5358           1 :         if (SurfNum == 0) {
    5359             :             // should not come here (would have already been caught in shelf get input), but is an error
    5360           0 :             ShowSevereError(state, "DaylightingDevice:Shelf = " + state.dataDaylightingDevicesData->Shelf(ShelfNum).Name + ":  window not found ");
    5361           0 :             ErrorsFound = true;
    5362             :         }
    5363             :     } // ShelfNum
    5364             : 
    5365         771 :     if (ErrorsFound) ShowFatalError(state, "CheckTDDsAndLightShelvesInDaylitZones: Errors in DAYLIGHTING input.");
    5366         771 : }
    5367             : 
    5368         771 : void AssociateWindowShadingControlWithDaylighting(EnergyPlusData &state)
    5369             : {
    5370         843 :     for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
    5371          72 :         if (state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightingControlName.empty()) continue;
    5372          25 :         int found = -1;
    5373          27 :         for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
    5374          27 :             if (UtilityRoutines::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightingControlName,
    5375          27 :                                             state.dataDaylightingData->daylightControl(daylightCtrlNum).Name)) {
    5376          25 :                 found = daylightCtrlNum;
    5377          25 :                 break;
    5378             :             }
    5379             :         }
    5380          25 :         if (found > 0) {
    5381          25 :             state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightControlIndex = found;
    5382             :         } else {
    5383           0 :             ShowWarningError(state, "AssociateWindowShadingControlWithDaylighting: Daylighting object name used in WindowShadingControl not found.");
    5384           0 :             ShowContinueError(state,
    5385           0 :                               "..The WindowShadingControl object=\"" + state.dataSurface->WindowShadingControl(iShadeCtrl).Name +
    5386           0 :                                   "\" and referenes an object named: \"" +
    5387           0 :                                   state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightingControlName + "\"");
    5388             :         }
    5389             :     }
    5390         771 : }
    5391             : 
    5392          62 : void GetLightWellData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
    5393             : {
    5394             : 
    5395             :     // SUBROUTINE INFORMATION:
    5396             :     //       AUTHOR         Fred Winkelmann
    5397             :     //       DATE WRITTEN   Apr 2004
    5398             :     //       MODIFIED       na
    5399             :     //       RE-ENGINEERED  na
    5400             : 
    5401             :     // PURPOSE OF THIS SUBROUTINE:
    5402             :     // Gets data for a light well associated with a rectangular exterior window.
    5403             :     // Calculates light well efficiency, defined as the ratio of the amount of visible
    5404             :     // solar radiation leaving a well to the amount entering the well.
    5405             : 
    5406             :     // METHODOLOGY EMPLOYED:
    5407             :     // Based on fit to Fig. 8-21, "Efficiency factors for various depths of light wells
    5408             :     // based on well-interreflectance values," Lighting Handbook, 8th Edition, Illuminating
    5409             :     // Engineering Society of North America, 1993.
    5410             : 
    5411             :     // Using/Aliasing
    5412             : 
    5413             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5414             : 
    5415             :     int IOStat;            // IO Status when calling get input subroutine
    5416             :     int NumAlpha;          // Number of alpha names being passed
    5417             :     int NumProp;           // Number of properties being passed
    5418             :     int TotLightWells;     // Total Light Well objects
    5419             :     int loop;              // DO loop index
    5420             :     int SurfNum;           // Surface number
    5421             :     bool WrongSurfaceType; // True if associated surface is not an exterior window
    5422             :     Real64 HeightWell;     // Well height (from window to bottom of well) (m)
    5423             :     Real64 PerimWell;      // Well perimeter (at bottom of well) (m)
    5424             :     Real64 AreaWell;       // Well area (at bottom of well) (m2)
    5425             :     Real64 VisReflWell;    // Area-weighted visible reflectance of well walls
    5426             :     Real64 WellCavRatio;   // Well cavity ratio
    5427          62 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    5428             :     // Get the total number of Light Well objects
    5429          62 :     cCurrentModuleObject = "DaylightingDevice:LightWell";
    5430          62 :     TotLightWells = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    5431          62 :     if (TotLightWells == 0) return;
    5432             : 
    5433           3 :     for (loop = 1; loop <= TotLightWells; ++loop) {
    5434             : 
    5435          14 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5436             :                                                                  cCurrentModuleObject,
    5437             :                                                                  loop,
    5438           2 :                                                                  state.dataIPShortCut->cAlphaArgs,
    5439             :                                                                  NumAlpha,
    5440           2 :                                                                  state.dataIPShortCut->rNumericArgs,
    5441             :                                                                  NumProp,
    5442             :                                                                  IOStat,
    5443           2 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    5444           2 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    5445           2 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    5446           2 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    5447             : 
    5448           2 :         SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface);
    5449           2 :         if (SurfNum == 0) {
    5450           0 :             ShowSevereError(state,
    5451           0 :                             cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
    5452           0 :                                 state.dataIPShortCut->cAlphaArgs(1) + "\" not found.");
    5453             :         }
    5454             : 
    5455             :         // Check that associated surface is an exterior window
    5456           2 :         WrongSurfaceType = false;
    5457           2 :         if (SurfNum != 0) {
    5458           2 :             if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Window &&
    5459           0 :                 state.dataSurface->Surface(SurfNum).ExtBoundCond != ExternalEnvironment)
    5460           0 :                 WrongSurfaceType = true;
    5461           2 :             if (WrongSurfaceType) {
    5462           0 :                 ShowSevereError(state,
    5463           0 :                                 cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
    5464           0 :                                     state.dataIPShortCut->cAlphaArgs(1) + "\" - not an exterior window.");
    5465           0 :                 ErrorsFound = true;
    5466             :             }
    5467             :         }
    5468             : 
    5469           2 :         if (!ErrorsFound) {
    5470             : 
    5471             :             // Associated surface is an exterior window; calculate light well efficiency.
    5472             : 
    5473           2 :             state.dataSurface->SurfWinLightWellEff(SurfNum) = 1.0;
    5474           2 :             HeightWell = state.dataIPShortCut->rNumericArgs(1);
    5475           2 :             PerimWell = state.dataIPShortCut->rNumericArgs(2);
    5476           2 :             AreaWell = state.dataIPShortCut->rNumericArgs(3);
    5477           2 :             VisReflWell = state.dataIPShortCut->rNumericArgs(4);
    5478             : 
    5479             :             // Warning if light well area is less than window area
    5480           2 :             if (AreaWell < (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum) - 0.1)) {
    5481           0 :                 ShowSevereError(state,
    5482           0 :                                 cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
    5483           0 :                                     state.dataIPShortCut->cAlphaArgs(1) + "\" - Areas.");
    5484           0 :                 ShowContinueError(state,
    5485           0 :                                   format("has Area of Bottom of Well={:.1R} that is less than window area={:.1R}",
    5486           0 :                                          state.dataSurface->Surface(SurfNum).Area,
    5487           0 :                                          AreaWell));
    5488             :             }
    5489             : 
    5490           2 :             if (HeightWell >= 0.0 && PerimWell > 0.0 && AreaWell > 0.0) {
    5491           2 :                 WellCavRatio = 2.5 * HeightWell * PerimWell / AreaWell;
    5492           2 :                 state.dataSurface->SurfWinLightWellEff(SurfNum) = std::exp(-WellCavRatio * (0.16368 - 0.14467 * VisReflWell));
    5493             :             }
    5494             :         }
    5495             : 
    5496             :     } // End of loop over light well objects
    5497             : }
    5498             : 
    5499     3963536 : inline int findWinShadingStatus(EnergyPlusData &state, int const IWin)
    5500             : {
    5501             :     // Return the window shading status, 1=unshaded, 2=shaded
    5502     3963536 :     int WinShadingIndex = 1;
    5503     3963536 :     bool WinShadedNoGlareControl = IS_SHADED_NO_GLARE_CTRL(state.dataSurface->SurfWinShadingFlag(IWin));
    5504     4207417 :     if ((state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) &&
    5505     3714223 :         (WinShadedNoGlareControl || state.dataSurface->SurfWinSolarDiffusing(IWin))) {
    5506      243881 :         WinShadingIndex = 2;
    5507             :     }
    5508     3963536 :     return WinShadingIndex;
    5509             : }
    5510             : 
    5511      972795 : void DayltgGlare(EnergyPlusData &state,
    5512             :                  int &IL,                  // Reference point index: 1=first ref pt, 2=second ref pt
    5513             :                  Real64 &BLUM,             // Window background (surround) luminance (cd/m2)
    5514             :                  Real64 &GLINDX,           // Glare index
    5515             :                  int const daylightCtrlNum // Current daylighting control number
    5516             : )
    5517             : {
    5518             : 
    5519             :     // SUBROUTINE INFORMATION:
    5520             :     //       AUTHOR         Fred Winkelmann
    5521             :     //       DATE WRITTEN   July 1997
    5522             : 
    5523             :     // PURPOSE OF THIS SUBROUTINE:
    5524             :     // CALCULATE GLARE INDEX.
    5525             : 
    5526             :     // METHODOLOGY EMPLOYED:
    5527             :     // Called from DayltgInteriorIllum.  Finds glare index at reference
    5528             :     // point no. IL in a space using the Cornell/BRS large source
    5529             :     // glare formula. BLUM is the background luminance (cd/m**2).
    5530             :     // TH comment 1/21/2010: The SurfaceWindow(IWin)%ShadingFlag has to be set
    5531             :     //  before calling this subroutine. For switchable glazings this is tricky
    5532             :     //  because the ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop)
    5533             :     //  may change every time step to represent intermediate switched state.
    5534             : 
    5535             :     // REFERENCES:
    5536             :     // Based on DOE-2.1E subroutine DGLARE.
    5537             : 
    5538      972795 :     Real64 GTOT = 0.0; // Glare constant
    5539             : 
    5540             :     // Loop over exterior windows associated with zone
    5541      972795 :     auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    5542      972795 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex);
    5543     3531695 :     for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
    5544     2558900 :         int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
    5545     2558900 :         int WinShadingIndex = findWinShadingStatus(state, IWin);
    5546             :         // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor
    5547             :         // below, which is (0.2936)**0.6
    5548     2558900 :         Real64 GTOT1 = 0.4794 * (std::pow(thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) *
    5549     2558900 :                        std::pow(thisDaylightControl.SolidAngAtRefPtWtd(loop, IL), 0.8);
    5550     5117800 :         Real64 GTOT2 = BLUM + 0.07 * (std::sqrt(thisDaylightControl.SolidAngAtRefPt(loop, IL))) *
    5551     5117800 :                                   thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL);
    5552     2558900 :         GTOT += GTOT1 / (GTOT2 + 0.000001);
    5553             :     }
    5554             : 
    5555             :     // Glare index (adding 0.000001 prevents LOG10 (0))
    5556      972795 :     GLINDX = 10.0 * std::log10(GTOT + 0.000001);
    5557             :     // Set glare index to zero for GTOT < 1
    5558      972795 :     GLINDX = max(0.0, GLINDX);
    5559      972795 : }
    5560             : 
    5561        1015 : void DayltgGlareWithIntWins(EnergyPlusData &state,
    5562             :                             Array1D<Real64> &GLINDX,  // Glare index
    5563             :                             int const daylightCtrlNum // Current daylighting control number
    5564             : )
    5565             : {
    5566             : 
    5567             :     // SUBROUTINE INFORMATION:
    5568             :     //       AUTHOR         Fred Winkelmann
    5569             :     //       DATE WRITTEN   March 2004
    5570             : 
    5571             :     // PURPOSE OF THIS SUBROUTINE:
    5572             :     // Calculate daylighting glare index for zones with interior windows.
    5573             : 
    5574             :     // METHODOLOGY EMPLOYED:
    5575             :     // Finds glare index at reference point IL in a daylit zone using the Cornell/BRS large source
    5576             :     // glare formula. Takes into account inter-reflected illuminance from light entering
    5577             :     // the zone through interior windows
    5578             : 
    5579             :     // REFERENCES:
    5580             :     // Based on subroutine DayltgGlare.
    5581             : 
    5582        1015 :     Real64 GTOT = 0.0; // Glare constant(?)
    5583             : 
    5584             :     // Calculate background luminance including effect of inter-reflected illuminance from light
    5585             :     // entering zone through its interior windows
    5586             : 
    5587        1015 :     auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    5588        1015 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex);
    5589        1015 :     int RefPoints = thisDaylightControl.TotalDaylRefPoints; // Number of daylighting reference points in zone
    5590        2030 :     for (int IL = 1; IL <= RefPoints; ++IL) {
    5591             :         Real64 BackgroundLum =
    5592        1015 :             thisDaylightControl.BacLum(IL) + thisEnclDaylight.InterReflIllFrIntWins * thisEnclDaylight.aveVisDiffReflect / DataGlobalConstants::Pi;
    5593        1015 :         BackgroundLum = max(thisDaylightControl.IllumSetPoint(IL) * thisEnclDaylight.aveVisDiffReflect / DataGlobalConstants::Pi, BackgroundLum);
    5594             : 
    5595             :         // Loop over exterior windows associated with zone
    5596        2030 :         for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
    5597        1015 :             int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
    5598        1015 :             int WinShadingIndex = findWinShadingStatus(state, IWin);
    5599             :             // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor
    5600             :             // below, which is (0.2936)**0.6
    5601        1015 :             Real64 GTOT1 = 0.4794 * (std::pow(thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) *
    5602        1015 :                            std::pow(thisDaylightControl.SolidAngAtRefPtWtd(loop, IL), 0.8);
    5603        2030 :             Real64 GTOT2 = BackgroundLum + 0.07 * (std::sqrt(thisDaylightControl.SolidAngAtRefPt(loop, IL))) *
    5604        2030 :                                                thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL);
    5605        1015 :             GTOT += GTOT1 / (GTOT2 + 0.000001);
    5606             :         }
    5607             : 
    5608             :         // Glare index
    5609        1015 :         GLINDX(IL) = 10.0 * std::log10(GTOT + 0.000001);
    5610             :         // Set glare index to zero for GTOT < 1
    5611        1015 :         GLINDX(IL) = max(0.0, GLINDX(IL));
    5612             :     }
    5613        1015 : }
    5614             : 
    5615        4338 : void DayltgExtHorizIllum(EnergyPlusData &state,
    5616             :                          Array1A<Real64> HISK, // Horizontal illuminance from sky for different sky types
    5617             :                          Real64 &HISU          // Horizontal illuminance from sun for unit beam normal
    5618             : )
    5619             : {
    5620             : 
    5621             :     // SUBROUTINE INFORMATION:
    5622             :     //       AUTHOR         Fred Winkelmann
    5623             :     //       DATE WRITTEN   July 1997
    5624             :     //       MODIFIED       na
    5625             :     //       RE-ENGINEERED  na
    5626             : 
    5627             :     // PURPOSE OF THIS SUBROUTINE:
    5628             :     // Calculates exterior daylight illuminance.
    5629             : 
    5630             :     // METHODOLOGY EMPLOYED:
    5631             :     // Called by CalcDayltgCoefficients. Calculates illuminance
    5632             :     // on unobstructed horizontal surface by integrating
    5633             :     // over the luminance distribution of standard CIE skies.
    5634             :     // Calculates horizontal beam illuminance.
    5635             :     // REFERENCES:
    5636             :     // Based on DOE-2.1E subroutine DHILL.
    5637             : 
    5638             :     // Argument array dimensioning
    5639        4338 :     HISK.dim(4);
    5640             : 
    5641             :     // SUBROUTINE PARAMETER DEFINITIONS:
    5642        4338 :     Real64 const DTH((2.0 * DataGlobalConstants::Pi) / double(NTH)); // Sky integration azimuth stepsize (radians)
    5643        4338 :     Real64 const DPH(DataGlobalConstants::PiOvr2 / double(NPH));     // Sky integration altitude stepsize (radians)
    5644             : 
    5645             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5646             :     int IPH; // Altitude index for sky integration
    5647             :     int ITH; // Azimuth index for sky integration
    5648        4338 :     auto &PH = state.dataDaylightingManager->PH;
    5649        4338 :     auto &TH = state.dataDaylightingManager->TH;
    5650        4338 :     auto &SPHCPH = state.dataDaylightingManager->SPHCPH;
    5651             :     int ISky; // Sky type index
    5652             : 
    5653             :     // Integrate to obtain illuminance from sky.
    5654             :     // The contribution in lumens/m2 from a patch of sky at altitude PH and azimuth TH
    5655             :     // is L(TH,PH)*SIN(PH)*COS(PH)*DTH*DPH, where L(TH,PH) is the luminance
    5656             :     // of the patch in cd/m2.
    5657             :     //  Init
    5658        4338 :     if (state.dataDaylightingManager->DayltgExtHorizIllum_firstTime) {
    5659         558 :         for (IPH = 1; IPH <= NPH; ++IPH) {
    5660         496 :             PH(IPH) = (IPH - 0.5) * DPH;
    5661         496 :             SPHCPH(IPH) = std::sin(PH(IPH)) * std::cos(PH(IPH)); // DA = COS(PH)*DTH*DPH
    5662             :         }
    5663        1178 :         for (ITH = 1; ITH <= NTH; ++ITH) {
    5664        1116 :             TH(ITH) = (ITH - 0.5) * DTH;
    5665             :         }
    5666          62 :         state.dataDaylightingManager->DayltgExtHorizIllum_firstTime = false;
    5667             :     }
    5668             : 
    5669        4338 :     HISK = 0.0;
    5670             : 
    5671             :     // Sky integration
    5672       39042 :     for (IPH = 1; IPH <= NPH; ++IPH) {
    5673       34704 :         Real64 const PH_IPH(PH(IPH));
    5674       34704 :         Real64 const SPHCPH_IPH(SPHCPH(IPH));
    5675      659376 :         for (ITH = 1; ITH <= NTH; ++ITH) {
    5676      624672 :             Real64 const TH_ITH(TH(ITH));
    5677     3123360 :             for (ISky = 1; ISky <= 4; ++ISky) {
    5678     2498688 :                 HISK(ISky) += DayltgSkyLuminance(state, ISky, TH_ITH, PH_IPH) * SPHCPH_IPH;
    5679             :             }
    5680             :         }
    5681             :     }
    5682             : 
    5683       21690 :     for (ISky = 1; ISky <= 4; ++ISky) {
    5684       17352 :         HISK(ISky) *= DTH * DPH;
    5685             :     }
    5686             : 
    5687             :     // Direct solar horizontal illum (for unit direct normal illuminance)
    5688        4338 :     HISU = state.dataDaylightingManager->SPHSUN * 1.0;
    5689        4338 : }
    5690             : 
    5691     6749023 : void DayltgHitObstruction(EnergyPlusData &state,
    5692             :                           int const IHOUR,           // Hour number
    5693             :                           int const IWin,            // Window index
    5694             :                           Vector3<Real64> const &R1, // Origin of ray (m)
    5695             :                           Vector3<Real64> const &RN, // Unit vector along ray
    5696             :                           Real64 &ObTrans            // Product of solar transmittances of exterior obstructions
    5697             : )
    5698             : {
    5699             : 
    5700             :     // SUBROUTINE INFORMATION:
    5701             :     //       AUTHOR         Fred Winkelmann
    5702             :     //       DATE WRITTEN   July 1997
    5703             :     //       MODIFIED       FCW, May 2003: update list of surface classes that qualify as obstructions;
    5704             :     //                        add interior surfaces as possible obstructors;
    5705             :     //                        return from DO loop over surfaces as soon as any obstruction is hit;
    5706             :     //                      FCW, July 2003: change from returning whether an obstruction is hit or not
    5707             :     //                        to product of solar transmittances of hit obstructions.
    5708             :     //                      FCW, Nov 2003: remove interior surfaces as possible obstructors since there
    5709             :     //                        is now a separate check for interior obstructions; exclude windows and
    5710             :     //                        doors as obstructors since if they are obstructors their base surfaces will
    5711             :     //                        also be obstructors
    5712             :     //       RE-ENGINEERED  Sept 2015. Stuart Mentzer. Octree for performance.
    5713             : 
    5714             :     // PURPOSE OF THIS SUBROUTINE:
    5715             :     // Determines the product of the solar transmittances of the obstructions hit by a ray
    5716             :     // from R1 in the direction of vector RN.
    5717             : 
    5718             :     // REFERENCES:
    5719             :     // Based on DOE-2.1E subroutine DHITSH.
    5720             : 
    5721             :     // Using/Aliasing
    5722             :     using ScheduleManager::LookUpScheduleValue;
    5723             : 
    5724             :     // Local declarations
    5725             :     SurfaceClass IType; // Surface type/class:  mirror surfaces of shading surfaces
    5726     6749023 :     auto &DayltgHitObstructionHP = state.dataDaylightingManager->DayltgHitObstructionHP;
    5727             :     bool hit; // True iff a particular obstruction is hit
    5728             : 
    5729     6749023 :     ObTrans = 1.0;
    5730             : 
    5731     6749023 :     auto const &window(state.dataSurface->Surface(IWin));
    5732     6749023 :     auto const window_iBaseSurf(window.BaseSurf);
    5733             : 
    5734             :     // Loop over potentially obstructing surfaces, which can be building elements, like walls, or shadowing surfaces, like overhangs
    5735             :     // Building elements are assumed to be opaque
    5736             :     // A shadowing surface is opaque unless its transmittance schedule value is non-zero
    5737     6749023 :     if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
    5738             : 
    5739    56394959 :         for (int ISurf : state.dataSurface->AllShadowPossObstrSurfaceList) {
    5740    51868280 :             auto const &surface(state.dataSurface->Surface(ISurf));
    5741    51868280 :             IType = surface.Class;
    5742    51868280 :             if ((IType == SurfaceClass::Wall || IType == SurfaceClass::Roof || IType == SurfaceClass::Floor) && (ISurf != window_iBaseSurf)) {
    5743             :                 PierceSurface(state, ISurf, R1, RN, DayltgHitObstructionHP, hit);
    5744    93669802 :                 if (hit) { // Building element is hit (assumed opaque)
    5745       45108 :                     ObTrans = 0.0;
    5746       45108 :                     break;
    5747             :                 }
    5748     5010825 :             } else if (surface.IsShadowing) {
    5749             :                 PierceSurface(state, ISurf, R1, RN, DayltgHitObstructionHP, hit);
    5750      439172 :                 if (hit) { // Shading surface is hit
    5751             :                     // Get solar transmittance of the shading surface
    5752       57538 :                     Real64 const Trans(surface.SchedShadowSurfIndex > 0 ? LookUpScheduleValue(state, surface.SchedShadowSurfIndex, IHOUR, 1) : 0.0);
    5753       57538 :                     if (Trans < 1.e-6) {
    5754       57538 :                         ObTrans = 0.0;
    5755       57538 :                         break;
    5756             :                     } else {
    5757           0 :                         ObTrans *= Trans;
    5758             :                     }
    5759             :                 }
    5760             :             }
    5761             :         }
    5762             : 
    5763             :     } else { // Surface octree search
    5764             : 
    5765     2119698 :         auto const &window_base(window_iBaseSurf > 0 ? state.dataSurface->Surface(window_iBaseSurf) : window);
    5766     2119698 :         auto const window_base_p(&window_base);
    5767             : 
    5768             :         // Lambda function for the octree to test for surface hit and update transmittance if hit
    5769   494081565 :         auto solarTransmittance = [=, &state, &R1, &RN, &hit, &ObTrans](SurfaceData const &surface) -> bool {
    5770   299776131 :             if (!surface.IsShadowPossibleObstruction) return false; // Do Consider separate octree without filtered surfaces
    5771    66829301 :             auto const sClass(surface.Class);
    5772    66829301 :             if ((sClass == SurfaceClass::Wall || sClass == SurfaceClass::Roof || sClass == SurfaceClass::Floor) && (&surface != window_base_p)) {
    5773    64697724 :                 PierceSurface(surface, R1, RN, state.dataDaylightingManager->DayltgHitObstructionHP, hit);
    5774   129323145 :                 if (hit) { // Building element is hit (assumed opaque)
    5775       72303 :                     ObTrans = 0.0;
    5776       72303 :                     return true;
    5777             :                 }
    5778     2131577 :             } else if (surface.IsShadowing) {
    5779       46653 :                 PierceSurface(surface, R1, RN, state.dataDaylightingManager->DayltgHitObstructionHP, hit);
    5780       46653 :                 if (hit) { // Shading surface is hit
    5781             :                     // Get solar transmittance of the shading surface
    5782           0 :                     Real64 const Trans(surface.SchedShadowSurfIndex > 0 ? LookUpScheduleValue(state, surface.SchedShadowSurfIndex, IHOUR, 1) : 0.0);
    5783           0 :                     if (Trans < 1.e-6) {
    5784           0 :                         ObTrans = 0.0;
    5785           0 :                         return true;
    5786             :                     } else {
    5787           0 :                         ObTrans *= Trans;
    5788           0 :                         return ObTrans == 0.0;
    5789             :                     }
    5790             :                 }
    5791             :             }
    5792    66756998 :             return false;
    5793     2119698 :         };
    5794             : 
    5795             :         // Check octree surface candidates for hits: short circuits if zero transmittance reached
    5796     4239396 :         Vector3<Real64> const RN_inv(SurfaceOctreeCube::safe_inverse(RN));
    5797     2119698 :         state.dataHeatBalMgr->surfaceOctree.processSomeSurfaceRayIntersectsCube(state, R1, RN, RN_inv, solarTransmittance);
    5798             :     }
    5799     6749023 : }
    5800             : 
    5801     2742823 : void DayltgHitInteriorObstruction(EnergyPlusData &state,
    5802             :                                   int const IWin,            // Window index
    5803             :                                   Vector3<Real64> const &R1, // Origin of ray (m)
    5804             :                                   Vector3<Real64> const &R2, // Destination of ray (m)
    5805             :                                   bool &hit                  // True iff ray hits an obstruction
    5806             : )
    5807             : {
    5808             : 
    5809             :     // SUBROUTINE INFORMATION:
    5810             :     //       AUTHOR         Fred Winkelmann
    5811             :     //       DATE WRITTEN   July 1997
    5812             :     //       MODIFIED       na
    5813             :     //       RE-ENGINEERED  Sept 2015. Stuart Mentzer. Octree for performance.
    5814             : 
    5815             :     // PURPOSE OF THIS SUBROUTINE:
    5816             :     // This subroutine checks for interior obstructions between reference point and window element.
    5817             : 
    5818             :     // Preconditions
    5819     2742823 :     assert(magnitude(R2 - R1) > 0.0); // Protect normalize() from divide by zero
    5820             : 
    5821             :     // Local declarations
    5822             :     SurfaceClass IType; // Surface type/class
    5823             :     auto &DayltgHitInteriorObstructionHP =
    5824     2742823 :         state.dataDaylightingManager->DayltgHitInteriorObstructionHP; // Hit coordinates, if ray hits an obstruction
    5825     2742823 :     auto &RN = state.dataDaylightingManager->RN;                      // Unit vector along ray
    5826             : 
    5827     2742823 :     hit = false;
    5828     2742823 :     RN = (R2 - R1).normalize();         // Make unit vector
    5829     2742823 :     Real64 const d12(distance(R1, R2)); // Distance between R1 and R2
    5830             : 
    5831     2742823 :     auto const &window(state.dataSurface->Surface(IWin));
    5832     2742823 :     auto const window_Enclosure(window.SolarEnclIndex);
    5833     2742823 :     auto const window_iBaseSurf(window.BaseSurf);
    5834     2742823 :     auto const &window_base(window_iBaseSurf > 0 ? state.dataSurface->Surface(window_iBaseSurf) : window);
    5835     2742823 :     auto const window_base_iExtBoundCond(window_base.ExtBoundCond);
    5836             : 
    5837             :     // Loop over potentially obstructing surfaces, which can be building elements, like walls, or shadowing surfaces, like overhangs
    5838     2742823 :     if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
    5839             : 
    5840    70119371 :         for (int ISurf = 1; ISurf <= state.dataSurface->TotSurfaces; ++ISurf) {
    5841    67918288 :             auto const &surface(state.dataSurface->Surface(ISurf));
    5842    67918288 :             IType = surface.Class;
    5843   135507570 :             if ((surface.IsShadowing) ||                         // Shadowing surface
    5844   101381759 :                 ((surface.SolarEnclIndex == window_Enclosure) && // Wall/ceiling/floor is in same zone as window
    5845    24794251 :                  (IType == SurfaceClass::Wall || IType == SurfaceClass::Roof || IType == SurfaceClass::Floor) && (ISurf != window_iBaseSurf) &&
    5846             :                  (ISurf != window_base_iExtBoundCond))) // Exclude window's base or base-adjacent surfaces
    5847             :             {
    5848             :                 PierceSurface(state, ISurf, R1, RN, d12, DayltgHitInteriorObstructionHP, hit); // Check if R2-R1 segment pierces surface
    5849    11500623 :                 if (hit) break;                                                                // Segment pierces surface: Don't check the rest
    5850             :             }
    5851             :         }
    5852             : 
    5853             :     } else { // Surface octree search
    5854             : 
    5855      510418 :         auto const window_base_p(&window_base);
    5856      510418 :         auto const &window_base_adjacent(window_base_iExtBoundCond > 0 ? state.dataSurface->Surface(window_base_iExtBoundCond) : window_base);
    5857      510418 :         auto const window_base_adjacent_p(&window_base_adjacent);
    5858             : 
    5859             :         // Lambda function for the octree to test for surface hit
    5860    84495391 :         auto surfaceHit = [=, &R1, &hit, &state](SurfaceData const &surface) -> bool {
    5861    76735020 :             auto const sClass(surface.Class);
    5862   153463134 :             if ((surface.IsShadowing) ||                         // Shadowing surface
    5863    81531100 :                 ((surface.SolarEnclIndex == window_Enclosure) && // Surface is in same zone as window
    5864     5817126 :                  (sClass == SurfaceClass::Wall || sClass == SurfaceClass::Roof || sClass == SurfaceClass::Floor) && // Wall, ceiling/roof, or floor
    5865     5329908 :                  (&surface != window_base_p) && (&surface != window_base_adjacent_p))) // Exclude window's base or base-adjacent surfaces
    5866             :             {
    5867     4833302 :                 PierceSurface(surface,
    5868             :                               R1,
    5869             :                               RN,
    5870     2416651 :                               d12,
    5871     2416651 :                               state.dataDaylightingManager->DayltgHitInteriorObstructionHP,
    5872             :                               hit); // Check if R2-R1 segment pierces surface
    5873     2416651 :                 return hit;
    5874             :             } else {
    5875    74318369 :                 return false;
    5876             :             }
    5877     1020836 :         };
    5878             : 
    5879             :         // Check octree surface candidates until a hit is found, if any
    5880      510418 :         state.dataHeatBalMgr->surfaceOctree.hasSurfaceSegmentIntersectsCube(R1, R2, surfaceHit);
    5881             :     }
    5882     2742823 : }
    5883             : 
    5884       20412 : void DayltgHitBetWinObstruction(EnergyPlusData &state,
    5885             :                                 int const IWin1,           // Surface number of origin window
    5886             :                                 int const IWin2,           // Surface number of destination window
    5887             :                                 Vector3<Real64> const &R1, // Origin of ray (on IWin1) (m)
    5888             :                                 Vector3<Real64> const &R2, // Destination of ray (on IWin2) (m)
    5889             :                                 bool &hit                  // True iff ray hits an obstruction
    5890             : )
    5891             : {
    5892             : 
    5893             :     // SUBROUTINE INFORMATION:
    5894             :     //       AUTHOR         Fred Winkelmann
    5895             :     //       DATE WRITTEN   Feb 2004
    5896             :     //       MODIFIED na
    5897             :     //       RE-ENGINEERED  Sept 2015. Stuart Mentzer. Octree for performance.
    5898             : 
    5899             :     // PURPOSE OF THIS SUBROUTINE:
    5900             :     // Determines if a ray from point R1 on window IWin1 to point R2
    5901             :     // on window IWin2 hits an obstruction
    5902             : 
    5903             :     // Preconditions
    5904       20412 :     assert(magnitude(R2 - R1) > 0.0); // Protect normalize() from divide by zero
    5905             : 
    5906             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5907             :     SurfaceClass IType; // Surface type/class
    5908       20412 :     auto &DayltgHitBetWinObstructionHP = state.dataDaylightingManager->DayltgHitBetWinObstructionHP;
    5909       20412 :     auto &DayltgHitBetWinObstructionRN = state.dataDaylightingManager->DayltgHitBetWinObstructionRN;
    5910             : 
    5911       20412 :     hit = false;
    5912       20412 :     DayltgHitBetWinObstructionRN = (R2 - R1).normalize(); // Unit vector
    5913       20412 :     Real64 const d12(distance(R1, R2));                   // Distance between R1 and R2 (m)
    5914             : 
    5915       20412 :     auto const &window1(state.dataSurface->Surface(IWin1));
    5916       20412 :     auto const window1_iBaseSurf(window1.BaseSurf);
    5917       20412 :     auto const &window1_base(window1_iBaseSurf > 0 ? state.dataSurface->Surface(window1_iBaseSurf) : window1);
    5918       20412 :     auto const window1_base_iExtBoundCond(window1_base.ExtBoundCond);
    5919             : 
    5920       20412 :     auto const &window2(state.dataSurface->Surface(IWin2));
    5921       20412 :     auto const window2_Enclosure(window2.SolarEnclIndex);
    5922       20412 :     auto const window2_iBaseSurf(window2.BaseSurf);
    5923       20412 :     auto const &window2_base(window2_iBaseSurf > 0 ? state.dataSurface->Surface(window2_iBaseSurf) : window2);
    5924       20412 :     auto const window2_base_iExtBoundCond(window2_base.ExtBoundCond);
    5925             : 
    5926             :     // Preconditions
    5927             :     //        assert( window1.Zone == window2_Zone ); //? This is violated in PurchAirWithDoubleFacadeDaylighting so then why the asymmetry
    5928             :     // of  only checking for wall/roof/floor for window2 zone below?
    5929             : 
    5930             :     // Loop over potentially obstructing surfaces, which can be building elements, like walls, or shadowing surfaces, like overhangs
    5931       20412 :     if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
    5932             : 
    5933      612360 :         for (int ISurf = 1; ISurf <= state.dataSurface->TotSurfaces; ++ISurf) {
    5934      591948 :             auto const &surface(state.dataSurface->Surface(ISurf));
    5935      591948 :             IType = surface.Class;
    5936     1183896 :             if ((surface.IsShadowing) ||                          // Shadowing surface
    5937      755244 :                 ((surface.SolarEnclIndex == window2_Enclosure) && // Wall/ceiling/floor is in same zone as windows
    5938       81648 :                  (IType == SurfaceClass::Wall || IType == SurfaceClass::Roof || IType == SurfaceClass::Floor) && // Wall, ceiling/roof, or floor
    5939      122472 :                  (ISurf != window1_iBaseSurf) && (ISurf != window2_iBaseSurf) &&                                 // Exclude windows' base surfaces
    5940       81648 :                  (ISurf != window1_base_iExtBoundCond) && (ISurf != window2_base_iExtBoundCond))) // Exclude windows' base-adjacent surfaces
    5941             :             {
    5942             :                 PierceSurface(
    5943             :                     state, ISurf, R1, DayltgHitBetWinObstructionRN, d12, DayltgHitBetWinObstructionHP, hit); // Check if R2-R1 segment pierces surface
    5944       81648 :                 if (hit) break; // Segment pierces surface: Don't check the rest
    5945             :             }
    5946             :         }
    5947             : 
    5948             :     } else { // Surface octree search
    5949             : 
    5950           0 :         auto const window1_base_p(&window1_base);
    5951           0 :         auto const &window1_base_adjacent(window1_base_iExtBoundCond > 0 ? state.dataSurface->Surface(window1_base_iExtBoundCond) : window1_base);
    5952           0 :         auto const window1_base_adjacent_p(&window1_base_adjacent);
    5953             : 
    5954           0 :         auto const window2_base_p(&window2_base);
    5955           0 :         auto const &window2_base_adjacent(window2_base_iExtBoundCond > 0 ? state.dataSurface->Surface(window2_base_iExtBoundCond) : window2_base);
    5956           0 :         auto const window2_base_adjacent_p(&window2_base_adjacent);
    5957             : 
    5958             :         // Lambda function for the octree to test for surface hit
    5959           0 :         auto surfaceHit = [=, &R1, &hit, &state](SurfaceData const &surface) -> bool {
    5960           0 :             auto const sClass(surface.Class);
    5961           0 :             if ((surface.IsShadowing) ||                          // Shadowing surface
    5962           0 :                 ((surface.SolarEnclIndex == window2_Enclosure) && // Surface is in same zone as window
    5963           0 :                  (sClass == SurfaceClass::Wall || sClass == SurfaceClass::Roof || sClass == SurfaceClass::Floor) && // Wall, ceiling/roof, or floor
    5964           0 :                  (&surface != window1_base_p) && (&surface != window2_base_p) &&                                    // Exclude windows' base surfaces
    5965           0 :                  (&surface != window1_base_adjacent_p) && (&surface != window2_base_adjacent_p))) // Exclude windows' base-adjacent surfaces
    5966             :             {
    5967           0 :                 PierceSurface(surface,
    5968             :                               R1,
    5969           0 :                               state.dataDaylightingManager->DayltgHitBetWinObstructionRN,
    5970           0 :                               d12,
    5971           0 :                               state.dataDaylightingManager->DayltgHitBetWinObstructionHP,
    5972             :                               hit); // Check if R2-R1 segment pierces surface
    5973           0 :                 return hit;
    5974             :             } else {
    5975           0 :                 return false;
    5976             :             }
    5977           0 :         };
    5978             : 
    5979             :         // Check octree surface candidates until a hit is found, if any
    5980           0 :         state.dataHeatBalMgr->surfaceOctree.hasSurfaceSegmentIntersectsCube(R1, R2, surfaceHit);
    5981             :     }
    5982       20412 : }
    5983             : 
    5984     2568509 : void initDaylighting(EnergyPlusData &state, bool const initSurfaceHeatBalancefirstTime)
    5985             : {
    5986             :     // For daylit zones, calculate interior daylight illuminance at reference points and
    5987             :     // simulate lighting control system to get overhead electric lighting reduction
    5988             :     // factor due to daylighting.
    5989    24548537 :     for (int SurfNum : state.dataSurface->AllExtSolWindowSurfaceList) {
    5990    21980028 :         state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep = 0.0;
    5991    21980028 :         state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep = 0.0;
    5992             :     }
    5993             : 
    5994             :     // Reset space power reduction factors
    5995    21031250 :     for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
    5996    18462741 :         state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = 1.0;
    5997             :     }
    5998     3983633 :     for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
    5999     1415124 :         auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    6000     1415124 :         thisDaylightControl.PowerReductionFactor = 1.0;
    6001     1415124 :         if (state.dataEnvrn->PreviousSolRadPositive) {
    6002             :             // Reset to zero only if there was solar in the previous timestep, otherwise these are already zero
    6003      409689 :             thisDaylightControl.DaylIllumAtRefPt = 0.0;
    6004      409689 :             thisDaylightControl.GlareIndexAtRefPt = 0.0;
    6005      409689 :             state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex).InterReflIllFrIntWins =
    6006             :                 0.0; // inter-reflected illuminance from interior windows
    6007      949063 :             for (int refPtNum = 1; refPtNum <= thisDaylightControl.TotalDaylRefPoints; ++refPtNum) {
    6008      539374 :                 thisDaylightControl.TimeExceedingGlareIndexSPAtRefPt(refPtNum) = 0.0;
    6009      539374 :                 thisDaylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(refPtNum) = 0.0;
    6010             :             }
    6011             :         }
    6012             : 
    6013     1415124 :         if (state.dataEnvrn->SunIsUp && thisDaylightControl.TotalDaylRefPoints != 0) {
    6014      701021 :             if (initSurfaceHeatBalancefirstTime) DisplayString(state, "Computing Interior Daylighting Illumination");
    6015      701021 :             DayltgInteriorIllum(state, daylightCtrlNum);
    6016             :         }
    6017             :     }
    6018             : 
    6019             :     // The following report variables are valid only for daylit zones/enclosures without interior windows
    6020     2568509 :     if (state.dataEnvrn->SunIsUp) {
    6021    10548703 :         for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
    6022     9959597 :             if ((state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0) &&
    6023      698984 :                 (!state.dataViewFactor->EnclSolInfo(enclNum).HasInterZoneWindow)) {
    6024      697969 :                 auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
    6025     2082804 :                 for (int extWinNum = 1; extWinNum <= thisEnclDaylight.NumOfDayltgExtWins; ++extWinNum) {
    6026     1384835 :                     int IWin = thisEnclDaylight.DayltgExtWinSurfNums(extWinNum);
    6027     1384835 :                     int IS = 1;
    6028     2839720 :                     if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF &&
    6029     2691472 :                         (IS_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || state.dataSurface->SurfWinSolarDiffusing(IWin))) {
    6030       72766 :                         IS = 2;
    6031             :                     }
    6032     1384835 :                     int refPtCount = 0;
    6033     2775781 :                     for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
    6034     1390946 :                         auto &thisControl = state.dataDaylightingData->daylightControl(controlNum);
    6035     1390946 :                         if (thisControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
    6036     3539911 :                             for (int refPtNum = 1; refPtNum <= thisControl.TotalDaylRefPoints; ++refPtNum) {
    6037     2148965 :                                 ++refPtCount; // Count reference points across each daylighting control in the same enclosure
    6038     2148965 :                                 state.dataSurface->SurfaceWindow(IWin).IllumFromWinAtRefPtRep(refPtCount) =
    6039     2148965 :                                     thisControl.IllumFromWinAtRefPt(extWinNum, IS, refPtNum);
    6040     2148965 :                                 state.dataSurface->SurfaceWindow(IWin).LumWinFromRefPtRep(refPtCount) =
    6041     2148965 :                                     thisControl.SourceLumFromWinAtRefPt(extWinNum, IS, refPtNum);
    6042             :                             }
    6043             :                         }
    6044             :                     }
    6045             :                 }
    6046             :             }
    6047             :         }
    6048             :     }
    6049             : 
    6050     2568509 :     if (state.dataEnvrn->SunIsUp && (int)state.dataDaylightingDevicesData->TDDPipe.size() > 0) {
    6051        1015 :         if (initSurfaceHeatBalancefirstTime) DisplayString(state, "Computing Interior Daylighting Illumination for TDD pipes");
    6052        1015 :         DayltgInteriorTDDIllum(state);
    6053             :     }
    6054             : 
    6055     3983633 :     for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
    6056     1415124 :         auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    6057             : 
    6058             :         // RJH DElight Modification Begin - Call to DElight electric lighting control subroutine
    6059             :         // Check if the sun is up and the current Thermal Zone hosts a Daylighting:DElight object
    6060     2116145 :         if (state.dataEnvrn->SunIsUp && thisDaylightControl.TotalDaylRefPoints != 0 &&
    6061      701021 :             (thisDaylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight)) {
    6062        2037 :             int zoneNum = thisDaylightControl.zoneIndex;
    6063             :             // Call DElight interior illuminance and electric lighting control subroutine
    6064        2037 :             Real64 dPowerReducFac = 1.0; // Return value Electric Lighting Power Reduction Factor for current Zone and Timestep
    6065        2037 :             Real64 dHISKFFC = state.dataEnvrn->HISKF * DataDElight::LUX2FC;
    6066        2037 :             Real64 dHISUNFFC = state.dataEnvrn->HISUNF * DataDElight::LUX2FC;
    6067        2037 :             Real64 dSOLCOS1 = state.dataEnvrn->SOLCOS(1);
    6068        2037 :             Real64 dSOLCOS2 = state.dataEnvrn->SOLCOS(2);
    6069        2037 :             Real64 dSOLCOS3 = state.dataEnvrn->SOLCOS(3);
    6070        2037 :             Real64 dLatitude = state.dataEnvrn->Latitude;
    6071        2037 :             Real64 dCloudFraction = state.dataEnvrn->CloudFraction;
    6072             :             // Init Error Flag to 0 (no Warnings or Errors) (returned from DElight)
    6073        2037 :             int iErrorFlag = 0;
    6074             :             bool elOpened;
    6075             : 
    6076             :             int iReadStatus;       // Error File Read Status
    6077        4074 :             std::string cErrorMsg; // Each DElight Error Message can be up to 200 characters long
    6078             :             bool bEndofErrFile;    // End of Error File flag
    6079             : 
    6080        2037 :             DElightManagerF::DElightElecLtgCtrl(len(state.dataHeatBal->Zone(zoneNum).Name),
    6081        2037 :                                                 state.dataHeatBal->Zone(zoneNum).Name,
    6082             :                                                 dLatitude,
    6083             :                                                 dHISKFFC,
    6084             :                                                 dHISUNFFC,
    6085             :                                                 dCloudFraction,
    6086             :                                                 dSOLCOS1,
    6087             :                                                 dSOLCOS2,
    6088             :                                                 dSOLCOS3,
    6089             :                                                 dPowerReducFac,
    6090             :                                                 iErrorFlag);
    6091             :             // Check Error Flag for Warnings or Errors returning from DElight
    6092             :             // RJH 2008-03-07: If no warnings/errors then read refpt illuminances for standard output reporting
    6093        2037 :             if (iErrorFlag != 0) {
    6094             :                 // Open DElight Electric Lighting Error File for reading
    6095           0 :                 auto iDElightErrorFile = state.files.outputDelightDfdmpFilePath.try_open(state.files.outputControl.delightdfdmp);
    6096           0 :                 elOpened = iDElightErrorFile.good();
    6097             : 
    6098             :                 // Sequentially read lines in DElight Electric Lighting Error File
    6099             :                 // and process them using standard EPlus warning/error handling calls
    6100           0 :                 bEndofErrFile = false;
    6101           0 :                 iReadStatus = 0;
    6102           0 :                 while (!bEndofErrFile && elOpened) {
    6103           0 :                     auto cErrorLine = iDElightErrorFile.readLine();
    6104           0 :                     if (cErrorLine.eof) {
    6105           0 :                         bEndofErrFile = true;
    6106           0 :                         continue;
    6107             :                     }
    6108             : 
    6109             :                     // Is the current line a Warning message?
    6110           0 :                     if (has_prefix(cErrorLine.data, "WARNING: ")) {
    6111           0 :                         cErrorMsg = cErrorLine.data.substr(9);
    6112           0 :                         ShowWarningError(state, cErrorMsg);
    6113             :                     }
    6114             :                     // Is the current line an Error message?
    6115           0 :                     if (has_prefix(cErrorLine.data, "ERROR: ")) {
    6116           0 :                         cErrorMsg = cErrorLine.data.substr(7);
    6117           0 :                         ShowSevereError(state, cErrorMsg);
    6118           0 :                         iErrorFlag = 1;
    6119             :                     }
    6120             :                 }
    6121             : 
    6122             :                 // Close DElight Error File and delete
    6123             : 
    6124           0 :                 if (elOpened) {
    6125           0 :                     iDElightErrorFile.close();
    6126           0 :                     FileSystem::removeFile(iDElightErrorFile.filePath);
    6127             :                 }
    6128             :                 // If any DElight Error occurred then ShowFatalError to terminate
    6129           0 :                 if (iErrorFlag > 0) {
    6130           0 :                     ShowFatalError(state, "End of DElight Error Messages");
    6131             :                 }
    6132             :             } else { // RJH 2008-03-07: No errors
    6133             :                 // extract reference point illuminance values from DElight Electric Lighting dump file for reporting
    6134             :                 // Open DElight Electric Lighting Dump File for reading
    6135        4074 :                 auto iDElightErrorFile = state.files.outputDelightEldmpFilePath.try_open(state.files.outputControl.delighteldmp);
    6136        2037 :                 if (iDElightErrorFile.is_open()) {
    6137        2037 :                     elOpened = true;
    6138             :                 } else {
    6139           0 :                     elOpened = false;
    6140             :                 }
    6141             : 
    6142             :                 // Sequentially read lines in DElight Electric Lighting Dump File
    6143             :                 // and extract refpt illuminances for standard EPlus output handling
    6144        2037 :                 bEndofErrFile = false;
    6145        2037 :                 int iDElightRefPt = 0; // Reference Point number for reading DElight Dump File (eplusout.delighteldmp)
    6146        2037 :                 iReadStatus = 0;
    6147       14259 :                 while (!bEndofErrFile && elOpened) {
    6148        6111 :                     auto line = iDElightErrorFile.read<Real64>();
    6149        6111 :                     Real64 dRefPtIllum = line.data; // tmp var for reading RefPt illuminance
    6150        8148 :                     if (line.eof) {
    6151        2037 :                         bEndofErrFile = true;
    6152        2037 :                         continue;
    6153             :                     }
    6154             :                     // Increment refpt counter
    6155        4074 :                     ++iDElightRefPt;
    6156             :                     // Assure refpt index does not exceed number of refpts in this zone
    6157        4074 :                     if (iDElightRefPt <= thisDaylightControl.TotalDaylRefPoints) {
    6158        4074 :                         thisDaylightControl.DaylIllumAtRefPt(iDElightRefPt) = dRefPtIllum;
    6159             :                     }
    6160             :                 }
    6161             : 
    6162             :                 // Close DElight Electric Lighting Dump File and delete
    6163        2037 :                 if (elOpened) {
    6164        2037 :                     iDElightErrorFile.close();
    6165        2037 :                     FileSystem::removeFile(iDElightErrorFile.filePath);
    6166             :                 };
    6167             :             }
    6168             :             // Store the calculated total zone Power Reduction Factor due to DElight daylighting
    6169             :             // in the ZoneDaylight structure for later use
    6170        2037 :             thisDaylightControl.PowerReductionFactor = dPowerReducFac;
    6171             :         }
    6172             :         // RJH DElight Modification End - Call to DElight electric lighting control subroutine
    6173             :     }
    6174             : 
    6175     2568509 :     if (state.dataEnvrn->SunIsUp && !state.dataGlobal->DoingSizing) {
    6176      894397 :         DayltgInteriorMapIllum(state);
    6177             :     }
    6178    21015074 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    6179    36909306 :         for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    6180    18462741 :             auto &thisSpace = state.dataHeatBal->space(spaceNum);
    6181    40474011 :             for (int SurfNum = thisSpace.WindowSurfaceFirst; SurfNum <= thisSpace.WindowSurfaceLast; ++SurfNum) {
    6182    22011270 :                 state.dataSurface->SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0;
    6183    22011270 :                 if (IS_SHADED(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
    6184      171656 :                     state.dataSurface->SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0;
    6185             :                 } else {
    6186    21839614 :                     state.dataSurface->SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0;
    6187             :                 }
    6188             :             }
    6189             :         }
    6190             :     }
    6191     2568509 : }
    6192             : 
    6193     2568509 : void manageDaylighting(EnergyPlusData &state)
    6194             : {
    6195     2568509 :     if (state.dataEnvrn->SunIsUp && (state.dataEnvrn->BeamSolarRad + state.dataEnvrn->GndSolarRad + state.dataEnvrn->DifSolarRad > 0.0)) {
    6196     6666610 :         for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
    6197     5844507 :             if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0) {
    6198      408450 :                 if (state.dataViewFactor->EnclSolInfo(enclNum).HasInterZoneWindow) {
    6199        1015 :                     DayltgInterReflIllFrIntWins(state, enclNum);
    6200        2030 :                     for (int daylightCtrlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
    6201        1015 :                         auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    6202        1015 :                         DayltgGlareWithIntWins(state, thisDaylightControl.GlareIndexAtRefPt, enclNum);
    6203             :                     }
    6204             :                 }
    6205             :             }
    6206             :         }
    6207      822103 :         DayltgElecLightingControl(state);
    6208     1746406 :     } else if (state.dataDaylightingData->mapResultsToReport && state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) {
    6209          38 :         for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
    6210          20 :             ReportIllumMap(state, MapNum);
    6211             :         }
    6212          18 :         state.dataDaylightingData->mapResultsToReport = false;
    6213             :     }
    6214     2568509 : }
    6215             : 
    6216      701021 : void DayltgInteriorIllum(EnergyPlusData &state,
    6217             :                          int const daylightCtrlNum) // Daylighting:Controls number
    6218             : {
    6219             : 
    6220             :     // SUBROUTINE INFORMATION:
    6221             :     //       AUTHOR         Fred Winkelmann
    6222             :     //       DATE WRITTEN   July 1997
    6223             :     //       MODIFIED       March 2000, FCW: interpolate clear-sky daylight factors using
    6224             :     //                      HourOfDay/WeightNow and NextHour/WeightNextHour. Previously
    6225             :     //                      only HourOfDay was used
    6226             :     //                      Jan 2001, FCW: interpolate in slat angle for windows with blinds
    6227             :     //                      that have movable slats
    6228             :     //                      Oct 2002, LKL: changed interpolation steps to HourOfDay/WeightNow
    6229             :     //                      LastHour/WeightPreviousHour
    6230             :     //                      Aug 2003, FCW: fix bug that prevented shadingControlType =
    6231             :     //                      MEETDAYLIGHTILLUMINANCESETPOINT from working
    6232             :     //                      Mar 2004, FCW: fix bug in calc of illuminance setpoint contribution
    6233             :     //                      to background luminance: now it is divided by pi to give cd/m2
    6234             :     //                      Mar 2004, FCW: modify to handle daylighting through interior windows
    6235             :     //                      June 2009, TH: modified for thermochromic windows
    6236             :     //                      Jan 2010, TH (CR 7984): added iterations for switchable windows with shading
    6237             :     //                       control of MeetDaylightIlluminanceSetpoint and glare control is active
    6238             :     //                       Also corrected bugs (CR 7988) for switchable glazings not related to CR 7984
    6239             : 
    6240             :     // PURPOSE OF THIS SUBROUTINE:
    6241             :     // Using daylighting factors and exterior illuminance, determine
    6242             :     // the current-hour interior daylight illuminance and glare index
    6243             :     // at each reference point in a space. Deploy window shading window by window
    6244             :     // if glare control is active for window and if the acceptable glare index
    6245             :     // is exceeded at both reference points.
    6246             : 
    6247             :     // Called by InitSurfaceHeatBalance.
    6248             : 
    6249             :     // REFERENCES:
    6250             :     // Based on DOE-2.1E subroutine DINTIL.
    6251             : 
    6252      701021 :     Real64 constexpr tmpSWIterStep(0.05); // step of switching factor, assuming maximum of 20 switching states
    6253             : 
    6254             :     int NREFPT; // Number of daylighting reference points
    6255             :     int ISky;   // Sky type index
    6256             :     int ISky1;  // Sky type index values for averaging two sky types
    6257             :     int ISky2;
    6258      701021 :     auto &DFSUHR = state.dataDaylightingManager->DFSUHR;       // Sun daylight factor for bare/shaded window
    6259      701021 :     auto &BFSUHR = state.dataDaylightingManager->BFSUHR;       // Sun background luminance factor for bare/shaded window
    6260      701021 :     auto &SFSUHR = state.dataDaylightingManager->SFSUHR;       // Sun source luminance factor for bare/shaded window
    6261      701021 :     auto &HorIllSky = state.dataDaylightingManager->HorIllSky; // Horizontal illuminance for different sky types
    6262      701021 :     auto &SetPnt = state.dataDaylightingManager->SetPnt;       // Illuminance setpoint at reference points (lux)
    6263      701021 :     auto &GLRNDX = state.dataDaylightingManager->GLRNDX;       // Glare index at reference point
    6264      701021 :     auto &GLRNEW = state.dataDaylightingManager->GLRNEW;       // New glare index at reference point
    6265      701021 :     auto &SFSKHR = state.dataDaylightingManager->SFSKHR; // Sky source luminance factor for sky type (second index), bare/shaded window (first index)
    6266      701021 :     auto &DFSKHR = state.dataDaylightingManager->DFSKHR; // Sky daylight factor for sky type (second index), bare/shaded window (first index)
    6267             :     auto &BFSKHR =
    6268      701021 :         state.dataDaylightingManager->BFSKHR; // Sky background luminance factor for sky type (second index), bare/shaded window (first index)
    6269             : 
    6270      701021 :     auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    6271      701021 :     int enclNum = thisDaylightControl.enclIndex;
    6272      701021 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
    6273             :     int ISWFLG; // Switchable glazing flag: =1 if one or more windows in a zone
    6274             :     //  has switchable glazing that adjusts visible transmittance to just meet
    6275             :     //  daylighting setpoint; =0 otherwise.
    6276             :     int ICtrl;           // Window shading control pointer
    6277             :     Real64 VTRAT;        // Ratio between switched and unswitched visible transmittance at normal incidence
    6278             :     Real64 BACL;         // Window background (surround) luminance for glare calc (cd/m2)
    6279             :     Real64 SkyWeight;    // Weighting factor used to average two different sky types
    6280             :     Real64 HorIllSkyFac; // Ratio between horizontal illuminance from sky horizontal irradiance and
    6281             :     //   luminous efficacy and horizontal illuminance from averaged sky
    6282             :     bool GlareFlag; // True if maximum glare is exceeded
    6283             : 
    6284             :     Real64 VTRatio;  // VT (visible transmittance) ratio = VTNow / VTMaster
    6285             :     Real64 VTNow;    // VT of the time step actual TC window
    6286             :     Real64 VTMaster; // VT of the base/master TC window
    6287             : 
    6288             :     // Added variables for glare iterations for switchable glazings
    6289      701021 :     auto &tmpSWSL1 = state.dataDaylightingManager->tmpSWSL1;
    6290      701021 :     auto &tmpSWSL2 = state.dataDaylightingManager->tmpSWSL2;
    6291      701021 :     auto &tmpSWFactor = state.dataDaylightingManager->tmpSWFactor;
    6292      701021 :     auto &tmpMult = state.dataDaylightingManager->tmpMult;
    6293      701021 :     auto &GlareOK = state.dataDaylightingManager->GlareOK;
    6294      701021 :     auto &tmpIllumFromWinAtRefPt = state.dataDaylightingManager->tmpIllumFromWinAtRefPt;
    6295      701021 :     auto &tmpBackLumFromWinAtRefPt = state.dataDaylightingManager->tmpBackLumFromWinAtRefPt;
    6296      701021 :     auto &tmpSourceLumFromWinAtRefPt = state.dataDaylightingManager->tmpSourceLumFromWinAtRefPt;
    6297      701021 :     auto &blnCycle = state.dataDaylightingManager->blnCycle;
    6298             : 
    6299      701021 :     bool breakOuterLoop(false);
    6300      701021 :     bool continueOuterLoop(false);
    6301             : 
    6302      701021 :     if (thisDaylightControl.DaylightMethod != DataDaylighting::DaylightingMethod::SplitFlux) return;
    6303             : 
    6304      698984 :     NREFPT = thisDaylightControl.TotalDaylRefPoints;
    6305             : 
    6306             :     // Three arrays to save original clear and dark (fully switched) states'
    6307             :     //  zone/window daylighting properties.
    6308      698984 :     if (state.dataDaylightingManager->DayltgInteriorIllum_firstTime) {
    6309          62 :         int const d1(max(maxval(state.dataHeatBal->Zone, &ZoneData::NumSubSurfaces),
    6310         124 :                          maxval(state.dataDaylightingData->enclDaylight, &DataDaylighting::EnclDaylightCalc::NumOfDayltgExtWins)));
    6311          62 :         tmpIllumFromWinAtRefPt.allocate(d1, 2, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6312          62 :         tmpBackLumFromWinAtRefPt.allocate(d1, 2, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6313          62 :         tmpSourceLumFromWinAtRefPt.allocate(d1, 2, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6314             : 
    6315          62 :         SetPnt.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6316          62 :         state.dataDaylightingManager->DaylIllum.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6317          62 :         GLRNDX.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6318          62 :         GLRNEW.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
    6319             : 
    6320          62 :         state.dataDaylightingManager->DayltgInteriorIllum_firstTime = false;
    6321             :     }
    6322      698984 :     tmpIllumFromWinAtRefPt = 0.0;
    6323      698984 :     tmpBackLumFromWinAtRefPt = 0.0;
    6324      698984 :     tmpSourceLumFromWinAtRefPt = 0.0;
    6325             : 
    6326             :     // Initialize reference point illuminance and window background luminance
    6327     1618116 :     for (int IL = 1; IL <= NREFPT; ++IL) {
    6328      919132 :         SetPnt(IL) = thisDaylightControl.IllumSetPoint(IL);
    6329      919132 :         state.dataDaylightingManager->DaylIllum(IL) = 0.0;
    6330      919132 :         thisDaylightControl.BacLum(IL) = 0.0;
    6331             :     }
    6332             : 
    6333      698984 :     if (state.dataEnvrn->SkyClearness > 3.0) { // Sky is average of clear and clear turbid
    6334      331604 :         SkyWeight = min(1.0, (state.dataEnvrn->SkyClearness - 3.0) / 3.0);
    6335      331604 :         ISky1 = 1;
    6336      331604 :         ISky2 = 2;
    6337      367380 :     } else if (state.dataEnvrn->SkyClearness > 1.2) { // Sky is average of clear turbid and intermediate
    6338       71209 :         SkyWeight = (state.dataEnvrn->SkyClearness - 1.2) / 1.8;
    6339       71209 :         ISky1 = 2;
    6340       71209 :         ISky2 = 3;
    6341             :     } else { // Sky is average of intermediate and overcast
    6342      296171 :         SkyWeight = min(1.0, max(0.0, (state.dataEnvrn->SkyClearness - 1.0) / 0.2, (state.dataEnvrn->SkyBrightness - 0.05) / 0.4));
    6343      296171 :         ISky1 = 3;
    6344      296171 :         ISky2 = 4;
    6345             :     }
    6346             : 
    6347             :     // First loop over exterior windows associated with this zone. The window may be an exterior window in
    6348             :     // the zone or an exterior window in an adjacent zone that shares an interior window with the zone.
    6349             :     // Find contribution of each window to the daylight illum and to the glare numerator at each reference point.
    6350             :     // Use shading flags set in WindowShadingManager.
    6351     2090945 :     for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
    6352     1391961 :         int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
    6353             : 
    6354             :         // Added TH 6/29/2009 for thermochromic windows
    6355     1391961 :         VTRatio = 1.0;
    6356     1391961 :         if (NREFPT > 0) {
    6357     1391961 :             int const IConst = state.dataSurface->Surface(IWin).Construction;
    6358     1391961 :             if (state.dataConstruction->Construct(IConst).TCFlag == 1) {
    6359             :                 // For thermochromic windows, daylight and glare factors are always calculated
    6360             :                 //  based on the master construction. They need to be adjusted by the VTRatio, including:
    6361             :                 //  ZoneDaylight()%DaylIllFacSky, DaylIllFacSun, DaylIllFacSunDisk; DaylBackFacSky,
    6362             :                 //  DaylBackFacSun, DaylBackFacSunDisk, DaylSourceFacSky, DaylSourceFacSun, DaylSourceFacSunDisk
    6363           0 :                 VTNow = General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef);
    6364           0 :                 VTMaster =
    6365           0 :                     General::POLYF(1.0, state.dataConstruction->Construct(state.dataConstruction->Construct(IConst).TCMasterConst).TransVisBeamCoef);
    6366           0 :                 VTRatio = VTNow / VTMaster;
    6367             :             }
    6368             :         }
    6369             : 
    6370     2871465 :         bool ShadedOrDiffusingGlassWin = state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF &&
    6371     4080192 :                                          (IS_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || state.dataSurface->SurfWinSolarDiffusing(IWin));
    6372             : 
    6373             :         // Loop over reference points
    6374     3541941 :         for (int IL = 1; IL <= NREFPT; ++IL) {
    6375             : 
    6376             :             // Daylight factors for current sun position
    6377    10749900 :             for (ISky = 1; ISky <= 4; ++ISky) {
    6378             : 
    6379             :                 // ===Bare window===
    6380     8599920 :                 DFSKHR(1, ISky) =
    6381     8599920 :                     VTRatio *
    6382    17199840 :                     (state.dataGlobal->WeightNow * thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay, 1, ISky, IL, loop) +
    6383     8599920 :                      state.dataGlobal->WeightPreviousHour * thisDaylightControl.DaylIllFacSky(state.dataGlobal->PreviousHour, 1, ISky, IL, loop));
    6384             : 
    6385     8599920 :                 if (ISky == 1)
    6386     2149980 :                     DFSUHR(1) =
    6387     2149980 :                         VTRatio *
    6388     4299960 :                         (state.dataGlobal->WeightNow * (thisDaylightControl.DaylIllFacSun(state.dataGlobal->HourOfDay, 1, IL, loop) +
    6389     4299960 :                                                         thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 1, IL, loop)) +
    6390     4299960 :                          state.dataGlobal->WeightPreviousHour * (thisDaylightControl.DaylIllFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) +
    6391     2149980 :                                                                  thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop)));
    6392             : 
    6393     8599920 :                 BFSKHR(1, ISky) =
    6394     8599920 :                     VTRatio *
    6395    17199840 :                     (state.dataGlobal->WeightNow * thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay, 1, ISky, IL, loop) +
    6396     8599920 :                      state.dataGlobal->WeightPreviousHour * thisDaylightControl.DaylBackFacSky(state.dataGlobal->PreviousHour, 1, ISky, IL, loop));
    6397             : 
    6398     8599920 :                 if (ISky == 1)
    6399     2149980 :                     BFSUHR(1) =
    6400     6449940 :                         VTRatio * (state.dataGlobal->WeightNow * (thisDaylightControl.DaylBackFacSun(state.dataGlobal->HourOfDay, 1, IL, loop) +
    6401     4299960 :                                                                   thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->HourOfDay, 1, IL, loop)) +
    6402     4299960 :                                    state.dataGlobal->WeightPreviousHour *
    6403     4299960 :                                        (thisDaylightControl.DaylBackFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) +
    6404     2149980 :                                         thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop)));
    6405             : 
    6406     8599920 :                 SFSKHR(1, ISky) =
    6407     8599920 :                     VTRatio *
    6408    17199840 :                     (state.dataGlobal->WeightNow * thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay, 1, ISky, IL, loop) +
    6409     8599920 :                      state.dataGlobal->WeightPreviousHour * thisDaylightControl.DaylSourceFacSky(state.dataGlobal->PreviousHour, 1, ISky, IL, loop));
    6410             : 
    6411     8599920 :                 if (ISky == 1)
    6412     2149980 :                     SFSUHR(1) = VTRatio *
    6413     4299960 :                                 (state.dataGlobal->WeightNow * (thisDaylightControl.DaylSourceFacSun(state.dataGlobal->HourOfDay, 1, IL, loop) +
    6414     4299960 :                                                                 thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->HourOfDay, 1, IL, loop)) +
    6415     4299960 :                                  state.dataGlobal->WeightPreviousHour *
    6416     4299960 :                                      (thisDaylightControl.DaylSourceFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) +
    6417     2149980 :                                       thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop)));
    6418             : 
    6419     8599920 :                 if (ShadedOrDiffusingGlassWin) {
    6420             : 
    6421             :                     // ===Shaded window or window with diffusing glass===
    6422      376996 :                     if (!state.dataSurface->SurfWinMovableSlats(IWin)) {
    6423             :                         // Shade, screen, blind with fixed slats, or diffusing glass
    6424     1130988 :                         DFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow *
    6425      753992 :                                                          thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay, 2, ISky, IL, loop) +
    6426      753992 :                                                      state.dataGlobal->WeightPreviousHour *
    6427      376996 :                                                          thisDaylightControl.DaylIllFacSky(state.dataGlobal->PreviousHour, 2, ISky, IL, loop));
    6428             : 
    6429      376996 :                         if (ISky == 1) {
    6430       94249 :                             DFSUHR(2) =
    6431      188498 :                                 VTRatio * (state.dataGlobal->WeightNow * thisDaylightControl.DaylIllFacSun(state.dataGlobal->HourOfDay, 2, IL, loop) +
    6432      188498 :                                            state.dataGlobal->WeightPreviousHour *
    6433       94249 :                                                thisDaylightControl.DaylIllFacSun(state.dataGlobal->PreviousHour, 2, IL, loop));
    6434             : 
    6435       94249 :                             if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin))
    6436      282747 :                                 DFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow *
    6437      188498 :                                                             thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 2, IL, loop) +
    6438      188498 :                                                         state.dataGlobal->WeightPreviousHour *
    6439       94249 :                                                             thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 2, IL, loop));
    6440             :                         }
    6441             : 
    6442     1130988 :                         BFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow *
    6443      753992 :                                                          thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay, 2, ISky, IL, loop) +
    6444      753992 :                                                      state.dataGlobal->WeightPreviousHour *
    6445      376996 :                                                          thisDaylightControl.DaylBackFacSky(state.dataGlobal->PreviousHour, 2, ISky, IL, loop));
    6446             : 
    6447      376996 :                         if (ISky == 1) {
    6448       94249 :                             BFSUHR(2) = VTRatio *
    6449      188498 :                                         (state.dataGlobal->WeightNow * thisDaylightControl.DaylBackFacSun(state.dataGlobal->HourOfDay, 2, IL, loop) +
    6450      188498 :                                          state.dataGlobal->WeightPreviousHour *
    6451       94249 :                                              thisDaylightControl.DaylBackFacSun(state.dataGlobal->PreviousHour, 2, IL, loop));
    6452       94249 :                             if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin))
    6453      282747 :                                 BFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow *
    6454      188498 :                                                             thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->HourOfDay, 2, IL, loop) +
    6455      188498 :                                                         state.dataGlobal->WeightPreviousHour *
    6456       94249 :                                                             thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->PreviousHour, 2, IL, loop));
    6457             :                         }
    6458             : 
    6459     1130988 :                         SFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow *
    6460      753992 :                                                          thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay, 2, ISky, IL, loop) +
    6461      753992 :                                                      state.dataGlobal->WeightPreviousHour *
    6462      376996 :                                                          thisDaylightControl.DaylSourceFacSky(state.dataGlobal->PreviousHour, 2, ISky, IL, loop));
    6463             : 
    6464      376996 :                         if (ISky == 1) {
    6465      282747 :                             SFSUHR(2) = VTRatio * (state.dataGlobal->WeightNow *
    6466      188498 :                                                        thisDaylightControl.DaylSourceFacSun(state.dataGlobal->HourOfDay, 2, IL, loop) +
    6467      188498 :                                                    state.dataGlobal->WeightPreviousHour *
    6468       94249 :                                                        thisDaylightControl.DaylSourceFacSun(state.dataGlobal->PreviousHour, 2, IL, loop));
    6469       94249 :                             if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin))
    6470      282747 :                                 SFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow *
    6471      188498 :                                                             thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->HourOfDay, 2, IL, loop) +
    6472      188498 :                                                         state.dataGlobal->WeightPreviousHour *
    6473       94249 :                                                             thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 2, IL, loop));
    6474             :                         }
    6475             : 
    6476             :                     } else { // Blind with movable slats
    6477           0 :                         int SurfWinSlatsAngIndex = state.dataSurface->SurfWinSlatsAngIndex(IWin);
    6478           0 :                         Real64 SurfWinSlatsAngInterpFac = state.dataSurface->SurfWinSlatsAngInterpFac(IWin);
    6479           0 :                         Real64 DaylIllFacSkyNow = General::InterpGeneral(
    6480           0 :                             thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
    6481             :                             thisDaylightControl.DaylIllFacSky(
    6482           0 :                                 state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
    6483           0 :                             SurfWinSlatsAngInterpFac);
    6484           0 :                         Real64 DaylBackFacSkyNow = General::InterpGeneral(
    6485           0 :                             thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
    6486             :                             thisDaylightControl.DaylBackFacSky(
    6487           0 :                                 state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
    6488           0 :                             SurfWinSlatsAngInterpFac);
    6489           0 :                         Real64 DaylSourceFacSkyNow = General::InterpGeneral(
    6490           0 :                             thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
    6491             :                             thisDaylightControl.DaylSourceFacSky(
    6492           0 :                                 state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
    6493           0 :                             SurfWinSlatsAngInterpFac);
    6494           0 :                         Real64 DaylIllFacSkyPrev = General::InterpGeneral(
    6495           0 :                             thisDaylightControl.DaylIllFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
    6496             :                             thisDaylightControl.DaylIllFacSky(
    6497           0 :                                 state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
    6498           0 :                             SurfWinSlatsAngInterpFac);
    6499           0 :                         Real64 DaylBackFacSkyPrev = General::InterpGeneral(
    6500           0 :                             thisDaylightControl.DaylBackFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
    6501             :                             thisDaylightControl.DaylBackFacSky(
    6502           0 :                                 state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
    6503           0 :                             SurfWinSlatsAngInterpFac);
    6504           0 :                         Real64 DaylSourceFacSkyPrev = General::InterpGeneral(
    6505           0 :                             thisDaylightControl.DaylSourceFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
    6506             :                             thisDaylightControl.DaylSourceFacSky(
    6507           0 :                                 state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
    6508           0 :                             SurfWinSlatsAngInterpFac);
    6509             : 
    6510           0 :                         DFSKHR(2, ISky) =
    6511           0 :                             VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSkyNow + state.dataGlobal->WeightPreviousHour * DaylIllFacSkyPrev);
    6512           0 :                         BFSKHR(2, ISky) =
    6513           0 :                             VTRatio * (state.dataGlobal->WeightNow * DaylBackFacSkyNow + state.dataGlobal->WeightPreviousHour * DaylBackFacSkyPrev);
    6514           0 :                         SFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow * DaylSourceFacSkyNow +
    6515           0 :                                                      state.dataGlobal->WeightPreviousHour * DaylSourceFacSkyPrev);
    6516             : 
    6517           0 :                         if (ISky == 1) {
    6518           0 :                             Real64 DaylIllFacSunNow = General::InterpGeneral(
    6519           0 :                                 thisDaylightControl.DaylIllFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
    6520             :                                 thisDaylightControl.DaylIllFacSun(
    6521           0 :                                     state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6522           0 :                                 SurfWinSlatsAngInterpFac);
    6523           0 :                             Real64 DaylBackFacSunNow = General::InterpGeneral(
    6524           0 :                                 thisDaylightControl.DaylBackFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
    6525             :                                 thisDaylightControl.DaylBackFacSun(
    6526           0 :                                     state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6527           0 :                                 SurfWinSlatsAngInterpFac);
    6528           0 :                             Real64 DaylSourceFacSunNow = General::InterpGeneral(
    6529           0 :                                 thisDaylightControl.DaylSourceFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
    6530             :                                 thisDaylightControl.DaylSourceFacSun(
    6531           0 :                                     state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6532           0 :                                 SurfWinSlatsAngInterpFac);
    6533           0 :                             Real64 DaylIllFacSunPrev = General::InterpGeneral(
    6534           0 :                                 thisDaylightControl.DaylIllFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
    6535             :                                 thisDaylightControl.DaylIllFacSun(
    6536           0 :                                     state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6537           0 :                                 SurfWinSlatsAngInterpFac);
    6538           0 :                             Real64 DaylBackFacSunPrev = General::InterpGeneral(
    6539           0 :                                 thisDaylightControl.DaylBackFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
    6540             :                                 thisDaylightControl.DaylBackFacSun(
    6541           0 :                                     state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6542           0 :                                 SurfWinSlatsAngInterpFac);
    6543           0 :                             Real64 DaylSourceFacSunPrev = General::InterpGeneral(
    6544           0 :                                 thisDaylightControl.DaylSourceFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
    6545             :                                 thisDaylightControl.DaylSourceFacSun(
    6546           0 :                                     state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6547           0 :                                 SurfWinSlatsAngInterpFac);
    6548           0 :                             DFSUHR(2) =
    6549           0 :                                 VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunNow + state.dataGlobal->WeightPreviousHour * DaylIllFacSunPrev);
    6550           0 :                             BFSUHR(2) = VTRatio *
    6551           0 :                                         (state.dataGlobal->WeightNow * DaylBackFacSunNow + state.dataGlobal->WeightPreviousHour * DaylBackFacSunPrev);
    6552           0 :                             SFSUHR(2) = VTRatio * (state.dataGlobal->WeightNow * DaylSourceFacSunNow +
    6553           0 :                                                    state.dataGlobal->WeightPreviousHour * DaylSourceFacSunPrev);
    6554             : 
    6555             :                             // We add the contribution from the solar disk if slats do not block beam solar
    6556             :                             // TH CR 8010, DaylIllFacSunDisk needs to be interpolated
    6557           0 :                             if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin)) {
    6558           0 :                                 Real64 DaylIllFacSunDiskNow = General::InterpGeneral(
    6559           0 :                                     thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
    6560             :                                     thisDaylightControl.DaylIllFacSunDisk(
    6561           0 :                                         state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6562           0 :                                     SurfWinSlatsAngInterpFac);
    6563           0 :                                 Real64 DaylBackFacSunDiskNow = General::InterpGeneral(
    6564           0 :                                     thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
    6565             :                                     thisDaylightControl.DaylBackFacSunDisk(
    6566           0 :                                         state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6567           0 :                                     SurfWinSlatsAngInterpFac);
    6568           0 :                                 Real64 DaylSourceFacSunDiskNow = General::InterpGeneral(
    6569           0 :                                     thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
    6570             :                                     thisDaylightControl.DaylSourceFacSunDisk(
    6571           0 :                                         state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6572           0 :                                     SurfWinSlatsAngInterpFac);
    6573           0 :                                 Real64 DaylIllFacSunDiskPrev = General::InterpGeneral(
    6574           0 :                                     thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
    6575             :                                     thisDaylightControl.DaylIllFacSunDisk(
    6576           0 :                                         state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6577           0 :                                     SurfWinSlatsAngInterpFac);
    6578           0 :                                 Real64 DaylBackFacSunDiskPrev = General::InterpGeneral(
    6579           0 :                                     thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
    6580             :                                     thisDaylightControl.DaylBackFacSunDisk(
    6581           0 :                                         state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6582           0 :                                     SurfWinSlatsAngInterpFac);
    6583           0 :                                 Real64 DaylSourceFacSunDiskPrev = General::InterpGeneral(
    6584           0 :                                     thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
    6585             :                                     thisDaylightControl.DaylSourceFacSunDisk(
    6586           0 :                                         state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
    6587           0 :                                     SurfWinSlatsAngInterpFac);
    6588           0 :                                 DFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunDiskNow +
    6589           0 :                                                         state.dataGlobal->WeightPreviousHour * DaylIllFacSunDiskPrev);
    6590           0 :                                 BFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylBackFacSunDiskNow +
    6591           0 :                                                         state.dataGlobal->WeightPreviousHour * DaylBackFacSunDiskPrev);
    6592           0 :                                 SFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylSourceFacSunDiskNow +
    6593           0 :                                                         state.dataGlobal->WeightPreviousHour * DaylSourceFacSunDiskPrev);
    6594             :                             }
    6595             :                         }
    6596             :                     } // End of check if window has blind with movable slats
    6597             :                 }     // End of check if window is shaded or has diffusing glass
    6598             :             }         // End of sky type loop, ISky
    6599             : 
    6600             :             // Get illuminance at ref point from bare and shaded window by
    6601             :             // multiplying daylight factors by exterior horizontal illuminance
    6602             : 
    6603             :             // Adding 0.001 in the following prevents zero HorIllSky in early morning or late evening when sun
    6604             :             // is up in the present time step but GILSK(ISky,HourOfDay) and GILSK(ISky,NextHour) are both zero.
    6605    10749900 :             for (ISky = 1; ISky <= 4; ++ISky) {
    6606             :                 // HorIllSky(ISky) = WeightNow * GILSK(ISky,HourOfDay) + WeightNextHour * GILSK(ISky,NextHour) + 0.001
    6607    25799760 :                 HorIllSky(ISky) = state.dataGlobal->WeightNow * state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, ISky) +
    6608    17199840 :                                   state.dataGlobal->WeightPreviousHour * state.dataDaylightingManager->GILSK(state.dataGlobal->PreviousHour, ISky) +
    6609             :                                   0.001;
    6610             :             }
    6611             : 
    6612             :             // HISKF is current time step horizontal illuminance from sky, calculated in DayltgLuminousEfficacy,
    6613             :             // which is called in WeatherManager. HISUNF is current time step horizontal illuminance from sun,
    6614             :             // also calculated in DayltgLuminousEfficacy.
    6615             : 
    6616     2149980 :             HorIllSkyFac = state.dataEnvrn->HISKF / ((1 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1));
    6617             : 
    6618     4394209 :             for (int IS = 1; IS <= 2; ++IS) {
    6619     4299960 :                 if (IS == 2 && !ShadedOrDiffusingGlassWin) break;
    6620             : 
    6621     2244229 :                 thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL) =
    6622     4488458 :                     DFSUHR(IS) * state.dataEnvrn->HISUNF +
    6623     2244229 :                     HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + DFSKHR(IS, ISky2) * (1.0 - SkyWeight) * HorIllSky(ISky2));
    6624     2244229 :                 thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL) =
    6625     4488458 :                     BFSUHR(IS) * state.dataEnvrn->HISUNF +
    6626     2244229 :                     HorIllSkyFac * (BFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + BFSKHR(IS, ISky2) * (1.0 - SkyWeight) * HorIllSky(ISky2));
    6627             : 
    6628     2244229 :                 thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL) =
    6629     4488458 :                     SFSUHR(IS) * state.dataEnvrn->HISUNF +
    6630     2244229 :                     HorIllSkyFac * (SFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + SFSKHR(IS, ISky2) * (1.0 - SkyWeight) * HorIllSky(ISky2));
    6631             : 
    6632     2244229 :                 thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL) = max(thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL), 0.0);
    6633             : 
    6634             :                 // Added TH 1/21/2010 - save the original clear and dark (fully switched) states'
    6635             :                 //  zone daylighting values, needed for switachable glazings
    6636     2244229 :                 tmpIllumFromWinAtRefPt(loop, IS, IL) = thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
    6637     2244229 :                 tmpBackLumFromWinAtRefPt(loop, IS, IL) = thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
    6638     2244229 :                 tmpSourceLumFromWinAtRefPt(loop, IS, IL) = thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL);
    6639             :             } // IS
    6640             : 
    6641             :         } // End of reference point loop, IL
    6642             :     }     // End of first loop over exterior windows associated with this zone
    6643             : 
    6644             :     // Initialize flag that one or more windows has switchable glazing
    6645             :     // control that adjusts visible transmittance to just meet dayltg setpoint
    6646             :     // (and the window has not already been switched)
    6647      698984 :     ISWFLG = 0;
    6648             : 
    6649             :     // Second loop over windows. Find total daylight illuminance and background luminance
    6650             :     // for each ref pt from all exterior windows associated with the zone.  Use shading flags.
    6651             :     // This illuminance excludes contribution of inter-reflected illuminance produced by solar
    6652             :     // entering the zone through interior windows (which is calculated in DayltgInterReflIllFrIntWins.
    6653             : 
    6654     2090945 :     for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
    6655     1391961 :         int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
    6656     1391961 :         ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    6657     1391961 :         if (state.dataSurface->Surface(IWin).HasShadeControl && ISWFLG == 0) {
    6658       88929 :             if (state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
    6659         665 :                 state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened)
    6660         665 :                 ISWFLG = 1;
    6661             :         }
    6662             : 
    6663             :         // Determine if illuminance contribution is from bare or shaded window
    6664             :         //  For switchable glazings with shading control type of WSCT_MeetDaylIlumSetp,
    6665             :         //   the shading flag is initialized at GlassConditionallyLightened (20), and
    6666             :         //   the window is initialized at clear state: IS = 1
    6667             :         //  For other windows with glare control, the shading flag is initialized at >10, to be determined
    6668     1391961 :         int IS = findWinShadingStatus(state, IWin);
    6669             : 
    6670     3541941 :         for (int IL = 1; IL <= NREFPT; ++IL) {
    6671     2149980 :             state.dataDaylightingManager->DaylIllum(IL) += thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
    6672     2149980 :             thisDaylightControl.BacLum(IL) += thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
    6673             :         }
    6674             :     } // End of second window loop over exterior windows associated with this zone
    6675             : 
    6676             :     // Optical switching control (e.g. electrochromic glass) to adjust
    6677             :     // window's vis trans downward so daylight level equals or is as
    6678             :     // close as possible to the illuminance setpoint at first reference point.
    6679             :     // Assumes vis trans in the fully switched state is less than that in the
    6680             :     // unswitched state. Assumes some windows in a space may have this control and
    6681             :     // others not.
    6682             : 
    6683      698984 :     auto &DILLSW = state.dataDaylightingManager->DILLSW;
    6684      698984 :     auto &DILLUN = state.dataDaylightingManager->DILLUN;
    6685      698984 :     auto &previously_shaded = state.dataDaylightingManager->previously_shaded;
    6686             : 
    6687             :     // If daylight illuminance is above setpoint, allow switching
    6688      698984 :     if (ISWFLG != 0 && state.dataDaylightingManager->DaylIllum(1) > SetPnt(1)) {
    6689             : 
    6690             :         // Third loop over windows.  Get illuminance at ref pt 1 from
    6691             :         // windows that can be switched (DILLSW) with a group and those that can't (DILLUN).
    6692             :         // Windows that can be switched are initially in the unswitched state. For subsequent
    6693             :         // groups the windows in previous groups are fully switched.
    6694         385 :         DILLSW = 0.0;
    6695         385 :         DILLUN = 0.0;
    6696         385 :         previously_shaded = false;
    6697             : 
    6698         385 :         int count = 0;
    6699        1155 :         for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
    6700         770 :             std::vector<int> const &listOfExtWin = thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1];
    6701        2310 :             for (const auto IWin : listOfExtWin) {
    6702        1540 :                 ++count;
    6703             :                 // need to map back to the original order of the "loop" to not change all the other data structures
    6704        1540 :                 int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
    6705        1540 :                 if (loop > 0) {
    6706        1540 :                     ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    6707        1540 :                     int IS = findWinShadingStatus(state, IWin);
    6708        1540 :                     if (state.dataSurface->Surface(IWin).HasShadeControl) {
    6709        3850 :                         if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened &&
    6710        2310 :                             state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
    6711         770 :                             !previously_shaded(loop)) {
    6712         770 :                             DILLSW(igroup) += thisDaylightControl.IllumFromWinAtRefPt(loop, IS, 1);
    6713         770 :                             previously_shaded(loop) = true;
    6714             :                         } else {
    6715         770 :                             if (!previously_shaded(loop)) {
    6716         770 :                                 DILLUN(igroup) += thisDaylightControl.IllumFromWinAtRefPt(loop, IS, 1);
    6717             :                             } else {
    6718           0 :                                 DILLUN(igroup) += thisDaylightControl.IllumFromWinAtRefPt(loop, 2, 1); // use the shaded state if previously shaded
    6719             :                             }
    6720             :                         }
    6721             :                     }
    6722             :                 }
    6723             :             }
    6724             :         } // End of third window loop, IWin
    6725             : 
    6726             :         // Transmittance multiplier
    6727        1155 :         for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
    6728         770 :             state.dataDaylightingManager->ASETIL(igroup) = (SetPnt(1) - DILLUN(igroup)) / (DILLSW(igroup) + 0.00001);
    6729             :         }
    6730             : 
    6731             :         // ASETIL < 1 means there's enough light, so check for switching
    6732             : 
    6733             :         // Fourth loop over windows to determine which to switch
    6734             :         // iterate in the order that the shades are specified in WindowShadeControl
    6735         385 :         count = 0;
    6736         385 :         breakOuterLoop = false;
    6737         385 :         continueOuterLoop = false;
    6738        1155 :         for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
    6739             : 
    6740         770 :             std::vector<int> const &listOfExtWin = thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1];
    6741         770 :             auto &thisTVIS1 = state.dataDaylightingManager->TVIS1(igroup);
    6742         770 :             auto &thisTVIS2 = state.dataDaylightingManager->TVIS2(igroup);
    6743         770 :             auto &thisASETIL = state.dataDaylightingManager->ASETIL(igroup);
    6744             : 
    6745        2310 :             for (const auto IWin : listOfExtWin) {
    6746        1540 :                 ++count;
    6747             :                 // need to map back to the original order of the "loop" to not change all the other data structures
    6748        1540 :                 int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
    6749        1540 :                 if (loop > 0) {
    6750        1540 :                     if (thisASETIL < 1.0) {
    6751             : 
    6752        1022 :                         ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    6753        1022 :                         if (!state.dataSurface->Surface(IWin).HasShadeControl) {
    6754           0 :                             continueOuterLoop = true;
    6755           0 :                             continue;
    6756             :                         }
    6757        2044 :                         if (state.dataSurface->SurfWinShadingFlag(IWin) != WinShadingType::GlassConditionallyLightened ||
    6758         742 :                             state.dataSurface->WindowShadingControl(ICtrl).shadingControlType != WindowShadingControlType::MeetDaylIlumSetp) {
    6759         280 :                             continueOuterLoop = true;
    6760         280 :                             continue;
    6761             :                         }
    6762             : 
    6763         742 :                         int const IConst = state.dataSurface->SurfActiveConstruction(IWin);
    6764             :                         // Vis trans at normal incidence of unswitched glass
    6765        1484 :                         thisTVIS1 = General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
    6766         742 :                                     state.dataSurface->SurfWinGlazedFrac(IWin);
    6767             : 
    6768             :                         // Vis trans at normal incidence of fully switched glass
    6769         742 :                         int const IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
    6770        1484 :                         thisTVIS2 = General::POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
    6771         742 :                                     state.dataSurface->SurfWinGlazedFrac(IWin);
    6772             : 
    6773             :                         // Reset shading flag to indicate that window is shaded by being partially or fully switched
    6774         742 :                         state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing;
    6775             : 
    6776             :                         // ASETIL < 0 means illuminance from non-daylight-switchable windows exceeds setpoint,
    6777             :                         // so completely switch all daylight-switchable windows to minimize solar gain
    6778         742 :                         if (thisASETIL <= 0.0) {
    6779           0 :                             state.dataSurface->SurfWinSwitchingFactor(IWin) = 1.0;
    6780           0 :                             state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS2;
    6781             :                         } else {
    6782             :                             // Case where 0 < ASETIL < 1: darken glass in all
    6783             :                             // daylight-switchable windows to just meet illuminance setpoint
    6784             :                             // From this equation: SETPNT(1) = DILLUN + DILLSW/TVIS1 * VisTransSelected
    6785         742 :                             state.dataSurface->SurfWinVisTransSelected(IWin) = max(thisTVIS2, thisASETIL * thisTVIS1) + 0.000001;
    6786         742 :                             state.dataSurface->SurfWinSwitchingFactor(IWin) =
    6787         742 :                                 (thisTVIS1 - state.dataSurface->SurfWinVisTransSelected(IWin)) / (thisTVIS1 - thisTVIS2 + 0.000001);
    6788             :                             // bound switching factor between 0 and 1
    6789         742 :                             state.dataSurface->SurfWinSwitchingFactor(IWin) = min(1.0, state.dataSurface->SurfWinSwitchingFactor(IWin));
    6790         742 :                             state.dataSurface->SurfWinSwitchingFactor(IWin) = max(0.0, state.dataSurface->SurfWinSwitchingFactor(IWin));
    6791             :                         }
    6792             : 
    6793             :                         // Adjust daylight quantities based on ratio between switched and unswitched visible transmittance
    6794        1484 :                         for (int IL = 1; IL <= NREFPT; ++IL) {
    6795             :                             // DaylIllum(IL) and BacLum(IL) were calculated at the clear state: IS = 1,
    6796             :                             //  and need to adjusted for intermediate switched state at VisTransSelected: IS = 2
    6797         742 :                             int IS = 1;
    6798         742 :                             VTRAT = state.dataSurface->SurfWinVisTransSelected(IWin) / (thisTVIS1 + 0.000001);
    6799         742 :                             state.dataDaylightingManager->DaylIllum(IL) += (VTRAT - 1.0) * thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
    6800         742 :                             thisDaylightControl.BacLum(IL) += (VTRAT - 1.0) * thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
    6801             : 
    6802             :                             // Adjust illum, background illum and source luminance for this window in intermediate switched state
    6803             :                             //  for later use in the DayltgGlare calc because SurfaceWindow(IWin)%ShadingFlag = WinShadingType::SwitchableGlazing = 2
    6804         742 :                             IS = 2;
    6805         742 :                             VTRAT = state.dataSurface->SurfWinVisTransSelected(IWin) / (thisTVIS2 + 0.000001);
    6806         742 :                             thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpIllumFromWinAtRefPt(loop, IS, IL);
    6807         742 :                             thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpBackLumFromWinAtRefPt(loop, IS, IL);
    6808         742 :                             thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpSourceLumFromWinAtRefPt(loop, IS, IL);
    6809             :                         } // IL
    6810             :                     }     // ASETIL < 1
    6811             :                 }
    6812             :                 // If new daylight does not exceed the illuminance setpoint, done, no more checking other groups of switchable glazings
    6813        1260 :                 if (state.dataDaylightingManager->DaylIllum(1) <= SetPnt(1)) {
    6814           0 :                     breakOuterLoop = true;
    6815           0 :                     break;
    6816             :                 }
    6817             :             }
    6818         770 :             if (breakOuterLoop) break;
    6819         770 :             if (continueOuterLoop) continue;
    6820             :         } // End of fourth window loop
    6821             : 
    6822             :     } // ISWFLG /= 0 .AND. DaylIllum(1) > SETPNT(1)
    6823             : 
    6824             :     // loop over windows to do luminance based control
    6825      698984 :     int count = 0;
    6826      769706 :     for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
    6827      160981 :         for (int const IWin : thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1]) {
    6828       90259 :             ++count;
    6829       90259 :             ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    6830       90259 :             WindowShadingControlType shCtrlType = state.dataSurface->WindowShadingControl(ICtrl).shadingControlType;
    6831       90259 :             if (!((shCtrlType == WindowShadingControlType::HiSolar_HiLumin_OffMidNight) ||
    6832             :                   (shCtrlType == WindowShadingControlType::HiSolar_HiLumin_OffSunset) ||
    6833             :                   (shCtrlType == WindowShadingControlType::HiSolar_HiLumin_OffNextMorning)))
    6834       88929 :                 continue;
    6835             :             // need to map back to the original order of the "loop" to not change all the other data structures
    6836        1330 :             int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
    6837        1330 :             if (loop > 0) {
    6838        1330 :                 WinShadingType currentFlag = state.dataSurface->SurfWinShadingFlag(IWin);
    6839        1330 :                 WinShadingType ShType = state.dataSurface->WindowShadingControl(ICtrl).ShadingType;
    6840        1330 :                 if ((currentFlag == WinShadingType::IntShadeConditionallyOff) || (currentFlag == WinShadingType::GlassConditionallyLightened) ||
    6841         714 :                     (currentFlag == WinShadingType::ExtShadeConditionallyOff) || (currentFlag == WinShadingType::IntBlindConditionallyOff) ||
    6842         714 :                     (currentFlag == WinShadingType::ExtBlindConditionallyOff) || (currentFlag == WinShadingType::BGShadeConditionallyOff) ||
    6843             :                     (currentFlag == WinShadingType::BGBlindConditionallyOff)) {
    6844         616 :                     if (thisDaylightControl.SourceLumFromWinAtRefPt(loop, 1, 1) > state.dataSurface->WindowShadingControl(ICtrl).SetPoint2) {
    6845             :                         // shade on if luminance of this window is above setpoint
    6846           0 :                         state.dataSurface->SurfWinShadingFlag(IWin) = ShType;
    6847             :                         // update total illuminance and background luminance
    6848           0 :                         for (int IL = 1; IL <= NREFPT; ++IL) {
    6849           0 :                             state.dataDaylightingManager->DaylIllum(IL) +=
    6850           0 :                                 thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) - thisDaylightControl.IllumFromWinAtRefPt(loop, 1, IL);
    6851           0 :                             thisDaylightControl.BacLum(IL) +=
    6852           0 :                                 thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) - thisDaylightControl.BackLumFromWinAtRefPt(loop, 1, IL);
    6853             :                         }
    6854             :                     } else {
    6855             :                         // shade off if luminance is below setpoint
    6856         616 :                         state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff;
    6857             :                     }
    6858             :                 }
    6859             :             }
    6860             :         }
    6861             :     }
    6862             : 
    6863             :     // Calculate glare index at each reference point assuming the daylight illuminance setpoint is
    6864             :     //  met at both reference points, either by daylight or electric lights
    6865     1618116 :     for (int IL = 1; IL <= NREFPT; ++IL) {
    6866      919132 :         BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect / DataGlobalConstants::Pi,
    6867      919132 :                    thisDaylightControl.BacLum(IL));
    6868             :         // DayltgGlare uses ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,1,loop) for unshaded windows, and
    6869             :         //  ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for shaded windows
    6870      919132 :         DayltgGlare(state, IL, BACL, GLRNDX(IL), daylightCtrlNum);
    6871             :     }
    6872             : 
    6873             :     // Check if glare level is less than maximum allowed at each ref pt.  If maximum
    6874             :     // is exceeded at either ref pt, attempt to reduce glare to acceptable level by closing
    6875             :     // shading device on windows that have shades that have not already been closed.
    6876      698984 :     GlareFlag = false;
    6877     1476557 :     for (int IL = 1; IL <= NREFPT; ++IL) {
    6878      888728 :         if (GLRNDX(IL) > thisDaylightControl.MaxGlareallowed) {
    6879      111155 :             GlareFlag = true;
    6880      111155 :             break;
    6881             :         }
    6882             :     }
    6883             : 
    6884      698984 :     auto &WDAYIL = state.dataDaylightingManager->WDAYIL;
    6885      698984 :     auto &WBACLU = state.dataDaylightingManager->WBACLU;
    6886      698984 :     auto &RDAYIL = state.dataDaylightingManager->RDAYIL;
    6887      698984 :     auto &RBACLU = state.dataDaylightingManager->RBACLU;
    6888      698984 :     if (GlareFlag) {
    6889             :         // Glare is too high at a ref pt.  Loop through windows.
    6890      111155 :         int count = 0;
    6891             : 
    6892      111155 :         continueOuterLoop = false;
    6893      151011 :         for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
    6894             : 
    6895       53663 :             std::vector<int> const &listOfExtWin = thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1];
    6896       53663 :             auto &thisTVIS1 = state.dataDaylightingManager->TVIS1(igroup);
    6897       53663 :             auto &thisTVIS2 = state.dataDaylightingManager->TVIS1(igroup);
    6898             : 
    6899       53663 :             int countBeforeListOfExtWinLoop = count;
    6900       53663 :             bool atLeastOneGlareControlIsActive = false;
    6901             : 
    6902      124175 :             for (const auto IWin : listOfExtWin) {
    6903       70512 :                 ++count;
    6904             :                 // need to map back to the original order of the "loop" to not change all the other data structures
    6905       70512 :                 int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
    6906       70512 :                 if (loop > 0) {
    6907             :                     // Check if window is eligible for glare control
    6908             :                     // TH 1/21/2010. Switchable glazings already in partially switched state
    6909             :                     //  should be allowed to further dim to control glare
    6910             :                     // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) {
    6911      141024 :                     if (NOT_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(IWin)) ||
    6912       70512 :                         ANY_BLIND(state.dataSurface->SurfWinShadingFlag(IWin))) {
    6913           0 :                         continueOuterLoop = false;
    6914           0 :                         continue;
    6915             :                     }
    6916       70512 :                     ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    6917       70512 :                     if (!state.dataSurface->Surface(IWin).HasShadeControl) {
    6918           0 :                         continueOuterLoop = false;
    6919           0 :                         continue;
    6920             :                     }
    6921       70512 :                     if (state.dataSurface->WindowShadingControl(ICtrl).GlareControlIsActive) {
    6922       70512 :                         atLeastOneGlareControlIsActive = true;
    6923             : 
    6924             :                         // Illuminance (WDAYIL) and background luminance (WBACLU) contribution from this
    6925             :                         // window without shading (IS=1) and with shading (IS=2) for each ref pt
    6926             :                         //  For switchable windows, this may be partially switched rather than fully dark
    6927      141024 :                         for (int IL = 1; IL <= NREFPT; ++IL) {
    6928      211536 :                             for (int IS = 1; IS <= 2; ++IS) {
    6929      141024 :                                 WDAYIL(IS, IL, igroup) = thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
    6930      141024 :                                 WBACLU(IS, IL, igroup) = thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
    6931             :                             }
    6932             :                         }
    6933             : 
    6934             :                         // Recalculate illuminance and glare with shading on this window.
    6935             :                         //  For switchable glazings, this is the fully switched (dark) state
    6936      141024 :                         for (int IL = 1; IL <= NREFPT; ++IL) {
    6937       70512 :                             if (state.dataSurface->SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) {
    6938             :                                 // for non switchable glazings or switchable glazings not switched yet (still in clear state)
    6939             :                                 //  SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened
    6940       70512 :                                 RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(1, IL, igroup) + WDAYIL(2, IL, igroup);
    6941       70512 :                                 RBACLU(IL, igroup) = thisDaylightControl.BacLum(IL) - WBACLU(1, IL, igroup) + WBACLU(2, IL, igroup);
    6942             :                             } else {
    6943             :                                 // switchable glazings already in partially switched state when calc the RDAYIL(IL) & RBACLU(IL)
    6944           0 :                                 RDAYIL(IL, igroup) =
    6945           0 :                                     state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(2, IL, igroup) + tmpIllumFromWinAtRefPt(loop, 2, IL);
    6946           0 :                                 RBACLU(IL, igroup) = thisDaylightControl.BacLum(IL) - WBACLU(2, IL, igroup) + tmpBackLumFromWinAtRefPt(loop, 2, IL);
    6947             :                             }
    6948             :                         }
    6949             : 
    6950       70512 :                         if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened)
    6951       70512 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing;
    6952           0 :                         else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::IntShadeConditionallyOff)
    6953           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::IntShade;
    6954           0 :                         else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::ExtShadeConditionallyOff)
    6955           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ExtShade;
    6956           0 :                         else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::IntBlindConditionallyOff)
    6957           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::IntBlind;
    6958           0 :                         else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::ExtBlindConditionallyOff)
    6959           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ExtBlind;
    6960           0 :                         else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::BGShadeConditionallyOff)
    6961           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::BGShade;
    6962           0 :                         else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::BGBlindConditionallyOff)
    6963           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::BGBlind;
    6964             : 
    6965             :                         // For switchable glazings, it is switched to fully dark state,
    6966             :                         // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare
    6967       70512 :                         if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
    6968      141024 :                             for (int IL = 1; IL <= NREFPT; ++IL) {
    6969       70512 :                                 thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL);
    6970       70512 :                                 thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL);
    6971       70512 :                                 thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
    6972             :                             }
    6973             : 
    6974       70512 :                             int const IConst = state.dataSurface->SurfActiveConstruction(IWin);
    6975             :                             // Vis trans at normal incidence of unswitched glass
    6976      141024 :                             thisTVIS1 = General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
    6977       70512 :                                         state.dataSurface->SurfWinGlazedFrac(IWin);
    6978             : 
    6979             :                             // Vis trans at normal incidence of fully switched glass
    6980       70512 :                             int const IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
    6981      141024 :                             thisTVIS2 = General::POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
    6982       70512 :                                         state.dataSurface->SurfWinGlazedFrac(IWin);
    6983             :                         }
    6984             :                     }
    6985             :                 }
    6986             :             }
    6987       53663 :             if (continueOuterLoop) continue;
    6988             : 
    6989       53663 :             if (atLeastOneGlareControlIsActive) {
    6990             : 
    6991             :                 // Re-calc daylight and glare at shaded state. For switchable glazings, it is the fully dark state.
    6992      107326 :                 for (int IL = 1; IL <= NREFPT; ++IL) {
    6993       53663 :                     BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect / DataGlobalConstants::Pi,
    6994       53663 :                                RBACLU(IL, igroup));
    6995             :                     // DayltgGlare uses ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for shaded state
    6996       53663 :                     DayltgGlare(state, IL, BACL, GLRNEW(IL), daylightCtrlNum);
    6997             :                 }
    6998             : 
    6999             :                 // Check if the shading did not improve the glare conditions
    7000             :                 //
    7001             :                 // blnCycle when true resets the specific window to its non-shaded condition. A later comment says
    7002             :                 //      Shading this window has not improved the glare situation.
    7003             :                 //      Reset shading flag to no shading condition, go to next window.
    7004             :                 //
    7005             :                 // If the original glare was too high at all reference points and the new glare is lower at all reference points it is good, don't
    7006             :                 // reset it. For each reference point, if the original glare was too high but ok at other reference points and the glare gets
    7007             :                 // lower at the reference and stays ok at the other reference points it is good, don't reset it.
    7008             :                 //
    7009             :                 // The old comments when there were only two reference points were:
    7010             :                 //     One ref pt;  go to next window if glare has increased.
    7011             :                 //     Two ref pts.  There are three cases depending on glare values.
    7012             :                 //         (1) Initial glare too high at both ref pts.  Deploy shading on
    7013             :                 //             this window if this decreases glare at both ref pts.
    7014             :                 //         (2) Initial glare too high only at first ref pt.  Deploy shading
    7015             :                 //             on this window if glare at first ref pt decreases and
    7016             :                 //             glare at second ref pt stays below max.
    7017             :                 //         (3) Initial glare too high at second ref pt.  Deploy shading if glare
    7018             :                 //             at second ref pt decreases and glare at first ref pt stays below max.
    7019             :                 //
    7020             :                 // The approach taken is just to count the number of reference points that fulfill the individual requirements and see if it
    7021             :                 // covers all the reference points.
    7022       53663 :                 int numRefPtOldAboveMaxNewBelowOld = 0;
    7023       53663 :                 int numRefPtOldBelowMaxNewBelowMax = 0;
    7024      107326 :                 for (int IL = 1; IL <= NREFPT; ++IL) {
    7025       53663 :                     if (GLRNDX(IL) > thisDaylightControl.MaxGlareallowed && GLRNEW(IL) <= GLRNDX(IL)) ++numRefPtOldAboveMaxNewBelowOld;
    7026       53663 :                     if (GLRNDX(IL) <= thisDaylightControl.MaxGlareallowed && GLRNEW(IL) <= thisDaylightControl.MaxGlareallowed)
    7027           0 :                         ++numRefPtOldBelowMaxNewBelowMax;
    7028             :                 }
    7029       53663 :                 blnCycle = true;
    7030       53663 :                 if ((numRefPtOldAboveMaxNewBelowOld + numRefPtOldBelowMaxNewBelowMax) == NREFPT) blnCycle = false;
    7031             :             }
    7032             : 
    7033             :             // restore the count to the value prior to the last loop through the group of exterior windows
    7034       53663 :             count = countBeforeListOfExtWinLoop;
    7035       53663 :             breakOuterLoop = false;
    7036             : 
    7037      108954 :             for (const auto IWin : listOfExtWin) {
    7038       69098 :                 ++count;
    7039             :                 // need to map back to the original order of the "loop" to not change all the other data structures
    7040       69098 :                 int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
    7041       69098 :                 if (loop > 0) {
    7042             :                     // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) {
    7043      138196 :                     if (NOT_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(IWin)) ||
    7044       69098 :                         ANY_BLIND(state.dataSurface->SurfWinShadingFlag(IWin)))
    7045           0 :                         continue;
    7046             : 
    7047       69098 :                     ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    7048       69098 :                     if (!state.dataSurface->Surface(IWin).HasShadeControl) continue;
    7049       69098 :                     if (state.dataSurface->WindowShadingControl(ICtrl).GlareControlIsActive) {
    7050             : 
    7051             :                         // Shading this window has not improved the glare situation.
    7052             :                         // Reset shading flag to no shading condition, go to next window.
    7053       69098 :                         if (blnCycle) {
    7054             :                             //  for switchable glazings, reset properties to clear state or partial switched state?
    7055           0 :                             if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
    7056           0 :                                 state.dataSurface->SurfWinSwitchingFactor(IWin) = 0.0;
    7057           0 :                                 state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS1;
    7058             : 
    7059             :                                 // RESET properties for fully dark state
    7060           0 :                                 for (int IL = 1; IL <= NREFPT; ++IL) {
    7061           0 :                                     thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL);
    7062           0 :                                     thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
    7063           0 :                                     thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL);
    7064             :                                 }
    7065             :                             }
    7066             : 
    7067           0 :                             state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff;
    7068           0 :                             continue;
    7069             :                         }
    7070             : 
    7071             :                         // Shading this window has improved the glare situation.
    7072             :                         // Reset background luminance, glare index, and daylight illuminance at each ref pt.
    7073             :                         // For switchable glazings, this is fully switched, dark state
    7074      138196 :                         for (int IL = 1; IL <= NREFPT; ++IL) {
    7075       69098 :                             thisDaylightControl.BacLum(IL) = RBACLU(IL, igroup);
    7076       69098 :                             GLRNDX(IL) = GLRNEW(IL);
    7077       69098 :                             state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup);
    7078             :                         }
    7079             : 
    7080             :                         // TH comments (5/22/2009): seems for EC windows, if the calculated glare exceeds the max setpoint,
    7081             :                         //  the EC windows will be reset to fully dark state which significantly reduces the available daylight.
    7082             :                         //  A better way is to dim the EC windows as necessary just to meet the glare index, which will still
    7083             :                         //  provide more daylight while not exceeding the max glare! The question is then how to set the
    7084             :                         //  SwitchingFactor to just meet the glare index.
    7085             :                         //  This was addressed in CR 7984 for E+ 5.0. 1/19/2010
    7086             : 
    7087             :                         // If switchable glazing, set switching factor to 1: fully switched.
    7088       69098 :                         if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
    7089             :                             // tmpSWFactor0 = SurfaceWindow( IWin ).SwitchingFactor; // save original
    7090             :                             // switching  factor
    7091             :                             ////Unused Set but never used
    7092       69098 :                             state.dataSurface->SurfWinSwitchingFactor(IWin) = 1.0;
    7093       69098 :                             state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS2;
    7094             : 
    7095             :                             // restore fully dark values
    7096      138196 :                             for (int IL = 1; IL <= NREFPT; ++IL) {
    7097       69098 :                                 WDAYIL(2, IL, igroup) = tmpIllumFromWinAtRefPt(loop, 2, IL);
    7098       69098 :                                 WBACLU(2, IL, igroup) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
    7099       69098 :                                 thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL);
    7100       69098 :                                 thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
    7101       69098 :                                 thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL);
    7102             :                             }
    7103             :                         }
    7104             : 
    7105             :                         // Check if glare now acceptable at each ref pt.
    7106       69098 :                         GlareOK = false;
    7107       69098 :                         if (NREFPT == 1) {
    7108       69098 :                             if (GLRNDX(1) <= thisDaylightControl.MaxGlareallowed) GlareOK = true;
    7109           0 :                         } else if (NREFPT > 1) {
    7110           0 :                             if (GLRNDX(1) <= thisDaylightControl.MaxGlareallowed && GLRNDX(2) <= thisDaylightControl.MaxGlareallowed) GlareOK = true;
    7111             :                         }
    7112             : 
    7113       69098 :                         if (GlareOK) {
    7114       27614 :                             if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing &&
    7115       13807 :                                 state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp) {
    7116             :                                 // Added TH 1/14/2010
    7117             :                                 // Only for switchable glazings with MeetDaylightIlluminanceSetpoint control
    7118             :                                 // The glazing is in fully dark state, it might lighten a bit to provide more daylight
    7119             :                                 //  while meeting maximum discomfort glare index
    7120             :                                 // Iteration to find the right switching factor meeting the glare index
    7121             : 
    7122             :                                 // get fully dark state values
    7123           0 :                                 tmpSWSL1 = tmpSourceLumFromWinAtRefPt(loop, 2, 1);
    7124           0 :                                 if (NREFPT > 1) tmpSWSL2 = tmpSourceLumFromWinAtRefPt(loop, 2, 2);
    7125             : 
    7126             :                                 // use simple fixed step search in iteraction, can be improved in future
    7127           0 :                                 tmpSWFactor = 1.0 - tmpSWIterStep;
    7128           0 :                                 while (tmpSWFactor > 0) {
    7129             :                                     // calc new glare at new switching state
    7130           0 :                                     for (int IL = 1; IL <= NREFPT; ++IL) {
    7131           0 :                                         RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) +
    7132           0 :                                                              (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor);
    7133           0 :                                         RBACLU(IL, igroup) =
    7134           0 :                                             thisDaylightControl.BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor);
    7135           0 :                                         BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
    7136             :                                                        DataGlobalConstants::Pi,
    7137           0 :                                                    RBACLU(IL, igroup));
    7138             :                                         // needs to update SourceLumFromWinAtRefPt(IL,2,loop) before re-calc DayltgGlare
    7139           0 :                                         tmpMult = (thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor) / thisTVIS2;
    7140           0 :                                         if (IL == 1) {
    7141           0 :                                             thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSWSL1 * tmpMult;
    7142             :                                         } else {
    7143           0 :                                             thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSWSL2 * tmpMult;
    7144             :                                         }
    7145             :                                         // Calc new glare
    7146           0 :                                         DayltgGlare(state, IL, BACL, GLRNEW(IL), daylightCtrlNum);
    7147             :                                     }
    7148             : 
    7149             :                                     // Check whether new glare is OK
    7150           0 :                                     GlareOK = false;
    7151           0 :                                     if (NREFPT == 1) {
    7152           0 :                                         if (GLRNEW(1) <= thisDaylightControl.MaxGlareallowed) GlareOK = true;
    7153           0 :                                     } else if (NREFPT > 1) {
    7154           0 :                                         if (GLRNEW(1) <= thisDaylightControl.MaxGlareallowed && GLRNEW(2) <= thisDaylightControl.MaxGlareallowed)
    7155           0 :                                             GlareOK = true;
    7156             :                                     }
    7157             : 
    7158           0 :                                     if (GlareOK) {
    7159           0 :                                         if (tmpSWFactor >= tmpSWIterStep) {
    7160             :                                             // Continue to lighten the glazing
    7161           0 :                                             tmpSWFactor -= tmpSWIterStep;
    7162           0 :                                             continue;
    7163             :                                         } else {
    7164             :                                             // Glare still OK but glazing already in clear state, no more lighten
    7165           0 :                                             breakOuterLoop = true;
    7166           0 :                                             break;
    7167             :                                         }
    7168             :                                     } else {
    7169             :                                         // Glare too high, exit and use previous switching state
    7170           0 :                                         tmpSWFactor += tmpSWIterStep;
    7171           0 :                                         breakOuterLoop = true;
    7172           0 :                                         break;
    7173             :                                     }
    7174             :                                 }
    7175             : 
    7176             :                                 // Final re-calculation if needed
    7177           0 :                                 if (!GlareOK) {
    7178             :                                     // Glare too high, use previous state and re-calc
    7179           0 :                                     for (int IL = 1; IL <= NREFPT; ++IL) {
    7180           0 :                                         RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) +
    7181           0 :                                                              (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor);
    7182           0 :                                         RBACLU(IL, igroup) =
    7183           0 :                                             thisDaylightControl.BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor);
    7184           0 :                                         BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
    7185             :                                                        DataGlobalConstants::Pi,
    7186           0 :                                                    RBACLU(IL, igroup));
    7187             : 
    7188             :                                         // needs to update SourceLumFromWinAtRefPt(IL,2,IWin) before re-calc DayltgGlare
    7189           0 :                                         tmpMult = (thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor) / thisTVIS2;
    7190           0 :                                         if (IL == 1) {
    7191           0 :                                             thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, 1) = tmpSWSL1 * tmpMult;
    7192             :                                         } else {
    7193           0 :                                             thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, 2) = tmpSWSL2 * tmpMult;
    7194             :                                         }
    7195           0 :                                         DayltgGlare(state, IL, BACL, GLRNEW(IL), daylightCtrlNum);
    7196             :                                     }
    7197             :                                 }
    7198             : 
    7199             :                                 // Update final results
    7200           0 :                                 for (int IL = 1; IL <= NREFPT; ++IL) {
    7201           0 :                                     thisDaylightControl.BacLum(IL) = RBACLU(IL, igroup);
    7202           0 :                                     GLRNDX(IL) = GLRNEW(IL);
    7203           0 :                                     state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup);
    7204             : 
    7205           0 :                                     tmpMult = (thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor) / thisTVIS2;
    7206             :                                     // update report variables
    7207           0 :                                     thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL) * tmpMult;
    7208           0 :                                     thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL) * tmpMult;
    7209             :                                 }
    7210           0 :                                 state.dataSurface->SurfWinSwitchingFactor(IWin) = tmpSWFactor;
    7211           0 :                                 state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor;
    7212             : 
    7213             :                             } else {
    7214             :                                 // For un-switchable glazing or switchable glazing but not MeetDaylightIlluminaceSetpoint control,
    7215             :                                 // it is in shaded state and glare is ok - job is done, exit the window loop - IWin
    7216       13807 :                                 breakOuterLoop = true;
    7217       13807 :                                 break;
    7218             :                             }
    7219             :                         }
    7220             :                     } // End of check if window glare control is active
    7221             :                 }
    7222             :             } // end of for(auto IWin : listOfExtWin)
    7223       53663 :             if (breakOuterLoop) break;
    7224             :         } // for group
    7225             :     }     // GlareFlag
    7226             : 
    7227             :     // Loop again over windows and reset remaining shading flags that
    7228             :     // are 10 or higher (i.e., conditionally off) to off
    7229     1397968 :     for (int spaceNum : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).spaceIndexes) {
    7230      698984 :         auto &thisSpace = state.dataHeatBal->space(spaceNum);
    7231     2082797 :         for (int IWin = thisSpace.WindowSurfaceFirst; IWin <= thisSpace.WindowSurfaceLast; ++IWin) {
    7232     1383813 :             if (state.dataSurface->Surface(IWin).ExtBoundCond != ExternalEnvironment) continue;
    7233     1382798 :             bool anyGlareControl = BITF_TEST_ANY(BITF(state.dataSurface->SurfWinShadingFlag(IWin)),
    7234             :                                                  BITF(WinShadingType::IntShadeConditionallyOff) | BITF(WinShadingType::GlassConditionallyLightened) |
    7235             :                                                      BITF(WinShadingType::ExtShadeConditionallyOff) | BITF(WinShadingType::IntBlindConditionallyOff) |
    7236             :                                                      BITF(WinShadingType::ExtBlindConditionallyOff));
    7237     1382798 :             if (anyGlareControl) {
    7238       16877 :                 state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff;
    7239             :             }
    7240             :         }
    7241             :     }
    7242             : 
    7243             :     // Variables for reporting
    7244     1618116 :     for (int IL = 1; IL <= NREFPT; ++IL) {
    7245      919132 :         thisDaylightControl.DaylIllumAtRefPt(IL) = state.dataDaylightingManager->DaylIllum(IL);
    7246      919132 :         thisDaylightControl.GlareIndexAtRefPt(IL) = GLRNDX(IL);
    7247             : 
    7248             :         // added TH 12/2/2008
    7249      919132 :         if (GLRNDX(IL) > thisDaylightControl.MaxGlareallowed) {
    7250      120428 :             thisDaylightControl.TimeExceedingGlareIndexSPAtRefPt(IL) = state.dataGlobal->TimeStepZone; // fraction of hours
    7251             :         } else {
    7252      798704 :             thisDaylightControl.TimeExceedingGlareIndexSPAtRefPt(IL) = 0.0;
    7253             :         }
    7254             : 
    7255             :         // added TH 7/6/2009
    7256      919132 :         if (state.dataDaylightingManager->DaylIllum(IL) > thisDaylightControl.IllumSetPoint(IL)) {
    7257      414949 :             thisDaylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(IL) = state.dataGlobal->TimeStepZone; // fraction of hours
    7258             :         } else {
    7259      504183 :             thisDaylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(IL) = 0.0;
    7260             :         }
    7261             :     }
    7262             : }
    7263             : 
    7264        1015 : void DayltgInteriorTDDIllum(EnergyPlusData &state)
    7265             : {
    7266             : 
    7267             :     // SUBROUTINE INFORMATION:
    7268             :     //       AUTHOR         Linda Lawrie
    7269             :     //       DATE WRITTEN   October 2006
    7270             :     //       MODIFIED       na
    7271             :     //       RE-ENGINEERED  na
    7272             : 
    7273             :     // PURPOSE OF THIS SUBROUTINE:
    7274             :     // Calculate the TDD Pipe illuminance values
    7275             : 
    7276             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7277             :     int PipeNum;                // TDD pipe object number
    7278             :     Real64 TDDTransVisDiffNow;  // TDD diffuse visible transmittance at the current hour
    7279             :     Real64 TDDTransVisDiffPrev; // TDD diffuse visible transmittance at the previous hour
    7280        1015 :     auto &TDDTransVisDiff = state.dataDaylightingManager->TDDTransVisDiff;
    7281             :     int ISky;  // Sky type index
    7282             :     int ISky1; // Sky type index values for averaging two sky types
    7283             :     int ISky2;
    7284             :     Real64 SkyWeight; // Weighting factor used to average two different sky types
    7285             : 
    7286        1015 :     if (state.dataEnvrn->SkyClearness > 3.0) { // Sky is average of clear and clear turbid
    7287         518 :         SkyWeight = min(1.0, (state.dataEnvrn->SkyClearness - 3.0) / 3.0);
    7288         518 :         ISky1 = 1;
    7289         518 :         ISky2 = 2;
    7290         497 :     } else if (state.dataEnvrn->SkyClearness > 1.2) { // Sky is average of clear turbid and intermediate
    7291          91 :         SkyWeight = (state.dataEnvrn->SkyClearness - 1.2) / 1.8;
    7292          91 :         ISky1 = 2;
    7293          91 :         ISky2 = 3;
    7294             :     } else { // Sky is average of intermediate and overcast
    7295         406 :         SkyWeight = min(1.0, max(0.0, (state.dataEnvrn->SkyClearness - 1.0) / 0.2, (state.dataEnvrn->SkyBrightness - 0.05) / 0.4));
    7296         406 :         ISky1 = 3;
    7297         406 :         ISky2 = 4;
    7298             :     }
    7299             : 
    7300             :     // Calculate and report TDD visible transmittances
    7301        3045 :     for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
    7302             : 
    7303        2030 :         state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisBeam =
    7304        4060 :             state.dataGlobal->WeightNow * state.dataDaylightingManager->TDDTransVisBeam(state.dataGlobal->HourOfDay, PipeNum) +
    7305        2030 :             state.dataGlobal->WeightPreviousHour * state.dataDaylightingManager->TDDTransVisBeam(state.dataGlobal->PreviousHour, PipeNum);
    7306             : 
    7307       10150 :         for (ISky = 1; ISky <= 4; ++ISky) {
    7308        8120 :             if (state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->HourOfDay, ISky, PipeNum) > 0.0) {
    7309        7840 :                 TDDTransVisDiffNow = state.dataDaylightingManager->TDDFluxTrans(state.dataGlobal->HourOfDay, ISky, PipeNum) /
    7310        3920 :                                      state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->HourOfDay, ISky, PipeNum);
    7311             :             } else {
    7312        4200 :                 TDDTransVisDiffNow = 0.0;
    7313             :             }
    7314             : 
    7315        8120 :             if (state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->PreviousHour, ISky, PipeNum) > 0.0) {
    7316        7672 :                 TDDTransVisDiffPrev = state.dataDaylightingManager->TDDFluxTrans(state.dataGlobal->PreviousHour, ISky, PipeNum) /
    7317        3836 :                                       state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->PreviousHour, ISky, PipeNum);
    7318             :             } else {
    7319        4284 :                 TDDTransVisDiffPrev = 0.0;
    7320             :             }
    7321             : 
    7322        8120 :             TDDTransVisDiff(ISky) = state.dataGlobal->WeightNow * TDDTransVisDiffNow + state.dataGlobal->WeightPreviousHour * TDDTransVisDiffPrev;
    7323             :         } // ISky
    7324             : 
    7325        2030 :         state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisDiff =
    7326        2030 :             SkyWeight * TDDTransVisDiff(ISky1) + (1.0 - SkyWeight) * TDDTransVisDiff(ISky2);
    7327             :     } // PipeNum
    7328        1015 : }
    7329             : 
    7330      822103 : void DayltgElecLightingControl(EnergyPlusData &state)
    7331             : {
    7332             : 
    7333             :     // SUBROUTINE INFORMATION:
    7334             :     //       AUTHOR         Fred Winkelmann
    7335             :     //       DATE WRITTEN   July 1997
    7336             :     //       MODIFIED       Mar 2004, FCW: add inter-reflected illuminance from interior windows to DaylIllum
    7337             :     //                      Apr 2004, FCW: move CALL ReportIllumMap from DayltgInteriorIllum2 (DayltgInteriorMapIllum)
    7338             :     //                      Apr 2010, BG NREL: remove inter-reflected illuminance to stop double counting
    7339             :     //                      Aug 2012, BG NREL: added availability schedule logic
    7340             : 
    7341             :     // PURPOSE OF THIS SUBROUTINE:
    7342             :     // For a daylit space, determines lighting power reduction factor due to
    7343             :     // daylighting for different lighting control systems.
    7344             : 
    7345             :     // Called by InitSurfaceHeatBalance.
    7346             : 
    7347             :     // REFERENCES:
    7348             :     // Based on DOE-2.1E subroutine DLTSYS.
    7349             : 
    7350      822103 :     if (state.dataDaylightingData->daylightControl.empty()) {
    7351      741724 :         return;
    7352             :     }
    7353             :     // Reset space power reduction factors
    7354      901877 :     for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
    7355      821498 :         state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = 1.0;
    7356             :     }
    7357             : 
    7358      490068 :     for (auto &thisDaylightControl : state.dataDaylightingData->daylightControl) {
    7359             : 
    7360      409689 :         if (thisDaylightControl.DaylightMethod != DataDaylighting::DaylightingMethod::SplitFlux) {
    7361             :             // Set space power reduction factors
    7362        2037 :             if (thisDaylightControl.PowerReductionFactor < 1.0) {
    7363        2016 :                 if (thisDaylightControl.spaceIndex > 0) {
    7364             :                     // This is a space-level daylighting control
    7365        2016 :                     state.dataDaylightingData->spacePowerReductionFactor(thisDaylightControl.spaceIndex) = thisDaylightControl.PowerReductionFactor;
    7366             :                 } else {
    7367             :                     // This is a zone-level daylighting control
    7368           0 :                     for (int spaceNum : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).spaceIndexes) {
    7369           0 :                         state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = thisDaylightControl.PowerReductionFactor;
    7370             :                     }
    7371             :                 }
    7372             :             }
    7373        2037 :             continue;
    7374             :         }
    7375             : 
    7376             :         // Electric lighting power reduction factor for a given daylighting control
    7377      407652 :         Real64 &TotReduction = thisDaylightControl.PowerReductionFactor;
    7378      407652 :         TotReduction = 0.0;
    7379      407652 :         Real64 ZFTOT = 0.0;
    7380             : 
    7381             :         // check if scheduled to be available
    7382      407652 :         if (ScheduleManager::GetCurrentScheduleValue(state, thisDaylightControl.AvailSchedNum) > 0.0) {
    7383             : 
    7384             :             // Loop over reference points
    7385      934692 :             for (int IL = 1; IL <= thisDaylightControl.TotalDaylRefPoints; ++IL) {
    7386             : 
    7387             :                 // Total fraction of zone that is daylit
    7388      531170 :                 ZFTOT += thisDaylightControl.FracZoneDaylit(IL);
    7389             : 
    7390      531170 :                 state.dataDaylightingManager->DaylIllum(IL) = thisDaylightControl.DaylIllumAtRefPt(IL);
    7391      531170 :                 Real64 FL = 0.0;
    7392      531170 :                 if (state.dataDaylightingManager->DaylIllum(IL) < thisDaylightControl.IllumSetPoint(IL)) {
    7393      119567 :                     FL =
    7394      119567 :                         (thisDaylightControl.IllumSetPoint(IL) - state.dataDaylightingManager->DaylIllum(IL)) / thisDaylightControl.IllumSetPoint(IL);
    7395             :                 }
    7396             : 
    7397             :                 // BRANCH ON LIGHTING SYSTEM TYPE
    7398      531170 :                 auto LSYSTP = thisDaylightControl.LightControlType;
    7399      531170 :                 Real64 FP = 0.0;
    7400      531170 :                 if (LSYSTP != DataDaylighting::LtgCtrlType::Stepped) {
    7401             :                     // Continuously dimmable system with linear power curve
    7402             :                     // Fractional output power required to meet setpoint
    7403      287580 :                     FP = 1.0;
    7404             :                     // LIGHT-CTRL-TYPE = CONTINUOUS (LSYSTP = 1)
    7405      287580 :                     if (FL <= thisDaylightControl.MinLightFraction) {
    7406      218464 :                         FP = thisDaylightControl.MinPowerFraction;
    7407             :                     }
    7408             :                     // LIGHT-CTRL-TYPE = CONTINUOUS/OFF (LSYSTP = 3)
    7409      287580 :                     if (FL <= thisDaylightControl.MinLightFraction && LSYSTP == DataDaylighting::LtgCtrlType::ContinuousOff) {
    7410      201452 :                         FP = 0.0;
    7411             :                     }
    7412      287580 :                     if (FL > thisDaylightControl.MinLightFraction && FL < 1.0) {
    7413      137424 :                         FP = (FL + (1.0 - FL) * thisDaylightControl.MinPowerFraction - thisDaylightControl.MinLightFraction) /
    7414       68712 :                              (1.0 - thisDaylightControl.MinLightFraction);
    7415             :                     }
    7416             : 
    7417             :                 } else { // LSYSTP = 2
    7418             :                     // Stepped system
    7419      243590 :                     FP = 0.0;
    7420             :                     // #9060: Use a tolerance, otherwise at very low (< 1e-12) daylighting conditions, you can get a multiplier > 1.0
    7421      243590 :                     if (state.dataDaylightingManager->DaylIllum(IL) < 0.1) {
    7422        3508 :                         FP = 1.0;
    7423      240082 :                     } else if (state.dataDaylightingManager->DaylIllum(IL) < thisDaylightControl.IllumSetPoint(IL)) {
    7424       32509 :                         FP = double(int(thisDaylightControl.LightControlSteps * FL) + 1) / double(thisDaylightControl.LightControlSteps);
    7425             :                     }
    7426             : 
    7427      243590 :                     if (thisDaylightControl.LightControlProbability < 1.0) {
    7428             :                         // Manual operation.  Occupant sets lights one level too high a fraction of the time equal to
    7429             :                         // 1. - ZoneDaylight(ZoneNum)%LightControlProbability.  RANDOM_NUMBER returns a random number
    7430             :                         // between 0 and 1.
    7431             :                         Real64 XRAN;
    7432           0 :                         RANDOM_NUMBER(XRAN);
    7433           0 :                         if (XRAN >= thisDaylightControl.LightControlProbability) {
    7434             :                             // Set level one higher
    7435           0 :                             if (FP < 1.0) {
    7436           0 :                                 FP += (1.0 / double(thisDaylightControl.LightControlSteps));
    7437             :                             }
    7438             :                         } // XRAN
    7439             :                     }     // Light Control Probability < 1
    7440             :                 }         // Lighting System Type
    7441             : 
    7442      531170 :                 thisDaylightControl.RefPtPowerReductionFactor(IL) = FP;
    7443             : 
    7444             :                 // Accumulate net ltg power reduction factor for entire zone
    7445      531170 :                 TotReduction += thisDaylightControl.RefPtPowerReductionFactor(IL) * thisDaylightControl.FracZoneDaylit(IL);
    7446             : 
    7447             :             } // End of loop over reference points, IL
    7448             : 
    7449             :             // Correct for fraction of zone (1-ZFTOT) not controlled by
    7450             :             // the reference points.  For this fraction (which is usually zero),
    7451             :             // the electric lighting is unaffected and the power reduction
    7452             :             // factor is therefore 1.0.
    7453      403522 :             TotReduction += (1.0 - ZFTOT);
    7454             :         } else { // controls not currently available
    7455        4130 :             TotReduction = 1.0;
    7456             :         }
    7457             : 
    7458             :         // Set space power reduction factors
    7459      407652 :         if (thisDaylightControl.spaceIndex > 0) {
    7460             :             // This is a space-level daylighting control
    7461      407652 :             state.dataDaylightingData->spacePowerReductionFactor(thisDaylightControl.spaceIndex) = TotReduction;
    7462             :         } else {
    7463             :             // This is a zone-level daylighting control
    7464           0 :             for (int spaceNum : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).spaceIndexes) {
    7465           0 :                 state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = TotReduction;
    7466             :             }
    7467             :         }
    7468             :     } // end daylighting control loop
    7469             : 
    7470             :     //  IF(DataDaylighting::TotIllumMaps > 0 .and. .not. DoingSizing .and. .not. WarmupFlag .and. .not. KickoffSimulation) THEN
    7471       80379 :     if ((int)state.dataDaylightingData->IllumMap.size() > 0 && !state.dataGlobal->DoingSizing && !state.dataGlobal->WarmupFlag) {
    7472        2842 :         for (int mapNum = 1; mapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapNum) {
    7473        1509 :             if (state.dataGlobal->TimeStep == 1) state.dataDaylightingData->mapResultsToReport = false;
    7474      139209 :             for (int IL = 1; IL <= state.dataDaylightingData->IllumMapCalc(mapNum).TotalMapRefPoints; ++IL) {
    7475      137700 :                 state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPtHr(IL) +=
    7476      137700 :                     state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPt(IL) / double(state.dataGlobal->NumOfTimeStepInHour);
    7477      137700 :                 if (state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPtHr(IL) > 0.0) {
    7478      137700 :                     state.dataDaylightingData->mapResultsToReport = true;
    7479      137700 :                     state.dataDaylightingData->mapResultsReported = true;
    7480             :                 }
    7481             :             }
    7482        1509 :             ReportIllumMap(state, mapNum);
    7483        1509 :             if (state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) {
    7484         252 :                 state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPtHr = 0.0;
    7485         252 :                 state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPt = 0.0;
    7486             :             }
    7487             :         }
    7488             :     }
    7489             : }
    7490             : 
    7491      533394 : Real64 DayltgGlarePositionFactor(Real64 &X, // Lateral and vertical distance of luminous window element from
    7492             :                                  Real64 &Y)
    7493             : {
    7494             : 
    7495             :     // SUBROUTINE INFORMATION:
    7496             :     //       AUTHOR         Fred Winkelmann
    7497             :     //       DATE WRITTEN   July 1997
    7498             :     //       MODIFIED       na
    7499             :     //       RE-ENGINEERED  na
    7500             : 
    7501             :     // PURPOSE OF THIS SUBROUTINE:
    7502             :     // by table interpolation, evaluates the
    7503             :     // Hopkinson position factor used in glare calculation
    7504             :     // (Hopkinson, Petherbridge, AND Longmore -- Daylighting,
    7505             :     // London, 1966, PP 307, 323).  X (Y) is the lateral
    7506             :     // (vertical) distance of luminous window element from
    7507             :     // horizontal line of vision, divided by horizontal distance
    7508             :     // from eye of observer. The array PF contains values of
    7509             :     // the position factor for X = 0, 0.5, 1.0, 1.5, 2.0, 2.5,
    7510             :     // and 3.0 and Y = 0, 0.5, 1.0, 1.5, 2.0. Called by CalcDayltgCoefficients.
    7511             : 
    7512             :     // REFERENCES:
    7513             :     // Based on DOE-2.1E subroutine DPFAC.
    7514             : 
    7515             :     // Return value
    7516             :     Real64 DayltgGlarePositionFactor; // Position factor
    7517             : 
    7518             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    7519             :     int IX; // Lateral and vertical displacement indices
    7520             :     int IY;
    7521             :     Real64 X1; // Lateral and vertical displacement ratios
    7522             :     Real64 Y1;
    7523             :     Real64 FA; // Intermediate variables
    7524             :     Real64 FB;
    7525             : 
    7526             :     // Position factor array
    7527             :     static constexpr std::array<std::array<Real64, 7>, 5> PF = {{
    7528             :         {1.00, 0.492, 0.226, 0.128, 0.081, 0.061, 0.057},
    7529             :         {0.123, 0.119, 0.065, 0.043, 0.029, 0.026, 0.023},
    7530             :         {0.019, 0.026, 0.019, 0.016, 0.014, 0.011, 0.011},
    7531             :         {0.008, 0.008, 0.008, 0.008, 0.008, 0.006, 0.006},
    7532             :         {0.0, 0.0, 0.003, 0.003, 0.003, 0.003, 0.003},
    7533             :     }};
    7534             : 
    7535      533394 :     DayltgGlarePositionFactor = 0.0;
    7536      533394 :     if (X < 0.0 || X >= 3.0) return DayltgGlarePositionFactor;
    7537      182986 :     if (Y < 0.0 || Y >= 2.0) return DayltgGlarePositionFactor;
    7538             : 
    7539      182433 :     IX = 1 + int(2.0 * X);
    7540      182433 :     IY = 1 + int(2.0 * Y);
    7541      182433 :     X1 = 0.5 * double(IX - 1);
    7542      182433 :     Y1 = 0.5 * double(IY - 1);
    7543      182433 :     FA = PF[IY - 1][IX - 1] + 2.0 * (X - X1) * (PF[IY - 1][IX] - PF[IY - 1][IX - 1]);
    7544      182433 :     FB = PF[IY][IX - 1] + 2.0 * (X - X1) * (PF[IY][IX] - PF[IY][IX - 1]);
    7545      182433 :     DayltgGlarePositionFactor = FA + 2.0 * (Y - Y1) * (FB - FA);
    7546             : 
    7547      182433 :     return DayltgGlarePositionFactor;
    7548             : }
    7549             : 
    7550      319816 : void DayltgInterReflectedIllum(EnergyPlusData &state,
    7551             :                                int const ISunPos, // Sun position counter; used to avoid calculating various
    7552             :                                int const IHR,     // Hour of day
    7553             :                                int const enclNum, // Daylighting enclosure index
    7554             :                                int const IWin     // Window index
    7555             : )
    7556             : {
    7557             : 
    7558             :     // SUBROUTINE INFORMATION:
    7559             :     //       AUTHOR         Fred Winkelmann
    7560             :     //       DATE WRITTEN   July 1997
    7561             :     //       MODIFIED       FCW December 1998
    7562             :     //                      FCW June 2001: Add blind calculations
    7563             :     //                      FCW Jan 2001: Add blinds with movable slats
    7564             :     //                      FCW Jan 2003: Add between-glass blinds
    7565             :     //                      FCW Jul 2003: account for transmittance of shading surfaces
    7566             :     //                       (previously these were assumed opaque even if transmittance schedule
    7567             :     //                        value was non-zero)
    7568             :     //                      FCW Aug 2003: modify initialization of WLUMSK from WLUMSK = 0. TO
    7569             :     //                        WLUMSK(:,:,IHR) = 0. Otherwise values calculated in previous
    7570             :     //                        call are incorrectly zeroed. Result was that window luminance with
    7571             :     //                        shade or blind included only contribution from first window element
    7572             :     //                        in window element loop in CalcDayltgCoefficients, thus seriously
    7573             :     //                        undercalculating window luminance for windows with more than one
    7574             :     //                        window element. Similarly, modified initialization of WLUMSU from
    7575             :     //                        WLUMSU = 0. to WLUMSU(:,IHR) = 0., and of WLUMSUdisk from
    7576             :     //                        WLUMSUdisk = 0. to WLUMSUdisk(:,IHR) = 0.
    7577             :     //                      PGE Aug 2003: Add daylighting shelves.
    7578             :     //                      FCW Nov 2003: Add beam solar and sky solar reflected from obstructions;
    7579             :     //                                    add beam solar reflected from ground accounting for obstructions.
    7580             :     //                      FCW Nov 2003: increase NPHMAX from 9 to 10 to avoid rays with altitude angle = 0
    7581             :     //                                    for vertical surfaces.
    7582             :     //                      FCW Nov 2003: fix the expression for min and max limits of azimuth; old expression
    7583             :     //                                    broke down for window normals with negative altitude angle
    7584             :     //                      FCW Nov 2003: add specular reflection from exterior obstructions
    7585             :     //                      FCW Apr 2004: add light well efficiency multiplying window transmittance
    7586             :     //                      FCW Apr 2004: add diffusing glazing
    7587             :     //                      RAR (FSEC)  May 2006: add exterior window screen
    7588             :     //                      B. Griffith NREL April 2010: CR7869 add adjacent zone area if window is not on this zone
    7589             :     //                                    apply interior window transmission and blocking to beam transmission from ext win
    7590             :     //       RE-ENGINEERED  na
    7591             : 
    7592             :     // PURPOSE OF THIS SUBROUTINE:
    7593             :     // Called from CalcDayltgCoefficients for each window and reference point in a daylit
    7594             :     // space, for each sun position. Calculates illuminance (EINTSK and EINTSU) at reference point due
    7595             :     // to internally reflected light by integrating to determine the amount of flux from
    7596             :     // sky and ground (and beam reflected from obstructions) transmitted through
    7597             :     // the center of the window and then reflecting this
    7598             :     // light from the inside surfaces of the space.  The "split-flux" method is used
    7599             :     // (Lynes, Principles of Natural Lighting, 1968).  EINT is determined for
    7600             :     // different sky types and for window with and without shades, screens or blinds.
    7601             :     // Also finds luminance (WLUMSK and WLUMSU) of window with shade or blind, &
    7602             :     // or with diffusing glass, for different sky types.
    7603             : 
    7604             :     // METHODOLOGY EMPLOYED:na
    7605             : 
    7606             :     // REFERENCES:
    7607             :     // Based on DOE-2.1E subroutine DREFLT.
    7608             : 
    7609             :     // Using/Aliasing
    7610             :     using DaylightingDevices::TransTDD;
    7611             :     using General::InterpProfAng;
    7612             :     using General::POLYF;
    7613             : 
    7614             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7615             :     // In the following I,J arrays:
    7616             :     // I = sky type;
    7617             :     // J = 1 for bare window, 2 and above for window with shade or blind.
    7618      319816 :     auto &ZSK = state.dataDaylightingManager->ZSK;
    7619      319816 :     auto &U = state.dataDaylightingManager->U;
    7620      319816 :     auto &DayltgInterReflectedIllumNearestHitPt = state.dataDaylightingManager->DayltgInterReflectedIllumNearestHitPt;
    7621      319816 :     auto &DayltgInterReflectedIllumObsHitPt = state.dataDaylightingManager->DayltgInterReflectedIllumObsHitPt;
    7622      319816 :     auto &DayltgInterReflectedIllumGroundHitPt = state.dataDaylightingManager->DayltgInterReflectedIllumGroundHitPt;
    7623      319816 :     auto &SkyObstructionMult = state.dataDaylightingManager->SkyObstructionMult;
    7624      319816 :     auto &FLFWSK = state.dataDaylightingManager->FLFWSK;
    7625      319816 :     auto &FLFWSU = state.dataDaylightingManager->FLFWSU;
    7626      319816 :     auto &FLFWSUdisk = state.dataDaylightingManager->FLFWSUdisk;
    7627      319816 :     auto &FLCWSK = state.dataDaylightingManager->FLCWSK;
    7628      319816 :     auto &FLCWSU = state.dataDaylightingManager->FLCWSU;
    7629      319816 :     auto &TransMult = state.dataDaylightingManager->TransMult;
    7630      319816 :     auto &DayltgInterReflectedIllumTransBmBmMult = state.dataDaylightingManager->DayltgInterReflectedIllumTransBmBmMult;
    7631      319816 :     auto &ObTransM = state.dataDaylightingManager->ObTransM;
    7632             : 
    7633             :     int ISky; // Sky type index: 1=clear, 2=clear turbid,
    7634             :     //  3=intermediate, 4=overcast
    7635             :     Real64 DPH; // Sky/ground element altitude and azimuth increments (radians)
    7636             :     Real64 DTH;
    7637             :     int IPH; // Sky/ground element altitude and azimuth indices
    7638             :     int ITH;
    7639             :     Real64 PH; // Sky/ground element altitude and azimuth (radians)
    7640             :     Real64 TH;
    7641             :     Real64 SPH; // Sine and cosine of PH
    7642             :     Real64 CPH;
    7643             :     Real64 PHMIN; // Limits of altitude integration (radians)
    7644             :     Real64 PHMAX;
    7645             :     Real64 ThMin; // Limits of azimuth integration (radians)
    7646             :     Real64 ThMax;
    7647             :     Real64 PhWin; // Altitude, azimuth angle of window normal (radians)
    7648             :     Real64 ThWin;
    7649             :     Real64 ACosTanTan; // ACOS(-TAN(Ph)*TAN(PhWin))
    7650             :     Real64 DA;         // CPH*DTH*DPH
    7651             :     Real64 COSB;       // Cosine of angle of incidence of light from sky or ground
    7652             :     Real64 TVISBR;     // Transmittance of window without shading at COSB
    7653             :     //  (times light well efficiency, if appropriate)
    7654             :     Real64 ZSU;
    7655             :     //  element for clear and overcast sky
    7656             :     Real64 ObTrans; // Product of solar transmittances of obstructions seen by a light ray
    7657             :     // unused  REAL(r64)         :: HitPointLumFrClearSky     ! Luminance of obstruction from clear sky (cd/m2)
    7658             :     // unused  REAL(r64)         :: HitPointLumFrOvercSky     ! Luminance of obstruction from overcast sky (cd/m2)
    7659             :     // unused  REAL(r64)         :: HitPointLumFrSun          ! Luminance of obstruction from sun (cd/m2)
    7660             :     int ICtrl;       // Window control pointer
    7661             :     int JSH;         // Shading index: JSH=1 is bare window, JSH=2 is shaded window
    7662             :     Real64 COSBSun;  // Cosine of angle of incidence of direct sun on window
    7663             :     Real64 TVISBSun; // Window's visible transmittance at COSBSun
    7664             :     //  (times light well efficiency, if appropriate)
    7665             :     Real64 ZSU1; // Transmitted direct normal illuminance (lux)
    7666             :     //  CHARACTER(len=32) :: ShType                    ! Window shading device type
    7667             :     bool ShadeOn;                // True if exterior or interior window shade present
    7668             :     bool BlindOn;                // True if exterior or interior window blind present
    7669             :     bool ScreenOn;               // True if exterior window screen present
    7670             :     int BlNum;                   // Blind number
    7671             :                                  //        int ScNum; // Screen number //Unused Set but never used
    7672             :     int PipeNum;                 // TDD pipe object number
    7673             :     int ShelfNum;                // Daylighting shelf object number
    7674             :     int InShelfSurf;             // Inside daylighting shelf surface number
    7675             :     int OutShelfSurf;            // Outside daylighting shelf surface number
    7676             :     Real64 TransBlBmDiffFront;   // Isolated blind vis beam-diffuse front transmittance
    7677             :     Real64 TransScBmDiffFront;   // Isolated screen vis beam-diffuse front transmittance
    7678             :     Real64 TransScDiffDiffFront; // Isolated screen vis diffuse-diffuse front transmittance
    7679             :     Real64 ReflGlDiffDiffBack;   // Bare glazing system vis diffuse back reflectance
    7680             :     Real64 ReflGlDiffDiffFront;  // Bare glazing system vis diffuse front reflectance
    7681             :     Real64 ReflBlBmDiffFront;    // Isolated blind vis beam-diffuse front reflectance
    7682             :     Real64 TransBlDiffDiffFront; // Isolated blind vis diffuse-diffuse front transmittance
    7683             :     Real64 ReflBlDiffDiffFront;  // Isolated blind vis diffuse-diffuse front reflectance
    7684             :     Real64 ReflBlDiffDiffBack;   // Isolated blind vis diffuse-diffuse back reflectance
    7685             :     Real64 ReflScDiffDiffBack;   // Isolated screen vis diffuse-diffuse back reflectance
    7686             :     Real64 ProfAng;              // Solar profile angle (radians)
    7687             :     Real64 SlatAng;              // Blind slat angle
    7688             :     int JB;                      // Blind slat angle index
    7689             :     Real64 t1;                   // Beam-beam vis trans of bare glass layers 1 and 2
    7690             :     Real64 t2;
    7691             :     Real64 td2; // Diffuse-diffuse vis trans of bare glass layers 2 and 3
    7692             :     Real64 td3;
    7693             :     Real64 rbd1; // Beam-diffuse back vis reflectance of bare glass layers 1 and 2
    7694             :     Real64 rbd2;
    7695             :     Real64 rfd2; // Beam-diffuse front vis reflectance of bare glass layers 2 and 3
    7696             :     Real64 rfd3;
    7697             :     Real64 tfshBd;     // Beam-diffuse front vis trans of bare blind
    7698             :     Real64 rfshB;      // Beam-diffuse front vis reflectance of bare blind
    7699             :     Real64 tfshd;      // Diffuse-diffuse front vis trans of bare blind
    7700             :     Real64 rbshd;      // Diffuse-diffuse back vis reflectance of bare blind
    7701             :     Real64 ZSUObsRefl; // Illuminance on window from beam solar reflected by an
    7702             :     //  obstruction (for unit beam normal illuminance)
    7703             :     int NearestHitSurfNum;  // Surface number of nearest obstruction
    7704             :     int NearestHitSurfNumX; // Surface number to use when obstruction is a shadowing surface
    7705             :     Real64 LumAtHitPtFrSun; // Luminance at hit point on obstruction from solar reflection
    7706             :     //  for unit beam normal illuminance (cd/m2)
    7707             :     Real64 SunObstructionMult; // = 1 if sun hits a ground point; otherwise = 0
    7708             :     Real64 Alfa;               // Direction angles for ray heading towards the ground (radians)
    7709             :     Real64 Beta;
    7710             :     Real64 HorDis;        // Distance between ground hit point and proj'n of window center onto ground (m)
    7711             :     bool hitObs;          // True iff obstruction is hit
    7712             :     Real64 ObsVisRefl;    // Visible reflectance of obstruction
    7713             :     Real64 SkyReflVisLum; // Reflected sky luminance at hit point divided by unobstructed sky
    7714             :     //  diffuse horizontal illuminance [(cd/m2)/lux]
    7715             :     Real64 dReflObsSky; // Contribution to sky-related illuminance on window due to sky diffuse
    7716             :     //  reflection from an obstruction
    7717             :     Real64 TVisSunRefl; // Diffuse vis trans of bare window for beam reflection calc
    7718             :     //  (times light well efficiency, if appropriate)
    7719             :     Real64 ZSU1refl; // Beam normal illuminance times ZSU1refl = illuminance on window
    7720             :     //  due to specular reflection from exterior surfaces
    7721             : 
    7722             :     DataDaylighting::ExtWinType ExtWinType; // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
    7723             :     Real64 EnclInsideSurfArea;              // temporary for calculations, total surface area of enclosure surfaces m2
    7724             :     int IntWinAdjZoneExtWinNum;             // the index of the exterior window in IntWinAdjZoneExtWin nested struct
    7725             :     int AdjExtWinLoop;                      // loop index for searching IntWinAdjZoneExtWin
    7726             :     int IntWinLoop;                         // loop index for searching interior windows
    7727             :     int IntWinNum;                          // window index for interior windows associated with exterior windows
    7728             :     Real64 COSBintWin;
    7729             : 
    7730             :     WinShadingType ShType;
    7731             : 
    7732      319816 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
    7733      319816 :     int const enclNumThisWin = state.dataSurface->Surface(state.dataSurface->Surface(IWin).BaseSurf).SolarEnclIndex;
    7734             :     // The inside surface area, ZoneDaylight(ZoneNum)%totInsSurfArea was calculated in subr DayltgAveInteriorReflectance
    7735             : 
    7736      319816 :     if (enclNumThisWin == enclNum) {
    7737      312496 :         ExtWinType = DataDaylighting::ExtWinType::InZoneExtWin;
    7738      312496 :         EnclInsideSurfArea = state.dataDaylightingData->enclDaylight(enclNumThisWin).totInsSurfArea;
    7739      312496 :         IntWinAdjZoneExtWinNum = 0;
    7740             :     } else {
    7741        7320 :         ExtWinType = DataDaylighting::ExtWinType::AdjZoneExtWin;
    7742             :         // If window is exterior window in adjacent zone, then use areas of both enclosures
    7743        7320 :         EnclInsideSurfArea =
    7744        7320 :             state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea + state.dataDaylightingData->enclDaylight(enclNumThisWin).totInsSurfArea;
    7745             :         // find index in IntWinAdjZoneExtWin
    7746        7320 :         for (AdjExtWinLoop = 1; AdjExtWinLoop <= thisEnclDaylight.NumOfIntWinAdjEnclExtWins; ++AdjExtWinLoop) {
    7747        2424 :             if (IWin == thisEnclDaylight.IntWinAdjEnclExtWin(AdjExtWinLoop).SurfNum) { // found it
    7748        2424 :                 IntWinAdjZoneExtWinNum = AdjExtWinLoop;
    7749        2424 :                 break; // added TH 4/13/2010
    7750             :             }
    7751             :         }
    7752             :     }
    7753             : 
    7754             :     // Initialize window luminance and fluxes for split-flux calculation
    7755      319816 :     state.dataDaylightingManager->WLUMSK(IHR, _, _) = 0.0;
    7756      319816 :     state.dataDaylightingManager->WLUMSU(IHR, _) = 0.0;
    7757      319816 :     state.dataDaylightingManager->WLUMSUdisk(IHR, _) = 0.0;
    7758      319816 :     FLFWSK = 0.0;
    7759      319816 :     FLFWSU = 0.0;
    7760      319816 :     FLFWSUdisk = 0.0;
    7761      319816 :     FLCWSK = 0.0;
    7762      319816 :     FLCWSU = 0.0;
    7763             : 
    7764      319816 :     int const IConst = state.dataSurface->SurfActiveConstruction(IWin);
    7765      319816 :     BlindOn = false;
    7766      319816 :     ShadeOn = false;
    7767      319816 :     ScreenOn = false;
    7768             : 
    7769      319816 :     if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    7770        4896 :         PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
    7771             :     }
    7772             : 
    7773      319816 :     ShelfNum = state.dataSurface->SurfDaylightingShelfInd(IWin);
    7774      319816 :     if (ShelfNum > 0) {
    7775        2448 :         InShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf;   // Inside daylighting shelf present if > 0
    7776        2448 :         OutShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf; // Outside daylighting shelf present if > 0
    7777             :     } else {
    7778      317368 :         InShelfSurf = 0;
    7779      317368 :         OutShelfSurf = 0;
    7780             :     }
    7781             : 
    7782             :     // Divide sky and ground into elements of altitude PH and
    7783             :     // azimuth TH, and add the contribution of light coming from each
    7784             :     // element to the transmitted flux at the center of the window
    7785             :     // Azimuth ranges over a maximum of 2 Pi radians.
    7786             :     // Altitude ranges over a maximum of Pi/2 radians between -Pi/2 < PH < +Pi/2, so that elements are not counted twice
    7787             :     // PH = 0 at the horizon; PH = Pi/2 at the zenith
    7788      319816 :     PHMIN = max(-DataGlobalConstants::PiOvr2, state.dataSurface->SurfWinPhi(IWin) - DataGlobalConstants::PiOvr2);
    7789      319816 :     PHMAX = min(DataGlobalConstants::PiOvr2, state.dataSurface->SurfWinPhi(IWin) + DataGlobalConstants::PiOvr2);
    7790      319816 :     DPH = (PHMAX - PHMIN) / double(NPHMAX);
    7791             : 
    7792             :     // Sky/ground element altitude integration
    7793      639632 :     Vector3<Real64> const SUNCOS_IHR(state.dataSurface->SurfSunCosHourly(IHR));
    7794     3517976 :     for (IPH = 1; IPH <= NPHMAX; ++IPH) {
    7795     3198160 :         PH = PHMIN + (double(IPH) - 0.5) * DPH;
    7796             : 
    7797     3198160 :         SPH = std::sin(PH);
    7798     3198160 :         CPH = std::cos(PH);
    7799             :         // Third component of unit vector in (TH,PH) direction
    7800     3198160 :         U(3) = SPH;
    7801             : 
    7802             :         // Limits of azimuth integration
    7803     3198160 :         PhWin = state.dataSurface->SurfWinPhi(IWin);
    7804     3198160 :         ThWin = state.dataSurface->SurfWinTheta(IWin);
    7805     3198160 :         if (PhWin >= 0.0) {
    7806     3198160 :             if (PH >= DataGlobalConstants::PiOvr2 - PhWin) {
    7807      633828 :                 ThMin = -DataGlobalConstants::Pi;
    7808      633828 :                 ThMax = DataGlobalConstants::Pi;
    7809             :             } else {
    7810     2564332 :                 ACosTanTan = std::acos(-std::tan(PH) * std::tan(PhWin));
    7811     2564332 :                 ThMin = ThWin - std::abs(ACosTanTan);
    7812     2564332 :                 ThMax = ThWin + std::abs(ACosTanTan);
    7813             :             }
    7814             : 
    7815             :         } else { // PhiSurf < 0.0
    7816           0 :             if (PH <= -PhWin - DataGlobalConstants::PiOvr2) {
    7817           0 :                 ThMin = -DataGlobalConstants::Pi;
    7818           0 :                 ThMax = DataGlobalConstants::Pi;
    7819             :             } else {
    7820           0 :                 ACosTanTan = std::acos(-std::tan(PH) * std::tan(PhWin));
    7821           0 :                 ThMin = ThWin - std::abs(ACosTanTan);
    7822           0 :                 ThMax = ThWin + std::abs(ACosTanTan);
    7823             :             }
    7824             :         }
    7825             : 
    7826     3198160 :         DTH = (ThMax - ThMin) / double(NTHMAX);
    7827     3198160 :         DA = CPH * DTH * DPH;
    7828             : 
    7829             :         // Sky/ground element azimuth integration
    7830     3198160 :         Real64 const sin_window_phi(std::sin(state.dataSurface->SurfWinPhi(IWin)));
    7831     3198160 :         Real64 const cos_window_phi(std::cos(state.dataSurface->SurfWinPhi(IWin)));
    7832    54368720 :         for (ITH = 1; ITH <= NTHMAX; ++ITH) {
    7833    51170560 :             TH = ThMin + (double(ITH) - 0.5) * DTH;
    7834    51170560 :             U(1) = CPH * std::cos(TH);
    7835    51170560 :             U(2) = CPH * std::sin(TH);
    7836             :             // Cosine of angle of incidence of light from sky or ground element
    7837    51170560 :             COSB = SPH * sin_window_phi + CPH * cos_window_phi * std::cos(TH - state.dataSurface->SurfWinTheta(IWin));
    7838    51170560 :             if (COSB < 0.0) continue; // Sky/ground elements behind window (although there shouldn't be any)
    7839             : 
    7840             :             // Initialize illuminance on window for this sky/ground element
    7841    51170560 :             ZSK = 0.0;
    7842    51170560 :             ZSU = 0.0;
    7843             :             // Initialize illuminance on window from beam solar reflection if ray hits an obstruction
    7844    51170560 :             ZSUObsRefl = 0.0;
    7845             : 
    7846    51170560 :             if (ISunPos == 1) { // Intersection calculation has to be done only for first sun position
    7847             :                 // Determine net transmittance of obstructions that the ray hits. ObTrans will be 1.0
    7848             :                 // if no obstructions are hit.
    7849     4037440 :                 DayltgHitObstruction(state, IHR, IWin, state.dataSurface->SurfaceWindow(IWin).WinCenter, U, ObTrans);
    7850     4037440 :                 ObTransM(IPH, ITH) = ObTrans;
    7851             :             }
    7852             : 
    7853             :             // SKY AND GROUND RADIATION ON WINDOW
    7854             : 
    7855             :             // Contribution is from sky if PH > 0 (ray goes upward), and from ground if PH < 0 (ray goes downward)
    7856             :             // (There may also be contributions from reflection from obstructions; see 'BEAM SOLAR AND SKY SOLAR
    7857             :             // REFLECTED FROM NEAREST OBSTRUCTION,' below.)
    7858             : 
    7859    51170560 :             if (ISunPos == 1) SkyObstructionMult(IPH, ITH) = 1.0;
    7860    51170560 :             if (PH > 0.0) { // Contribution is from sky
    7861   153279520 :                 for (ISky = 1; ISky <= 4; ++ISky) {
    7862   122623616 :                     ZSK(ISky) = DayltgSkyLuminance(state, ISky, TH, PH) * COSB * DA * ObTransM(IPH, ITH);
    7863             :                 }
    7864             :             } else { // PH <= 0.0; contribution is from ground
    7865    20514656 :                 if (state.dataSurface->CalcSolRefl && ObTransM(IPH, ITH) > 1.e-6 && ISunPos == 1) {
    7866             :                     // Calculate effect of obstructions on shading of sky diffuse reaching the ground point hit
    7867             :                     // by the ray. This effect is given by the ratio SkyObstructionMult =
    7868             :                     // (obstructed sky diffuse at ground point)/(unobstructed sky diffuse at ground point).
    7869             :                     // This ratio is calculated for an isotropic sky.
    7870             :                     // Ground point hit by the ray:
    7871         640 :                     Alfa = std::acos(-U(3));
    7872         640 :                     Beta = std::atan2(U(2), U(1));
    7873         640 :                     HorDis = (state.dataSurface->SurfaceWindow(IWin).WinCenter(3) - state.dataSurface->GroundLevelZ) * std::tan(Alfa);
    7874         640 :                     DayltgInterReflectedIllumGroundHitPt(3) = state.dataSurface->GroundLevelZ;
    7875         640 :                     DayltgInterReflectedIllumGroundHitPt(1) = state.dataSurface->SurfaceWindow(IWin).WinCenter(1) + HorDis * std::cos(Beta);
    7876         640 :                     DayltgInterReflectedIllumGroundHitPt(2) = state.dataSurface->SurfaceWindow(IWin).WinCenter(2) + HorDis * std::sin(Beta);
    7877             : 
    7878         640 :                     SkyObstructionMult(IPH, ITH) =
    7879         640 :                         CalcObstrMultiplier(state, DayltgInterReflectedIllumGroundHitPt, AltAngStepsForSolReflCalc, AzimAngStepsForSolReflCalc);
    7880             :                 } // End of check if solar reflection calc is in effect
    7881   102573280 :                 for (ISky = 1; ISky <= 4; ++ISky) {
    7882             :                     // Below, luminance of ground in cd/m2 is illuminance on ground in lumens/m2
    7883             :                     // times ground reflectance, divided by pi, times obstruction multiplier.
    7884    82058624 :                     ZSK(ISky) =
    7885    82058624 :                         (state.dataDaylightingManager->GILSK(IHR, ISky) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi) * COSB *
    7886    82058624 :                         DA * ObTransM(IPH, ITH) * SkyObstructionMult(IPH, ITH);
    7887             :                 }
    7888             :                 // Determine if sun illuminates the point that ray hits the ground. If the solar reflection
    7889             :                 // calculation has been requested (CalcSolRefl = .TRUE.) shading by obstructions, including
    7890             :                 // the building itself, is considered in determining whether sun hits the ground point.
    7891             :                 // Otherwise this shading is ignored and the sun always hits the ground point.
    7892    20514656 :                 SunObstructionMult = 1.0;
    7893    20514656 :                 if (state.dataSurface->CalcSolRefl && ObTransM(IPH, ITH) > 1.e-6) {
    7894             :                     // Sun reaches ground point if vector from this point to the sun is unobstructed
    7895        7680 :                     hitObs = false;
    7896       38134 :                     for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    7897             :                         PierceSurface(state, ObsSurfNum, DayltgInterReflectedIllumGroundHitPt, SUNCOS_IHR, DayltgInterReflectedIllumObsHitPt, hitObs);
    7898       30712 :                         if (hitObs) break;
    7899             :                     }
    7900        7680 :                     if (hitObs) SunObstructionMult = 0.0;
    7901             :                 }
    7902    41029312 :                 ZSU = (state.dataDaylightingManager->GILSU(IHR) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi) * COSB * DA *
    7903    20514656 :                       ObTransM(IPH, ITH) * SunObstructionMult;
    7904             :             }
    7905             :             // BEAM SOLAR AND SKY SOLAR REFLECTED FROM NEAREST OBSTRUCTION
    7906             : 
    7907    51170560 :             if (state.dataSurface->CalcSolRefl && ObTransM(IPH, ITH) < 1.0) {
    7908             :                 // Find obstruction whose hit point is closest to the center of the window
    7909        3840 :                 DayltgClosestObstruction(
    7910        3840 :                     state, state.dataSurface->SurfaceWindow(IWin).WinCenter, U, NearestHitSurfNum, DayltgInterReflectedIllumNearestHitPt);
    7911        3840 :                 if (NearestHitSurfNum > 0) {
    7912             : 
    7913             :                     // Beam solar reflected from nearest obstruction.
    7914        3840 :                     DayltgSurfaceLumFromSun(state, IHR, U, NearestHitSurfNum, DayltgInterReflectedIllumNearestHitPt, LumAtHitPtFrSun);
    7915        3840 :                     ZSUObsRefl = LumAtHitPtFrSun * COSB * DA;
    7916        3840 :                     ZSU += ZSUObsRefl;
    7917             : 
    7918             :                     // Sky solar reflected from nearest obstruction.
    7919        3840 :                     int const ObsConstrNum = state.dataSurface->Surface(NearestHitSurfNum).Construction;
    7920        3840 :                     if (ObsConstrNum > 0) {
    7921             :                         // Exterior building surface is nearest hit
    7922           0 :                         if (!state.dataConstruction->Construct(ObsConstrNum).TypeIsWindow) {
    7923             :                             // Obstruction is not a window, i.e., is an opaque surface
    7924           0 :                             ObsVisRefl =
    7925           0 :                                 1.0 - state.dataMaterial->Material(state.dataConstruction->Construct(ObsConstrNum).LayerPoint(1)).AbsorpVisible;
    7926             :                         } else {
    7927             :                             // Obstruction is a window; assume it is bare
    7928           0 :                             ObsVisRefl = state.dataConstruction->Construct(ObsConstrNum).ReflectVisDiffFront;
    7929             :                         }
    7930             :                     } else {
    7931             :                         // Shadowing surface is nearest hit
    7932        3840 :                         if (state.dataSurface->SurfDaylightingShelfInd(NearestHitSurfNum) > 0) {
    7933             :                             // Skip daylighting shelves, whose reflection is separately calculated
    7934           0 :                             ObsVisRefl = 0.0;
    7935             :                         } else {
    7936        3840 :                             ObsVisRefl = state.dataSurface->SurfShadowDiffuseVisRefl(NearestHitSurfNum);
    7937        3840 :                             if (state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum) > 0)
    7938           0 :                                 ObsVisRefl += state.dataSurface->SurfShadowGlazingFrac(NearestHitSurfNum) *
    7939           0 :                                               state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum))
    7940           0 :                                                   .ReflectVisDiffFront;
    7941             :                             // Note in the above that ShadowSurfDiffuseVisRefl is the reflectance of opaque part of
    7942             :                             // shadowing surface times (1 - ShadowSurfGlazingFrac)
    7943             :                         }
    7944             :                     }
    7945        3840 :                     NearestHitSurfNumX = NearestHitSurfNum;
    7946             :                     // Each shadowing surface has a "mirror" duplicate surface facing in the opposite direction.
    7947             :                     // The following gets the correct side of a shadowing surface for reflection.
    7948        3840 :                     if (state.dataSurface->Surface(NearestHitSurfNum).IsShadowing) {
    7949        3840 :                         if (dot(U, state.dataSurface->Surface(NearestHitSurfNum).OutNormVec) > 0.0) NearestHitSurfNumX = NearestHitSurfNum + 1;
    7950             :                     }
    7951        3840 :                     if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
    7952           0 :                         state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    7953        7680 :                         SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
    7954        3840 :                                         state.dataSolarShading->SurfDifShdgRatioIsoSky(NearestHitSurfNumX) / DataGlobalConstants::Pi;
    7955             :                     } else {
    7956           0 :                         SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
    7957           0 :                                         state.dataSolarShading->SurfDifShdgRatioIsoSkyHRTS(1, IHR, NearestHitSurfNumX) / DataGlobalConstants::Pi;
    7958             :                     }
    7959        3840 :                     dReflObsSky = SkyReflVisLum * COSB * DA;
    7960       19200 :                     for (ISky = 1; ISky <= 4; ++ISky) {
    7961       15360 :                         ZSK(ISky) += state.dataDaylightingManager->GILSK(IHR, ISky) * dReflObsSky;
    7962             :                     }
    7963             :                 }
    7964             :             } // End of check if exterior solar reflection calculation is active
    7965             : 
    7966             :             //  ===Bare window (no shade or blind; non-diffusing glass)===
    7967             : 
    7968             :             // Increment flux entering space and window luminance (cd/m2).
    7969             :             // FLCW--(I,J) = part of incoming flux (in lumens) that goes up to ceiling and upper part of walls.
    7970             :             // FLFW--(I,J) = part that goes down to floor and lower part of walls
    7971             : 
    7972    51170560 :             if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    7973             :                 // Unshaded visible transmittance of TDD for a single ray from sky/ground element
    7974      783360 :                 TVISBR = TransTDD(state, PipeNum, COSB, DataDaylightingDevices::RadType::VisibleBeam) * state.dataSurface->SurfWinGlazedFrac(IWin);
    7975             : 
    7976             :                 // Make all transmitted light diffuse for a TDD with a bare diffuser
    7977     3916800 :                 for (ISky = 1; ISky <= 4; ++ISky) {
    7978     3133440 :                     state.dataDaylightingManager->WLUMSK(IHR, 1, ISky) += ZSK(ISky) * TVISBR / DataGlobalConstants::Pi;
    7979     3133440 :                     FLFWSK(1, ISky) += ZSK(ISky) * TVISBR * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    7980     3133440 :                     FLCWSK(1, ISky) += ZSK(ISky) * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
    7981             : 
    7982             :                     // For later calculation of diffuse visible transmittance
    7983     3133440 :                     state.dataDaylightingManager->TDDFluxInc(IHR, ISky, PipeNum) += ZSK(ISky);
    7984     3133440 :                     state.dataDaylightingManager->TDDFluxTrans(IHR, ISky, PipeNum) += ZSK(ISky) * TVISBR;
    7985             : 
    7986     3133440 :                     if (ISky == 1) {
    7987      783360 :                         state.dataDaylightingManager->WLUMSU(IHR, 1) += ZSU * TVISBR / DataGlobalConstants::Pi;
    7988      783360 :                         FLFWSU(1) += ZSU * TVISBR * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    7989      783360 :                         FLCWSU(1) += ZSU * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
    7990             : 
    7991             :                         // For later calculation of diffuse visible transmittance
    7992      783360 :                         state.dataDaylightingManager->TDDFluxInc(IHR, ISky, PipeNum) += ZSU;
    7993      783360 :                         state.dataDaylightingManager->TDDFluxTrans(IHR, ISky, PipeNum) += ZSU * TVISBR;
    7994             :                     }
    7995             :                 }
    7996             : 
    7997             :             } else { // Bare window
    7998             :                 // Transmittance of bare window for this sky/ground element
    7999   100774400 :                 TVISBR = POLYF(COSB, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin) *
    8000    50387200 :                          state.dataSurface->SurfWinLightWellEff(IWin);
    8001             : 
    8002    50387200 :                 if (InShelfSurf > 0) { // Inside daylighting shelf
    8003             :                     // Daylighting shelf simplification:  All light is diffuse
    8004             :                     // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
    8005     1958400 :                     for (ISky = 1; ISky <= 4; ++ISky) {
    8006     1566720 :                         FLCWSK(1, ISky) += ZSK(ISky) * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8007             : 
    8008     1566720 :                         if (ISky == 1) {
    8009      391680 :                             FLCWSU(1) += ZSU * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8010             :                         }
    8011             :                     }
    8012             : 
    8013             :                 } else { // Normal window
    8014             : 
    8015             :                     // CR 7869  correct TVISBR if disk beam passes thru interior window
    8016    49995520 :                     if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
    8017             :                         // modify TVISBR by second window transmission
    8018             :                         // first determine if ray from point passes thru any interior window
    8019      387840 :                         hitObs = false;
    8020      387840 :                         for (IntWinLoop = 1; IntWinLoop <= thisEnclDaylight.IntWinAdjEnclExtWin(IntWinAdjZoneExtWinNum).NumOfIntWindows;
    8021             :                              ++IntWinLoop) {
    8022           0 :                             IntWinNum = thisEnclDaylight.IntWinAdjEnclExtWin(IntWinAdjZoneExtWinNum).IntWinNum(IntWinLoop);
    8023           0 :                             PierceSurface(state,
    8024             :                                           IntWinNum,
    8025           0 :                                           state.dataSurface->SurfaceWindow(IntWinNum).WinCenter,
    8026             :                                           SUNCOS_IHR,
    8027             :                                           DayltgInterReflectedIllumObsHitPt,
    8028             :                                           hitObs);
    8029           0 :                             if (hitObs) { // disk passes thru
    8030             :                                 // cosine of incidence angle of light from sky or ground element for
    8031           0 :                                 COSBintWin = SPH * std::sin(state.dataSurface->SurfWinPhi(IntWinNum)) +
    8032           0 :                                              CPH * std::cos(state.dataSurface->SurfWinPhi(IntWinNum)) *
    8033           0 :                                                  std::cos(TH - state.dataSurface->SurfWinTheta(IntWinNum));
    8034           0 :                                 TVISBR *=
    8035           0 :                                     POLYF(COSBintWin,
    8036           0 :                                           state.dataConstruction->Construct(state.dataSurface->Surface(IntWinNum).Construction).TransVisBeamCoef);
    8037           0 :                                 break;
    8038             :                             }
    8039             :                         }
    8040      387840 :                         if (!hitObs) { // blocked by opaque parts, beam does not actually pass thru interior window to reach zone
    8041      387840 :                             TVISBR = 0.0;
    8042             :                         }
    8043             :                     }
    8044             : 
    8045   249977600 :                     for (ISky = 1; ISky <= 4; ++ISky) {
    8046             :                         // IF (PH < 0.0d0) THEN
    8047             :                         // Fixed by FCW, Nov. 2003:
    8048   199982080 :                         if (PH > 0.0) {
    8049   119020160 :                             FLFWSK(1, ISky) += ZSK(ISky) * TVISBR;
    8050   119020160 :                             if (ISky == 1) FLFWSU(1) += ZSU * TVISBR;
    8051             :                         } else {
    8052    80961920 :                             FLCWSK(1, ISky) += ZSK(ISky) * TVISBR;
    8053    80961920 :                             if (ISky == 1) FLCWSU(1) += ZSU * TVISBR;
    8054             :                         }
    8055             :                     }
    8056             :                 } // End of check if window with daylighting shelf or normal window
    8057             :             }     // End of check if TDD:DOME or bare window
    8058             : 
    8059             :             // Check if window has shade or blind
    8060    51170560 :             ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    8061    51170560 :             if (state.dataSurface->Surface(IWin).HasShadeControl) {
    8062    23781440 :                 ShType = state.dataSurface->WindowShadingControl(ICtrl).ShadingType;
    8063    23781440 :                 BlNum = state.dataSurface->SurfWinBlindNumber(IWin);
    8064             :                 //                    ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used
    8065             : 
    8066    23781440 :                 ShadeOn = ANY_SHADE(ShType);
    8067    23781440 :                 BlindOn = ANY_BLIND(ShType);
    8068    23781440 :                 ScreenOn = (ShType == WinShadingType::ExtScreen);
    8069             :             }
    8070             : 
    8071    51170560 :             if (ShadeOn || BlindOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
    8072             : 
    8073             :                 // ===Window with interior or exterior shade or blind, exterior screen, or with diffusing glass===
    8074             : 
    8075             :                 // Increment flux entering space and window luminance. Shades and diffusing glass are
    8076             :                 // assumed to be perfect diffusers, i.e., the transmittance is independent of angle of
    8077             :                 // incidence and the transmitted light is isotropic. The transmittance of a blind is
    8078             :                 // assumed to depend on profile angle and slat angle; the diffuse light entering the room from
    8079             :                 // the slats of the blind is assumed to be isotropic. With blinds, light can also enter
    8080             :                 // the room by passing between the slats without reflection. The beam transmittance of a screen
    8081             :                 // is assumed to depend on sun azimuth and azimuth angle.
    8082             : 
    8083             :                 // For light from a shade, or from diffusing glass, or from the slats of a blind, a flux fraction,
    8084             :                 // SurfaceWindow(IWin)%FractionUpgoing (determined by window tilt), goes up toward
    8085             :                 // ceiling and upper part of walls, and 1-Surfacewindow(iwin)%FractionUpgoing
    8086             :                 // goes down toward floor and lower part of walls. For a blind, the light passing
    8087             :                 // between the slats goes either up or down depending on the altitude angle of the
    8088             :                 // element from which the light came. For a screen, the light passing
    8089             :                 // between the screen's cylinders goes either up or down depending on the altitude angle of the
    8090             :                 // element from which the light came.
    8091             : 
    8092       23040 :                 int IConstShaded = state.dataSurface->SurfWinActiveShadedConstruction(IWin);
    8093       23040 :                 if (state.dataSurface->SurfWinSolarDiffusing(IWin)) IConstShaded = state.dataSurface->Surface(IWin).Construction;
    8094             : 
    8095             :                 // Transmittance of window including shade, screen or blind
    8096       23040 :                 DayltgInterReflectedIllumTransBmBmMult = 0.0;
    8097       23040 :                 TransMult = 0.0;
    8098             : 
    8099       23040 :                 if (ShadeOn) { // Shade
    8100       23040 :                     if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    8101             :                         // Shaded visible transmittance of TDD for a single ray from sky/ground element
    8102           0 :                         TransMult(1) =
    8103           0 :                             TransTDD(state, PipeNum, COSB, DataDaylightingDevices::RadType::VisibleBeam) * state.dataSurface->SurfWinGlazedFrac(IWin);
    8104             :                     } else { // Shade only, no TDD
    8105             :                         // Calculate transmittance of the combined window and shading device for this sky/ground element
    8106       69120 :                         TransMult(1) = POLYF(COSB, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
    8107       46080 :                                        state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8108             :                     }
    8109             : 
    8110           0 :                 } else if (ScreenOn) { // Screen: get beam-beam, beam-diffuse and diffuse-diffuse vis trans/ref of screen and glazing system
    8111           0 :                     CalcScreenTransmittance(state, IWin, (PH - state.dataSurface->SurfWinPhi(IWin)), (TH - state.dataSurface->SurfWinTheta(IWin)));
    8112           0 :                     ReflGlDiffDiffFront = state.dataConstruction->Construct(IConst).ReflectVisDiffFront;
    8113           0 :                     ReflScDiffDiffBack = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).DifReflectVis;
    8114           0 :                     TransScBmDiffFront = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmDifTransVis;
    8115           0 :                     TransMult(1) = TransScBmDiffFront * state.dataSurface->SurfWinGlazedFrac(IWin) *
    8116           0 :                                    state.dataConstruction->Construct(IConst).TransDiffVis / (1 - ReflGlDiffDiffFront * ReflScDiffDiffBack) *
    8117           0 :                                    state.dataSurface->SurfWinLightWellEff(IWin);
    8118           0 :                     DayltgInterReflectedIllumTransBmBmMult(1) =
    8119           0 :                         state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTransVis;
    8120             : 
    8121           0 :                 } else if (BlindOn) { // Blind: get beam-diffuse and beam-beam vis trans of blind+glazing system
    8122             :                     // PETER:  As long as only interior blinds are allowed for TDDs, no need to change TransMult calculation
    8123             :                     //         for TDDs because it is based on TVISBR which is correctly calculated for TDDs above.
    8124             : 
    8125           0 :                     ProfileAngle(state, IWin, U, state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
    8126             : 
    8127           0 :                     for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    8128           0 :                         if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
    8129             : 
    8130           0 :                         TransBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
    8131             : 
    8132           0 :                         if (ShType == WinShadingType::IntBlind) { // Interior blind
    8133           0 :                             ReflGlDiffDiffBack = state.dataConstruction->Construct(IConst).ReflectVisDiffBack;
    8134           0 :                             ReflBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
    8135           0 :                             ReflBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
    8136           0 :                             TransBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
    8137           0 :                             TransMult(JB) = TVISBR * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront /
    8138           0 :                                                                                (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack));
    8139             : 
    8140           0 :                         } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind
    8141           0 :                             ReflGlDiffDiffFront = state.dataConstruction->Construct(IConst).ReflectVisDiffFront;
    8142           0 :                             ReflBlDiffDiffBack = state.dataHeatBal->Blind(BlNum).VisBackDiffDiffRefl(JB);
    8143           0 :                             TransMult(JB) = TransBlBmDiffFront * state.dataSurface->SurfWinGlazedFrac(IWin) *
    8144           0 :                                             state.dataConstruction->Construct(IConst).TransDiffVis /
    8145           0 :                                             (1.0 - ReflGlDiffDiffFront * ReflBlDiffDiffBack) * state.dataSurface->SurfWinLightWellEff(IWin);
    8146             : 
    8147             :                         } else { // Between-glass blind
    8148           0 :                             t1 = POLYF(COSB, state.dataConstruction->Construct(IConst).tBareVisCoef(1));
    8149           0 :                             td2 = state.dataConstruction->Construct(IConst).tBareVisDiff(2);
    8150           0 :                             rbd1 = state.dataConstruction->Construct(IConst).rbBareVisDiff(1);
    8151           0 :                             rfd2 = state.dataConstruction->Construct(IConst).rfBareVisDiff(2);
    8152           0 :                             tfshBd = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
    8153           0 :                             tfshd = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
    8154           0 :                             rfshB = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
    8155           0 :                             rbshd = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
    8156           0 :                             if (state.dataConstruction->Construct(IConst).TotGlassLayers == 2) { // 2 glass layers
    8157           0 :                                 TransMult(JB) =
    8158           0 :                                     t1 * (tfshBd * (1.0 + rfd2 * rbshd) + rfshB * rbd1 * tfshd) * td2 * state.dataSurface->SurfWinLightWellEff(IWin);
    8159             :                             } else { // 3 glass layers; blind between layers 2 and 3
    8160           0 :                                 t2 = POLYF(COSB, state.dataConstruction->Construct(IConst).tBareVisCoef(2));
    8161           0 :                                 td3 = state.dataConstruction->Construct(IConst).tBareVisDiff(3);
    8162           0 :                                 rfd3 = state.dataConstruction->Construct(IConst).rfBareVisDiff(3);
    8163           0 :                                 rbd2 = state.dataConstruction->Construct(IConst).rbBareVisDiff(2);
    8164           0 :                                 TransMult(JB) = t1 * t2 * (tfshBd * (1.0 + rfd3 * rbshd) + rfshB * (rbd2 * tfshd + td2 * rbd1 * td2 * tfshd)) * td3 *
    8165           0 :                                                 state.dataSurface->SurfWinLightWellEff(IWin);
    8166             :                             }
    8167             :                         }
    8168             : 
    8169           0 :                         if (state.dataSurface->SurfWinMovableSlats(IWin)) {
    8170           0 :                             SlatAng = (JB - 1) * DataGlobalConstants::Pi / (MaxSlatAngs - 1);
    8171             :                         } else {
    8172           0 :                             SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
    8173             :                         }
    8174           0 :                         DayltgInterReflectedIllumTransBmBmMult(JB) =
    8175           0 :                             TVISBR * General::BlindBeamBeamTrans(ProfAng,
    8176             :                                                                  SlatAng,
    8177           0 :                                                                  state.dataHeatBal->Blind(BlNum).SlatWidth,
    8178           0 :                                                                  state.dataHeatBal->Blind(BlNum).SlatSeparation,
    8179           0 :                                                                  state.dataHeatBal->Blind(BlNum).SlatThickness);
    8180             :                     } // End of loop over slat angles
    8181             : 
    8182             :                 } else { // Diffusing glass
    8183           0 :                     TransMult(1) = POLYF(COSB, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
    8184           0 :                                    state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8185             :                 } // End of check if shade, blind or diffusing glass
    8186             : 
    8187       23040 :                 if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    8188             :                     // No beam is transmitted.  This takes care of all types of screens and blinds.
    8189           0 :                     DayltgInterReflectedIllumTransBmBmMult = 0.0;
    8190             :                 }
    8191             : 
    8192             :                 // Daylighting shelf simplification:  No beam makes it past end of shelf, all light is diffuse
    8193       23040 :                 if (InShelfSurf > 0) {                            // Inside daylighting shelf
    8194           0 :                     DayltgInterReflectedIllumTransBmBmMult = 0.0; // No beam, diffuse only
    8195             :                 }
    8196             : 
    8197             :                 // DayltgInterReflectedIllumTransBmBmMult is used in the following for windows with blinds or screens to get contribution from light
    8198             :                 // passing directly between slats or between screen material without reflection.
    8199             : 
    8200      115200 :                 for (ISky = 1; ISky <= 4; ++ISky) {
    8201      184320 :                     for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    8202             :                         // EXIT after first pass if not movable slats or exterior window screen
    8203      184320 :                         if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
    8204             : 
    8205       92160 :                         state.dataDaylightingManager->WLUMSK(IHR, JB + 1, ISky) += ZSK(ISky) * TransMult(JB) / DataGlobalConstants::Pi;
    8206       92160 :                         FLFWSK(JB + 1, ISky) += ZSK(ISky) * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    8207       92160 :                         if (PH > 0.0 && (BlindOn || ScreenOn)) FLFWSK(JB + 1, ISky) += ZSK(ISky) * DayltgInterReflectedIllumTransBmBmMult(JB);
    8208       92160 :                         FLCWSK(JB + 1, ISky) += ZSK(ISky) * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8209       92160 :                         if (PH <= 0.0 && (BlindOn || ScreenOn)) FLCWSK(JB + 1, ISky) += ZSK(ISky) * DayltgInterReflectedIllumTransBmBmMult(JB);
    8210       92160 :                         if (ISky == 1) {
    8211       23040 :                             state.dataDaylightingManager->WLUMSU(IHR, JB + 1) += ZSU * TransMult(JB) / DataGlobalConstants::Pi;
    8212       23040 :                             FLFWSU(JB + 1) += ZSU * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    8213       23040 :                             if (PH > 0.0 && (BlindOn || ScreenOn)) FLFWSU(JB + 1) += ZSU * DayltgInterReflectedIllumTransBmBmMult(JB);
    8214       23040 :                             FLCWSU(JB + 1) += ZSU * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8215       23040 :                             if (PH <= 0.0 && (BlindOn || ScreenOn)) FLCWSU(JB + 1) += ZSU * DayltgInterReflectedIllumTransBmBmMult(JB);
    8216             :                         }
    8217             :                     }
    8218             :                 }
    8219             :             } // End of window with shade, screen, blind or diffusing glass
    8220             : 
    8221             :         } // End of azimuth integration loop, ITH
    8222             :     }     // End of altitude integration loop, IPH
    8223             : 
    8224      319816 :     if (OutShelfSurf > 0) { // Outside daylighting shelf
    8225             :         // Add exterior diffuse illuminance due to outside shelf
    8226             :         // Since all of the illuminance is added to the zone as upgoing diffuse, it can be added as a lump sum here
    8227             : 
    8228        2448 :         TVISBR = state.dataConstruction->Construct(IConst).TransDiffVis; // Assume diffuse transmittance for shelf illuminance
    8229             : 
    8230       12240 :         for (ISky = 1; ISky <= 4; ++ISky) {
    8231             :             // This is only an estimate because the anisotropic sky view of the shelf is not yet taken into account.
    8232             :             // SurfAnisoSkyMult would be great to use but it is not available until the heat balance starts up.
    8233       19584 :             ZSK(ISky) = state.dataDaylightingManager->GILSK(IHR, ISky) * 1.0 * state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectVis *
    8234        9792 :                         state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor;
    8235             : 
    8236             :             // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
    8237        9792 :             FLCWSK(1, ISky) += ZSK(ISky) * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8238             : 
    8239        9792 :             if (ISky == 1) {
    8240        7344 :                 ZSU = state.dataDaylightingManager->GILSU(IHR) * state.dataHeatBal->SurfSunlitFracHR(IHR, OutShelfSurf) *
    8241        4896 :                       state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectVis * state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor;
    8242        2448 :                 FLCWSU(1) += ZSU * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8243             :             }
    8244             :         } // ISKY
    8245             :     }
    8246             : 
    8247             :     // Sky-related portion of internally reflected illuminance.
    8248             :     // The inside surface area, ZoneDaylight(ZoneNum)%totInsSurfArea, and ZoneDaylight(ZoneNum)%aveVisDiffReflect,
    8249             :     // were calculated in subr DayltgAveInteriorReflectance.
    8250             : 
    8251     1599080 :     for (ISky = 1; ISky <= 4; ++ISky) {
    8252     3837792 :         for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
    8253     3837792 :             if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
    8254             :             // Full area of window is used in following since effect of dividers on reducing
    8255             :             // effective window transmittance has already been accounted for in calc of FLFWSK and FLCWSK.
    8256     2558528 :             state.dataDaylightingManager->EINTSK(IHR, JSH, ISky) =
    8257     5117056 :                 (FLFWSK(JSH, ISky) * state.dataSurface->SurfWinRhoFloorWall(IWin) +
    8258     5117056 :                  FLCWSK(JSH, ISky) * state.dataSurface->SurfWinRhoCeilingWall(IWin)) *
    8259     5117056 :                 (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
    8260     2558528 :                 (EnclInsideSurfArea * (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect));
    8261             :         } // JSH
    8262             :     }     // ISKY
    8263             : 
    8264             :     // BEAM SOLAR RADIATION ON WINDOW
    8265             : 
    8266             :     // Beam reaching window directly (without specular reflection from exterior obstructions)
    8267             : 
    8268      319816 :     if (state.dataHeatBal->SurfSunlitFracHR(IHR, IWin) > 0.0) {
    8269             :         // Cos of angle of incidence
    8270      482922 :         COSBSun = state.dataDaylightingManager->SPHSUN * std::sin(state.dataSurface->SurfWinPhi(IWin)) +
    8271      482922 :                   state.dataDaylightingManager->CPHSUN * std::cos(state.dataSurface->SurfWinPhi(IWin)) *
    8272      241461 :                       std::cos(state.dataDaylightingManager->THSUN - state.dataSurface->SurfWinTheta(IWin));
    8273             : 
    8274      241461 :         if (COSBSun > 0.0) {
    8275             :             // Multiply direct normal illuminance (normalized to 1.0 lux)
    8276             :             // by incident angle factor and by fraction of window that is sunlit.
    8277             :             // Note that in the following SurfSunlitFracHR accounts for possibly non-zero transmittance of
    8278             :             // shading surfaces.
    8279             : 
    8280      241461 :             ZSU1 = COSBSun * state.dataHeatBal->SurfSunlitFracHR(IHR, IWin);
    8281             : 
    8282             :             // Contribution to window luminance and downgoing flux
    8283             : 
    8284             :             // -- Bare window
    8285             : 
    8286      241461 :             if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    8287             :                 // Unshaded visible transmittance of TDD for collimated beam from the sun
    8288        4488 :                 TVISBSun =
    8289        4488 :                     TransTDD(state, PipeNum, COSBSun, DataDaylightingDevices::RadType::VisibleBeam) * state.dataSurface->SurfWinGlazedFrac(IWin);
    8290        4488 :                 state.dataDaylightingManager->TDDTransVisBeam(IHR, PipeNum) = TVISBSun;
    8291             : 
    8292        4488 :                 FLFWSUdisk(1) = 0.0; // Diffuse light only
    8293             : 
    8294        4488 :                 state.dataDaylightingManager->WLUMSU(IHR, 1) += ZSU1 * TVISBSun / DataGlobalConstants::Pi;
    8295        4488 :                 FLFWSU(1) += ZSU1 * TVISBSun * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    8296        4488 :                 FLCWSU(1) += ZSU1 * TVISBSun * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8297             : 
    8298             :             } else { // Bare window
    8299      473946 :                 TVISBSun = POLYF(COSBSun, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin) *
    8300      236973 :                            state.dataSurface->SurfWinLightWellEff(IWin);
    8301             : 
    8302             :                 // Daylighting shelf simplification:  No beam makes it past end of shelf, all light is diffuse
    8303      236973 :                 if (InShelfSurf > 0) {   // Inside daylighting shelf
    8304        1836 :                     FLFWSUdisk(1) = 0.0; // Diffuse light only
    8305             : 
    8306             :                     // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
    8307             :                     // WLUMSU(1,IHR) = WLUMSU(1,IHR) + ZSU1 * TVISBSun / PI
    8308             :                     // FLFWSU(1) = FLFWSU(1) + ZSU1 * TVISBSun * (1.0 - SurfaceWindow(IWin)%FractionUpgoing)
    8309        1836 :                     FLCWSU(1) += ZSU1 * TVISBSun * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8310             :                 } else { // Normal window
    8311      235137 :                     FLFWSUdisk(1) = ZSU1 * TVISBSun;
    8312             :                 }
    8313             :             }
    8314             : 
    8315             :             // -- Window with shade, screen, blind or diffusing glass
    8316      241461 :             if (ShadeOn || BlindOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
    8317          66 :                 DayltgInterReflectedIllumTransBmBmMult = 0.0;
    8318          66 :                 TransMult = 0.0;
    8319             : 
    8320             :                 // TH 7/7/2010 moved from inside the loop: DO JB = 1,MaxSlatAngs
    8321          66 :                 if (BlindOn)
    8322           0 :                     ProfileAngle(state, IWin, state.dataSurface->SurfSunCosHourly(IHR), state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
    8323             : 
    8324         132 :                 for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    8325         132 :                     if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
    8326             : 
    8327          66 :                     if (ShadeOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) { // Shade or screen on or diffusing glass
    8328          66 :                         if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    8329             :                             // Shaded visible transmittance of TDD for collimated beam from the sun
    8330           0 :                             TransMult(1) = TransTDD(state, PipeNum, COSBSun, DataDaylightingDevices::RadType::VisibleBeam) *
    8331           0 :                                            state.dataSurface->SurfWinGlazedFrac(IWin);
    8332             :                         } else {
    8333          66 :                             if (ScreenOn) {
    8334           0 :                                 TransMult(1) = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTransVis *
    8335           0 :                                                state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8336             :                             } else {
    8337          66 :                                 int IConstShaded = state.dataSurface->SurfWinActiveShadedConstruction(IWin);
    8338          66 :                                 if (state.dataSurface->SurfWinSolarDiffusing(IWin)) IConstShaded = state.dataSurface->Surface(IWin).Construction;
    8339         198 :                                 TransMult(1) = POLYF(COSBSun, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
    8340         132 :                                                state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8341             :                             }
    8342             :                         }
    8343             : 
    8344             :                     } else { // Blind on
    8345             : 
    8346             :                         // As long as only interior blinds are allowed for TDDs, no need to change TransMult calculation
    8347             :                         // for TDDs because it is based on TVISBSun which is correctly calculated for TDDs above.
    8348             : 
    8349           0 :                         TransBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
    8350             : 
    8351           0 :                         if (ShType == WinShadingType::IntBlind) { // Interior blind
    8352             :                             // TH CR 8121, 7/7/2010
    8353             :                             // ReflBlBmDiffFront = InterpProfAng(ProfAng,Blind(BlNum)%VisFrontBeamDiffRefl)
    8354           0 :                             ReflBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
    8355             : 
    8356             :                             // TH added 7/12/2010 for CR 8121
    8357           0 :                             ReflBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
    8358           0 :                             TransBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
    8359             : 
    8360           0 :                             TransMult(JB) = TVISBSun * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront /
    8361           0 :                                                                                  (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack));
    8362             : 
    8363           0 :                         } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind
    8364           0 :                             TransMult(JB) = TransBlBmDiffFront *
    8365           0 :                                             (state.dataConstruction->Construct(IConst).TransDiffVis /
    8366           0 :                                              (1.0 - ReflGlDiffDiffFront * state.dataHeatBal->Blind(BlNum).VisBackDiffDiffRefl(JB))) *
    8367           0 :                                             state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8368             : 
    8369             :                         } else { // Between-glass blind
    8370           0 :                             t1 = POLYF(COSBSun, state.dataConstruction->Construct(IConst).tBareVisCoef(1));
    8371           0 :                             tfshBd = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
    8372           0 :                             rfshB = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
    8373           0 :                             if (state.dataConstruction->Construct(IConst).TotGlassLayers == 2) { // 2 glass layers
    8374           0 :                                 TransMult(JB) =
    8375           0 :                                     t1 * (tfshBd * (1.0 + rfd2 * rbshd) + rfshB * rbd1 * tfshd) * td2 * state.dataSurface->SurfWinLightWellEff(IWin);
    8376             :                             } else { // 3 glass layers; blind between layers 2 and 3
    8377           0 :                                 t2 = POLYF(COSBSun, state.dataConstruction->Construct(IConst).tBareVisCoef(2));
    8378           0 :                                 TransMult(JB) = t1 * t2 * (tfshBd * (1.0 + rfd3 * rbshd) + rfshB * (rbd2 * tfshd + td2 * rbd1 * td2 * tfshd)) * td3 *
    8379           0 :                                                 state.dataSurface->SurfWinLightWellEff(IWin);
    8380             :                             }
    8381             :                         }
    8382           0 :                         if (state.dataSurface->SurfWinMovableSlats(IWin)) {
    8383           0 :                             SlatAng = (JB - 1) * DataGlobalConstants::Pi / (MaxSlatAngs - 1);
    8384             :                         } else {
    8385           0 :                             SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
    8386             :                         }
    8387           0 :                         DayltgInterReflectedIllumTransBmBmMult(JB) =
    8388           0 :                             TVISBSun * General::BlindBeamBeamTrans(ProfAng,
    8389             :                                                                    SlatAng,
    8390           0 :                                                                    state.dataHeatBal->Blind(BlNum).SlatWidth,
    8391           0 :                                                                    state.dataHeatBal->Blind(BlNum).SlatSeparation,
    8392           0 :                                                                    state.dataHeatBal->Blind(BlNum).SlatThickness);
    8393             :                     } // ShadeOn/ScreenOn/BlindOn/Diffusing glass
    8394             : 
    8395          66 :                     if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
    8396           0 :                         DayltgInterReflectedIllumTransBmBmMult = 0.0; // No beam, diffuse only
    8397             :                     }
    8398             : 
    8399             :                     // Daylighting shelf simplification:  No beam makes it past end of shelf, all light is diffuse
    8400          66 :                     if (InShelfSurf > 0) {                            // Inside daylighting shelf
    8401           0 :                         DayltgInterReflectedIllumTransBmBmMult = 0.0; // No beam, diffuse only (Not sure if this really works)
    8402             :                                                                       // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
    8403             :                     }
    8404             : 
    8405          66 :                     state.dataDaylightingManager->WLUMSU(IHR, JB + 1) += ZSU1 * TransMult(JB) / DataGlobalConstants::Pi;
    8406          66 :                     state.dataDaylightingManager->WLUMSUdisk(IHR, JB + 1) =
    8407          66 :                         ZSU1 * DayltgInterReflectedIllumTransBmBmMult(JB) / DataGlobalConstants::Pi;
    8408          66 :                     FLFWSU(JB + 1) += ZSU1 * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    8409          66 :                     FLFWSUdisk(JB + 1) = ZSU1 * DayltgInterReflectedIllumTransBmBmMult(JB);
    8410          66 :                     FLCWSU(JB + 1) += ZSU1 * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8411             :                 } // End of loop over slat angles
    8412             :             }     // End of window with shade or blind
    8413             :         }         // COSBSun > 0
    8414             :     }             // SurfSunlitFracHR > 0
    8415             : 
    8416             :     // Beam reaching window after specular reflection from exterior obstruction
    8417             : 
    8418             :     // In the following, Beam normal illuminance times ZSU1refl = illuminance on window due to
    8419             :     // specular reflection from exterior surfaces
    8420             : 
    8421      319816 :     if (state.dataSurface->CalcSolRefl && state.dataSurface->SurfWinOriginalClass(IWin) != SurfaceClass::TDD_Dome) {
    8422          96 :         ZSU1refl = state.dataSurface->SurfReflFacBmToBmSolObs(IHR, IWin);
    8423             : 
    8424          96 :         if (ZSU1refl > 0.0) {
    8425             :             // Contribution to window luminance and downgoing flux
    8426             : 
    8427             :             // -- Bare window. We use diffuse-diffuse transmittance here rather than beam-beam to avoid
    8428             :             //    complications due to specular reflection from multiple exterior surfaces
    8429             : 
    8430           0 :             TVisSunRefl = state.dataConstruction->Construct(IConst).TransDiffVis * state.dataSurface->SurfWinGlazedFrac(IWin) *
    8431           0 :                           state.dataSurface->SurfWinLightWellEff(IWin);
    8432             :             // In the following it is assumed that all reflected beam is going downward, as it would be in the
    8433             :             // important case of reflection from a highly glazed facade of a neighboring building. However, in
    8434             :             // rare cases (such as upward specular reflection from a flat horizontal skylight) it may
    8435             :             // actually be going upward.
    8436           0 :             FLFWSUdisk(1) += ZSU1refl * TVisSunRefl;
    8437             : 
    8438             :             // -- Window with shade, blind or diffusing glass
    8439             : 
    8440           0 :             if (ShadeOn || BlindOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
    8441           0 :                 DayltgInterReflectedIllumTransBmBmMult = 0.0;
    8442           0 :                 TransMult = 0.0;
    8443             : 
    8444           0 :                 for (JB = 1; JB <= MaxSlatAngs; ++JB) {
    8445           0 :                     if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
    8446             : 
    8447           0 :                     if (ShadeOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) { // Shade on or diffusing glass
    8448           0 :                         int IConstShaded = state.dataSurface->SurfWinActiveShadedConstruction(IWin);
    8449           0 :                         if (state.dataSurface->SurfWinSolarDiffusing(IWin)) IConstShaded = state.dataSurface->Surface(IWin).Construction;
    8450           0 :                         TransMult(1) = state.dataConstruction->Construct(IConstShaded).TransDiffVis * state.dataSurface->SurfWinGlazedFrac(IWin) *
    8451           0 :                                        state.dataSurface->SurfWinLightWellEff(IWin);
    8452             : 
    8453           0 :                     } else if (ScreenOn) { // Exterior screen on
    8454           0 :                         TransScDiffDiffFront = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).DifDifTransVis;
    8455           0 :                         TransMult(1) = TransScDiffDiffFront *
    8456           0 :                                        (state.dataConstruction->Construct(IConst).TransDiffVis / (1.0 - ReflGlDiffDiffFront * ReflScDiffDiffBack)) *
    8457           0 :                                        state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8458             : 
    8459             :                     } else { // Blind on
    8460           0 :                         TransBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
    8461           0 :                         if (ShType == WinShadingType::IntBlind) { // Interior blind
    8462           0 :                             ReflBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
    8463           0 :                             TransMult(JB) = TVisSunRefl * (TransBlDiffDiffFront + ReflBlDiffDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront /
    8464           0 :                                                                                       (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack));
    8465             : 
    8466           0 :                         } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind
    8467           0 :                             TransMult(JB) = TransBlDiffDiffFront *
    8468           0 :                                             (state.dataConstruction->Construct(IConst).TransDiffVis /
    8469           0 :                                              (1.0 - ReflGlDiffDiffFront * state.dataHeatBal->Blind(BlNum).VisBackDiffDiffRefl(JB))) *
    8470           0 :                                             state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
    8471             : 
    8472             :                         } else { // Between-glass blind
    8473           0 :                             t1 = state.dataConstruction->Construct(IConst).tBareVisDiff(1);
    8474           0 :                             tfshBd = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
    8475           0 :                             rfshB = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
    8476           0 :                             if (state.dataConstruction->Construct(IConst).TotGlassLayers == 2) { // 2 glass layers
    8477           0 :                                 TransMult(JB) =
    8478           0 :                                     t1 * (tfshBd * (1.0 + rfd2 * rbshd) + rfshB * rbd1 * tfshd) * td2 * state.dataSurface->SurfWinLightWellEff(IWin);
    8479             :                             } else { // 3 glass layers; blind between layers 2 and 3
    8480           0 :                                 t2 = state.dataConstruction->Construct(IConst).tBareVisDiff(2);
    8481           0 :                                 TransMult(JB) = t1 * t2 * (tfshBd * (1.0 + rfd3 * rbshd) + rfshB * (rbd2 * tfshd + td2 * rbd1 * td2 * tfshd)) * td3 *
    8482           0 :                                                 state.dataSurface->SurfWinLightWellEff(IWin);
    8483             :                             }
    8484             :                         } // End of check of interior/exterior/between-glass blind
    8485             :                     }     // ShadeOn/BlindOn
    8486             : 
    8487           0 :                     state.dataDaylightingManager->WLUMSU(IHR, JB + 1) += ZSU1refl * TransMult(JB) / DataGlobalConstants::Pi;
    8488           0 :                     FLFWSU(JB + 1) += ZSU1refl * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
    8489           0 :                     FLCWSU(JB + 1) += ZSU1refl * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
    8490             :                 } // End of loop over slat angles
    8491             :             }     // End of check if window has shade, blind or diffusing glass
    8492             :         }         // End of check if ZSU1refl > 0.0
    8493             :     }             // End of check if solar reflections are in effect
    8494             : 
    8495             :     // Sun-related portion of internally reflected illuminance
    8496             : 
    8497      959448 :     for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
    8498      959448 :         if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
    8499             : 
    8500             :         // Full area of window is used in following since effect of dividers on reducing
    8501             :         // effective window transmittance already accounted for in calc of FLFWSU and FLCWSU
    8502             :         // CR 7869 added effect of intervening interior windows on transmittance and
    8503             :         // added inside surface area of adjacent zone
    8504      639632 :         state.dataDaylightingManager->EINTSU(IHR, JSH) =
    8505     1279264 :             (FLFWSU(JSH) * state.dataSurface->SurfWinRhoFloorWall(IWin) + FLCWSU(JSH) * state.dataSurface->SurfWinRhoCeilingWall(IWin)) *
    8506     1279264 :             (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
    8507      639632 :             (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
    8508             : 
    8509     1918896 :         state.dataDaylightingManager->EINTSUdisk(IHR, JSH) = FLFWSUdisk(JSH) * state.dataSurface->SurfWinRhoFloorWall(IWin) *
    8510     1279264 :                                                              (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
    8511      639632 :                                                              (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
    8512             :     }
    8513      319816 : }
    8514             : 
    8515        1674 : void ComplexFenestrationLuminances(EnergyPlusData &state,
    8516             :                                    int const IWin,
    8517             :                                    int const WinEl,
    8518             :                                    int const NBasis,
    8519             :                                    int const IHR,
    8520             :                                    int const iRefPoint,
    8521             :                                    Array2<Real64> &ElementLuminanceSky,      // sky related luminance at window element (exterior side)
    8522             :                                    Array1D<Real64> &ElementLuminanceSun,     // sun related luminance at window element (exterior side),
    8523             :                                    Array1D<Real64> &ElementLuminanceSunDisk, // sun related luminance at window element (exterior side),
    8524             :                                    DataDaylighting::CalledFor const CalledFrom,
    8525             :                                    int const MapNum)
    8526             : {
    8527             : 
    8528             :     // SUBROUTINE INFORMATION:
    8529             :     //       AUTHOR         Simon Vidanovic
    8530             :     //       DATE WRITTEN   June 2013
    8531             :     //       MODIFIED       na
    8532             :     //       RE-ENGINEERED  na
    8533             : 
    8534             :     int iIncElem;
    8535             :     int iSky;
    8536             :     int SolBmIndex;
    8537             :     Real64 LambdaInc;
    8538             :     Real64 Altitude;
    8539             :     Real64 Azimuth;
    8540             :     int CurCplxFenState;
    8541             :     Real64 SunObstrMultiplier; // sun obstruction multiplier used to determine if sun hit the ground point
    8542             :     Real64 ObstrTrans;         // product of all surface transmittances intersecting incoming beam
    8543             : 
    8544             :     Real64 BeamObstrMultiplier; // beam obstruction multiplier in case incoming beam is from the ground
    8545             :     bool hitObs;                // True iff obstruction is hit
    8546             :     auto &ComplexFenestrationLuminancesObsHitPt =
    8547        1674 :         state.dataDaylightingManager->ComplexFenestrationLuminancesObsHitPt; // Coordinates of hit point on an obstruction (m)
    8548             :     auto &ComplexFenestrationLuminancesGroundHitPt =
    8549             :         state.dataDaylightingManager
    8550        1674 :             ->ComplexFenestrationLuminancesGroundHitPt; // Coordinates of point that ray from window center hits the ground (m)
    8551             : 
    8552             :     int NRefl;          // number of exterior obstructions
    8553             :     int iReflElem;      // incoming direction blocking surfaces element counter
    8554             :     int iReflElemIndex; // reflection element index
    8555             : 
    8556             :     int NGnd;          // number of ground elements
    8557             :     int iGndElem;      // ground elements counter
    8558             :     int iGndElemIndex; // ground element index
    8559             : 
    8560        1674 :     CurCplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
    8561             : 
    8562             :     // Calculate luminance from sky and sun excluding exterior obstruction transmittances and obstruction multipliers
    8563        1674 :     SolBmIndex = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).SolBmIndex(IHR, state.dataGlobal->TimeStep);
    8564      244404 :     for (iIncElem = 1; iIncElem <= NBasis; ++iIncElem) {
    8565      242730 :         LambdaInc = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.Lamda(iIncElem);
    8566             :         // COSB = ComplexWind(IWin)%Geom(CurCplxFenState)%CosInc(iIncElem)
    8567             :         // DA = ComplexWind(IWin)%Geom(CurCplxFenState)%DAInc(iIncElem)
    8568      242730 :         Altitude = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).pInc(iIncElem).Altitude;
    8569      242730 :         Azimuth = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).pInc(iIncElem).Azimuth;
    8570      242730 :         if (Altitude > 0.0) {
    8571             :             // Ray from sky element
    8572      535680 :             for (iSky = 1; iSky <= 4; ++iSky) {
    8573      428544 :                 ElementLuminanceSky(iSky, iIncElem) = DayltgSkyLuminance(state, iSky, Azimuth, Altitude) * LambdaInc;
    8574             :             }
    8575      135594 :         } else if (Altitude < 0.0) {
    8576             :             // Ray from ground element
    8577             :             // BeamObstrMultiplier = ComplexWind(IWin)%DaylghtGeom(CurCplxFenState)%GndObstrMultiplier(WinEl, iIncElem)
    8578      535680 :             for (iSky = 1; iSky <= 4; ++iSky) {
    8579      428544 :                 ElementLuminanceSky(iSky, iIncElem) =
    8580      428544 :                     state.dataDaylightingManager->GILSK(IHR, iSky) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
    8581             :             }
    8582      107136 :             ElementLuminanceSun(iIncElem) =
    8583      107136 :                 state.dataDaylightingManager->GILSU(IHR) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
    8584             :         } else {
    8585             :             // Ray from the element which is half sky and half ground
    8586      142290 :             for (iSky = 1; iSky <= 4; ++iSky) {
    8587             :                 // in this case half of the pach is coming from the sky and half from the ground
    8588      113832 :                 ElementLuminanceSky(iSky, iIncElem) = 0.5 * DayltgSkyLuminance(state, iSky, Azimuth, Altitude) * LambdaInc;
    8589      341496 :                 ElementLuminanceSky(iSky, iIncElem) += 0.5 * state.dataDaylightingManager->GILSK(IHR, iSky) *
    8590      227664 :                                                        state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
    8591             :             }
    8592       28458 :             ElementLuminanceSun(iIncElem) =
    8593       28458 :                 0.5 * state.dataDaylightingManager->GILSU(IHR) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
    8594             :         }
    8595             :         // Sun beam calculations
    8596      242730 :         if ((SolBmIndex == iIncElem) && (state.dataHeatBal->SurfSunlitFracHR(IHR, IWin) > 0.0)) {
    8597        1008 :             ElementLuminanceSunDisk(iIncElem) = 1.0;
    8598             :         }
    8599             :     }
    8600             : 
    8601             :     // add exterior obstructions transmittances to calculated luminances
    8602        1674 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    8603        1674 :         NRefl = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).NReflSurf(WinEl);
    8604             :     } else {
    8605           0 :         assert(MapNum > 0);
    8606           0 :         NRefl = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).NReflSurf(WinEl);
    8607             :     }
    8608        1674 :     for (iReflElem = 1; iReflElem <= NRefl; ++iReflElem) {
    8609           0 :         if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    8610           0 :             ObstrTrans = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).TransOutSurf(iReflElem, WinEl);
    8611           0 :             iReflElemIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefSurfIndex(iReflElem, WinEl);
    8612             :         } else {
    8613           0 :             ObstrTrans =
    8614           0 :                 state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).TransOutSurf(iReflElem, WinEl);
    8615           0 :             iReflElemIndex =
    8616           0 :                 state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefSurfIndex(iReflElem, WinEl);
    8617             :         }
    8618             : 
    8619           0 :         for (iSky = 1; iSky <= 4; ++iSky) {
    8620           0 :             ElementLuminanceSky(iSky, iReflElemIndex) *= ObstrTrans;
    8621             :         }
    8622           0 :         ElementLuminanceSun(iReflElemIndex) *= ObstrTrans;
    8623           0 :         ElementLuminanceSunDisk(iReflElemIndex) *= ObstrTrans;
    8624             :     }
    8625             : 
    8626             :     // add exterior ground element obstruction multipliers to calculated luminances. For sun reflection, calculate if
    8627             :     // sun reaches the ground for that point
    8628        1674 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    8629        1674 :         NGnd = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).NGnd(WinEl);
    8630             :     } else {
    8631           0 :         NGnd = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).NGnd(WinEl);
    8632             :     }
    8633        3348 :     Vector3<Real64> const SUNCOS_IHR(state.dataSurface->SurfSunCosHourly(IHR));
    8634      108810 :     for (iGndElem = 1; iGndElem <= NGnd; ++iGndElem) {
    8635             :         // case for sky elements. Integration is done over upper ground hemisphere to determine how many obstructions
    8636             :         // were hit in the process
    8637      107136 :         if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    8638      107136 :             BeamObstrMultiplier =
    8639      107136 :                 state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndObstrMultiplier(iGndElem, WinEl);
    8640      107136 :             iGndElemIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndIndex(iGndElem, WinEl);
    8641             :         } else {
    8642           0 :             BeamObstrMultiplier = state.dataBSDFWindow->ComplexWind(IWin)
    8643           0 :                                       .DaylghtGeom(CurCplxFenState)
    8644           0 :                                       .IlluminanceMap(iRefPoint, MapNum)
    8645           0 :                                       .GndObstrMultiplier(iGndElem, WinEl);
    8646           0 :             iGndElemIndex =
    8647           0 :                 state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).GndIndex(iGndElem, WinEl);
    8648             :         }
    8649      535680 :         for (iSky = 1; iSky <= 4; ++iSky) {
    8650      428544 :             ElementLuminanceSky(iSky, iGndElemIndex) *= BeamObstrMultiplier;
    8651             :         }
    8652             : 
    8653             :         // direct sun disk reflect off the ground
    8654      107136 :         SunObstrMultiplier = 1.0;
    8655      107136 :         if (state.dataSurface->CalcSolRefl) {
    8656             :             // Sun reaches ground point if vector from this point to the sun is unobstructed
    8657      107136 :             hitObs = false;
    8658      204042 :             for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    8659      107136 :                 if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    8660      107136 :                     ComplexFenestrationLuminancesGroundHitPt(1) =
    8661      107136 :                         state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndPt(iGndElem, WinEl).x;
    8662      107136 :                     ComplexFenestrationLuminancesGroundHitPt(2) =
    8663      107136 :                         state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndPt(iGndElem, WinEl).y;
    8664      107136 :                     ComplexFenestrationLuminancesGroundHitPt(3) =
    8665      107136 :                         state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndPt(iGndElem, WinEl).z;
    8666             :                 } else {
    8667           0 :                     ComplexFenestrationLuminancesGroundHitPt(1) = state.dataBSDFWindow->ComplexWind(IWin)
    8668           0 :                                                                       .DaylghtGeom(CurCplxFenState)
    8669           0 :                                                                       .IlluminanceMap(iRefPoint, MapNum)
    8670           0 :                                                                       .GndPt(iGndElem, WinEl)
    8671           0 :                                                                       .x;
    8672           0 :                     ComplexFenestrationLuminancesGroundHitPt(2) = state.dataBSDFWindow->ComplexWind(IWin)
    8673           0 :                                                                       .DaylghtGeom(CurCplxFenState)
    8674           0 :                                                                       .IlluminanceMap(iRefPoint, MapNum)
    8675           0 :                                                                       .GndPt(iGndElem, WinEl)
    8676           0 :                                                                       .y;
    8677           0 :                     ComplexFenestrationLuminancesGroundHitPt(3) = state.dataBSDFWindow->ComplexWind(IWin)
    8678           0 :                                                                       .DaylghtGeom(CurCplxFenState)
    8679           0 :                                                                       .IlluminanceMap(iRefPoint, MapNum)
    8680           0 :                                                                       .GndPt(iGndElem, WinEl)
    8681           0 :                                                                       .z;
    8682             :                 }
    8683             : 
    8684             :                 PierceSurface(state, ObsSurfNum, ComplexFenestrationLuminancesGroundHitPt, SUNCOS_IHR, ComplexFenestrationLuminancesObsHitPt, hitObs);
    8685      107136 :                 if (hitObs) break;
    8686             :             }
    8687      107136 :             if (hitObs) SunObstrMultiplier = 0.0;
    8688             :         }
    8689      107136 :         ElementLuminanceSun(iGndElemIndex) *= SunObstrMultiplier;
    8690             :     }
    8691        1674 : }
    8692             : 
    8693         186 : void DayltgInterReflectedIllumComplexFenestration(EnergyPlusData &state,
    8694             :                                                   int const IWin,            // Window index
    8695             :                                                   int const WinEl,           // Current window element counter
    8696             :                                                   int const IHR,             // Hour of day
    8697             :                                                   int const daylightCtrlNum, // Daylighting control number
    8698             :                                                   int const iRefPoint,       // reference point counter
    8699             :                                                   DataDaylighting::CalledFor const CalledFrom,
    8700             :                                                   int const MapNum)
    8701             : {
    8702             : 
    8703             :     // SUBROUTINE INFORMATION:
    8704             :     //       AUTHOR         Simon Vidanovic
    8705             :     //       DATE WRITTEN   April 2013
    8706             :     //       MODIFIED       na
    8707             :     //       RE-ENGINEERED  na
    8708             : 
    8709             :     // PURPOSE OF THIS SUBROUTINE:
    8710             :     // Called from CalcDayltgCoefficients for each complex (bsdf) fenestration and reference point in a daylit
    8711             :     // space, for each sun position. Calculates illuminance (EINTSK and EINTSU) at reference point due
    8712             :     // to internally reflected light by integrating to determine the amount of flux from
    8713             :     // sky and ground (and beam reflected from obstructions) transmitted through
    8714             :     // the center of the window and then reflecting this
    8715             :     // light from the inside surfaces of the space.
    8716             : 
    8717         372 :     Array2D<Real64> FLSK;     // Sky related luminous flux
    8718         372 :     Array1D<Real64> FLSU;     // Sun related luminous flux, excluding entering beam
    8719         372 :     Array1D<Real64> FLSUdisk; // Sun related luminous flux, due to entering beam
    8720             : 
    8721         372 :     Array2D<Real64> FirstFluxSK;     // Sky related first reflected flux
    8722         372 :     Array1D<Real64> FirstFluxSU;     // Sun related first reflected flux, excluding entering beam
    8723         372 :     Array1D<Real64> FirstFluxSUdisk; // Sun related first reflected flux, due to entering beam
    8724             : 
    8725         372 :     Array2D<Real64> ElementLuminanceSky;     // sky related luminance at window element (exterior side)
    8726         372 :     Array1D<Real64> ElementLuminanceSun;     // sun related luminance at window element (exterior side), exluding beam
    8727         372 :     Array1D<Real64> ElementLuminanceSunDisk; // sun related luminance at window element (exterior side), due to sun beam
    8728             :     Real64 FLSUTot;
    8729             :     Real64 FLSUdiskTot;
    8730             : 
    8731             :     // Total for first relflected fluxes
    8732         186 :     auto &FFSKTot = state.dataDaylightingManager->FFSKTot;
    8733             :     Real64 FFSUTot;
    8734             :     Real64 FFSUdiskTot;
    8735             : 
    8736             :     Real64 COSIncSun; // cosine of sun incidence angle (from basis elements)
    8737             : 
    8738             :     int iSky;   // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
    8739             :     int iConst; // Construction number
    8740             : 
    8741             :     int CurCplxFenState;
    8742             :     int NIncBasis;
    8743             :     int NTrnBasis;
    8744             :     int SolBmIndex; // index of current sun position
    8745             : 
    8746             :     int iIncElem;  // incoming direction counter
    8747             :     int iBackElem; // outgoing direction counter
    8748             : 
    8749             :     Real64 LambdaInc; // current lambda value for incoming direction
    8750             :     // REAL(r64) :: LambdaTrn  ! current lambda value for incoming direction
    8751             :     Real64 dirTrans; // directional bsdf transmittance
    8752             : 
    8753         186 :     CurCplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
    8754         186 :     iConst = state.dataSurface->SurfaceWindow(IWin).ComplexFen.State(CurCplxFenState).Konst;
    8755         186 :     NTrnBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Trn.NBasis;
    8756             : 
    8757         186 :     if (!allocated(FLSK)) FLSK.allocate(4, NTrnBasis);
    8758         186 :     FLSK = 0.0;
    8759         186 :     if (!allocated(FLSU)) FLSU.dimension(NTrnBasis, 0.0);
    8760         186 :     if (!allocated(FLSUdisk)) FLSUdisk.dimension(NTrnBasis, 0.0);
    8761             : 
    8762         186 :     if (!allocated(FirstFluxSK)) FirstFluxSK.allocate(4, NTrnBasis);
    8763         186 :     FirstFluxSK = 0.0;
    8764         186 :     if (!allocated(FirstFluxSU)) FirstFluxSU.dimension(NTrnBasis, 0.0);
    8765         186 :     if (!allocated(FirstFluxSUdisk)) FirstFluxSUdisk.dimension(NTrnBasis, 0.0);
    8766             : 
    8767         186 :     NIncBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.NBasis;
    8768         186 :     if (!allocated(ElementLuminanceSky)) ElementLuminanceSky.allocate(4, NIncBasis);
    8769         186 :     ElementLuminanceSky = 0.0;
    8770         186 :     if (!allocated(ElementLuminanceSun)) ElementLuminanceSun.dimension(NIncBasis, 0.0);
    8771         186 :     if (!allocated(ElementLuminanceSunDisk)) ElementLuminanceSunDisk.dimension(NIncBasis, 0.0);
    8772             : 
    8773             :     // Integration over sky/ground/sun elements is done over window incoming basis element and flux is calculated for each
    8774             :     // outgoing direction. This is used to calculate first reflected flux
    8775             : 
    8776         186 :     ComplexFenestrationLuminances(
    8777             :         state, IWin, WinEl, NIncBasis, IHR, iRefPoint, ElementLuminanceSky, ElementLuminanceSun, ElementLuminanceSunDisk, CalledFrom, MapNum);
    8778             : 
    8779             :     // luminance from sun disk needs to include fraction of sunlit area
    8780         186 :     SolBmIndex = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).SolBmIndex(IHR, state.dataGlobal->TimeStep);
    8781         186 :     if (SolBmIndex > 0) {
    8782         122 :         COSIncSun = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).CosInc(SolBmIndex);
    8783             :     } else {
    8784          64 :         COSIncSun = 0.0;
    8785             :     }
    8786         186 :     ElementLuminanceSunDisk *= state.dataHeatBal->SurfSunlitFracHR(IHR, IWin) * COSIncSun;
    8787             : 
    8788             :     //        FLSKTot = 0.0;
    8789         186 :     FLSUTot = 0.0;
    8790         186 :     FLSUdiskTot = 0.0;
    8791         186 :     FFSKTot = 0.0;
    8792         186 :     FFSUTot = 0.0;
    8793         186 :     FFSUdiskTot = 0.0;
    8794             :     // now calculate flux into each outgoing direction by integrating over all incoming directions
    8795       27156 :     for (iBackElem = 1; iBackElem <= NTrnBasis; ++iBackElem) {
    8796     3937620 :         for (iIncElem = 1; iIncElem <= NIncBasis; ++iIncElem) {
    8797     3910650 :             LambdaInc = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.Lamda(iIncElem);
    8798     3910650 :             dirTrans = state.dataConstruction->Construct(iConst).BSDFInput.VisFrtTrans(iBackElem, iIncElem);
    8799             : 
    8800    19553250 :             for (iSky = 1; iSky <= 4; ++iSky) {
    8801    15642600 :                 FLSK(iSky, iBackElem) += dirTrans * LambdaInc * ElementLuminanceSky(iSky, iIncElem);
    8802             :             }
    8803             : 
    8804     3910650 :             FLSU(iBackElem) += dirTrans * LambdaInc * ElementLuminanceSun(iIncElem);
    8805     3910650 :             FLSUdisk(iBackElem) += dirTrans * LambdaInc * ElementLuminanceSunDisk(iIncElem);
    8806             :         }
    8807             : 
    8808      134850 :         for (iSky = 1; iSky <= 4; ++iSky) {
    8809      107880 :             FirstFluxSK(iSky, iBackElem) =
    8810      107880 :                 FLSK(iSky, iBackElem) * state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).AveRhoVisOverlap(iBackElem);
    8811      107880 :             FFSKTot(iSky) += FirstFluxSK(iSky, iBackElem);
    8812             :             //                FLSKTot( iSky ) += FLSK( iSky, iBackElem );
    8813             :         }
    8814       26970 :         FirstFluxSU(iBackElem) = FLSU(iBackElem) * state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).AveRhoVisOverlap(iBackElem);
    8815       26970 :         FFSUTot += FirstFluxSU(iBackElem);
    8816       26970 :         FLSUTot += FLSU(iBackElem);
    8817             : 
    8818       26970 :         FirstFluxSUdisk(iBackElem) = FLSUdisk(iBackElem) * state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).AveRhoVisOverlap(iBackElem);
    8819       26970 :         FFSUdiskTot += FirstFluxSUdisk(iBackElem);
    8820       26970 :         FLSUdiskTot += FLSUdisk(iBackElem);
    8821             :     }
    8822             : 
    8823         186 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex);
    8824         186 :     Real64 EnclInsideSurfArea = thisEnclDaylight.totInsSurfArea;
    8825         930 :     for (iSky = 1; iSky <= 4; ++iSky) {
    8826        2232 :         state.dataDaylightingManager->EINTSK(IHR, 1, iSky) = FFSKTot(iSky) *
    8827        1488 :                                                              (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
    8828         744 :                                                              (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
    8829             :     }
    8830         372 :     state.dataDaylightingManager->EINTSU(IHR, 1) = FFSUTot * (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
    8831         186 :                                                    (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
    8832         372 :     state.dataDaylightingManager->EINTSUdisk(IHR, 1) = FFSUdiskTot *
    8833         372 :                                                        (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
    8834         186 :                                                        (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
    8835             : 
    8836         186 :     if (allocated(FLSK)) FLSK.deallocate();
    8837         186 :     if (allocated(FLSU)) FLSU.deallocate();
    8838         186 :     if (allocated(FLSUdisk)) FLSUdisk.deallocate();
    8839             : 
    8840         186 :     if (allocated(FirstFluxSK)) FirstFluxSK.deallocate();
    8841         186 :     if (allocated(FirstFluxSU)) FirstFluxSU.deallocate();
    8842         186 :     if (allocated(FirstFluxSUdisk)) FirstFluxSUdisk.deallocate();
    8843             : 
    8844         186 :     if (allocated(ElementLuminanceSky)) ElementLuminanceSky.deallocate();
    8845         186 :     if (allocated(ElementLuminanceSun)) ElementLuminanceSun.deallocate();
    8846         186 :     if (allocated(ElementLuminanceSunDisk)) ElementLuminanceSunDisk.deallocate();
    8847         186 : }
    8848             : 
    8849        1488 : void DayltgDirectIllumComplexFenestration(EnergyPlusData &state,
    8850             :                                           int const IWin,      // Window index
    8851             :                                           int const WinEl,     // Current window element counter
    8852             :                                           int const IHR,       // Hour of day
    8853             :                                           int const iRefPoint, // reference point index
    8854             :                                           DataDaylighting::CalledFor const CalledFrom,
    8855             :                                           int const MapNum)
    8856             : {
    8857             : 
    8858             :     // SUBROUTINE INFORMATION:
    8859             :     //       AUTHOR         Simon Vidanovic
    8860             :     //       DATE WRITTEN   June 2013
    8861             :     //       MODIFIED       na
    8862             :     //       RE-ENGINEERED  na
    8863             : 
    8864             :     // Luminances from different sources to the window
    8865        2976 :     Array2D<Real64> ElementLuminanceSky; // sky related luminance at window element (exterior side)
    8866        2976 :     Array1D<Real64> ElementLuminanceSun; // sun related luminance at window element (exterior side),
    8867             :     // exluding beam
    8868        2976 :     Array1D<Real64> ElementLuminanceSunDisk; // sun related luminance at window element (exterior side),
    8869             :     // due to sun beam
    8870             : 
    8871        1488 :     auto &WinLumSK = state.dataDaylightingManager->WinLumSK; // Sky related window luminance
    8872        1488 :     auto &EDirSky = state.dataDaylightingManager->EDirSky;   // Sky related direct illuminance
    8873             :     Real64 WinLumSU;                                         // Sun related window luminance, excluding entering beam
    8874             :     Real64 EDirSun;                                          // Sun related direct illuminance, excluding entering beam
    8875             :     int CurCplxFenState;
    8876             :     int NIncBasis;
    8877             :     int RefPointIndex; // reference point patch number
    8878             :     int iIncElem;
    8879             :     int iConst;
    8880             :     int iSky;
    8881             : 
    8882             :     Real64 dirTrans;    // directional BSDF transmittance
    8883             :     Real64 dOmega;      // solid view angle of current element
    8884             :     Real64 zProjection; // z-axe projection of solid view angle (used to calculate amount of light at horizontal surface
    8885             :     // laying at reference point)
    8886             : 
    8887        1488 :     CurCplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
    8888        1488 :     iConst = state.dataSurface->SurfaceWindow(IWin).ComplexFen.State(CurCplxFenState).Konst;
    8889        1488 :     NIncBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.NBasis;
    8890             : 
    8891        1488 :     if (!allocated(ElementLuminanceSky)) ElementLuminanceSky.allocate(4, NIncBasis);
    8892        1488 :     ElementLuminanceSky = 0.0;
    8893        1488 :     if (!allocated(ElementLuminanceSun)) ElementLuminanceSun.dimension(NIncBasis, 0.0);
    8894        1488 :     if (!allocated(ElementLuminanceSunDisk)) ElementLuminanceSunDisk.dimension(NIncBasis, 0.0);
    8895             : 
    8896        1488 :     ComplexFenestrationLuminances(
    8897             :         state, IWin, WinEl, NIncBasis, IHR, iRefPoint, ElementLuminanceSky, ElementLuminanceSun, ElementLuminanceSunDisk, CalledFrom, MapNum);
    8898             : 
    8899             :     // find number of outgoing basis towards current reference point
    8900        1488 :     if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    8901        1488 :         RefPointIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefPointIndex(WinEl);
    8902        1488 :         dOmega = state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint).SolidAngle(WinEl);
    8903        1488 :         zProjection = state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint).SolidAngleVec(WinEl).z;
    8904           0 :     } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    8905           0 :         assert(MapNum > 0);
    8906           0 :         RefPointIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefPointIndex(WinEl);
    8907           0 :         dOmega = state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum).SolidAngle(WinEl);
    8908           0 :         zProjection = state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum).SolidAngleVec(WinEl).z;
    8909             :     }
    8910             : 
    8911        1488 :     WinLumSK = 0.0;
    8912        1488 :     WinLumSU = 0.0;
    8913             :     // WinLumSUdisk = 0.0d0
    8914        1488 :     EDirSky = 0.0;
    8915        1488 :     EDirSun = 0.0;
    8916             :     //        EDirSunDisk = 0.0; //Unused Set but never used
    8917             : 
    8918      217248 :     for (iIncElem = 1; iIncElem <= NIncBasis; ++iIncElem) {
    8919             :         // LambdaInc = ComplexWind(IWin)%Geom(CurCplxFenState)%Inc%Lamda(iIncElem)
    8920      215760 :         dirTrans = state.dataConstruction->Construct(iConst).BSDFInput.VisFrtTrans(RefPointIndex, iIncElem);
    8921             : 
    8922     1078800 :         for (iSky = 1; iSky <= 4; ++iSky) {
    8923      863040 :             WinLumSK(iSky) += dirTrans * ElementLuminanceSky(iSky, iIncElem);
    8924             :         }
    8925             : 
    8926      215760 :         WinLumSU += dirTrans * ElementLuminanceSun(iIncElem);
    8927             : 
    8928             :         // For sun disk need to go throug outgoing directions and see which directions actually contain reference point
    8929             :     }
    8930             : 
    8931        1488 :     if (zProjection > 0.0) {
    8932        5580 :         for (iSky = 1; iSky <= 4; ++iSky) {
    8933        4464 :             EDirSky(iSky) = WinLumSK(iSky) * dOmega * zProjection;
    8934             :         }
    8935        1116 :         EDirSun = WinLumSU * dOmega * zProjection;
    8936             :     }
    8937             : 
    8938             :     // Store solution in global variables
    8939        7440 :     for (iSky = 1; iSky <= 4; ++iSky) {
    8940        5952 :         state.dataDaylightingManager->AVWLSK(IHR, 1, iSky) += WinLumSK(iSky);
    8941        5952 :         state.dataDaylightingManager->EDIRSK(IHR, 1, iSky) += EDirSky(iSky);
    8942             :     }
    8943             : 
    8944        1488 :     state.dataDaylightingManager->AVWLSU(IHR, 1) += WinLumSU;
    8945        1488 :     state.dataDaylightingManager->EDIRSU(IHR, 1) += EDirSun;
    8946             :     // AVWLSUdisk(1,IHR) = AVWLSUdisk(1,IHR) + WinLumSUdisk
    8947        1488 : }
    8948             : 
    8949         186 : void DayltgDirectSunDiskComplexFenestration(EnergyPlusData &state,
    8950             :                                             int const iWin,  // Window index
    8951             :                                             int const iHour, // Hour of day
    8952             :                                             int const iRefPoint,
    8953             :                                             int const NumEl,                             // Total number of window elements
    8954             :                                             Real64 const AZVIEW,                         // Azimuth of view vector in absolute coord system for
    8955             :                                             DataDaylighting::CalledFor const CalledFrom, // indicate  which type of routine called this routine
    8956             :                                             int const MapNum)
    8957             : {
    8958             : 
    8959             :     // SUBROUTINE INFORMATION:
    8960             :     //       AUTHOR         Simon Vidanovic
    8961             :     //       DATE WRITTEN   June 2013
    8962             :     //       MODIFIED       na
    8963             :     //       RE-ENGINEERED  na
    8964             : 
    8965             :     // PURPOSE OF THIS SUBROUTINE:
    8966             :     // Calculate illuminance from sun disk for complex fenestration systems
    8967             : 
    8968             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8969             :     int CurCplxFenState;
    8970             :     int iConst;
    8971             :     int SolBmIndex;
    8972             :     int NTrnBasis;
    8973             :     int iTrnElem;
    8974         186 :     Real64 WindowSolidAngleDaylightPoint(0.0);
    8975             :     Real64 XR;
    8976             :     Real64 YR;
    8977             :     Real64 PosFac;
    8978             :     Real64 dirTrans;
    8979             :     Real64 LambdaTrn;
    8980             :     Real64 WinLumSunDisk; // window luminance from sun disk
    8981             :     Real64 ELumSunDisk;   // window illuminance from sun disk
    8982             :     Real64 TransBeam;     // transmittance of the beam for given direction
    8983         186 :     auto &DayltgDirectSunDiskComplexFenestrationV = state.dataDaylightingManager->DayltgDirectSunDiskComplexFenestrationV;       // temporary vector
    8984         186 :     auto &DayltgDirectSunDiskComplexFenestrationRWin = state.dataDaylightingManager->DayltgDirectSunDiskComplexFenestrationRWin; // Window center
    8985             :     Real64 RayZ; // z component of unit vector for outgoing direction
    8986             :     bool refPointIntersect;
    8987             : 
    8988         186 :     CurCplxFenState = state.dataSurface->SurfaceWindow(iWin).ComplexFen.CurrentState;
    8989         186 :     iConst = state.dataSurface->SurfaceWindow(iWin).ComplexFen.State(CurCplxFenState).Konst;
    8990         186 :     SolBmIndex = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).SolBmIndex(iHour, state.dataGlobal->TimeStep);
    8991             : 
    8992         186 :     switch (CalledFrom) {
    8993         186 :     case DataDaylighting::CalledFor::RefPoint: {
    8994         186 :         WindowSolidAngleDaylightPoint = state.dataSurface->SurfaceWindow(iWin).SolidAngAtRefPtWtd(iRefPoint);
    8995         186 :     } break;
    8996           0 :     case DataDaylighting::CalledFor::MapPoint: {
    8997           0 :         WindowSolidAngleDaylightPoint = 0.0;
    8998           0 :     } break;
    8999           0 :     default: {
    9000           0 :         assert(false); // Bad CalledFrom argument
    9001             :     } break;
    9002             :     }
    9003             : 
    9004         186 :     if (WindowSolidAngleDaylightPoint < 1e-6) return;
    9005             : 
    9006           0 :     WinLumSunDisk = 0.0;
    9007           0 :     ELumSunDisk = 0.0;
    9008           0 :     NTrnBasis = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).Trn.NBasis;
    9009           0 :     for (iTrnElem = 1; iTrnElem <= NTrnBasis; ++iTrnElem) {
    9010             :         // if ray from any part of the window can reach reference point
    9011           0 :         if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    9012           0 :             refPointIntersect =
    9013           0 :                 state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefPointIntersection(iTrnElem);
    9014           0 :         } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
    9015           0 :             assert(MapNum > 0);
    9016           0 :             refPointIntersect =
    9017           0 :                 state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefPointIntersection(iTrnElem);
    9018             :         }
    9019           0 :         if (refPointIntersect) {
    9020           0 :             if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
    9021           0 :                 PosFac = state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefPtIntPosFac(iTrnElem);
    9022             :             } else {
    9023           0 :                 PosFac =
    9024           0 :                     state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefPtIntPosFac(iTrnElem);
    9025             :             }
    9026           0 :             RayZ = -state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).z;
    9027             : 
    9028             :             // Need to recalculate position factor for dominant direction in case of specular bsdf.  Otherwise this will produce
    9029             :             // very inaccurate results because of position factor of the sun and bsdf pach can vary by lot
    9030           0 :             if (iTrnElem == SolBmIndex) {
    9031           0 :                 XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - state.dataDaylightingManager->THSUN) + 0.001);
    9032           0 :                 YR = std::tan(state.dataDaylightingManager->PHSUN + 0.001);
    9033           0 :                 PosFac = DayltgGlarePositionFactor(XR, YR);
    9034           0 :                 RayZ = state.dataDaylightingManager->SPHSUN;
    9035             :             }
    9036             : 
    9037           0 :             if (PosFac != 0.0) {
    9038           0 :                 if (SolBmIndex > 0) {
    9039           0 :                     dirTrans = state.dataConstruction->Construct(iConst).BSDFInput.VisFrtTrans(iTrnElem, SolBmIndex);
    9040             :                 } else {
    9041           0 :                     dirTrans = 0.0;
    9042             :                 }
    9043           0 :                 LambdaTrn = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).Trn.Lamda(iTrnElem);
    9044             : 
    9045           0 :                 DayltgDirectSunDiskComplexFenestrationV(1) = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).x;
    9046           0 :                 DayltgDirectSunDiskComplexFenestrationV(2) = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).y;
    9047           0 :                 DayltgDirectSunDiskComplexFenestrationV(3) = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).z;
    9048           0 :                 DayltgDirectSunDiskComplexFenestrationV = -DayltgDirectSunDiskComplexFenestrationV;
    9049             : 
    9050           0 :                 DayltgDirectSunDiskComplexFenestrationRWin(1) = state.dataSurface->Surface(iWin).Centroid.x;
    9051           0 :                 DayltgDirectSunDiskComplexFenestrationRWin(2) = state.dataSurface->Surface(iWin).Centroid.y;
    9052           0 :                 DayltgDirectSunDiskComplexFenestrationRWin(3) = state.dataSurface->Surface(iWin).Centroid.z;
    9053             : 
    9054           0 :                 DayltgHitObstruction(
    9055             :                     state, iHour, iWin, DayltgDirectSunDiskComplexFenestrationRWin, DayltgDirectSunDiskComplexFenestrationV, TransBeam);
    9056             : 
    9057           0 :                 WinLumSunDisk += (14700.0 * std::sqrt(0.000068 * PosFac) * double(NumEl) / std::pow(WindowSolidAngleDaylightPoint, 0.8)) * dirTrans *
    9058           0 :                                  LambdaTrn * TransBeam;
    9059             : 
    9060           0 :                 ELumSunDisk += RayZ * dirTrans * LambdaTrn * TransBeam;
    9061             :             }
    9062             :         }
    9063             :     }
    9064             : 
    9065           0 :     state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = WinLumSunDisk;
    9066           0 :     state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = ELumSunDisk;
    9067             : }
    9068             : 
    9069   249137524 : Real64 DayltgSkyLuminance(EnergyPlusData &state,
    9070             :                           int const ISky,     // Sky type: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
    9071             :                           Real64 const THSKY, // Azimuth and altitude of sky element (radians)
    9072             :                           Real64 const PHSKY)
    9073             : {
    9074             : 
    9075             :     // SUBROUTINE INFORMATION:
    9076             :     //       AUTHOR         Fred Winkelmann
    9077             :     //       DATE WRITTEN   July 1997
    9078             :     //       MODIFIED       na
    9079             :     //       RE-ENGINEERED  na
    9080             : 
    9081             :     // PURPOSE OF THIS SUBROUTINE:
    9082             :     // Called by CalcDayltgCoefficients, DayltgExtHorizIllum AND DayltgInterReflectedIllum.  gives
    9083             :     // luminance in cd/m2 for four different sky types, as described in R.Perez, P.Ineichen,
    9084             :     // R.Seals, J.Michalsky and R.Stewart, "Modeling daylight availability and irradiance
    9085             :     // components from direct and global irradiance," Solar Energy 44, 1990, 271-289.
    9086             :     // The luminance distributions in this routine are normalized such that
    9087             :     // the zenith luminance is 1.0, i.e., DayltgSkyLuminance =
    9088             :     // (sky luminance at THSKY, PHSKY)/(zenith luminance), which is dimensionless.
    9089             :     // The sky types are:
    9090             :     // 1. Standard CIE clear sky
    9091             :     // 2. Standard CIE high-turbidity clear sky
    9092             :     // 3. CIE intermediate sky
    9093             :     // 4. CIE overcast sky
    9094             : 
    9095             :     // METHODOLOGY EMPLOYED:
    9096             : 
    9097             :     // REFERENCES:
    9098             :     // Based on DOE-2.1E subroutine DSKYLU, which did only clear and overcast skies.
    9099             : 
    9100             :     // OTHER NOTES:
    9101             :     // THSKY ranges from 0 to 2Pi starting with 0 directly East and rotating clockwise.
    9102             :     // PHSKY ranges from 0 to Pi starting with 0 at the horizon and Pi/2 at the zenith.
    9103             : 
    9104             :     // USE STATEMENTS: na
    9105             : 
    9106             :     // Return value
    9107   249137524 :     Real64 DayltgSkyLuminance(0.0); // Luminance of sky element divided by zenith luminance
    9108             : 
    9109             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    9110             :     Real64 SPHSKY;    // Sine of PHSKY
    9111   249137524 :     Real64 G(0.0);    // Angle between sun and element of sky (radians)
    9112   249137524 :     Real64 COSG(0.0); // Cosine of G
    9113             :     Real64 Z;         // Solar zenith angle (radians)
    9114             :     Real64 Z1;        // Luminance factors (intermediate variables)
    9115             :     Real64 Z2;
    9116             :     Real64 Z3;
    9117             :     Real64 Z4;
    9118             : 
    9119   249137524 :     SPHSKY = max(std::sin(PHSKY), 0.01); // Prevent floating point underflows
    9120   249137524 :     Z = DataGlobalConstants::PiOvr2 - state.dataDaylightingManager->PHSUN;
    9121   249137524 :     if (ISky >= 1 && ISky <= 3) { // Following not needed for overcast sky
    9122   373706286 :         COSG = SPHSKY * state.dataDaylightingManager->SPHSUN +
    9123   186853143 :                std::cos(PHSKY) * state.dataDaylightingManager->CPHSUN * std::cos(THSKY - state.dataDaylightingManager->THSUN);
    9124   186853143 :         COSG = max(DataPrecisionGlobals::constant_minusone, min(COSG, 1.0)); // Prevent out of range due to roundoff
    9125   186853143 :         G = std::acos(COSG);
    9126             :     }
    9127             : 
    9128   249137524 :     if (ISky == 1) { // Clear Sky
    9129    62284381 :         Z1 = 0.910 + 10.0 * std::exp(-3.0 * G) + 0.45 * COSG * COSG;
    9130    62284381 :         Z2 = 1.0 - std::exp(-0.32 / SPHSKY);
    9131    62284381 :         Z3 = 0.27385 * (0.91 + 10.0 * std::exp(-3.0 * Z) + 0.45 * state.dataDaylightingManager->SPHSUN * state.dataDaylightingManager->SPHSUN);
    9132    62284381 :         DayltgSkyLuminance = Z1 * Z2 / Z3;
    9133             : 
    9134   186853143 :     } else if (ISky == 2) { // Clear turbid sky
    9135    62284381 :         Z1 = 0.856 + 16.0 * std::exp(-3.0 * G) + 0.3 * COSG * COSG;
    9136    62284381 :         Z2 = 1.0 - std::exp(-0.32 / SPHSKY);
    9137    62284381 :         Z3 = 0.27385 * (0.856 + 16.0 * std::exp(-3.0 * Z) + 0.3 * state.dataDaylightingManager->SPHSUN * state.dataDaylightingManager->SPHSUN);
    9138    62284381 :         DayltgSkyLuminance = Z1 * Z2 / Z3;
    9139             : 
    9140   124568762 :     } else if (ISky == 3) { // Intermediate sky
    9141    62284381 :         Z1 = (1.35 * (std::sin(3.59 * PHSKY - 0.009) + 2.31) * std::sin(2.6 * state.dataDaylightingManager->PHSUN + 0.316) + PHSKY + 4.799) / 2.326;
    9142    62284381 :         Z2 = std::exp(-G * 0.563 * ((state.dataDaylightingManager->PHSUN - 0.008) * (PHSKY + 1.059) + 0.812));
    9143    62284381 :         Z3 = 0.99224 * std::sin(2.6 * state.dataDaylightingManager->PHSUN + 0.316) + 2.73852;
    9144    62284381 :         Z4 = std::exp(-Z * 0.563 * ((state.dataDaylightingManager->PHSUN - 0.008) * 2.6298 + 0.812));
    9145    62284381 :         DayltgSkyLuminance = Z1 * Z2 / (Z3 * Z4);
    9146             : 
    9147    62284381 :     } else if (ISky == 4) { // Overcast sky
    9148    62284381 :         DayltgSkyLuminance = (1.0 + 2.0 * SPHSKY) / 3.0;
    9149             :     }
    9150             : 
    9151   249137524 :     return DayltgSkyLuminance;
    9152             : }
    9153             : 
    9154       28308 : void ProfileAngle(EnergyPlusData &state,
    9155             :                   int const SurfNum,                                      // Surface number
    9156             :                   Vector3<Real64> const &CosDirSun,                       // Solar direction cosines
    9157             :                   DataWindowEquivalentLayer::Orientation const HorOrVert, // If HORIZONTAL, calculates ProfileAngHor
    9158             :                   Real64 &ProfileAng                                      // Solar profile angle (radians).
    9159             : )
    9160             : {
    9161             : 
    9162             :     // SUBROUTINE INFORMATION:
    9163             :     //       AUTHOR         Fred Winkelmann
    9164             :     //       DATE WRITTEN   May 2001
    9165             :     //       MODIFIED       na
    9166             :     //       RE-ENGINEERED  na
    9167             : 
    9168             :     // PURPOSE OF THIS SUBROUTINE:
    9169             :     // Calculates profile angle for a surface.
    9170             : 
    9171             :     // Using/Aliasing
    9172             :     using namespace DataSurfaces;
    9173             : 
    9174             :     // Locals
    9175             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    9176             :     // For HorOrVert = HORIZONTAL,
    9177             :     //  this is the incidence angle in a plane that is normal to the window
    9178             :     //  and parallel to the Y-axis of the window (the axis along
    9179             :     //  which the height of the window is measured).
    9180             :     //  For HorOrVert = VERTICAL,
    9181             :     //  this is the incidence angle in a plane that is normal to the window
    9182             :     //  and parallel to the X-axis of the window (the axis along
    9183             :     //  which the width of the window is measured).
    9184             :     // If VERTICAL, calculates ProfileAngVert
    9185             : 
    9186             :     // SUBROUTINE PARAMETER DEFINITIONS: na
    9187             :     // INTERFACE BLOCK SPECIFICATIONS: na
    9188             :     // DERIVED TYPE DEFINITIONS: na
    9189             : 
    9190             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9191             :     Real64 ElevSun;                                          // Sun elevation; angle between sun and horizontal (radians)
    9192             :     Real64 ElevWin;                                          // Window elevation: angle between window outward normal and horizontal (radians)
    9193             :     Real64 AzimWin;                                          // Window azimuth (radians)
    9194             :     Real64 AzimSun;                                          // Sun azimuth (radians)
    9195             :     Real64 ThWin;                                            // Azimuth angle of WinNorm
    9196       28308 :     auto &WinNorm = state.dataDaylightingManager->WinNorm;   // Window outward normal unit vector
    9197       28308 :     auto &SunPrime = state.dataDaylightingManager->SunPrime; // Projection of sun vector onto plane (perpendicular to window plane) determined by
    9198             :                                                              // WinNorm and vector along baseline of window
    9199       28308 :     auto &WinNormCrossBase = state.dataDaylightingManager->WinNormCrossBase; // Cross product of WinNorm and vector along window baseline
    9200             : 
    9201       28308 :     if (HorOrVert == DataWindowEquivalentLayer::Orientation::Horizontal) { // Profile angle for horizontal structures
    9202       28308 :         ElevWin = DataGlobalConstants::PiOvr2 - state.dataSurface->Surface(SurfNum).Tilt * DataGlobalConstants::DegToRadians;
    9203       28308 :         AzimWin = (90.0 - state.dataSurface->Surface(SurfNum).Azimuth) * DataGlobalConstants::DegToRadians;
    9204       28308 :         ElevSun = std::asin(CosDirSun(3));
    9205       28308 :         AzimSun = std::atan2(CosDirSun(2), CosDirSun(1));
    9206       28308 :         ProfileAng = std::atan(std::sin(ElevSun) / std::abs(std::cos(ElevSun) * std::cos(AzimWin - AzimSun))) - ElevWin;
    9207             :     } else { // Profile angle for vertical structures
    9208           0 :         ElevWin = DataGlobalConstants::PiOvr2 - state.dataSurface->Surface(SurfNum).Tilt * DataGlobalConstants::DegToRadians;
    9209           0 :         AzimWin = state.dataSurface->Surface(SurfNum).Azimuth * DataGlobalConstants::DegToRadians; // 7952
    9210           0 :         AzimSun = std::atan2(CosDirSun(1), CosDirSun(2));                                          // 7952
    9211           0 :         if (std::abs(ElevWin) < 0.1) {                                                             // Near-vertical window
    9212           0 :             ProfileAng = AzimWin - AzimSun;                                                        // CR7952 allow sign changes.
    9213             :         } else {
    9214           0 :             WinNorm = state.dataSurface->Surface(SurfNum).OutNormVec;
    9215           0 :             ThWin = AzimWin - DataGlobalConstants::PiOvr2;
    9216           0 :             Real64 const sin_ElevWin(std::sin(ElevWin));
    9217           0 :             WinNormCrossBase(1) = -sin_ElevWin * std::cos(ThWin);
    9218           0 :             WinNormCrossBase(2) = sin_ElevWin * std::sin(ThWin);
    9219           0 :             WinNormCrossBase(3) = std::cos(ElevWin);
    9220           0 :             SunPrime = CosDirSun - WinNormCrossBase * dot(CosDirSun, WinNormCrossBase);
    9221           0 :             ProfileAng = std::abs(std::acos(dot(WinNorm, SunPrime) / SunPrime.magnitude()));
    9222             :             // CR7952 correct sign of result for vertical slats
    9223           0 :             if ((AzimWin - AzimSun) < 0.0) ProfileAng = -1.0 * ProfileAng;
    9224             :         }
    9225             :         // Constrain to 0 to pi
    9226           0 :         if (ProfileAng > DataGlobalConstants::Pi) ProfileAng = 2.0 * DataGlobalConstants::Pi - ProfileAng;
    9227             :     }
    9228       28308 : }
    9229             : 
    9230        3840 : void DayltgClosestObstruction(EnergyPlusData &state,
    9231             :                               Vector3<Real64> const &RecPt,  // Point on window from which ray emanates (m)
    9232             :                               Vector3<Real64> const &RayVec, // Unit vector along ray pointing away from window (m)
    9233             :                               int &NearestHitSurfNum,        // Surface number of nearest obstruction that is hit by ray;
    9234             :                               Vector3<Real64> &NearestHitPt  // Ray's hit point on nearest obstruction (m)
    9235             : )
    9236             : {
    9237             : 
    9238             :     // SUBROUTINE INFORMATION:
    9239             :     //       AUTHOR         Fred Winkelmann
    9240             :     //       DATE WRITTEN   November 2003
    9241             :     //       MODIFIED       na
    9242             :     //       RE-ENGINEERED  na
    9243             : 
    9244             :     // PURPOSE OF THIS SUBROUTINE:
    9245             :     // Determines surface number and hit point of closest exterior obstruction hit
    9246             :     // by a ray from a window. If no obstruction is hit, NearestHitSurfNum = 0.
    9247             : 
    9248             :     // Locals
    9249             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    9250             :     //  = 0 if no obstruction is hit.
    9251             : 
    9252             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9253        3840 :     auto &HitPt = state.dataDaylightingManager->HitPt; // Hit point on an obstruction (m)
    9254             :     bool hit;                                          // True iff obstruction is hit
    9255             : 
    9256        3840 :     NearestHitSurfNum = 0;
    9257        3840 :     Real64 NearestHitDistance_sq(std::numeric_limits<Real64>::max()); // Distance squared from receiving point to nearest hit point for a ray (m^2)
    9258        3840 :     NearestHitPt = 0.0;
    9259        3840 :     if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
    9260             : 
    9261       19200 :         for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    9262             :             // Determine if this ray hits the surface and, if so, get the distance from the receiving point to the hit
    9263             :             PierceSurface(state, ObsSurfNum, RecPt, RayVec, HitPt, hit);
    9264       15360 :             if (hit) { // Ray pierces surface
    9265             :                 // If obstruction is a window and its base surface is the nearest obstruction hit so far set nearestHitSurface to this window
    9266             :                 // Note that in this case NearestHitDistance_sq has already been calculated, so does not have to be recalculated
    9267        3840 :                 if ((state.dataSurface->Surface(ObsSurfNum).Class == SurfaceClass::Window) &&
    9268           0 :                     (state.dataSurface->Surface(ObsSurfNum).BaseSurf == NearestHitSurfNum)) {
    9269           0 :                     NearestHitSurfNum = ObsSurfNum;
    9270             :                 } else {
    9271             :                     // Distance squared from receiving point to hit point
    9272        3840 :                     Real64 const HitDistance_sq(distance_squared(HitPt, RecPt));
    9273             :                     // Reset NearestHitSurfNum and NearestHitDistance_sq if this hit point is closer than previous closest
    9274        3840 :                     if (HitDistance_sq < NearestHitDistance_sq) {
    9275        3840 :                         NearestHitDistance_sq = HitDistance_sq;
    9276        3840 :                         NearestHitSurfNum = ObsSurfNum;
    9277        3840 :                         NearestHitPt = HitPt;
    9278             :                     }
    9279             :                 }
    9280             :             } // End of check if obstruction was hit
    9281             :         }     // End of loop over possible obstructions for this ray
    9282             : 
    9283             :     } else { // Surface octree search
    9284             : 
    9285           0 :         SurfaceData const *nearestHitSurface(nullptr);
    9286             : 
    9287             :         // Lambda function for the octree to test for surface hit
    9288           0 :         auto surfaceHit = [=, &state, &RecPt, &RayVec, &hit, &NearestHitDistance_sq, &nearestHitSurface, &NearestHitPt](SurfaceData const &surface) {
    9289           0 :             if (surface.IsShadowPossibleObstruction) {
    9290             :                 // Determine if this ray hits the surface and, if so, get the distance from the receiving point to the hit
    9291           0 :                 PierceSurface(surface, RecPt, RayVec, state.dataDaylightingManager->HitPt, hit); // Check if ray pierces surface
    9292           0 :                 if (hit) {                                                                       // Ray pierces surface
    9293             :                     // If obstruction is a window and its base surface is the nearest obstruction hit so far set nearestHitSurface to this window
    9294             :                     // Note that in this case NearestHitDistance_sq has already been calculated, so does not have to be recalculated
    9295           0 :                     if ((surface.Class == SurfaceClass::Window) && (surface.BaseSurf > 0) &&
    9296           0 :                         (&state.dataSurface->Surface(surface.BaseSurf) == nearestHitSurface)) {
    9297           0 :                         nearestHitSurface = &surface;
    9298             :                     } else {
    9299             :                         // Distance squared from receiving point to hit point
    9300           0 :                         Real64 const HitDistance_sq(distance_squared(HitPt, RecPt));
    9301             :                         // Reset nearestHitSurface and NearestHitDistance_sq if this hit point is closer than previous closest
    9302           0 :                         if (HitDistance_sq < NearestHitDistance_sq) {
    9303           0 :                             NearestHitDistance_sq = HitDistance_sq;
    9304           0 :                             nearestHitSurface = &surface;
    9305           0 :                             NearestHitPt = HitPt;
    9306             :                         }
    9307             :                     }
    9308             :                 } // End of check if obstruction was hit
    9309             :             }
    9310           0 :         };
    9311             : 
    9312             :         // Process octree surface candidates
    9313           0 :         Vector3<Real64> const RayVec_inv(SurfaceOctreeCube::safe_inverse(RayVec));
    9314           0 :         state.dataHeatBalMgr->surfaceOctree.processSurfaceRayIntersectsCube(RecPt, RayVec, RayVec_inv, surfaceHit);
    9315           0 :         if (nearestHitSurface != nullptr) { // Find surface number: This is inefficient: Improve when surfaces know their own number
    9316           0 :             for (int i = 1; i <= state.dataSurface->TotSurfaces; ++i) {
    9317           0 :                 if (&state.dataSurface->Surface(i) == nearestHitSurface) {
    9318           0 :                     NearestHitSurfNum = i;
    9319           0 :                     break;
    9320             :                 }
    9321             :             }
    9322           0 :             assert(NearestHitSurfNum != 0);
    9323             :         }
    9324             :     }
    9325        3840 : }
    9326             : 
    9327        3840 : void DayltgSurfaceLumFromSun(EnergyPlusData &state,
    9328             :                              int const IHR,                    // Hour number
    9329             :                              Vector3<Real64> const &Ray,       // Ray from window to reflecting surface (m)
    9330             :                              int const ReflSurfNum,            // Number of surface for which luminance is being calculated
    9331             :                              Vector3<Real64> const &ReflHitPt, // Point on ReflSurfNum for luminance calculation (m)
    9332             :                              Real64 &LumAtReflHitPtFrSun       // Luminance at ReflHitPt from beam solar reflection for unit
    9333             : )
    9334             : {
    9335             : 
    9336             :     // SUBROUTINE INFORMATION:
    9337             :     //       AUTHOR         Fred Winkelmann
    9338             :     //       DATE WRITTEN   November 2003
    9339             :     //       MODIFIED       na
    9340             :     //       RE-ENGINEERED  na
    9341             : 
    9342             :     // PURPOSE OF THIS SUBROUTINE:
    9343             :     // Calculates exterior surface luminance due to beam solar diffuse reflection.
    9344             : 
    9345             :     // Locals
    9346             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    9347             :     //  beam normal illuminance (cd/m2)
    9348             : 
    9349             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9350        3840 :     auto &DayltgSurfaceLumFromSunReflNorm = state.dataDaylightingManager->DayltgSurfaceLumFromSunReflNorm; // Unit normal to reflecting surface (m)
    9351        3840 :     auto &DayltgSurfaceLumFromSunObsHitPt = state.dataDaylightingManager->DayltgSurfaceLumFromSunObsHitPt; // Hit point on obstruction (m)
    9352             :     bool hitObs;                                                                                           // True iff obstruction is hit
    9353             :     Real64 CosIncAngAtHitPt; // Cosine of angle of incidence of sun at HitPt
    9354             :     Real64 DiffVisRefl;      // Diffuse visible reflectance of ReflSurfNum
    9355             : 
    9356        3840 :     LumAtReflHitPtFrSun = 0.0;
    9357             :     // Skip daylighting shelves since reflection from these is separately calculated
    9358        7680 :     if (state.dataSurface->SurfDaylightingShelfInd(ReflSurfNum) > 0) return;
    9359             :     // Normal to reflecting surface in hemisphere containing window element
    9360        3840 :     DayltgSurfaceLumFromSunReflNorm = state.dataSurface->Surface(ReflSurfNum).OutNormVec;
    9361        3840 :     if (state.dataSurface->Surface(ReflSurfNum).IsShadowing) {
    9362        3840 :         if (dot(DayltgSurfaceLumFromSunReflNorm, Ray) > 0.0) {
    9363        3840 :             DayltgSurfaceLumFromSunReflNorm *= -1.0;
    9364             :         }
    9365             :     }
    9366             :     // Cosine of angle of incidence of sun at HitPt if sun were to reach HitPt
    9367        3840 :     Vector3<Real64> const SUNCOS_IHR(state.dataSurface->SurfSunCosHourly(IHR));
    9368        3840 :     CosIncAngAtHitPt = dot(DayltgSurfaceLumFromSunReflNorm, SUNCOS_IHR);
    9369             :     // Require that the sun be in front of this surface relative to window element
    9370        3840 :     if (CosIncAngAtHitPt <= 0.0) return; // Sun is in back of reflecting surface
    9371             :     // Sun reaches ReflHitPt if vector from ReflHitPt to sun is unobstructed
    9372           0 :     hitObs = false;
    9373           0 :     for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    9374             :         // Exclude as a possible obstructor ReflSurfNum and its base surface (if it has one)
    9375           0 :         if (ObsSurfNum == ReflSurfNum || ObsSurfNum == state.dataSurface->Surface(ReflSurfNum).BaseSurf) continue;
    9376             :         PierceSurface(state, ObsSurfNum, ReflHitPt, SUNCOS_IHR, DayltgSurfaceLumFromSunObsHitPt, hitObs);
    9377           0 :         if (hitObs) break;
    9378             :     }
    9379           0 :     if (hitObs) return; // Obstruction was hit, blocking s auto surfaceHit = [&state, &GroundHitPtun
    9380             :     // Obstruction was not hit; sun reaches ReflHitPt.
    9381             :     // Calculate luminance at ReflHitPt due to beam solar reflection (for unit beam normal illuminance)
    9382           0 :     if (state.dataSurface->Surface(ReflSurfNum).IsShadowing) {
    9383           0 :         DiffVisRefl = state.dataSurface->SurfShadowDiffuseVisRefl(ReflSurfNum);
    9384             :         // Note that if the shadowing surface has a non-zero glazing fraction (e.g., neighboring bldg) that the above is
    9385             :         // (1 - glazing fraction) * (vis refl of opaque part of shadowing surface); specular reflection is
    9386             :         // excluded in this value of DiffVisRefl.
    9387             :     } else { // Exterior building surface
    9388           0 :         if (!state.dataConstruction->Construct(state.dataSurface->Surface(ReflSurfNum).Construction).TypeIsWindow) {
    9389           0 :             DiffVisRefl = 1.0 - state.dataConstruction->Construct(state.dataSurface->Surface(ReflSurfNum).Construction).OutsideAbsorpSolar;
    9390             :         } else {
    9391             :             // Window; assume bare so no beam-to-diffuse reflection
    9392           0 :             DiffVisRefl = 0.0;
    9393             :         }
    9394             :     }
    9395           0 :     LumAtReflHitPtFrSun = CosIncAngAtHitPt * DiffVisRefl / DataGlobalConstants::Pi;
    9396             : }
    9397             : 
    9398      894397 : void DayltgInteriorMapIllum(EnergyPlusData &state)
    9399             : {
    9400             : 
    9401             :     // *****super modified version of DayltgInteriorIllum by Peter Graham Ellis
    9402             :     // *****removes all control code, just calculates illum with previously determined control settings
    9403             :     // *****this should be packaged into a subroutine called from 2 places
    9404             : 
    9405             :     // SUBROUTINE INFORMATION:
    9406             :     //       AUTHOR         Fred Winkelmann
    9407             :     //       DATE WRITTEN   July 1997
    9408             :     //       MODIFIED       March 2000, FW: interpolate clear-sky daylight factors using
    9409             :     //                      HourOfDay/WeightNow and NextHour/WeightNextHour. Previously
    9410             :     //                      only HourOfDay was used
    9411             :     //                      Jan 2001, FW: interpolate in slat angle for windows with blinds
    9412             :     //                      that have movable slats
    9413             :     //                      Dec 2003, FW: fix bug--even though between-glass shade/blind is on
    9414             :     //                        daylight illum at ref pt was calculated as though it was off
    9415             :     //                      June 2009, TH: modified for thermochromic windows
    9416             :     //                      March 2010, TH: fix bug (CR 8057) for electrochromic windows
    9417             :     //       RE-ENGINEERED  na
    9418             : 
    9419             :     // PURPOSE OF THIS SUBROUTINE:
    9420             :     // Using daylighting factors and exterior illuminance, determine
    9421             :     // the current-hour interior daylight illuminance and glare index
    9422             :     // at each reference point in a space.
    9423             : 
    9424             :     // Called by InitSurfaceHeatBalance.
    9425             : 
    9426             :     // REFERENCES:
    9427             :     // Based on DOE-2.1E subroutine DINTIL.
    9428             : 
    9429             :     // Using/Aliasing
    9430             :     using General::POLYF;
    9431             : 
    9432             :     // Locals
    9433      894397 :     auto &daylight_illum = state.dataDaylightingManager->daylight_illum;
    9434             : 
    9435             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9436             :     int NREFPT; // Number of daylighting map reference points
    9437             :     // INTEGER   :: REFPT1                ! 1st reference point
    9438             :     int ISky;  // Sky type index
    9439             :     int ISky1; // Sky type index values for averaging two sky types
    9440             :     int ISky2;
    9441      894397 :     auto &DFSUHR = state.dataDaylightingManager->DFSUHR; // Sun daylight factor for bare/shaded window
    9442      894397 :     auto &IConstShaded = state.dataDaylightingManager->IConstShaded;
    9443      894397 :     auto &VTDark = state.dataDaylightingManager->VTDark;
    9444      894397 :     auto &VTMULT = state.dataDaylightingManager->VTMULT;
    9445      894397 :     auto &DayltgInteriorMapIllumDFSUHR = state.dataDaylightingManager->DayltgInteriorMapIllumDFSUHR;
    9446      894397 :     auto &DayltgInteriorMapIllumHorIllSky = state.dataDaylightingManager->DayltgInteriorMapIllumHorIllSky;
    9447      894397 :     auto &DFSKHR = state.dataDaylightingManager->DayltgInteriorMapIllumDFSKHR;
    9448             :     int IL;              // Reference point index
    9449             :     int IWin;            // Window index
    9450             :     int IS;              // IS=1 for unshaded window, =2 for shaded window
    9451             :     int ICtrl;           // Window shading control pointer
    9452             :     Real64 SkyWeight;    // Weighting factor used to average two different sky types
    9453             :     Real64 HorIllSkyFac; // Ratio between horizontal illuminance from sky horizontal irradiance and
    9454             :     //   luminous efficacy and horizontal illuminance from averaged sky
    9455             :     int loop; // Window loop index
    9456             :     int ILB;
    9457             :     int IConst;
    9458             :     Real64 VTRatio;
    9459             :     Real64 VTNow;
    9460             :     Real64 VTMaster;
    9461             : 
    9462      894397 :     if (state.dataDaylightingManager->DayltgInteriorMapIllum_FirstTimeFlag) {
    9463         769 :         daylight_illum.allocate(DataDaylighting::MaxMapRefPoints);
    9464         769 :         state.dataDaylightingManager->DayltgInteriorMapIllum_FirstTimeFlag = false;
    9465             :     }
    9466             : 
    9467      894397 :     if (state.dataGlobal->WarmupFlag) return;
    9468             : 
    9469             :     //              Initialize reference point illuminance and window background luminance
    9470             : 
    9471      152428 :     for (int mapNum = 1; mapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapNum) {
    9472        1737 :         auto &thisMap = state.dataDaylightingData->IllumMapCalc(mapNum);
    9473        1737 :         int enclNum = thisMap.enclIndex;
    9474        1737 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
    9475             : 
    9476        1737 :         NREFPT = thisMap.TotalMapRefPoints;
    9477             : 
    9478        1737 :         daylight_illum = 0.0;
    9479             : 
    9480        1737 :         if (state.dataEnvrn->SkyClearness > 3.0) { // Sky is average of clear and clear turbid
    9481        1321 :             SkyWeight = min(1.0, (state.dataEnvrn->SkyClearness - 3.0) / 3.0);
    9482        1321 :             ISky1 = 1;
    9483        1321 :             ISky2 = 2;
    9484         416 :         } else if (state.dataEnvrn->SkyClearness > 1.2) { // Sky is average of clear turbid and intermediate
    9485         180 :             SkyWeight = (state.dataEnvrn->SkyClearness - 1.2) / 1.8;
    9486         180 :             ISky1 = 2;
    9487         180 :             ISky2 = 3;
    9488             :         } else { // Sky is average of intermediate and overcast
    9489         236 :             SkyWeight = min(1.0, max(0.0, (state.dataEnvrn->SkyClearness - 1.0) / 0.2, (state.dataEnvrn->SkyBrightness - 0.05) / 0.4));
    9490         236 :             ISky1 = 3;
    9491         236 :             ISky2 = 4;
    9492             :         }
    9493             : 
    9494             :         //              First loop over windows in this space.
    9495             :         //              Find contribution of each window to the daylight illum
    9496             :         //              and to the glare numerator at each reference point.
    9497             :         //              Use shading flags set in WindowShadingManager.
    9498             : 
    9499       11857 :         for (loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
    9500       10120 :             IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
    9501             : 
    9502             :             // Added TH 6/29/2009 for thermochromic windows
    9503       10120 :             VTRatio = 1.0;
    9504       10120 :             if (NREFPT > 0) {
    9505       10120 :                 IConst = state.dataSurface->Surface(IWin).Construction;
    9506       10120 :                 if (state.dataConstruction->Construct(IConst).TCFlag == 1) {
    9507             :                     // For thermochromic windows, daylight and glare factors are always calculated
    9508             :                     //  based on the master construction. They need to be adjusted by the VTRatio, including:
    9509             :                     //  ZoneDaylight()%DaylIllFacSky, DaylIllFacSun, DaylIllFacSunDisk; DaylBackFacSky,
    9510             :                     //  DaylBackFacSun, DaylBackFacSunDisk, DaylSourceFacSky, DaylSourceFacSun, DaylSourceFacSunDisk
    9511           0 :                     VTNow = POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef);
    9512           0 :                     VTMaster =
    9513           0 :                         POLYF(1.0, state.dataConstruction->Construct(state.dataConstruction->Construct(IConst).TCMasterConst).TransVisBeamCoef);
    9514           0 :                     VTRatio = VTNow / VTMaster;
    9515             :                 }
    9516             :             }
    9517             : 
    9518             :             //              Loop over reference points
    9519      978620 :             for (ILB = 1; ILB <= NREFPT; ++ILB) {
    9520             : 
    9521             :                 //          Daylight factors for current sun position
    9522     4842500 :                 for (ISky = 1; ISky <= 4; ++ISky) {
    9523             :                     //                                ===Bare window===
    9524     3874000 :                     DFSKHR(1, ISky) =
    9525     7748000 :                         VTRatio * (state.dataGlobal->WeightNow * thisMap.DaylIllFacSky(state.dataGlobal->HourOfDay, 1, ISky, ILB, loop) +
    9526     3874000 :                                    state.dataGlobal->WeightPreviousHour * thisMap.DaylIllFacSky(state.dataGlobal->PreviousHour, 1, ISky, ILB, loop));
    9527             : 
    9528     3874000 :                     if (ISky == 1) {
    9529      968500 :                         DayltgInteriorMapIllumDFSUHR(1) =
    9530      968500 :                             VTRatio *
    9531     1937000 :                             (state.dataGlobal->WeightNow * (thisMap.DaylIllFacSun(state.dataGlobal->HourOfDay, 1, ILB, loop) +
    9532     1937000 :                                                             thisMap.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 1, ILB, loop)) +
    9533     1937000 :                              state.dataGlobal->WeightPreviousHour * (thisMap.DaylIllFacSun(state.dataGlobal->PreviousHour, 1, ILB, loop) +
    9534      968500 :                                                                      thisMap.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 1, ILB, loop)));
    9535             :                     }
    9536             : 
    9537    11018400 :                     if ((state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) &&
    9538     4477600 :                         (IS_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || state.dataSurface->SurfWinSolarDiffusing(IWin))) {
    9539             : 
    9540             :                         //                                 ===Shaded window===
    9541     3270400 :                         if (!state.dataSurface->SurfWinMovableSlats(IWin)) {
    9542             :                             // Shade, screen, blind with fixed slats, or diffusing glass
    9543     3270400 :                             DFSKHR(2, ISky) =
    9544     3270400 :                                 VTRatio *
    9545     6540800 :                                 (state.dataGlobal->WeightNow * thisMap.DaylIllFacSky(state.dataGlobal->HourOfDay, 2, ISky, ILB, loop) +
    9546     3270400 :                                  state.dataGlobal->WeightPreviousHour * thisMap.DaylIllFacSky(state.dataGlobal->PreviousHour, 2, ISky, ILB, loop));
    9547             : 
    9548     3270400 :                             if (ISky == 1) {
    9549      817600 :                                 DayltgInteriorMapIllumDFSUHR(2) =
    9550      817600 :                                     VTRatio *
    9551     1635200 :                                     (state.dataGlobal->WeightNow * thisMap.DaylIllFacSun(state.dataGlobal->HourOfDay, 2, ILB, loop) +
    9552      817600 :                                      state.dataGlobal->WeightPreviousHour * thisMap.DaylIllFacSun(state.dataGlobal->PreviousHour, 2, ILB, loop));
    9553             : 
    9554      817600 :                                 if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin)) {
    9555      817600 :                                     DayltgInteriorMapIllumDFSUHR(2) +=
    9556      817600 :                                         VTRatio *
    9557     1635200 :                                         (state.dataGlobal->WeightNow * thisMap.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 2, ILB, loop) +
    9558     1635200 :                                          state.dataGlobal->WeightPreviousHour *
    9559      817600 :                                              thisMap.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 2, ILB, loop));
    9560             :                                 }
    9561             :                             }
    9562             :                         } else { // Blind with movable slats
    9563           0 :                             int SurfWinSlatsAngIndex = state.dataSurface->SurfWinSlatsAngIndex(IWin);
    9564           0 :                             Real64 SurfWinSlatsAngInterpFac = state.dataSurface->SurfWinSlatsAngInterpFac(IWin);
    9565           0 :                             Real64 DaylIllFacSkyNow = General::InterpGeneral(
    9566           0 :                                 thisMap.DaylIllFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, ILB, loop),
    9567             :                                 thisMap.DaylIllFacSky(
    9568           0 :                                     state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, ILB, loop),
    9569           0 :                                 SurfWinSlatsAngInterpFac);
    9570           0 :                             Real64 DaylIllFacSkyPrev = General::InterpGeneral(
    9571           0 :                                 thisMap.DaylIllFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, ILB, loop),
    9572             :                                 thisMap.DaylIllFacSky(
    9573           0 :                                     state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, ILB, loop),
    9574           0 :                                 SurfWinSlatsAngInterpFac);
    9575             : 
    9576           0 :                             DFSKHR(2, ISky) =
    9577           0 :                                 VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSkyNow + state.dataGlobal->WeightPreviousHour * DaylIllFacSkyPrev);
    9578             : 
    9579           0 :                             if (ISky == 1) {
    9580           0 :                                 Real64 DaylIllFacSunNow = General::InterpGeneral(
    9581           0 :                                     thisMap.DaylIllFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ILB, loop),
    9582             :                                     thisMap.DaylIllFacSun(
    9583           0 :                                         state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
    9584           0 :                                     SurfWinSlatsAngInterpFac);
    9585           0 :                                 Real64 DaylIllFacSunPrev = General::InterpGeneral(
    9586           0 :                                     thisMap.DaylIllFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ILB, loop),
    9587             :                                     thisMap.DaylIllFacSun(
    9588           0 :                                         state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
    9589           0 :                                     SurfWinSlatsAngInterpFac);
    9590           0 :                                 DFSUHR(2) = VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunNow +
    9591           0 :                                                        state.dataGlobal->WeightPreviousHour * DaylIllFacSunPrev);
    9592             : 
    9593             :                                 // We add the contribution from the solar disk if slats do not block beam solar
    9594             :                                 // TH CR 8010, DaylIllFacSunDisk needs to be interpolated
    9595           0 :                                 if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin)) {
    9596           0 :                                     Real64 DaylIllFacSunDiskNow = General::InterpGeneral(
    9597           0 :                                         thisMap.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ILB, loop),
    9598             :                                         thisMap.DaylIllFacSunDisk(
    9599           0 :                                             state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
    9600           0 :                                         SurfWinSlatsAngInterpFac);
    9601           0 :                                     Real64 DaylIllFacSunDiskPrev = General::InterpGeneral(
    9602           0 :                                         thisMap.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ILB, loop),
    9603             :                                         thisMap.DaylIllFacSunDisk(
    9604           0 :                                             state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
    9605           0 :                                         SurfWinSlatsAngInterpFac);
    9606           0 :                                     DFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunDiskNow +
    9607           0 :                                                             state.dataGlobal->WeightPreviousHour * DaylIllFacSunDiskPrev);
    9608             :                                 }
    9609             :                             }
    9610             : 
    9611             :                         } // End of check if window has blind with movable slats
    9612             : 
    9613             :                     } // End of check if window is shaded or has diffusing glass
    9614             :                 }
    9615             : 
    9616             :                 //              Get illuminance at ref point from bare and shaded window by
    9617             :                 //              multiplying daylight factors by exterior horizontal illuminance
    9618             : 
    9619             :                 // Adding 0.001 in the following prevents zero DayltgInteriorMapIllumHorIllSky in early morning or late evening when sun
    9620             :                 // is up in the present time step but GILSK(ISky,HourOfDay) and GILSK(ISky,NextHour) are both zero.
    9621     4842500 :                 for (ISky = 1; ISky <= 4; ++ISky) {
    9622     3874000 :                     DayltgInteriorMapIllumHorIllSky(ISky) =
    9623     7748000 :                         state.dataGlobal->WeightNow * state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, ISky) +
    9624     7748000 :                         state.dataGlobal->WeightPreviousHour * state.dataDaylightingManager->GILSK(state.dataGlobal->PreviousHour, ISky) + 0.001;
    9625             :                 }
    9626             : 
    9627             :                 // HISKF is current time step horizontal illuminance from sky, calculated in DayltgLuminousEfficacy,
    9628             :                 // which is called in WeatherManager. HISUNF is current time step horizontal illuminance from sun,
    9629             :                 // also calculated in DayltgLuminousEfficacy.
    9630     1937000 :                 HorIllSkyFac = state.dataEnvrn->HISKF /
    9631      968500 :                                ((1.0 - SkyWeight) * DayltgInteriorMapIllumHorIllSky(ISky2) + SkyWeight * DayltgInteriorMapIllumHorIllSky(ISky1));
    9632             : 
    9633     2754600 :                 for (IS = 1; IS <= 2; ++IS) {
    9634     1937000 :                     if (IS == 2 && state.dataSurface->SurfWinWindowModelType(IWin) == WindowModel::BSDF) break;
    9635     1937000 :                     if (IS == 2 && NOT_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) && !state.dataSurface->SurfWinSolarDiffusing(IWin)) break;
    9636             : 
    9637     1786100 :                     thisMap.IllumFromWinAtMapPt(loop, IS, ILB) =
    9638     3572200 :                         DayltgInteriorMapIllumDFSUHR(IS) * state.dataEnvrn->HISUNF +
    9639     3572200 :                         HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * DayltgInteriorMapIllumHorIllSky(ISky1) +
    9640     1786100 :                                         DFSKHR(IS, ISky2) * (1.0 - SkyWeight) * DayltgInteriorMapIllumHorIllSky(ISky2));
    9641             :                 }
    9642             : 
    9643             :             } // End of reference point loop
    9644             :         }     // End of first loop over windows
    9645             : 
    9646             :         //              Second loop over windows. Find total daylight illuminance
    9647             :         //              and background luminance for each ref pt from all windows in
    9648             :         //              the space.  Use shading flags.
    9649             : 
    9650       11857 :         for (loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
    9651       10120 :             IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
    9652             : 
    9653       10120 :             IS = findWinShadingStatus(state, IWin);
    9654             : 
    9655             :             // CR 8057. 3/17/2010.
    9656             :             // Switchable windows may be in partially switched state rather than fully dark state
    9657       10120 :             VTMULT = 1.0;
    9658             : 
    9659       10120 :             ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
    9660       10120 :             if (state.dataSurface->Surface(IWin).HasShadeControl) {
    9661        8815 :                 if (state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
    9662           0 :                     state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
    9663             :                     // switchable windows in partial or fully switched state,
    9664             :                     //  get its intermediate VT calculated in DayltgInteriorIllum
    9665           0 :                     IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
    9666           0 :                     if (IConstShaded > 0)
    9667           0 :                         VTDark =
    9668           0 :                             POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin);
    9669           0 :                     if (VTDark > 0) VTMULT = state.dataSurface->SurfWinVisTransSelected(IWin) / VTDark;
    9670             :                 }
    9671             :             }
    9672             : 
    9673      978620 :             for (IL = 1; IL <= NREFPT; ++IL) {
    9674             :                 //              Determine if illuminance contribution is from bare or shaded window
    9675      968500 :                 daylight_illum(IL) += VTMULT * thisMap.IllumFromWinAtMapPt(loop, IS, IL);
    9676             :             }
    9677             :         } // End of second window loop
    9678             : 
    9679             :         //              Variables for reporting
    9680      153687 :         for (IL = 1; IL <= NREFPT; ++IL) {
    9681      151950 :             thisMap.DaylIllumAtMapPt(IL) = max(daylight_illum(IL), 0.0);
    9682             :         }
    9683             :     } // End loop over maps
    9684             : }
    9685             : 
    9686        1529 : void ReportIllumMap(EnergyPlusData &state, int const MapNum)
    9687             : {
    9688             : 
    9689             :     // SUBROUTINE INFORMATION:
    9690             :     //       AUTHOR         Peter Ellis
    9691             :     //       DATE WRITTEN   May 2003
    9692             :     //       MODIFIED       na
    9693             :     //       RE-ENGINEERED  na
    9694             : 
    9695             :     // PURPOSE OF THIS SUBROUTINE:
    9696             :     // This subroutine produces the Daylighting Illuminance Map output.  Each separate map (by zone)
    9697             :     // is placed on a temporary file and later (see CloseReportIllumMaps) coallesced into a single
    9698             :     // output file.
    9699             : 
    9700             :     // Using/Aliasing
    9701             :     using DataStringGlobals::CharComma;
    9702             :     using DataStringGlobals::CharSpace;
    9703             :     using DataStringGlobals::CharTab;
    9704             : 
    9705             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9706        3058 :     std::string String;
    9707             :     int RefPt;
    9708             :     int X;
    9709             :     int Y;
    9710             :     int R;
    9711             :     int IllumOut;
    9712             : 
    9713        1529 :     auto &FirstTimeMaps = state.dataDaylightingManager->FirstTimeMaps;
    9714        1529 :     auto &EnvrnPrint = state.dataDaylightingManager->EnvrnPrint;
    9715        1529 :     auto &SavedMnDy = state.dataDaylightingManager->SavedMnDy;
    9716        1529 :     auto &XValue = state.dataDaylightingManager->XValue;
    9717        1529 :     auto &YValue = state.dataDaylightingManager->YValue;
    9718        1529 :     auto &IllumValue = state.dataDaylightingManager->IllumValue;
    9719        3058 :     std::string MapNoString;
    9720             :     int linelen;
    9721             :     // BSLLC Start
    9722             :     int SQYear;
    9723             :     int SQMonth;
    9724             :     int SQDayOfMonth;
    9725             :     int IllumIndex;
    9726             :     //        static bool CommaDelimited( true ); //Unused Set but never used
    9727             :     // BSLLC Finish
    9728             : 
    9729        1529 :     if (state.dataDaylightingManager->ReportIllumMap_firstTime) {
    9730           5 :         state.dataDaylightingManager->ReportIllumMap_firstTime = false;
    9731           5 :         FirstTimeMaps.dimension((int)state.dataDaylightingData->IllumMap.size(), true);
    9732           5 :         EnvrnPrint.dimension((int)state.dataDaylightingData->IllumMap.size(), true);
    9733           5 :         SavedMnDy.allocate((int)state.dataDaylightingData->IllumMap.size());
    9734             :     }
    9735             : 
    9736        1529 :     if (FirstTimeMaps(MapNum)) {
    9737             : 
    9738           7 :         FirstTimeMaps(MapNum) = false;
    9739             : 
    9740           7 :         auto openMapFile = [&](const fs::path &filePath) -> InputOutputFile & {
    9741          14 :             auto &outputFile = *state.dataDaylightingData->IllumMap(MapNum).mapFile;
    9742           7 :             outputFile.filePath = fs::path(filePath.string() + fmt::to_string(MapNum));
    9743          14 :             outputFile.ensure_open(state, "ReportIllumMap");
    9744           7 :             return outputFile;
    9745           7 :         };
    9746           7 :         if (state.dataDaylightingData->MapColSep == CharTab) {
    9747           0 :             if (!openMapFile(state.files.outputMapTabFilePath).good()) return;
    9748             :             //                CommaDelimited = false; //Unused Set but never used
    9749           7 :         } else if (state.dataDaylightingData->MapColSep == CharComma) {
    9750           7 :             if (!openMapFile(state.files.outputMapCsvFilePath).good()) return;
    9751             :             //                CommaDelimited = true; //Unused Set but never used
    9752             :         } else {
    9753           0 :             if (!openMapFile(state.files.outputMapTxtFilePath).good()) return;
    9754             :             //                CommaDelimited = false; //Unused Set but never used
    9755             :         }
    9756             : 
    9757           7 :         SavedMnDy(MapNum) = state.dataEnvrn->CurMnDyHr.substr(0, 5);
    9758             : 
    9759          14 :         state.dataDaylightingData->IllumMap(MapNum).Name =
    9760          21 :             format("{} at {:.2R}m", state.dataDaylightingData->IllumMap(MapNum).Name, state.dataDaylightingData->IllumMap(MapNum).Z);
    9761             :     }
    9762        1529 :     if (SavedMnDy(MapNum) != state.dataEnvrn->CurMnDyHr.substr(0, 5)) {
    9763          13 :         EnvrnPrint(MapNum) = true;
    9764          13 :         SavedMnDy(MapNum) = state.dataEnvrn->CurMnDyHr.substr(0, 5);
    9765             :     }
    9766             : 
    9767        1529 :     state.dataDaylightingData->IllumMap(MapNum).pointsHeader = "";
    9768        1529 :     int rCount = 0;
    9769        3325 :     for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
    9770        1796 :         if (state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex == state.dataDaylightingData->IllumMap(MapNum).zoneIndex) {
    9771        1529 :             auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
    9772             : 
    9773        3414 :             for (R = 1; R <= thisDaylightControl.TotalDaylRefPoints; ++R) {
    9774        1885 :                 ++rCount;
    9775        5655 :                 state.dataDaylightingData->IllumMap(MapNum).pointsHeader += format(" RefPt{}=({:.2R}:{:.2R}:{:.2R}),",
    9776             :                                                                                    rCount,
    9777             :                                                                                    thisDaylightControl.DaylRefPtAbsCoord(1, R),
    9778             :                                                                                    thisDaylightControl.DaylRefPtAbsCoord(2, R),
    9779        3770 :                                                                                    thisDaylightControl.DaylRefPtAbsCoord(3, R));
    9780             :             }
    9781             :         }
    9782             :     }
    9783             : 
    9784        1529 :     if (rCount > 0) {
    9785             :         // Remove trailing comma
    9786        1529 :         state.dataDaylightingData->IllumMap(MapNum).pointsHeader.pop_back();
    9787             :     }
    9788        1529 :     if (EnvrnPrint(MapNum)) {
    9789         120 :         WriteDaylightMapTitle(state,
    9790             :                               MapNum,
    9791          20 :                               *state.dataDaylightingData->IllumMap(MapNum).mapFile,
    9792          20 :                               state.dataDaylightingData->IllumMap(MapNum).Name,
    9793          20 :                               state.dataEnvrn->EnvironmentName,
    9794          20 :                               state.dataDaylightingData->IllumMap(MapNum).zoneIndex,
    9795          20 :                               state.dataDaylightingData->IllumMap(MapNum).pointsHeader,
    9796          20 :                               state.dataDaylightingData->IllumMap(MapNum).Z);
    9797          20 :         EnvrnPrint(MapNum) = false;
    9798             :     }
    9799             : 
    9800        1529 :     if (!state.dataGlobal->WarmupFlag) {
    9801        1529 :         if (state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) { // Report only hourly
    9802             : 
    9803             :             // Write X scale column header
    9804         544 :             auto mapLine = format(" {} {:02}:00", SavedMnDy(MapNum), state.dataGlobal->HourOfDay);
    9805         272 :             if (state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded) linelen = int(len(mapLine));
    9806         272 :             RefPt = 1;
    9807        2752 :             for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
    9808             :                 const auto AddXorYString = format("{}({:.2R};{:.2R})=",
    9809        2480 :                                                   state.dataDaylightingData->MapColSep,
    9810        2480 :                                                   state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt),
    9811        9920 :                                                   state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
    9812        2480 :                 if (state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded) linelen += int(len(AddXorYString));
    9813        2480 :                 mapLine += AddXorYString;
    9814        2480 :                 ++RefPt;
    9815             :             } // X
    9816             : 
    9817         272 :             if (state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded) {
    9818           7 :                 state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLength = linelen;
    9819           7 :                 if (static_cast<std::string::size_type>(state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLength) > len(mapLine)) {
    9820           0 :                     ShowWarningError(state,
    9821           0 :                                      format("ReportIllumMap: Map=\"{}\" -- the X Header overflows buffer -- will be truncated at {} characters.",
    9822           0 :                                             state.dataDaylightingData->IllumMap(MapNum).Name,
    9823           0 :                                             int(len(mapLine))));
    9824           0 :                     ShowContinueError(state,
    9825           0 :                                       format("...needed {} characters. Please contact EnergyPlus support.",
    9826           0 :                                              state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLength));
    9827             :                 }
    9828           7 :                 state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded = false;
    9829             :             }
    9830             : 
    9831         272 :             print(*state.dataDaylightingData->IllumMap(MapNum).mapFile, "{}\n", mapLine);
    9832             : 
    9833             :             // Write Y scale prefix and illuminance values
    9834         272 :             RefPt = 1;
    9835        2992 :             for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
    9836        8160 :                 mapLine = format("({:.2R};{:.2R})=",
    9837        2720 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt),
    9838        5440 :                                  state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
    9839       27520 :                 for (R = RefPt; R <= RefPt + state.dataDaylightingData->IllumMap(MapNum).Xnum - 1; ++R) {
    9840       24800 :                     IllumOut = nint(state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr(R));
    9841       24800 :                     if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(R)) {
    9842       24800 :                         String = fmt::to_string(IllumOut);
    9843             :                     } else {
    9844           0 :                         String = fmt::to_string(IllumOut);
    9845           0 :                         String = "*" + String;
    9846             :                     }
    9847       24800 :                     mapLine += state.dataDaylightingData->MapColSep + String;
    9848             :                 }
    9849             : 
    9850        2720 :                 print(*state.dataDaylightingData->IllumMap(MapNum).mapFile, "{}\n", mapLine);
    9851             : 
    9852        2720 :                 RefPt += state.dataDaylightingData->IllumMap(MapNum).Xnum;
    9853             :             } // X
    9854             : 
    9855         272 :             if (state.dataSQLiteProcedures->sqlite) {
    9856          16 :                 if (state.dataDaylightingManager->SQFirstTime) {
    9857           1 :                     int const nX(maxval(state.dataDaylightingData->IllumMap, &DataDaylighting::IllumMapData::Xnum));
    9858           1 :                     int const nY(maxval(state.dataDaylightingData->IllumMap, &DataDaylighting::IllumMapData::Ynum));
    9859           1 :                     XValue.allocate(nX);
    9860           1 :                     YValue.allocate(nY);
    9861           1 :                     IllumValue.allocate(nX, nY);
    9862           1 :                     state.dataDaylightingManager->SQFirstTime = false;
    9863             :                 }
    9864             : 
    9865             :                 // We need DataGlobals::CalendarYear, and not DataEnvironment::Year because
    9866             :                 // otherwise if you run a TMY file, you'll get for eg 1977, 1981, etc
    9867          16 :                 SQYear = state.dataGlobal->CalendarYear;
    9868          16 :                 SQMonth = state.dataEnvrn->Month;
    9869          16 :                 SQDayOfMonth = state.dataEnvrn->DayOfMonth;
    9870             : 
    9871         176 :                 for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
    9872         160 :                     YValue(Y) = state.dataDaylightingData->IllumMap(MapNum).Ymin + (Y - 1) * state.dataDaylightingData->IllumMap(MapNum).Yinc;
    9873        1760 :                     for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
    9874        1600 :                         XValue(X) = state.dataDaylightingData->IllumMap(MapNum).Xmin + (X - 1) * state.dataDaylightingData->IllumMap(MapNum).Xinc;
    9875        1600 :                         IllumIndex = X + (Y - 1) * state.dataDaylightingData->IllumMap(MapNum).Xnum;
    9876        1600 :                         IllumValue(X, Y) = nint(state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr(IllumIndex));
    9877        1600 :                         if (!state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(IllumIndex)) {
    9878           0 :                             IllumValue(X, Y) = -IllumValue(X, Y);
    9879             :                         }
    9880             :                     } // X Loop
    9881             :                 }     // Y Loop
    9882             : 
    9883          64 :                 state.dataSQLiteProcedures->sqlite->createSQLiteDaylightMap(MapNum,
    9884             :                                                                             SQYear,
    9885             :                                                                             SQMonth,
    9886             :                                                                             SQDayOfMonth,
    9887          16 :                                                                             state.dataGlobal->HourOfDay,
    9888          16 :                                                                             state.dataDaylightingData->IllumMap(MapNum).Xnum,
    9889             :                                                                             XValue,
    9890          16 :                                                                             state.dataDaylightingData->IllumMap(MapNum).Ynum,
    9891             :                                                                             YValue,
    9892             :                                                                             IllumValue);
    9893             : 
    9894             :             } // WriteOutputToSQLite
    9895             :         }     // end time step
    9896             :     }         // not Warmup
    9897             : }
    9898             : 
    9899         771 : void CloseReportIllumMaps(EnergyPlusData &state)
    9900             : {
    9901             : 
    9902             :     // SUBROUTINE INFORMATION:
    9903             :     //       AUTHOR         Linda K. Lawrie
    9904             :     //       DATE WRITTEN   June 2003
    9905             :     //       MODIFIED       na
    9906             :     //       RE-ENGINEERED  na
    9907             : 
    9908             :     // PURPOSE OF THIS SUBROUTINE:
    9909             :     // This subroutine "closes" out the created daylight illuminance maps by merging them
    9910             :     // into the "eplusout.map" file.
    9911             : 
    9912             :     // Using/Aliasing
    9913             :     using DataStringGlobals::CharComma;
    9914             :     using DataStringGlobals::CharSpace;
    9915             :     using DataStringGlobals::CharTab;
    9916             : 
    9917             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9918         771 :     if ((int)state.dataDaylightingData->IllumMap.size() > 0) {
    9919             :         // Write map header
    9920           5 :         if (state.dataDaylightingData->MapColSep == CharTab) {
    9921           0 :             state.files.map.filePath = state.files.outputMapTabFilePath;
    9922           5 :         } else if (state.dataDaylightingData->MapColSep == CharComma) {
    9923           5 :             state.files.map.filePath = state.files.outputMapCsvFilePath;
    9924             :         } else {
    9925           0 :             state.files.map.filePath = state.files.outputMapTxtFilePath;
    9926             :         }
    9927             : 
    9928           5 :         state.files.map.ensure_open(state, "CloseReportIllumMaps");
    9929             : 
    9930          12 :         for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
    9931           7 :             if (!state.dataDaylightingData->IllumMap(MapNum).mapFile->good()) continue; // fatal error processing
    9932             : 
    9933          14 :             const auto mapLines = state.dataDaylightingData->IllumMap(MapNum).mapFile->getLines();
    9934           7 :             if (mapLines.empty()) {
    9935           0 :                 ShowSevereError(state, "CloseReportIllumMaps: IllumMap=\"" + state.dataDaylightingData->IllumMap(MapNum).Name + "\" is empty.");
    9936           0 :                 break;
    9937             :             }
    9938        3019 :             for (const auto &mapLine : mapLines) {
    9939        3012 :                 print(state.files.map, "{}\n", mapLine);
    9940             :             }
    9941           7 :             state.dataDaylightingData->IllumMap(MapNum).mapFile->del();
    9942             :         }
    9943             : 
    9944           5 :         if (!state.dataDaylightingData->mapResultsReported && !state.dataErrTracking->AbortProcessing) {
    9945           0 :             const auto message = "CloseReportIllumMaps: Illuminance maps requested but no data ever reported. Likely cause is no solar.";
    9946           0 :             ShowSevereError(state, message);
    9947           0 :             print(state.files.map, "{}\n", message);
    9948             :         }
    9949             :     }
    9950         771 : }
    9951             : 
    9952         771 : void CloseDFSFile(EnergyPlusData &state)
    9953             : {
    9954             : 
    9955             :     // SUBROUTINE INFORMATION:
    9956             :     //       AUTHOR         Linda Lawrie
    9957             :     //       DATE WRITTEN   August 2010
    9958             :     //       MODIFIED       na
    9959             :     //       RE-ENGINEERED  na
    9960             : 
    9961             :     // PURPOSE OF THIS SUBROUTINE:
    9962             :     // Make sure DFSFile is closed at exit time.  Do not rely on operating system to
    9963             :     // take care of it.
    9964             : 
    9965         771 :     state.files.dfs.close();
    9966         771 : }
    9967             : 
    9968          62 : void DayltgSetupAdjZoneListsAndPointers(EnergyPlusData &state)
    9969             : {
    9970             : 
    9971             :     // SUBROUTINE INFORMATION:
    9972             :     //       AUTHOR         Fred Winkelmann
    9973             :     //       DATE WRITTEN   Feb. 2004
    9974             :     //       MODIFIED:      June 2010;LKL - Merged two routines.
    9975             : 
    9976             :     // PURPOSE OF THIS SUBROUTINE:
    9977             :     // For each Daylighting:Detailed enclosure, creates a list of adjacent enclosures,
    9978             :     // that have one or more exterior windows and that share one or more interior
    9979             :     // windows with Z. Used in calculation of daylighting through interior windows.
    9980             : 
    9981             :     // Sets the daylighting factor pointers for each Daylighting:Detailed control. The pointer
    9982             :     // may be associated with an exterior window in a daylit target zone's enclosure or an exterior window in
    9983             :     // an adjacent enclosure, daylit or not, that shares interior windows with the target zone's enclosure.
    9984             : 
    9985             :     // Count number of exterior Windows (use to allocate arrays)
    9986         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
    9987         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
    9988         708 :         thisEnclDaylight.TotalExtWindows = 0;
    9989             : 
    9990             :         // Count exterior windows in this solar enclosure
    9991        8030 :         for (int const surfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
    9992       15812 :             if ((state.dataSurface->Surface(surfNum).Class == SurfaceClass::Window &&
    9993       13478 :                  state.dataSurface->Surface(surfNum).ExtBoundCond == ExternalEnvironment) ||
    9994        6156 :                 state.dataSurface->SurfWinOriginalClass(surfNum) == SurfaceClass::TDD_Diffuser) {
    9995        1166 :                 ++thisEnclDaylight.TotalExtWindows;
    9996             :             }
    9997             :         }
    9998             :     } // End of primary enclosure loop
    9999             : 
   10000         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10001         708 :         int NumList = 0;
   10002         708 :         if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
   10003         286 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10004         286 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10005             :         // This is a Daylighting:Detailed enclosure
   10006             :         // Find adjacent zones/enclosures
   10007        7218 :         for (int adjEnclNum = 1; adjEnclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++adjEnclNum) {
   10008        6935 :             if (adjEnclNum == enclNum) continue;
   10009             :             // Require that adjEnclNum have a least one exterior window
   10010        6652 :             bool AdjEnclHasExtWins = false;
   10011       64609 :             for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10012       68090 :                 if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
   10013        5067 :                     (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
   10014        5066 :                     AdjEnclHasExtWins = true;
   10015        5066 :                     break;
   10016             :                 }
   10017             :             }
   10018        6652 :             if (!AdjEnclHasExtWins) continue;
   10019             :             // Loop again through surfaces in ZoneNumAdj and see if any are interior windows adjacent to ZoneNum
   10020       64869 :             for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10021       75871 :                 if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
   10022       16067 :                     (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond >= 1)) {
   10023             :                     // This is an interior window in ZoneNumAdj
   10024           1 :                     if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj).ExtBoundCond).SolarEnclIndex == enclNum) {
   10025             :                         // This interior window is adjacent to ZoneNum
   10026           1 :                         ++NumList;
   10027           1 :                         break;
   10028             :                     }
   10029             :                 }
   10030             :             }
   10031             :         }
   10032         283 :         thisEnclDaylight.AdjIntWinEnclNums.allocate(NumList);
   10033         283 :         thisEnclDaylight.AdjIntWinEnclNums = 0;
   10034             :     } // End of primary enclosure loop
   10035             : 
   10036         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10037         708 :         int NumList = 0;
   10038         708 :         if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
   10039         286 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10040         286 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10041             :         // This is a Daylighting:Detailed enclosure
   10042             :         // Find adjacent zones/enclosures
   10043        7218 :         for (int adjEnclNum = 1; adjEnclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++adjEnclNum) {
   10044        6935 :             if (adjEnclNum == enclNum) continue;
   10045             :             // Require that adjEnclNum have a least one exterior window
   10046        6652 :             bool AdjEnclHasExtWins = false;
   10047       64609 :             for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10048       68090 :                 if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
   10049        5067 :                     (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
   10050        5066 :                     AdjEnclHasExtWins = true;
   10051        5066 :                     break;
   10052             :                 }
   10053             :             }
   10054        6652 :             if (!AdjEnclHasExtWins) continue;
   10055             :             // Loop again through surfaces in ZoneNumAdj and see if any are interior windows adjacent to enclNum
   10056       64869 :             for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10057       75871 :                 if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
   10058       16067 :                     (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond >= 1)) {
   10059             :                     // This is an interior window in adjEnclNum
   10060           1 :                     if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj).ExtBoundCond).SolarEnclIndex == enclNum) {
   10061             :                         // This interior window is adjacent to ZoneNum
   10062           1 :                         ++NumList;
   10063           1 :                         int enclNumAdj = state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex;
   10064           1 :                         thisEnclDaylight.AdjIntWinEnclNums(NumList) = enclNumAdj;
   10065           1 :                         state.dataDaylightingData->enclDaylight(enclNumAdj).adjEnclHasDayltgCtrl = true;
   10066           1 :                         break;
   10067             :                     }
   10068             :                 }
   10069             :             }
   10070             :         }
   10071         283 :         thisEnclDaylight.NumOfIntWinAdjEncls = NumList;
   10072             :     } // End of primary enclosure loop
   10073             : 
   10074             :     // now fill out information on relationship between adjacent exterior windows and associated interior windows
   10075         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10076         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10077             :         // first find count of exterior windows
   10078        1415 :         if (thisEnclDaylight.NumOfIntWinAdjEncls <= 0) {
   10079         707 :             thisEnclDaylight.NumOfIntWinAdjEnclExtWins = 0;
   10080         707 :             continue;
   10081             :         }
   10082           2 :         for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
   10083           9 :             for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10084          10 :                 if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
   10085           2 :                     (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
   10086           1 :                     ++thisEnclDaylight.NumOfIntWinAdjEnclExtWins;
   10087             :                 }
   10088             :             }
   10089             :         }
   10090             :         // now allocate nested struct based on exterior window count
   10091           1 :         thisEnclDaylight.IntWinAdjEnclExtWin.allocate(thisEnclDaylight.NumOfIntWinAdjEnclExtWins);
   10092             : 
   10093             :         // now fill nested structure
   10094           1 :         int ExtWinIndex = 0;
   10095           2 :         for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
   10096           9 :             for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10097          10 :                 if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
   10098           2 :                     (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
   10099           1 :                     ++ExtWinIndex;
   10100           1 :                     thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).SurfNum = SurfNumAdj;
   10101             : 
   10102             :                     // now count interior windows shared by both zones
   10103           1 :                     int NumOfIntWindowsCount = 0;
   10104           9 :                     for (int SurfNumAdj2 : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10105          10 :                         if ((state.dataSurface->Surface(SurfNumAdj2).Class == SurfaceClass::Window) &&
   10106           2 :                             (state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond >= 1)) {
   10107             :                             // This is an interior window in ZoneNumAdj
   10108           1 :                             if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond).SolarEnclIndex == enclNum) {
   10109             :                                 // This interior window is adjacent to ZoneNum and associated with this
   10110           1 :                                 ++NumOfIntWindowsCount;
   10111             :                             }
   10112             :                         }
   10113             :                     }
   10114             :                     // allocate nested array
   10115           1 :                     thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).IntWinNum.allocate(NumOfIntWindowsCount);
   10116           1 :                     thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).IntWinNum = 0;
   10117           1 :                     int IntWinIndex = 0;
   10118           9 :                     for (int SurfNumAdj2 : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10119          10 :                         if ((state.dataSurface->Surface(SurfNumAdj2).Class == SurfaceClass::Window) &&
   10120           2 :                             (state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond >= 1)) {
   10121             :                             // This is an interior window in ZoneNumAdj
   10122           1 :                             if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond).SolarEnclIndex == enclNum) {
   10123             :                                 // This interior window is adjacent to ZoneNum and associated with this
   10124           1 :                                 ++IntWinIndex;
   10125           1 :                                 thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).IntWinNum(IntWinIndex) = SurfNumAdj2;
   10126             :                             }
   10127             :                         }
   10128             :                     }
   10129             :                 }
   10130             :             }
   10131             :         }
   10132             :     } // End of primary enclosure loop
   10133             : 
   10134         124 :     Array1D_int enclExtWin;
   10135          62 :     enclExtWin.dimension(state.dataViewFactor->NumOfSolarEnclosures, 0);
   10136             : 
   10137         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10138         708 :         enclExtWin(enclNum) = 0;
   10139         708 :         if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
   10140         286 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10141         286 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10142             :         // This is a Daylighting:Detailed zone
   10143             : 
   10144             :         // Get exterior windows in this solar enclosure
   10145        3405 :         for (int const surfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
   10146        7083 :             if ((state.dataSurface->Surface(surfNum).Class == SurfaceClass::Window &&
   10147        5406 :                  state.dataSurface->Surface(surfNum).ExtBoundCond == ExternalEnvironment) ||
   10148        2284 :                 state.dataSurface->SurfWinOriginalClass(surfNum) == SurfaceClass::TDD_Diffuser) {
   10149         838 :                 ++enclExtWin(enclNum);
   10150             :             }
   10151             :         }
   10152             : 
   10153             :         // Get exterior windows in adjacent enclosures that share interior windows with enclNum
   10154         283 :         if (thisEnclDaylight.NumOfIntWinAdjEncls > 0) {
   10155           2 :             for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
   10156             :                 // Get exterior windows in EnclNumAdj -- there must be at least one, otherwise
   10157             :                 // it would not be an "AdjIntWinEncl"
   10158           9 :                 for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10159          18 :                     if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window &&
   10160          15 :                          state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment) ||
   10161           7 :                         state.dataSurface->SurfWinOriginalClass(SurfNumAdj) == SurfaceClass::TDD_Diffuser) {
   10162           1 :                         ++enclExtWin(enclNum);
   10163             :                     }
   10164             :                 }
   10165             :             }
   10166             :         }
   10167             :     } // End of primary enclosure loop
   10168             : 
   10169          62 :     std::size_t maxShadeDeployOrderExtWinsSize(0);
   10170         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10171         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10172         708 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10173         283 :         thisEnclDaylight.NumOfDayltgExtWins = 0;
   10174         283 :         int thisEnclNumRefPoints = state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints;
   10175         283 :         if (thisEnclNumRefPoints > 0) {
   10176             :             // This is a Daylighting:Detailed enclosure
   10177             : 
   10178             :             // Get exterior windows in this enclosure
   10179         283 :             if (enclExtWin(enclNum) == 0) continue;
   10180         283 :             thisEnclDaylight.DayltgExtWinSurfNums.allocate(enclExtWin(enclNum));
   10181         283 :             thisEnclDaylight.DayltgExtWinSurfNums = 0;
   10182         567 :             for (int controlNum : thisEnclDaylight.daylightControlIndexes) {
   10183         284 :                 auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
   10184         284 :                 thisDaylightControl.MapShdOrdToLoopNum.allocate(enclExtWin(enclNum));
   10185         284 :                 thisDaylightControl.MapShdOrdToLoopNum = 0;
   10186             : 
   10187         284 :                 thisDaylightControl.SolidAngAtRefPt.allocate(enclExtWin(enclNum), thisDaylightControl.TotalDaylRefPoints);
   10188         284 :                 thisDaylightControl.SolidAngAtRefPt = 0.0;
   10189         284 :                 thisDaylightControl.SolidAngAtRefPtWtd.allocate(enclExtWin(enclNum), thisDaylightControl.TotalDaylRefPoints);
   10190         284 :                 thisDaylightControl.SolidAngAtRefPtWtd = 0.0;
   10191         284 :                 thisDaylightControl.IllumFromWinAtRefPt.allocate(enclExtWin(enclNum), 2, thisDaylightControl.TotalDaylRefPoints);
   10192         284 :                 thisDaylightControl.IllumFromWinAtRefPt = 0.0;
   10193         284 :                 thisDaylightControl.BackLumFromWinAtRefPt.allocate(enclExtWin(enclNum), 2, thisDaylightControl.TotalDaylRefPoints);
   10194         284 :                 thisDaylightControl.BackLumFromWinAtRefPt = 0.0;
   10195         284 :                 thisDaylightControl.SourceLumFromWinAtRefPt.allocate(enclExtWin(enclNum), 2, thisDaylightControl.TotalDaylRefPoints);
   10196         284 :                 thisDaylightControl.SourceLumFromWinAtRefPt = 0.0;
   10197             :             }
   10198             : 
   10199         283 :             int enclExtWinCtr = 0;
   10200             : 
   10201        3405 :             for (int const surfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
   10202        7083 :                 if ((state.dataSurface->Surface(surfNum).Class == SurfaceClass::Window &&
   10203        5406 :                      state.dataSurface->Surface(surfNum).ExtBoundCond == ExternalEnvironment) ||
   10204        2284 :                     state.dataSurface->SurfWinOriginalClass(surfNum) == SurfaceClass::TDD_Diffuser) {
   10205         838 :                     ++enclExtWinCtr;
   10206         838 :                     thisEnclDaylight.DayltgExtWinSurfNums(enclExtWinCtr) = surfNum;
   10207             :                 }
   10208             :             }
   10209             : 
   10210             :             // Get exterior windows in adjacent enclosures that share interior windows with enclNum
   10211         283 :             if (thisEnclDaylight.NumOfIntWinAdjEncls > 0) {
   10212           2 :                 for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
   10213             :                     // Get exterior windows in EnclNumAdj -- there must be at least one, otherwise
   10214             :                     // it would not be an "AdjIntWinEncl"
   10215           9 :                     for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
   10216          18 :                         if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window &&
   10217          15 :                              state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment) ||
   10218           7 :                             state.dataSurface->SurfWinOriginalClass(SurfNumAdj) == SurfaceClass::TDD_Diffuser) {
   10219           1 :                             ++enclExtWinCtr;
   10220           1 :                             thisEnclDaylight.DayltgExtWinSurfNums(enclExtWinCtr) = SurfNumAdj;
   10221             : 
   10222             :                             // If no daylighting in the adjacent enclosure, set up variables anyway:
   10223           1 :                             if (state.dataViewFactor->EnclSolInfo(adjEnclNum).TotalEnclosureDaylRefPoints == 0) {
   10224           1 :                                 if (!state.dataSurface->SurfWinSurfDayLightInit(SurfNumAdj)) {
   10225           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPt.allocate(thisEnclNumRefPoints);
   10226           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPt = 0.0;
   10227           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPtWtd.allocate(thisEnclNumRefPoints);
   10228           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPtWtd = 0.0;
   10229           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).IllumFromWinAtRefPt.allocate(2, thisEnclNumRefPoints);
   10230           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).IllumFromWinAtRefPt = 0.0;
   10231           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).BackLumFromWinAtRefPt.allocate(2, thisEnclNumRefPoints);
   10232           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).BackLumFromWinAtRefPt = 0.0;
   10233           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).SourceLumFromWinAtRefPt.allocate(2, thisEnclNumRefPoints);
   10234           1 :                                     state.dataSurface->SurfaceWindow(SurfNumAdj).SourceLumFromWinAtRefPt = 0.0;
   10235           1 :                                     state.dataSurface->SurfWinSurfDayLightInit(SurfNumAdj) = true;
   10236             :                                 }
   10237             :                             }
   10238             :                         }
   10239             :                     }
   10240             :                 }
   10241             :             }
   10242             : 
   10243         283 :             thisEnclDaylight.NumOfDayltgExtWins = enclExtWin(enclNum);
   10244         283 :             int winSize = enclExtWin(enclNum);
   10245             : 
   10246         567 :             for (int controlNum : thisEnclDaylight.daylightControlIndexes) {
   10247         284 :                 auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
   10248         284 :                 int refSize = thisDaylightControl.TotalDaylRefPoints;
   10249         284 :                 thisDaylightControl.DaylIllFacSky.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, 4, refSize, winSize);
   10250         284 :                 thisDaylightControl.DaylSourceFacSky.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, 4, refSize, winSize);
   10251         284 :                 thisDaylightControl.DaylBackFacSky.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, 4, refSize, winSize);
   10252         284 :                 thisDaylightControl.DaylIllFacSun.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
   10253         284 :                 thisDaylightControl.DaylIllFacSunDisk.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
   10254         284 :                 thisDaylightControl.DaylSourceFacSun.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
   10255         284 :                 thisDaylightControl.DaylSourceFacSunDisk.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
   10256         284 :                 thisDaylightControl.DaylBackFacSun.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
   10257         284 :                 thisDaylightControl.DaylBackFacSunDisk.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
   10258             :             }
   10259             :         } // End of check if thisEnclNumRefPoints > 0
   10260             : 
   10261         283 :         if (state.dataSurface->TotWinShadingControl > 0) {
   10262          22 :             std::size_t maxSize = CreateShadeDeploymentOrder(state, enclNum);
   10263          22 :             if (maxSize > maxShadeDeployOrderExtWinsSize) maxShadeDeployOrderExtWinsSize = maxSize;
   10264             :         }
   10265             :     } // End of primary enclosure loop
   10266             : 
   10267             :     // size these for the maximum of the shade deployment order
   10268          62 :     state.dataDaylightingManager->DILLSW.allocate(maxShadeDeployOrderExtWinsSize);
   10269          62 :     state.dataDaylightingManager->DILLUN.allocate(maxShadeDeployOrderExtWinsSize);
   10270          62 :     state.dataDaylightingManager->WDAYIL.allocate(2, state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
   10271          62 :     state.dataDaylightingManager->WBACLU.allocate(2, state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
   10272          62 :     state.dataDaylightingManager->RDAYIL.allocate(state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
   10273          62 :     state.dataDaylightingManager->RBACLU.allocate(state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
   10274             : 
   10275          62 :     state.dataDaylightingManager->TVIS1.allocate(maxShadeDeployOrderExtWinsSize);
   10276          62 :     state.dataDaylightingManager->TVIS2.allocate(maxShadeDeployOrderExtWinsSize);
   10277          62 :     state.dataDaylightingManager->ASETIL.allocate(maxShadeDeployOrderExtWinsSize);
   10278             : 
   10279         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10280         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10281         708 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10282         283 :         int thisEnclNumRefPoints = state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints;
   10283         283 :         if (thisEnclNumRefPoints > 0) {
   10284         283 :             if (state.dataSurface->TotWinShadingControl > 0) {
   10285          22 :                 MapShadeDeploymentOrderToLoopNumber(state, enclNum);
   10286             :             }
   10287             :         }
   10288             :     }
   10289             : 
   10290          69 :     for (int mapNum = 1; mapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapNum) {
   10291           7 :         int numExtWin = enclExtWin(state.dataDaylightingData->IllumMapCalc(mapNum).enclIndex);
   10292           7 :         int numMapRefPts = state.dataDaylightingData->IllumMapCalc(mapNum).TotalMapRefPoints;
   10293             : 
   10294           7 :         if (numMapRefPts > 0) {
   10295           7 :             state.dataDaylightingData->IllumMapCalc(mapNum).IllumFromWinAtMapPt.allocate(numExtWin, 2, numMapRefPts);
   10296           7 :             state.dataDaylightingData->IllumMapCalc(mapNum).IllumFromWinAtMapPt = 0.0;
   10297             : 
   10298          14 :             state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSky.allocate(
   10299          14 :                 24, state.dataSurface->actualMaxSlatAngs + 1, 4, numMapRefPts, numExtWin);
   10300          14 :             state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSun.allocate(
   10301          14 :                 24, state.dataSurface->actualMaxSlatAngs + 1, numMapRefPts, numExtWin);
   10302          14 :             state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSunDisk.allocate(
   10303          14 :                 24, state.dataSurface->actualMaxSlatAngs + 1, numMapRefPts, numExtWin);
   10304             :         }
   10305             :     } // End of map loop
   10306             : 
   10307          62 :     state.dataDaylightingManager->EINTSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4, 0.0);
   10308          62 :     state.dataDaylightingManager->EINTSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
   10309          62 :     state.dataDaylightingManager->EINTSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
   10310          62 :     state.dataDaylightingManager->WLUMSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4, 0.0);
   10311          62 :     state.dataDaylightingManager->WLUMSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
   10312          62 :     state.dataDaylightingManager->WLUMSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
   10313          62 :     state.dataDaylightingManager->EDIRSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4);
   10314          62 :     state.dataDaylightingManager->EDIRSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
   10315          62 :     state.dataDaylightingManager->EDIRSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
   10316          62 :     state.dataDaylightingManager->AVWLSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4);
   10317          62 :     state.dataDaylightingManager->AVWLSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
   10318          62 :     state.dataDaylightingManager->AVWLSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
   10319          62 :     state.dataDaylightingManager->FLFWSU.dimension(state.dataSurface->actualMaxSlatAngs + 1);
   10320          62 :     state.dataDaylightingManager->FLFWSUdisk.dimension(state.dataSurface->actualMaxSlatAngs + 1);
   10321          62 :     state.dataDaylightingManager->FLCWSU.dimension(state.dataSurface->actualMaxSlatAngs + 1);
   10322          62 :     state.dataDaylightingManager->TransMult.dimension(state.dataSurface->actualMaxSlatAngs);
   10323          62 :     state.dataDaylightingManager->DayltgInterReflectedIllumTransBmBmMult.dimension(state.dataSurface->actualMaxSlatAngs);
   10324          62 :     state.dataDaylightingManager->TransBmBmMult.dimension(state.dataSurface->actualMaxSlatAngs);
   10325          62 :     state.dataDaylightingManager->TransBmBmMultRefl.dimension(state.dataSurface->actualMaxSlatAngs);
   10326          62 :     state.dataDaylightingManager->FLCWSK.dimension(state.dataSurface->actualMaxSlatAngs + 1, 4);
   10327          62 :     state.dataDaylightingManager->FLFWSK.dimension(state.dataSurface->actualMaxSlatAngs + 1, 4);
   10328             : 
   10329             :     static constexpr std::string_view Format_700("! <Enclosure/Window Adjacency Daylighting Counts>, Enclosure Name, Number of Exterior Windows, "
   10330             :                                                  "Number of Exterior Windows in Adjacent Enclosures\n");
   10331          62 :     print(state.files.eio, Format_700);
   10332         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10333         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10334         708 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10335         283 :         if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
   10336             :         static constexpr std::string_view Format_701("Enclosure/Window Adjacency Daylighting Counts, {},{},{}\n");
   10337         566 :         print(state.files.eio,
   10338             :               Format_701,
   10339         283 :               state.dataViewFactor->EnclSolInfo(enclNum).Name,
   10340             :               thisEnclDaylight.TotalExtWindows,
   10341         566 :               (thisEnclDaylight.NumOfDayltgExtWins - thisEnclDaylight.TotalExtWindows));
   10342             :     }
   10343             :     static constexpr std::string_view Format_702(
   10344             :         "! <Enclosure/Window Adjacency Daylighting Matrix>, Enclosure Name, Number of Adjacent Enclosures with Windows,Adjacent "
   10345             :         "Enclosure Names - 1st 100 (max)\n");
   10346          62 :     print(state.files.eio, Format_702);
   10347         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10348         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10349         708 :         if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
   10350         283 :         if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
   10351             :         static constexpr std::string_view Format_703("Enclosure/Window Adjacency Daylighting Matrix, {},{}");
   10352         283 :         print(state.files.eio, Format_703, state.dataViewFactor->EnclSolInfo(enclNum).Name, thisEnclDaylight.NumOfIntWinAdjEncls);
   10353         284 :         for (int loop = 1, loop_end = min(thisEnclDaylight.NumOfIntWinAdjEncls, 100); loop <= loop_end; ++loop) {
   10354           1 :             print(state.files.eio, ",{}", state.dataViewFactor->EnclSolInfo(thisEnclDaylight.AdjIntWinEnclNums(loop)).Name);
   10355             :         }
   10356         283 :         print(state.files.eio, "\n");
   10357             :     }
   10358             : 
   10359          62 :     enclExtWin.deallocate();
   10360          62 : }
   10361             : 
   10362          22 : std::size_t CreateShadeDeploymentOrder(EnergyPlusData &state, int const enclNum)
   10363             : {
   10364             :     // J. Glazer - 2018
   10365             :     // create sorted list for shade deployment order
   10366             :     // first step is to create a sortable list of WindowShadingControl objects by sequence
   10367          44 :     std::vector<std::pair<int, int>> shadeControlSequence; // sequence, WindowShadingControl
   10368          55 :     for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
   10369          41 :         for (int spaceNum : state.dataHeatBal->Zone(state.dataSurface->WindowShadingControl(iShadeCtrl).ZoneIndex).spaceIndexes) {
   10370          33 :             int shadeCtrlEnclNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
   10371          33 :             if (shadeCtrlEnclNum == enclNum) {
   10372          25 :                 shadeControlSequence.push_back(std::make_pair(state.dataSurface->WindowShadingControl(iShadeCtrl).SequenceNumber, iShadeCtrl));
   10373          25 :                 break;
   10374             :             }
   10375             :         }
   10376             :     }
   10377             :     // sort the WindowShadingControl objects based on sequence number
   10378          22 :     sort(shadeControlSequence.begin(), shadeControlSequence.end());
   10379             :     // now make the deployment list of lists.
   10380             :     // each sublist is a group of surfaces that should be deployed together
   10381             :     // often the sublist is just a single item.
   10382          22 :     std::size_t maxShadeDeployOrderExtWinsSize = 0;
   10383          44 :     for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
   10384          22 :         auto &thisDaylightCtrl = state.dataDaylightingData->daylightControl(controlNum);
   10385          47 :         for (auto sequence : shadeControlSequence) {
   10386          25 :             int curShadeControl = sequence.second;
   10387          25 :             if (state.dataSurface->WindowShadingControl(curShadeControl).multiSurfaceControl == MultiSurfaceControl::Group) {
   10388             :                 // add a group of surfaces since they should be deployed as a group
   10389           8 :                 std::vector<int> group;
   10390          13 :                 for (int i = 1; i <= state.dataSurface->WindowShadingControl(curShadeControl).FenestrationCount; i++) {
   10391           9 :                     group.push_back(state.dataSurface->WindowShadingControl(curShadeControl).FenestrationIndex(i));
   10392             :                 }
   10393           4 :                 thisDaylightCtrl.ShadeDeployOrderExtWins.push_back(group);
   10394             :             } else {
   10395             :                 // add each individial surface as a separate list so they are deployed individually
   10396          46 :                 for (int i = 1; i <= state.dataSurface->WindowShadingControl(curShadeControl).FenestrationCount; i++) {
   10397          50 :                     std::vector<int> singleMemberVector;
   10398          25 :                     singleMemberVector.push_back(state.dataSurface->WindowShadingControl(curShadeControl).FenestrationIndex(i));
   10399          25 :                     thisDaylightCtrl.ShadeDeployOrderExtWins.push_back(singleMemberVector);
   10400             :                 }
   10401             :             }
   10402             :         }
   10403          22 :         maxShadeDeployOrderExtWinsSize = max(maxShadeDeployOrderExtWinsSize, thisDaylightCtrl.ShadeDeployOrderExtWins.size());
   10404             :     }
   10405          22 :     int maxNumOfDayltgExtWins = 0;
   10406         117 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10407          95 :         maxNumOfDayltgExtWins = max(maxNumOfDayltgExtWins, state.dataDaylightingData->enclDaylight(enclNum).NumOfDayltgExtWins);
   10408             :     }
   10409          22 :     state.dataDaylightingManager->previously_shaded.allocate(maxNumOfDayltgExtWins);
   10410             : 
   10411          44 :     return maxShadeDeployOrderExtWinsSize;
   10412             : }
   10413             : 
   10414          22 : void MapShadeDeploymentOrderToLoopNumber(EnergyPlusData &state, int const enclNum)
   10415             : {
   10416             :     // J. Glazer - 2018
   10417             :     // Allow a way to map back to the original "loop" index that is used in many other places in the
   10418             :     // ZoneDayLight data structure when traversing the list in the order of the window shaded deployment
   10419             : 
   10420          22 :     auto const &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10421          22 :     auto const &thisSolEnclosureName = state.dataViewFactor->EnclSolInfo(enclNum).Name;
   10422          22 :     if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0 && thisEnclDaylight.NumOfDayltgExtWins > 0) {
   10423          44 :         for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
   10424          22 :             auto &thisDaylightCtrl = state.dataDaylightingData->daylightControl(controlNum);
   10425          22 :             if (thisDaylightCtrl.ShadeDeployOrderExtWins.size() > 0) {
   10426          21 :                 int count = 0;
   10427          21 :                 bool showOnce = true;
   10428          50 :                 for (auto listOfExtWin : thisDaylightCtrl.ShadeDeployOrderExtWins) {
   10429          63 :                     for (auto IWinShdOrd : listOfExtWin) {
   10430          34 :                         ++count;
   10431          34 :                         if (count > thisEnclDaylight.NumOfDayltgExtWins) {
   10432           0 :                             if (showOnce) {
   10433           0 :                                 ShowWarningError(state,
   10434           0 :                                                  "MapShadeDeploymentOrderToLoopNumber: too many controlled shaded windows in enclosure " +
   10435             :                                                      thisSolEnclosureName);
   10436           0 :                                 ShowContinueError(
   10437             :                                     state, "Check the Zone Name in the WindowShadingControl that references the following fenestration surfaces:");
   10438           0 :                                 showOnce = false;
   10439             :                             }
   10440           0 :                             ShowContinueError(state, "  -  " + state.dataSurface->Surface(IWinShdOrd).Name);
   10441             :                         }
   10442          34 :                         bool found = false;
   10443          86 :                         for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
   10444          86 :                             int IWinLoop = thisEnclDaylight.DayltgExtWinSurfNums(loop);
   10445          86 :                             if (IWinShdOrd == IWinLoop) {
   10446          34 :                                 thisDaylightCtrl.MapShdOrdToLoopNum(count) = loop;
   10447          34 :                                 found = true;
   10448          34 :                                 break;
   10449             :                             }
   10450             :                         }
   10451             :                     }
   10452             :                 }
   10453             :             }
   10454             :         } // controlNum loop
   10455             :     }
   10456          22 : }
   10457             : 
   10458        1015 : void DayltgInterReflIllFrIntWins(EnergyPlusData &state, int const enclNum)
   10459             : {
   10460             : 
   10461             :     // SUBROUTINE INFORMATION:
   10462             :     //       AUTHOR         Fred Winkelmann
   10463             :     //       DATE WRITTEN   Mar. 2004
   10464             : 
   10465             :     // PURPOSE OF THIS SUBROUTINE:
   10466             :     // Calculates the inter-reflected illuminance in a daylit zone from beam
   10467             :     // and diffuse daylight entering the zone through interior windows. This illuminance
   10468             :     // is determined by the split-flux method and is assumed to be uniform, i.e., the same
   10469             :     // at all reference points.
   10470             : 
   10471             :     Real64 QDifTrans;              // Luminous flux transmitted through an int win from adjacent zone's enclosure (lumens)
   10472             :     Real64 QDifTransUp;            // Upgoing part of QDifTrans (lumens)
   10473             :     Real64 QDifTransDn;            // Downgoing part of QDifTrans (lumens)
   10474             :     Real64 DifInterReflIllThisWin; // Inter-reflected illuminance due to QDifTrans (lux)
   10475             :     Real64 BmInterReflIll;         // Inter-reflected illuminance due to beam solar entering ZoneNum's enclosure
   10476             :                                    //  through its interior windows (lux)
   10477             : 
   10478        1015 :     auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10479        1015 :     thisEnclDaylight.InterReflIllFrIntWins = 0.0;
   10480             : 
   10481        1015 :     auto &thisEnclSurfaces(state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr);
   10482        8120 :     for (int const IWin : thisEnclSurfaces) {
   10483        7105 :         if (state.dataSurface->Surface(IWin).Class == SurfaceClass::Window && state.dataSurface->Surface(IWin).ExtBoundCond >= 1) {
   10484             :             // This is an interior window in ZoneNum
   10485        1015 :             int const ConstrNum = state.dataSurface->Surface(IWin).Construction;
   10486        1015 :             int const adjEnclNum = state.dataSurface->Surface(state.dataSurface->Surface(IWin).ExtBoundCond).SolarEnclIndex;
   10487        3045 :             QDifTrans = state.dataHeatBal->EnclSolQSDifSol(adjEnclNum) * state.dataConstruction->Construct(ConstrNum).TransDiffVis *
   10488        2030 :                         state.dataSurface->Surface(IWin).Area * state.dataEnvrn->PDIFLW;
   10489        1015 :             QDifTransUp = QDifTrans * state.dataSurface->SurfWinFractionUpgoing(IWin);
   10490        1015 :             QDifTransDn = QDifTrans * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
   10491        3045 :             if (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea *
   10492        2030 :                     (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect) !=
   10493             :                 0.0) {
   10494        1015 :                 DifInterReflIllThisWin =
   10495        1015 :                     (QDifTransDn * state.dataSurface->SurfWinRhoFloorWall(IWin) + QDifTransUp * state.dataSurface->SurfWinRhoCeilingWall(IWin)) /
   10496        2030 :                     (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea *
   10497        1015 :                      (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect));
   10498             :             } else {
   10499           0 :                 DifInterReflIllThisWin = 0.0;
   10500             :             }
   10501        1015 :             thisEnclDaylight.InterReflIllFrIntWins += DifInterReflIllThisWin;
   10502             :         }
   10503             :     }
   10504             : 
   10505             :     // Add inter-reflected illuminance from beam solar entering enclosure through interior windows
   10506             :     // TH, CR 7873, 9/17/2009
   10507        1015 :     BmInterReflIll = 0.0;
   10508        1015 :     if (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea > 0) {
   10509        3045 :         BmInterReflIll = (state.dataHeatBal->EnclSolDBIntWin(enclNum) * state.dataEnvrn->BeamSolarRad * state.dataEnvrn->PDIRLW *
   10510        1015 :                           state.dataDaylightingData->enclDaylight(enclNum).floorVisRefl) /
   10511        2030 :                          (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea *
   10512        1015 :                           (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect));
   10513             :     }
   10514             : 
   10515        1015 :     thisEnclDaylight.InterReflIllFrIntWins += BmInterReflIll;
   10516        1015 : }
   10517             : 
   10518          62 : void CalcMinIntWinSolidAngs(EnergyPlusData &state)
   10519             : {
   10520             : 
   10521             :     // SUBROUTINE INFORMATION:
   10522             :     //       AUTHOR         Fred Winkelmann
   10523             :     //       DATE WRITTEN   Feb. 2004
   10524             :     //       MODIFIED:na
   10525             :     //       RE-ENGINEERED  na
   10526             : 
   10527             :     // PURPOSE OF THIS SUBROUTINE:
   10528             :     // For each Daylighting:Detailed zone finds the minimum solid angle subtended
   10529             :     // by interior windows through which daylight can pass from adjacent zones with
   10530             :     // exterior windows.
   10531             : 
   10532             :     // METHODOLOGY EMPLOYED:na
   10533             :     // REFERENCES:na
   10534             :     // Using/Aliasing
   10535             : 
   10536             :     // Locals
   10537             :     // SUBROUTINE ARGUMENT DEFINITIONS: na
   10538             :     // SUBROUTINE PARAMETER DEFINITIONS: na
   10539             :     // INTERFACE BLOCK SPECIFICATIONS: na
   10540             :     // DERIVED TYPE DEFINITIONS: na
   10541             : 
   10542             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   10543             : 
   10544             :     bool is_Triangle;      // True if window is a triangle
   10545             :     bool is_Rectangle;     // True if window is a rectangle
   10546             :     Real64 IntWinSolidAng; // Approximation to solid angle subtended by an interior window
   10547             :     // from a point a distance SQRT(zone floor area) away.
   10548          62 :     auto &W1 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW1; // Window vertices
   10549          62 :     auto &W2 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW2;
   10550          62 :     auto &W3 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW3;
   10551          62 :     auto &WC = state.dataDaylightingManager->CalcMinIntWinSolidAngsWC;   // Center point of window
   10552          62 :     auto &W21 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW21; // Unit vectors from window vertex 2 to 1 and 2 to 3
   10553          62 :     auto &W23 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW23;
   10554          62 :     auto &RREF = state.dataDaylightingManager->CalcMinIntWinSolidAngsRREF;   // Location of a reference point in absolute coordinate system
   10555          62 :     auto &Ray = state.dataDaylightingManager->CalcMinIntWinSolidAngsRay;     // Unit vector along ray from reference point to window center
   10556          62 :     auto &REFWC = state.dataDaylightingManager->CalcMinIntWinSolidAngsREFWC; // Vector from reference point to center of window
   10557          62 :     auto &WNORM = state.dataDaylightingManager->CalcMinIntWinSolidAngsWNORM; // Unit vector normal to window (pointing away from room)
   10558             :     Real64 HW;                                                               // Window height and width (m)
   10559             :     Real64 WW;
   10560             :     Real64 DIS;  // Distance from ref point to window center (m)
   10561             :     Real64 COSB; // Cosine of angle between ray from ref pt to center of window
   10562             :                  //  and window outward normal
   10563             : 
   10564         770 :     for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
   10565         708 :         auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
   10566         708 :         thisEnclDaylight.MinIntWinSolidAng = 2.0 * DataGlobalConstants::Pi;
   10567         708 :         if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
   10568         286 :         if (thisEnclDaylight.NumOfIntWinAdjEncls == 0) continue;
   10569           8 :         for (int IWin : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
   10570           7 :             if ((state.dataSurface->Surface(IWin).Class == SurfaceClass::Window) && (state.dataSurface->Surface(IWin).ExtBoundCond >= 1)) {
   10571             :                 // This is an interior window in enclNum
   10572           1 :                 int const winAdjEnclNum = state.dataSurface->Surface(state.dataSurface->Surface(IWin).ExtBoundCond).SolarEnclIndex;
   10573           1 :                 bool IntWinNextToIntWinAdjZone = false; // True if an interior window is next to a zone with one or more exterior windows
   10574           1 :                 for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
   10575           1 :                     if (winAdjEnclNum == adjEnclNum) {
   10576           1 :                         IntWinNextToIntWinAdjZone = true;
   10577           1 :                         break;
   10578             :                     }
   10579             :                 }
   10580           1 :                 if (IntWinNextToIntWinAdjZone) {
   10581           2 :                     for (int controlNum : thisEnclDaylight.daylightControlIndexes) {
   10582           1 :                         auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
   10583           2 :                         for (int IL = 1; IL <= thisDaylightControl.TotalDaylRefPoints; ++IL) {
   10584             :                             // Reference point in absolute coordinate system
   10585           1 :                             RREF = thisDaylightControl.DaylRefPtAbsCoord({1, 3}, IL);
   10586           1 :                             is_Triangle = (state.dataSurface->Surface(IWin).Sides == 3);
   10587           1 :                             is_Rectangle = (state.dataSurface->Surface(IWin).Sides == 4);
   10588           1 :                             if (is_Rectangle) {
   10589             :                                 // Vertices of window numbered counter-clockwise starting at upper left as viewed
   10590             :                                 // from inside of room. Assumes original vertices are numbered counter-clockwise from
   10591             :                                 // upper left as viewed from outside.
   10592           1 :                                 W3 = state.dataSurface->Surface(IWin).Vertex(2);
   10593           1 :                                 W2 = state.dataSurface->Surface(IWin).Vertex(3);
   10594           1 :                                 W1 = state.dataSurface->Surface(IWin).Vertex(4);
   10595           0 :                             } else if (is_Triangle) {
   10596           0 :                                 W3 = state.dataSurface->Surface(IWin).Vertex(2);
   10597           0 :                                 W2 = state.dataSurface->Surface(IWin).Vertex(3);
   10598           0 :                                 W1 = state.dataSurface->Surface(IWin).Vertex(1);
   10599             :                             }
   10600             :                             // Unit vectors from window vertex 2 to 1 and 2 to 3, center point of window,
   10601             :                             // and vector from ref pt to center of window
   10602           1 :                             W21 = W1 - W2;
   10603           1 :                             W23 = W3 - W2;
   10604           1 :                             HW = W21.magnitude();
   10605           1 :                             WW = W23.magnitude();
   10606           1 :                             if (is_Rectangle) {
   10607           1 :                                 WC = W2 + (W23 + W21) / 2.0;
   10608           0 :                             } else if (is_Triangle) {
   10609           0 :                                 WC = W2 + (W23 + W21) / 3.0;
   10610             :                             }
   10611             :                             // Vector from ref point to center of window
   10612           1 :                             REFWC = WC - RREF;
   10613           1 :                             W21 /= HW;
   10614           1 :                             W23 /= WW;
   10615             :                             // Unit vector normal to window (pointing away from room)
   10616           1 :                             WNORM = state.dataSurface->Surface(IWin).OutNormVec;
   10617             :                             // Distance from ref point to center of window
   10618           1 :                             DIS = REFWC.magnitude();
   10619             :                             // Unit vector from ref point to center of window
   10620           1 :                             Ray = REFWC / DIS;
   10621             :                             // Cosine of angle between ray from ref pt to center of window and window outward normal
   10622           1 :                             COSB = dot(WNORM, Ray);
   10623           1 :                             if (COSB > 0.01765) { // 0 <= B < 89 deg
   10624             :                                 // Above test avoids case where ref point cannot receive daylight directly from the
   10625             :                                 // interior window
   10626           1 :                                 IntWinSolidAng = COSB * state.dataSurface->Surface(IWin).Area / (pow_2(DIS) + 0.001);
   10627           1 :                                 thisEnclDaylight.MinIntWinSolidAng = min(thisEnclDaylight.MinIntWinSolidAng, IntWinSolidAng);
   10628             :                             }
   10629             :                         } // End of loop over reference points
   10630             :                     }     // End of loop over daylighting controls
   10631             :                 }
   10632             :             }
   10633             :         } // End of loop over surfaces in zone
   10634             :     }     // End of loop over zones
   10635          62 : }
   10636             : 
   10637         124 : void CheckForGeometricTransform(EnergyPlusData &state, bool &doTransform, Real64 &OldAspectRatio, Real64 &NewAspectRatio)
   10638             : {
   10639             : 
   10640             :     // SUBROUTINE INFORMATION:
   10641             :     //       AUTHOR         Linda Lawrie
   10642             :     //       DATE WRITTEN   February 2009
   10643             :     //       MODIFIED       na
   10644             :     //       RE-ENGINEERED  na
   10645             : 
   10646             :     // PURPOSE OF THIS SUBROUTINE:
   10647             :     // check for geometrytransform in the daylighting access for reference and map points
   10648             : 
   10649             :     // METHODOLOGY EMPLOYED:
   10650             :     // once reference points  have been converted to WCS,
   10651             :     //  change them to reflect a different aspect
   10652             :     // ratio for the entire building based on user input.
   10653             : 
   10654             :     // REFERENCES:
   10655             :     // na
   10656             : 
   10657             :     // Using/Aliasing
   10658             :     // Locals
   10659             :     // SUBROUTINE ARGUMENT DEFINITIONS:
   10660             : 
   10661             :     // SUBROUTINE PARAMETER DEFINITIONS:
   10662         124 :     static std::string const CurrentModuleObject("GeometryTransform");
   10663             : 
   10664             :     // INTERFACE BLOCK SPECIFICATIONS
   10665             :     // na
   10666             : 
   10667             :     // DERIVED TYPE DEFINITIONS
   10668             :     // na
   10669             : 
   10670             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   10671         248 :     Array1D_string cAlphas(1);
   10672         248 :     Array1D<Real64> rNumerics;
   10673             :     int NAlphas;
   10674             :     int NNum;
   10675             :     int IOStat;
   10676         248 :     std::string transformPlane;
   10677             : 
   10678             :     // begin execution
   10679             :     // get user input...
   10680         124 :     doTransform = false;
   10681         124 :     OldAspectRatio = 1.0;
   10682         124 :     NewAspectRatio = 1.0;
   10683             : 
   10684         124 :     if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
   10685           0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10686             :                                                                  CurrentModuleObject,
   10687             :                                                                  1,
   10688             :                                                                  cAlphas,
   10689             :                                                                  NAlphas,
   10690             :                                                                  rNumerics,
   10691             :                                                                  NNum,
   10692             :                                                                  IOStat,
   10693           0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
   10694           0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
   10695           0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
   10696           0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
   10697           0 :         OldAspectRatio = rNumerics(1);
   10698           0 :         NewAspectRatio = rNumerics(2);
   10699           0 :         transformPlane = cAlphas(1);
   10700           0 :         if (transformPlane != "XY") {
   10701           0 :             ShowWarningError(state,
   10702           0 :                              CurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" + cAlphas(1) + "...ignored.");
   10703             :         }
   10704           0 :         doTransform = true;
   10705           0 :         state.dataSurface->AspectTransform = true;
   10706             :     }
   10707         124 :     if (state.dataSurface->WorldCoordSystem) {
   10708          56 :         doTransform = false;
   10709          56 :         state.dataSurface->AspectTransform = false;
   10710             :     }
   10711         124 : }
   10712             : 
   10713          20 : void WriteDaylightMapTitle(EnergyPlusData &state,
   10714             :                            int const mapNum,
   10715             :                            InputOutputFile &mapFile,
   10716             :                            std::string const &mapName,
   10717             :                            std::string const &environmentName,
   10718             :                            int const ZoneNum,
   10719             :                            std::string const &refPts,
   10720             :                            Real64 const zcoord)
   10721             : {
   10722             :     // SUBROUTINE INFORMATION:
   10723             :     //       AUTHOR         Greg Stark
   10724             :     //       DATE WRITTEN   Sept 2008
   10725             :     //       MODIFIED       na
   10726             :     //       RE-ENGINEERED  na
   10727             : 
   10728             :     // PURPOSE OF THIS SUBROUTINE:
   10729             :     // The purpose of the routine is to allow the daylighting map data to be written in various formats
   10730             : 
   10731             :     // must add correct number of commas at end
   10732          60 :     const auto fullmapName = fmt::format("{}:{}:{} Illuminance [lux] (Hourly)", state.dataHeatBal->Zone(ZoneNum).Name, environmentName, mapName);
   10733         100 :     print(mapFile,
   10734             :           "Date/Time{}{}{}{}{}{}\n",
   10735          20 :           state.dataDaylightingData->MapColSep,
   10736             :           fullmapName,
   10737          20 :           state.dataDaylightingData->MapColSep,
   10738             :           refPts,
   10739          20 :           state.dataDaylightingData->MapColSep,
   10740          40 :           state.dataDaylightingData->MapColSep);
   10741             : 
   10742          20 :     if (state.dataSQLiteProcedures->sqlite) {
   10743           1 :         state.dataSQLiteProcedures->sqlite->createSQLiteDaylightMapTitle(mapNum, fullmapName, environmentName, ZoneNum, refPts, zcoord);
   10744             :     }
   10745          20 : }
   10746             : 
   10747        2313 : } // namespace EnergyPlus::DaylightingManager

Generated by: LCOV version 1.13