-
Kyle Klenk (kck540) authoredKyle Klenk (kck540) authored
sunGeomtry.f90 9.41 KiB
! SUMMA - Structure for Unifying Multiple Modeling Alternatives
! Copyright (C) 2014-2020 NCAR/RAL; University of Saskatchewan; University of Washington
!
! This file is part of SUMMA
!
! For more information see: http://www.ral.ucar.edu/projects/summa
!
! This program is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! This program is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program. If not, see <http://www.gnu.org/licenses/>.
MODULE sunGeomtry_module
USE nrtype
implicit none
private
public::clrsky_rad
contains
! *************************************************************************************************
! public subroutine CLRSKY_RAD: get hourly radiation index
! *************************************************************************************************
SUBROUTINE CLRSKY_RAD(MONTH,DAY,HOUR,DT,SLOPE,AZI,LAT,HRI,COSZEN)
! ----------------------------------------------------------------------------------------
! Used to get hourly radiation index
!
! Modification history
! - comments added by David Rupp 2006.
!
! Procedure appears similar to Stull(1988) "An Introduction to Boundary Layer
! Meteorology " as seen in matlab routine obtained from Joe Kidston <joekidston@yahoo.co.uk>.
! Note that equation of time is not used. Also, solar declination is assumed to stay
! constant over the period of one day. What other assumptions are made? Is this
! adequate for the level of precision we require? Worth reading Stull(1988).
!
! - Modified to integrate over time step up to, but not greater than, 24 hours (D. Rupp, July 2006)
!
! ----------------------------------------------------------------------------------------
IMPLICIT NONE
! Input variables
INTEGER(I4B), INTENT(IN) :: MONTH ! month as mm integer
INTEGER(I4B), INTENT(IN) :: DAY ! day of month as dd integer
REAL(DP), INTENT(IN) :: HOUR ! hour of day as real
REAL(DP), INTENT(IN) :: DT ! time step in units of hours
REAL(DP), INTENT(IN) :: SLOPE ! slope of ground surface in degrees
REAL(DP), INTENT(IN) :: AZI ! aspect (azimuth) of ground surface in degrees
REAL(DP), INTENT(IN) :: LAT ! latitude in degrees (negative for southern hemisphere)
! Outputs
REAL(DP), INTENT(OUT) :: HRI ! average radiation index over time step DT
REAL(DP), INTENT(OUT) :: COSZEN ! average cosine of the zenith angle over time step DT
! Internal
REAL(DP) :: CRAD ! conversion from degrees to radians
REAL(DP) :: YRAD ! conversion from year to radians
REAL(DP) :: T ! time from noon in radians
REAL(DP) :: DELT1 ! time step in radians
REAL(DP) :: SLOPE1 ! slope of ground surface in radians
REAL(DP) :: AZI1 ! aspect (azimuth) of ground surface in radians
REAL(DP) :: LAT1 ! latitude in radians
REAL(DP) :: FJULIAN ! julian date as real
REAL(DP) :: D ! solar declination
REAL(DP) :: LP ! latitude adjusted for non-level surface (= LAT1 for level surface)
REAL(DP) :: TD ! used to calculate sunrise/set
REAL(DP) :: TPI ! used to calculate sunrise/set
REAL(DP) :: TP ! used to calculate sunrise/set
REAL(DP) :: DDT ! used to calculate sunrise/set(= 0 for level surface)
REAL(DP) :: T1 ! first time in time step or sunrise
REAL(DP) :: T2 ! last time in time step or sunset
REAL(DP) :: AUX ! Auxiliary variable used to check whether the sunset/sunrise time calculation can succeed
! ----------------------------------------------------------------------------------------
! CONVERSION FACTORS
! degrees to radians
CRAD=PI_D/180.0D0
! days-of-year to radians
YRAD=2.0D0*PI_D/365.0D0
! CONVERT TIME TO RADIANS FROM NOON
T=(HOUR-12.0)*PI_D/12.0D0
! Convert time step to radians
DELT1=DT*PI_D/12.0D0
! CONVERT ground slope, ground aspect, and latitude TO RADIANS
SLOPE1=SLOPE*CRAD ! tilt angle
AZI1=AZI*CRAD ! surface-solar Azimuth ??
LAT1=LAT*CRAD ! latitude
! Calculate julian date
FJULIAN=dble(JULIAN(MONTH,DAY))
! Calculate solar declination
D=CRAD*23.5*SIN((FJULIAN-82.0)*YRAD)
! Calculate latitude "adjustment" for ground slope, aspect and latitude (LP = LAT1 for level surface)
LP=ASIN(SIN(SLOPE1)*COS(AZI1)*COS(LAT1) + COS(SLOPE1)*SIN(LAT1)) ! angle between solar rays and surface (tilted) ??
! Calculate time of sunrise/sunset on level surface as radians from noon
! Account for high latitude locations, where there might not be a sunrise/sunset time on a given day
! In such cases AUX > 1 or AUX < -1. Fix AUX at (-)1 in those cases, to fix sunrise at 00.00 or 24.00 of the current day (instead of some time before/after the current day)
AUX=-TAN(LAT1)*TAN(D)
IF(abs(AUX) > 1.) THEN
TD=ACOS(SIGN(1._dp, AUX))
ELSE
TD=ACOS(AUX)
END IF
! print *, 'Sunrise = ', TD
! Calculate time of sunrise/sunset adjusted for inclined ground surface as radians from noon???
TPI=-TAN(LP)*TAN(D)
IF(ABS(TPI).LT.1.0) THEN
TP=ACOS(TPI)
ELSE
TP=0.0
ENDIF
! Calculate time adjustment for ground slope, aspect and latitude (DDT = 0 for level surface)
DDT=ATAN(SIN(AZI1)*SIN(SLOPE1)/(COS(SLOPE1)*COS(LAT1)-COS(AZI1)*SIN(SLOPE1)*SIN(LAT1)))
! print*, 'ddt = ', ddt
! Set beginning time of time step (set to sunrise if before sunrise)
T1=MAX(T,-TP-DDT,-TD)
! Set end time of time step (adjust if after sunset)
T2=MIN(T+DELT1,TD,TP-DDT)
! print *, 'First t1 and t2 = ', t1, t2
IF(T2.LE.T1) THEN
HRI=0.0 ! nighttime
ELSE
! Calculate integral of radiation index from T1 to T2 and divide by time step DELTA1
! NOTE: this assumes the declination does not change from T1 to T2
HRI=(SIN(D)*SIN(LP)*(T2-T1)+COS(D)*COS(LP)*(SIN(T2+DDT) &
-SIN(T1+DDT)))/(COS(SLOPE1)*DELT1) ! radiation index
ENDIF
! print *, hri
! ----------------- for time intervals that extend to following day ----------------------
! Check to see of timestep extends to following day
IF((T+DELT1).GT.PI_D) THEN
! Advance julian day by 1
FJULIAN = FJULIAN + 1
! Calculate solar declination
D=CRAD*23.5*SIN((FJULIAN-82.0)*YRAD)
! Calculate time of sunrise/sunset on level surface as radians from noon
! Account for high latitude locations, where there might not be a sunrise/sunset time on a given day
! In such cases AUX > 1 or AUX < -1. Fix AUX at (-)1 in those cases
AUX=-TAN(LAT1)*TAN(D)
IF(abs(AUX) > 1.) THEN
TD=ACOS(SIGN(1._dp, AUX))
ELSE
TD=ACOS(AUX)
END IF
! print *, 'Sunrise #2 = ', TD, DELT1
! Calculate time of sunrise/sunset adjusted for inclined ground surface as radians from noon???
TPI=-TAN(LP)*TAN(D)
IF(ABS(TPI).LT.1.0) THEN
TP=ACOS(TPI)
ELSE
TP=0.0
ENDIF
! Set beginning time to sunrise
T1=MAX(-TP-DDT,-TD)
! Set end time of time step
T2=MIN(T+DELT1-2*PI_D,TD,TP-DDT)
! print *, 'Second t1 and t2 = ', t1, t2
IF(T2.LE.T1) THEN
HRI=HRI ! still nighttime in day 2
ELSE
! Calculate integral of radiation index from T1 to T2 and divide by time step DELTA1
! NOTE: this assumes the declination does not change from T1 to T2
HRI=HRI+(SIN(D)*SIN(LP)*(T2-T1)+COS(D)*COS(LP)*(SIN(T2+DDT) &
-SIN(T1+DDT)))/(COS(SLOPE1)*DELT1) ! radiation index
ENDIF
! print *, hri
ENDIF
! ----------------------------------------------------------------------------------------
! Calculate cosine of solar zenith angle (= HRI for level surface)
COSZEN = HRI*COS(SLOPE1)
! this is assumed to be an appropriate representative value over the
! time step. It is used for albedo calculations.
! ----------------------------------------------------------------------------------------
CONTAINS
! *************************************************************************************************
! internal function JULIAN: calculate day of year
! *************************************************************************************************
FUNCTION JULIAN(MONTH,DAY)
USE nrtype
IMPLICIT NONE
! input
INTEGER(I4B) :: MONTH,DAY ! month and day
! output
INTEGER(I4B) :: JULIAN ! julian day
! internal
INTEGER(I4B),DIMENSION(12) :: MADD ! julian day at start of each month
! specify the julian day at the start of each month (-1)
MADD = (/0,31,59,90,120,151,181,212,243,273,304,334/)
! compute the julian day
JULIAN=DAY+MADD(MONTH)
RETURN
END FUNCTION JULIAN
! ----------------------------------------------------------------------------------------
END SUBROUTINE CLRSKY_RAD
end module sunGeomtry_module