1 ! This file contains subroutines related to reading the
2 ! absorption cross sections of gases that contribute to atmospheric transmission:
3 ! Some of these subroutines are also called from rxn.f when loading photolysis cross sections
4 ! for these same gases. It is possible to have different cross sections for
5 ! transmission and for photolysis, e.g. for ozone, Bass et al. could be used
6 ! for transmission while Molina and Molina could be used for photolysis.
7 ! This flexibility can be useful but users should be aware.
8 ! For xsections that are temperature dependent, caution should be used in passing the proper
9 ! temperature to the data routines. Usually, transmission is for layers, TLAY(NZ-1), while
10 ! photolysis is at levels, T(NZ).
11 ! The following subroutines are her:
26 !=============================================================================*
28 module module_xsections
34 public :: o3xs, rdo2xs, rdso2xs, no2xs_jpl06a
38 REAL, allocatable :: rei218(:), rei228(:), rei243(:), rei295(:)
39 REAL :: v195, v345, v830
40 REAL, allocatable :: wmo203(:), wmo273(:)
43 REAL, allocatable :: jpl295(:), jpl218(:)
46 REAL, allocatable :: mol226(:), mol263(:), mol298(:)
47 REAL :: v185, v240, v350
49 REAL, allocatable :: c0(:), c1(:), c2(:)
52 REAL, allocatable :: no2xs_a(:), no2xs_b(:)
56 SUBROUTINE rdxs_init( nw, wl )
58 integer, intent(in) :: nw
59 real, intent(in) :: wl(nw)
61 integer :: istat, astat
64 if( .not. allocated( rei218 ) ) then
65 allocate( rei218(nw-1),rei228(nw-1),rei243(nw-1),rei295(nw-1),stat=astat )
68 if( .not. allocated( wmo203 ) ) then
69 allocate( wmo203(nw-1),wmo273(nw-1),stat=astat )
72 if( .not. allocated( jpl218 ) ) then
73 allocate( jpl218(nw-1),jpl295(nw-1),stat=astat )
76 if( .not. allocated( mol226 ) ) then
77 allocate( mol226(nw-1),mol263(nw-1),mol298(nw-1),stat=astat )
80 if( .not. allocated( c0 ) ) then
81 allocate( c0(nw-1),c1(nw-1),c2(nw-1),stat=astat )
84 if( .not. allocated( no2xs_a ) ) then
85 allocate( no2xs_a(nw-1),no2xs_b(nw-1),stat=astat )
89 !_______________________________________________________________________
90 ! read data from different sources
91 ! rei = Reims group (Malicet et al., Brion et al.)
92 ! jpl = JPL 2006 evaluation
93 ! wmo = WMO 1985 O3 assessment
94 ! mol = Molina and Molina
96 !_______________________________________________________________________
105 END SUBROUTINE rdxs_init
107 SUBROUTINE o3xs(nz,t,nw,wl, xs)
108 !-----------------------------------------------------------------------------*
110 != Read ozone molecular absorption cross section. Re-grid data to match =*
111 != specified wavelength working grid. Interpolate in temperature as needed =*
112 !-----------------------------------------------------------------------------*
114 != MABS - INTEGER, option for splicing different combinations of (I)=*
115 != absorption cross secttions =*
116 != NZ - INTEGER, number of altitude levels or layers (I)=*
117 != T - REAL, temperature of levels or layers (I)=*
118 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
119 != wavelength grid =*
120 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
121 != working wavelength grid. In vacuum, nm =*
122 != XS - REAL, molecular absoprtion cross section (cm^2) of O3 at (O)=*
123 != each specified wavelength (WMO value at 273) =*
124 !-----------------------------------------------------------------------------*
126 ! input: (altitude working grid)
128 INTEGER, intent(in) :: nw
129 REAL, intent(in) :: wl(nw)
131 INTEGER, intent(in) :: nz
132 REAL, intent(in) :: t(nz)
135 ! ozone absorption cross sections interpolated to
136 ! working wavelength grid (iw)
137 ! working altitude grid (iz) for temperature of layer or level (specified in call)
138 ! Units are cm2 molecule-1 in vacuum
140 REAL, intent(inout) :: xs(:,:)
145 REAL :: factor, factor1
149 ! assign according to wavelength range:
150 ! 175.439 - 185.185 1985WMO (203, 273 K)
151 ! 185.185 - 195.00 2006JPL_O3 (218, 295 K)
152 ! 195.00 - 345.00 Reims group (218, 228, 243, 295 K)
153 ! 345.00 - 830.00 Reims group (295 K)
154 ! no extrapolations in temperature allowed
157 IF(wl(iw) < v185) THEN
158 factor = (wmo273(iw) - wmo203(iw))/(273. - 203.)
159 xs(1:nz,iw) = wmo203(iw) + (t(1:nz) - 203.)*factor
160 WHERE (t(1:nz) <= 203.)
161 xs(1:nz,iw) = wmo203(iw)
162 ELSEWHERE (t(1:nz) >= 273.)
163 xs(1:nz,iw) = wmo273(iw)
165 ELSEIF(wl(iw) >= v185 .AND. wl(iw) < v195) THEN
166 factor = (jpl295(iw) - jpl218(iw))/(295. - 218.)
167 xs(1:nz,iw) = jpl218(iw) + (t(1:nz) - 218.)*factor
168 WHERE (t(1:nz) <= 218.)
169 xs(1:nz,iw) = jpl218(iw)
170 ELSEWHERE (t(1:nz) >= 295.)
171 xs(1:nz,iw) = jpl295(iw)
173 ELSEIF(wl(iw) >= v195 .AND. wl(iw) < v345) THEN
174 factor = .1*(rei228(iw) - rei218(iw))
175 WHERE( t(1:nz) < 218. )
176 xs(1:nz,iw) = rei218(iw)
177 ELSEWHERE( t(1:nz) >= 218. .AND. t(1:nz) < 228. )
178 xs(1:nz,iw) = rei218(iw) + (t(1:nz) - 218.)*factor
180 factor = (rei243(iw) - rei228(iw))/15.
181 WHERE( t(1:nz) >= 228. .AND. t(1:nz) < 243. )
182 xs(1:nz,iw) = rei228(iw) + (t(1:nz) - 228.)*factor
184 factor = (rei295(iw) - rei243(iw))/(295. - 243.)
185 WHERE( t(1:nz) >= 243. .AND. t(1:nz) < 295.)
186 xs(1:nz,iw) = rei243(iw) + (t(1:nz) - 243.)*factor
187 ELSEWHERE( t(1:nz) >= 295. )
188 xs(1:nz,iw) = rei295(iw)
190 ELSEIF(wl(iw) >= v345) THEN
191 xs(1:nz,iw) = rei295(iw)
197 !=============================================================================*
199 SUBROUTINE o3_rei(nw,wl)
200 !-----------------------------------------------------------------------------*
202 != Read and interpolate the O3 cross section from Reims group =*
203 !-----------------------------------------------------------------------------*
205 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
206 != wavelength grid =*
207 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
208 != working wavelength grid =*
209 != REI218 - REAL, cross section (cm^2) for O3 at 218K (O)=*
210 != REI228 - REAL, cross section (cm^2) for O3 at 218K (O)=*
211 != REI243 - REAL, cross section (cm^2) for O3 at 218K (O)=*
212 != REI295 - REAL, cross section (cm^2) for O3 at 218K (O)=*
213 != V195 - REAL, exact wavelength in vacuum for data breaks (O)=*
214 != e.g. start, stop, or other change =*
215 != V345 - REAL, exact wavelength in vacuum for data breaks (O)=*
216 != V830 - REAL, exact wavelength in vacuum for data breaks (O)=*
217 !-----------------------------------------------------------------------------*
221 INTEGER, intent(in) :: nw
222 REAL, intent(in) :: wl(nw)
226 INTEGER, PARAMETER :: kdata = 70000
228 INTEGER n1, n2, n3, n4, iw
229 REAL x1(kdata), x2(kdata), x3(kdata), x4(kdata)
230 REAL y1(kdata), y2(kdata), y3(kdata), y4(kdata)
235 ! used for air-to-vacuum wavelength conversion
238 CHARACTER(len=256) :: emsg
240 ! data from the Reims group:
241 != For Hartley and Huggins bands, use temperature-dependent values from =*
242 != Malicet et al., J. Atmos. Chem. v.21, pp.263-273, 1995. =*
243 != over 345.01 - 830.00, use values from Brion, room temperature only
245 OPEN(UNIT=kin,FILE='DATAE1/O3/1995Malicet_O3.txt',STATUS='old',iostat=ierr)
247 call wrf_error_fatal( 'o3_rei: Failed to open DATAE1/O3/1985Malicet_O3.txt' )
250 READ(kin,*,iostat=ierr)
252 call wrf_error_fatal( 'o3_rei: Failed to read DATAE1/O3/1985Malicet_O3.txt' )
260 READ(kin,*,iostat=ierr) x1(i), y1(i), y2(i), y3(i), y4(i)
262 call wrf_error_fatal( 'o3_rei: Failed to read DATAE1/O3/1985Malicet_O3.txt' )
270 != over 345.01 - 830.00, use values from Brion, room temperature only
271 ! skip datum at 345.00 because already read in from 1995Malicet
273 OPEN(UNIT=kin,FILE='DATAE1/O3/1998Brion_295.txt',STATUS='old')
279 READ(kin,*) x1(n1), y1(n1)
284 ri(i) = refrac(x1(i), 2.45E19)
287 x1(i) = x1(i) * ri(i)
290 CALL addpnt(x1,y1,kdata,n1,x1(1)*(1.-deltax),0.)
291 CALL addpnt(x1,y1,kdata,n1, 0.,0.)
292 CALL addpnt(x1,y1,kdata,n1,x1(n1)*(1.+deltax),0.)
293 CALL addpnt(x1,y1,kdata,n1, 1.e+38,0.)
294 CALL inter2(nw,wl,rei295,n1,x1,y1,ierr)
295 IF (ierr .NE. 0) THEN
296 WRITE(emsg,'(''o3_rei: interp err = '',i5,'' in O3 xsect - Reims 295K'')') ierr
297 call wrf_error_fatal( trim(emsg) )
301 ri(i) = refrac(x2(i), 2.45E19)
304 x2(i) = x2(i) * ri(i)
309 CALL addpnt(x2,y2,kdata,n2,x2(1)*(1.-deltax),0.)
310 CALL addpnt(x2,y2,kdata,n2, 0.,0.)
311 CALL addpnt(x2,y2,kdata,n2,x2(n2)*(1.+deltax),0.)
312 CALL addpnt(x2,y2,kdata,n2, 1.e+38,0.)
313 CALL inter2(nw,wl,rei243,n2,x2,y2,ierr)
314 IF (ierr .NE. 0) THEN
315 WRITE(emsg,'(''o3_wmo: interp err = '',i5,'' in O3 xsect - Reims 243K'')') ierr
316 call wrf_error_fatal( trim(emsg) )
319 CALL addpnt(x3,y3,kdata,n3,x3(1)*(1.-deltax),0.)
320 CALL addpnt(x3,y3,kdata,n3, 0.,0.)
321 CALL addpnt(x3,y3,kdata,n3,x3(n3)*(1.+deltax),0.)
322 CALL addpnt(x3,y3,kdata,n3, 1.e+38,0.)
323 CALL inter2(nw,wl,rei228,n3,x3,y3,ierr)
324 IF (ierr .NE. 0) THEN
325 WRITE(emsg,'(''o3_wmo: interp err = '',i5,'' in O3 xswct - Reims 228K'')') ierr
326 call wrf_error_fatal( trim(emsg) )
329 CALL addpnt(x4,y4,kdata,n4,x4(1)*(1.-deltax),0.)
330 CALL addpnt(x4,y4,kdata,n4, 0.,0.)
331 CALL addpnt(x4,y4,kdata,n4,x4(n4)*(1.+deltax),0.)
332 CALL addpnt(x4,y4,kdata,n4, 1.e+38,0.)
333 CALL inter2(nw,wl,rei218,n4,x4,y4,ierr)
334 IF (ierr .NE. 0) THEN
335 WRITE(emsg,'(''o3_wmo: interp err = '',i5,'' in O3 xswct - Reims 218K'')') ierr
336 call wrf_error_fatal( trim(emsg) )
339 ! wavelength breaks must be converted to vacuum:
341 v195 = 195.00 * refrac(195.00, 2.45E19)
342 v345 = 345.00 * refrac(345.00, 2.45E19)
343 v830 = 830.00 * refrac(830.00, 2.45E19)
345 END SUBROUTINE o3_rei
347 !=============================================================================*
349 SUBROUTINE o3_wmo(nw,wl)
350 !-----------------------------------------------------------------------------*
352 != Read and interpolate the O3 cross section =*
353 != data from WMO 85 Ozone Assessment =*
354 !-----------------------------------------------------------------------------*
356 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
357 != wavelength grid =*
358 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
359 != working wavelength grid =*
360 != WMO203 - REAL, cross section (cm^2) for O3 at 203K (O)=*
361 != WMO273 - REAL, cross section (cm^2) for O3 at 273K (O)=*
362 != V176 - REAL, exact wavelength in vacuum for data breaks (O)=*
363 != e.g. start, stop, or other change =*
364 != V850 - REAL, exact wavelength in vacuum for data breaks (O)=*
365 !-----------------------------------------------------------------------------*
369 INTEGER, intent(in) :: nw
370 REAL, intent(in) :: wl(nw)
374 INTEGER, parameter :: kdata = 200
377 REAL x1(kdata), x2(kdata)
378 REAL y1(kdata), y2(kdata)
384 ! used for air-to-vacuum wavelength conversion
387 CHARACTER(len=256) :: emsg
391 !----------------------------------------------------------
392 ! cross sections from WMO 1985 Ozone Assessment
393 ! from 175.439 to 847.500 nm
395 OPEN(UNIT=kin,FILE='DATAE1/wmo85',STATUS='old',iostat=ierr)
397 call wrf_error_fatal( 'o3_wmo: Failed to open DATAE1/wmo85' )
400 read(kin,*,iostat=ierr)
402 call wrf_error_fatal( 'o3_wmo: Failed to read DATAE1/wmo85' )
408 READ(kin,*,iostat=ierr) idum, a1, a2, dum, dum, dum, y1(i), y2(i)
410 call wrf_error_fatal( 'o3_wmo: Failed to read DATAE1/wmo85' )
417 ! convert wavelengths to vacuum
420 ri(i) = refrac(x1(i), 2.45E19)
423 x1(i) = x1(i) * ri(i)
424 x2(i) = x2(i) * ri(i)
427 CALL addpnt(x1,y1,kdata,n1,x1(1)*(1.-deltax),0.)
428 CALL addpnt(x1,y1,kdata,n1, 0.,0.)
429 CALL addpnt(x1,y1,kdata,n1,x1(n1)*(1.+deltax),0.)
430 CALL addpnt(x1,y1,kdata,n1, 1.e+38,0.)
431 CALL inter2(nw,wl,wmo203,n1,x1,y1,ierr)
432 IF (ierr .NE. 0) THEN
433 WRITE(emsg,'(''o3_wmo: interp err = '',i5,'' in O3 cross section - WMO - 203K'')') ierr
434 call wrf_error_fatal( trim(emsg) )
437 CALL addpnt(x2,y2,kdata,n2,x2(1)*(1.-deltax),0.)
438 CALL addpnt(x2,y2,kdata,n2, 0.,0.)
439 CALL addpnt(x2,y2,kdata,n2,x2(n2)*(1.+deltax),0.)
440 CALL addpnt(x2,y2,kdata,n2, 1.e+38,0.)
441 CALL inter2(nw,wl,wmo273,n2,x2,y2,ierr)
442 IF (ierr .NE. 0) THEN
443 WRITE(emsg,'(''o3_wmo: interp err = '',i5,'' in O3 cross section - WMO - 273K'')') ierr
444 call wrf_error_fatal( trim(emsg) )
447 ! wavelength breaks must be converted to vacuum:
449 a1 = (175.438 + 176.991) / 2.
450 v176 = a1 * refrac(a1,2.45E19)
452 a1 = (847.5 + 852.5) / 2.
453 v850 = a1 * refrac(a1, 2.45E19)
455 END SUBROUTINE o3_wmo
457 !=============================================================================*
459 SUBROUTINE o3_jpl(nw,wl)
460 !-----------------------------------------------------------------------------*
462 != Read and interpolate the O3 cross section from JPL 2006 =*
463 !-----------------------------------------------------------------------------*
465 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
466 != wavelength grid =*
467 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
468 != working wavelength grid =*
469 != JPL218 - REAL, cross section (cm^2) for O3 at 218K (O)=*
470 != JPL295 - REAL, cross section (cm^2) for O3 at 295K (O)=*
471 != V186 - REAL, exact wavelength in vacuum for data breaks (O)=*
472 != e.g. start, stop, or other change =*
473 != V825 - REAL, exact wavelength in vacuum for data breaks (O)=*
474 !-----------------------------------------------------------------------------*
478 INTEGER, intent(in) :: nw
479 REAL, intent(in) :: wl(nw)
483 INTEGER, parameter :: kdata = 200
486 REAL x1(kdata), x2(kdata)
487 REAL y1(kdata), y2(kdata)
492 CHARACTER(len=256) :: emsg
494 ! used for air-to-vacuum wavelength conversion
500 OPEN(UNIT=kin,FILE='DATAE1/O3/2006JPL_O3.txt',STATUS='old',iostat=ierr)
502 call wrf_error_fatal( 'o3_jpl: Failed to open DATAE1/O3/2006JPL_O3.txt' )
505 read(kin,*,iostat=ierr)
507 call wrf_error_fatal( 'o3_jpl: Failed to read DATAE1/O3/2006JPL_O3.txt' )
513 READ(kin,*,iostat=ierr) dum, dum, x1(i), y1(i), y2(i)
515 call wrf_error_fatal( 'o3_jpl: Failed to read DATAE1/O3/2006JPL_O3.txt' )
517 y1(i) = y1(i) * 1.e-20
518 y2(i) = y2(i) * 1.e-20
522 ! convert wavelengths to vacuum
525 ri(i) = refrac(x1(i), 2.45E19)
528 x1(i) = x1(i) * ri(i)
532 CALL addpnt(x1,y1,kdata,n1,x1(1)*(1.-deltax),0.)
533 CALL addpnt(x1,y1,kdata,n1, 0.,0.)
534 CALL addpnt(x1,y1,kdata,n1,x1(n1)*(1.+deltax),0.)
535 CALL addpnt(x1,y1,kdata,n1, 1.e+38,0.)
536 CALL inter2(nw,wl,jpl295,n1,x1,y1,ierr)
537 IF (ierr .NE. 0) THEN
538 WRITE(emsg,'(''o3_jpl: interp err = '',i5,'' in file O3 cross section - WMO - 295K'')') ierr
539 call wrf_error_fatal( trim(emsg) )
542 CALL addpnt(x2,y2,kdata,n2,x2(1)*(1.-deltax),0.)
543 CALL addpnt(x2,y2,kdata,n2, 0.,0.)
544 CALL addpnt(x2,y2,kdata,n2,x2(n2)*(1.+deltax),0.)
545 CALL addpnt(x2,y2,kdata,n2, 1.e+38,0.)
546 CALL inter2(nw,wl,jpl218,n2,x2,y2,ierr)
547 IF (ierr .NE. 0) THEN
548 WRITE(emsg,'(''o3_jpl: interp err = '',i5,'' in file O3 cross section - WMO - 218K'')') ierr
549 call wrf_error_fatal( trim(emsg) )
552 ! wavelength breaks must be converted to vacuum:
554 v186 = 186.051 * refrac(186.051, 2.45E19)
555 v825 = 825. * refrac(825. , 2.45E19)
558 END SUBROUTINE o3_jpl
560 !=============================================================================*
562 SUBROUTINE o3_mol(nw,wl)
563 !-----------------------------------------------------------------------------*
565 != Read and interpolate the O3 cross section from Molina and Molina 1986 =*
566 !-----------------------------------------------------------------------------*
568 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
569 != wavelength grid =*
570 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
571 != working wavelength grid =*
572 != MOL226 - REAL, cross section (cm^2) for O3 at 226 K (O)=*
573 != MOL263 - REAL, cross section (cm^2) for O3 at 263 K (O)=*
574 != MOL298 - REAL, cross section (cm^2) for O3 at 298 K (O)=*
575 != V185 - REAL, exact wavelength in vacuum for data breaks (O)=*
576 != e.g. start, stop, or other change =*
577 != V240 - REAL, exact wavelength in vacuum for data breaks (O)=*
578 != V350 - REAL, exact wavelength in vacuum for data breaks (O)=*
579 !-----------------------------------------------------------------------------*
583 INTEGER, intent(in) :: nw
584 REAL, intent(in) :: wl(nw)
591 INTEGER, parameter :: kdata = 335
592 INTEGER n1, n2, n3, iw
593 REAL x1(kdata), x2(kdata), x3(kdata)
594 REAL y1(kdata), y2(kdata), y3(kdata)
596 ! used for air-to-vacuum wavelength conversion
599 CHARACTER(len=256) :: emsg
603 OPEN(UNIT=kin,FILE='DATAE1/O3/1986Molina.txt',STATUS='old',iostat=ierr)
605 call wrf_error_fatal( 'o3_mol: Failed to open DATAE1/O3/1986Molina.txt' )
608 READ(kin,*,iostat=ierr)
610 call wrf_error_fatal( 'o3_mol: Failed to read DATAE1/O3/1986Molina.txt' )
619 READ(kin,*,iostat=ierr) x1(n1), y1(n1), y3(n3)
621 call wrf_error_fatal( 'o3_mol: Failed to read DATAE1/O3/1986Molina.txt' )
629 READ(kin,*,iostat=ierr) x1(n1), y1(n1), y2(n2), y3(n3)
631 call wrf_error_fatal( 'o3_mol: Failed to read DATAE1/O3/1986Molina.txt' )
638 ! convert all wavelengths from air to vacuum
641 ri(i) = refrac(x1(i), 2.45E19)
644 x1(i) = x1(i) * ri(i)
648 ri(i) = refrac(x2(i), 2.45E19)
651 x2(i) = x2(i) * ri(i)
655 ri(i) = refrac(x3(i), 2.45E19)
658 x3(i) = x3(i) * ri(i)
661 ! convert wavelength breaks from air to vacuum
663 v185 = 185. * refrac(185. , 2.45E19)
664 v240 = 240.5 * refrac(240.5, 2.45E19)
665 v350 = 350. * refrac(350. , 2.45E19)
667 ! interpolate to working grid
669 CALL addpnt(x1,y1,kdata,n1,x1(1)*(1.-deltax),0.)
670 CALL addpnt(x1,y1,kdata,n1, 0.,0.)
671 CALL addpnt(x1,y1,kdata,n1,x1(n1)*(1.+deltax),0.)
672 CALL addpnt(x1,y1,kdata,n1, 1.e+38,0.)
673 CALL inter2(nw,wl,mol226,n1,x1,y1,ierr)
674 IF (ierr .NE. 0) THEN
675 WRITE(emsg,'(''o3_mol: interp err = '',i5,'' in O3 xsect - 226K Molina'')') ierr
676 call wrf_error_fatal( trim(emsg) )
679 CALL addpnt(x2,y2,kdata,n2,x2(1)*(1.-deltax),0.)
680 CALL addpnt(x2,y2,kdata,n2, 0.,0.)
681 CALL addpnt(x2,y2,kdata,n2,x2(n2)*(1.+deltax),0.)
682 CALL addpnt(x2,y2,kdata,n2, 1.e+38,0.)
683 CALL inter2(nw,wl,mol263,n2,x2,y2,ierr)
684 IF (ierr .NE. 0) THEN
685 WRITE(emsg,'(''o3_mol: interp err = '',i5,'' in O3 xsect - 263K Molina'')') ierr
686 call wrf_error_fatal( trim(emsg) )
689 CALL addpnt(x3,y3,kdata,n3,x3(1)*(1.-deltax),0.)
690 CALL addpnt(x3,y3,kdata,n3, 0.,0.)
691 CALL addpnt(x3,y3,kdata,n3,x3(n3)*(1.+deltax),0.)
692 CALL addpnt(x3,y3,kdata,n3, 1.e+38,0.)
693 CALL inter2(nw,wl,mol298,n3,x3,y3,ierr)
694 IF (ierr .NE. 0) THEN
695 WRITE(emsg,'(''o3_mol: interp err = '',i5,'' in O3 xsect - 298K Molina'')') ierr
696 call wrf_error_fatal( trim(emsg) )
699 END SUBROUTINE o3_mol
701 !=============================================================================*
703 SUBROUTINE o3_bas(nw,wl)
704 !-----------------------------------------------------------------------------*
706 != Read and interpolate the O3 cross section from Bass 1985 =*
707 !-----------------------------------------------------------------------------*
709 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
710 != wavelength grid =*
711 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
712 != working wavelength grid =*
713 != c0 - REAL, coefficint for polynomial fit to cross section (cm^2) (O)=*
714 != c1 - REAL, coefficint for polynomial fit to cross section (cm^2) (O)=*
715 != c2 - REAL, coefficint for polynomial fit to cross section (cm^2) (O)=*
716 != Vb245 - REAL, exact wavelength in vacuum for data breaks (O)=*
717 != e.g. start, stop, or other change =*
718 != Vb342 - REAL, exact wavelength in vacuum for data breaks (O)=*
719 !-----------------------------------------------------------------------------*
723 INTEGER, intent(in) :: nw
724 REAL, intent(in) :: wl(nw)
728 INTEGER, parameter :: kdata = 2000
734 REAL x1(kdata), x2(kdata), x3(kdata)
735 REAL y1(kdata), y2(kdata), y3(kdata)
737 ! used for air-to-vacuum wavelength conversion
740 CHARACTER(len=256) :: emsg
742 OPEN(UNIT=kin,FILE='DATAE1/O3/1985Bass_O3.txt',STATUS='old',iostat=ierr)
744 call wrf_error_fatal( 'o3_bas: Failed to open DATAE1/O3/1985Bass_O3.txt' )
747 READ(kin,*,iostat=ierr)
753 READ(kin,*) x1(i), y1(i), y2(i), y3(i)
755 call wrf_error_fatal( 'o3_bas: Failed to read DATAE1/O3/1985Bass_O3.txt' )
759 y1(1:n1) = 1.e-20 * y1(1:n1)
760 y2(1:n1) = 1.e-20 * y2(1:n1)
761 y3(1:n1) = 1.e-20 * y3(1:n1)
763 ! convert all wavelengths from air to vacuum
766 ri(i) = refrac(x1(i), 2.45E19)
768 x1(1:n1) = x1(1:n1) * ri(1:n1)
772 ! convert wavelength breaks to vacuum
774 vb245 = 245.018 * refrac(245.018, 2.45E19)
775 vb342 = 341.981 * refrac(341.981, 2.45E19)
777 ! interpolate to working grid
779 CALL addpnt(x1,y1,kdata,n1,x1(1)*(1.-deltax),0.)
780 CALL addpnt(x1,y1,kdata,n1, 0.,0.)
781 CALL addpnt(x1,y1,kdata,n1,x1(n1)*(1.+deltax),0.)
782 CALL addpnt(x1,y1,kdata,n1, 1.e+38,0.)
783 CALL inter2(nw,wl,c0,n1,x1,y1,ierr)
784 IF (ierr .NE. 0) THEN
785 WRITE(emsg,'(''o3_bas: interp err = '',i5,'' in O3 xsect - c0 Bass'')') ierr
786 call wrf_error_fatal( trim(emsg) )
789 CALL addpnt(x2,y2,kdata,n2,x2(1)*(1.-deltax),0.)
790 CALL addpnt(x2,y2,kdata,n2, 0.,0.)
791 CALL addpnt(x2,y2,kdata,n2,x2(n2)*(1.+deltax),0.)
792 CALL addpnt(x2,y2,kdata,n2, 1.e+38,0.)
793 CALL inter2(nw,wl,c1,n2,x2,y2,ierr)
794 IF (ierr .NE. 0) THEN
795 WRITE(emsg,'(''o3_bas: interp err = '',i5,'' in O3 xsect - c1 Bass'')') ierr
796 call wrf_error_fatal( trim(emsg) )
799 CALL addpnt(x3,y3,kdata,n3,x3(1)*(1.-deltax),0.)
800 CALL addpnt(x3,y3,kdata,n3, 0.,0.)
801 CALL addpnt(x3,y3,kdata,n3,x3(n3)*(1.+deltax),0.)
802 CALL addpnt(x3,y3,kdata,n3, 1.e+38,0.)
803 CALL inter2(nw,wl,c2,n3,x3,y3,ierr)
804 IF (ierr .NE. 0) THEN
805 WRITE(emsg,'(''o3_bas: interp err = '',i5,'' in O3 xsect - c2 Bass'')') ierr
806 call wrf_error_fatal( trim(emsg) )
809 END SUBROUTINE o3_bas
811 !=============================================================================*
813 SUBROUTINE rdo2xs(nw,wl,o2xs1)
814 !-----------------------------------------------------------------------------*
816 != Compute equivalent O2 cross section, except =*
817 != the SR bands and the Lyman-alpha line. =*
818 !-----------------------------------------------------------------------------*
820 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
821 != wavelength grid =*
822 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
823 != working wavelength grid
824 != vertical layer at each specified wavelength =*
825 != O2XS1 - REAL, O2 molecular absorption cross section =*
827 !-----------------------------------------------------------------------------*
831 INTEGER, intent(in) :: nw
832 REAL, intent(in) :: wl(nw)
834 ! Output O2 xsect, temporary, will be over-written in Lyman-alpha and
835 ! Schumann-Runge wavelength bands.
837 REAL, intent(inout) :: o2xs1(:)
841 INTEGER, parameter :: kdata = 200
845 REAL :: x1(kdata), y1(kdata)
846 CHARACTER(len=256) :: emsg
848 ! Read O2 absorption cross section data:
849 ! 116.65 to 203.05 nm = from Brasseur and Solomon 1986
850 ! 205 to 240 nm = Yoshino et al. 1988
852 ! Note that subroutine la_srb.f will over-write values in the spectral regions
854 ! - Lyman-alpha (LA: 121.4-121.9 nm, Chabrillat and Kockarts parameterization)
855 ! - Schumann-Runge bands (SRB: 174.4-205.8 nm, Koppers parameteriaztion)
859 OPEN(UNIT=kin,FILE='DATAE1/O2/O2_brasseur.abs',iostat=ierr)
861 call wrf_error_fatal( 'rdso2xs: Failed to open DATAE1/O2/O2_brasseur.abs' )
864 READ(kin,*,iostat=ierr)
866 call wrf_error_fatal( 'rdso2xs: Failed to read DATAE1/O2/O2_brasseur.abs' )
870 READ(kin,*,iostat=ierr) x, y
872 call wrf_error_fatal( 'rdso2xs: Failed to read DATAE1/O2/O2_brasseur.abs' )
874 IF (x .LE. 204.) THEN
882 OPEN(UNIT=kin,FILE='DATAE1/O2/O2_yoshino.abs',STATUS='old',iostat=ierr)
884 call wrf_error_fatal( 'rdso2xs: Failed to open DATAE1/O2/O2_yoshino.abs' )
888 READ(kin,*,iostat=ierr)
890 call wrf_error_fatal( 'rdso2xs: Failed to read DATAE1/O2/O2_yoshino.abs' )
895 READ(kin,*,iostat=ierr) x, y
897 call wrf_error_fatal( 'rdso2xs: Failed to read DATAE1/O2/O2_yoshino.abs' )
904 ! Add termination points and interpolate onto the
905 ! user grid (set in subroutine gridw):
907 CALL addpnt(x1,y1,kdata,n,x1(1)*(1.-deltax),y1(1))
908 CALL addpnt(x1,y1,kdata,n,0. ,y1(1))
909 CALL addpnt(x1,y1,kdata,n,x1(n)*(1.+deltax),0.)
910 CALL addpnt(x1,y1,kdata,n, 1.E+38,0.)
911 CALL inter2(nw,wl,o2xs1, n,x1,y1, ierr)
912 IF (ierr .NE. 0) THEN
913 WRITE(emsg,'(''rdo2xs: interp err = '',i5,'' in O2 -> O + O'')') ierr
914 call wrf_error_fatal( trim(emsg) )
917 END SUBROUTINE rdo2xs
919 !=============================================================================*
921 SUBROUTINE rdno2xs(nw,wl)
922 !-----------------------------------------------------------------------------*
924 != Read NO2 molecular absorption cross section. Re-grid data to match =*
925 != specified wavelength working grid. =*
926 !-----------------------------------------------------------------------------*
928 != NW - INTEGER, number of specified intervals + 1 in working (I)=*
929 != wavelength grid =*
930 != WL - REAL, vector of lower limits of wavelength intervals in (I)=*
931 != working wavelength grid =*
932 != NO2XS - REAL, molecular absoprtion cross section (cm^2) of NO2 at (O)=*
933 != each specified wavelength =*
934 !-----------------------------------------------------------------------------*
938 INTEGER, intent(in) :: nw
939 REAL, intent(in) :: wl(nw)
942 INTEGER, parameter :: kdata = 100
944 INTEGER :: i, n1, n2, ierr
946 REAL :: x1(kdata), x2(kdata), y1(kdata), y2(kdata)
948 ! NO2 absorption cross section from JPL2006
949 ! with interpolation of bin midpoints
951 OPEN(UNIT=kin,FILE='DATAE1/NO2/NO2_jpl2006.abs',STATUS='old')
957 READ(kin,*) dum1, dum2, y1(i), y2(i)
958 x1(i) = 0.5 * (dum1 + dum2)
966 CALL addpnt(x1,y1,kdata,n1,x1(1)*(1.-deltax),0.)
967 CALL addpnt(x1,y1,kdata,n1, 0.,0.)
968 CALL addpnt(x1,y1,kdata,n1,x1(n1)*(1.+deltax), 0.)
969 CALL addpnt(x1,y1,kdata,n1, 1.e+38, 0.)
970 CALL inter2(nw,wl,no2xs_a,n1,x1,y1,ierr)
972 CALL addpnt(x2,y2,kdata,n2,x2(1)*(1.-deltax),0.)
973 CALL addpnt(x2,y2,kdata,n2, 0.,0.)
974 CALL addpnt(x2,y2,kdata,n2,x2(n2)*(1.+deltax), 0.)
975 CALL addpnt(x2,y2,kdata,n2, 1.e+38, 0.)
976 CALL inter2(nw,wl,no2xs_b,n2,x2,y2,ierr)
978 END SUBROUTINE rdno2xs
980 !=============================================================================*
982 SUBROUTINE no2xs_jpl06a(nz,t,nw,wl, no2xs)
984 ! interpolate NO2 xs from JPL2006
988 INTEGER, intent(in) :: nz
989 INTEGER, intent(in) :: nw
990 REAL, intent(in) :: t(nz)
991 REAL, intent(in) :: wl(nw)
995 REAL, intent(inout) :: no2xs(:,:)
1002 tfac(1:nz) = (t(1:nz) - 220.)/74.
1004 no2xs(1:nz,iw) = no2xs_a(iw) + (no2xs_b(iw)-no2xs_a(iw))*tfac(1:nz)
1007 END SUBROUTINE no2xs_jpl06a
1009 !=============================================================================*
1011 SUBROUTINE rdso2xs(nw,wl,so2xs)
1012 !-----------------------------------------------------------------------------*
1014 != Read SO2 molecular absorption cross section. Re-grid data to match =*
1015 != specified wavelength working grid. =*
1016 !-----------------------------------------------------------------------------*
1018 INTEGER, parameter :: kdata = 1000
1020 ! input: (altitude working grid)
1021 INTEGER, intent(in) :: nw
1022 REAL, intent(in) :: wl(nw)
1026 REAL, intent(inout) :: so2xs(nw)
1034 INTEGER i, l, n, idum
1035 CHARACTER(len=40) :: fil
1036 CHARACTER(len=256) :: emsg
1037 !************ absorption cross sections:
1038 ! SO2 absorption cross sections from J. Quant. Spectrosc. Radiat. Transfer
1039 ! 37, 165-182, 1987, T. J. McGee and J. Burris Jr.
1040 ! Angstrom vs. cm2/molecule, value at 221 K
1042 fil = 'DATA/McGee87'
1043 OPEN(UNIT=kin,FILE='DATAE1/SO2/SO2xs.all',STATUS='old')
1049 READ(kin,*) x1(i), y1(i)
1054 CALL addpnt(x1,y1,kdata,n,x1(1)*(1.-deltax),0.)
1055 CALL addpnt(x1,y1,kdata,n, 0.,0.)
1056 CALL addpnt(x1,y1,kdata,n,x1(n)*(1.+deltax),0.)
1057 CALL addpnt(x1,y1,kdata,n, 1.e+38,0.)
1058 CALL inter2(nw,wl,so2xs,n,x1,y1,ierr)
1059 IF (ierr .NE. 0) THEN
1060 WRITE(emsg,'(''rdso2xs: interp err = '',i5,'' in file '',a)') ierr, fil
1061 call wrf_error_fatal( trim(emsg) )
1064 END SUBROUTINE rdso2xs
1066 real FUNCTION refrac(w,airden)
1070 ! input vacuum wavelength, nm and air density, molec cm-3
1072 REAL, intent(in) :: w, airden
1074 ! output refractive index for standard air
1075 ! (dry air at 15 deg. C, 101.325 kPa, 0.03% CO2)
1079 REAL :: sig, sigsq, dum
1081 ! from CRC Handbook, originally from Edlen, B., Metrologia, 2, 71, 1966.
1082 ! valid from 200 nm to 2000 nm
1083 ! beyond this range, use constant value
1087 ELSEIF (w > 2000.) then
1095 dum = 8342.13 + 2406030./(130. - sigsq) + 15997./(38.9 - sigsq)
1097 ! adjust to local air density
1098 dum = dum * airden/(2.69e19 * 273.15/288.15)
1100 ! index of refraction:
1101 refrac = 1. + 1.E-8 * dum
1105 end module module_xsections