3 use params_mod, only : dp
8 public :: tuv_radfld, sundis, calc_zenith
10 integer :: nstr = 1 ! stream count
14 SUBROUTINE tuv_radfld( nlambda_start, cld_od_opt, cldfrac, nlyr, nwave, &
16 aircol, o2col, o3col, so2col, no2col, &
17 tauaer300, tauaer400, tauaer600, tauaer999, &
18 waer300, waer400, waer600, waer999, &
19 gaer300, gaer400, gaer600, gaer999, &
20 dtaer, omaer, gaer, dtcld, omcld, gcld, &
21 has_aer_ra_feedback, &
22 qll, dobsi, o3_xs, no2_xs, o2_xs, &
23 so2_xs, wmin, wc, tlev, srb_o2_xs, radfld, efld, &
26 dir_fld, dwn_fld, up_fld, dt_cld, tuv_diags )
28 dir_fld, dwn_fld, up_fld, dt_cld )
30 !-----------------------------------------------------------------------------
31 ! ... calculate the radiation field
32 !-----------------------------------------------------------------------------
34 use srb, only : la_srb
35 use rad_trans, only : rtlink
37 !-----------------------------------------------------------------------------
39 !-----------------------------------------------------------------------------
40 integer, intent(in) :: nlambda_start
41 integer, intent(in) :: nlyr
42 integer, intent(in) :: nwave
43 integer, intent(in) :: cld_od_opt
44 real, intent(in) :: zenith
45 real, intent(in) :: dobsi
46 real, intent(in) :: wmin
47 real, intent(in) :: z(:)
48 real, intent(in) :: albedo(:)
49 real, intent(in) :: aircol(:)
50 real, intent(in) :: o2col(:)
51 real, intent(in) :: o3col(:)
52 real, intent(in) :: so2col(:)
53 real, intent(in) :: no2col(:)
54 real, intent(in) :: tauaer300(:)
55 real, intent(in) :: tauaer400(:)
56 real, intent(in) :: tauaer600(:)
57 real, intent(in) :: tauaer999(:)
58 real, intent(in) :: waer300(:)
59 real, intent(in) :: waer400(:)
60 real, intent(in) :: waer600(:)
61 real, intent(in) :: waer999(:)
62 real, intent(in) :: gaer300(:)
63 real, intent(in) :: gaer400(:)
64 real, intent(in) :: gaer600(:)
65 real, intent(in) :: gaer999(:)
66 real, intent(in) :: qll(:)
67 real, intent(in) :: wc(:)
68 real, intent(in) :: tlev(:)
69 real, intent(in) :: cldfrac(:)
70 real, intent(in) :: o2_xs(:)
71 real, intent(in) :: so2_xs(:)
72 real, intent(in) :: o3_xs(:,:)
73 real, intent(in) :: no2_xs(:,:)
74 real, intent(out) :: srb_o2_xs(:,:)
75 real, intent(out) :: radfld(:,:)
76 real, intent(out) :: efld(:,:)
77 real, intent(inout) :: dir_fld(:,:), dwn_fld(:,:), up_fld(:,:)
78 real, intent(inout) :: e_dir(:,:), e_dn(:,:), e_up(:,:)
79 real, intent(inout) :: dt_cld(:)
80 real, intent(inout) :: dtaer(:,:), omaer(:,:), gaer(:,:)
81 real, intent(inout) :: dtcld(:,:), omcld(:,:), gcld(:,:)
82 logical, intent(in) :: has_aer_ra_feedback
84 logical, intent(in) :: tuv_diags
87 !-----------------------------------------------------------------------------
89 !-----------------------------------------------------------------------------
92 integer :: n_radlev, n_radlevp1
93 integer :: nid(0:nlyr)
94 real :: dtrl(nlyr,nwave)
95 real :: dto2(nlyr,nwave)
96 real :: dto3(nlyr,nwave)
97 real :: dtso2(nlyr,nwave)
98 real :: dtno2(nlyr,nwave)
99 ! real :: dtcld(nlyr,nwave)
100 ! real :: dtaer(nlyr,nwave)
101 real :: dtsnw(nlyr,nwave)
103 ! real :: omcld(nlyr,nwave)
104 ! real :: gcld(nlyr,nwave)
105 ! real :: omaer(nlyr,nwave)
106 ! real :: gaer(nlyr,nwave)
107 real :: omsnw(nlyr,nwave)
108 real :: gsnw(nlyr,nwave)
120 real :: dsdh(0:nlyr,nlyr)
122 n_radlev = size( radfld,dim=2 )
123 n_radlevp1 = n_radlev + 1
137 call odrl( wc, aircol, dtrl )
138 call seto2( o2col, o2_xs, dto2 )
139 call odo3( o3col, o3_xs, dto3, dobsi )
140 call setso2( so2col, so2_xs, dtso2 )
141 call setno2( no2col, no2_xs, dtno2 )
142 !-------------------------------------------------------------
143 ! aerosol optical depths
144 !-------------------------------------------------------------
145 if( has_aer_ra_feedback ) then
146 call setaer( nlambda_start, wc, tauaer300, tauaer400, &
147 tauaer600, tauaer999, waer300, &
148 waer400, waer600, waer999, &
149 gaer300, gaer400, gaer600, &
150 gaer999, dtaer, omaer, gaer )
152 !-------------------------------------------------------------
153 ! cloud optical depths (cloud water units = g/m3)
154 !-------------------------------------------------------------
155 call setcld( nlambda_start, cld_od_opt, z, qll, cldfrac, &
157 dt_cld(:n_radlev) = dtcld(2:n_radlevp1,1)
159 call sphers( nlyr, z, zenith, dsdh, nid )
163 open(unit=33,file='WRF-TUV.dbg.out')
164 write(33,*) 'tuv_radfld: tuv_diags'
165 write(33,'(''nlyr = '',i4)') nlyr
166 write(33,'(''dsdh(1,1) = '',1p,g15.7)') dsdh(1,1)
167 write(33,*) 'dsdh(nlyr,:)'
169 write(33,'(1p,5g15.7)') dsdh(nlyr,n:min(n+4,nlyr))
175 call airmas( nlyr, dsdh, nid, aircol, vcol, scol )
176 call la_srb( nlyr, z, tlev, wmin, &
177 vcol, scol, o2_xs, dto2, srb_o2_xs )
179 do wn = nlambda_start,nwave
181 nstr, nlyr+1, nlyr, nwave, &
182 wn, albedo(wn), zenith, &
189 dtcld, omcld, gcld, &
190 dtaer, omaer, gaer, &
191 dtsnw, omsnw, gsnw, &
193 edir, edn, eup, fdir, fdn, fup, tuv_diags )
195 edir, edn, eup, fdir, fdn, fup )
197 ! radfld(wn,1:nlyr-1) = fdir(2:nlyr) + fdn(2:nlyr) + fup(2:nlyr)
198 ! efld(1:nlyr-1,wn) = edir(2:nlyr) + edn(2:nlyr) + eup(2:nlyr)
199 ! dir_fld(1:nlyr-1,wn) = fdir(2:nlyr)
200 ! dwn_fld(1:nlyr-1,wn) = fdn(2:nlyr)
201 ! up_fld(1:nlyr-1,wn) = fup(2:nlyr)
202 ! e_dir(1:nlyr-1,wn) = edir(2:nlyr)
203 ! e_dn(1:nlyr-1,wn) = edn(2:nlyr)
204 ! e_up(1:nlyr-1,wn) = eup(2:nlyr)
205 radfld(wn,1:n_radlev) = fdir(2:n_radlevp1) + fdn(2:n_radlevp1) + fup(2:n_radlevp1)
206 efld(1:n_radlev,wn) = edir(2:n_radlevp1) + edn(2:n_radlevp1) + eup(2:n_radlevp1)
207 dir_fld(1:n_radlev,wn) = fdir(2:n_radlevp1)
208 dwn_fld(1:n_radlev,wn) = fdn(2:n_radlevp1)
209 up_fld(1:n_radlev,wn) = fup(2:n_radlevp1)
210 e_dir(1:n_radlev,wn) = edir(2:n_radlevp1)
211 e_dn(1:n_radlev,wn) = edn(2:n_radlevp1)
212 e_up(1:n_radlev,wn) = eup(2:n_radlevp1)
215 END SUBROUTINE tuv_radfld
217 SUBROUTINE odrl( wc, aircol, dtrl )
218 !-----------------------------------------------------------------------------*
220 != Compute Rayleigh optical depths as a function of altitude and wavelength =*
221 !-----------------------------------------------------------------------------*
223 != C - REAL, number of air molecules per cm^2 at each specified (O)=*
225 != DTRL - REAL, Rayleigh optical depth at each specified altitude (O)=*
226 != and each specified wavelength =*
227 !-----------------------------------------------------------------------------*
229 !-----------------------------------------------------------------------------*
231 !-----------------------------------------------------------------------------*
232 REAL, intent(in) :: aircol(:)
233 REAL, intent(in) :: wc(:)
234 REAL, intent(out) :: dtrl(:,:)
236 !-----------------------------------------------------------------------------*
238 !-----------------------------------------------------------------------------*
239 INTEGER :: nwave, nlyr
241 REAL :: srayl, wmicrn, xx
244 nlyr = size( aircol )
245 !-----------------------------------------------------------------------------*
246 ! compute Rayleigh cross sections and depths:
247 !-----------------------------------------------------------------------------*
249 !-----------------------------------------------------------------------------*
250 ! Rayleigh scattering cross section from WMO 1985 (originally from
251 ! Nicolet, M., On the molecular scattering in the terrestrial atmosphere:
252 ! An empirical formula for its calculation in the homoshpere, Planet.
253 ! Space Sci., 32, 1467-1468, 1984.
254 !-----------------------------------------------------------------------------*
255 wmicrn = wc(wn)*1.E-3
256 IF( wmicrn <= 0.55 ) THEN
257 xx = 3.6772 + 0.389*wmicrn + 0.09426/wmicrn
261 srayl = 4.02e-28/(wmicrn)**xx
262 !-----------------------------------------------------------------------------*
263 ! alternate (older) expression from
264 ! Frohlich and Shaw, Appl.Opt. v.11, p.1773 (1980).
265 !-----------------------------------------------------------------------------*
266 dtrl(:nlyr,wn) = aircol(:nlyr)*srayl
271 SUBROUTINE odo3( o3col, o3xs, dto3, dobsi )
272 !-----------------------------------------------------------------------------
273 != NAME: Optical Depths of O3
275 != Compute ozone optical depths as a function of altitude and wavelength
276 !-----------------------------------------------------------------------------
278 != O3XS - REAL, molecular absoprtion cross section (cm^2) of O3 at (I)
279 != each specified wavelength and altitude
280 != C - REAL, ozone vertical column increments, molec cm-2, for each (I)
282 != DTO3 - REAL, optical depth due to ozone absorption at each (O)
283 != specified altitude at each specified wavelength
284 !-----------------------------------------------------------------------------
286 !-----------------------------------------------------------------------------
287 ! ... dummy arguments
288 !-----------------------------------------------------------------------------
289 REAL, intent(in) :: dobsi
290 REAL, intent(in) :: o3col(:)
291 REAL, intent(in) :: o3xs(:,:)
292 REAL, intent(inout) :: dto3(:,:)
294 INTEGER :: nlyr, nwave
296 REAL :: dob_at_grnd, scale_fac
298 nwave = size(o3xs,dim=1)
301 if( dobsi == 0. ) then
302 !-----------------------------------------------------------------------------
304 !-----------------------------------------------------------------------------
306 dto3(:nlyr,wn) = o3col(:nlyr) * o3xs(wn,:nlyr)
309 !-----------------------------------------------------------------------------
310 ! scale model o3 column to dobsi
311 !-----------------------------------------------------------------------------
312 dob_at_grnd = sum( o3col(:nlyr) )/2.687e16
313 scale_fac = dobsi/dob_at_grnd
315 dto3(:nlyr,wn) = scale_fac * o3col(:nlyr) * o3xs(wn,:nlyr)
321 SUBROUTINE seto2( o2col, o2xs1, dto2 )
322 !-----------------------------------------------------------------------------
324 != Set up an altitude profile of air molecules. Subroutine includes a
325 != shape-conserving scaling method that allows scaling of the entire
326 != profile to a given sea-level pressure.
327 !-----------------------------------------------------------------------------
329 != CZ - REAL, number of air molecules per cm^2 at each specified (O)
331 !-----------------------------------------------------------------------------
333 !-----------------------------------------------------------------------------
334 ! ... dummy arguments
335 !-----------------------------------------------------------------------------
336 REAL, intent(in) :: o2col(:)
337 REAL, intent(in) :: o2xs1(:)
338 REAL, intent(out) :: dto2(:,:)
340 !-----------------------------------------------------------------------------
341 ! ... local variables
342 !-----------------------------------------------------------------------------
343 INTEGER :: nlyr, nwave
349 !-----------------------------------------------------------------------------
350 ! Assumes that O2 = 20.95 % of air density. If desire different O2
351 ! profile (e.g. for upper atmosphere) then can load it here.
352 !-----------------------------------------------------------------------------
354 dto2(:nlyr,wn) = o2col(:nlyr) * o2xs1(wn)
359 SUBROUTINE setso2( colso2, so2_xs, dtso2 )
360 !-----------------------------------------------------------------------------
362 != Set up an altitude profile of SO2 molecules, and corresponding absorption
363 != optical depths. Subroutine includes a shape-conserving scaling method
364 != that allows scaling of the entire profile to a given overhead SO2
366 !-----------------------------------------------------------------------------
368 != SO2_XS - REAL, molecular absoprtion cross section (cm^2) of O2 at (I)
369 != each specified wavelength
370 != DTSO2 - REAL, optical depth due to SO2 absorption at each (O)
371 != specified altitude at each specified wavelength
372 !-----------------------------------------------------------------------------
374 !-----------------------------------------------------------------------------
375 ! ... dummy arguments
376 !-----------------------------------------------------------------------------
377 REAL, intent(in) :: colso2(:)
378 REAL, intent(in) :: so2_xs(:)
379 REAL, intent(out) :: dtso2(:,:)
381 !-----------------------------------------------------------------------------
382 ! ... local variables
383 !-----------------------------------------------------------------------------
384 integer :: nwave, nlyr
387 nwave = size( so2_xs )
388 nlyr = size( colso2 )
391 dtso2(:nlyr,wn) = colso2(:nlyr)*so2_xs(wn)
394 END SUBROUTINE setso2
396 SUBROUTINE setno2( colno2, no2_xs, dtno2 )
397 !-----------------------------------------------------------------------------
398 != NAME: Optical Depths of no2
400 != Compute no2 optical depths as a function of altitude and wavelength
401 !-----------------------------------------------------------------------------
403 != NO2_XS - REAL, molecular absoprtion cross section (cm^2) of no2 at (I)
404 != each specified wavelength and altitude
405 != COLNO2 - REAL, no2 vertical column increments, molec cm-2, for each (I)
407 != DTNO2 - REAL, optical depth due to no2 absorption at each (O)
408 != specified altitude at each specified wavelength
409 !-----------------------------------------------------------------------------
411 !-----------------------------------------------------------------------------
412 ! ... dummy arguments
413 !-----------------------------------------------------------------------------
414 REAL, intent(in) :: colno2(:)
415 REAL, intent(in) :: no2_xs(:,:)
416 REAL, intent(inout) :: dtno2(:,:)
418 INTEGER :: nlyr, nwave
421 nwave = size(no2_xs,dim=1)
425 dtno2(:nlyr,wn) = colno2(:nlyr) * no2_xs(wn,:nlyr)
428 END SUBROUTINE setno2
430 subroutine setaer( nlambda_start, wc, tauaer300, tauaer400, &
431 tauaer600, tauaer999, &
432 waer300, waer400, waer600, waer999, &
433 gaer300, gaer400, gaer600, gaer999, &
435 !----------------------------------------------------------------------
436 ! The routine is based on aerosol treatment in module_ra_rrtmg_sw.F
438 ! nzlev: number of specified altitude levels in the working grid
439 ! z: specified altitude working grid
440 ! Aerosol optical properties at 300, 400, 600 and 999 nm.
441 ! tauaer300, tauaer400, tauaer600, tauaer999: Layer AODs
442 ! waer300, waer400, waer600, waer999: Layer SSAs
443 ! gaer300, gaer400, gaer600, gaer999: Layer asymmetry parameters
446 ! dtaer: Layer AOD at FTUV wavelengths
447 ! omaer: Layer SSA at FTUV wavelengths
448 ! gaer : Layer asymmetry parameters at FTUV wavelengths
449 !------------------------------------------------------------------------
451 !-----------------------------------------------------------------------------
453 !-----------------------------------------------------------------------------
454 integer, intent(in) :: nlambda_start
455 real, intent(in) :: wc(:)
456 real, intent(in) :: tauaer300(:), tauaer400(:), &
457 tauaer600(:), tauaer999(:)
458 real, intent(in) :: waer300(:), waer400(:), &
459 waer600(:), waer999(:)
460 real, intent(in) :: gaer300(:), gaer400(:), &
461 gaer600(:), gaer999(:)
462 real, intent(out) :: dtaer(:,:), omaer(:,:), gaer(:,:)
464 !-----------------------------------------------------------------------------
466 !-----------------------------------------------------------------------------
467 real, parameter :: thresh = 1.e-9
468 integer :: k, wn, nlyr, nwave
469 real :: ang, slope, wfac
471 nlyr = size(dtaer,dim=1)
472 nwave = size(dtaer,dim=2)
475 do wn = nlambda_start,nwave
476 wfac = wc(wn)*1.e-3 - .6
478 !-----------------------------------------------------------------------------
479 ! use angstrom exponent to calculate aerosol optical depth; wc is in nm.
480 !-----------------------------------------------------------------------------
481 if( tauaer300(k) > thresh .and. tauaer999(k) > thresh ) then
482 ang = log(tauaer300(k)/tauaer999(k))/log(0.999/0.3)
483 dtaer(k,wn) = tauaer400(k)*(0.4/(wc(wn)*1.e-3))**ang
484 !-----------------------------------------------------------------------------
485 ! ssa - use linear interpolation/extrapolation
486 !-----------------------------------------------------------------------------
487 slope = 5.*(waer600(k) - waer400(k))
488 omaer(k,wn) = slope*wfac + waer600(k)
489 omaer(k,wn) = max( .4,min( 1.,omaer(k,wn) ) )
490 !-----------------------------------------------------------------------------
491 ! asymmetry parameter - use linear interpolation/extrapolation
492 !-----------------------------------------------------------------------------
493 slope = 5.*(gaer600(k) - gaer400(k))
494 gaer(k,wn) = slope*wfac + gaer600(k)
495 gaer(k,wn) = max( .5,min( 1.,gaer(k,wn) ) )
500 end subroutine setaer
502 subroutine setcld( nlambda_start, cld_od_opt, z, xlwc, cldfrac, &
504 !-----------------------------------------------------------------------------
506 != Set up cloud optical depth, single albedo and g
507 !-----------------------------------------------------------------------------
510 != NZ - INTEGER, number of specified altitude levels in the working (I)
512 != Z - real(dp), specified altitude working grid (km) (I)
513 != XLWC Cloud water content g/M3 (I)
515 != dtcld - cloud optical depth
516 != omcld - cloud droplet single albedo
518 !-----------------------------------------------------------------------------
520 ! VERTICAL DOMAIN is from bottom(1) to TOP (TOP=nz)
521 ! CCM from top(1) to bottom(nz)
522 !-----------------------------------------------------------------------------
524 !-----------------------------------------------------------------------------
525 ! ... Dummy arguments
526 !-----------------------------------------------------------------------------
527 integer, intent(in) :: nlambda_start
528 integer, intent(in) :: cld_od_opt
529 real, intent(in) :: z(:)
530 real, intent(in) :: xlwc(:)
531 real, intent(in) :: cldfrac(:)
532 real, intent(inout) :: dtcld(:,:)
533 real, intent(inout) :: omcld(:,:)
534 real, intent(inout) :: gcld(:,:)
535 !-----------------------------------------------------------------------------
536 ! ... Local variables
537 !-----------------------------------------------------------------------------
538 real, parameter :: km2m = 1.e3 ! kilometer to meter
539 real, parameter :: wden = 1.e6 ! g/m3 (1 m3 water = 1e6 g water)
540 real, parameter :: re = 10.0 * 1.e-6 ! assuming cloud drop radius = 10 um to M
541 real, parameter :: fac = 1./(wden*re)
545 integer :: nlyr, nwave
546 real, allocatable :: wrk(:), layer_cldfrac(:)
548 nlyr = size(dtcld,dim=1)
549 nwave = size(dtcld,dim=2)
551 allocate( wrk(nlyr),layer_cldfrac(nlyr),stat=astat )
552 if( astat /= 0 ) then
553 call wrf_error_fatal( 'setcld: failed to allocate wrk' )
556 !-----------------------------------------------------------------------------
557 ! ... calculate optical depth
558 !-----------------------------------------------------------------------------
559 wrk(1:nlyr-1) = (z(2:nlyr) - z(1:nlyr-1))*km2m ! (km -> m)
560 wrk(1:nlyr-1) = 1.5 * .5*(xlwc(1:nlyr-1) + xlwc(2:nlyr))*wrk(1:nlyr-1)*fac
561 wrk(1:nlyr-1) = max( wrk(1:nlyr-1),0. )
562 if( cld_od_opt == 2 ) then
563 layer_cldfrac(1:nlyr-1) = .5*(cldfrac(1:nlyr-1) + cldfrac(2:nlyr))
564 wrk(1:nlyr-1) = wrk(1:nlyr-1)*layer_cldfrac(1:nlyr-1)*sqrt( layer_cldfrac(1:nlyr-1) )
566 !----------------------------------------------------
567 ! ....calculate cloud optical depth T
568 ! following Liao et al. JGR, 104, 23697, 1999
569 !----------------------------------------------------
570 if( any( wrk(1:nlyr-1) > 0. ) ) then
571 do wn = nlambda_start,nwave
572 dtcld(1:nlyr-1,wn) = wrk(1:nlyr-1)
573 omcld(1:nlyr-1,wn) = .9999
574 gcld (1:nlyr-1,wn) = .85
578 if( allocated( wrk ) ) then
581 if( allocated( layer_cldfrac ) ) then
582 deallocate( layer_cldfrac )
585 end subroutine setcld
587 REAL FUNCTION sundis( julday )
588 !-----------------------------------------------------------------------------
590 ! calculate earth-sun distance variation for a given date. based on
591 ! fourier coefficients originally from: spencer, j.w., 1971, fourier
592 ! series representation of the position of the sun, search, 2:172
593 !-----------------------------------------------------------------------------
595 ! idate - integer, specification of the date, from yymmdd (i)
596 ! esrm2 - real(dp), variation of the earth-sun distance (o)
597 ! esrm2 = (average e/s dist)^2 / (e/s dist on day idate)^2
598 !-----------------------------------------------------------------------------
602 !-----------------------------------------------------------------------------
603 ! ... dummy arguments
604 !-----------------------------------------------------------------------------
605 integer, intent(in) :: julday
607 !-----------------------------------------------------------------------------
608 ! ... local variables
609 !-----------------------------------------------------------------------------
610 real(dp), parameter :: pi = 3.1415926_dp
612 real(dp) :: dayn, thet0
613 real(dp) :: sinth, costh, sin2th, cos2th
615 !-----------------------------------------------------------------------------
616 ! ... parse date to find day number (julian day)
617 !-----------------------------------------------------------------------------
618 dayn = real(julday - 1,kind=dp) + .5_dp
619 !-----------------------------------------------------------------------------
620 ! ... define angular day number and compute esrm2:
621 !-----------------------------------------------------------------------------
622 thet0 = 2._dp*pi*dayn/365._dp
623 !-----------------------------------------------------------------------------
624 ! ... calculate sin(2*thet0), cos(2*thet0) from
625 ! addition theorems for trig functions for better
626 ! performance; the computation of sin2th, cos2th
627 ! is about 5-6 times faster than the evaluation
628 ! of the intrinsic functions sin and cos
629 !-----------------------------------------------------------------------------
632 sin2th = 2._dp*sinth*costh
633 cos2th = costh*costh - sinth*sinth
634 sundis = real( 1.000110_dp + .034221_dp*costh + .001280_dp*sinth &
635 + .000719_dp*cos2th + .000077_dp*sin2th )
639 subroutine calc_zenith( lat, long, julday, gmt, zenith, &
640 its, ite, jts, jte, &
642 !-------------------------------------------------------------------
643 ! this subroutine calculates solar zenith and azimuth angles for a
644 ! part time and location. must specify:
646 ! lat - latitude in decimal degrees
647 ! long - longitude in decimal degrees
648 ! gmt - greenwich mean time - decimal military eg.
649 ! 22.75 = 45 min after ten pm gmt
653 ! .. Scalar Arguments ..
654 !-------------------------------------------------------------------
655 integer, intent(in) :: julday
656 integer, intent(in) :: its,ite
657 integer, intent(in) :: jts,jte
658 integer, intent(in) :: ims,ime
659 integer, intent(in) :: jms,jme
660 real(dp), intent(in) :: gmt
661 real, intent(in) :: lat(ims:ime,jms:jme)
662 real, intent(in) :: long(ims:ime,jms:jme)
663 real, intent(out) :: zenith(ims:ime,jms:jme)
665 !-------------------------------------------------------------------
667 !-------------------------------------------------------------------
668 real(dp), parameter :: d2r = 3.1415926_dp/180.0_dp
669 real(dp), parameter :: r2d = 1.0_dp/d2r
672 real(dp) :: caz, csz, cw, d, ec, epsi, eqt, eyt, feqt, feqt1, &
673 feqt2, feqt3, feqt4, feqt5, feqt6, feqt7, lbgmt, lzgmt, ml, pepsi, &
674 pi, ra, raz, rdecl, reqt, rlt, rml, rra, ssw, sw, tab, w, wr, &
677 d = real(julday,dp) + gmt/24.0_dp
678 !-------------------------------------------------------------------
679 ! calc geom mean longitude
680 !-------------------------------------------------------------------
681 ml = 279.2801988_dp + d*(.9856473354_dp + 2.267E-13_dp*d)
683 !-------------------------------------------------------------------
684 ! calc equation of time in sec
685 ! w = mean long of perigee
687 ! epsi = mean obliquity of ecliptic
688 !-------------------------------------------------------------------
689 w = 282.4932328_dp + d*(4.70684E-5_dp + 3.39E-13_dp*d)
691 ec = 1.6720041E-2_dp - d*(1.1444E-9_dp + 9.4E-17_dp*d)
692 epsi = 23.44266511_dp - d*(3.5626E-7_dp + 1.23E-15_dp*d)
694 yt = (tan(pepsi/2.0_dp))**2
699 feqt1 = -sin(rml)*cw*(eyt + 2._dp*ec)
700 feqt2 = cos(rml)*sw*(2._dp*ec - eyt)
701 feqt3 = sin(2._dp*rml)*(yt - (5._dp*ec**2/4._dp)*(cw**2 - sw**2))
702 feqt4 = cos(2._dp*rml)*(5._dp*ec**2*ssw/4._dp)
703 feqt5 = sin(3._dp*rml)*(eyt*cw)
704 feqt6 = -cos(3._dp*rml)*(eyt*sw)
705 feqt7 = -sin(4._dp*rml)*(.5_dp*yt**2)
706 feqt = feqt1 + feqt2 + feqt3 + feqt4 + feqt5 + feqt6 + feqt7
707 eqt = feqt*13751.0_dp
709 !-------------------------------------------------------------------
710 ! convert eq of time from sec to deg
711 !-------------------------------------------------------------------
713 !-------------------------------------------------------------------
714 ! calc right ascension in rads
715 !-------------------------------------------------------------------
718 !-------------------------------------------------------------------
719 ! calc declination in rads, deg
720 !-------------------------------------------------------------------
721 tab = 0.43360_dp*sin(rra)
725 !-------------------------------------------------------------------
726 ! calc local hour angle
727 !-------------------------------------------------------------------
728 lbgmt = 12.0_dp - eqt/3600._dp + real(long(i,j),dp)*24._dp/360._dp
729 lzgmt = 15.0_dp*(gmt - lbgmt)
731 rlt = real(lat(i,j),dp)*d2r
732 csz = sin(rlt)*sin(rdecl) + cos(rlt)*cos(rdecl)*cos(zpt)
733 csz = min( 1._dp,csz )
735 zenith(i,j) = real( zr/d2r,4 )
739 end subroutine calc_zenith
741 SUBROUTINE sphers( nlyr, z, zen, dsdh, nid )
742 !-----------------------------------------------------------------------------
744 != Calculate slant path over vertical depth ds/dh in spherical geometry.
745 != Calculation is based on: A.Dahlback, and K.Stamnes, A new spheric model
746 != for computing the radiation field available for photolysis and heating
747 != at twilight, Planet.Space Sci., v39, n5, pp. 671-683, 1991 (Appendix B)
748 !-----------------------------------------------------------------------------
750 != NZ - INTEGER, number of specified altitude levels in the working (I)
752 != Z - REAL, specified altitude working grid (km) (I)
753 != ZEN - REAL, solar zenith angle (degrees) (I)
754 != DSDH - REAL, slant path of direct beam through each layer crossed (O)
755 != when travelling from the top of the atmosphere to layer i;
756 != DSDH(i,j), i = 0..NZ-1, j = 1..NZ-1
757 != NID - INTEGER, number of layers crossed by the direct beam when (O)
758 != travelling from the top of the atmosphere to layer i;
759 != NID(i), i = 0..NZ-1
760 !-----------------------------------------------------------------------------
761 ! This program is free software; you can redistribute it and/or modify
762 ! it under the terms of the GNU General Public License as published by the
763 != Free Software Foundation; either version 2 of the license, or (at your
764 != option) any later version.
765 != The TUV package is distributed in the hope that it will be useful, but
766 != WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBI-
767 != LITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
768 != License for more details.
769 != To obtain a copy of the GNU General Public License, write to:
770 != Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
771 !-----------------------------------------------------------------------------
772 != To contact the authors, please mail to:
773 != Sasha Madronich, NCAR/ACD, P.O.Box 3000, Boulder, CO, 80307-3000, USA
774 != send email to: sasha@ucar.edu
775 !-----------------------------------------------------------------------------
777 use params_mod, only : pi, radius
781 !-----------------------------------------------------------------------------
782 ! ... dummy arguments
783 !-----------------------------------------------------------------------------
784 INTEGER, intent(in) :: nlyr
785 REAL, intent(in) :: zen
786 REAL, intent(in) :: z(:)
788 INTEGER, intent(inout) :: nid(0:nlyr)
789 REAL, intent(inout) :: dsdh(0:nlyr,nlyr)
792 !-----------------------------------------------------------------------------
793 ! ... local variables
794 !-----------------------------------------------------------------------------
795 REAL, parameter :: dr = pi/180.
801 REAL :: ds_dh(1:nlyr)
802 REAL(8) :: zenrad, rpsinz, rj, rjp1, dsj, dhj, ga, gb, sm
804 zenrad = REAL( zen*dr,8 )
805 !-----------------------------------------------------------------------------
806 ! include the elevation above sea level to the radius of the earth:
807 !-----------------------------------------------------------------------------
810 !-----------------------------------------------------------------------------
811 ! from bottom-up to top-down
812 ! note zd is the elevation above earth surface:
813 !-----------------------------------------------------------------------------
814 zd(0:nlyr) = z(nlyr+1:1:-1) - z(1)
816 !-----------------------------------------------------------------------------
818 !-----------------------------------------------------------------------------
821 !-----------------------------------------------------------------------------
822 ! calculate ds/dh of every layer
823 !-----------------------------------------------------------------------------
827 rpsinz = real(re + zd(k),8) * SIN(zenrad)
828 ! IF( zen > 90.0 .AND. rpsinz < real(re,8) ) THEN
829 IF( zen <= 90.0 .or. rpsinz >= real(re,8) ) THEN
830 !-----------------------------------------------------------------------------
831 ! Find index of layer in which the screening height lies
832 !-----------------------------------------------------------------------------
834 IF( zen > 90.0 ) THEN
836 IF( rpsinz < real(zd(j-1) + re,8) .AND. &
837 rpsinz >= real(zd(j) + re,8) ) then
845 ! IF( j == id .AND. id == k .AND. zen > 90.0 ) then
846 IF( j /= id .or. k /= id .or. zen <= 90.0 ) then
851 rj = real(re + zd(jm1),8)
852 rjp1 = real(re + zd(j),8)
853 dhj = zd(jm1) - zd(j)
855 ga = max( rj*rj - rpsinz*rpsinz,0.0_8 )
856 gb = max( rjp1*rjp1 - rpsinz*rpsinz,0.0_8 )
858 IF( id > k .AND. j == id ) THEN
861 dsj = SQRT( ga ) - sm*SQRT( gb )
863 ds_dh(j) = real( dsj/dhj,4 )
873 END SUBROUTINE sphers
875 SUBROUTINE airmas( nlyr, dsdh, nid, cz, vcol, scol )
876 !-----------------------------------------------------------------------------
878 != Calculate vertical and slant air columns, in spherical geometry, as a
879 != function of altitude.
880 !-----------------------------------------------------------------------------
882 != NZ - INTEGER, number of specified altitude levels in the working (I)
884 != DSDH - REAL, slant path of direct beam through each layer crossed (O)
885 != when travelling from the top of the atmosphere to layer i;
886 != DSDH(i,j), i = 0..NZ-1, j = 1..NZ-1
887 != NID - INTEGER, number of layers crossed by the direct beam when (O)
888 != travelling from the top of the atmosphere to layer i;
889 != NID(i), i = 0..NZ-1
890 != VCOL - REAL, output, vertical air column, molec cm-2, above level iz
891 != SCOL - REAL, output, slant air column in direction of sun, above iz
892 != also in molec cm-2
893 !-----------------------------------------------------------------------------
895 use params_mod, only : largest
899 !-----------------------------------------------------------------------------
900 ! ... dummy arguments
901 !-----------------------------------------------------------------------------
902 INTEGER, intent(in) :: nlyr
903 INTEGER, intent(in) :: nid(0:nlyr)
904 REAL, intent(in) :: dsdh(0:nlyr,nlyr)
905 REAL, intent(in) :: cz(nlyr)
907 REAL, intent(inout) :: vcol(nlyr), scol(nlyr)
909 !-----------------------------------------------------------------------------
910 ! ... local variables
911 !-----------------------------------------------------------------------------
912 INTEGER :: lyr, j, nlev, nlevi
915 !-----------------------------------------------------------------------------
916 ! calculate vertical and slant column from each level: work downward
917 !-----------------------------------------------------------------------------
922 vsum = vsum + cz(nlevi)
925 IF( nid(lyr) < 0 ) THEN
928 !-----------------------------------------------------------------------------
929 ! single pass layers:
930 !-----------------------------------------------------------------------------
931 DO j = 1, MIN(nid(lyr), lyr)
932 sum = sum + cz(nlev-j)*dsdh(lyr,j)
934 !-----------------------------------------------------------------------------
935 ! double pass layers:
936 !-----------------------------------------------------------------------------
937 DO j = MIN(nid(lyr),lyr)+1, nid(lyr)
938 sum = sum + 2.*cz(nlev-j)*dsdh(lyr,j)
944 END SUBROUTINE airmas