1 subroutine da_transform_xtoy_rttov_adj ( iv, jo_grad_y, jo_grad_x )
3 !---------------------------------------------------------------------------
4 ! Purpose: transform gradient from obs space to model grid space.
6 ! METHOD: jo_grad_x = H^T jo_grad_y = - H^T R^-1 ( d - H delta_x )
7 ! 1. input gradient in obs space and reference state of RTTOV
8 ! 2. call adjoint of RTM
9 ! 3. adjoint of interpolation from model grid to obs loc
10 !---------------------------------------------------------------------------
14 !#include "rttov_v2q.interface"
16 type (x_type), intent(inout) :: jo_grad_x !
17 type (y_type), intent(in) :: jo_grad_y ! H' delta_x
18 type (iv_type), intent(in) :: iv ! O-B structure.
22 integer :: i, j, k,c ! Index dimension.
23 integer :: nlevels ! Number of obs levels.
24 integer :: num_rad ! Number of radiance obs
26 integer :: status(mpi_status_size) ! MPI status.
29 real, allocatable :: model_mr(:)
34 type(con_vars_type), allocatable :: con_vars(:), con_vars_ad(:)
35 type(aux_vars_type), allocatable :: aux_vars(:)
37 ! evenly distributed versions
38 type(con_vars_type), allocatable :: d_con_vars(:), d_con_vars_ad(:)
39 type(aux_vars_type), allocatable :: d_aux_vars(:)
40 real, allocatable :: d_tb(:,:)
41 integer :: d_num_rad, l_num_rad,e,s,len,nl
42 real, allocatable :: temp_t(:,:),temp_q(:,:), temp_ps(:), rtemp(:,:)
43 real, allocatable :: temp_tb(:,:)
44 integer, allocatable :: itemp(:,:)
46 if (iv%num_inst < 1) return
48 if (trace_use) call da_trace_entry("da_transform_xtoy_rttov_adj")
50 do i = 1, iv%num_inst ! loop for sensor
52 if (iv%instid(i)%num_rad_glo < 1) cycle
54 num_rad = iv%instid(i)%num_rad
55 nlevels = iv%instid(i)%nlevels
56 nchan = iv%instid(i)%nchan
60 allocate (model_mr(1:nlevels))
62 allocate (con_vars(num_rad))
63 allocate (con_vars_ad(num_rad))
64 allocate (aux_vars(num_rad))
66 !---------------------------------------------------------------
67 ! [1.0] assign tb = R^-1 Re :
68 !---------------------------------------------------------------
70 !---------------------------------------------
71 ! [2.0] get input of da_rttov_ad
72 !---------------------------------------------
75 con_vars(n) % nlevels = nlevels
77 allocate (con_vars(n) % t(nlevels))
78 allocate (con_vars(n) % q(nlevels))
79 allocate (con_vars_ad(n) % t(nlevels))
80 allocate (con_vars_ad(n) % q(nlevels))
82 con_vars(n) % t(:) = 0.0
83 con_vars(n) % q(:) = 0.0
84 con_vars_ad(n) % t(:) = 0.0
85 con_vars_ad(n) % q(:) = 0.0
87 con_vars(n) % t(:) = iv%instid(i)%t(:,n)
88 con_vars(n) % q(:) = iv%instid(i)%mr(:,n)
89 con_vars(n) % ps = iv%instid(i)%ps(n)
91 aux_vars(n) % t2m = iv%instid(i)%t2m(n)
92 aux_vars(n) % q2m = iv%instid(i)%mr2m(n)
93 aux_vars(n) % u10 = iv%instid(i)%u10(n)
94 aux_vars(n) % v10 = iv%instid(i)%v10(n)
96 aux_vars(n) % surftype = iv%instid(i)%landsea_mask(n)
97 aux_vars(n) % surft = iv%instid(i)%ts(n)
98 ! aux_vars(n) % fastem(:) = 0.0
100 aux_vars(n) % satzen = iv%instid(i)%satzen(n)
101 aux_vars(n) % satazi = iv%instid(i)%satazi(n)
105 !-------------------------------------------------
106 ! [2.9] Distribute evenly across processors
107 !-------------------------------------------------
109 d_num_rad=num_tovs_after(i,myproc+1)
111 if (d_num_rad > 0) then
112 allocate (d_con_vars(d_num_rad))
113 allocate (d_con_vars_ad(d_num_rad))
114 allocate (d_aux_vars(d_num_rad))
115 allocate (d_tb(nchan,d_num_rad))
117 d_con_vars(:) % nlevels = nlevels
119 allocate (d_con_vars(n) % t(nlevels))
120 allocate (d_con_vars(n) % q(nlevels))
121 d_con_vars(n) % t(:) = 0.0
122 d_con_vars(n) % q(:) = 0.0
123 allocate (d_con_vars_ad(n) % t(nlevels))
124 allocate (d_con_vars_ad(n) % q(nlevels))
125 d_con_vars_ad(n) % t(:) = 0.0
126 d_con_vars_ad(n) % q(:) = 0.0
129 ! Fill up with data that stays local
131 l_num_rad=min(num_rad,d_num_rad)
133 if (l_num_rad > 0) then
135 d_con_vars(n) % t(:) = con_vars(n) % t(:)
136 d_con_vars(n) % q(:) = con_vars(n) % q(:)
137 ! d_aux_vars(n) % fastem(:) = 0.0
139 d_con_vars(1:l_num_rad) % nlevels = con_vars(1:l_num_rad) % nlevels
140 d_con_vars(1:l_num_rad) % ps = con_vars(1:l_num_rad) % ps
141 d_aux_vars(1:l_num_rad) % t2m = aux_vars(1:l_num_rad) % t2m
142 d_aux_vars(1:l_num_rad) % q2m = aux_vars(1:l_num_rad) % q2m
143 d_aux_vars(1:l_num_rad) % u10 = aux_vars(1:l_num_rad) % u10
144 d_aux_vars(1:l_num_rad) % v10 = aux_vars(1:l_num_rad) % v10
145 d_aux_vars(1:l_num_rad) % surftype = aux_vars(1:l_num_rad) % surftype
146 d_aux_vars(1:l_num_rad) % surft = aux_vars(1:l_num_rad) % surft
147 d_aux_vars(1:l_num_rad) % satzen = aux_vars(1:l_num_rad) % satzen
148 d_aux_vars(1:l_num_rad) % satazi = aux_vars(1:l_num_rad) % satazi
150 d_tb(:,1:l_num_rad) = jo_grad_y%instid(i)%tb(:,1:l_num_rad)
153 ! Get data from elsewhere
155 do c=1,tovs_copy_count(i)
156 if (tovs_send_pe(i,c)==myproc) then
157 s=tovs_send_start(i,c)
158 len=tovs_send_count(i,c)
161 allocate(temp_t(nlevels,len))
163 temp_t(:,j)=con_vars(s+j-1) % t(:)
165 call mpi_send( temp_t,nl, true_mpi_real, tovs_recv_pe(i,c), &
168 allocate(temp_q(nlevels,len))
170 temp_q(:,j)=con_vars(s+j-1) % q(:)
172 call mpi_send (temp_q,nl, true_mpi_real, tovs_recv_pe(i,c), &
175 allocate (temp_tb(nchan,len))
176 temp_tb(:,:)=jo_grad_y%instid(i)%tb(:,s:e)
177 call mpi_send (temp_tb,len*nchan, &
178 true_mpi_real, tovs_recv_pe(i,c), c*8+3, comm, ierr)
180 allocate (rtemp(len,8))
181 rtemp(:,1)= con_vars(s:e) % ps
182 rtemp(:,2)= aux_vars(s:e) % t2m
183 rtemp(:,3)= aux_vars(s:e) % q2m
184 rtemp(:,4)= aux_vars(s:e) % u10
185 rtemp(:,5)= aux_vars(s:e) % v10
186 rtemp(:,6)= aux_vars(s:e) % surft
187 rtemp(:,7)= aux_vars(s:e) % satzen
188 rtemp(:,8)= aux_vars(s:e) % satazi
189 call mpi_send(rtemp,len*8, true_mpi_real, tovs_recv_pe(i,c), &
192 allocate (itemp(len,2))
193 itemp(:,1)= con_vars(s:e) % nlevels
194 itemp(:,2)= aux_vars(s:e) % surftype
195 call mpi_send(itemp,len*2, mpi_integer, tovs_recv_pe(i,c), &
199 if (tovs_recv_pe(i,c)==myproc) then
200 s=tovs_recv_start(i,c)
201 len=tovs_send_count(i,c)
204 allocate(temp_t(nlevels,len))
205 call mpi_recv(temp_t,nl, true_mpi_real, tovs_send_pe(i,c), &
206 c*8+1, comm, status, ierr)
208 d_con_vars(s+j-1) % t(:)=temp_t(:,j)
211 allocate(temp_q(nlevels,len))
212 call mpi_recv(temp_q,nl, true_mpi_real, tovs_send_pe(i,c), &
213 c*8+2, comm, status, ierr)
215 d_con_vars(s+j-1) % q(:)=temp_q(:,j)
218 allocate (temp_tb(nchan,len))
219 call mpi_recv(temp_tb,len*nchan, true_mpi_real, &
220 tovs_send_pe(i,c), c*8+3, comm, status, ierr)
221 d_tb(:,s:e)=temp_tb(:,:)
223 allocate (rtemp(len,8))
224 call mpi_recv(rtemp,len*8, true_mpi_real, &
225 tovs_send_pe(i,c), c*8+4, comm, status, ierr)
226 d_con_vars(s:e) % ps = rtemp(:,1)
227 d_aux_vars(s:e) % t2m = rtemp(:,2)
228 d_aux_vars(s:e) % q2m = rtemp(:,3)
229 d_aux_vars(s:e) % u10 = rtemp(:,4)
230 d_aux_vars(s:e) % v10 = rtemp(:,5)
231 d_aux_vars(s:e) % surft = rtemp(:,6)
232 d_aux_vars(s:e) % satzen = rtemp(:,7)
233 d_aux_vars(s:e) % satazi = rtemp(:,8)
235 allocate (itemp(len,2))
236 call mpi_recv(itemp,len*2, mpi_integer, &
237 tovs_send_pe(i,c), c*8+5, comm, status, ierr)
238 d_con_vars(s:e) % nlevels = itemp(:,1)
239 d_aux_vars(s:e) % surftype = itemp(:,2)
243 if (tovs_send_pe(i,c)==myproc) then
250 if (tovs_recv_pe(i,c)==myproc) then
260 if (d_num_rad > 0) then
262 call da_rttov_ad (i, nchan, d_num_rad, d_con_vars, &
263 d_aux_vars, d_con_vars_ad, d_tb)
268 call da_rttov_ad (i, nchan, 1, d_con_vars(n:n), &
269 d_aux_vars(n:n), d_con_vars_ad(n:n), d_tb(:,n:n))
271 !$OMP END PARALLEL DO
277 if (l_num_rad > 0) then
279 con_vars_ad(n) % t(:) = d_con_vars_ad(n) % t(:)
280 con_vars_ad(n) % q(:) = d_con_vars_ad(n) % q(:)
283 con_vars_ad(1:l_num_rad) % ps = d_con_vars_ad(1:l_num_rad) % ps
285 end if ! d_num_rad > 0
287 ! Return the data to other processors. Note the meaning of send_pe and
288 ! recv_pe is swapped here
292 do c=1,tovs_copy_count(i)
293 if (tovs_recv_pe(i,c)==myproc) then
294 s=tovs_recv_start(i,c)
295 len=tovs_send_count(i,c)
298 allocate(temp_t(nlevels,len))
300 temp_t(:,j)=d_con_vars_ad(s+j-1) % t(:)
302 call mpi_send (temp_t,nl, true_mpi_real, tovs_send_pe(i,c), &
305 allocate(temp_q(nlevels,len))
307 temp_q(:,j)=d_con_vars_ad(s+j-1) % q(:)
309 call mpi_send (temp_q,nl, true_mpi_real, tovs_send_pe(i,c), &
312 allocate(rtemp(len,1))
313 rtemp(:,1) = d_con_vars_ad(s:e) % ps
314 call mpi_send (rtemp,len, true_mpi_real, tovs_send_pe(i,c), &
318 if (tovs_send_pe(i,c)==myproc) then
319 s=tovs_send_start(i,c)
320 len=tovs_send_count(i,c)
323 allocate(temp_t(nlevels,len))
324 call mpi_recv (temp_t,nl, true_mpi_real, tovs_recv_pe(i,c), &
325 c*8+6, comm, status, ierr)
327 con_vars_ad(s+j-1) % t(:)=temp_t(:,j)
330 allocate(temp_q(nlevels,len))
331 call mpi_recv (temp_q,nl, true_mpi_real, tovs_recv_pe(i,c), &
332 c*8+7, comm, status, ierr)
334 con_vars_ad(s+j-1) % q(:)=temp_q(:,j)
337 allocate(rtemp(len,1))
338 call mpi_recv (rtemp,len, true_mpi_real, tovs_recv_pe(i,c), &
339 c*8+8, comm, status, ierr)
340 con_vars_ad(s:e) % ps=rtemp(:,1)
343 if (tovs_recv_pe(i,c)==myproc) then
348 if (tovs_send_pe(i,c)==myproc) then
355 if (d_num_rad > 0) then
357 deallocate (d_con_vars(n) % t)
358 deallocate (d_con_vars(n) % q)
359 deallocate (d_con_vars_ad(n) % t)
360 deallocate (d_con_vars_ad(n) % q)
364 deallocate (d_con_vars)
365 deallocate (d_aux_vars)
366 deallocate (d_con_vars_ad)
369 ! adjoint of convert to hPa
371 if (num_rad > 0) then
372 con_vars_ad(:)% ps = con_vars_ad(:)%ps * 0.01
376 ! 4.2 scale transform
379 model_mr(k) = con_vars_ad(n) % q(k)
381 if (iv%instid(i)%info%zk(k,n) <= 0.0) then
382 con_vars_ad(n)%t(k) = 0.0 !coefs(i) % ref_prfl_t(k,gas_id_watervapour)
383 con_vars_ad(n)%q(k) = 0.0 !coefs(i) % ref_prfl_mr(k,gas_id_watervapour)
385 ! adjoint of q(kg/kg) to ppmv
387 con_vars_ad(n)%q(k) = model_mr(k) * q2ppmv
389 ! gas_unit_ppmv, &! in
391 ! gas_id_watervapour, &! in
393 ! con_vars_ad(n)%q(k) ) ! inout
398 if (num_rad > 0) then
399 allocate(temp_t(nlevels,num_rad))
401 temp_t(:,n) = con_vars_ad(n)% t(:)
403 call da_interp_lin_3d_adj (jo_grad_x%t, iv%instid(i)%info, temp_t)
406 allocate(temp_q(nlevels,num_rad))
408 temp_q(:,n) = con_vars_ad(n)% q(:)
410 call da_interp_lin_3d_adj (jo_grad_x%q, iv%instid(i)%info, temp_q)
413 allocate(temp_ps(num_rad))
415 temp_ps(n) = con_vars_ad(n)% ps
417 call da_interp_lin_2d_adj (jo_grad_x% psfc, iv%instid(i)%info, 1, temp_ps)
421 if (num_rad > 0) then
423 deallocate (con_vars(n) % t)
424 deallocate (con_vars(n) % q)
425 deallocate (con_vars_ad(n) % t)
426 deallocate (con_vars_ad(n) % q)
429 deallocate (con_vars)
430 deallocate (aux_vars)
431 deallocate (con_vars_ad)
432 deallocate (model_mr)
434 end do ! end loop for sensor
436 if (trace_use) call da_trace_exit("da_transform_xtoy_rttov_adj")
438 call da_error(__FILE__,__LINE__, &
439 (/"Must compile with $RTTOV option for radiances"/))
442 end subroutine da_transform_xtoy_rttov_adj