Line data Source code
1 : module cam3_ozone_data
2 :
3 : !-----------------------------------------------------------------------
4 : ! Purpose:
5 : !
6 : ! Interpolates zonal ozone datasets used by CAM3 and puts the field 'O3' into
7 : ! the physics buffer.
8 : !
9 : ! Revision history:
10 : ! 2004-07-31 B. Eaton Assemble module from comozp.F90, oznini.F90, oznint.F90, radozn.F90
11 : ! 2004-08-19 B. Eaton Modify ozone_data_vert_interp to return mass mixing ratio.
12 : ! 2004-08-30 B. Eaton Add ozone_data_get_cnst method.
13 : ! 2008 June B. Eaton Change name to cam3_ozone_data to support backwards compatibility
14 : ! for reading the CAM3 ozone data. Add *_readnl method so module
15 : ! reads its own namelist. Add cam3_ozone_data_on variable to
16 : ! turn the module on from the namelist. By default it's off.
17 : !-----------------------------------------------------------------------
18 :
19 : use shr_kind_mod, only: r8 => shr_kind_r8
20 : use spmd_utils, only: masterproc
21 : use ppgrid, only: begchunk, endchunk, pcols, pver
22 : use cam_abortutils, only: endrun
23 : use cam_logfile, only: iulog
24 : use physics_types, only: physics_state
25 : use boundarydata, only: boundarydata_type, boundarydata_init, boundarydata_update, &
26 : boundarydata_vert_interp
27 : use mpishorthand
28 :
29 : implicit none
30 : private
31 : save
32 :
33 : ! Public methods
34 : public ::&
35 : cam3_ozone_data_readnl, &! get namelist input
36 : cam3_ozone_data_register, &! register ozone with physics buffer
37 : cam3_ozone_data_init, &! open dataset and spatially interpolate data bounding initial time
38 : cam3_ozone_data_timestep_init ! interpolate to current time
39 :
40 : ! Namelist variables
41 : logical, public :: cam3_ozone_data_on = .false. ! switch to turn module on/off
42 : logical :: ozncyc = .true. ! .true. => assume annual cycle ozone data
43 : character(len=256) :: bndtvo = ' ' ! full pathname for time-variant ozone dataset
44 :
45 : ! Local
46 : integer :: oz_idx ! index into phys_buffer for ozone
47 :
48 : type(boundarydata_type) :: ozonedata
49 : character(len=6), parameter, dimension(1) :: nc_name = (/'OZONE '/) ! constituent names
50 :
51 : !================================================================================================
52 : contains
53 : !================================================================================================
54 :
55 1536 : subroutine cam3_ozone_data_readnl(nlfile)
56 :
57 : use namelist_utils, only: find_group_name
58 : use units, only: getunit, freeunit
59 : use mpishorthand
60 :
61 : character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
62 :
63 : ! Local variables
64 : integer :: unitn, ierr
65 : character(len=*), parameter :: subname = 'cam3_ozone_data_readnl'
66 :
67 : namelist /cam3_ozone_data_nl/ cam3_ozone_data_on, bndtvo, ozncyc
68 : !-----------------------------------------------------------------------------
69 :
70 1536 : if (masterproc) then
71 2 : unitn = getunit()
72 2 : open( unitn, file=trim(nlfile), status='old' )
73 2 : call find_group_name(unitn, 'cam3_ozone_data_nl', status=ierr)
74 2 : if (ierr == 0) then
75 0 : read(unitn, cam3_ozone_data_nl, iostat=ierr)
76 0 : if (ierr /= 0) then
77 0 : call endrun(subname // ':: ERROR reading namelist')
78 : end if
79 : end if
80 2 : close(unitn)
81 2 : call freeunit(unitn)
82 : end if
83 :
84 : #ifdef SPMD
85 : ! Broadcast namelist variables
86 1536 : call mpibcast(cam3_ozone_data_on, 1, mpilog, 0, mpicom)
87 1536 : call mpibcast(bndtvo, len(bndtvo), mpichar, 0, mpicom)
88 1536 : call mpibcast(ozncyc, 1, mpilog, 0, mpicom)
89 : #endif
90 :
91 1536 : end subroutine cam3_ozone_data_readnl
92 :
93 : !================================================================================================
94 :
95 0 : subroutine cam3_ozone_data_register()
96 : use physics_buffer, only : pbuf_add_field, dtype_r8
97 :
98 0 : call pbuf_add_field('O3','physpkg',dtype_r8,(/pcols,pver/),oz_idx)
99 :
100 0 : end subroutine cam3_ozone_data_register
101 :
102 : !================================================================================================
103 :
104 0 : subroutine cam3_ozone_data_init(phys_state)
105 : !-----------------------------------------------------------------------
106 : !
107 : ! Purpose: Do initial read of time-variant ozone boundary dataset, containing
108 : ! ozone mixing ratios as a function of latitude and pressure. Read two
109 : ! consecutive months between which the current date lies. Routine
110 : ! RADOZ2 then evaluates the two path length integrals (with and without
111 : ! pressure weighting) from zero to the interfaces between the input
112 : ! levels. It also stores the contribution to the integral from each
113 : ! layer.
114 : !
115 : ! Method: Call appropriate netcdf wrapper routines and interpolate to model grid
116 : !
117 : ! Author: CCM Core Group
118 : ! Modified: P. Worley, August 2003, for chunking and performance optimization
119 : ! J. Edwards, Dec 2005, functionality now performed by zonalbndrydata
120 : !-----------------------------------------------------------------------
121 :
122 0 : use cam_history, only: addfld
123 :
124 : type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
125 : !-----------------------------------------------------------------------
126 :
127 0 : call addfld ('O3VMR', (/ 'lev' /), 'A', 'm3/m3', 'Ozone volume mixing ratio', sampling_seq='rad_lwsw')
128 :
129 :
130 : ! Initialize for one field (arg_4=1) and do not vertically interpolate (arg_6=3)
131 0 : call boundarydata_init(bndtvo, phys_state, nc_name, 1, ozonedata, 3)
132 :
133 0 : if (masterproc) then
134 0 : write(iulog,*)'cam3_ozone_data_init: Initializing CAM3 prescribed ozone'
135 0 : write(iulog,*)'Time-variant boundary dataset (ozone) is: ', trim(bndtvo)
136 0 : if (ozncyc) then
137 0 : write(iulog,*)'OZONE dataset will be reused for each model year'
138 : else
139 0 : write(iulog,*)'OZONE dataset will not be cycled'
140 : end if
141 : end if
142 :
143 0 : end subroutine cam3_ozone_data_init
144 :
145 : !================================================================================================
146 :
147 0 : subroutine cam3_ozone_data_timestep_init(pbuf2d, phys_state)
148 : !-----------------------------------------------------------------------
149 : !
150 : ! Purpose: Interpolate ozone mixing ratios to current time, reading in new monthly
151 : ! data if necessary, and spatially interpolating it.
152 : !
153 : ! Method: Find next month of ozone data to interpolate. Linearly interpolate
154 : ! vertically and horizontally
155 : !
156 : !-----------------------------------------------------------------------
157 :
158 :
159 0 : use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_get_chunk
160 :
161 :
162 : type(physics_state), intent(in) :: phys_state(begchunk:endchunk)
163 : type(physics_buffer_desc), pointer :: pbuf2d(:,:)
164 0 : real(r8),pointer :: tmpptr(:,:)
165 :
166 : integer lchnk
167 :
168 0 : call boundarydata_update(phys_state, ozonedata)
169 :
170 0 : do lchnk = begchunk, endchunk
171 0 : call pbuf_get_field(pbuf_get_chunk(pbuf2d, lchnk), oz_idx, tmpptr)
172 0 : call ozone_data_get_cnst(phys_state(lchnk), tmpptr)
173 : enddo
174 :
175 0 : end subroutine cam3_ozone_data_timestep_init
176 :
177 : !================================================================================================
178 :
179 0 : subroutine ozone_data_get_cnst(state, q)
180 :
181 0 : use cam_history, only: outfld
182 : use physconst, only: mwo3
183 :
184 : type(physics_state), intent(in) :: state
185 : real(r8) :: q(:,:) ! constituent mass mixing ratio
186 :
187 : ! local variables
188 : integer :: lchnk ! chunk identifier
189 : integer :: i, k
190 0 : real(r8) :: ozmixin(pcols,ozonedata%levsiz)
191 : ! *** N.B. this hardwired mw of dry air needs to be changed to the share value
192 : real(r8), parameter :: mwdry = 28.9644_r8 ! Effective molecular weight of dry air (g/mol)
193 : real(r8), parameter :: mwr = mwo3/mwdry ! convert from the dataset values of vmr to mmr
194 : !-------------------------------------------------------------------------------
195 :
196 0 : lchnk = state%lchnk
197 :
198 0 : ozmixin=0._r8
199 0 : do k=1,ozonedata%levsiz
200 0 : do i=1,state%ncol
201 0 : ozmixin(i,k) = ozonedata%datainst(state%latmapback(i),k,lchnk,1)
202 : end do
203 : end do
204 : call boundarydata_vert_interp(lchnk, state%ncol, ozonedata%levsiz, &
205 0 : 1, ozonedata%pin, state%pmid, ozmixin , q)
206 :
207 0 : call outfld('O3VMR', q, pcols, lchnk)
208 :
209 0 : do k=1,pver
210 0 : do i=1,state%ncol
211 0 : q(i,k) = mwr*q(i,k)
212 : end do
213 : end do
214 :
215 0 : end subroutine ozone_data_get_cnst
216 :
217 : !================================================================================================
218 :
219 : end module cam3_ozone_data
220 :
|