1 subroutine da_get_innov_vector_rttov (it, grid, ob, iv)
3 !---------------------------------------------------------------------------
4 ! Purpose: Calculate innovation vector for radiance data.
7 ! 1. interpolate grid%xb to obs location
8 ! 2. call forward RTM to get simulated bright temperature
9 ! 3. obs BT - simulated BT
10 !---------------------------------------------------------------------------
14 integer, intent(in) :: it ! External iteration.
15 type (domain), intent(in) :: grid ! first guess state.
16 type (y_type), intent(inout) :: ob ! Observation structure.
17 type (iv_type), intent(inout) :: iv ! O-B structure.
21 integer :: n ! Loop counter.
22 integer :: i, j, k ! Index dimension.
23 integer :: nlevels ! Number of obs levels.
24 integer :: nchanprof, errorstatus
26 character(len=256) :: atlas_path
27 real*8 :: seap, icep, lndp, snop
28 real, allocatable :: v_p(:,:)
30 integer :: inst, nchan
31 real, allocatable :: pres(:)
36 real,allocatable :: temp(:), temp2(:), temp3(:,:)
38 type(rttov_emissivity), allocatable :: emissivity(:)
40 type(con_vars_type), allocatable :: con_vars(:)
41 type(aux_vars_type), allocatable :: aux_vars(:)
43 type(rttov_chanprof), allocatable :: chanprof(:)
44 type(rttov_profile), allocatable :: profiles(:)
46 ! variables for computing clwp
47 real, allocatable :: dpf(:,:), clw(:,:), pf(:,:)
49 real, allocatable :: em_mspps(:) ! emissivity caluclated using MSPPS algorithm
50 real :: ts_mspps ! surface temperature calcualted using MSPPS algorithm
52 if (trace_use) call da_trace_entry("da_get_innov_vector_rttov")
54 !------------------------------------------------------
55 ! [1.0] calculate the background bright temperature
56 !-------------------------------------------------------
58 do inst = 1, iv%num_inst ! loop for sensor
59 if ( iv%instid(inst)%num_rad < 1 ) cycle
60 nlevels = iv%instid(inst)%nlevels
61 nchan = iv%instid(inst)%nchan
63 if (iv%instid(inst)%info%n2 < iv%instid(inst)%info%n1) cycle
64 n1 = iv%instid(inst)%info%n1
65 n2 = iv%instid(inst)%info%n2
69 allocate (pres(1:nlevels))
70 allocate (con_vars(n1:n2))
71 allocate (aux_vars(n1:n2))
73 pres(1:nlevels) = coefs(inst) % coef % ref_prfl_p(1:nlevels)
75 allocate(v_p(kms:kme,n1:n2))
77 allocate(clw(kms:kme,n1:n2))
78 allocate(dpf(kms:kme,n1:n2))
79 allocate(pf(kms:kme+1,n1:n2))
81 ! horizontal interpolate grid%xb pressure to ob position for every grid%xb levels
85 v_p(k,n) = 0.01*(iv%instid(inst)%info%dym(k,n)*( &
86 iv%instid(inst)%info%dxm(k,n)*grid%xb%p(iv%instid(inst)%info%i(k,n), iv%instid(inst)%info%j(k,n),k) + &
87 iv%instid(inst)%info%dx(k,n) *grid%xb%p(iv%instid(inst)%info%i(k,n)+1,iv%instid(inst)%info%j(k,n),k)) + &
88 iv%instid(inst)%info%dy(k,n) *( &
89 iv%instid(inst)%info%dxm(k,n)*grid%xb%p(iv%instid(inst)%info%i(k,n), iv%instid(inst)%info%j(k,n)+1,k) + &
90 iv%instid(inst)%info%dx(k,n) *grid%xb%p(iv%instid(inst)%info%i(k,n)+1,iv%instid(inst)%info%j(k,n)+1,k)))
94 call da_to_zk_new(pres, v_p(:,n1:n2), v_interp_p, n1n2,nlevels,iv%instid(inst)%info%zk(:,n1:n2))
96 call da_convert_zk (iv%instid(inst)%info)
98 ! [1.2] Interpolate horizontally to ob:
99 call da_interp_lin_3d (grid%xb%t, iv%instid(inst)%info, iv%instid(inst)%t (:,n1:n2))
100 call da_interp_lin_3d (grid%xb%q, iv%instid(inst)%info, iv%instid(inst)%mr(:,n1:n2))
105 if (iv%instid(inst)%info%zk(k,n) <= 0.0) then
106 iv%instid(inst)%t(k,n) = coefs(inst) % coef % ref_prfl_t(k,gas_id_watervapour) ! outside model level
107 iv%instid(inst)%mr(k,n) = coefs(inst) % coef % ref_prfl_mr(k,gas_id_watervapour)
109 iv%instid(inst)%mr(k,n) = iv%instid(inst)%mr(k,n) * q2ppmv
111 if (pres(k) < 100.0) iv%instid(inst)%mr(k,n) = coefs(inst) % coef % ref_prfl_mr(k,gas_id_watervapour)
114 ! determine surface type of obs location
115 !-----------------------------------------
116 call da_detsurtyp( grid%xb%snow, grid%xb%xice, grid%xb%landmask, &
117 grid%xb%ivgtyp, grid%xb%isltyp, &
118 ims, ime, jms, jme, &
119 iv%instid(inst)%info%i(1,n), iv%instid(inst)%info%j(1,n), &
120 iv%instid(inst)%info%dx(1,n), iv%instid(inst)%info%dy(1,n), &
121 iv%instid(inst)%info%dxm(1,n), iv%instid(inst)%info%dym(1,n), &
122 iv%instid(inst)%isflg(n),iv%instid(inst)%vegtyp(n), iv%instid(inst)%soiltyp(n), &
123 seap, icep, lndp, snop )
125 iv%instid(inst)%snow_frac(n) = snop ! snow coverage fraction 0-1
127 if ( iv%instid(inst)%isflg(n) == 0 .or. iv%instid(inst)%isflg(n) == 4 ) then ! sea
128 iv%instid(inst)%surftype(n) = 1
129 else if ( iv%instid(inst)%isflg(n) == 1 .or. iv%instid(inst)%isflg(n) == 5 ) then ! sea-ice with snow
130 iv%instid(inst)%surftype(n) = 2
132 iv%instid(inst)%surftype(n) = 0
137 call da_interp_lin_2d (grid%xb % u10, iv%instid(inst)%info, 1, iv%instid(inst)%u10(n1:n2))
138 call da_interp_lin_2d (grid%xb % v10, iv%instid(inst)%info, 1, iv%instid(inst)%v10(n1:n2))
139 call da_interp_lin_2d (grid%xb % t2, iv%instid(inst)%info, 1, iv%instid(inst)%t2m(n1:n2))
140 call da_interp_lin_2d (grid%xb % q2, iv%instid(inst)%info, 1, iv%instid(inst)%q2m(n1:n2))
141 call da_interp_lin_2d (grid%xb % psfc, iv%instid(inst)%info, 1, iv%instid(inst)%ps (n1:n2))
142 call da_interp_lin_2d (grid%xb % tsk, iv%instid(inst)%info, 1, iv%instid(inst)%ts (n1:n2))
143 call da_interp_lin_2d (grid%xb % terr, iv%instid(inst)%info, 1, iv%instid(inst)%elevation(n1:n2))
145 if ( use_mspps_ts(inst) ) then
146 ! only for AMSU-A over land
147 if ( trim(rttov_inst_name(rtminit_sensor(inst))) == 'amsua' ) then
149 if ( iv%instid(inst)%surftype(n) == 0 ) then
150 call da_mspps_ts(ob%instid(inst)%tb(1:nchan,n), nchan, &
151 iv%instid(inst)%satzen(n), ts_mspps)
152 ! ts_mspps is initilaized as negative values in the
153 ! da_mspps_ts subroutine. Apply only valid values here.
154 if ( ts_mspps > 0.0 ) then
155 iv%instid(inst)%ts(n) = ts_mspps
162 ! variables for calculation of cloud affected radiance
163 !-------------------------------------------------------
165 call da_interp_lin_2d (grid%xb%t (:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%tm(k,:))
166 call da_interp_lin_2d (grid%xb%q (:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%qm(k,:))
167 call da_interp_lin_2d (grid%xb%qrn(:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%qrn(k,:))
168 call da_interp_lin_2d (grid%xb%qcw(:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%qcw(k,:))
169 ! call da_interp_lin_2d (grid%xb%qci(:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%qci(k,:))
170 ! call da_interp_lin_2d (grid%xb%qsn(:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%qsn(k,:))
171 ! call da_interp_lin_2d (grid%xb%qgr(:,:,k), iv%instid(inst)%info, k, iv%instid(inst)%qgr(k,:))
174 iv%instid(inst)%pm(:,n1:n2) = v_p(:,n1:n2)
176 iv%instid(inst)%ps(n1:n2) = 0.01 * iv%instid(inst)%ps(n1:n2) ! hPa
177 iv%instid(inst)%mr2m(n1:n2) = iv%instid(inst)%q2m(n1:n2) * q2ppmv ! ppmv
179 ! ADD for computing cloud liquid water path (mm) from guess
181 pf(kts,n1:n2) = 100.0*iv%instid(inst)%ps(n1:n2)
183 pf(k,n1:n2) = 50.0*(v_p(k-1,n1:n2)+v_p(k,n1:n2))
185 pf(kte+1,n1:n2)= 50.0*v_p(kte,n1:n2)
187 iv%instid(inst)%clwp(n1:n2) = 0.0
189 dpf(k,n1:n2) = pf(k,n1:n2) - pf(k+1,n1:n2)
190 clw(k,n1:n2) = iv%instid(inst)%qcw(k,n1:n2)*dpf(k,n1:n2)/gravity
191 where (v_p(k,n1:n2)<100.0) clw (k,n1:n2) = 0.0
192 iv%instid(inst)%clwp(n1:n2) =iv%instid(inst)%clwp(n1:n2) + clw(k,n1:n2)
196 !-------------------------------------------
198 nchanprof = nchan*n1n2
199 allocate(emissivity(nchanprof))
200 emissivity(:)%emis_in = 0.0
202 if ( rttov_emis_atlas_ir > 0 .or. rttov_emis_atlas_mw > 0 ) then
203 ! set up emissivity atlas
204 atlas_path = 'emis_data/'
205 write(unit=message(1),fmt='(A,A)') &
206 'Setting up emissivity atlas for instrument ', trim(iv%instid(inst)%rttovid_string)
207 call da_message(message(1:1))
208 call rttov_setup_emis_atlas( &
211 grid%start_month, & ! in
212 atlas_type(inst), & ! in
214 atlas_id(inst), & ! in, optional
215 path = trim(atlas_path), & ! in, optional
216 coefs = coefs(inst)) ! in
218 if ( errorstatus /= errorstatus_success ) then
219 call da_error(__FILE__,__LINE__, &
220 (/"failure in setting up emissivity atlas"/))
223 ! Generate the chanprof array
224 allocate(chanprof(nchanprof))
226 chanprof((n-n1)*nchan+1:(n-n1+1)*nchan)%prof = n-n1+1
227 chanprof((n-n1)*nchan+1:(n-n1+1)*nchan)%chan = (/ (j, j=1,nchan) /)
230 allocate(profiles(n2-n1+1))
232 ! latitude, longitude, surftype are used for retreiving emis from atlas
233 ! zenangle is used by MW emmisivity atlas
234 ! snow_frac is used only by IR emmisivity atlas
235 profiles(n-n1+1)%latitude = iv%instid(inst)%info%lat(1,n)
236 profiles(n-n1+1)%longitude = iv%instid(inst)%info%lon(1,n)
237 profiles(n-n1+1)%zenangle = iv%instid(inst)%satzen(n)
238 profiles(n-n1+1)%skin%surftype = iv%instid(inst)%surftype(n)
239 profiles(n-n1+1)%skin%snow_fraction = iv%instid(inst)%snow_frac(n)
242 ! Retrieve values from atlas
243 call rttov_get_emis( &
250 emissivity=emissivity(:)%emis_in ) ! out
251 if ( errorstatus /= errorstatus_success ) then
252 call da_error(__FILE__,__LINE__, &
253 (/"failure in retrieving emissivity values"/))
255 deallocate (profiles)
256 deallocate (chanprof)
259 if ( use_mspps_emis(inst) ) then
260 ! Only for AMSU-A over land
261 if ( trim(rttov_inst_name(rtminit_sensor(inst))) == 'amsua' ) then
262 allocate(em_mspps(nchan))
264 if ( iv%instid(inst)%surftype(n) == 0 ) then
265 call da_mspps_emis(ob%instid(inst)%tb(1:nchan,n), nchan, em_mspps)
267 if ( emissivity((n-n1)*nchan+k)%emis_in < 0.01 ) then
268 emissivity((n-n1)*nchan+k)%emis_in = em_mspps(k)
278 !$OMP PRIVATE ( n, temp, temp2, temp3 )
280 con_vars(n) % nlevels = nlevels
281 allocate (con_vars(n) % t(nlevels))
282 allocate (con_vars(n) % q(nlevels))
283 if ( use_rttov_kmatrix ) then
284 allocate (con_vars(n) % t_jac(nchan,nlevels))
285 allocate (con_vars(n) % q_jac(nchan,nlevels))
286 allocate (con_vars(n) % ps_jac(nchan))
287 con_vars(n) % t_jac(:,:) = 0.0
288 con_vars(n) % q_jac(:,:) = 0.0
289 con_vars(n) % ps_jac(:) = 0.0
292 con_vars(n) % t(1:nlevels) = iv%instid(inst)%t(1:nlevels,n)
293 con_vars(n) % q(1:nlevels) = iv%instid(inst)%mr(1:nlevels,n)
294 con_vars(n) % ps = iv%instid(inst)%ps(n)
296 aux_vars(n) % t2m = iv%instid(inst)%t2m(n)
297 aux_vars(n) % q2m = iv%instid(inst)%mr2m(n)
298 aux_vars(n) % u10 = iv%instid(inst)%u10(n)
299 aux_vars(n) % v10 = iv%instid(inst)%v10(n)
300 aux_vars(n) % surftype = iv%instid(inst)%surftype(n)
301 aux_vars(n) % surft = iv%instid(inst)%ts(n)
302 aux_vars(n) % satzen = iv%instid(inst)%satzen(n)
303 aux_vars(n) % satazi = iv%instid(inst)%satazi(n)
304 aux_vars(n) % solzen = iv%instid(inst)%solzen(n)
305 aux_vars(n) % solazi = iv%instid(inst)%solazi(n)
306 aux_vars(n) % elevation = iv%instid(inst)%elevation(n) !iv%instid(inst)%info%elv(n)
307 aux_vars(n) % rlat = iv%instid(inst)%info%lat(1,n)
309 ! [1.3] Call RTM forward model
310 ! da_rttov_direct nominally an array version, but doesn't handle arrays
311 ! of surface flags properly
312 ! da_rttov_k or da_rttov_direct is used one profile per call
313 allocate(temp(nchan),temp2(nchan),temp3(nchan,nlevels-1))
314 if ( use_rttov_kmatrix ) then
315 call da_rttov_k (inst, nchan, 1, nlevels, &
316 con_vars(n:n), aux_vars(n:n), &
317 temp, temp2, temp3, emissivity((n-n1)*nchan+1:(n-n1+1)*nchan))
318 iv%instid(inst)%emiss(:,n) = emissivity((n-n1)*nchan+1:(n-n1+1)*nchan)%emis_out
320 call da_rttov_direct (inst, nchan, 1, nlevels, &
321 con_vars(n:n), aux_vars(n:n), &
322 temp, temp2, temp3, emissivity((n-n1)*nchan+1:(n-n1+1)*nchan))
323 iv%instid(inst)%emiss(:,n) = emissivity((n-n1)*nchan+1:(n-n1+1)*nchan)%emis_out
325 iv%instid(inst)%tb_xb(:,n)=temp(:)
326 iv%instid(inst)%rad_xb(:,n)=temp2(:)
327 ! Overcast Radiances for AIRS Cloud Detection(MMR)
328 iv%instid(inst)%rad_ovc(:,1:nlevels-1,n)=temp3(:,:) ! overcast nlayers=nlevels-1
329 deallocate(temp,temp2,temp3)
332 !$OMP END PARALLEL DO
334 if ( use_rttov_kmatrix ) then
337 iv%instid(inst)%t_jacobian(:,k,n) = con_vars(n)%t_jac(:,k)
338 iv%instid(inst)%q_jacobian(:,k,n) = con_vars(n)%q_jac(:,k)
340 iv%instid(inst)%ps_jacobian(:,n) = con_vars(n)%ps_jac(:)
343 deallocate (con_vars(n) % t_jac)
344 deallocate (con_vars(n) % q_jac)
345 deallocate (con_vars(n) % ps_jac)
350 deallocate (con_vars(n) % t)
351 deallocate (con_vars(n) % q)
354 !----------------------------------------------------------------
355 ! [2.0] calculate components of innovation vector:
356 !----------------------------------------------------------------
360 if (iv%instid(inst)%tb_inv(k,n) > missing_r) then
361 iv%instid(inst)%tb_inv(k,n) = ob%instid(inst)%tb(k,n) - iv%instid(inst)%tb_xb(k,n)
363 iv%instid(inst)%tb_inv(k,n) = missing_r
364 iv%instid(inst)%tb_qc(k,n) = qc_bad
374 deallocate (con_vars)
375 deallocate (aux_vars)
376 deallocate (emissivity)
378 if ( rttov_emis_atlas_ir > 0 .or. rttov_emis_atlas_mw > 0 ) then
379 call rttov_deallocate_emis_atlas(atlas)
382 end do ! end loop for sensor
384 if (trace_use) call da_trace_exit("da_get_innov_vector_rttov")
386 call da_error(__FILE__,__LINE__, &
387 (/"Must compile with $RTTOV option for radiances"/))
390 end subroutine da_get_innov_vector_rttov