FV3 Bundle
type_displ.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: type_displ
3 ! Purpose: displacement data derived type
4 ! Author: Benjamin Menetrier
5 ! Licensing: this code is distributed under the CeCILL-C license
6 ! Copyright © 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
7 !----------------------------------------------------------------------
8 module type_displ
9 
10 use fckit_mpi_module, only: fckit_mpi_sum,fckit_mpi_status
11 use netcdf
12 !$ use omp_lib
15 use tools_kinds, only: kind_real
17 use tools_nc, only: ncfloat
18 use tools_qsort, only: qsort
19 use tools_stripack, only: trans,scoord
20 use type_com, only: com_type
21 use type_ens, only: ens_type
22 use type_geom, only: geom_type
23 use type_linop, only: linop_type
24 use type_mesh, only: mesh_type
25 use type_mpl, only: mpl_type
26 use type_nam, only: nam_type
27 use type_samp, only: samp_type
28 
29 implicit none
30 
31 character(len=1024) :: displ_method = 'cor_max' ! Displacement computation method
32 real(kind_real),parameter :: cor_th = 0.2_kind_real ! Correlation threshold
33 
34 ! Displacement data derived type
36  integer :: niter ! Number of stored iterations
37  real(kind_real),allocatable :: dist(:,:,:) ! Displacement distance
38  real(kind_real),allocatable :: valid(:,:,:) ! Displacement validity
39  real(kind_real),allocatable :: rhflt(:,:,:) ! Displacement filtering support radius
40 
41  real(kind_real),allocatable :: lon_c2a(:,:) ! Longitude origin
42  real(kind_real),allocatable :: lat_c2a(:,:) ! Latitude origin
43  real(kind_real),allocatable :: lon_c2a_raw(:,:,:) ! Raw displaced longitude
44  real(kind_real),allocatable :: lat_c2a_raw(:,:,:) ! Raw displaced latitude
45  real(kind_real),allocatable :: dist_c2a_raw(:,:,:) ! Raw displacement distance
46  real(kind_real),allocatable :: lon_c2a_flt(:,:,:) ! Filtered displaced longitude
47  real(kind_real),allocatable :: lat_c2a_flt(:,:,:) ! Filtered displaced latitude
48  real(kind_real),allocatable :: dist_c2a_flt(:,:,:) ! Displacement distance, filtered
49 contains
50  procedure :: alloc => displ_alloc
51  procedure :: dealloc => displ_dealloc
52  procedure :: compute => displ_compute
53  procedure :: write => displ_write
54 end type displ_type
55 
56 private
57 public :: displ_type
58 
59 contains
60 
61 !----------------------------------------------------------------------
62 ! Subroutine: displ_alloc
63 ! Purpose: displacement data allocation
64 !----------------------------------------------------------------------
65 subroutine displ_alloc(displ,nam,geom,samp)
66 
67 implicit none
68 
69 ! Passed variables
70 class(displ_type),intent(inout) :: displ ! Displacement data
71 type(nam_type),intent(in) :: nam ! Namelist
72 type(geom_type),intent(in) :: geom ! Geometry
73 type(samp_type),intent(in) :: samp ! Sampling
74 
75 ! Allocation
76 allocate(displ%dist(0:nam%displ_niter,geom%nl0,2:nam%nts))
77 allocate(displ%valid(0:nam%displ_niter,geom%nl0,2:nam%nts))
78 allocate(displ%rhflt(0:nam%displ_niter,geom%nl0,2:nam%nts))
79 allocate(displ%lon_c2a(samp%nc2a,geom%nl0))
80 allocate(displ%lat_c2a(samp%nc2a,geom%nl0))
81 allocate(displ%lon_c2a_raw(samp%nc2a,geom%nl0,2:nam%nts))
82 allocate(displ%lat_c2a_raw(samp%nc2a,geom%nl0,2:nam%nts))
83 allocate(displ%dist_c2a_raw(samp%nc2a,geom%nl0,2:nam%nts))
84 allocate(displ%lon_c2a_flt(samp%nc2a,geom%nl0,2:nam%nts))
85 allocate(displ%lat_c2a_flt(samp%nc2a,geom%nl0,2:nam%nts))
86 allocate(displ%dist_c2a_flt(samp%nc2a,geom%nl0,2:nam%nts))
87 
88 ! Initialization
89 call msr(displ%dist)
90 call msr(displ%valid)
91 call msr(displ%rhflt)
92 call msr(displ%lon_c2a)
93 call msr(displ%lat_c2a)
94 call msr(displ%lon_c2a_raw)
95 call msr(displ%lat_c2a_raw)
96 call msr(displ%dist_c2a_raw)
97 call msr(displ%lon_c2a_flt)
98 call msr(displ%lat_c2a_flt)
99 call msr(displ%dist_c2a_flt)
100 
101 end subroutine displ_alloc
102 
103 !----------------------------------------------------------------------
104 ! Subroutine: displ_dealloc
105 ! Purpose: displacement data deallocation
106 !----------------------------------------------------------------------
107 subroutine displ_dealloc(displ)
109 implicit none
110 
111 ! Passed variables
112 class(displ_type),intent(inout) :: displ ! Displacement data
113 
114 ! Deallocation
115 if (allocated(displ%dist)) deallocate(displ%dist)
116 if (allocated(displ%valid)) deallocate(displ%valid)
117 if (allocated(displ%rhflt)) deallocate(displ%rhflt)
118 if (allocated(displ%lon_c2a)) deallocate(displ%lon_c2a)
119 if (allocated(displ%lat_c2a)) deallocate(displ%lat_c2a)
120 if (allocated(displ%lon_c2a_raw)) deallocate(displ%lon_c2a_raw)
121 if (allocated(displ%lat_c2a_raw)) deallocate(displ%lat_c2a_raw)
122 if (allocated(displ%dist_c2a_raw)) deallocate(displ%dist_c2a_raw)
123 if (allocated(displ%lon_c2a_flt)) deallocate(displ%lon_c2a_flt)
124 if (allocated(displ%lat_c2a_flt)) deallocate(displ%lat_c2a_flt)
125 if (allocated(displ%dist_c2a_flt)) deallocate(displ%dist_c2a_flt)
126 
127 end subroutine displ_dealloc
128 
129 !----------------------------------------------------------------------
130 ! Subroutine: displ_compute
131 ! Purpose: compute correlation maximum displacement
132 !----------------------------------------------------------------------
133 subroutine displ_compute(displ,mpl,nam,geom,samp,ens)
135 implicit none
136 
137 ! Passed variables
138 class(displ_type),intent(inout) :: displ ! Displacement data
139 type(mpl_type),intent(inout) :: mpl ! MPI data
140 type(nam_type),intent(in) :: nam ! Namelist
141 type(geom_type),intent(in) :: geom ! Geometry
142 type(samp_type),intent(inout) :: samp ! Sampling
143 type(ens_type), intent(in) :: ens ! Ensemble
144 
145 ! Local variables
146 integer :: ic0,ic1,ic2,ic2a,jc0,jc1,il0,il0i,isub,iv,its,ie,ie_sub,iter,ic0a,jc0d,ind
147 real(kind_real) :: fac4,fac6,m11_avg,m2m2_avg,fld_1,fld_2,drhflt,dum,cormax
148 real(kind_real) :: lon_target,lat_target,rad_target,x_cm,y_cm,z_cm,n_cm
149 real(kind_real) :: norm_tot,distsum_tot
150 real(kind_real),allocatable :: fld_ext(:,:,:,:)
151 real(kind_real),allocatable :: m1_1(:,:,:,:,:,:),m2_1(:,:,:,:,:,:)
152 real(kind_real),allocatable :: m1_2(:,:,:,:,:,:),m2_2(:,:,:,:,:,:)
153 real(kind_real),allocatable :: m11(:,:,:,:,:,:)
154 real(kind_real),allocatable :: cor(:),cor_avg(:)
155 real(kind_real),allocatable :: x(:),y(:),z(:)
156 real(kind_real) :: dlon_c0a(geom%nc0a),dlat_c0a(geom%nc0a)
157 real(kind_real) :: dlon_c2a(samp%nc2a),dlat_c2a(samp%nc2a),dist_c2a(samp%nc2a)
158 real(kind_real) :: dlon_c2b(samp%nc2b),dlat_c2b(samp%nc2b)
159 real(kind_real) :: lon_c2a_ori(samp%nc2a,geom%nl0),lat_c2a_ori(samp%nc2a,geom%nl0)
160 real(kind_real) :: lon_c2a(samp%nc2a),lat_c2a(samp%nc2a)
161 real(kind_real),allocatable :: lon_c2(:),lat_c2(:),valid_c2(:)
162 real(kind_real) :: x_ori(samp%nc2a),y_ori(samp%nc2a),z_ori(samp%nc2a)
163 real(kind_real) :: dx_ini(samp%nc2a),dy_ini(samp%nc2a),dz_ini(samp%nc2a)
164 real(kind_real) :: dx(samp%nc2a),dy(samp%nc2a),dz(samp%nc2a)
165 logical :: dichotomy,convergence
166 logical :: mask_c2a(samp%nc2a,geom%nl0),mask_c2(nam%nc2,geom%nl0)
167 type(mesh_type) :: mesh
168 
169 ! Allocation
170 call displ%alloc(nam,geom,samp)
171 allocate(fld_ext(samp%nc0d,geom%nl0,nam%nv,2:nam%nts))
172 allocate(m1_1(nam%nc1,samp%nc2a,geom%nl0,nam%nv,2:nam%nts,ens%nsub))
173 allocate(m2_1(nam%nc1,samp%nc2a,geom%nl0,nam%nv,2:nam%nts,ens%nsub))
174 allocate(m1_2(nam%nc1,samp%nc2a,geom%nl0,nam%nv,2:nam%nts,ens%nsub))
175 allocate(m2_2(nam%nc1,samp%nc2a,geom%nl0,nam%nv,2:nam%nts,ens%nsub))
176 allocate(m11(nam%nc1,samp%nc2a,geom%nl0,nam%nv,2:nam%nts,ens%nsub))
177 allocate(lon_c2(nam%nc2))
178 allocate(lat_c2(nam%nc2))
179 allocate(valid_c2(nam%nc2))
180 
181 ! Initialization
182 m1_1 = 0.0
183 m2_1 = 0.0
184 m1_2 = 0.0
185 m2_2 = 0.0
186 m11 = 0.0
187 
188 ! Initialization
189 do il0=1,geom%nl0
190  do ic2=1,nam%nc2
191  ic1 = samp%c2_to_c1(ic2)
192  mask_c2(ic2,il0) = samp%c1l0_log(ic1,il0)
193  end do
194  do ic2a=1,samp%nc2a
195  ic2 = samp%c2a_to_c2(ic2a)
196  mask_c2a(ic2a,il0) = mask_c2(ic2,il0)
197  if (mask_c2a(ic2a,il0)) then
198  ic0 = samp%c2_to_c0(ic2)
199  lon_c2a_ori(ic2a,il0) = geom%lon(ic0)
200  lat_c2a_ori(ic2a,il0) = geom%lat(ic0)
201  end if
202  end do
203 end do
204 
205 ! Copy
206 displ%lon_c2a = lon_c2a_ori
207 displ%lat_c2a = lat_c2a_ori
208 
209 ! Compute moments
210 write(mpl%info,'(a7,a)') '','Compute moments'
211 call flush(mpl%info)
212 do isub=1,ens%nsub
213  if (ens%nsub==1) then
214  write(mpl%info,'(a10,a)',advance='no') '','Full ensemble, member:'
215  else
216  write(mpl%info,'(a10,a,i4,a)',advance='no') '','Sub-ensemble ',isub,', member:'
217  end if
218  call flush(mpl%info)
219 
220  ! Compute centered moments iteratively
221  do ie_sub=1,ens%ne/ens%nsub
222  write(mpl%info,'(i4)',advance='no') ie_sub
223  call flush(mpl%info)
224 
225  ! Full ensemble index
226  ie = ie_sub+(isub-1)*ens%ne/ens%nsub
227 
228  ! Computation factors
229  fac4 = 1.0/real(ie_sub,kind_real)
230  fac6 = real(ie_sub-1,kind_real)/real(ie_sub,kind_real)
231 
232  do its=2,nam%nts
233  do iv=1,nam%nv
234  ! Halo extension
235  call samp%com_AD%ext(mpl,geom%nl0,ens%fld(:,:,iv,its,ie),fld_ext(:,:,iv,its))
236  end do
237  end do
238 
239  do its=2,nam%nts
240  do iv=1,nam%nv
241  !$omp parallel do schedule(static) private(il0,ic2a,ic2,ic1,jc1,ic0,jc0,ic0a,jc0d,fld_1,fld_2)
242  do il0=1,geom%nl0
243  do ic2a=1,samp%nc2a
244  ic2 = samp%c2a_to_c2(ic2a)
245  ic1 = samp%c2_to_c1(ic2)
246  if (samp%c1l0_log(ic1,il0)) then
247  do jc1=1,nam%nc1
248  if (samp%displ_mask(jc1,ic2)) then
249  ! Indices
250  ic0 = samp%c2_to_c0(ic2)
251  jc0 = samp%c1_to_c0(jc1)
252  ic0a = geom%c0_to_c0a(ic0)
253  jc0d = samp%c0_to_c0d(jc0)
254 
255  ! Copy points
256  fld_1 = ens%fld(ic0a,il0,iv,1,ie)
257  fld_2 = fld_ext(jc0d,il0,iv,its)
258 
259  ! Remove means
260  fld_1 = fld_1 - m1_1(jc1,ic2a,il0,iv,its,isub)
261  fld_2 = fld_2 - m1_2(jc1,ic2a,il0,iv,its,isub)
262 
263  ! Update high-order moments
264  if (ie_sub>1) then
265  ! Covariance
266  m11(jc1,ic2a,il0,iv,its,isub) = m11(jc1,ic2a,il0,iv,its,isub)+fac6*fld_1*fld_2
267 
268  ! Variances
269  m2_1(jc1,ic2a,il0,iv,its,isub) = m2_1(jc1,ic2a,il0,iv,its,isub)+fac6*fld_1**2
270  m2_2(jc1,ic2a,il0,iv,its,isub) = m2_2(jc1,ic2a,il0,iv,its,isub)+fac6*fld_2**2
271  end if
272 
273  ! Update means
274  m1_1(jc1,ic2a,il0,iv,its,isub) = m1_1(jc1,ic2a,il0,iv,its,isub)+fac4*fld_1
275  m1_2(jc1,ic2a,il0,iv,its,isub) = m1_2(jc1,ic2a,il0,iv,its,isub)+fac4*fld_2
276  end if
277  end do
278  end if
279  end do
280  end do
281  !$omp end parallel do
282  end do
283  end do
284  end do
285  write(mpl%info,'(a)') ''
286  call flush(mpl%info)
287 end do
288 
289 ! Find correlation propagation
290 write(mpl%info,'(a7,a)') '','Find correlation propagation'
291 call flush(mpl%info)
292 
293 do its=2,nam%nts
294  do il0=1,geom%nl0
295  write(mpl%info,'(a10,a,i2,a,i3)') '','Timeslot ',its,' - level ',nam%levs(il0)
296  call flush(mpl%info)
297 
298  ! Number of points
299  call mpl%f_comm%allreduce(real(count(mask_c2a(:,il0)),kind_real),norm_tot,fckit_mpi_sum())
300 
301  !$omp parallel do schedule(static) private(ic2a,ic2,jc1,jc0,iv,m11_avg,m2m2_avg,lon_target,lat_target,rad_target), &
302  !$omp& private(x_cm,y_cm,z_cm,n_cm,ind) firstprivate(cor,cor_avg,x,y,z)
303  do ic2a=1,samp%nc2a
304  ic2 = samp%c2a_to_c2(ic2a)
305  if (mask_c2a(ic2a,il0)) then
306  ! Allocation
307  allocate(cor(nam%nv))
308  allocate(cor_avg(nam%nc1))
309 
310  do jc1=1,nam%nc1
311  ! Initialization
312  call msr(cor_avg(jc1))
313 
314  if (samp%displ_mask(jc1,ic2)) then
315  ! Compute correlation for each variable
316  do iv=1,nam%nv
317  ! Correlation
318  m11_avg = sum(m11(jc1,ic2a,il0,iv,its,:))/real(ens%nsub,kind_real)
319  m2m2_avg = sum(m2_1(jc1,ic2a,il0,iv,its,:))*sum(m2_2(jc1,ic2a,il0,iv,its,:))/real(ens%nsub**2,kind_real)
320  if (m2m2_avg>0.0) then
321  cor(iv) = m11_avg/sqrt(m2m2_avg)
322  else
323  call msr(cor(iv))
324  end if
325  end do
326 
327  ! Average correlations
328  if (isanynotmsr(cor)) then
329  cor_avg(jc1) = sum(cor,mask=isnotmsr(cor))/real(count(isnotmsr(cor)),kind_real)
330  else
331  call mpl%abort('average correlation contains missing values only')
332  end if
333  end if
334  end do
335 
336  select case (trim(displ_method))
337  case ('cor_max')
338  ! Locate the maximum correlation, with a correlation threshold
339  if (maxval(cor_avg)>cor_th) then
340  ! Find maximum
341  call msi(ind)
342  cormax = cor_th
343  do jc1=1,nam%nc1
344  if (cor_avg(jc1)>cormax) then
345  ind = jc1
346  cormax = cor_avg(jc1)
347  end if
348  end do
349  jc1 = ind
350  jc0 = samp%c1_to_c0(jc1)
351  lon_target = geom%lon(jc0)
352  lat_target = geom%lat(jc0)
353  else
354  lon_target = 0.0
355  lat_target = 0.0
356  end if
357  case ('cor_center_mass')
358  ! Locate the correlation center of mass, with a correlation threshold
359 
360  ! Allocation
361  allocate(x(1))
362  allocate(y(1))
363  allocate(z(1))
364 
365  ! Initialization
366  x_cm = 0.0
367  y_cm = 0.0
368  z_cm = 0.0
369  n_cm = 0.0
370 
371  do jc1=1,nam%nc1
372  if (cor_avg(jc1)>max(cor_th,0.5*maxval(cor_avg))) then
373  ! Compute cartesian coordinates
374  jc0 = samp%c1_to_c0(jc1)
375  call trans(1,geom%lat(jc0),geom%lon(jc0),x,y,z)
376 
377  ! Update center of mass
378  x_cm = x_cm+cor_avg(jc1)*x(1)
379  y_cm = y_cm+cor_avg(jc1)*y(1)
380  z_cm = z_cm+cor_avg(jc1)*z(1)
381  n_cm = n_cm+cor_avg(jc1)
382  end if
383  end do
384 
385  if (n_cm>0.0) then
386  ! Final center of mass
387  x_cm = x_cm/n_cm
388  y_cm = y_cm/n_cm
389  z_cm = z_cm/n_cm
390 
391  ! Back to spherical coordinates
392  call scoord(x_cm,y_cm,z_cm,lat_target,lon_target,rad_target)
393  else
394  lon_target = 0.0
395  lat_target = 0.0
396  end if
397 
398  ! Release memory
399  deallocate(x)
400  deallocate(y)
401  deallocate(z)
402  end select
403 
404  ! Compute displacement and distance
405  dlon_c2a(ic2a) = lon_target-lon_c2a_ori(ic2a,il0)
406  dlat_c2a(ic2a) = lat_target-lat_c2a_ori(ic2a,il0)
407  call lonlatmod(dlon_c2a(ic2a),dlat_c2a(ic2a))
408  call sphere_dist(lon_c2a_ori(ic2a,il0),lat_c2a_ori(ic2a,il0),lon_target,lat_target,dist_c2a(ic2a))
409 
410  ! Release memory
411  deallocate(cor)
412  deallocate(cor_avg)
413  end if
414  end do
415  !$omp end parallel do
416 
417  ! Copy lon/lat
418  do ic2a=1,samp%nc2a
419  lon_c2a(ic2a) = lon_c2a_ori(ic2a,il0)+dlon_c2a(ic2a)
420  lat_c2a(ic2a) = lat_c2a_ori(ic2a,il0)+dlat_c2a(ic2a)
421  call lonlatmod(lon_c2a(ic2a),lat_c2a(ic2a))
422  end do
423 
424  ! Check raw mesh
425  call mpl%loc_to_glb(samp%nc2a,lon_c2a,nam%nc2,samp%c2_to_proc,samp%c2_to_c2a,.false.,lon_c2)
426  call mpl%loc_to_glb(samp%nc2a,lat_c2a,nam%nc2,samp%c2_to_proc,samp%c2_to_c2a,.false.,lat_c2)
427  if (mpl%main) then
428  mesh = samp%mesh%copy()
429  call mesh%trans(lon_c2,lat_c2)
430  call mesh%check(valid_c2)
431  displ%valid(0,il0,its) = sum(valid_c2,mask=mask_c2(:,il0))/real(count((mask_c2(:,il0))),kind_real)
432  end if
433  call mpl%f_comm%broadcast(displ%valid(0,il0,its),mpl%ioproc-1)
434  displ%rhflt(0,il0,its) = 0.0
435 
436  ! Average distance
437  call mpl%f_comm%allreduce(sum(dist_c2a,mask=mask_c2a(:,il0)),distsum_tot,fckit_mpi_sum())
438  displ%dist(0,il0,its) = distsum_tot/norm_tot
439 
440  ! Copy
441  displ%lon_c2a_raw(:,il0,its) = lon_c2a
442  displ%lat_c2a_raw(:,il0,its) = lat_c2a
443  displ%dist_c2a_raw(:,il0,its) = dist_c2a
444 
445  if (nam%displ_niter>0) then
446  ! Filter displacement
447 
448  ! Convert to cartesian coordinates
449  call trans(samp%nc2a,lat_c2a_ori(:,il0),lon_c2a_ori(:,il0),x_ori,y_ori,z_ori)
450  call trans(samp%nc2a,lat_c2a,lon_c2a,dx_ini,dy_ini,dz_ini)
451 
452  ! Dichotomy initialization
453  dx_ini = dx_ini-x_ori
454  dy_ini = dy_ini-y_ori
455  dz_ini = dz_ini-z_ori
456  convergence = .true.
457  dichotomy = .false.
458  displ%rhflt(1,il0,its) = nam%displ_rhflt
459  drhflt = displ%rhflt(1,il0,its)
460 
461  do iter=1,nam%displ_niter
462  ! Copy increment
463  dx = dx_ini
464  dy = dy_ini
465  dz = dz_ini
466 
467  ! Median filter to remove extreme values
468  call samp%diag_filter(mpl,nam,geom,il0,'median',displ%rhflt(iter,il0,its),dx)
469  call samp%diag_filter(mpl,nam,geom,il0,'median',displ%rhflt(iter,il0,its),dy)
470  call samp%diag_filter(mpl,nam,geom,il0,'median',displ%rhflt(iter,il0,its),dz)
471 
472  ! Average filter to smooth displacement
473  call samp%diag_filter(mpl,nam,geom,il0,'gc99',displ%rhflt(iter,il0,its),dx)
474  call samp%diag_filter(mpl,nam,geom,il0,'gc99',displ%rhflt(iter,il0,its),dy)
475  call samp%diag_filter(mpl,nam,geom,il0,'gc99',displ%rhflt(iter,il0,its),dz)
476 
477  ! Back to spherical coordinates
478  dx = dx+x_ori
479  dy = dy+y_ori
480  dz = dz+z_ori
481  do ic2a=1,samp%nc2a
482  call scoord(dx(ic2a),dy(ic2a),dz(ic2a),lat_c2a(ic2a),lon_c2a(ic2a),dum)
483  end do
484 
485  ! Reduce distance with respect to boundary
486  do ic2a=1,samp%nc2a
487  if (mask_c2a(ic2a,il0)) then
488  ic2 = samp%c2a_to_c2(ic2a)
489  call reduce_arc(lon_c2a_ori(ic2a,il0),lat_c2a_ori(ic2a,il0),lon_c2a(ic2a),lat_c2a(ic2a),samp%mesh%bdist(ic2), &
490  & dist_c2a(ic2a))
491  dlon_c2a(ic2a) = lon_c2a(ic2a)-lon_c2a_ori(ic2a,il0)
492  dlat_c2a(ic2a) = lat_c2a(ic2a)-lat_c2a_ori(ic2a,il0)
493  end if
494  end do
495 
496  ! Copy lon/lat
497  do ic2a=1,samp%nc2a
498  lon_c2a(ic2a) = lon_c2a_ori(ic2a,il0)+dlon_c2a(ic2a)
499  lat_c2a(ic2a) = lat_c2a_ori(ic2a,il0)+dlat_c2a(ic2a)
500  call lonlatmod(lon_c2a(ic2a),lat_c2a(ic2a))
501  end do
502 
503  ! Check mesh
504  call mpl%loc_to_glb(samp%nc2a,lon_c2a,nam%nc2,samp%c2_to_proc,samp%c2_to_c2a,.false.,lon_c2)
505  call mpl%loc_to_glb(samp%nc2a,lat_c2a,nam%nc2,samp%c2_to_proc,samp%c2_to_c2a,.false.,lat_c2)
506  if (mpl%main) then
507  mesh = samp%mesh%copy()
508  call mesh%trans(lon_c2,lat_c2)
509  call mesh%check(valid_c2)
510  displ%valid(iter,il0,its) = sum(valid_c2,mask=mask_c2(:,il0))/real(count((mask_c2(:,il0))),kind_real)
511  end if
512  call mpl%f_comm%broadcast(displ%valid(iter,il0,its),mpl%ioproc-1)
513 
514  ! Compute distances
515  do ic2a=1,samp%nc2a
516  if (mask_c2a(ic2a,il0)) call sphere_dist(lon_c2a_ori(ic2a,il0),lat_c2a_ori(ic2a,il0), &
517  & lon_c2a(ic2a),lat_c2a(ic2a),dist_c2a(ic2a))
518  end do
519 
520  ! Average distance
521  call mpl%f_comm%allreduce(sum(dist_c2a,mask=mask_c2a(:,il0)),distsum_tot,fckit_mpi_sum())
522  displ%dist(iter,il0,its) = distsum_tot/norm_tot
523 
524  ! Print results
525  write(mpl%info,'(a13,a,i2,a,f10.2,a,f6.2,a,f6.2,a,f7.2,a)') '','Iteration ',iter,': rhflt = ', &
526  & displ%rhflt(iter,il0,its)*reqkm,' km, valid points: ',100.0*displ%valid(0,il0,its),'% ~> ', &
527  & 100.0*displ%valid(iter,il0,its),'%, average displacement = ',displ%dist(iter,il0,its)*reqkm,' km'
528  call flush(mpl%info)
529 
530  ! Update support radius
531  if (displ%valid(iter,il0,its)<1.0-nam%displ_tol) then
532  ! Increase filtering support radius
533  if (dichotomy) then
534  drhflt = 0.5*drhflt
535  if (iter<nam%displ_niter) displ%rhflt(iter+1,il0,its) = displ%rhflt(iter,il0,its)+drhflt
536  else
537  convergence = .false.
538  if (iter<nam%displ_niter) displ%rhflt(iter+1,il0,its) = displ%rhflt(iter,il0,its)+drhflt
539  drhflt = 2.0*drhflt
540  end if
541  else
542  ! Convergence
543  convergence = .true.
544 
545  ! Change dichotomy status
546  if (.not.dichotomy) then
547  dichotomy = .true.
548  drhflt = 0.5*drhflt
549  end if
550 
551  ! Decrease filtering support radius
552  drhflt = 0.5*drhflt
553  if (iter<nam%displ_niter) displ%rhflt(iter+1,il0,its) = displ%rhflt(iter,il0,its)-drhflt
554  end if
555  end do
556 
557  ! Copy
558  displ%lon_c2a_flt(:,il0,its) = lon_c2a
559  displ%lat_c2a_flt(:,il0,its) = lat_c2a
560  displ%dist_c2a_flt(:,il0,its) = dist_c2a
561 
562  ! Check convergence
563  if (.not.convergence) call mpl%abort('iterative filtering failed')
564  else
565  ! Print results
566  write(mpl%info,'(a10,a22,f10.2,a,f6.2,a,f7.2,a)') '','Raw displacement: rhflt = ', &
567  & displ%rhflt(0,il0,its)*reqkm,' km, valid points: ',100.0*displ%valid(0,il0,its),'%, average displacement = ', &
568  & displ%dist(0,il0,its)*reqkm,' km'
569  call flush(mpl%info)
570  end if
571 
572  ! Displacement interpolation
573  do ic2a=1,samp%nc2a
574  call lonlatmod(dlon_c2a(ic2a),dlat_c2a(ic2a))
575  end do
576  il0i = min(il0,geom%nl0i)
577  call samp%com_AB%ext(mpl,dlon_c2a,dlon_c2b)
578  call samp%com_AB%ext(mpl,dlat_c2a,dlat_c2b)
579  call samp%h(il0i)%apply(mpl,dlon_c2b,dlon_c0a)
580  call samp%h(il0i)%apply(mpl,dlat_c2b,dlat_c0a)
581 
582  ! Displaced grid
583  do ic0a=1,geom%nc0a
584  ic0 = geom%c0a_to_c0(ic0a)
585  samp%displ_lon(ic0a,il0,its) = geom%lon(ic0)+dlon_c0a(ic0a)
586  samp%displ_lat(ic0a,il0,its) = geom%lat(ic0)+dlat_c0a(ic0a)
587  call lonlatmod(samp%displ_lon(ic0a,il0,its),samp%displ_lat(ic0a,il0,its))
588  end do
589  end do
590 end do
591 
592 ! Displaced grid for timeslot 1
593 do il0=1,geom%nl0
594  do ic0a=1,geom%nc0a
595  ic0 = geom%c0a_to_c0(ic0a)
596  samp%displ_lon(ic0a,il0,1) = geom%lon(ic0)
597  samp%displ_lat(ic0a,il0,1) = geom%lat(ic0)
598  end do
599 end do
600 
601 end subroutine displ_compute
602 
603 !----------------------------------------------------------------------
604 ! Subroutine: displ_write
605 ! Purpose: write displacement data
606 !----------------------------------------------------------------------
607 subroutine displ_write(displ,mpl,nam,geom,samp,filename)
609 implicit none
610 
611 ! Passed variables
612 class(displ_type),intent(in) :: displ ! Displacement data
613 type(mpl_type),intent(inout) :: mpl ! MPI data
614 type(nam_type),intent(in) :: nam ! Namelist
615 type(geom_type),intent(in) :: geom ! Geometry
616 type(samp_type),intent(in) :: samp ! Sampling
617 character(len=*),intent(in) :: filename ! File name
618 
619 ! Local variables
620 integer :: ncid,nc2_id,nl0_id,nts_id,displ_niter_id,vunit_id,valid_id,dist_id,rhflt_id
621 integer :: lon_c2_id,lat_c2_id,lon_c2_raw_id,lat_c2_raw_id,dist_c2_raw_id,lon_c2_flt_id,lat_c2_flt_id,dist_c2_flt_id
622 integer :: iproc,its,il0,ic2a,ic2,i
623 integer,allocatable :: c2a_to_c2(:)
624 real(kind_real),allocatable :: sbuf(:),rbuf(:),lon_c2(:,:),lat_c2(:,:)
625 real(kind_real),allocatable :: lon_c2_raw(:,:,:),lat_c2_raw(:,:,:),dist_c2_raw(:,:,:)
626 real(kind_real),allocatable :: lon_c2_flt(:,:,:),lat_c2_flt(:,:,:),dist_c2_flt(:,:,:)
627 character(len=1024) :: subr = 'displ_write'
628 type(fckit_mpi_status) :: status
629 
630 ! Allocation
631 allocate(sbuf(samp%nc2a*geom%nl0*(2+(nam%nts-1)*6)))
632 
633 ! Prepare buffer
634 i = 1
635 do il0=1,geom%nl0
636  do ic2a=1,samp%nc2a
637  sbuf(i) = displ%lon_c2a(ic2a,il0)*rad2deg
638  i = i+1
639  sbuf(i) = displ%lat_c2a(ic2a,il0)*rad2deg
640  i = i+1
641  do its=2,nam%nts
642  sbuf(i) = displ%lon_c2a_raw(ic2a,il0,its)*rad2deg
643  i = i+1
644  sbuf(i) = displ%lat_c2a_raw(ic2a,il0,its)*rad2deg
645  i = i+1
646  sbuf(i) = displ%dist_c2a_raw(ic2a,il0,its)*reqkm
647  i = i+1
648  sbuf(i) = displ%lon_c2a_flt(ic2a,il0,its)*rad2deg
649  i = i+1
650  sbuf(i) = displ%lat_c2a_flt(ic2a,il0,its)*rad2deg
651  i = i+1
652  sbuf(i) = displ%dist_c2a_flt(ic2a,il0,its)*reqkm
653  i = i+1
654  end do
655  end do
656 end do
657 
658 if (mpl%main) then
659  ! Allocation
660  allocate(lon_c2(nam%nc2,geom%nl0))
661  allocate(lat_c2(nam%nc2,geom%nl0))
662  allocate(lon_c2_raw(nam%nc2,geom%nl0,nam%nts-1))
663  allocate(lat_c2_raw(nam%nc2,geom%nl0,nam%nts-1))
664  allocate(dist_c2_raw(nam%nc2,geom%nl0,nam%nts-1))
665  allocate(lon_c2_flt(nam%nc2,geom%nl0,nam%nts-1))
666  allocate(lat_c2_flt(nam%nc2,geom%nl0,nam%nts-1))
667  allocate(dist_c2_flt(nam%nc2,geom%nl0,nam%nts-1))
668 
669  do iproc=1,mpl%nproc
670  ! Allocation
671  allocate(c2a_to_c2(samp%proc_to_nc2a(iproc)))
672  allocate(rbuf(samp%proc_to_nc2a(iproc)*geom%nl0*(2+(nam%nts-1)*6)))
673 
674  if (iproc==mpl%ioproc) then
675  ! Copy buffer
676  c2a_to_c2 = samp%c2a_to_c2
677  rbuf = sbuf
678  else
679  ! Receive data on ioproc
680  call mpl%f_comm%receive(c2a_to_c2,iproc-1,mpl%tag,status)
681  call mpl%f_comm%receive(rbuf,iproc-1,mpl%tag+1,status)
682  end if
683 
684  ! Write data
685  i = 1
686  do il0=1,geom%nl0
687  do ic2a=1,samp%proc_to_nc2a(iproc)
688  ic2 = c2a_to_c2(ic2a)
689  lon_c2(ic2,il0) = rbuf(i)
690  i = i+1
691  lat_c2(ic2,il0) = rbuf(i)
692  i = i+1
693  do its=2,nam%nts
694  lon_c2_raw(ic2,il0,its-1) = rbuf(i)
695  i = i+1
696  lat_c2_raw(ic2,il0,its-1) = rbuf(i)
697  i = i+1
698  dist_c2_raw(ic2,il0,its-1) = rbuf(i)
699  i = i+1
700  lon_c2_flt(ic2,il0,its-1) = rbuf(i)
701  i = i+1
702  lat_c2_flt(ic2,il0,its-1) = rbuf(i)
703  i = i+1
704  dist_c2_flt(ic2,il0,its-1) = rbuf(i)
705  i = i+1
706  end do
707  end do
708  end do
709 
710  ! Release memory
711  deallocate(c2a_to_c2)
712  deallocate(rbuf)
713  end do
714 else
715  ! Send data to ioproc
716  call mpl%f_comm%send(samp%c2a_to_c2,mpl%ioproc-1,mpl%tag)
717  call mpl%f_comm%send(sbuf,mpl%ioproc-1,mpl%tag+1)
718 end if
719 call mpl%update_tag(2)
720 
721 ! Release memory
722 deallocate(sbuf)
723 
724 if (mpl%main) then
725  ! Create file
726  call mpl%ncerr(subr,nf90_create(trim(nam%datadir)//'/'//trim(filename),or(nf90_clobber,nf90_64bit_offset),ncid))
727 
728  ! Write namelist parameters
729  call nam%ncwrite(mpl,ncid)
730 
731  ! Define dimensions
732  call mpl%ncerr(subr,nf90_def_dim(ncid,'nc2',nam%nc2,nc2_id))
733  call mpl%ncerr(subr,nf90_def_dim(ncid,'nl0',geom%nl0,nl0_id))
734  call mpl%ncerr(subr,nf90_def_dim(ncid,'nts',nam%nts-1,nts_id))
735  call mpl%ncerr(subr,nf90_def_dim(ncid,'niter',nam%displ_niter+1,displ_niter_id))
736 
737  ! Define variables
738  call mpl%ncerr(subr,nf90_def_var(ncid,'vunit',ncfloat,(/nc2_id,nl0_id/),vunit_id))
739  call mpl%ncerr(subr,nf90_def_var(ncid,'valid',ncfloat,(/displ_niter_id,nl0_id,nts_id/),valid_id))
740  call mpl%ncerr(subr,nf90_put_att(ncid,valid_id,'_FillValue',msvalr))
741  call mpl%ncerr(subr,nf90_def_var(ncid,'dist',ncfloat,(/displ_niter_id,nl0_id,nts_id/),dist_id))
742  call mpl%ncerr(subr,nf90_put_att(ncid,dist_id,'_FillValue',msvalr))
743  call mpl%ncerr(subr,nf90_def_var(ncid,'rhflt',ncfloat,(/displ_niter_id,nl0_id,nts_id/),rhflt_id))
744  call mpl%ncerr(subr,nf90_put_att(ncid,rhflt_id,'_FillValue',msvalr))
745  call mpl%ncerr(subr,nf90_def_var(ncid,'lon_c2',ncfloat,(/nc2_id,nl0_id/),lon_c2_id))
746  call mpl%ncerr(subr,nf90_put_att(ncid,lon_c2_id,'_FillValue',msvalr))
747  call mpl%ncerr(subr,nf90_def_var(ncid,'lat_c2',ncfloat,(/nc2_id,nl0_id/),lat_c2_id))
748  call mpl%ncerr(subr,nf90_put_att(ncid,lat_c2_id,'_FillValue',msvalr))
749  call mpl%ncerr(subr,nf90_def_var(ncid,'lon_c2_raw',ncfloat,(/nc2_id,nl0_id,nts_id/),lon_c2_raw_id))
750  call mpl%ncerr(subr,nf90_put_att(ncid,lon_c2_raw_id,'_FillValue',msvalr))
751  call mpl%ncerr(subr,nf90_def_var(ncid,'lat_c2_raw',ncfloat,(/nc2_id,nl0_id,nts_id/),lat_c2_raw_id))
752  call mpl%ncerr(subr,nf90_put_att(ncid,lat_c2_raw_id,'_FillValue',msvalr))
753  call mpl%ncerr(subr,nf90_def_var(ncid,'dist_c2_raw',ncfloat,(/nc2_id,nl0_id,nts_id/),dist_c2_raw_id))
754  call mpl%ncerr(subr,nf90_put_att(ncid,dist_c2_raw_id,'_FillValue',msvalr))
755  call mpl%ncerr(subr,nf90_def_var(ncid,'lon_c2_flt',ncfloat,(/nc2_id,nl0_id,nts_id/),lon_c2_flt_id))
756  call mpl%ncerr(subr,nf90_put_att(ncid,lon_c2_flt_id,'_FillValue',msvalr))
757  call mpl%ncerr(subr,nf90_def_var(ncid,'lat_c2_flt',ncfloat,(/nc2_id,nl0_id,nts_id/),lat_c2_flt_id))
758  call mpl%ncerr(subr,nf90_put_att(ncid,lat_c2_flt_id,'_FillValue',msvalr))
759  call mpl%ncerr(subr,nf90_def_var(ncid,'dist_c2_flt',ncfloat,(/nc2_id,nl0_id,nts_id/),dist_c2_flt_id))
760  call mpl%ncerr(subr,nf90_put_att(ncid,dist_c2_flt_id,'_FillValue',msvalr))
761 
762  ! End definition mode
763  call mpl%ncerr(subr,nf90_enddef(ncid))
764 
765  ! Write data
766  call mpl%ncerr(subr,nf90_put_var(ncid,vunit_id,geom%vunit(samp%c2_to_c0,:)))
767  call mpl%ncerr(subr,nf90_put_var(ncid,valid_id,displ%valid))
768  call mpl%ncerr(subr,nf90_put_var(ncid,dist_id,displ%dist*reqkm))
769  call mpl%ncerr(subr,nf90_put_var(ncid,rhflt_id,displ%rhflt*reqkm))
770  call mpl%ncerr(subr,nf90_put_var(ncid,lon_c2_id,lon_c2))
771  call mpl%ncerr(subr,nf90_put_var(ncid,lat_c2_id,lat_c2))
772  call mpl%ncerr(subr,nf90_put_var(ncid,lon_c2_raw_id,lon_c2_raw))
773  call mpl%ncerr(subr,nf90_put_var(ncid,lat_c2_raw_id,lat_c2_raw))
774  call mpl%ncerr(subr,nf90_put_var(ncid,dist_c2_raw_id,dist_c2_raw))
775  call mpl%ncerr(subr,nf90_put_var(ncid,lon_c2_flt_id,lon_c2_flt))
776  call mpl%ncerr(subr,nf90_put_var(ncid,lat_c2_flt_id,lat_c2_flt))
777  call mpl%ncerr(subr,nf90_put_var(ncid,dist_c2_flt_id,dist_c2_flt))
778 
779  ! Close file
780  call mpl%ncerr(subr,nf90_close(ncid))
781 
782  ! Release memory
783  deallocate(lon_c2)
784  deallocate(lat_c2)
785  deallocate(lon_c2_raw)
786  deallocate(lat_c2_raw)
787  deallocate(dist_c2_raw)
788  deallocate(lon_c2_flt)
789  deallocate(lat_c2_flt)
790  deallocate(dist_c2_flt)
791 end if
792 
793 end subroutine displ_write
794 
795 end module type_displ
subroutine, public reduce_arc(lon_i, lat_i, lon_f, lat_f, maxdist, dist)
Definition: tools_func.F90:94
character(len=1024) displ_method
Definition: type_displ.F90:31
real(kind_real), parameter, public rad2deg
Definition: tools_const.F90:17
subroutine displ_alloc(displ, nam, geom, samp)
Definition: type_displ.F90:66
subroutine, public trans(n, rlat, rlon, x, y, z)
subroutine displ_dealloc(displ)
Definition: type_displ.F90:108
real(kind_real), parameter, public msvalr
Definition: tools_const.F90:24
subroutine, public lonlatmod(lon, lat)
Definition: tools_func.F90:37
subroutine, public vector_product(v1, v2, vp)
Definition: tools_func.F90:131
real(kind_real), parameter cor_th
Definition: type_displ.F90:32
subroutine displ_compute(displ, mpl, nam, geom, samp, ens)
Definition: type_displ.F90:134
subroutine, public sphere_dist(lon_i, lat_i, lon_f, lat_f, dist)
Definition: tools_func.F90:67
real(kind_real), parameter, public deg2rad
Definition: tools_const.F90:16
real(kind=kind_real), parameter req
Earth radius at equator (m)
subroutine displ_write(displ, mpl, nam, geom, samp, filename)
Definition: type_displ.F90:608
#define max(a, b)
Definition: mosaic_util.h:33
subroutine, public scoord(px, py, pz, plat, plon, pnrm)
integer, parameter, public kind_real
#define min(a, b)
Definition: mosaic_util.h:32
integer, parameter, public ncfloat
Definition: tools_nc.F90:27
real(kind_real), parameter, public reqkm
Definition: tools_const.F90:19