LCOV - code coverage report
Current view: top level - EnergyPlus - SolarReflectionManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 0.0 % 600 0
Test Date: 2025-05-22 16:09:37 Functions: 0.0 % 6 0

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : #include <cmath>
      51              : 
      52              : // EnergyPlus Headers
      53              : #include <EnergyPlus/Construction.hh>
      54              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      55              : #include <EnergyPlus/DataEnvironment.hh>
      56              : #include <EnergyPlus/DataHeatBalance.hh>
      57              : #include <EnergyPlus/DataSurfaces.hh>
      58              : #include <EnergyPlus/DataSystemVariables.hh>
      59              : #include <EnergyPlus/DataVectorTypes.hh>
      60              : #include <EnergyPlus/DisplayRoutines.hh>
      61              : #include <EnergyPlus/General.hh>
      62              : #include <EnergyPlus/PierceSurface.hh>
      63              : #include <EnergyPlus/ScheduleManager.hh>
      64              : #include <EnergyPlus/SolarReflectionManager.hh>
      65              : #include <EnergyPlus/SolarShading.hh>
      66              : 
      67              : namespace EnergyPlus {
      68              : 
      69              : namespace SolarReflectionManager {
      70              : 
      71              :     // MODULE INFORMATION
      72              :     //       AUTHOR         Fred Winkelmann
      73              :     //       DATE WRITTEN   September 2003
      74              :     //       MODIFIED       May 2004, FCW: modify calculation of receiving point location on a
      75              :     //                        receiving surface so can handle surface of any number of vertices
      76              :     //                        (previously restricted to 3- or 4-sided surfaces).
      77              :     //       RE-ENGINEERED  na
      78              : 
      79              :     // PURPOSE OF THIS MODULE:
      80              :     // Manages the calculation of factors for solar reflected from obstructions and ground.
      81              : 
      82              :     // METHODOLOGY EMPLOYED:
      83              :     // REFERENCES: na
      84              : 
      85              :     // OTHER NOTES: na
      86              : 
      87              :     // Using/Aliasing
      88              :     using namespace DataHeatBalance;
      89              :     using namespace DataSurfaces;
      90              :     using namespace DataEnvironment;
      91              : 
      92              :     using namespace DataVectorTypes;
      93              : 
      94            0 :     void InitSolReflRecSurf(EnergyPlusData &state)
      95              :     {
      96              : 
      97              :         // SUBROUTINE INFORMATION:
      98              :         //       AUTHOR         Fred Winkelmann
      99              :         //       DATE WRITTEN   September 2003
     100              :         //       MODIFIED       na
     101              :         //       RE-ENGINEERED  na
     102              : 
     103              :         // PURPOSE OF THIS SUBROUTINE:
     104              :         // Initializes the derived type SolReflRecSurf, which contains information
     105              :         // needed to calculate factors for solar reflection from obstructions and ground.
     106              : 
     107              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     108              :         int SurfNum;            // Surface number
     109              :         int RecSurfNum;         // Receiving surface number
     110              :         int loop;               // DO loop indices
     111              :         int loop1;              // DO loop indices
     112              :         int loopA;              // DO loop indices
     113              :         int loopB;              // DO loop indices
     114              :         int ObsSurfNum;         // Surface number of an obstruction
     115              :         bool ObsBehindRec;      // True if an obstruction is entirely behind a receiving surface
     116              :         bool ObsHasView;        // True if view between receiving surface and heat trans surf obstruction
     117            0 :         Vector3<Real64> RecVec; // First vertex of a receiving surface (m)
     118            0 :         Vector3<Real64> ObsVec; // A vertex of a candidate obstructing surface (m)
     119            0 :         Vector3<Real64> VecAB;  // Vector from receiving surface vertex to obstruction surface vertex (m)
     120            0 :         Vector3<Real64> HitPt;  // Hit point (m)
     121              :         Real64 DotProd;         // Dot product of vectors (m2)
     122              :         int RecPtNum;           // Receiving point number
     123              :         // unused  REAL(r64)         :: SumX                 ! Sum of X (or Y or Z) coordinate values of a surface
     124              :         // unused  REAL(r64)         :: SumY                 ! Sum of X (or Y or Z) coordinate values of a surface
     125              :         // unused  REAL(r64)         :: SumZ                 ! Sum of X (or Y or Z) coordinate values of a surface
     126              :         Real64 PhiSurf;   // Altitude of normal to receiving surface (radians)
     127              :         Real64 ThetaSurf; // Azimuth of normal to receiving surface (radians)
     128              :         Real64 PhiMin;    // Minimum and maximum values of ray altitude angle (radians)
     129              :         Real64 PhiMax;    // Minimum and maximum values of ray altitude angle (radians)
     130              :         Real64 ThetaMin;  // Minimum and maximum values of ray azimuth angle (radians)
     131              :         Real64 ThetaMax;  // Minimum and maximum values of ray azimuth angle (radians)
     132              :         Real64 Phi;       // Ray altitude angle, increment, sine, and cosine
     133              :         Real64 DPhi;      // Ray altitude angle, increment, sine, and cosine
     134              :         Real64 SPhi;      // Ray altitude angle, increment, sine, and cosine
     135              :         Real64 CPhi;      // Ray altitude angle, increment, sine, and cosine
     136              :         Real64 Theta;     // Ray azimuth angle and increment
     137              :         Real64 DTheta;    // Ray azimuth angle and increment
     138              :         int IPhi;         // Ray altitude angle and azimuth angle indices
     139              :         int ITheta;       // Ray altitude angle and azimuth angle indices
     140              :         // unused  REAL(r64)         :: APhi                 ! Intermediate variable
     141              :         int RayNum;                   // Ray number
     142            0 :         Vector3<Real64> URay;         // Unit vector along ray pointing away from receiving surface
     143              :         Real64 CosIncAngRay;          // Cosine of angle of incidence of ray on receiving surface
     144              :         Real64 dOmega;                // Solid angle associated with a ray
     145              :         bool hit;                     // True iff obstruction is hit
     146              :         int TotObstructionsHit;       // Number of obstructions hit by a ray
     147              :         Real64 HitDistance;           // Distance from receiving point to hit point for a ray (m)
     148              :         int NearestHitSurfNum;        // Surface number of nearest obstruction hit by a ray
     149            0 :         Vector3<Real64> NearestHitPt; // Nearest hit pit for a ray (m)
     150              :         Real64 NearestHitDistance;    // Distance from receiving point to nearest hit point for a ray (m)
     151              :         int ObsSurfNumToSkip;         // Surface number of obstruction to be ignored
     152            0 :         Vector3<Real64> RecPt;        // Receiving point (m)
     153            0 :         Vector3<Real64> RayVec;       // Unit vector along ray
     154            0 :         Vector3<Real64> Vec1;         // Vectors between hit surface vertices (m)
     155            0 :         Vector3<Real64> Vec2;         // Vectors between hit surface vertices (m)
     156            0 :         Vector3<Real64> VNorm;        // For a hit surface, unit normal vector pointing into the hemisphere
     157              :         // containing the receiving point
     158              :         int ObsConstrNum; // Construction number of obstruction; = 0 if a shading surface
     159              :         Real64 Alfa;      // Direction angles for ray heading towards the ground (radians)
     160              :         Real64 Beta;
     161              :         Real64 HorDis;               // Distance between ground hit point and proj'n of receiving pt onto ground (m)
     162            0 :         Vector3<Real64> GroundHitPt; // Coordinates of ground hit point
     163              :         // unused  REAL(r64)         :: ArgASin
     164              :         Real64 ACosTanTan;
     165              :         int J;           // DO loop indices
     166              :         int K;           // DO loop indices
     167              :         int NumRecPts;   // Number of surface receiving points for reflected solar radiation
     168              :         Real64 VertexWt; // Vertex weighting factor for calculating receiving points
     169              : 
     170            0 :         static Vector3<Real64> const unit_z(0.0, 0.0, 1.0);
     171            0 :         static Vector3<Real64> const zero3(0.0);
     172              : 
     173              :         // Find number of surfaces that are sun-exposed exterior building heat transfer surfaces.
     174              :         // These are candidates for receiving solar reflected from obstructions and ground.
     175              :         // CR 7640.  12/3/2008 BG simplified logic to allow for Other Side Conditions Modeled boundary condition.
     176              :         //           and solar collectors on shading surfaces that need this.
     177              : 
     178              :         // shading surfaces have ExtSolar = False, so they are not included in TotSolReflRecSurf
     179            0 :         state.dataSolarReflectionManager->TotSolReflRecSurf = 0;
     180            0 :         for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     181            0 :             if (state.dataSurface->Surface(SurfNum).ExtSolar) {
     182            0 :                 ++state.dataSolarReflectionManager->TotSolReflRecSurf;
     183              :             }
     184              :         }
     185              : 
     186              :         // TH 3/29/2010. ShadowSurfPossibleReflector is not used!
     187              :         // Set flag that determines whether a surface can be an exterior reflector
     188              :         // DO SurfNum = 1,TotSurfaces
     189              :         //  Surface(SurfNum)%ShadowSurfPossibleReflector = .FALSE.
     190              :         // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
     191              :         //  IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond > 0 ) CYCLE
     192              :         //  IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond == Ground) CYCLE
     193              :         //  IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond == OtherSideCoefNoCalcExt) CYCLE
     194              :         //  IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond == OtherSideCoefCalcExt) CYCLE
     195              : 
     196              :         // Exclude daylighting shelves. A separate solar reflection calculation is done for these.
     197              :         //  IF(Surface(SurfNum)%Shelf > 0) CYCLE
     198              : 
     199              :         // Exclude duplicate shading surfaces
     200              :         // TH 3/24/2010. Why? a mirror shading surface can reflect solar (either beam or diffuse)
     201              :         //  can use a flag like Surface(SurfNum)%Mirrored (True or False) to avoid string comparison
     202              :         //   and to allow surface names starting with 'Mir'
     203              :         // IF(Surface(SurfNum)%Name(1:3) == 'Mir') CYCLE
     204              :         //  IF(Surface(SurfNum)%MirroredSurf) CYCLE
     205              : 
     206              :         //  Surface(SurfNum)%ShadowSurfPossibleReflector = .TRUE.
     207              :         // END DO
     208              : 
     209            0 :         if (state.dataSolarReflectionManager->TotSolReflRecSurf == 0) {
     210            0 :             ShowWarningError(state, "Calculation of solar reflected from obstructions has been requested but there");
     211            0 :             ShowContinueError(state, "are no building surfaces that can receive reflected solar. Calculation will not be done.");
     212            0 :             state.dataSurface->CalcSolRefl = false;
     213            0 :             return;
     214              :         }
     215              : 
     216              :         // Should this be moved up front?
     217            0 :         if (state.dataEnvrn->IgnoreSolarRadiation) {
     218            0 :             state.dataSolarReflectionManager->TotSolReflRecSurf = 0;
     219            0 :             state.dataSurface->CalcSolRefl = false;
     220            0 :             return;
     221              :         }
     222              : 
     223            0 :         state.dataSolarReflectionManager->SolReflRecSurf.allocate(state.dataSolarReflectionManager->TotSolReflRecSurf);
     224              : 
     225            0 :         state.dataSurface->SurfReflFacBmToDiffSolObs.dimension(24, state.dataSurface->TotSurfaces, 0.0);
     226            0 :         state.dataSurface->SurfReflFacBmToDiffSolGnd.dimension(24, state.dataSurface->TotSurfaces, 0.0);
     227            0 :         state.dataSurface->SurfReflFacBmToBmSolObs.dimension(24, state.dataSurface->TotSurfaces, 0.0);
     228            0 :         state.dataSurface->SurfReflFacSkySolObs.dimension(state.dataSurface->TotSurfaces, 0.0);
     229            0 :         state.dataSurface->SurfReflFacSkySolGnd.dimension(state.dataSurface->TotSurfaces, 0.0);
     230            0 :         state.dataSurface->SurfCosIncAveBmToBmSolObs.dimension(24, state.dataSurface->TotSurfaces, 0.0);
     231              : 
     232              :         // Only surfaces with sun exposure can receive solar reflection from ground or onstructions
     233              :         //  Shading surfaces are always not exposed to solar (ExtSolar = False)
     234            0 :         RecSurfNum = 0;
     235            0 :         for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     236            0 :             state.dataSurface->SurfShadowRecSurfNum(SurfNum) = 0;
     237            0 :             if (state.dataSurface->Surface(SurfNum).ExtSolar) {
     238            0 :                 ++RecSurfNum;
     239            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).SurfNum = SurfNum;
     240            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).SurfName = state.dataSurface->Surface(SurfNum).Name;
     241            0 :                 state.dataSurface->SurfShadowRecSurfNum(SurfNum) = RecSurfNum;
     242              : 
     243              :                 // Warning if any receiving surface vertex is below ground level, taken to be at Z = 0 in absolute coords
     244            0 :                 for (loop = 1; loop <= state.dataSurface->Surface(SurfNum).Sides; ++loop) {
     245            0 :                     if (state.dataSurface->Surface(SurfNum).Vertex(loop).z < state.dataSurface->GroundLevelZ) {
     246            0 :                         ShowWarningError(
     247              :                             state,
     248            0 :                             format("Calculation of reflected solar onto surface={} may be inaccurate", state.dataSurface->Surface(SurfNum).Name));
     249            0 :                         ShowContinueError(state, "because it has one or more vertices below ground level.");
     250            0 :                         break;
     251              :                     }
     252              :                 }
     253              :             }
     254              :         }
     255              : 
     256              :         // Get MaxRecPts for allocating SolReflRecSurf arrays that depend on number of receiving points
     257            0 :         state.dataSurface->MaxRecPts = 1;
     258            0 :         for (RecSurfNum = 1; RecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf; ++RecSurfNum) {
     259            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumRecPts =
     260            0 :                 state.dataSurface->Surface(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).SurfNum).Sides;
     261            0 :             if (state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumRecPts > state.dataSurface->MaxRecPts)
     262            0 :                 state.dataSurface->MaxRecPts = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumRecPts;
     263              :         }
     264              : 
     265            0 :         state.dataSurface->MaxReflRays = AltAngStepsForSolReflCalc * AzimAngStepsForSolReflCalc;
     266            0 :         for (RecSurfNum = 1; RecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf; ++RecSurfNum) {
     267            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec = 0.0;
     268            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt.dimension(state.dataSurface->MaxRecPts, zero3);
     269            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RayVec.dimension(state.dataSurface->MaxReflRays, zero3);
     270            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).CosIncAngRay.dimension(state.dataSurface->MaxReflRays, 0.0);
     271            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).dOmegaRay.dimension(state.dataSurface->MaxReflRays, 0.0);
     272            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum)
     273            0 :                 .HitPt.dimension(state.dataSurface->MaxReflRays, state.dataSurface->MaxRecPts, zero3);
     274            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum)
     275            0 :                 .HitPtSurfNum.dimension(state.dataSurface->MaxReflRays, state.dataSurface->MaxRecPts, 0.0);
     276            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum)
     277            0 :                 .HitPtSolRefl.dimension(state.dataSurface->MaxReflRays, state.dataSurface->MaxRecPts, 0.0);
     278            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum)
     279            0 :                 .RecPtHitPtDis.dimension(state.dataSurface->MaxReflRays, state.dataSurface->MaxRecPts, 0.0);
     280            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum)
     281            0 :                 .HitPtNormVec.dimension(state.dataSurface->MaxReflRays, state.dataSurface->MaxRecPts, zero3);
     282            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums.dimension(state.dataSurface->TotSurfaces, 0);
     283              :         }
     284              : 
     285            0 :         for (RecSurfNum = 1; RecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf; ++RecSurfNum) {
     286            0 :             SurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).SurfNum;
     287              :             // Outward norm to receiving surface
     288            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec = state.dataSurface->Surface(SurfNum).OutNormVec;
     289            0 :             RecVec = state.dataSurface->Surface(SurfNum).Vertex(1);
     290              :             // Loop over all surfaces and find those that can be obstructing surfaces for this receiving surf
     291            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs = 0;
     292            0 :             for (ObsSurfNum = 1; ObsSurfNum <= state.dataSurface->TotSurfaces; ++ObsSurfNum) {
     293              :                 // Exclude the receiving surface itself and its base surface (if it has one)
     294            0 :                 if (ObsSurfNum == SurfNum || ObsSurfNum == state.dataSurface->Surface(SurfNum).BaseSurf) continue;
     295              :                 // Exclude non-exterior heat transfer surfaces
     296            0 :                 if (state.dataSurface->Surface(ObsSurfNum).HeatTransSurf && state.dataSurface->Surface(ObsSurfNum).ExtBoundCond != 0) continue;
     297              :                 // Exclude duplicate shading surfaces
     298              :                 // IF(Surface(ObsSurfNum)%Name(1:3) == 'Mir') CYCLE
     299              :                 // TH2 CR8959
     300              :                 // IF(Surface(ObsSurfNum)%MirroredSurf) CYCLE
     301              : 
     302              :                 // Exclude surfaces that are entirely behind the receiving surface.This is true if dot products of the
     303              :                 // rec. surface outward normal and vector from first vertex of rec. surface and each vertex of
     304              :                 // obstructing surface are all negative.
     305            0 :                 ObsBehindRec = true;
     306            0 :                 for (loop = 1; loop <= state.dataSurface->Surface(ObsSurfNum).Sides; ++loop) {
     307            0 :                     ObsVec = state.dataSurface->Surface(ObsSurfNum).Vertex(loop);
     308            0 :                     DotProd = dot(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec, ObsVec - RecVec);
     309              :                     // CR8251      IF(DotProd > 0.01d0) THEN  ! This obstructing-surface vertex is not behind receiving surface
     310            0 :                     if (DotProd > Constant::OneMillionth) { // This obstructing-surface vertex is not behind receiving surface
     311            0 :                         ObsBehindRec = false;
     312            0 :                         break;
     313              :                     }
     314              :                 }
     315            0 :                 if (ObsBehindRec) continue;
     316              : 
     317              :                 // Exclude heat transfer surfaces that have no view with the receiving surface.
     318              :                 // There is view if: for at least one vector VecAB from a receiving surface vertex to
     319              :                 // a vertex of a potential obstructing surface that satisfies VecAB.nA > 0.0 and VecAB.nB < 0.0,
     320              :                 // where nA and nB are the outward normal to the receiving and obstructing surface, resp.
     321            0 :                 if (state.dataSurface->Surface(ObsSurfNum).HeatTransSurf) {
     322            0 :                     ObsHasView = false;
     323            0 :                     for (loopA = 1; loopA <= state.dataSurface->Surface(SurfNum).Sides; ++loopA) {
     324            0 :                         for (loopB = 1; loopB <= state.dataSurface->Surface(ObsSurfNum).Sides; ++loopB) {
     325            0 :                             VecAB = (state.dataSurface->Surface(ObsSurfNum).Vertex(loopB) - state.dataSurface->Surface(SurfNum).Vertex(loopA));
     326            0 :                             if (dot(VecAB, state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec) > 0.0 &&
     327            0 :                                 dot(VecAB, state.dataSurface->Surface(ObsSurfNum).OutNormVec) < 0.0) {
     328            0 :                                 ObsHasView = true;
     329            0 :                                 break;
     330              :                             }
     331              :                         }
     332            0 :                         if (ObsHasView) break;
     333              :                     }
     334            0 :                     if (!ObsHasView) continue;
     335              :                 }
     336              : 
     337              :                 // This is a possible obstructing surface for this receiving surface
     338            0 :                 ++state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs;
     339            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum)
     340            0 :                     .PossibleObsSurfNums(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs) = ObsSurfNum;
     341              :             }
     342              : 
     343              :             // Get coordinates of receiving points on this receiving surface. The number of receiving points
     344              :             // is equal to the number of surface vertices (3 or higher).
     345              : 
     346            0 :             NumRecPts = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumRecPts;
     347            0 :             for (J = 1; J <= NumRecPts; ++J) {
     348            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(J) = 0.0;
     349            0 :                 for (K = 1; K <= NumRecPts; ++K) {
     350            0 :                     if (NumRecPts == 3) { // Receiving surface is a triangle
     351            0 :                         VertexWt = 0.2;
     352            0 :                         if (K == J) VertexWt = 0.6;
     353              :                     } else { // Receiving surface has 4 or more vertices
     354            0 :                         VertexWt = 1.0 / (2.0 * NumRecPts);
     355            0 :                         if (K == J) VertexWt = (NumRecPts + 1.0) / (2.0 * NumRecPts);
     356              :                     }
     357            0 :                     state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(J).x +=
     358            0 :                         VertexWt * state.dataSurface->Surface(SurfNum).Vertex(K).x;
     359            0 :                     state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(J).y +=
     360            0 :                         VertexWt * state.dataSurface->Surface(SurfNum).Vertex(K).y;
     361            0 :                     state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(J).z +=
     362            0 :                         VertexWt * state.dataSurface->Surface(SurfNum).Vertex(K).z;
     363              :                 }
     364              :             }
     365              : 
     366              :             // Create rays going outward from receiving surface. The same rays will be used at each receiving point.
     367              :             // The rays are used in calculating diffusely reflected solar incident on receiving surface.
     368              : 
     369              :             // Divide hemisphere around receiving surface into elements of altitude Phi and
     370              :             // azimuth Theta and create ray unit vector at each Phi,Theta pair in front of the surface.
     371              :             // Phi = 0 at the horizon; Phi = Pi/2 at the zenith
     372              : 
     373            0 :             PhiSurf = std::asin(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec.z);
     374            0 :             Real64 const tan_PhiSurf = std::tan(PhiSurf);
     375            0 :             Real64 const sin_PhiSurf = std::sin(PhiSurf);
     376            0 :             Real64 const cos_PhiSurf = std::cos(PhiSurf);
     377              : 
     378            0 :             if (std::abs(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec.x) > 1.0e-5 ||
     379            0 :                 std::abs(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec.y) > 1.0e-5) {
     380            0 :                 ThetaSurf = std::atan2(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec.y,
     381            0 :                                        state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec.x);
     382              :             } else {
     383            0 :                 ThetaSurf = 0.0;
     384              :             }
     385            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PhiNormVec = PhiSurf;
     386            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).ThetaNormVec = ThetaSurf;
     387            0 :             PhiMin = max(-Constant::PiOvr2, PhiSurf - Constant::PiOvr2);
     388            0 :             PhiMax = min(Constant::PiOvr2, PhiSurf + Constant::PiOvr2);
     389            0 :             DPhi = (PhiMax - PhiMin) / AltAngStepsForSolReflCalc;
     390            0 :             RayNum = 0;
     391              : 
     392              :             // Altitude loop
     393            0 :             for (IPhi = 1; IPhi <= AltAngStepsForSolReflCalc; ++IPhi) {
     394            0 :                 Phi = PhiMin + (IPhi - 0.5) * DPhi;
     395            0 :                 SPhi = std::sin(Phi);
     396            0 :                 CPhi = std::cos(Phi);
     397              :                 // Third component of ray unit vector in (Theta,Phi) direction
     398            0 :                 URay(3) = SPhi;
     399              : 
     400            0 :                 if (PhiSurf >= 0.0) {
     401            0 :                     if (Phi >= Constant::PiOvr2 - PhiSurf) {
     402            0 :                         ThetaMin = -Constant::Pi;
     403            0 :                         ThetaMax = Constant::Pi;
     404              :                     } else {
     405            0 :                         ACosTanTan = std::acos(-std::tan(Phi) * tan_PhiSurf);
     406            0 :                         ThetaMin = ThetaSurf - std::abs(ACosTanTan);
     407            0 :                         ThetaMax = ThetaSurf + std::abs(ACosTanTan);
     408              :                     }
     409              : 
     410              :                 } else { // PhiSurf < 0.0
     411            0 :                     if (Phi <= -PhiSurf - Constant::PiOvr2) {
     412            0 :                         ThetaMin = -Constant::Pi;
     413            0 :                         ThetaMax = Constant::Pi;
     414              :                     } else {
     415            0 :                         ACosTanTan = std::acos(-std::tan(Phi) * tan_PhiSurf);
     416            0 :                         ThetaMin = ThetaSurf - std::abs(ACosTanTan);
     417            0 :                         ThetaMax = ThetaSurf + std::abs(ACosTanTan);
     418              :                     }
     419              :                 }
     420              : 
     421            0 :                 DTheta = (ThetaMax - ThetaMin) / AzimAngStepsForSolReflCalc;
     422            0 :                 dOmega = CPhi * DTheta * DPhi;
     423              : 
     424              :                 // Azimuth loop
     425            0 :                 for (ITheta = 1; ITheta <= AzimAngStepsForSolReflCalc; ++ITheta) {
     426            0 :                     Theta = ThetaMin + (ITheta - 0.5) * DTheta;
     427            0 :                     URay.x = CPhi * std::cos(Theta);
     428            0 :                     URay.y = CPhi * std::sin(Theta);
     429              :                     // Cosine of angle of incidence of ray on receiving surface
     430            0 :                     CosIncAngRay = SPhi * sin_PhiSurf + CPhi * cos_PhiSurf * std::cos(Theta - ThetaSurf);
     431            0 :                     if (CosIncAngRay < 0.0) continue; // Ray is behind receiving surface (although there shouldn't be any)
     432            0 :                     ++RayNum;
     433            0 :                     state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RayVec(RayNum) = URay;
     434            0 :                     state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).CosIncAngRay(RayNum) = CosIncAngRay;
     435            0 :                     state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).dOmegaRay(RayNum) = dOmega;
     436              :                 } // End of azimuth loop
     437              : 
     438              :             } // End of altitude loop
     439            0 :             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumReflRays = RayNum;
     440              : 
     441              :         } // End of loop over receiving surfaces
     442              : 
     443              :         // Loop again over receiving surfaces and, for each ray, get hit point and info associated with that point
     444              :         // (hit point = point that ray intersects nearest obstruction, or, if ray is downgoing and hits no
     445              :         // obstructions, point that ray intersects ground plane).
     446              : 
     447            0 :         for (RecSurfNum = 1; RecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf; ++RecSurfNum) {
     448            0 :             SurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).SurfNum;
     449            0 :             for (RecPtNum = 1; RecPtNum <= state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumRecPts; ++RecPtNum) {
     450            0 :                 RecPt = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(RecPtNum);
     451            0 :                 for (RayNum = 1; RayNum <= state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumReflRays; ++RayNum) {
     452              :                     // Loop over possible obstructions. If ray hits one or more obstructions get hit point on closest obstruction.
     453              :                     // If ray hits no obstructions and is going upward set HitPointSurfNum = 0.
     454              :                     // If ray hits no obstructions and is going downward set HitPointSurfNum = -1 and get hit point on ground.
     455            0 :                     TotObstructionsHit = 0;
     456            0 :                     NearestHitSurfNum = 0;
     457            0 :                     NearestHitDistance = 1.0e+8;
     458            0 :                     ObsSurfNumToSkip = 0;
     459            0 :                     RayVec = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RayVec(RayNum);
     460            0 :                     for (loop1 = 1; loop1 <= state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs; ++loop1) {
     461              :                         // Surface number of this obstruction
     462            0 :                         ObsSurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop1);
     463              :                         // If a window was hit previously (see below), ObsSurfNumToSkip was set to the window's base surface in order
     464              :                         // to remove that surface from consideration as a hit surface for this ray
     465            0 :                         if (ObsSurfNum == ObsSurfNumToSkip) continue;
     466              :                         // Determine if this ray hits ObsSurfNum (in which case hit is true) and, if so, what the
     467              :                         // distance from the receiving point to the hit point is
     468            0 :                         hit = PierceSurface(state, ObsSurfNum, RecPt, RayVec, HitPt);
     469            0 :                         if (hit) {
     470              :                             // added TH 3/29/2010 to set ObsSurfNumToSkip
     471            0 :                             if (state.dataSurface->Surface(ObsSurfNum).Class == SurfaceClass::Window) {
     472            0 :                                 ObsSurfNumToSkip = state.dataSurface->Surface(ObsSurfNum).BaseSurf;
     473              :                             }
     474              : 
     475              :                             // If obstruction is a window and its base surface is the nearest obstruction hit so far,
     476              :                             // set NearestHitSurfNum to this window. Note that in this case NearestHitDistance has already
     477              :                             // been calculated, so does not have to be recalculated.
     478            0 :                             if (state.dataSurface->Surface(ObsSurfNum).Class == SurfaceClass::Window &&
     479            0 :                                 state.dataSurface->Surface(ObsSurfNum).BaseSurf == NearestHitSurfNum) {
     480            0 :                                 NearestHitSurfNum = ObsSurfNum;
     481              :                             } else {
     482            0 :                                 ++TotObstructionsHit;
     483              :                                 // Distance from receiving point to hit point
     484            0 :                                 HitDistance = distance(HitPt, RecPt);
     485              :                                 // Reset NearestHitSurfNum and NearestHitDistance if this hit point is closer than previous closest
     486            0 :                                 if (HitDistance < NearestHitDistance) {
     487            0 :                                     NearestHitDistance = HitDistance;
     488            0 :                                     NearestHitSurfNum = ObsSurfNum;
     489            0 :                                     NearestHitPt = HitPt;
     490            0 :                                 } else if (HitDistance == NearestHitDistance) { // TH2 CR8959
     491              :                                     // Ray hits mirrored surfaces. Choose the surface facing the ray.
     492            0 :                                     if (dot(state.dataSurface->Surface(ObsSurfNum).OutNormVec, RayVec) <= 0.0) {
     493            0 :                                         NearestHitSurfNum = ObsSurfNum;
     494              :                                     }
     495              :                                 }
     496              :                             }
     497              :                         } // End of check if obstruction was hit
     498              :                     }     // End of loop over possible obstructions for this ray
     499              : 
     500            0 :                     if (TotObstructionsHit > 0) {
     501              :                         // One or more obstructions were hit by this ray
     502            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSurfNum(RayNum, RecPtNum) = NearestHitSurfNum;
     503            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPtHitPtDis(RayNum, RecPtNum) = NearestHitDistance;
     504            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPt(RayNum, RecPtNum) = NearestHitPt;
     505              :                         // For hit surface, calculate unit normal vector pointing into the hemisphere
     506              :                         // containing the receiving point
     507            0 :                         Vec1 = (state.dataSurface->Surface(NearestHitSurfNum).Vertex(1) - state.dataSurface->Surface(NearestHitSurfNum).Vertex(3));
     508            0 :                         Vec2 = (state.dataSurface->Surface(NearestHitSurfNum).Vertex(2) - state.dataSurface->Surface(NearestHitSurfNum).Vertex(3));
     509            0 :                         VNorm = cross(Vec1, Vec2);
     510            0 :                         VNorm.normalize(); // Do Handle magnitude==0
     511            0 :                         if (dot(VNorm, -RayVec) < 0.0) VNorm = -VNorm;
     512            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtNormVec(RayNum, RecPtNum) = VNorm;
     513              :                         // Get solar and visible beam-to-diffuse reflectance at nearest hit point
     514            0 :                         ObsConstrNum = state.dataSurface->Surface(NearestHitSurfNum).Construction;
     515            0 :                         if (ObsConstrNum > 0) {
     516              :                             // Exterior building surface is nearest hit
     517            0 :                             if (!state.dataConstruction->Construct(ObsConstrNum).TypeIsWindow) {
     518              :                                 // Obstruction is not a window, i.e., is an opaque surface
     519            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSolRefl(RayNum, RecPtNum) =
     520            0 :                                     1.0 - state.dataConstruction->Construct(ObsConstrNum).OutsideAbsorpSolar;
     521              :                             } else {
     522              :                                 // Obstruction is a window. Assume it is bare so that there is no beam-to-diffuse reflection
     523              :                                 // (beam-to-beam reflection is calculated in subroutine CalcBeamSolSpecularReflFactors).
     524            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSolRefl(RayNum, RecPtNum) = 0.0;
     525              :                             }
     526              :                         } else {
     527              :                             // Shading surface is nearest hit
     528            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSolRefl(RayNum, RecPtNum) =
     529            0 :                                 state.dataSurface->SurfShadowDiffuseSolRefl(NearestHitSurfNum);
     530              :                         }
     531              :                     } else {
     532              :                         // No obstructions were hit by this ray
     533            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSurfNum(RayNum, RecPtNum) = 0;
     534              :                         // If ray is going downward find the hit point on the ground plane if the receiving point
     535              :                         // is above ground level; note that GroundLevelZ is <= 0.0
     536            0 :                         if (RayVec(3) < 0.0 &&
     537            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(RecPtNum).z > state.dataSurface->GroundLevelZ) {
     538              :                             // Ray hits ground
     539            0 :                             Alfa = std::acos(-RayVec.z);
     540            0 :                             Beta = std::atan2(RayVec.y, RayVec.x);
     541            0 :                             HorDis = (RecPt.z - state.dataSurface->GroundLevelZ) * std::tan(Alfa);
     542            0 :                             GroundHitPt.z = state.dataSurface->GroundLevelZ;
     543            0 :                             GroundHitPt.x = RecPt.x + HorDis * std::cos(Beta);
     544            0 :                             GroundHitPt.y = RecPt.y + HorDis * std::sin(Beta);
     545            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPt(RayNum, RecPtNum) = GroundHitPt;
     546            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSurfNum(RayNum, RecPtNum) = -1;
     547            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPtHitPtDis(RayNum, RecPtNum) =
     548            0 :                                 (RecPt(3) - state.dataSurface->GroundLevelZ) / (-RayVec(3));
     549            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtSolRefl(RayNum, RecPtNum) =
     550            0 :                                 state.dataEnvrn->GndReflectance;
     551            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).HitPtNormVec(RayNum, RecPtNum) = unit_z;
     552              :                         } // End of check if ray hits ground
     553              :                     }     // End of check if obstruction hit
     554              :                 }         // End of RayNum loop
     555              :             }             // End of receiving point loop
     556              :         }                 // End of receiving surface loop
     557            0 :     }
     558              : 
     559              :     //=====================================================================================================
     560              : 
     561            0 :     void CalcBeamSolDiffuseReflFactors(EnergyPlusData &state)
     562              :     {
     563              : 
     564              :         // SUBROUTINE INFORMATION:
     565              :         //       AUTHOR         Fred Winkelmann
     566              :         //       DATE WRITTEN   September 2003
     567              :         //       MODIFIED       TH 4/6/2010, fixed CR 7872
     568              :         //       RE-ENGINEERED  B. Griffith, October 2012, for timestep integrated solar.
     569              : 
     570              :         // PURPOSE OF THIS SUBROUTINE:
     571              :         // manage calculations for factors for irradiance on exterior heat transfer surfaces due to
     572              :         // beam-to-diffuse solar reflection from obstructions and ground.
     573              : 
     574              :         // METHODOLOGY EMPLOYED: call worker routine depending on solar calculation method
     575              : 
     576            0 :         if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
     577            0 :             if (state.dataGlobal->BeginSimFlag) {
     578            0 :                 DisplayString(state, "Calculating Beam-to-Diffuse Exterior Solar Reflection Factors");
     579              :             } else {
     580            0 :                 DisplayString(state, "Updating Beam-to-Diffuse Exterior Solar Reflection Factors");
     581              :             }
     582            0 :             state.dataSurface->SurfReflFacBmToDiffSolObs = 0.0;
     583            0 :             state.dataSurface->SurfReflFacBmToDiffSolGnd = 0.0;
     584            0 :             for (state.dataSolarReflectionManager->IHr = 1; state.dataSolarReflectionManager->IHr <= 24; ++state.dataSolarReflectionManager->IHr) {
     585            0 :                 FigureBeamSolDiffuseReflFactors(state, state.dataSolarReflectionManager->IHr);
     586              :             }    // End of IHr loop
     587              :         } else { // timestep integrated solar, use current hour of day
     588            0 :             state.dataSurface->SurfReflFacBmToDiffSolObs(state.dataGlobal->HourOfDay, {1, state.dataSurface->TotSurfaces}) = 0.0;
     589            0 :             state.dataSurface->SurfReflFacBmToDiffSolGnd(state.dataGlobal->HourOfDay, {1, state.dataSurface->TotSurfaces}) = 0.0;
     590            0 :             FigureBeamSolDiffuseReflFactors(state, state.dataGlobal->HourOfDay);
     591              :         }
     592            0 :     }
     593              : 
     594            0 :     void FigureBeamSolDiffuseReflFactors(EnergyPlusData &state, int const iHour)
     595              :     {
     596              : 
     597              :         // SUBROUTINE INFORMATION:
     598              :         //       AUTHOR         Fred Winkelmann, derived from original CalcBeamSolDiffuseReflFactors
     599              :         //       DATE WRITTEN   September 2003
     600              :         //       MODIFIED       na
     601              :         //       RE-ENGINEERED  B. Griffith, October 2012, revised for timestep integrated solar
     602              : 
     603              :         // PURPOSE OF THIS SUBROUTINE:
     604              :         // Calculates factors for irradiance on exterior heat transfer surfaces due to
     605              :         // beam-to-diffuse solar reflection from obstructions and ground.
     606              : 
     607            0 :         Array1D<Real64> ReflBmToDiffSolObs(state.dataSurface->MaxRecPts); // Irradiance at a receiving point for
     608              :         // beam solar diffusely reflected from obstructions, divided by
     609              :         // beam normal irradiance
     610            0 :         Array1D<Real64> ReflBmToDiffSolGnd(state.dataSurface->MaxRecPts); // Irradiance at a receiving point for
     611              :         // beam solar diffusely reflected from the ground, divided by
     612              :         // beam normal irradiance
     613              :         bool hit; // True iff obstruction is hit
     614            0 :         ReflBmToDiffSolObs = 0.0;
     615            0 :         ReflBmToDiffSolGnd = 0.0;
     616              : 
     617              :         // Unit vector to sun
     618            0 :         state.dataSolarReflectionManager->SunVec = state.dataSurface->SurfSunCosHourly(iHour);
     619              : 
     620              :         // loop through each surface that can receive beam solar reflected as diffuse solar from other surfaces
     621            0 :         for (state.dataSolarReflectionManager->RecSurfNum = 1;
     622            0 :              state.dataSolarReflectionManager->RecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf;
     623            0 :              ++state.dataSolarReflectionManager->RecSurfNum) {
     624            0 :             state.dataSolarReflectionManager->SurfNum =
     625            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum).SurfNum;
     626              : 
     627            0 :             for (state.dataSolarReflectionManager->RecPtNum = 1;
     628            0 :                  state.dataSolarReflectionManager->RecPtNum <=
     629            0 :                  state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum).NumRecPts;
     630            0 :                  ++state.dataSolarReflectionManager->RecPtNum) {
     631            0 :                 ReflBmToDiffSolObs(state.dataSolarReflectionManager->RecPtNum) = 0.0;
     632            0 :                 ReflBmToDiffSolGnd(state.dataSolarReflectionManager->RecPtNum) = 0.0;
     633              : 
     634            0 :                 for (state.dataSolarReflectionManager->RayNum = 1;
     635            0 :                      state.dataSolarReflectionManager->RayNum <=
     636            0 :                      state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum).NumReflRays;
     637            0 :                      ++state.dataSolarReflectionManager->RayNum) {
     638            0 :                     state.dataSolarReflectionManager->HitPtSurfNum =
     639            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     640            0 :                             .HitPtSurfNum(state.dataSolarReflectionManager->RayNum, state.dataSolarReflectionManager->RecPtNum);
     641              : 
     642              :                     // Skip rays that do not hit an obstruction or ground.
     643              :                     // (Note that if a downgoing ray does not hit an obstruction it will have HitPtSurfNum = 0
     644              :                     // if the receiving point is below ground level (see subr. InitSolReflRecSurf); this means
     645              :                     // that a below-ground-level receiving point receives no ground-reflected radiation although
     646              :                     // it is allowed to receive obstruction-reflected solar radiation and direct (unreflected)
     647              :                     // beam and sky solar radiation. As far as reflected solar is concerned, the program does
     648              :                     // not handle a sloped ground plane or a horizontal ground plane whose level is different
     649              :                     // from one side of the building to another.)
     650            0 :                     if (state.dataSolarReflectionManager->HitPtSurfNum == 0)
     651            0 :                         continue; // Ray hits sky or obstruction with receiving pt. below ground level
     652              : 
     653            0 :                     if (state.dataSolarReflectionManager->HitPtSurfNum > 0) {
     654              :                         // Skip rays that hit a daylighting shelf, from which solar reflection is calculated separately.
     655            0 :                         if (state.dataSurface->SurfDaylightingShelfInd(state.dataSolarReflectionManager->HitPtSurfNum) > 0) continue;
     656              : 
     657              :                         // Skip rays that hit a window
     658              :                         // If hit point's surface is a window or glass door go to next ray since it is assumed for now
     659              :                         // that windows have only beam-to-beam, not beam-to-diffuse, reflection
     660              :                         // TH 3/29/2010. Code modified and moved
     661            0 :                         if (state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum).Class == SurfaceClass::Window ||
     662            0 :                             state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum).Class == SurfaceClass::GlassDoor)
     663            0 :                             continue;
     664              : 
     665              :                         // Skip rays that hit non-sunlit surface. Assume first time step of the hour.
     666            0 :                         state.dataSolarReflectionManager->SunLitFract =
     667            0 :                             state.dataHeatBal->SurfSunlitFrac(iHour, 1, state.dataSolarReflectionManager->HitPtSurfNum);
     668              : 
     669              :                         // If hit point's surface is not sunlit go to next ray
     670              :                         // TH 3/25/2010. why limit to HeatTransSurf? shading surfaces should also apply
     671              :                         // IF(Surface(HitPtSurfNum)%HeatTransSurf .AND. SunLitFract < 0.01d0) CYCLE
     672            0 :                         if (state.dataSolarReflectionManager->SunLitFract < 0.01) continue;
     673              : 
     674              :                         // TH 3/26/2010. If the hit point falls into the shadow even though SunLitFract > 0, can Cycle.
     675              :                         //  This cannot be done now, therefore there are follow-up checks of blocking sun ray
     676              :                         //   from the hit point.
     677              : 
     678              :                         // TH 3/29/2010. Code modified and moved up
     679              :                         // If hit point's surface is a window go to next ray since it is assumed for now
     680              :                         // that windows have only beam-to-beam, not beam-to-diffuse, reflection
     681              :                         // IF(Surface(HitPtSurfNum)%Construction > 0) THEN
     682              :                         //  IF(Construct(Surface(HitPtSurfNum)%Construction)%TypeIsWindow) CYCLE
     683              :                         // END IF
     684              :                     }
     685              : 
     686              :                     // Does an obstruction block the vector from this ray's hit point to the sun?
     687            0 :                     state.dataSolarReflectionManager->OriginThisRay =
     688            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     689            0 :                             .HitPt(state.dataSolarReflectionManager->RayNum, state.dataSolarReflectionManager->RecPtNum);
     690              : 
     691              :                     // Note: if sun is in back of hit surface relative to receiving point, CosIncBmAtHitPt will be < 0
     692            0 :                     state.dataSolarReflectionManager->CosIncBmAtHitPt =
     693            0 :                         dot(state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     694            0 :                                 .HitPtNormVec(state.dataSolarReflectionManager->RayNum, state.dataSolarReflectionManager->RecPtNum),
     695            0 :                             state.dataSolarReflectionManager->SunVec);
     696            0 :                     if (state.dataSolarReflectionManager->CosIncBmAtHitPt <= 0.0) continue;
     697              : 
     698              :                     // CR 7872 - TH 4/6/2010. The shading surfaces should point to the receiveing heat transfer surface
     699              :                     //  according to the the right hand rule. If user inputs do not follow the rule, use the following
     700              :                     //  code to check the mirrored shading surface
     701            0 :                     if (state.dataSolarReflectionManager->HitPtSurfNum > 0) {
     702            0 :                         if (state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum).IsShadowing) {
     703            0 :                             if (state.dataSolarReflectionManager->HitPtSurfNum + 1 < state.dataSurface->TotSurfaces) {
     704            0 :                                 if (state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum + 1).IsShadowing &&
     705            0 :                                     state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum + 1).MirroredSurf) {
     706              :                                     // Check whether the sun is behind the mirrored shading surface
     707            0 :                                     state.dataSolarReflectionManager->CosIncBmAtHitPt2 =
     708            0 :                                         dot(state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum + 1).OutNormVec,
     709            0 :                                             state.dataSolarReflectionManager->SunVec);
     710            0 :                                     if (state.dataSolarReflectionManager->CosIncBmAtHitPt2 >= 0.0) continue;
     711              :                                 }
     712              :                             }
     713              :                         }
     714              :                     }
     715              : 
     716              :                     // TH 3/25/2010. CR 7872. Seems should loop over all possible obstructions for the HitPtSurfNum
     717              :                     //  rather than RecSurfNum, because if the HitPtSurfNum is a shading surface,
     718              :                     //  it does not belong to SolReflRecSurf which only contain heat transfer surfaces
     719              :                     //  that can receive reflected solar (ExtSolar = True)!
     720              : 
     721              :                     // To speed up, ideally should store all possible shading surfaces for the HitPtSurfNum
     722              :                     //  obstruction surface in the SolReflSurf(HitPtSurfNum)%PossibleObsSurfNums(loop) array as well
     723            0 :                     hit = false;
     724            0 :                     for (state.dataSolarReflectionManager->ObsSurfNum = 1;
     725            0 :                          state.dataSolarReflectionManager->ObsSurfNum <= state.dataSurface->TotSurfaces;
     726            0 :                          ++state.dataSolarReflectionManager->ObsSurfNum) {
     727              :                         //        DO loop = 1,SolReflRecSurf(RecSurfNum)%NumPossibleObs
     728              :                         //          ObsSurfNum = SolReflRecSurf(RecSurfNum)%PossibleObsSurfNums(loop)
     729              : 
     730              :                         // CR 8959 -- The other side of a mirrored surface cannot obstruct the mirrored surface
     731            0 :                         if (state.dataSolarReflectionManager->HitPtSurfNum > 0) {
     732            0 :                             if (state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNum).MirroredSurf) {
     733            0 :                                 if (state.dataSolarReflectionManager->ObsSurfNum == state.dataSolarReflectionManager->HitPtSurfNum - 1) continue;
     734              :                             }
     735              :                         }
     736              : 
     737              :                         // skip the hit surface
     738            0 :                         if (state.dataSolarReflectionManager->ObsSurfNum == state.dataSolarReflectionManager->HitPtSurfNum) continue;
     739              : 
     740              :                         // skip mirrored surfaces
     741            0 :                         if (state.dataSurface->Surface(state.dataSolarReflectionManager->ObsSurfNum).MirroredSurf) continue;
     742              :                         // IF(Surface(ObsSurfNum)%ShadowingSurf .AND. Surface(ObsSurfNum)%Name(1:3) == 'Mir') THEN
     743              :                         //  CYCLE
     744              :                         // ENDIF
     745              : 
     746              :                         // skip interior surfaces
     747            0 :                         if (state.dataSurface->Surface(state.dataSolarReflectionManager->ObsSurfNum).ExtBoundCond >= 1) continue;
     748              : 
     749              :                         // For now it is assumed that obstructions that are shading surfaces are opaque.
     750              :                         // An improvement here would be to allow these to have transmittance.
     751            0 :                         hit = PierceSurface(state,
     752            0 :                                             state.dataSolarReflectionManager->ObsSurfNum,
     753            0 :                                             state.dataSolarReflectionManager->OriginThisRay,
     754            0 :                                             state.dataSolarReflectionManager->SunVec,
     755            0 :                                             state.dataSolarReflectionManager->ObsHitPt);
     756            0 :                         if (hit) break; // An obstruction was hit
     757              :                     }
     758            0 :                     if (hit) continue; // Sun does not reach this ray's hit point
     759              : 
     760              :                     // Sun reaches this ray's hit point; get beam-reflected diffuse radiance at hit point for
     761              :                     // unit beam normal solar
     762              : 
     763              :                     // CosIncBmAtHitPt = DOT_PRODUCT(SolReflRecSurf(RecSurfNum)%HitPtNormVec(RecPtNum,RayNum),SunVec)
     764              :                     // Note: if sun is in back of hit surface relative to receiving point, CosIncBmAtHitPt will be < 0
     765              :                     // and use of MAX in following gives zero beam solar reflecting at hit point.
     766              :                     // BmReflSolRadiance = MAX(0.0d0,CosIncBmAtHitPt)*SolReflRecSurf(RecSurfNum)%HitPtSolRefl(RecPtNum,RayNum)
     767              : 
     768            0 :                     state.dataSolarReflectionManager->BmReflSolRadiance =
     769            0 :                         state.dataSolarReflectionManager->CosIncBmAtHitPt *
     770            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     771            0 :                             .HitPtSolRefl(state.dataSolarReflectionManager->RayNum, state.dataSolarReflectionManager->RecPtNum);
     772              : 
     773            0 :                     if (state.dataSolarReflectionManager->BmReflSolRadiance > 0.0) {
     774              :                         // Contribution to reflection factor from this hit point
     775            0 :                         if (state.dataSolarReflectionManager->HitPtSurfNum > 0) {
     776              :                             // Ray hits an obstruction
     777            0 :                             state.dataSolarReflectionManager->dReflBeamToDiffSol =
     778            0 :                                 state.dataSolarReflectionManager->BmReflSolRadiance *
     779            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     780            0 :                                     .dOmegaRay(state.dataSolarReflectionManager->RayNum) *
     781            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     782            0 :                                     .CosIncAngRay(state.dataSolarReflectionManager->RayNum) /
     783              :                                 Constant::Pi;
     784            0 :                             ReflBmToDiffSolObs(state.dataSolarReflectionManager->RecPtNum) += state.dataSolarReflectionManager->dReflBeamToDiffSol;
     785              :                         } else {
     786              :                             // Ray hits ground (in this case we do not multiply by BmReflSolRadiance since
     787              :                             // ground reflectance and cos of incidence angle of sun on
     788              :                             // ground is taken into account later when SurfReflFacBmToDiffSolGnd is used)
     789            0 :                             state.dataSolarReflectionManager->dReflBeamToDiffSol =
     790            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     791            0 :                                     .dOmegaRay(state.dataSolarReflectionManager->RayNum) *
     792            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum)
     793            0 :                                     .CosIncAngRay(state.dataSolarReflectionManager->RayNum) /
     794              :                                 Constant::Pi;
     795            0 :                             ReflBmToDiffSolGnd(state.dataSolarReflectionManager->RecPtNum) += state.dataSolarReflectionManager->dReflBeamToDiffSol;
     796              :                         }
     797              :                     }
     798              :                 } // End of loop over rays from receiving point
     799              :             }     // End of loop over receiving points
     800              : 
     801              :             // Average over receiving points
     802            0 :             state.dataSurface->SurfReflFacBmToDiffSolObs(iHour, state.dataSolarReflectionManager->SurfNum) = 0.0;
     803            0 :             state.dataSurface->SurfReflFacBmToDiffSolGnd(iHour, state.dataSolarReflectionManager->SurfNum) = 0.0;
     804            0 :             state.dataSolarReflectionManager->NumRecPts =
     805            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->RecSurfNum).NumRecPts;
     806            0 :             for (state.dataSolarReflectionManager->RecPtNum = 1;
     807            0 :                  state.dataSolarReflectionManager->RecPtNum <= state.dataSolarReflectionManager->NumRecPts;
     808            0 :                  ++state.dataSolarReflectionManager->RecPtNum) {
     809            0 :                 state.dataSurface->SurfReflFacBmToDiffSolObs(iHour, state.dataSolarReflectionManager->SurfNum) +=
     810            0 :                     ReflBmToDiffSolObs(state.dataSolarReflectionManager->RecPtNum);
     811            0 :                 state.dataSurface->SurfReflFacBmToDiffSolGnd(iHour, state.dataSolarReflectionManager->SurfNum) +=
     812            0 :                     ReflBmToDiffSolGnd(state.dataSolarReflectionManager->RecPtNum);
     813              :             }
     814            0 :             state.dataSurface->SurfReflFacBmToDiffSolObs(iHour, state.dataSolarReflectionManager->SurfNum) /=
     815            0 :                 state.dataSolarReflectionManager->NumRecPts;
     816            0 :             state.dataSurface->SurfReflFacBmToDiffSolGnd(iHour, state.dataSolarReflectionManager->SurfNum) /=
     817            0 :                 state.dataSolarReflectionManager->NumRecPts;
     818              : 
     819              :             // Do not allow SurfReflFacBmToDiffSolGnd to exceed the surface's unobstructed ground view factor
     820            0 :             state.dataSurface->SurfReflFacBmToDiffSolGnd(iHour, state.dataSolarReflectionManager->SurfNum) =
     821            0 :                 min(0.5 * (1.0 - state.dataSurface->Surface(state.dataSolarReflectionManager->SurfNum).CosTilt),
     822            0 :                     state.dataSurface->SurfReflFacBmToDiffSolGnd(iHour, state.dataSolarReflectionManager->SurfNum));
     823              :             // Note: the above factors are dimensionless; they are equal to
     824              :             // (W/m2 reflected solar incident on SurfNum)/(W/m2 beam normal solar)
     825              :         } // End of loop over receiving surfaces
     826            0 :     }
     827              : 
     828              :     //=================================================================================================
     829              : 
     830            0 :     void CalcBeamSolSpecularReflFactors(EnergyPlusData &state)
     831              :     {
     832              : 
     833              :         // SUBROUTINE INFORMATION:
     834              :         //       AUTHOR         Fred Winkelmann
     835              :         //       DATE WRITTEN   September 2003
     836              :         //       MODIFIED       na
     837              :         //       RE-ENGINEERED  B. Griffith, October 2012, for timestep integrated solar
     838              : 
     839              :         // PURPOSE OF THIS SUBROUTINE:
     840              :         // Manage calculation of factors for beam solar irradiance on exterior heat transfer surfaces due to
     841              :         // specular (beam-to-beam) reflection from obstructions such as a highly-glazed neighboring
     842              :         // building.
     843              : 
     844              :         // METHODOLOGY EMPLOYED:
     845              :         // call worker routine as appropriate
     846              : 
     847            0 :         if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
     848            0 :             if (state.dataGlobal->BeginSimFlag) {
     849            0 :                 DisplayString(state, "Calculating Beam-to-Beam Exterior Solar Reflection Factors");
     850              :             } else {
     851            0 :                 DisplayString(state, "Updating Beam-to-Beam Exterior Solar Reflection Factors");
     852              :             }
     853            0 :             state.dataSurface->SurfReflFacBmToBmSolObs = 0.0;
     854            0 :             state.dataSurface->SurfCosIncAveBmToBmSolObs = 0.0;
     855            0 :             for (state.dataSolarReflectionManager->NumHr = 1; state.dataSolarReflectionManager->NumHr <= 24;
     856            0 :                  ++state.dataSolarReflectionManager->NumHr) {
     857            0 :                 FigureBeamSolSpecularReflFactors(state, state.dataSolarReflectionManager->NumHr);
     858              :             }    // End of NumHr loop
     859              :         } else { // timestep integrated solar, use current hour of day
     860            0 :             state.dataSurface->SurfReflFacBmToBmSolObs(state.dataGlobal->HourOfDay, {1, state.dataSurface->TotSurfaces}) = 0.0;
     861            0 :             state.dataSurface->SurfCosIncAveBmToBmSolObs(state.dataGlobal->HourOfDay, {1, state.dataSurface->TotSurfaces}) = 0.0;
     862            0 :             FigureBeamSolSpecularReflFactors(state, state.dataGlobal->HourOfDay);
     863              :         }
     864            0 :     }
     865              : 
     866            0 :     void FigureBeamSolSpecularReflFactors(EnergyPlusData &state, int const iHour)
     867              :     {
     868              : 
     869              :         // SUBROUTINE INFORMATION:
     870              :         //       AUTHOR         Fred Winkelmann
     871              :         //       DATE WRITTEN   September 2003
     872              :         //       MODIFIED       na
     873              :         //       RE-ENGINEERED  B. Griffith, October 2012, for timestep integrated solar
     874              : 
     875              :         // PURPOSE OF THIS SUBROUTINE:
     876              :         // Calculates factors for beam solar irradiance on exterior heat transfer surfaces due to
     877              :         // specular (beam-to-beam) reflection from obstructions such as a highly-glazed neighboring
     878              :         // building. Specular reflection can occur from shading surfaces with non-zero specular
     879              :         // reflectance and from exterior windows of the building (in calculating reflection from
     880              :         // these windows, they are assumed to have no shades or blinds).
     881              :         // Reflection from the ground and opaque building surfaces is assumed to be totally diffuse,
     882              :         // i.e. these surfaces has no specular reflection component.
     883              : 
     884              :         // METHODOLOGY EMPLOYED:
     885              :         // <description>
     886              : 
     887              :         // REFERENCES:
     888              :         // na
     889              : 
     890              :         // Locals
     891              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     892            0 :         Array1D<Real64> ReflBmToDiffSolObs(state.dataSurface->MaxRecPts); // Irradiance at a receiving point for
     893              :         // beam solar diffusely reflected from obstructions, divided by
     894              :         // beam normal irradiance
     895              :         // unused  INTEGER           :: RayNum               =0   ! Ray number
     896              :         bool hitRefl;                                                   // True iff reflecting surface is hit
     897              :         bool hitObs;                                                    // True iff obstruction is hit
     898              :         bool hitObsRefl;                                                // True iff obstruction hit between rec. pt. and reflection point
     899            0 :         Array1D<Real64> ReflBmToBmSolObs(state.dataSurface->MaxRecPts); // Irradiance at a receiving point for
     900              :         // beam solar specularly reflected from obstructions, divided by
     901              :         // beam normal irradiance
     902              :         Real64 ReflDistanceSq; // Distance squared from receiving point to hit point on a reflecting surface (m)
     903              :         Real64 ReflDistance;   // Distance from receiving point to hit point on a reflecting surface (m)
     904            0 :         Array1D<Real64> ReflFacTimesCosIncSum(state.dataSurface->MaxRecPts); // Sum of ReflFac times CosIncAngRefl
     905              : 
     906            0 :         ReflBmToDiffSolObs = 0.0;
     907            0 :         ReflFacTimesCosIncSum = 0.0;
     908              : 
     909            0 :         if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return; // Skip if sun is below horizon
     910              : 
     911              :         // Unit vector to sun
     912            0 :         state.dataSolarReflectionManager->SunVect = state.dataSurface->SurfSunCosHourly(iHour);
     913              : 
     914            0 :         for (int RecSurfNum = 1; RecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf; ++RecSurfNum) {
     915              :             int const SurfNum =
     916            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).SurfNum; // Heat transfer surface number corresponding to RecSurfNum
     917            0 :             if (state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs > 0) {
     918            0 :                 ReflBmToBmSolObs = 0.0;
     919            0 :                 ReflFacTimesCosIncSum = 0.0;
     920            0 :                 int const NumRecPts = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumRecPts;
     921              :                 // Find possible reflecting surfaces for this receiving surface
     922            0 :                 for (int loop = 1, loop_end = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs; loop <= loop_end; ++loop) {
     923              :                     int const ReflSurfNum =
     924            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop); // Reflecting surface number
     925              :                     // Keep windows; keep shading surfaces with specular reflectance
     926            0 :                     if ((state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window && state.dataSurface->Surface(ReflSurfNum).ExtSolar) ||
     927            0 :                         (state.dataSurface->SurfShadowGlazingFrac(ReflSurfNum) > 0.0 && state.dataSurface->Surface(ReflSurfNum).IsShadowing)) {
     928              :                         // Skip if window and not sunlit
     929            0 :                         if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window &&
     930            0 :                             state.dataHeatBal->SurfSunlitFrac(iHour, 1, ReflSurfNum) < 0.01)
     931            0 :                             continue;
     932              :                         // Check if sun is in front of this reflecting surface.
     933            0 :                         state.dataSolarReflectionManager->ReflNorm = state.dataSurface->Surface(ReflSurfNum).OutNormVec;
     934            0 :                         state.dataSolarReflectionManager->CosIncAngRefl =
     935            0 :                             dot(state.dataSolarReflectionManager->SunVect, state.dataSolarReflectionManager->ReflNorm);
     936            0 :                         if (state.dataSolarReflectionManager->CosIncAngRefl < 0.0) continue;
     937              : 
     938              :                         // Get sun position unit vector for mirror image of sun in reflecting surface
     939            0 :                         state.dataSolarReflectionManager->SunVecMir =
     940            0 :                             state.dataSolarReflectionManager->SunVect -
     941            0 :                             2.0 * dot(state.dataSolarReflectionManager->SunVect, state.dataSolarReflectionManager->ReflNorm) *
     942            0 :                                 state.dataSolarReflectionManager->ReflNorm;
     943              :                         // Angle of incidence of reflected beam on receiving surface
     944            0 :                         state.dataSolarReflectionManager->CosIncAngRec =
     945            0 :                             dot(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec, state.dataSolarReflectionManager->SunVecMir);
     946            0 :                         if (state.dataSolarReflectionManager->CosIncAngRec <= 0.0) continue;
     947            0 :                         for (int RecPtNum = 1; RecPtNum <= NumRecPts; ++RecPtNum) {
     948              :                             // See if ray from receiving point to mirrored sun hits the reflecting surface
     949            0 :                             state.dataSolarReflectionManager->RecPt = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).RecPt(RecPtNum);
     950            0 :                             hitRefl = PierceSurface(state,
     951              :                                                     ReflSurfNum,
     952            0 :                                                     state.dataSolarReflectionManager->RecPt,
     953            0 :                                                     state.dataSolarReflectionManager->SunVecMir,
     954            0 :                                                     state.dataSolarReflectionManager->HitPtRefl);
     955            0 :                             if (hitRefl) { // Reflecting surface was hit
     956              :                                 ReflDistanceSq =
     957            0 :                                     distance_squared(state.dataSolarReflectionManager->HitPtRefl, state.dataSolarReflectionManager->RecPt);
     958            0 :                                 ReflDistance = std::sqrt(ReflDistanceSq);
     959              :                                 // Determine if ray from receiving point to hit point is obstructed
     960            0 :                                 hitObsRefl = false;
     961            0 :                                 for (int loop2 = 1, loop2_end = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs;
     962            0 :                                      loop2 <= loop2_end;
     963              :                                      ++loop2) {
     964            0 :                                     int const ObsSurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop2);
     965            0 :                                     if (ObsSurfNum == ReflSurfNum || ObsSurfNum == state.dataSurface->Surface(ReflSurfNum).BaseSurf) continue;
     966            0 :                                     hitObs = PierceSurface(state,
     967              :                                                            ObsSurfNum,
     968            0 :                                                            state.dataSolarReflectionManager->RecPt,
     969            0 :                                                            state.dataSolarReflectionManager->SunVecMir,
     970              :                                                            ReflDistance,
     971            0 :                                                            state.dataSolarReflectionManager->HitPtObs); // ReflDistance cutoff added
     972            0 :                                     if (hitObs) { // => Could skip distance check (unless < vs <= ReflDistance really matters)
     973            0 :                                         if (distance_squared(state.dataSolarReflectionManager->HitPtObs, state.dataSolarReflectionManager->RecPt) <
     974              :                                             ReflDistanceSq) {
     975            0 :                                             hitObsRefl = true;
     976            0 :                                             break;
     977              :                                         }
     978              :                                     }
     979              :                                 }
     980            0 :                                 if (hitObsRefl) continue; // Obstruction closer than reflection pt. was hit; go to next rec. pt.
     981              :                                 // There is no obstruction for this ray between rec. pt. and hit point on reflecting surface.
     982              :                                 // See if ray from hit pt. on reflecting surface to original (unmirrored) sun position is obstructed
     983            0 :                                 hitObs = false;
     984            0 :                                 if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window) { // Reflecting surface is a window
     985              :                                     // Receiving surface number for this window
     986            0 :                                     int const ReflSurfRecNum = state.dataSurface->SurfShadowRecSurfNum(
     987            0 :                                         ReflSurfNum); // Receiving surface number corresponding to a reflecting surface number
     988            0 :                                     if (ReflSurfRecNum > 0) {
     989              :                                         // Loop over possible obstructions for this window
     990            0 :                                         for (int loop2 = 1,
     991            0 :                                                  loop2_end = state.dataSolarReflectionManager->SolReflRecSurf(ReflSurfRecNum).NumPossibleObs;
     992            0 :                                              loop2 <= loop2_end;
     993              :                                              ++loop2) {
     994              :                                             int const ObsSurfNum =
     995            0 :                                                 state.dataSolarReflectionManager->SolReflRecSurf(ReflSurfRecNum).PossibleObsSurfNums(loop2);
     996            0 :                                             hitObs = PierceSurface(state,
     997              :                                                                    ObsSurfNum,
     998            0 :                                                                    state.dataSolarReflectionManager->HitPtRefl,
     999            0 :                                                                    state.dataSolarReflectionManager->SunVect,
    1000            0 :                                                                    state.dataSolarReflectionManager->HitPtObs);
    1001            0 :                                             if (hitObs) break;
    1002              :                                         }
    1003              :                                     }
    1004              :                                 } else { // Reflecting surface is a building shade
    1005            0 :                                     for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    1006            0 :                                         if (ObsSurfNum == ReflSurfNum) continue;
    1007              : 
    1008              :                                         // TH2 CR8959 -- Skip mirrored surfaces
    1009            0 :                                         if (state.dataSurface->Surface(ObsSurfNum).MirroredSurf) continue;
    1010              :                                         // TH2 CR8959 -- The other side of a mirrored surface cannot obstruct the mirrored surface
    1011            0 :                                         if (state.dataSurface->Surface(ReflSurfNum).MirroredSurf) {
    1012            0 :                                             if (ObsSurfNum == ReflSurfNum - 1) continue;
    1013              :                                         }
    1014              : 
    1015            0 :                                         hitObs = PierceSurface(state,
    1016              :                                                                ObsSurfNum,
    1017            0 :                                                                state.dataSolarReflectionManager->HitPtRefl,
    1018            0 :                                                                state.dataSolarReflectionManager->SunVect,
    1019            0 :                                                                state.dataSolarReflectionManager->HitPtObs);
    1020            0 :                                         if (hitObs) break;
    1021              :                                     }
    1022              :                                 }
    1023              : 
    1024            0 :                                 if (hitObs) continue; // Obstruction hit between reflection hit point and sun; go to next receiving pt.
    1025              : 
    1026              :                                 // No obstructions. Calculate reflected beam irradiance at receiving pt. from this reflecting surface.
    1027            0 :                                 state.dataSolarReflectionManager->SpecReflectance = 0.0;
    1028            0 :                                 if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window) {
    1029            0 :                                     state.dataSolarReflectionManager->ConstrNumRefl = state.dataSurface->Surface(ReflSurfNum).Construction;
    1030            0 :                                     state.dataSolarReflectionManager->SpecReflectance = Window::POLYF(
    1031            0 :                                         std::abs(state.dataSolarReflectionManager->CosIncAngRefl),
    1032            0 :                                         state.dataConstruction->Construct(state.dataSolarReflectionManager->ConstrNumRefl).ReflSolBeamFrontCoef);
    1033              :                                 }
    1034            0 :                                 if (state.dataSurface->Surface(ReflSurfNum).IsShadowing &&
    1035            0 :                                     state.dataSurface->SurfShadowGlazingConstruct(ReflSurfNum) > 0) {
    1036            0 :                                     state.dataSolarReflectionManager->ConstrNumRefl = state.dataSurface->SurfShadowGlazingConstruct(ReflSurfNum);
    1037            0 :                                     state.dataSolarReflectionManager->SpecReflectance =
    1038            0 :                                         state.dataSurface->SurfShadowGlazingFrac(ReflSurfNum) *
    1039            0 :                                         Window::POLYF(
    1040            0 :                                             std::abs(state.dataSolarReflectionManager->CosIncAngRefl),
    1041            0 :                                             state.dataConstruction->Construct(state.dataSolarReflectionManager->ConstrNumRefl).ReflSolBeamFrontCoef);
    1042              :                                 }
    1043              :                                 // Angle of incidence of reflected beam on receiving surface
    1044            0 :                                 state.dataSolarReflectionManager->CosIncAngRec =
    1045            0 :                                     dot(state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NormVec,
    1046            0 :                                         state.dataSolarReflectionManager->SunVecMir);
    1047            0 :                                 state.dataSolarReflectionManager->ReflFac =
    1048            0 :                                     state.dataSolarReflectionManager->SpecReflectance * state.dataSolarReflectionManager->CosIncAngRec;
    1049              :                                 // Contribution to specular reflection factor
    1050            0 :                                 ReflBmToBmSolObs(RecPtNum) += state.dataSolarReflectionManager->ReflFac;
    1051            0 :                                 ReflFacTimesCosIncSum(RecPtNum) +=
    1052            0 :                                     state.dataSolarReflectionManager->ReflFac * state.dataSolarReflectionManager->CosIncAngRec;
    1053              :                             } // End of check if reflecting surface was hit
    1054              :                         }     // End of loop over receiving points
    1055              :                     }         // End of check if valid reflecting surface
    1056              :                 }             // End of loop over obstructing surfaces
    1057              :                 // Average over receiving points
    1058              : 
    1059            0 :                 for (int RecPtNum = 1; RecPtNum <= NumRecPts; ++RecPtNum) {
    1060            0 :                     if (ReflBmToBmSolObs(RecPtNum) != 0.0) {
    1061            0 :                         state.dataSolarReflectionManager->CosIncWeighted = ReflFacTimesCosIncSum(RecPtNum) / ReflBmToBmSolObs(RecPtNum);
    1062              :                     } else {
    1063            0 :                         state.dataSolarReflectionManager->CosIncWeighted = 0.0;
    1064              :                     }
    1065            0 :                     state.dataSurface->SurfCosIncAveBmToBmSolObs(iHour, SurfNum) += state.dataSolarReflectionManager->CosIncWeighted;
    1066            0 :                     state.dataSurface->SurfReflFacBmToBmSolObs(iHour, SurfNum) += ReflBmToBmSolObs(RecPtNum);
    1067              :                 }
    1068            0 :                 state.dataSurface->SurfReflFacBmToBmSolObs(iHour, SurfNum) /= double(NumRecPts);
    1069            0 :                 state.dataSurface->SurfCosIncAveBmToBmSolObs(iHour, SurfNum) /= double(NumRecPts);
    1070              :             } // End of check if number of possible obstructions > 0
    1071              :         }     // End of loop over receiving surfaces
    1072            0 :     }
    1073              : 
    1074              :     //=================================================================================================
    1075              : 
    1076            0 :     void CalcSkySolDiffuseReflFactors(EnergyPlusData &state)
    1077              :     {
    1078              : 
    1079              :         // SUBROUTINE INFORMATION:
    1080              :         //       AUTHOR         Fred Winkelmann
    1081              :         //       DATE WRITTEN   October 2003
    1082              :         //       MODIFIED       na
    1083              :         //       RE-ENGINEERED  na
    1084              : 
    1085              :         // PURPOSE OF THIS SUBROUTINE:
    1086              :         // Calculates factors for irradiance on exterior heat transfer surfaces due to
    1087              :         // reflection of sky diffuse solar radiation from obstructions and ground.
    1088              : 
    1089              :         // Using/Aliasing
    1090              : 
    1091              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1092            0 :         Array1D<Real64> ReflSkySolObs(state.dataSurface->MaxRecPts); // Irradiance at a receiving point for sky diffuse solar
    1093              :         // reflected from obstructions, divided by unobstructed
    1094              :         // sky diffuse horizontal irradiance
    1095            0 :         Array1D<Real64> ReflSkySolGnd(state.dataSurface->MaxRecPts); // Irradiance at a receiving point for sky diffuse solar
    1096              :         // reflected from ground, divided by unobstructed
    1097              :         // sky diffuse horizontal irradiance
    1098              :         bool hitObs; // True iff obstruction is hit
    1099              : 
    1100            0 :         Real64 const DPhi(Constant::PiOvr2 / (AltAngStepsForSolReflCalc / 2.0));      // Altitude angle and increment (radians)
    1101            0 :         Real64 const DTheta(2.0 * Constant::Pi / (2.0 * AzimAngStepsForSolReflCalc)); // Azimuth increment (radians)
    1102              : 
    1103              :         // Pre-compute these constants
    1104              :         // Initialize the 0 index with dummy value so the iterators line up below
    1105            0 :         std::vector<Real64> sin_Phi({-1});
    1106            0 :         std::vector<Real64> cos_Phi({-1});
    1107            0 :         for (int IPhi = 1; IPhi <= (AltAngStepsForSolReflCalc / 2); ++IPhi) {
    1108            0 :             Real64 Phi((IPhi - 0.5) * DPhi); // Altitude angle and increment (radians)
    1109            0 :             sin_Phi.push_back(std::sin(Phi));
    1110            0 :             cos_Phi.push_back(std::cos(Phi));
    1111              :         }
    1112              : 
    1113            0 :         std::vector<Real64> sin_Theta({-1});
    1114            0 :         std::vector<Real64> cos_Theta({-1});
    1115            0 :         for (int ITheta = 1; ITheta <= 2 * AzimAngStepsForSolReflCalc; ++ITheta) {
    1116            0 :             Real64 Theta = (ITheta - 0.5) * DTheta; // Azimuth angle (radians)
    1117            0 :             sin_Theta.push_back(std::sin(Theta));
    1118            0 :             cos_Theta.push_back(std::cos(Theta));
    1119              :         }
    1120              : 
    1121            0 :         DisplayString(state, "Calculating Sky Diffuse Exterior Solar Reflection Factors");
    1122            0 :         ReflSkySolObs = 0.0;
    1123            0 :         ReflSkySolGnd = 0.0;
    1124              : 
    1125            0 :         for (state.dataSolarReflectionManager->iRecSurfNum = 1;
    1126            0 :              state.dataSolarReflectionManager->iRecSurfNum <= state.dataSolarReflectionManager->TotSolReflRecSurf;
    1127            0 :              ++state.dataSolarReflectionManager->iRecSurfNum) {
    1128            0 :             state.dataSolarReflectionManager->iSurfNum =
    1129            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum).SurfNum;
    1130            0 :             for (state.dataSolarReflectionManager->iRecPtNum = 1;
    1131            0 :                  state.dataSolarReflectionManager->iRecPtNum <=
    1132            0 :                  state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum).NumRecPts;
    1133            0 :                  ++state.dataSolarReflectionManager->iRecPtNum) {
    1134            0 :                 ReflSkySolObs(state.dataSolarReflectionManager->iRecPtNum) = 0.0;
    1135            0 :                 ReflSkySolGnd(state.dataSolarReflectionManager->iRecPtNum) = 0.0;
    1136            0 :                 for (state.dataSolarReflectionManager->iRayNum = 1;
    1137            0 :                      state.dataSolarReflectionManager->iRayNum <=
    1138            0 :                      state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum).NumReflRays;
    1139            0 :                      ++state.dataSolarReflectionManager->iRayNum) {
    1140            0 :                     state.dataSolarReflectionManager->HitPntSurfNum =
    1141            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1142            0 :                             .HitPtSurfNum(state.dataSolarReflectionManager->iRayNum, state.dataSolarReflectionManager->iRecPtNum);
    1143              :                     // Skip rays that do not hit an obstruction or ground.
    1144              :                     // (Note that if a downgoing ray does not hit an obstruction it will have HitPtSurfNum = 0
    1145              :                     // if the receiving point is below ground level (see subr. InitSolReflRecSurf); this means
    1146              :                     // that a below-ground-level receiving point receives no ground-reflected radiation although
    1147              :                     // it is allowed to receive obstruction-reflected solar radiation and direct (unreflected)
    1148              :                     // beam and sky solar radiation. As far as reflected solar is concerned, the program does
    1149              :                     // not handle a sloped ground plane or a horizontal ground plane whose level is different
    1150              :                     // from one side of the building to another.)
    1151            0 :                     if (state.dataSolarReflectionManager->HitPntSurfNum == 0)
    1152            0 :                         continue; // Ray hits sky or obstruction with receiving pt. below ground level
    1153            0 :                     state.dataSolarReflectionManager->HitPntRefl =
    1154            0 :                         state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1155            0 :                             .HitPt(state.dataSolarReflectionManager->iRayNum, state.dataSolarReflectionManager->iRecPtNum);
    1156            0 :                     if (state.dataSolarReflectionManager->HitPntSurfNum > 0) {
    1157              :                         // Ray hits an obstruction
    1158              :                         // Skip hit points on daylighting shelves, from which solar reflection is separately calculated
    1159            0 :                         if (state.dataSurface->SurfDaylightingShelfInd(state.dataSolarReflectionManager->HitPntSurfNum) > 0) continue;
    1160              :                         // Reflected radiance at hit point divided by unobstructed sky diffuse horizontal irradiance
    1161            0 :                         state.dataSolarReflectionManager->HitPtSurfNumX = state.dataSolarReflectionManager->HitPntSurfNum;
    1162              :                         // Each shading surface has a "mirror" duplicate surface facing in the opposite direction.
    1163              :                         // The following gets the correct side of a shading surface in order to get the right value
    1164              :                         // of DifShdgRatioIsoSky (the two sides can have different sky shadowing).
    1165            0 :                         if (state.dataSurface->Surface(state.dataSolarReflectionManager->HitPntSurfNum).IsShadowing) {
    1166            0 :                             if (dot(state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1167            0 :                                         .RayVec(state.dataSolarReflectionManager->iRayNum),
    1168            0 :                                     state.dataSurface->Surface(state.dataSolarReflectionManager->HitPntSurfNum).OutNormVec) > 0.0) {
    1169            0 :                                 if (state.dataSolarReflectionManager->HitPntSurfNum + 1 < state.dataSurface->TotSurfaces)
    1170            0 :                                     state.dataSolarReflectionManager->HitPtSurfNumX = state.dataSolarReflectionManager->HitPntSurfNum + 1;
    1171            0 :                                 if (state.dataSurface->SurfDaylightingShelfInd(state.dataSolarReflectionManager->HitPtSurfNumX) > 0) continue;
    1172              :                             }
    1173              :                         }
    1174              : 
    1175            0 :                         if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
    1176            0 :                             state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    1177            0 :                             state.dataSolarReflectionManager->SkyReflSolRadiance =
    1178            0 :                                 state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNumX).ViewFactorSky *
    1179            0 :                                 state.dataSolarShading->SurfDifShdgRatioIsoSky(state.dataSolarReflectionManager->HitPtSurfNumX) *
    1180            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1181            0 :                                     .HitPtSolRefl(state.dataSolarReflectionManager->iRayNum, state.dataSolarReflectionManager->iRecPtNum);
    1182              :                         } else {
    1183            0 :                             state.dataSolarReflectionManager->SkyReflSolRadiance =
    1184            0 :                                 state.dataSurface->Surface(state.dataSolarReflectionManager->HitPtSurfNumX).ViewFactorSky *
    1185            0 :                                 state.dataSolarShading->SurfDifShdgRatioIsoSkyHRTS(1, 1, state.dataSolarReflectionManager->HitPtSurfNumX) *
    1186            0 :                                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1187            0 :                                     .HitPtSolRefl(state.dataSolarReflectionManager->iRayNum, state.dataSolarReflectionManager->iRecPtNum);
    1188              :                         }
    1189            0 :                         state.dataSolarReflectionManager->dReflSkySol =
    1190            0 :                             state.dataSolarReflectionManager->SkyReflSolRadiance *
    1191            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1192            0 :                                 .dOmegaRay(state.dataSolarReflectionManager->iRayNum) *
    1193            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1194            0 :                                 .CosIncAngRay(state.dataSolarReflectionManager->iRayNum) /
    1195              :                             Constant::Pi;
    1196            0 :                         ReflSkySolObs(state.dataSolarReflectionManager->iRecPtNum) += state.dataSolarReflectionManager->dReflSkySol;
    1197              :                     } else {
    1198              :                         // Ray hits ground;
    1199              :                         // Find radiance at hit point due to reflection of sky diffuse reaching
    1200              :                         // ground directly, i.e., without reflecting from obstructions.
    1201              :                         // Send rays upward from hit point and see which ones are unobstructed and so go to sky.
    1202              :                         // Divide hemisphere centered at ground hit point into elements of altitude Phi and
    1203              :                         // azimuth Theta and create upward-going ray unit vector at each Phi,Theta pair.
    1204              :                         // Phi = 0 at the horizon; Phi = Pi/2 at the zenith.
    1205            0 :                         Real64 dReflSkyGnd = 0.0; // Factor for ground radiance due to direct sky diffuse reflection
    1206              :                         // Altitude loop
    1207            0 :                         for (int IPhi = 1; IPhi <= (AltAngStepsForSolReflCalc / 2); ++IPhi) {
    1208              :                             // Third component of ray unit vector in (Theta,Phi) direction
    1209            0 :                             state.dataSolarReflectionManager->URay(3) = sin_Phi[IPhi];
    1210            0 :                             Real64 dOmega = cos_Phi[IPhi] * DTheta * DPhi; // Solid angle increment (steradians)
    1211              :                             // Cosine of angle of incidence of ray on ground
    1212            0 :                             Real64 CosIncAngRayToSky = sin_Phi[IPhi]; // Cosine of incidence angle on ground of ray to sky
    1213              :                             // Azimuth loop
    1214            0 :                             for (int ITheta = 1; ITheta <= 2 * AzimAngStepsForSolReflCalc; ++ITheta) {
    1215            0 :                                 state.dataSolarReflectionManager->URay.x = cos_Phi[IPhi] * cos_Theta[ITheta];
    1216            0 :                                 state.dataSolarReflectionManager->URay.y = cos_Phi[IPhi] * sin_Theta[ITheta];
    1217              :                                 // Does this ray hit an obstruction?
    1218            0 :                                 hitObs = false;
    1219            0 :                                 for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
    1220            0 :                                     state.dataSolarReflectionManager->iObsSurfNum = ObsSurfNum;
    1221              :                                     // Horizontal roof surfaces cannot be obstructions for rays from ground
    1222            0 :                                     if (state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).Tilt < 5.0) continue;
    1223            0 :                                     if (!state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).IsShadowing) {
    1224            0 :                                         if (dot(state.dataSolarReflectionManager->URay,
    1225            0 :                                                 state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).OutNormVec) >= 0.0)
    1226            0 :                                             continue;
    1227              :                                         // Special test for vertical surfaces with URay dot OutNormVec < 0; excludes
    1228              :                                         // case where ground hit point is in back of ObsSurfNum
    1229            0 :                                         if (state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).Tilt > 89.0 &&
    1230            0 :                                             state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).Tilt < 91.0) {
    1231            0 :                                             state.dataSolarReflectionManager->SurfVert =
    1232            0 :                                                 state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).Vertex(2);
    1233            0 :                                             state.dataSolarReflectionManager->SurfVertToGndPt =
    1234            0 :                                                 state.dataSolarReflectionManager->HitPntRefl - state.dataSolarReflectionManager->SurfVert;
    1235            0 :                                             if (dot(state.dataSolarReflectionManager->SurfVertToGndPt,
    1236            0 :                                                     state.dataSurface->Surface(state.dataSolarReflectionManager->iObsSurfNum).OutNormVec) < 0.0)
    1237            0 :                                                 continue;
    1238              :                                         }
    1239              :                                     }
    1240            0 :                                     hitObs = PierceSurface(state,
    1241            0 :                                                            state.dataSolarReflectionManager->iObsSurfNum,
    1242            0 :                                                            state.dataSolarReflectionManager->HitPntRefl,
    1243            0 :                                                            state.dataSolarReflectionManager->URay,
    1244            0 :                                                            state.dataSolarReflectionManager->HitPntObs);
    1245            0 :                                     if (hitObs) break;
    1246              :                                 }
    1247            0 :                                 if (hitObs) continue; // Obstruction hit
    1248              :                                 // Sky is hit
    1249            0 :                                 dReflSkyGnd += CosIncAngRayToSky * dOmega / Constant::Pi;
    1250              :                             } // End of azimuth loop
    1251              :                         }     // End of altitude loop
    1252            0 :                         ReflSkySolGnd(state.dataSolarReflectionManager->iRecPtNum) +=
    1253            0 :                             dReflSkyGnd *
    1254            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1255            0 :                                 .dOmegaRay(state.dataSolarReflectionManager->iRayNum) *
    1256            0 :                             state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum)
    1257            0 :                                 .CosIncAngRay(state.dataSolarReflectionManager->iRayNum) /
    1258              :                             Constant::Pi;
    1259              :                     } // End of check if ray from receiving point hits obstruction or ground
    1260              :                 }     // End of loop over rays from receiving point
    1261              :             }         // End of loop over receiving points
    1262              : 
    1263              :             // Average over receiving points
    1264            0 :             state.dataSurface->SurfReflFacSkySolObs(state.dataSolarReflectionManager->iSurfNum) = 0.0;
    1265            0 :             state.dataSurface->SurfReflFacSkySolGnd(state.dataSolarReflectionManager->iSurfNum) = 0.0;
    1266            0 :             state.dataSolarReflectionManager->iNumRecPts =
    1267            0 :                 state.dataSolarReflectionManager->SolReflRecSurf(state.dataSolarReflectionManager->iRecSurfNum).NumRecPts;
    1268            0 :             for (state.dataSolarReflectionManager->iRecPtNum = 1;
    1269            0 :                  state.dataSolarReflectionManager->iRecPtNum <= state.dataSolarReflectionManager->iNumRecPts;
    1270            0 :                  ++state.dataSolarReflectionManager->iRecPtNum) {
    1271            0 :                 state.dataSurface->SurfReflFacSkySolObs(state.dataSolarReflectionManager->iSurfNum) +=
    1272            0 :                     ReflSkySolObs(state.dataSolarReflectionManager->iRecPtNum);
    1273            0 :                 state.dataSurface->SurfReflFacSkySolGnd(state.dataSolarReflectionManager->iSurfNum) +=
    1274            0 :                     ReflSkySolGnd(state.dataSolarReflectionManager->iRecPtNum);
    1275              :             }
    1276            0 :             state.dataSurface->SurfReflFacSkySolObs(state.dataSolarReflectionManager->iSurfNum) /= state.dataSolarReflectionManager->iNumRecPts;
    1277            0 :             state.dataSurface->SurfReflFacSkySolGnd(state.dataSolarReflectionManager->iSurfNum) /= state.dataSolarReflectionManager->iNumRecPts;
    1278              :             // Do not allow SurfReflFacBmToDiffSolGnd to exceed the surface's unobstructed ground view factor
    1279            0 :             state.dataSurface->SurfReflFacSkySolGnd(state.dataSolarReflectionManager->iSurfNum) =
    1280            0 :                 min(0.5 * (1.0 - state.dataSurface->Surface(state.dataSolarReflectionManager->iSurfNum).CosTilt),
    1281            0 :                     state.dataSurface->SurfReflFacSkySolGnd(state.dataSolarReflectionManager->iSurfNum));
    1282              :             // Note: the above factors are dimensionless; they are equal to
    1283              :             // (W/m2 reflected solar incident on SurfNum)/(W/m2 unobstructed horizontal sky diffuse irradiance)
    1284              :         } // End of loop over receiving surfaces
    1285            0 :     }
    1286              : 
    1287              : } // namespace SolarReflectionManager
    1288              : 
    1289              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1