Nodes of different colours represent the following:
Solid arrows point from a parent (sub)module to the submodule which is descended from it. Dashed arrows point from a module being used to the module or program unit using it. Where possible, edges connecting nodes are given different colours to make them easier to distinguish in large graphs.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed arrows point from an interface to procedures which implement that interface. This could include the module procedures in a generic interface or the implementation in a submodule of an interface in a parent module. Where possible, edges connecting nodes are given different colours to make them easier to distinguish in large graphs.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed arrows point from an interface to procedures which implement that interface. This could include the module procedures in a generic interface or the implementation in a submodule of an interface in a parent module. Where possible, edges connecting nodes are given different colours to make them easier to distinguish in large graphs.
SUBROUTINE InitSolReflRecSurf
! SUBROUTINE INFORMATION:
! AUTHOR Fred Winkelmann
! DATE WRITTEN September 2003
! MODIFIED na
! RE-ENGINEERED na
! PURPOSE OF THIS SUBROUTINE:
! Initializes the derived type SolReflRecSurf, which contains information
! needed to calculate factors for solar reflection from obstructions and ground.
! METHODOLOGY EMPLOYED: na
! REFERENCES: na
! USE STATEMENTS:
USE Vectors
IMPLICIT NONE ! Enforce explicit typing of all variables in this routine
! SUBROUTINE PARAMETER DEFINITIONS: na
! INTERFACE BLOCK SPECIFICATIONS: na
! DERIVED TYPE DEFINITIONS: na
! SUBROUTINE LOCAL VARIABLE DECLARATIONS:
INTEGER :: SurfNum ! Surface number
INTEGER :: RecSurfNum ! Receiving surface number
INTEGER :: loop ! DO loop indices
INTEGER :: loop1 ! DO loop indices
INTEGER :: loopA ! DO loop indices
INTEGER :: loopb ! DO loop indices
INTEGER :: ObsSurfNum ! Surface number of an obstruction
LOGICAL :: ObsBehindRec ! True if an obstruction is entirely behind a receiving surface
LOGICAL :: ObsHasView ! True if view between receiving surface and heat trans surf obstruction
REAL(r64) :: RecVec(3) ! First vertex of a receiving surface (m)
REAL(r64) :: ObsVec(3) ! A vertex of a candidate obstructing surface (m)
REAL(r64) :: VecAB(3) ! Vector from receiving surface vertex to obstruction surface vertex (m)
REAL(r64) :: HitPt(3) ! Hit point (m)
REAL(r64) :: DotProd ! Dot product of vectors (m2)
INTEGER :: RecPtNum ! Receiving point number
!unused REAL(r64) :: SumX ! Sum of X (or Y or Z) coordinate values of a surface
!unused REAL(r64) :: SumY ! Sum of X (or Y or Z) coordinate values of a surface
!unused REAL(r64) :: SumZ ! Sum of X (or Y or Z) coordinate values of a surface
REAL(r64) :: PhiSurf ! Altitude of normal to receiving surface (radians)
REAL(r64) :: ThetaSurf ! Azimuth of normal to receiving surface (radians)
REAL(r64) :: PhiMin ! Minimum and maximum values of ray altitude angle (radians)
REAL(r64) :: PhiMax ! Minimum and maximum values of ray altitude angle (radians)
REAL(r64) :: ThetaMin ! Minimum and maximum values of ray azimuth angle (radians)
REAL(r64) :: ThetaMax ! Minimum and maximum values of ray azimuth angle (radians)
REAL(r64) :: Phi ! Ray altitude angle, increment, sine, and cosine
REAL(r64) :: DPhi ! Ray altitude angle, increment, sine, and cosine
REAL(r64) :: SPhi ! Ray altitude angle, increment, sine, and cosine
REAL(r64) :: CPhi ! Ray altitude angle, increment, sine, and cosine
REAL(r64) :: Theta ! Ray azimuth angle and increment
REAL(r64) :: DTheta ! Ray azimuth angle and increment
INTEGER :: IPhi ! Ray altitude angle and azimuth angle indices
INTEGER :: ITheta ! Ray altitude angle and azimuth angle indices
!unused REAL(r64) :: APhi ! Intermediate variable
INTEGER :: RayNum ! Ray number
REAL(r64) :: URay(3) ! Unit vector along ray pointing away from receiving surface
REAL(r64) :: CosIncAngRay ! Cosine of angle of incidence of ray on receiving surface
REAL(r64) :: dOmega ! Solid angle associated with a ray
INTEGER :: IHit ! = 1 if obstruction is hit, 0 otherwise
INTEGER :: TotObstructionsHit ! Number of obstructions hit by a ray
REAL(r64) :: HitDistance ! Distance from receiving point to hit point for a ray (m)
INTEGER :: NearestHitSurfNum ! Surface number of nearest obstruction hit by a ray
REAL(r64) :: NearestHitPt(3) ! Nearest hit pit for a ray (m)
REAL(r64) :: NearestHitDistance ! Distance from receiving point to nearest hit point for a ray (m)
INTEGER :: ObsSurfNumToSkip ! Surface number of obstruction to be ignored
REAL(r64) :: RecPt(3) ! Receiving point (m)
REAL(r64) :: RayVec(3) ! Unit vector along ray
REAL(r64) :: Vec1(3) ! Vectors between hit surface vertices (m)
REAL(r64) :: Vec2(3) ! Vectors between hit surface vertices (m)
REAL(r64) :: VNorm(3) ! For a hit surface, unit normal vector pointing into the hemisphere
! containing the receiving point
INTEGER :: ObsConstrNum ! Construction number of obstruction; = 0 if a shading surface
REAL(r64) :: Alfa,Beta ! Direction angles for ray heading towards the ground (radians)
REAL(r64) :: HorDis ! Distance between ground hit point and proj'n of receiving pt onto ground (m)
REAL(r64) :: GroundHitPt(3) ! Coordinates of ground hit point
!unused REAL(r64) :: ArgASin
REAL(r64) :: ACosTanTan
INTEGER :: J ! DO loop indices
INTEGER :: K ! DO loop indices
INTEGER :: L ! DO loop indices
INTEGER :: NumRecPts ! Number of surface receiving points for reflected solar radiation
REAL(r64) :: VertexWt ! Vertex weighting factor for calculating receiving points
! FLOW:
! Find number of surfaces that are sun-exposed exterior building heat transfer surfaces.
! These are candidates for receiving solar reflected from obstructions and ground.
! CR 7640. 12/3/2008 BG simplified logic to allow for Other Side Conditions Modeled boundary condition.
! and solar collectors on shading surfaces that need this.
!
! shading surfaces have ExtSolar = False, so they are not included in TotSolReflRecSurf
TotSolReflRecSurf = 0
DO SurfNum = 1,TotSurfaces
IF (Surface(SurfNum)%ExtSolar) THEN
TotSolReflRecSurf = TotSolReflRecSurf + 1
ENDIF
END DO
! TH 3/29/2010. ShadowSurfPossibleReflector is not used!
! Set flag that determines whether a surface can be an exterior reflector
!DO SurfNum = 1,TotSurfaces
! Surface(SurfNum)%ShadowSurfPossibleReflector = .FALSE.
! Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
! IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond > 0 ) CYCLE
! IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond == Ground) CYCLE
! IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond == OtherSideCoefNoCalcExt) CYCLE
! IF(Surface(SurfNum)%HeatTransSurf .AND. Surface(SurfNum)%ExtBoundCond == OtherSideCoefCalcExt) CYCLE
! Exclude daylighting shelves. A separate solar reflection calculation is done for these.
! IF(Surface(SurfNum)%Shelf > 0) CYCLE
! Exclude duplicate shading surfaces
! TH 3/24/2010. Why? a mirror shading surface can reflect solar (either beam or diffuse)
! can use a flag like Surface(SurfNum)%Mirrored (True or False) to avoid string comparison
! and to allow surface names starting with 'Mir'
!IF(Surface(SurfNum)%Name(1:3) == 'Mir') CYCLE
! IF(Surface(SurfNum)%MirroredSurf) CYCLE
! Surface(SurfNum)%ShadowSurfPossibleReflector = .TRUE.
!END DO
IF(TotSolReflRecSurf == 0) THEN
CALL ShowWarningError('Calculation of solar reflected from obstructions has been requested but there')
CALL ShowContinueError('are no building surfaces that can receive reflected solar. Calculation will not be done.')
CalcSolRefl = .FALSE.
RETURN
END IF
! Should this be moved up front?
IF (IgnoreSolarRadiation) THEN
TotSolReflRecSurf = 0
CalcSolRefl = .FALSE.
RETURN
ENDIF
ALLOCATE(SolReflRecSurf(TotSolReflRecSurf))
ALLOCATE(ReflFacBmToDiffSolObs(TotSurfaces,24))
ReflFacBmToDiffSolObs = 0.0d0
ALLOCATE(ReflFacBmToDiffSolGnd(TotSurfaces,24))
ReflFacBmToDiffSolGnd = 0.0d0
ALLOCATE(ReflFacBmToBmSolObs(TotSurfaces,24))
ReflFacBmToBmSolObs = 0.0d0
ALLOCATE(ReflFacSkySolObs(TotSurfaces))
ReflFacSkySolObs = 0.0d0
ALLOCATE(ReflFacSkySolGnd(TotSurfaces))
ReflFacSkySolGnd = 0.0d0
ALLOCATE(CosIncAveBmToBmSolObs(TotSurfaces,24))
CosIncAveBmToBmSolObs = 0.0d0
! Only surfaces with sun exposure can receive solar reflection from ground or onstructions
! Shading surfaces are always not exposed to solar (ExtSolar = False)
RecSurfNum = 0
DO SurfNum = 1,TotSurfaces
Surface(SurfNum)%ShadowSurfRecSurfNum = 0
IF (Surface(SurfNum)%ExtSolar) THEN
RecSurfNum = RecSurfNum + 1
SolReflRecSurf(RecSurfNum)%SurfNum = SurfNum
SolReflRecSurf(RecSurfNum)%SurfName = Surface(SurfNum)%Name
Surface(SurfNum)%ShadowSurfRecSurfNum = RecSurfNum
! Warning if any receiving surface vertex is below ground level, taken to be at Z = 0 in absolute coords
DO loop = 1,Surface(SurfNum)%Sides
IF(Surface(SurfNum)%Vertex(loop)%Z < GroundLevelZ) THEN
CALL ShowWarningError('Calculation of reflected solar onto surface=' &
//TRIM(Surface(SurfNum)%Name)//' may be inaccurate')
CALL ShowContinueError('because it has one or more vertices below ground level.')
EXIT
END IF
END DO
END IF
END DO
! Get MaxRecPts for allocating SolReflRecSurf arrays that depend on number of receiving points
MaxRecPts = 1
DO RecSurfNum = 1,TotSolReflRecSurf
SolReflRecSurf(RecSurfNum)%NumRecPts = Surface(SolReflRecSurf(RecSurfNum)%SurfNum)%Sides
IF(SolReflRecSurf(RecSurfNum)%NumRecPts > MaxRecPts) MaxRecPts = SolReflRecSurf(RecSurfNum)%NumRecPts
END DO
MaxReflRays = AltAngStepsForSolReflCalc * AzimAngStepsForSolReflCalc
DO RecSurfNum = 1,TotSolReflRecSurf
SolReflRecSurf(RecSurfNum)%NormVec = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%RecPt(3,MaxRecPts))
SolReflRecSurf(RecSurfNum)%RecPt = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%RayVec(3,MaxReflRays))
SolReflRecSurf(RecSurfNum)%RayVec = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%CosIncAngRay(MaxReflRays))
SolReflRecSurf(RecSurfNum)%CosIncAngRay = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%dOmegaRay(MaxReflRays))
SolReflRecSurf(RecSurfNum)%dOmegaRay = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%HitPt(3,MaxRecPts,MaxReflRays))
SolReflRecSurf(RecSurfNum)%HitPt = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%HitPtSurfNum(MaxRecPts,MaxReflRays))
SolReflRecSurf(RecSurfNum)%HitPtSurfNum = 0
ALLOCATE(SolReflRecSurf(RecSurfNum)%HitPtSolRefl(MaxRecPts,MaxReflRays))
SolReflRecSurf(RecSurfNum)%HitPtSolRefl = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%RecPtHitPtDis(MaxRecPts,MaxReflRays))
SolReflRecSurf(RecSurfNum)%RecPtHitPtDis = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%HitPtNormVec(3,MaxRecPts,MaxReflRays))
SolReflRecSurf(RecSurfNum)%HitPtNormVec = 0.0d0
ALLOCATE(SolReflRecSurf(RecSurfNum)%PossibleObsSurfNums(TotSurfaces))
SolReflRecSurf(RecSurfNum)%PossibleObsSurfNums = 0
END DO
DO RecSurfNum = 1,TotSolReflRecSurf
SurfNum = SolReflRecSurf(RecSurfNum)%SurfNum
! Outward norm to receiving surface
SolReflRecSurf(RecSurfNum)%NormVec = Surface(SurfNum)%OutNormVec(1:3)
RecVec = Surface(SurfNum)%Vertex(1)
! Loop over all surfaces and find those that can be obstructing surfaces for this receiving surf
SolReflRecSurf(RecSurfNum)%NumPossibleObs = 0
DO ObsSurfNum = 1,TotSurfaces
! Exclude the receiving surface itself and its base surface (if it has one)
IF(ObsSurfNum == SurfNum .OR. ObsSurfNum == Surface(SurfNum)%BaseSurf) CYCLE
! Exclude non-exterior heat transfer surfaces
IF(Surface(ObsSurfNum)%HeatTransSurf .AND. Surface(ObsSurfNum)%ExtBoundCond /= 0) CYCLE
! Exclude duplicate shading surfaces
!IF(Surface(ObsSurfNum)%Name(1:3) == 'Mir') CYCLE
!TH2 CR8959
!IF(Surface(ObsSurfNum)%MirroredSurf) CYCLE
! Exclude surfaces that are entirely behind the receiving surface.This is true if dot products of the
! rec. surface outward normal and vector from first vertex of rec. surface and each vertex of
! obstructing surface are all negative.
ObsBehindRec = .TRUE.
DO loop = 1,Surface(ObsSurfNum)%Sides
ObsVec = Surface(ObsSurfNum)%Vertex(loop)
DotProd = DOT_PRODUCT(SolReflRecSurf(RecSurfNum)%NormVec,ObsVec-RecVec)
!CR8251 IF(DotProd > 0.01d0) THEN ! This obstructing-surface vertex is not behind receiving surface
IF(DotProd > 1.d-6) THEN ! This obstructing-surface vertex is not behind receiving surface
ObsBehindRec = .FALSE.
EXIT
END IF
END DO
IF(ObsBehindRec) CYCLE
! Exclude heat transfer surfaces that have no view with the receiving surface.
! There is view if: for at least one vector VecAB from a receiving surface vertex to
! a vertex of a potential obstructing surface that satisfies VecAB.nA > 0.0 and VecAB.nB < 0.0,
! where nA and nB are the outward normal to the receiving and obstructing surface, resp.
IF(Surface(ObsSurfNum)%HeatTransSurf) THEN
ObsHasView = .FALSE.
DO loopA = 1,Surface(SurfNum)%Sides
DO loopB = 1,Surface(ObsSurfNum)%Sides
VecAB = Surface(ObsSurfNum)%Vertex(loopB) - Surface(SurfNum)%Vertex(loopA)
IF(DOT_PRODUCT(VecAB,SolReflRecSurf(RecSurfNum)%NormVec) > 0.0d0 .AND. &
DOT_PRODUCT(VecAB,Surface(ObsSurfNum)%OutNormVec) < 0.0d0) THEN
ObsHasView = .TRUE.
EXIT
END IF
END DO
IF(ObsHasView) EXIT
END DO
IF(.NOT.ObsHasView) CYCLE
END IF
! This is a possible obstructing surface for this receiving surface
SolReflRecSurf(RecSurfNum)%NumPossibleObs = SolReflRecSurf(RecSurfNum)%NumPossibleObs + 1
SolReflRecSurf(RecSurfNum)%PossibleObsSurfNums(SolReflRecSurf(RecSurfNum)%NumPossibleObs) = ObsSurfNum
END DO
! Get coordinates of receiving points on this receiving surface. The number of receiving points
! is equal to the number of surface vertices (3 or higher).
NumRecPts = SolReflRecSurf(RecSurfNum)%NumRecPts
DO J = 1,NumRecPts
DO L = 1,3
SolReflRecSurf(RecSurfNum)%RecPt(L,J) = 0.0d0
END DO
DO K = 1,NumRecPts
IF(NumRecPts == 3) THEN ! Receiving surface is a triangle
VertexWt = 0.2d0
IF(K == J) VertexWt = 0.6d0
ELSE ! Receiving surface has 4 or more vertices
VertexWt = 1.d0/(2.d0*REAL(NumRecPts,r64))
IF(K == J) VertexWt = (REAL(NumRecPts,r64)+1.d0)/(2.d0*REAL(NumRecPts,r64))
END IF
SolReflRecSurf(RecSurfNum)%RecPt(1,J) = SolReflRecSurf(RecSurfNum)%RecPt(1,J) + &
VertexWt * Surface(SurfNum)%Vertex(K)%X
SolReflRecSurf(RecSurfNum)%RecPt(2,J) = SolReflRecSurf(RecSurfNum)%RecPt(2,J) + &
VertexWt * Surface(SurfNum)%Vertex(K)%Y
SolReflRecSurf(RecSurfNum)%RecPt(3,J) = SolReflRecSurf(RecSurfNum)%RecPt(3,J) + &
VertexWt * Surface(SurfNum)%Vertex(K)%Z
END DO
END DO
! Create rays going outward from receiving surface. The same rays will be used at each receiving point.
! The rays are used in calculating diffusely reflected solar incident on receiving surface.
! Divide hemisphere around receiving surface into elements of altitude Phi and
! azimuth Theta and create ray unit vector at each Phi,Theta pair in front of the surface.
! Phi = 0 at the horizon; Phi = Pi/2 at the zenith
PhiSurf = ASIN(SolReflRecSurf(RecSurfNum)%NormVec(3))
IF(ABS(SolReflRecSurf(RecSurfNum)%NormVec(1)) > 1.0d-5 .OR. ABS(SolReflRecSurf(RecSurfNum)%NormVec(2)) > 1.0d-5) THEN
ThetaSurf = ATAN2(SolReflRecSurf(RecSurfNum)%NormVec(2), SolReflRecSurf(RecSurfNum)%NormVec(1))
ELSE
ThetaSurf = 0.d0
END IF
SolReflRecSurf(RecSurfNum)%PhiNormVec = PhiSurf
SolReflRecSurf(RecSurfNum)%ThetaNormVec = ThetaSurf
PhiMin = MAX(-PiOvr2, PhiSurf - PiOvr2)
PhiMax = MIN(PiOvr2, PhiSurf + PiOvr2)
DPhi = (PhiMax - PhiMin) / AltAngStepsForSolReflCalc
RayNum = 0
! Altitude loop
DO IPhi = 1,AltAngStepsForSolReflCalc
Phi = PhiMin + (IPhi - 0.5d0) * DPhi
SPhi = SIN(Phi)
CPhi = COS(Phi)
! Third component of ray unit vector in (Theta,Phi) direction
URay(3) = SPhi
IF(PhiSurf >= 0.0d0) THEN
IF(Phi >= PiOvr2 - PhiSurf) THEN
ThetaMin = -Pi
ThetaMax = Pi
ELSE
ACosTanTan = ACOS(-TAN(Phi)*TAN(PhiSurf))
ThetaMin = ThetaSurf - ABS(ACosTanTan)
ThetaMax = ThetaSurf + ABS(ACosTanTan)
END IF
ELSE ! PhiSurf < 0.0
IF(Phi <= -PhiSurf - PiOvr2) THEN
ThetaMin = -Pi
ThetaMax = Pi
ELSE
ACosTanTan = ACOS(-TAN(Phi)*TAN(PhiSurf))
ThetaMin = ThetaSurf - ABS(ACosTanTan)
ThetaMax = ThetaSurf + ABS(ACosTanTan)
END IF
END IF
DTheta = (ThetaMax - ThetaMin) / AzimAngStepsForSolReflCalc
dOmega = CPhi * DTheta * DPhi
! Azimuth loop
DO ITheta = 1,AzimAngStepsForSolReflCalc
Theta = ThetaMin + (ITheta - 0.5d0) * DTheta
URay(1) = CPhi * COS(Theta)
URay(2) = CPhi * SIN(Theta)
! Cosine of angle of incidence of ray on receiving surface
CosIncAngRay = SPhi * SIN(PhiSurf) + CPhi * COS(PhiSurf) * COS(Theta-ThetaSurf)
IF (CosIncAngRay < 0.0d0) CYCLE ! Ray is behind receiving surface (although there shouldn't be any)
RayNum = RayNum + 1
SolReflRecSurf(RecSurfNum)%RayVec(1:3,RayNum) = URay
SolReflRecSurf(RecSurfNum)%CosIncAngRay(RayNum) = CosIncAngRay
SolReflRecSurf(RecSurfNum)%dOmegaRay(RayNum) = dOmega
END DO ! End of azimuth loop
END DO ! End of altitude loop
SolReflRecSurf(RecSurfNum)%NumReflRays = RayNum
END DO ! End of loop over receiving surfaces
! Loop again over receiving surfaces and, for each ray, get hit point and info associated with that point
! (hit point = point that ray intersects nearest obstruction, or, if ray is downgoing and hits no
! obstructions, point that ray intersects ground plane).
DO RecSurfNum = 1, TotSolReflRecSurf
SurfNum = SolReflRecSurf(RecSurfNum)%SurfNum
DO RecPtNum = 1, SolReflRecSurf(RecSurfNum)%NumRecPts
RecPt = SolReflRecSurf(RecSurfNum)%RecPt(1:3,RecPtNum)
DO RayNum = 1, SolReflRecSurf(RecSurfNum)%NumReflRays
IHit = 0
! Loop over possible obstructions. If ray hits one or more obstructions get hit point on closest obstruction.
! If ray hits no obstructions and is going upward set HitPointSurfNum = 0.
! If ray hits no obstructions and is going downward set HitPointSurfNum = -1 and get hit point on ground.
TotObstructionsHit = 0
NearestHitSurfNum = 0
NearestHitDistance = 1.d+8
ObsSurfNumToSkip = 0
RayVec = SolReflRecSurf(RecSurfNum)%RayVec(1:3,RayNum)
DO loop1 = 1,SolReflRecSurf(RecSurfNum)%NumPossibleObs
! Surface number of this obstruction
ObsSurfNum = SolReflRecSurf(RecSurfNum)%PossibleObsSurfNums(loop1)
! If a window was hit previously (see below), ObsSurfNumToSkip was set to the window's base surface in order
! to remove that surface from consideration as a hit surface for this ray
IF(ObsSurfNum == ObsSurfNumToSkip) CYCLE
! Determine if this ray hits ObsSurfNum (in which case IHit > 0) and, if so, what the
! distance from the receiving point to the hit point is
CALL PierceSurface(ObsSurfNum,RecPt,RayVec,IHit,HitPt)
IF(IHit > 0) THEN
! added TH 3/29/2010 to set ObsSurfNumToSkip
IF(Surface(ObsSurfNum)%Class == SurfaceClass_Window) THEN
ObsSurfNumToSkip = Surface(ObsSurfNum)%BaseSurf
ENDIF
! If obstruction is a window and its base surface is the nearest obstruction hit so far,
! set NearestHitSurfNum to this window. Note that in this case NearestHitDistance has already
! been calculated, so does not have to be recalculated.
IF(Surface(ObsSurfNum)%Class == SurfaceClass_Window .AND. Surface(ObsSurfNum)%BaseSurf == NearestHitSurfNum) THEN
NearestHitSurfNum = ObsSurfNum
ELSE
TotObstructionsHit = TotObstructionsHit + 1
! Distance from receiving point to hit point
HitDistance = SQRT(DOT_PRODUCT(HitPt-RecPt,HitPt-RecPt))
! Reset NearestHitSurfNum and NearestHitDistance if this hit point is closer than previous closest
IF(HitDistance < NearestHitDistance) THEN
NearestHitDistance = HitDistance
NearestHitSurfNum = ObsSurfNum
NearestHitPt = HitPt
ELSE IF(HitDistance == NearestHitDistance) THEN ! TH2 CR8959
! Ray hits mirrored surfaces. Choose the surface facing the ray.
IF(DOT_PRODUCT(Surface(ObsSurfNum)%OutNormVec,RayVec) <= 0.0d0) THEN
NearestHitSurfNum = ObsSurfNum
END IF
END IF
END IF
END IF ! End of check if obstruction was hit
END DO ! End of loop over possible obstructions for this ray
IF(TotObstructionsHit > 0) THEN
! One or more obstructions were hit by this ray
SolReflRecSurf(RecSurfNum)%HitPtSurfNum(RecPtNum,RayNum) = NearestHitSurfNum
SolReflRecSurf(RecSurfNum)%RecPtHitPtDis(RecPtNum,RayNum) = NearestHitDistance
SolReflRecSurf(RecSurfNum)%HitPt(1:3,RecPtNum,RayNum) = NearestHitPt
! For hit surface, calculate unit normal vector pointing into the hemisphere
! containing the receiving point
Vec1 = Surface(NearestHitSurfNum)%Vertex(1) - Surface(NearestHitSurfNum)%Vertex(3)
Vec2 = Surface(NearestHitSurfNum)%Vertex(2) - Surface(NearestHitSurfNum)%Vertex(3)
CALL CrossProduct(Vec1,Vec2,VNorm)
VNorm = VNorm/SQRT(DOT_PRODUCT(VNorm,VNorm))
IF(DOT_PRODUCT(VNorm,-RayVec) < 0.0d0) VNorm = -VNorm
SolReflRecSurf(RecSurfNum)%HitPtNormVec(1:3,RecPtNum,RayNum) = VNorm
! Get solar and visible beam-to-diffuse reflectance at nearest hit point
ObsConstrNum = Surface(NearestHitSurfNum)%Construction
IF(ObsConstrNum > 0) THEN
! Exterior building surface is nearest hit
IF(.NOT.Construct(ObsConstrNum)%TypeIsWindow) THEN
! Obstruction is not a window, i.e., is an opaque surface
SolReflRecSurf(RecSurfNum)%HitPtSolRefl(RecPtNum,RayNum) = &
1.0d0 - Construct(ObsConstrNum)%OutsideAbsorpSolar
ELSE
! Obstruction is a window. Assume it is bare so that there is no beam-to-diffuse reflection
! (beam-to-beam reflection is calculated in subroutine CalcBeamSolSpecularReflFactors).
SolReflRecSurf(RecSurfNum)%HitPtSolRefl(RecPtNum,RayNum) = 0.0d0
END IF
ELSE
! Shading surface is nearest hit
SolReflRecSurf(RecSurfNum)%HitPtSolRefl(RecPtNum,RayNum) = Surface(NearestHitSurfNum)%ShadowSurfDiffuseSolRefl
END IF
ELSE
! No obstructions were hit by this ray
SolReflRecSurf(RecSurfNum)%HitPtSurfNum(RecPtNum,RayNum) = 0
! If ray is going downward find the hit point on the ground plane if the receiving point
! is above ground level; note that GroundLevelZ is <= 0.0
IF(RayVec(3) < 0.0d0 .AND. SolReflRecSurf(RecSurfNum)%RecPt(3,RecPtNum) > GroundLevelZ) THEN
! Ray hits ground
Alfa = ACOS(-RayVec(3))
Beta = ATAN2(RayVec(2),RayVec(1))
HorDis = (RecPt(3)-GroundLevelZ)*TAN(Alfa)
GroundHitPt(3) = GroundLevelZ
GroundHitPt(1) = RecPt(1) + HorDis*COS(Beta)
GroundHitPt(2) = RecPt(2) + HorDis*SIN(Beta)
SolReflRecSurf(RecSurfNum)%HitPt(1:3,RecPtNum,RayNum) = GroundHitPt(1:3)
SolReflRecSurf(RecSurfNum)%HitPtSurfNum(RecPtNum,RayNum) = -1
SolReflRecSurf(RecSurfNum)%RecPtHitPtDis(RecPtNum,RayNum) = (RecPt(3)-GroundLevelZ)/(-RayVec(3))
SolReflRecSurf(RecSurfNum)%HitPtSolRefl(RecPtNum,RayNum) = GndReflectance
SolReflRecSurf(RecSurfNum)%HitPtNormVec(1,RecPtNum,RayNum) = 0.0d0
SolReflRecSurf(RecSurfNum)%HitPtNormVec(2,RecPtNum,RayNum) = 0.0d0
SolReflRecSurf(RecSurfNum)%HitPtNormVec(3,RecPtNum,RayNum) = 1.0d0
END IF ! End of check if ray hits ground
END IF ! End of check if obstruction hit
END DO ! End of RayNum loop
END DO ! End of receiving point loop
END DO ! End of receiving surface loop
RETURN
END SUBROUTINE InitSolReflRecSurf