1 module module_ra_eclipse
5 !--------------------------------------------
6 ! Solar eclipse prediction moduel
8 ! Alex Montornes and Bernat Codina. University of Barcelona. 2015
10 ! Based on Montornes A., Codina B., Zack J., Sola, Y.: Implementation of the
11 ! Bessel's method for solar eclipses prediction in the WRF-ARW model. 2015
13 ! This key point of this subroutine is the evaluation of the degree of obscuration,
14 ! i.e. the part of the solar disk that is hidden by the Moon. This variable is
15 ! introduced in the SW schemes and used as a correction of the incoming radiation.
16 ! In other words, if obscur is the part of the solar disk hidden by the Moon, then
17 ! (1-obscur) is the part of the solar disk emitting radiation.
19 ! Note that if obscur = 0., then we recover the standard code
21 !----------------------------
24 ! amontornes 2015/09 First implementation
26 !----------------------------
29 subroutine solar_eclipse(ims,ime,jms,jme,its,ite,jts,jte, &
30 julian,gmt,year,xtime,radt, &
31 degrad,xlon,xlat,Obscur,mask, &
32 elat_track,elon_track,sw_eclipse )
33 !-------------------------------------------------------------
46 integer, intent(in) :: ims,ime,jms,jme, &
49 real, intent(in) :: gmt,degrad,julian,xtime,radt
50 integer, intent(in) :: year
51 ! Geographical information
52 real, dimension(ims:ime,jms:jme), intent(in) :: xlat,xlon
53 real, dimension(ims:ime,jms:jme), intent(inout) :: Obscur
55 integer, dimension(ims:ime,jms:jme), intent(inout) :: mask
56 real, intent(inout) :: elat_track,elon_track
57 ! Namelist option 1 - enabled / 0 - disabled
58 integer, intent(in) :: sw_eclipse
65 real, parameter :: pi = 3.1415926535897932384626433
66 real, parameter :: epsil = 0.0818192 ! Earth excentricity
68 ! Besseliam elements from file eclipse_besselian_elements.dat
69 ! X, Y :: coordinates of the eclipse's axis in the fundamental plane
70 ! d, mu :: declination and azimuth (deg)
71 ! l1, l2 :: radii of the penumbra and umbra regions in the fundamental
73 ! tanf1, tanf2 :: angle of the shadow's conus
74 ! t0, min, max :: time when the Besselian elements are valid
75 ! Dt :: time correction
76 integer, parameter :: NBessel = 4 ! Dimension
77 real, dimension(NBessel) :: X, Y, d, l1, l2, mu
78 real :: tanf1, tanf2, t0, tmin, tmax, Dt
83 ! Besselian elements at the current time t1
84 real :: cx, cy, cd, cl1, cl2, cmu
86 ! Current time t1, and hourly angle H
90 ! Latitude and longitude in radians
94 ! Geocentric coordinates
96 real :: cos_lat1, sin_lat1 ! cos/sin of the corrected latitude
97 real :: xi, eta1, zeta1 ! Geocentric coordinates at the observation point
100 real :: DELTA, DELTA2 ! Distance of the observation point
101 ! to the eclipse axis
102 real :: LL1, LL2 ! Penumbra and Umbra radius
103 ! from the point observer's plane
104 logical :: eclipse_exist
115 real :: E, E_1, tan_rd1, rd1, rho1, cy1, tan_gamma, cgamma, sin_beta, &
116 tan_C, C, cm, tan_lat1, tan_lat, sin_H, &
117 cos_H, tan_H, beta, lon, tan_rd2, rd2, rho2
138 ! Check if the eclipse is enabled by the namelist.input
139 ! If eclipse is not enabled -> set eclipse variables to zero and nothing to do
140 if(sw_eclipse .eq. 0) then
150 xt24 = mod(xtime+radt,1440.)
152 julday = int(julian)+1
158 ! Check if the eclipse exists for the current simulation date
159 eclipse_exist = .false.
161 ! and load the besselian elements
162 ! Note: eclipse_besselian_elements.dat should be in the running directory!
163 call load_besselian_elements(t1, julday, year, X, Y, d, l1, l2, mu, &
164 tanf1, tanf2, t0, tmin, tmax, NBessel, &
168 ! If the eclipse does not exist, then we set all the output vars to zero and finish
169 if(.not. eclipse_exist) then
178 ! Compute the besselian elements at t1
179 call compute_besselian_t(t1, NBessel, X, Y, d, l1, l2, mu, t0, Dt, &
180 cx, cy, cd, cl1, cl2, cmu)
183 ! Convert the beselian elements from deg to radians
187 !---------------------------
188 ! STEP 1: Compute the eclipse track. This is just a diagnosis for the user
194 !-- Compute the excentricity correction
195 E = sqrt(1 - epsil**2)
198 tan_rd1 = E_1 * tan(rd)
201 rho1 = sin(rd)/sin(rd1)
205 tan_rd2 = E * tan(rd)
208 rho2 = cos(rd)/cos(rd2)
211 cgamma = atan(tan_gamma)
213 sin_beta = cx/sin(cgamma)
215 !-- If |sin(beta)|>1 then the axis of the eclipse is tangent to the Earth's
216 ! surface or directly it does not crosses the Earth.
217 if(abs(sin_beta) .lt. 1) then
218 beta = asin(sin_beta)
220 tan_C = cy1 / cos(beta)
225 sin_lat1 = cm * sin(C + rd1)
226 cos_lat1 = sqrt(1 - sin_lat1**2)
227 tan_lat1 = sin_lat1/cos_lat1
228 !-- Convert to geographic latitude
229 tan_lat = E_1 * tan_lat1
230 elat_track= atan(tan_lat)/degrad
231 !-- Compute the hourly angle
232 sin_H = cx / cos_lat1
233 cos_H = cm * cos(C+rd1)/cos_lat1
237 if(cos_H .lt. 0) then
238 if(sin_H .ge. 0) then
244 !-- Compute the longitude
245 elon_track= (rmu - H)/degrad
246 !-- Convert to geopgraphic longitude
247 if(elon_track .gt. 360) then
248 elon_track = elon_track -360
250 if(elon_track .gt. 180) then
251 elon_track = elon_track -360
253 if(elon_track .le. -180) then
254 elon_track = elon_track +360
256 !-- Correct the Earth's movement
257 elon_track = -elon_track + 1.002738 * 15*Dt/3600
260 !---------------------------
261 ! STEP 2: Compute the obscuricity for each grid-point. This step it is important
262 ! in order to reduce the incoming radiation
263 ! Loop over latitudes
265 ! Loop over longitudes
267 !--Correct the Earth's movement
268 lon = -xlon(i,j) - 1.002738 * 15*Dt/3600
272 if(lon .gt. 360) then
276 !-- Convert degrees to radians
277 rlat = xlat(i,j)*degrad
283 !-- Adjust the Earth's sphericity
284 A = sqrt( 1 - ( epsil * sin(rlat) )**2 )
287 cos_lat1 = cos(rlat) / A
288 sin_lat1 = sin(rlat) * E / A
290 !-- Geocentric coordinates at the observation point
291 xi = cos_lat1 * sin(H)
292 eta1 = sin_lat1 * cos(rd1) * E - cos_lat1 * sin(rd1) * cos(H)
293 zeta1 = sin_lat1 * sin(rd2) * E + cos_lat1 * cos(rd2) * cos(H)
295 !-- Correct cy (sembla que no es necessari)
298 !-- Distance to the shadow axis
299 DELTA2 = (xi - cx)**2 + (eta1 - cy1)**2;
302 !-- Penumbra and Umbra cone's circumference over the Earth's surface
303 LL1 = (cl1 - zeta1 * tanf1) ! Penumbra
304 LL2 = (cl2 - zeta1 * tanf2) ! Umbra
306 ! Check if we are inside the eclipse
307 if(DELTA .gt. LL1) then ! Without obscuration
310 elseif(DELTA .le. LL1 .and. DELTA .gt. abs(LL2)) then ! Penumbra
311 Obscur(i,j) = (LL1 - DELTA) / (LL1 + LL2) ! Partial eclipse
313 elseif(DELTA .le. abs(LL2)) then ! Umbra
315 Obscur(i,j) = 1. ! Total eclipse
318 Obscur(i,j) = (LL1 - DELTA) / (LL1 + LL2) ! Annular eclipse
323 ! Check that the obscuration is not greater than 1
324 if(Obscur(i,j) .gt. 1) then
329 ! End loop over longitudes
331 ! End loop over longitudes
334 !----------------------------
335 ! INTERNAL SUBROUTINES
336 ! load_besselian_elements --> load the besselian elements from eclipse_besselian_elements.dat
337 ! compute_besselian_t --> compute the besselian elements for the current time
339 !----------------------------
340 subroutine load_besselian_elements(t, julday, year, X, Y, d, l1, l2, mu, &
341 tanf1, tanf2, t0, tmin, tmax, NBessel, &
354 integer, intent(in) :: julday, year, NBessel
355 real, intent(in) :: t
356 logical, intent(inout) :: eclipse_exist
357 real, dimension(NBessel), intent(inout) :: X, Y, d, l1, l2, mu
358 real, intent(inout) :: tanf1, tanf2, t0, tmin, tmax, Dt
362 integer :: ryear, rjulday
363 logical :: file_exist
368 eclipse_exist = .false.
371 ! Load the information from eclipse_besselian_elements.dat
373 inquire( file="eclipse_besselian_elements.dat", exist=file_exist)
375 open (20,FILE='eclipse_besselian_elements.dat',status="old",action="read")
377 call wrf_error_fatal('load_besselian_elements: eclipse_besselian_elements.dat not found')
382 ! Load the list of eclipse features
383 read(20,*,end=1)ryear,rjulday,t0,tmin,tmax, &
384 X(1), X(2), X(3), X(4), &
385 Y(1), Y(2), Y(3), Y(4), &
386 d(1), d(2), d(3), d(4), &
387 l1(1),l1(2),l1(3),l1(4), &
388 l2(1),l2(2),l2(3),l2(4), &
389 mu(1),mu(2),mu(3),mu(4), &
391 ! Check if the current date matches with the loaded episode
392 if(ryear .eq. year .and. rjulday .eq. julday .and. tmin .le. t .and. t .le. tmax) then
393 eclipse_exist = .true.
402 !----------------------------
403 !----------------------------
404 !----------------------------
405 subroutine compute_besselian_t(t1, NBessel, X, Y, d, l1, l2, mu, t0, Dt, &
406 cx, cy, cd, cl1, cl2, cmu)
408 integer, intent(in) :: NBessel
409 real, intent(in) :: t1
410 real, dimension(NBessel), intent(in) :: X, Y, d, l1, l2, mu
411 real, intent(in) :: t0, Dt
412 real, intent(inout) :: cx, cy, cd, cl1, cl2, cmu
424 t = (t1 + DT/3600) - t0
427 cx = cx + X(i) * t**(i-1)
428 cy = cy + Y(i) * t**(i-1)
429 cd = cd + d(i) * t**(i-1)
430 cl1 = cl1 + l1(i) * t**(i-1)
431 cl2 = cl2 + l2(i) * t**(i-1)
432 cmu = cmu + mu(i) * t**(i-1)
436 !----------------------------
437 !----------------------------
439 end module module_ra_eclipse