1 !=============================================================================
2 ! This file contains the following subroutines, related to the calculation
3 ! of radiation at Lyman-alpha and Schumann-Runge wavelengths:
11 ! and the following functions
13 !=============================================================================
20 public :: la_srb, sjo2, init_srb
21 public :: nchebev_term, nchebev_wave
22 public :: chebev_ac, chebev_bc
25 INTEGER, parameter :: kla = 2
26 INTEGER, PARAMETER :: ksrb = 18
27 integer, parameter :: nla = kla - 1
28 integer, parameter :: nsrb = ksrb - 1
30 integer :: nchebev_term, nchebev_wave
33 REAL(8) :: b(3), c(3), d(3), e(3)
34 REAL(8), allocatable :: chebev_ac(:,:)
35 REAL(8), allocatable :: chebev_bc(:,:)
45 b(:) = (/ 6.8431e-01_8, 2.29841e-01_8, 8.65412e-02_8 /)
46 c(:) = (/ 8.22114e-21_8, 1.77556e-20_8, 8.22112e-21_8 /)
47 d(:) = (/ 6.0073e-21_8, 4.28569e-21_8, 1.28059e-20_8 /)
48 e(:) = (/ 8.21666e-21_8, 1.63296e-20_8, 4.85121e-17_8 /)
49 xslod(:) = (/6.2180730E-21, 5.8473627E-22, 5.6996334E-22, &
50 4.5627094E-22, 1.7668250E-22, 1.1178808E-22, &
51 1.2040544E-22, 4.0994668E-23, 1.8450616E-23, &
52 1.5639540E-23, 8.7961075E-24, 7.6475608E-24, &
53 7.6260556E-24, 7.5565696E-24, 7.6334338E-24, &
54 7.4371992E-24, 7.3642966E-24 /)
55 wlla(:) = (/ 121.4, 121.9/)
56 wlsrb(:) = (/174.4, 177.0, 178.6, 180.2, 181.8, &
57 183.5, 185.2, 186.9, 188.7, 190.5, &
58 192.3, 194.2, 196.1, 198.0, 200.0, &
61 END SUBROUTINE init_srb
63 SUBROUTINE la_srb( nlyr, z, tlev, wmin, &
64 vcol, scol, o2_xs, dto2, srb_o2_xs )
65 !-----------------------------------------------------------------------------
67 != Compute equivalent optical depths for O2 absorption, and O2 effective
68 != absorption cross sections, parameterized in the Lyman-alpha and SR bands
69 !-----------------------------------------------------------------------------
71 != NZ - INTEGER, number of specified altitude levels in the working (I)
73 != Z - REAL, specified altitude working grid (km) (I)
74 != NW - INTEGER, number of specified intervals + 1 in working (I)
76 != WL - REAL, vector of lxower limits of wavelength intervals in (I)
77 != working wavelength grid
78 != CZ - REAL, number of air molecules per cm^2 at each specified (I)
80 != ZEN - REAL, solar zenith angle (I)
82 != O2XS1 - REAL, O2 cross section from rdo2xs (I)
84 != DTO2 - REAL, optical depth due to O2 absorption at each specified (O)
85 != vertical layer at each specified wavelength
86 != O2XS - REAL, molecular absorption cross section in SR bands at (O)
87 != each specified altitude and wavelength. Includes Herzberg
89 !-----------------------------------------------------------------------------
91 use params_mod, only : o2vmr, largest
93 !-----------------------------------------------------------------------------
95 !-----------------------------------------------------------------------------
96 INTEGER, intent(in) :: nlyr
97 REAL, intent(in) :: wmin
98 REAL, intent(in) :: z(:)
99 REAL, intent(in) :: tlev(:)
101 REAL, intent(in) :: vcol(:)
102 REAL, intent(in) :: scol(:)
103 REAL, intent(in) :: o2_xs(:)
104 REAL, intent(inout) :: dto2(:,:)
105 REAL, intent(inout) :: srb_o2_xs(:,:)
107 !-----------------------------------------------------------------------------
108 ! ... local variables
109 !-----------------------------------------------------------------------------
113 !-----------------------------------------------------------------------------
114 ! Lyman-alpha variables
115 ! O2 optical depth and equivalent cross section in the Lyman-alpha region
116 !-----------------------------------------------------------------------------
120 REAL :: dto2la(nlyr,nla), o2xsla(nlyr,nla)
122 !-----------------------------------------------------------------------------
123 ! grid on which Koppers' parameterization is defined
124 ! O2 optical depth and equivalent cross section on Koppers' grid
125 !-----------------------------------------------------------------------------
126 REAL :: dto2k(nlyr,nsrb), o2xsk(nlyr,nsrb)
128 nlev_srb = size( srb_o2_xs,dim=2 )
130 !----------------------------------------------------------------------
131 ! initalize O2 cross sections
132 !----------------------------------------------------------------------
134 srb_o2_xs(:,k) = o2_xs(:)
137 IF( wmin <= wlsrb(nsrb) ) THEN
138 !----------------------------------------------------------------------
139 ! Slant O2 column and x-sections.
140 !----------------------------------------------------------------------
141 o2col(:nlyr) = o2vmr * scol(:nlyr)
142 !----------------------------------------------------------------------
143 ! Effective secant of solar zenith angle.
144 ! Use 2.0 if no direct sun (value for isotropic radiation)
145 ! For nz, use value at nz-1
146 !----------------------------------------------------------------------
147 WHERE( scol(:nlyr) > .1*largest )
150 secchi(:nlyr) = scol(:nlyr)/vcol(:nlyr)
153 !---------------------------------------------------------------------
154 ! Lyman-Alpha parameterization, output values of O2 optical depth
155 ! and O2 effective (equivalent) cross section
156 !----------------------------------------------------------------------
157 CALL lymana( nlyr, o2col, secchi, dto2la, o2xsla )
158 DO wn = ila, ila + nla - 1
160 dto2(:nlyr,wn) = dto2la(:nlyr,iw)
161 srb_o2_xs(wn,:nlev_srb) = o2xsla(2:nlev_srb+1,iw)
164 !------------------------------------------------------------------------------
165 ! Koppers' parameterization of the SR bands, output values of O2
166 ! optical depth and O2 equivalent cross section
167 !------------------------------------------------------------------------------
168 CALL schum( nlyr, o2col, tlev, secchi, dto2k, o2xsk )
169 DO wn = isrb, isrb + nsrb - 1
171 dto2(:nlyr,wn) = dto2k(:nlyr,iw)
172 srb_o2_xs(wn,:nlev_srb) = o2xsk(2:nlev_srb+1,iw)
176 END SUBROUTINE la_srb
178 SUBROUTINE lymana( nlyr, o2col, secchi, dto2la, o2xsla )
179 !-----------------------------------------------------------------------------
181 != Calculate the effective absorption cross section of O2 in the Lyman-Alpha
182 != bands and an effective O2 optical depth at all altitudes. Parameterized
183 != after: Chabrillat, S., and G. Kockarts, Simple parameterization of the
184 != absorption of the solar Lyman-Alpha line, Geophysical Research Letters,
185 != Vol.24, No.21, pp 2659-2662, 1997.
186 !-----------------------------------------------------------------------------
188 != NZ - INTEGER, number of specified altitude levels in the working (I)
190 != O2COL - REAL, slant overhead O2 column (molec/cc) at each specified (I)
192 != DTO2LA - REAL, optical depth due to O2 absorption at each specified (O)
194 != O2XSLA - REAL, molecular absorption cross section in LA bands (O)
195 !-----------------------------------------------------------------------------
198 !-----------------------------------------------------------------------------
199 ! ... dummy arguments
200 !-----------------------------------------------------------------------------
201 INTEGER, intent(in) :: nlyr
202 REAL, intent(in) :: o2col(:)
203 REAL, intent(in) :: secchi(:)
204 REAL, intent(inout) :: dto2la(nlyr,nla), o2xsla(nlyr,nla)
206 !-----------------------------------------------------------------------------
207 ! ... local variables
208 !-----------------------------------------------------------------------------
209 REAL, parameter :: xsmin = 1.e-20
210 REAL(8), parameter :: rmmin = 1.e-100_8
212 INTEGER :: k, kp1, wn
214 REAL(8) :: rm(nlyr), ro2(nlyr)
215 REAL(8) :: rm_wrk(3), ro2_wrk(3)
218 dto2la(:nlyr,wn) = 0.
219 o2xsla(:nlyr,wn) = 0.
221 !-----------------------------------------------------------------------------
222 ! calculate reduction factors at every layer
223 !-----------------------------------------------------------------------------
227 o2_col = real( o2col(k),8 )
228 rm_wrk(:) = b(:) * EXP( -c(:) * o2_col )
229 ro2_wrk(:) = d(:) * EXP( -e(:) * o2_col )
230 rm(k) = sum( rm_wrk )
231 ro2(k) = sum( ro2_wrk )
234 !-----------------------------------------------------------------------------
235 ! calculate effective O2 optical depths and effective O2 cross sections
236 !-----------------------------------------------------------------------------
239 IF (rm(k) > rmmin) THEN
240 IF (ro2(k) > rmmin) THEN
241 o2xsla(k,1) = REAL( ro2(k)/rm(k) )
246 IF (rm(kp1) > 0._8) THEN
247 dto2la(k,1) = LOG( rm(kp1) )/secchi(kp1) &
248 - LOG( rm(k)) /secchi(k)
258 !-----------------------------------------------------------------------------
259 ! do top layer separately
260 !-----------------------------------------------------------------------------
261 IF( rm(nlyr) > rmmin ) THEN
262 o2xsla(nlyr,1) = REAL( ro2(nlyr)/rm(nlyr) )
264 o2xsla(nlyr,1) = xsmin
267 END SUBROUTINE lymana
269 SUBROUTINE schum( nlyr, o2col, tlev, secchi, dto2, o2xsk )
270 !-----------------------------------------------------------------------------
272 != Calculate the equivalent absorption cross section of O2 in the SR bands.
273 != The algorithm is based on parameterization of G.A. Koppers, and
274 != D.P. Murtagh [ref. Ann.Geophys., 14 68-79, 1996]
275 != Final values do include effects from the Herzberg continuum.
276 !-----------------------------------------------------------------------------
278 != NZ - INTEGER, number of specified altitude levels in the working (I)
280 != O2COL - REAL, slant overhead O2 column (molec/cc) at each specified (I)
282 != TLEV - tmeperature at each level
283 != SECCHI - ratio of slant to vertical o2 columns
284 != DTO2 - REAL, optical depth due to O2 absorption at each specified
285 != vertical layer at each specified wavelength
286 != O2XSK - REAL, molecular absorption cross section in SR bands at
287 != each specified wavelength. Includes Herzberg continuum
288 !-----------------------------------------------------------------------------
290 use params_mod, only : precis
292 !-----------------------------------------------------------------------------
293 ! ... dummy arguments
294 !-----------------------------------------------------------------------------
295 INTEGER, intent(in) :: nlyr
296 REAL, intent(in) :: o2col(:)
297 REAL, intent(in) :: tlev(:), secchi(:)
298 REAL, intent(inout) :: dto2(nlyr,nsrb), o2xsk(nlyr,nsrb)
300 !-----------------------------------------------------------------------------
301 ! ... local variables
302 !-----------------------------------------------------------------------------
303 REAL, parameter :: o2col_min = exp( 38. )
305 INTEGER :: wn, k, ktop, ktop1, kbot, nlyrm1
311 !-----------------------------------------------------------------------------
312 ! ...Initialize cross sections to values at large optical depth
313 !-----------------------------------------------------------------------------
315 o2xsk(:nlyr,wn) = xslod(wn)
318 !-----------------------------------------------------------------------------
319 ! Calculate cross sections
320 ! Set smallest O2col = exp(38.) molec cm-2
321 ! to stay in range of parameterization
322 ! given by Koppers et al. at top of atm.
323 !-----------------------------------------------------------------------------
328 o2col1(k) = MAX( o2col(k),o2col_min )
332 ktop = MIN(ktop1,ktop)
333 ELSE IF (x > 56.0) THEN
336 CALL effxs( x, tlev(k), xs )
337 o2xsk(k,:nsrb) = xs(:nsrb)
341 !-----------------------------------------------------------------------------
342 ! fill in cross section where X is out of range by repeating edge table values
343 ! Do not allow kbot = nlyr to avoid division by zero in no light case.
344 !-----------------------------------------------------------------------------
345 IF( kbot == nlyr) then
351 o2xsk(:kbot,wn) = o2xsk(kbot+1,wn)
355 IF( ktop < nlyr ) THEN
357 o2xsk(ktop+1:nlyr,wn) = o2xsk(ktop,wn)
361 !-----------------------------------------------------------------------------
362 ! Calculate incremental optical depths
363 !-----------------------------------------------------------------------------
364 dto2(nlyr,1:nsrb) = 0.0 ! set optical depth to zero at top
366 !-----------------------------------------------------------------------------
367 ! ... calculate an optical depth weighted by density,
368 ! put in mean value estimate, if in shade
369 !-----------------------------------------------------------------------------
370 WHERE (ABS(1. - o2col1(2:nlyr)/o2col1(:nlyrm1)) <= 2.*precis)
371 dto2(:nlyrm1,wn) = o2xsk(2:nlyr,wn)*o2col1(2:nlyr)/real(nlyrm1)
373 dto2(:nlyr-1,wn) = ABS( &
374 (o2xsk(2:nlyr,wn)*o2col1(2:nlyr) - o2xsk(:nlyrm1,wn)*o2col1(:nlyrm1)) &
375 /(1. + LOG(o2xsk(2:nlyr,wn)/o2xsk(:nlyrm1,wn)) &
376 / LOG(o2col1(2:nlyr)/o2col1(:nlyrm1))) )
377 !-----------------------------------------------------------------------------
378 ! ... change to vertical optical depth
379 !-----------------------------------------------------------------------------
380 dto2(:nlyrm1,wn) = 2. * dto2(:nlyrm1,wn)/(secchi(:nlyr-1)+secchi(2:nlyr))
386 SUBROUTINE EFFXS( x, t, xs )
387 !-----------------------------------------------------------------------------
388 ! Subroutine for evaluating the effective cross section
389 ! of O2 in the Schumann-Runge bands using parameterization
390 ! of G.A. Koppers, and D.P. Murtagh [ref. Ann.Geophys., 14
394 ! ln(xs) = A(X)[T-220]+B(X)
395 ! X = log of slant column of O2
396 ! A,B calculated from Chebyshev polynomial coeffs
397 ! AC and BC using NR routine chebev. Assume interval
399 !-----------------------------------------------------------------------------
401 !-----------------------------------------------------------------------------
402 ! ... dummy arguments
403 !-----------------------------------------------------------------------------
404 REAL, intent(in) :: t, x
405 REAL, intent(out) :: xs(nsrb)
407 !-----------------------------------------------------------------------------
408 ! ... local variables
409 !-----------------------------------------------------------------------------
411 REAL :: a(nsrb), b(nsrb)
413 call calc_params( x, a, b )
415 xs(:nsrb) = EXP( a(:nsrb)*( t - 220.) + b(:nsrb) )
419 SUBROUTINE CALC_PARAMS( x, a, b )
420 !-----------------------------------------------------------------------------
421 ! calculates coefficients (A,B), used in calculating the
422 ! effective cross section, for nsrb wavelength intervals
423 ! as a function of log O2 column density (X)
424 ! Wavelength intervals are defined in WMO1985
425 !-----------------------------------------------------------------------------
427 !-----------------------------------------------------------------------------
428 ! ... dummy arguments
429 !-----------------------------------------------------------------------------
430 REAL, intent(in) :: x
431 REAL, intent(out) :: a(nsrb), b(nsrb)
433 !-----------------------------------------------------------------------------
434 ! ... local variables
435 !-----------------------------------------------------------------------------
438 !-----------------------------------------------------------------------------
439 ! call Chebyshev Evaluation routine to calc A and B from
440 ! set of 20 coeficients for each wavelength
441 !-----------------------------------------------------------------------------
444 a(wn) = chebev( 38.0 , 56.0, chebev_ac(:,wn), nchebev_term, x )
445 b(wn) = chebev( 38.0 , 56.0, chebev_bc(:,wn), nchebev_term, x )
448 END SUBROUTINE CALC_PARAMS
450 REAL FUNCTION chebev( a, b, c, m, x )
451 !-------------------------------------------------------------
452 ! Chebyshev evaluation algorithm
453 ! See Numerical recipes p193
454 !-------------------------------------------------------------
456 !-------------------------------------------------------------
457 ! ... dummy arguments
458 !-------------------------------------------------------------
459 INTEGER, intent(in) :: m
460 REAL, intent(in) :: a, b, x
461 REAL(8), intent(in) :: c(:)
463 !-------------------------------------------------------------
464 ! ... local variables
465 !-------------------------------------------------------------
467 REAL :: d, dd, sv, y, y2
469 IF( (x - a)*(x - b) > 0.) THEN
474 y = (2.*x - a - b)/(b - a)
478 d = y2*d - dd + real( c(J),4 )
481 chebev = y*d - dd + 0.5*real( c(1),4 )
486 SUBROUTINE sjo2( nlyr, nwave, xso2, xsqy )
487 !-----------------------------------------------------------------------------
489 != Update the weighting function (cross section x quantum yield) for O2
490 != photolysis. The strong spectral variations in the O2 cross sections are
491 != parameterized into a few bands for Lyman-alpha (121.4-121.9 nm, one band)
492 != and Schumann-Runge (174.4-205.8, nsrb bands) regions. The parameterizations
493 != depend on the overhead O2 column, and therefore on altitude and solar
494 != zenith angle, so they need to be updated at each time/zenith step.
495 !-----------------------------------------------------------------------------
497 != NZ - INTEGER, number of altitude levels in working altitude grid (I)
498 != NW - INTEGER, number of specified intervals + 1 in working (I)
500 != XSO2 - REAL, molecular absorption cross section in SR bands at (I)
501 != each specified altitude and wavelength. Includes Herzberg
503 != NJ - INTEGER, index of O2 photolysis in array SQ (I)
504 != xsqy - REAL, cross section x quantum yield (cm^2) for each (O)
505 != photolysis reaction, at each wavelength and each altitude level
506 !-----------------------------------------------------------------------------
509 !-----------------------------------------------------------------------------
510 ! ... dummy arguments
511 !-----------------------------------------------------------------------------
512 INTEGER, intent(in) :: nlyr, nwave
513 REAL, intent(in) :: xso2(:,:)
514 REAL, intent(inout) :: xsqy(:,:)
516 !-----------------------------------------------------------------------------
517 ! ... local variables
518 !-----------------------------------------------------------------------------
521 !-----------------------------------------------------------------------------
523 ! quantum yield assumed to be unity
524 ! assign cross section values at all wavelengths and at all altitudes
526 !-----------------------------------------------------------------------------
528 xsqy(:nwave,k) = xso2(:nwave,k)