FV3 Bundle
type_lct.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: type_lct
3 ! Purpose: LCT 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_lct
9 
10 use fckit_mpi_module, only: fckit_mpi_sum,fckit_mpi_status
11 use tools_const, only: reqkm,pi
13 use tools_kinds, only: kind_real
15 use type_bpar, only: bpar_type
16 use type_ens, only: ens_type
17 use type_geom, only: geom_type
18 use type_io, only: io_type
19 use type_lct_blk, only: lct_blk_type
20 use type_mom, only: mom_type
21 use type_mpl, only: mpl_type
22 use type_nam, only: nam_type
23 use type_samp, only: samp_type
24 use type_rng, only: rng_type
25 
26 implicit none
27 
28 logical,parameter :: write_cor = .true. ! Write raw and fitted correlations
29 
30 ! LCT data derived type
32  type(samp_type) :: samp ! Sampling
33  type(mom_type) :: mom ! Moments
34  type(lct_blk_type),allocatable :: blk(:) ! LCT blocks
35  logical :: allocated ! Allocation flag
36 contains
37  procedure :: alloc => lct_alloc
38  procedure :: dealloc => lct_dealloc
39  procedure :: run_lct => lct_run_lct
40  procedure :: compute => lct_compute
41  procedure :: filter => lct_filter
42  procedure :: rmse => lct_rmse
43  procedure :: write => lct_write
44  procedure :: write_cor => lct_write_cor
45 end type lct_type
46 
47 private
48 public :: lct_type
49 
50 contains
51 
52 !----------------------------------------------------------------------
53 ! Subroutine: lct_alloc
54 ! Purpose: LCT data allocation
55 !----------------------------------------------------------------------
56 subroutine lct_alloc(lct,nam,geom,bpar)
57 
58 implicit none
59 
60 ! Passed variables
61 class(lct_type),intent(inout) :: lct ! LCT
62 type(nam_type),intent(in) :: nam ! Namelist
63 type(geom_type),intent(in) :: geom ! Geometry
64 type(bpar_type),intent(in) :: bpar ! Block parameters
65 
66 ! Local variables
67 integer :: ib
68 
69 ! Allocation
70 allocate(lct%blk(bpar%nb))
71 do ib=1,bpar%nb
72  call lct%blk(ib)%alloc(nam,geom,bpar,lct%samp,ib)
73 end do
74 
75 ! Update allocation flag
76 lct%allocated = .true.
77 
78 end subroutine lct_alloc
79 
80 !----------------------------------------------------------------------
81 ! Subroutine: lct_dealloc
82 ! Purpose: LCT data deallocation
83 !----------------------------------------------------------------------
84 subroutine lct_dealloc(lct,bpar)
85 
86 implicit none
87 
88 ! Passed variables
89 class(lct_type),intent(inout) :: lct ! LCT
90 type(bpar_type),intent(in) :: bpar ! Block parameters
91 
92 ! Local variables
93 integer :: ib
94 
95 ! Release memory
96 if (allocated(lct%blk)) then
97  do ib=1,bpar%nb
98  call lct%blk(ib)%dealloc
99  end do
100  deallocate(lct%blk)
101 end if
102 
103 ! Update allocation flag
104 lct%allocated = .false.
105 
106 end subroutine lct_dealloc
107 
108 !----------------------------------------------------------------------
109 ! Subroutine: lct_run_lct
110 ! Purpose: LCT driver
111 !----------------------------------------------------------------------
112 subroutine lct_run_lct(lct,mpl,rng,nam,geom,bpar,io,ens)
114 implicit none
115 
116 ! Passed variables
117 class(lct_type),intent(inout) :: lct ! LCT
118 type(mpl_type),intent(inout) :: mpl ! MPI data
119 type(rng_type),intent(inout) :: rng ! Random number generator
120 type(nam_type),intent(inout) :: nam ! Namelist
121 type(geom_type),intent(in) :: geom ! Geometry
122 type(bpar_type),intent(in) :: bpar ! Block parameters
123 type(io_type),intent(in) :: io ! I/O
124 type(ens_type),intent(in) :: ens ! Ensemble
125 
126 ! Setup sampling
127 write(mpl%info,'(a)') '-------------------------------------------------------------------'
128 write(mpl%info,'(a,i5,a)') '--- Setup sampling (nc1 = ',nam%nc1,')'
129 call flush(mpl%info)
130 
131 ! Set artificially small local radius
132 nam%local_rad = 1.0e-12
133 
134 ! Setup sampling
135 call lct%samp%setup_sampling(mpl,rng,nam,geom,bpar,io,ens)
136 
137 ! Compute MPI distribution, halo A
138 write(mpl%info,'(a)') '-------------------------------------------------------------------'
139 write(mpl%info,'(a)') '--- Compute MPI distribution, halos A'
140 call flush(mpl%info)
141 call lct%samp%compute_mpi_a(mpl,nam,geom)
142 
143 ! Compute MPI distribution, halos A-B
144 write(mpl%info,'(a)') '-------------------------------------------------------------------'
145 write(mpl%info,'(a)') '--- Compute MPI distribution, halos A-B'
146 call flush(mpl%info)
147 call lct%samp%compute_mpi_ab(mpl,nam,geom)
148 
149 ! Compute MPI distribution, halo C
150 write(mpl%info,'(a)') '-------------------------------------------------------------------'
151 write(mpl%info,'(a)') '--- Compute MPI distribution, halo C'
152 call flush(mpl%info)
153 call lct%samp%compute_mpi_c(mpl,nam,geom)
154 
155 if (nam%diag_rhflt>0.0) then
156  ! Compute MPI distribution, halo F
157  write(mpl%info,'(a)') '-------------------------------------------------------------------'
158  write(mpl%info,'(a)') '--- Compute MPI distribution, halo F'
159  call flush(mpl%info)
160  call lct%samp%compute_mpi_f(mpl,nam,geom)
161 end if
162 
163 ! Compute sample moments
164 write(mpl%info,'(a)') '-------------------------------------------------------------------'
165 write(mpl%info,'(a)') '--- Compute sample moments'
166 call flush(mpl%info)
167 call lct%mom%compute(mpl,nam,geom,bpar,lct%samp,ens)
168 
169 ! Compute LCT
170 write(mpl%info,'(a)') '-------------------------------------------------------------------'
171 write(mpl%info,'(a)') '--- Compute LCT'
172 call flush(mpl%info)
173 call lct%compute(mpl,nam,geom,bpar)
174 
175 ! Filter LCT
176 write(mpl%info,'(a)') '-------------------------------------------------------------------'
177 write(mpl%info,'(a)') '--- Filter LCT'
178 call flush(mpl%info)
179 call lct%filter(mpl,nam,geom,bpar)
180 
181 ! LCT RMSE
182 write(mpl%info,'(a)') '-------------------------------------------------------------------'
183 write(mpl%info,'(a)') '--- LCT RMSE'
184 call flush(mpl%info)
185 call lct%rmse(mpl,nam,geom,bpar)
186 
187 ! Write LCT
188 write(mpl%info,'(a)') '-------------------------------------------------------------------'
189 write(mpl%info,'(a)') '--- Write LCT'
190 call flush(mpl%info)
191 call lct%write(mpl,nam,geom,bpar,io)
192 
193 if (write_cor) then
194  ! Write correlation and LCT fit
195  write(mpl%info,'(a)') '-------------------------------------------------------------------'
196  write(mpl%info,'(a)') '--- Write correlation and LCT fit'
197  call flush(mpl%info)
198  call lct%write_cor(mpl,nam,geom,bpar,io)
199 end if
200 
201 end subroutine lct_run_lct
202 
203 !----------------------------------------------------------------------
204 ! Subroutine: lct_compute
205 ! Purpose: compute LCT
206 !----------------------------------------------------------------------
207 subroutine lct_compute(lct,mpl,nam,geom,bpar)
209 implicit none
210 
211 ! Passed variables
212 class(lct_type),intent(inout) :: lct ! LCT
213 type(mpl_type),intent(inout) :: mpl ! MPI data
214 type(nam_type),intent(in) :: nam ! Namelist
215 type(geom_type),intent(in) :: geom ! Geometry
216 type(bpar_type),intent(in) :: bpar ! Block parameters
217 
218 ! Local variables
219 integer :: ib
220 
221 ! Allocation
222 call lct%alloc(nam,geom,bpar)
223 
224 do ib=1,bpar%nb
225  write(mpl%info,'(a7,a,a)') '','Block: ',trim(bpar%blockname(ib))
226  call flush(mpl%info)
227 
228  ! Compute correlation
229  write(mpl%info,'(a10,a)') '','Compute correlation'
230  call flush(mpl%info)
231  call lct%blk(ib)%correlation(nam,geom,bpar,lct%samp,lct%mom%blk(ib))
232 
233  ! Compute LCT fit
234  write(mpl%info,'(a10,a)') '','Compute LCT fit'
235  call flush(mpl%info)
236  call lct%blk(ib)%fitting(mpl,nam,geom,bpar,lct%samp)
237 end do
238 
239 end subroutine lct_compute
240 
241 !----------------------------------------------------------------------
242 ! Subroutine: lct_filter
243 ! Purpose: filter LCT
244 !----------------------------------------------------------------------
245 subroutine lct_filter(lct,mpl,nam,geom,bpar)
247 implicit none
248 
249 ! Passed variables
250 class(lct_type),intent(inout) :: lct ! LCT
251 type(mpl_type),intent(inout) :: mpl ! MPI data
252 type(nam_type),intent(in) :: nam ! Namelist
253 type(geom_type),intent(in) :: geom ! Geometry
254 type(bpar_type),intent(in) :: bpar ! Block parameters
255 
256 ! Local variables
257 integer :: ib,il0,jl0,jl0r,ic1a,ic1,ic0,jc3,jc0,icomp,iscales,nmsr,nmsr_tot
258 real(kind_real),allocatable :: fld_c1a(:),fld_filt_c1a(:),dx(:,:),dy(:,:),dz(:,:)
259 logical :: valid
260 logical,allocatable :: mask_c1a(:,:),dmask(:,:)
261 
262 ! Allocation
263 allocate(fld_c1a(lct%samp%nc1a))
264 allocate(mask_c1a(lct%samp%nc1a,geom%nl0))
265 if (nam%diag_rhflt>0) allocate(fld_filt_c1a(lct%samp%nc1a))
266 
267 ! Define mask
268 do il0=1,geom%nl0
269  do ic1a=1,lct%samp%nc1a
270  ic1 = lct%samp%c1a_to_c1(ic1a)
271  mask_c1a(ic1a,il0) = lct%samp%c1l0_log(ic1,il0)
272  end do
273 end do
274 
275 do ib=1,bpar%nb
276  write(mpl%info,'(a7,a,a)') '','Block: ',trim(bpar%blockname(ib))
277  call flush(mpl%info)
278 
279  ! Allocation
280  if (nam%diag_rhflt>0) then
281  allocate(dx(nam%nc3,bpar%nl0r(ib)))
282  allocate(dy(nam%nc3,bpar%nl0r(ib)))
283  allocate(dz(nam%nc3,bpar%nl0r(ib)))
284  allocate(dmask(nam%nc3,bpar%nl0r(ib)))
285  end if
286 
287  do il0=1,geom%nl0
288  ! Count missing LCT
289  nmsr = 0
290  do ic1a=1,lct%samp%nc1a
291  if (mask_c1a(ic1a,il0).and.(.not.(all(isnotmsr(lct%blk(ib)%coef(:,ic1a,il0))) &
292  & .and.all(isnotmsr(lct%blk(ib)%coef(:,ic1a,il0)))))) nmsr = nmsr+1
293  end do
294  call mpl%f_comm%allreduce(nmsr,nmsr_tot,fckit_mpi_sum())
295  write(mpl%info,'(a10,a,i3,a,i8,a)',advance='no') '','Level',nam%levs(il0),': ',nmsr_tot,' missing points'
296 
297  do iscales=1,lct%blk(ib)%nscales
298  do icomp=1,4+1
299  ! Copy
300  if (icomp<=4) then
301  fld_c1a = lct%blk(ib)%D(icomp,iscales,:,il0)
302  else
303  fld_c1a = lct%blk(ib)%coef(iscales,:,il0)
304  end if
305 
306  if (nam%diag_rhflt>0) then
307  ! Copy
308  fld_filt_c1a = fld_c1a
309 
310  ! Filter
311  call lct%samp%diag_filter(mpl,nam,geom,il0,'median',nam%diag_rhflt,fld_filt_c1a)
312  call lct%samp%diag_filter(mpl,nam,geom,il0,'gc99',nam%diag_rhflt,fld_filt_c1a)
313  end if
314 
315  ! Fill missing values
316  if (nmsr_tot>0) then
317  call lct%samp%diag_fill(mpl,nam,geom,il0,fld_c1a)
318  if (nam%diag_rhflt>0) call lct%samp%diag_fill(mpl,nam,geom,il0,fld_filt_c1a)
319  end if
320 
321 
322  ! Copy
323  if (icomp<=4) then
324  lct%blk(ib)%D(icomp,iscales,:,il0) = fld_c1a
325  if (nam%diag_rhflt>0) lct%blk(ib)%D_filt(icomp,iscales,:,il0) = fld_filt_c1a
326  else
327  lct%blk(ib)%coef(iscales,:,il0) = fld_c1a
328  if (nam%diag_rhflt>0) lct%blk(ib)%coef_filt(iscales,:,il0) = fld_filt_c1a
329  end if
330  end do
331  end do
332 
333  ! Count missing LCT
334  nmsr = 0
335  do ic1a=1,lct%samp%nc1a
336  if (mask_c1a(ic1a,il0).and.(.not.(all(isnotmsr(lct%blk(ib)%coef(:,ic1a,il0))) &
337  & .and.all(isnotmsr(lct%blk(ib)%coef(:,ic1a,il0)))))) nmsr = nmsr+1
338  end do
339  call mpl%f_comm%allreduce(nmsr,nmsr_tot,fckit_mpi_sum())
340  write(mpl%info,'(a,i8,a)',advance='no') ' ~> ',nmsr_tot,' missing points'
341  if (nam%diag_rhflt>0) then
342  write(mpl%info,'(a,f10.2,a)') ', filtering at ',nam%diag_rhflt*reqkm,' km'
343  else
344  write(mpl%info,'(a,f10.2,a)') ', no filtering'
345  end if
346 
347  if (nam%diag_rhflt>0) then
348  do ic1a=1,lct%samp%nc1a
349  ! Global index
350  ic1 = lct%samp%c1a_to_c1(ic1a)
351 
352  if (lct%samp%c1l0_log(ic1,il0)) then
353  ! Compute deltas
354  ic0 = lct%samp%c1_to_c0(ic1)
355  do jl0r=1,bpar%nl0r(ib)
356  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
357  do jc3=1,nam%nc3
358  dmask(jc3,jl0r) = lct%samp%c1l0_log(ic1,il0).and.lct%samp%c1c3l0_log(ic1,jc3,jl0)
359  if (dmask(jc3,jl0r)) then
360  jc0 = lct%samp%c1c3_to_c0(ic1,jc3)
361  call geom%compute_deltas(ic0,il0,jc0,jl0,dx(jc3,jl0r),dy(jc3,jl0r),dz(jc3,jl0r))
362  end if
363  end do
364  end do
365 
366  ! Check tensor validity
367  valid = .true.
368  do iscales=1,lct%blk(ib)%nscales
369  if (valid) then
370  call check_cond(lct%blk(ib)%D_filt(1,iscales,ic1a,il0),lct%blk(ib)%D_filt(2,iscales,ic1a,il0), &
371  & lct%blk(ib)%D_filt(4,iscales,ic1a,il0),valid)
372  if (bpar%nl0r(ib)>1) valid = valid.and.(lct%blk(ib)%D_filt(3,iscales,ic1a,il0)>0.0)
373  valid = valid.and.(lct%blk(ib)%coef_filt(iscales,ic1a,il0)>0.0)
374  if (lct%blk(ib)%nscales>1) valid = valid.and.(lct%blk(ib)%coef_filt(iscales,ic1a,il0)<1.0)
375  end if
376  end do
377  if (valid) then
378  ! Rebuild fit
379  call fit_lct(mpl,nam%nc3,bpar%nl0r(ib),dx,dy,dz,dmask,lct%blk(ib)%nscales, &
380  & lct%blk(ib)%D_filt(:,:,ic1a,il0),lct%blk(ib)%coef_filt(:,ic1a,il0),lct%blk(ib)%fit_filt(:,:,ic1a,il0))
381  else
382  ! Missing values
383  call msr(lct%blk(ib)%fit_filt(:,:,ic1a,il0))
384  end if
385  end if
386  end do
387  end if
388  end do
389 
390  ! Release memory
391  if (nam%diag_rhflt>0) then
392  deallocate(dx)
393  deallocate(dy)
394  deallocate(dz)
395  deallocate(dmask)
396  end if
397 end do
398 
399 end subroutine lct_filter
400 
401 !----------------------------------------------------------------------
402 ! Subroutine: lct_rmse
403 ! Purpose: compute LCT fit RMSE
404 !----------------------------------------------------------------------
405 subroutine lct_rmse(lct,mpl,nam,geom,bpar)
407 implicit none
408 
409 ! Passed variables
410 class(lct_type),intent(in) :: lct ! LCT
411 type(mpl_type),intent(in) :: mpl ! MPI data
412 type(nam_type),intent(in) :: nam ! Namelist
413 type(geom_type),intent(in) :: geom ! Geometry
414 type(bpar_type),intent(in) :: bpar ! Block parameters
415 
416 ! Local variables
417 integer :: ib,il0,jl0r,jl0,ic1a,ic1,jc3
418 real(kind_real) :: rmse,norm,rmse_tot,norm_tot
419 real(kind_real) :: rmse_filt,norm_filt,rmse_filt_tot,norm_filt_tot
420 
421 do ib=1,bpar%nb
422  write(mpl%info,'(a7,a,a)') '','Block: ',trim(bpar%blockname(ib))
423  call flush(mpl%info)
424 
425  ! Compute RMSE
426  rmse = 0.0
427  norm = 0.0
428  if (nam%diag_rhflt>0) then
429  rmse_filt = 0.0
430  norm_filt = 0.0
431  end if
432  do il0=1,geom%nl0
433  do ic1a=1,lct%samp%nc1a
434  ic1 = lct%samp%c1a_to_c1(ic1a)
435  do jl0r=1,bpar%nl0r(ib)
436  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
437  do jc3=1,nam%nc3
438  if (lct%samp%c1l0_log(ic1,il0).and.lct%samp%c1c3l0_log(ic1,jc3,jl0)) then
439  if (isnotmsr(lct%blk(ib)%fit(jc3,jl0r,ic1a,il0))) then
440  rmse = rmse+(lct%blk(ib)%fit(jc3,jl0r,ic1a,il0)-lct%blk(ib)%raw(jc3,jl0r,ic1a,il0))**2
441  norm = norm+1.0
442  end if
443  if (nam%diag_rhflt>0) then
444  if (isnotmsr(lct%blk(ib)%fit_filt(jc3,jl0r,ic1a,il0))) then
445  rmse_filt = rmse_filt+(lct%blk(ib)%fit_filt(jc3,jl0r,ic1a,il0)-lct%blk(ib)%raw(jc3,jl0r,ic1a,il0))**2
446  norm_filt = norm_filt+1.0
447  end if
448  end if
449  end if
450  end do
451  end do
452  end do
453  end do
454  call mpl%f_comm%allreduce(rmse,rmse_tot,fckit_mpi_sum())
455  call mpl%f_comm%allreduce(norm,norm_tot,fckit_mpi_sum())
456  if (norm_tot>0.0) rmse_tot = sqrt(rmse_tot/norm_tot)
457  write(mpl%info,'(a10,a,e15.8,a,i8,a)') '','LCT fit RMSE: ',rmse_tot,' for ',int(norm_tot),' diagnostic points'
458  call flush(mpl%info)
459  if (nam%diag_rhflt>0) then
460  call mpl%f_comm%allreduce(rmse_filt,rmse_filt_tot,fckit_mpi_sum())
461  call mpl%f_comm%allreduce(norm_filt,norm_filt_tot,fckit_mpi_sum())
462  if (norm_filt_tot>0.0) rmse_filt_tot = sqrt(rmse_filt_tot/norm_filt_tot)
463  write(mpl%info,'(a10,a,e15.8,a,i8,a)') '','LCT filtered fit RMSE: ',rmse_filt_tot,' for ',int(norm_tot),' diagnostic points'
464  call flush(mpl%info)
465  end if
466 end do
467 
468 end subroutine lct_rmse
469 
470 !----------------------------------------------------------------------
471 ! Subroutine: lct_write
472 ! Purpose: interpolate and write LCT
473 !----------------------------------------------------------------------
474 subroutine lct_write(lct,mpl,nam,geom,bpar,io)
476 implicit none
477 
478 ! Passed variables
479 class(lct_type),intent(inout) :: lct ! LCT
480 type(mpl_type),intent(inout) :: mpl ! MPI data
481 type(nam_type),intent(in) :: nam ! Namelist
482 type(geom_type),intent(in) :: geom ! Geometry
483 type(bpar_type),intent(in) :: bpar ! Block parameters
484 type(io_type),intent(in) :: io ! I/O
485 
486 ! Local variables
487 integer :: ib,iv,il0,il0i,ic1a,ic1,icomp,ic0a,iscales
488 real(kind_real) :: det,Lavg_tot,norm_tot
489 real(kind_real),allocatable :: D(:,:,:,:),coef(:,:,:),fld_c1a(:,:,:),fld_c1b(:,:),fld(:,:,:)
490 logical :: mask_c1a(lct%samp%nc1a,geom%nl0)
491 character(len=1) :: iscaleschar
492 character(len=1024) :: filename
493 
494 ! Define mask
495 do il0=1,geom%nl0
496  do ic1a=1,lct%samp%nc1a
497  ic1 = lct%samp%c1a_to_c1(ic1a)
498  mask_c1a(ic1a,il0) = lct%samp%c1l0_log(ic1,il0)
499  end do
500 end do
501 
502 do ib=1,bpar%nb
503  write(mpl%info,'(a7,a,a)') '','Block: ',trim(bpar%blockname(ib))
504  call flush(mpl%info)
505 
506  ! Allocation
507  allocate(d(4,lct%blk(ib)%nscales,lct%samp%nc1a,geom%nl0))
508  allocate(coef(lct%blk(ib)%nscales,lct%samp%nc1a,geom%nl0))
509 
510  ! Initialization
511  if (nam%diag_rhflt>0) then
512  d = lct%blk(ib)%D_filt
513  coef = lct%blk(ib)%coef_filt
514  else
515  d = lct%blk(ib)%D
516  coef = lct%blk(ib)%coef
517  end if
518 
519  do iscales=1,lct%blk(ib)%nscales
520  write(mpl%info,'(a10,a,i2)') '','Scale: ',iscales
521 
522  ! Allocation
523  allocate(fld_c1a(lct%samp%nc1a,geom%nl0,2*4+1))
524  allocate(fld_c1b(lct%samp%nc2b,geom%nl0))
525  allocate(fld(geom%nc0a,geom%nl0,2*4+2))
526 
527  ! Initialization
528  call msr(fld_c1a)
529  call msr(fld)
530 
531  ! Copy and inverse diffusion tensor
532  write(mpl%info,'(a13,a)') '','Copy and inverse diffusion tensor'
533  call flush(mpl%info)
534  do il0=1,geom%nl0
535  do ic1a=1,lct%samp%nc1a
536  ic1 = lct%samp%c1a_to_c1(ic1a)
537  if (mask_c1a(ic1a,il0)) then
538  ! Ensure positive-definiteness of D
539  d(1,iscales,ic1a,il0) = max(dmin,d(1,iscales,ic1a,il0))
540  d(2,iscales,ic1a,il0) = max(dmin,d(2,iscales,ic1a,il0))
541  if (bpar%nl0r(ib)>1) d(3,iscales,ic1a,il0) = max(dmin,d(3,iscales,ic1a,il0))
542  d(4,iscales,ic1a,il0) = max(-1.0_kind_real+dmin,min(d(4,iscales,ic1a,il0),1.0_kind_real-dmin))
543 
544  ! Copy diffusion tensor
545  fld_c1a(ic1a,il0,1) = d(1,iscales,ic1a,il0)
546  fld_c1a(ic1a,il0,2) = d(2,iscales,ic1a,il0)
547  fld_c1a(ic1a,il0,3) = d(3,iscales,ic1a,il0)
548  fld_c1a(ic1a,il0,4) = sqrt(d(1,iscales,ic1a,il0)*d(2,iscales,ic1a,il0))*d(4,iscales,ic1a,il0)
549 
550  ! Inverse diffusion tensor
551  call lct_d2h(mpl,fld_c1a(ic1a,il0,1),fld_c1a(ic1a,il0,2),fld_c1a(ic1a,il0,3),fld_c1a(ic1a,il0,4), &
552  & fld_c1a(ic1a,il0,4+1),fld_c1a(ic1a,il0,4+2),fld_c1a(ic1a,il0,4+3),fld_c1a(ic1a,il0,4+4))
553 
554  ! Copy coefficient
555  fld_c1a(ic1a,il0,2*4+1) = coef(iscales,ic1a,il0)
556  end if
557  end do
558  end do
559 
560  ! Interpolate components
561  write(mpl%info,'(a13,a)') '','Interpolate components'
562  call flush(mpl%info)
563  do icomp=1,2*4+1
564  call lct%samp%com_AB%ext(mpl,geom%nl0,fld_c1a(:,:,icomp),fld_c1b)
565  do il0=1,geom%nl0
566  il0i = min(il0,geom%nl0i)
567  call lct%samp%h(il0i)%apply(mpl,fld_c1b(:,il0),fld(:,il0,icomp))
568  end do
569  end do
570 
571  ! Compute horizontal length-scale and equivalent support radius
572  write(mpl%info,'(a13,a)') '','Compute horizontal length-scale and equivalent support radius:'
573  call flush(mpl%info)
574  do il0=1,geom%nl0
575  do ic0a=1,geom%nc0a
576  if (geom%mask_c0a(ic0a,il0)) then
577  ! Length-scale = D determinant^{1/4}
578  det = fld(ic0a,il0,1)*fld(ic0a,il0,2)-fld(ic0a,il0,4)**2
579  if (det>0.0) then
580  fld(ic0a,il0,2*4+2) = sqrt(sqrt(det))
581  else
582  call mpl%abort('non-valid horizontal diffusion tensor determinant, grid c0')
583  end if
584  end if
585  end do
586  call mpl%f_comm%allreduce(sum(fld(:,il0,2*4+2),isnotmsr(fld(:,il0,2*3+2))),lavg_tot,fckit_mpi_sum())
587  call mpl%f_comm%allreduce(real(count(isnotmsr(fld(:,il0,2*4+2))),kind_real),norm_tot,fckit_mpi_sum())
588  if (norm_tot>0.0) write(mpl%info,'(a16,a,i3,a,f10.2,a,f10.2,a)') '','Level',nam%levs(il0),' ~> ', &
589  & lavg_tot/norm_tot*reqkm,' km / ',lavg_tot/norm_tot*gau2gc*reqkm,' km'
590  end do
591 
592  ! Copy output values
593  do il0=1,geom%nl0
594  do ic0a=1,geom%nc0a
595  if (geom%mask_c0a(ic0a,il0)) then
596  lct%blk(ib)%D11(ic0a,il0,iscales) = fld(ic0a,il0,1)
597  lct%blk(ib)%D22(ic0a,il0,iscales) = fld(ic0a,il0,2)
598  lct%blk(ib)%D33(ic0a,il0,iscales) = fld(ic0a,il0,3)
599  lct%blk(ib)%D12(ic0a,il0,iscales) = fld(ic0a,il0,4)
600  lct%blk(ib)%H11(ic0a,il0,iscales) = fld(ic0a,il0,4+1)
601  lct%blk(ib)%H22(ic0a,il0,iscales) = fld(ic0a,il0,4+2)
602  lct%blk(ib)%H33(ic0a,il0,iscales) = fld(ic0a,il0,4+3)
603  lct%blk(ib)%H12(ic0a,il0,iscales) = fld(ic0a,il0,4+4)
604  lct%blk(ib)%Dcoef(ic0a,il0,iscales) = fld(ic0a,il0,2*4+1)
605  lct%blk(ib)%DLh(ic0a,il0,iscales) = fld(ic0a,il0,2*4+2)
606  end if
607  end do
608  end do
609 
610  ! Write LCT
611  write(mpl%info,'(a13,a)') '','Write LCT'
612  call flush(mpl%info)
613  filename = trim(nam%prefix)//'_lct'
614  iv = bpar%b_to_v2(ib)
615  write(iscaleschar,'(i1)') iscales
616  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_D11_'//iscaleschar,lct%blk(ib)%D11(:,:,iscales))
617  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_D22_'//iscaleschar,lct%blk(ib)%D22(:,:,iscales))
618  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_D33_'//iscaleschar,lct%blk(ib)%D33(:,:,iscales))
619  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_D12_'//iscaleschar,lct%blk(ib)%D12(:,:,iscales))
620  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_H11_'//iscaleschar,lct%blk(ib)%H11(:,:,iscales))
621  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_H22_'//iscaleschar,lct%blk(ib)%H22(:,:,iscales))
622  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_H33_'//iscaleschar,lct%blk(ib)%H33(:,:,iscales))
623  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_H12_'//iscaleschar,lct%blk(ib)%H12(:,:,iscales))
624  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_coef_'//iscaleschar,lct%blk(ib)%Dcoef(:,:,iscales))
625  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_Lh_'//iscaleschar,lct%blk(ib)%DLh(:,:,iscales))
626 
627  ! Release memory
628  deallocate(fld_c1a)
629  deallocate(fld_c1b)
630  deallocate(fld)
631  end do
632 
633  ! Release memory
634  deallocate(d)
635  deallocate(coef)
636 end do
637 
638 end subroutine lct_write
639 
640 !----------------------------------------------------------------------
641 ! Subroutine: lct_write_cor
642 ! Purpose: write correlation and LCT fit
643 !----------------------------------------------------------------------
644 subroutine lct_write_cor(lct,mpl,nam,geom,bpar,io)
646 implicit none
647 
648 ! Passed variables
649 class(lct_type),intent(in) :: lct ! LCT
650 type(mpl_type),intent(inout) :: mpl ! MPI data
651 type(nam_type),intent(in) :: nam ! Namelist
652 type(geom_type),intent(in) :: geom ! Geometry
653 type(bpar_type),intent(in) :: bpar ! Block parameters
654 type(io_type),intent(in) :: io ! I/O
655 
656 ! Local variables
657 integer :: ib,iv,il0,jl0r,jl0,ic1a,ic1,jc3,i,iproc,ic0,nf
658 real(kind_real),allocatable :: fld_c0a(:,:,:),fld_c0(:,:,:),sbuf(:),rbuf(:)
659 logical :: valid
660 logical :: free(geom%nc0,geom%nl0)
661 character(len=1024) :: filename
662 type(fckit_mpi_status) :: status
663 
664 ! Number of fields
665 if (nam%diag_rhflt>0) then
666  nf = 3
667 else
668  nf = 2
669 end if
670 
671 ! Allocation
672 allocate(fld_c0a(geom%nc0a,geom%nl0,nf))
673 
674 do ib=1,bpar%nb
675  write(mpl%info,'(a7,a,a)') '','Block: ',trim(bpar%blockname(ib))
676  call flush(mpl%info)
677 
678  ! Allocation
679  if (mpl%main) allocate(rbuf(nam%nc3*bpar%nl0r(ib)*nf))
680  allocate(fld_c0(geom%nc0,geom%nl0,nf))
681 
682  ! Select level
683  il0 = 1
684 
685  ! Prepare field
686  if (mpl%main) call msr(fld_c0)
687  free = .true.
688  do ic1=1,nam%nc1
689  ! Select tensor to plot
690  valid = .true.
691  do jl0r=1,bpar%nl0r(ib)
692  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
693  do jc3=1,nam%nc3
694  if (valid.and.lct%samp%c1l0_log(ic1,il0).and.lct%samp%c1c3l0_log(ic1,jc3,jl0)) &
695  & valid = valid.and.free(lct%samp%c1c3_to_c0(ic1,jc3),jl0)
696  end do
697  end do
698 
699  if (valid) then
700  ! Remember that the footprint is not free anymore
701  do jl0r=1,bpar%nl0r(ib)
702  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
703  do jc3=1,nam%nc3
704  free(lct%samp%c1c3_to_c0(ic1,jc3),jl0) = .false.
705  end do
706  end do
707 
708  ! Find processor
709  iproc = lct%samp%c2_to_proc(ic1)
710  if (iproc==mpl%myproc) then
711  ! Allocate buffer
712  allocate(sbuf(nam%nc3*bpar%nl0r(ib)*nf))
713 
714  ! Prepare buffer
715  call msr(sbuf)
716  ic1a = lct%samp%c1_to_c1a(ic1)
717  i = 1
718  do jl0r=1,bpar%nl0r(ib)
719  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
720  do jc3=1,nam%nc3
721  if (lct%samp%c1l0_log(ic1,il0).and.lct%samp%c1c3l0_log(ic1,jc3,jl0)) then
722  sbuf(i) = lct%blk(ib)%raw(jc3,jl0r,ic1a,il0)
723  sbuf(i+1) = lct%blk(ib)%fit(jc3,jl0r,ic1a,il0)
724  if (nf==3) sbuf(i+2) = lct%blk(ib)%fit_filt(jc3,jl0r,ic1a,il0)
725  end if
726  i = i+nf
727  end do
728  end do
729  end if
730 
731  if (mpl%main) then
732  if (iproc==mpl%ioproc) then
733  ! Copy
734  rbuf = sbuf
735  else
736  ! Receive data
737  call mpl%f_comm%receive(rbuf,iproc-1,mpl%tag,status)
738  end if
739 
740  ! Fill field
741  i = 1
742  do jl0r=1,bpar%nl0r(ib)
743  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
744  do jc3=1,nam%nc3
745  if (lct%samp%c1l0_log(ic1,il0).and.lct%samp%c1c3l0_log(ic1,jc3,jl0)) then
746  ic0 = lct%samp%c1c3_to_c0(ic1,jc3)
747  fld_c0(ic0,jl0,1) = rbuf(i)
748  fld_c0(ic0,jl0,2) = rbuf(i+1)
749  if (nf==3) fld_c0(ic0,jl0,3) = rbuf(i+2)
750  end if
751  i = i+nf
752  end do
753  end do
754  else
755  ! Send data
756  if (iproc==mpl%myproc) call mpl%f_comm%send(sbuf,mpl%ioproc-1,mpl%tag)
757  end if
758  call mpl%update_tag(1)
759 
760  ! Release memory
761  if (iproc==mpl%myproc) deallocate(sbuf)
762  end if
763  end do
764 
765  ! Global to local
766  call mpl%glb_to_loc(geom%nl0,geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,fld_c0(:,:,1),geom%nc0a,fld_c0a(:,:,1))
767  call mpl%glb_to_loc(geom%nl0,geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,fld_c0(:,:,2),geom%nc0a,fld_c0a(:,:,2))
768  if (nf==3) call mpl%glb_to_loc(geom%nl0,geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,fld_c0(:,:,3),geom%nc0a,fld_c0a(:,:,3))
769 
770  ! Write LCT diagnostics
771  write(mpl%info,'(a10,a)') '','Write LCT diagnostics'
772  call flush(mpl%info)
773  filename = trim(nam%prefix)//'_lct'
774  iv = bpar%b_to_v2(ib)
775  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_raw',fld_c0a(:,:,1))
776  call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_fit',fld_c0a(:,:,2))
777  if (nf==3) call io%fld_write(mpl,nam,geom,filename,trim(nam%varname(iv))//'_fit_filt',fld_c0a(:,:,3))
778 
779  ! Release memory
780  if (mpl%main) deallocate(rbuf)
781 end do
782 
783 end subroutine lct_write_cor
784 
785 end module type_lct
real(kind_real), parameter, public dmin
Definition: tools_func.F90:21
subroutine lct_rmse(lct, mpl, nam, geom, bpar)
Definition: type_lct.F90:406
subroutine lct_alloc(lct, nam, geom, bpar)
Definition: type_lct.F90:57
subroutine, public check_cond(d1, d2, nod, valid)
Definition: tools_func.F90:661
subroutine lct_write_cor(lct, mpl, nam, geom, bpar, io)
Definition: type_lct.F90:645
real(kind_real), parameter, public gau2gc
Definition: tools_func.F90:20
subroutine lct_dealloc(lct, bpar)
Definition: type_lct.F90:85
subroutine lct_filter(lct, mpl, nam, geom, bpar)
Definition: type_lct.F90:246
subroutine lct_compute(lct, mpl, nam, geom, bpar)
Definition: type_lct.F90:208
#define max(a, b)
Definition: mosaic_util.h:33
subroutine, public lct_d2h(mpl, D11, D22, D33, D12, H11, H22, H33, H12)
Definition: tools_func.F90:620
integer, parameter, public kind_real
#define min(a, b)
Definition: mosaic_util.h:32
logical, parameter write_cor
Definition: type_lct.F90:28
subroutine lct_write(lct, mpl, nam, geom, bpar, io)
Definition: type_lct.F90:475
subroutine lct_run_lct(lct, mpl, rng, nam, geom, bpar, io, ens)
Definition: type_lct.F90:113
real(fp), parameter, public pi
real(kind_real), parameter, public reqkm
Definition: tools_const.F90:19
subroutine, public fit_lct(mpl, nc, nl0, dx, dy, dz, dmask, nscales, D, coef, fit)
Definition: tools_func.F90:548