FV3 Bundle
type_nicas_blk.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: type_nicas_blk
3 ! Purpose: NICAS data block 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 !----------------------------------------------------------------------
9 
10 use netcdf
11 !$ use omp_lib
14 use tools_kinds, only: kind_real
16 use tools_nc, only: ncfloat
17 use tools_qsort, only: qsort
18 use tools_repro, only: supeq
19 use type_bpar, only: bpar_type
21 use type_com, only: com_type
22 use type_geom, only: geom_type
23 use type_io, only: io_type
24 use type_kdtree, only: kdtree_type
25 use type_linop, only: linop_type
26 use type_mesh, only: mesh_type
27 use type_mpl, only: mpl_type
28 use type_nam, only: nam_type
29 use type_rng, only: rng_type
30 use fckit_mpi_module, only: fckit_mpi_sum,fckit_mpi_min,fckit_mpi_max
31 
32 implicit none
33 
34 integer,parameter :: nc1max = 50000 ! Maximum size of the Sc1 subset
35 logical,parameter :: write_grids = .false. ! Write Sc1 and Sc2 subsets lon/lat
36 real(kind_real),parameter :: sqrt_r = 0.721_kind_real ! Square-root factor (empirical)
37 real(kind_real),parameter :: sqrt_r_dble = 0.86_kind_real ! Square-root factor (empirical)
38 real(kind_real),parameter :: sqrt_rfac = 0.9_kind_real ! Square-root factor (empirical)
39 real(kind_real),parameter :: sqrt_coef = 0.54_kind_real ! Square-root factor (empirical)
40 real(kind_real),parameter :: s_inf = 1.0e-2_kind_real ! Minimum value for the convolution coefficients
41 real(kind_real),parameter :: tol = 1.0e-3_kind_real ! Positive-definiteness test tolerance
42 integer,parameter :: nitermax = 50 ! Number of iterations for the positive-definiteness test
43 logical,parameter :: test_no_point = .false. ! Test NICAS with no subgrid point on the last MPI task
44 
45 ! Ball data derived type
47  integer :: nbd ! Number of values
48  integer,allocatable :: bd_to_c1(:) ! Ball data index to subset Sc1
49  integer,allocatable :: bd_to_l1(:) ! Ball data index to subset Sl1
50  real(kind_real),allocatable :: val(:) ! Values
51 contains
52  procedure :: alloc => balldata_alloc
53  procedure :: dealloc => balldata_dealloc
54  procedure :: pack => balldata_pack
55 end type balldata_type
56 
57 ! NICAS block derived type
59  ! Block index and name
60  integer :: ib ! Block index
61  character(len=1024) :: name ! Name
62  logical :: double_fit ! Double fit
63  logical :: anisotropic ! Anisoptropic tensor
64 
65  ! Specific geometry
66  integer :: nc1 ! Number of points in subset Sc1
67  integer,allocatable :: vbot(:) ! Bottom level in grid Gh
68  integer,allocatable :: vtop(:) ! Top level in grid Gh
69  integer,allocatable :: nc2(:) ! Number of points in subset Sc2
70  integer :: ns ! Number of subgrid nodes
71 
72  ! Full interpolations
73  type(linop_type),allocatable :: hfull(:) ! Horizontal interpolation
74  type(linop_type) :: vfull ! Vertical interpolation
75  type(linop_type),allocatable :: sfull(:) ! Subsample interpolation
76 
77  ! Other data
78 
79  ! Level selection
80  logical,allocatable :: llev(:) ! Level selection
81 
82  ! Parameters/normalization conversion
83  integer,allocatable :: s_to_c1(:) ! Subgrid to subset Sc1
84  integer,allocatable :: s_to_l1(:) ! Subgrid to subset Sl1
85  integer,allocatable :: c1_to_c0(:) ! Subset Sc1 to subset Sc0
86  integer,allocatable :: l1_to_l0(:) ! Subset Sl1 to subset Sl0
87  integer,allocatable :: c0_to_c1(:) ! Subset Sc0 to subset Sc1
88  integer,allocatable :: l0_to_l1(:) ! Subset Sl0 to subset Sl1
89  logical,allocatable :: mask_c1(:,:) ! Mask from subset C1 to subgrid
90  logical,allocatable :: mask_c2(:,:) ! Mask from subset C2 to subgrid
91  integer,allocatable :: c1l1_to_s(:,:) ! Grid Gv to subgrid
92  integer,allocatable :: c1_to_proc(:) ! Subset Sc1 to local task
93  integer,allocatable :: s_to_proc(:) ! Subgrid to local task
94 
95 
96  ! MPI distribution
97  integer :: nc1a ! Number of points in subset Sc1 on halo A
98  integer :: nc1bb ! Number of points in subset Sc1 on halo B (extended)
99  integer :: nsbb ! Number of points in subgrid on halo B (extended)
100  logical,allocatable :: lcheck_sa(:) ! Detection of halo A on subgrid
101  logical,allocatable :: lcheck_sb(:) ! Detection of halo B on subgrid
102  logical,allocatable :: lcheck_sc(:) ! Detection of halo C on subgrid
103  integer,allocatable :: c1a_to_c1(:) ! Subset Sc1, halo A to global
104  integer,allocatable :: c1_to_c1a(:) ! Subset Sc1, global to halo A
105  integer,allocatable :: c1b_to_c1(:) ! Subset Sc1, halo B to global
106  integer,allocatable :: c1_to_c1b(:) ! Subset Sc1, global to halo B
107  integer,allocatable :: c1bl1_to_sb(:,:) ! Halo B, subset Sc1 to subgrid
108  integer,allocatable :: interph_lg(:,:) ! Local to global for horizontal interpolation
109  integer,allocatable :: interps_lg(:,:) ! Local to global for subsampling interpolation
110  integer,allocatable :: c1a_to_c0a(:) ! Halo A, subset Sc1 to subset Sc0
111  integer,allocatable :: sa_to_c0a(:) ! Halo A, subgrid to subset Sc0
112  integer,allocatable :: sa_to_l0(:) ! Halo A, subgrid to subset Sl0
113  integer,allocatable :: sa_to_sb(:) ! Subgrid, halo A to halo B
114  integer,allocatable :: sc_to_sb(:) ! Subgrid, halo C to halo B
115  integer,allocatable :: sa_to_s(:) ! Subgrid, halo A to global
116  integer,allocatable :: s_to_sa(:) ! Subgrid, global to halo A
117  integer,allocatable :: sb_to_s(:) ! Subgrid, halo B to global
118  integer,allocatable :: s_to_sb(:) ! Subgrid, global to halo B
119  integer,allocatable :: sc_to_s(:) ! Subgrid, halo C to global
120  integer,allocatable :: s_to_sc(:) ! Subgrid, global to halo C
121  integer,allocatable :: sbb_to_s(:) ! Subgrid, halo B (extended) to global
122  integer,allocatable :: c1_to_c1bb(:) ! Subset Sc1, global to halo B (extended)
123  integer,allocatable :: c1bb_to_c1(:) ! Subset Sc1, halo B (extended) to global
124 
125  ! Convolution parameters
126  real(kind_real) :: rhmax !
127  real(kind_real),allocatable :: rh_c1(:,:) !
128  real(kind_real),allocatable :: rv_c1(:,:) !
129  real(kind_real),allocatable :: h11_c1(:,:) !
130  real(kind_real),allocatable :: h22_c1(:,:) !
131  real(kind_real),allocatable :: h33_c1(:,:) !
132  real(kind_real),allocatable :: h12_c1(:,:) !
133  type(balldata_type),allocatable :: hcoef(:) !
134  type(balldata_type),allocatable :: distnorm(:) !
135  type(balldata_type),allocatable :: distnormv(:) !
136  type(balldata_type),allocatable :: rfac(:) !
137  type(balldata_type),allocatable :: coef(:) !
138 
139  ! Extended data for normalization computation
140  integer :: nsc_nor ! Number of subgrid nodes on halo C (extended for normalization)
141  integer,allocatable :: sc_nor_to_s(:) ! Subgrid, halo C to global (extended for normalization)
142  integer,allocatable :: s_to_sc_nor(:) ! Subgrid, global to halo C (extended for normalization)
143  integer,allocatable :: sb_to_sc_nor(:) ! Subgrid, halo B to halo C (extended for normalization)
144  type(linop_type) :: c_nor ! Convolution (extended for normalization)
145 
146  ! KD-tree
147  type(kdtree_type) :: kdtree ! KD-tree
148 
149  ! Required data to apply a localization
150 
151  ! Number of points
152  integer :: nc1b ! Number of points in subset Sc1 on halo B
153  integer :: nl1 ! Number of levels in subset Sl1
154  integer :: nsa ! Number of subgrid nodes on halo A
155  integer :: nsb ! Number of subgrid nodes on halo B
156  integer :: nsc ! Number of subgrid nodes on halo C
157  integer :: nc0d ! Number of points in subset Sc1 on halo D
158  integer :: nc0dinv ! Number of points in subset Sc1 on halo Dinv
159 
160  ! Inter-halo conversions
161  integer,allocatable :: sa_to_sc(:) ! Subgrid, halo A to halo C
162  integer,allocatable :: sb_to_sc(:) ! Subgrid, halo B to halo C
163 
164  ! Linear operators
165  type(linop_type) :: c ! Convolution
166  type(linop_type),allocatable :: h(:) ! Horizontal interpolation
167  type(linop_type) :: v ! Vertical interpolation
168  type(linop_type),allocatable :: s(:) ! Subsample interpolation
169  type(linop_type),allocatable :: d(:,:) ! Advection
170  type(linop_type),allocatable :: dinv(:,:) ! Inverse advection
171 
172  ! Copy conversions
173  integer,allocatable :: sb_to_c1b(:) ! Subgrid to subset Sc1 on halo B
174  integer,allocatable :: sb_to_l1(:) ! Subgrid to subset Sl1 on halo B
175 
176  ! Normalization
177  real(kind_real),allocatable :: norm(:,:) ! Normalization factor
178 
179  ! Localization weights
180  real(kind_real),allocatable :: coef_ens(:,:) ! Ensemble coefficient square-root
181  real(kind_real) :: wgt ! Main weight
182 
183  ! Communications
184  type(com_type) :: com_ab ! Communication between halos A and B
185  type(com_type) :: com_ac ! Communication between halos A and C
186  type(com_type) :: com_ad ! Communication between halos A and D
187  type(com_type) :: com_adinv ! Communication between halos A and Dinv
188 contains
189  procedure :: dealloc => nicas_blk_dealloc
190  procedure :: compute_parameters => nicas_blk_compute_parameters
191  procedure :: compute_sampling => nicas_blk_compute_sampling
192  procedure :: compute_interp_h => nicas_blk_compute_interp_h
193  procedure :: compute_interp_v => nicas_blk_compute_interp_v
194  procedure :: compute_interp_s => nicas_blk_compute_interp_s
195  procedure :: compute_mpi_ab => nicas_blk_compute_mpi_ab
196  procedure :: compute_convol => nicas_blk_compute_convol
197  procedure :: compute_convol_network => nicas_blk_compute_convol_network
198  procedure :: compute_convol_distance => nicas_blk_compute_convol_distance
199  procedure :: compute_convol_weights => nicas_blk_compute_convol_weights
200  procedure :: compute_mpi_c => nicas_blk_compute_mpi_c
201  procedure :: compute_normalization => nicas_blk_compute_normalization
202  procedure :: compute_adv => nicas_blk_compute_adv
203  procedure :: apply => nicas_blk_apply
204  procedure :: apply_from_sqrt => nicas_blk_apply_from_sqrt
205  procedure :: apply_sqrt => nicas_blk_apply_sqrt
206  procedure :: apply_sqrt_ad => nicas_blk_apply_sqrt_ad
207  procedure :: apply_interp => nicas_blk_apply_interp
208  procedure :: apply_interp_ad => nicas_blk_apply_interp_ad
209  procedure :: apply_interp_h => nicas_blk_apply_interp_h
210  procedure :: apply_interp_h_ad => nicas_blk_apply_interp_h_ad
211  procedure :: apply_interp_v => nicas_blk_apply_interp_v
212  procedure :: apply_interp_v_ad => nicas_blk_apply_interp_v_ad
213  procedure :: apply_interp_s => nicas_blk_apply_interp_s
214  procedure :: apply_interp_s_ad => nicas_blk_apply_interp_s_ad
215  procedure :: apply_convol => nicas_blk_apply_convol
216  procedure :: apply_adv => nicas_blk_apply_adv
217  procedure :: apply_adv_ad => nicas_blk_apply_adv_ad
218  procedure :: apply_adv_inv => nicas_blk_apply_adv_inv
219  procedure :: test_adjoint => nicas_blk_test_adjoint
220  procedure :: test_pos_def => nicas_blk_test_pos_def
221  procedure :: test_sqrt => nicas_blk_test_sqrt
222  procedure :: test_dirac => nicas_blk_test_dirac
223 end type nicas_blk_type
224 
225 private
226 public :: nicas_blk_type
227 
228 contains
229 
230 !----------------------------------------------------------------------
231 ! Subroutine: balldata_alloc
232 ! Purpose: ball data allocation
233 !----------------------------------------------------------------------
234 subroutine balldata_alloc(balldata)
236 implicit none
237 
238 ! Passed variables
239 class(balldata_type),intent(inout) :: balldata ! Ball data
240 
241 ! Allocation
242 allocate(balldata%bd_to_c1(balldata%nbd))
243 allocate(balldata%bd_to_l1(balldata%nbd))
244 allocate(balldata%val(balldata%nbd))
245 
246 end subroutine balldata_alloc
247 
248 !----------------------------------------------------------------------
249 ! Subroutine: balldata_dealloc
250 ! Purpose: ball data deallocation
251 !----------------------------------------------------------------------
252 subroutine balldata_dealloc(balldata)
254 implicit none
255 
256 ! Passed variables
257 class(balldata_type),intent(inout) :: balldata ! Ball data
258 
259 ! Release memory
260 if (allocated(balldata%bd_to_c1)) deallocate(balldata%bd_to_c1)
261 if (allocated(balldata%bd_to_l1)) deallocate(balldata%bd_to_l1)
262 if (allocated(balldata%val)) deallocate(balldata%val)
263 
264 end subroutine balldata_dealloc
265 
266 !----------------------------------------------------------------------
267 ! Subroutine: balldata_pack
268 ! Purpose: pack data into balldata object
269 !----------------------------------------------------------------------
270 subroutine balldata_pack(balldata,nc1,nl1,val)
272 implicit none
273 
274 ! Passed variables
275 class(balldata_type),intent(inout) :: balldata ! Ball data
276 integer,intent(in) :: nc1 ! Horizontal box size
277 integer,intent(in) :: nl1 ! Vertical box size
278 real(kind_real),intent(in) :: val(nc1,nl1) ! Box value
279 
280 ! Local variables
281 integer :: ibd,ic1,il1
282 
283 ! Count non-missing values
284 balldata%nbd = count(isnotmsr(val))
285 
286 ! Allocation
287 call balldata%alloc
288 
289 ! Pack data
290 ibd = 0
291 do il1=1,nl1
292  do ic1=1,nc1
293  if (isnotmsr(val(ic1,il1))) then
294  ibd = ibd+1
295  balldata%bd_to_c1(ibd) = ic1
296  balldata%bd_to_l1(ibd) = il1
297  balldata%val(ibd) = val(ic1,il1)
298  end if
299  end do
300 end do
301 
302 end subroutine balldata_pack
303 
304 !----------------------------------------------------------------------
305 ! Subroutine: nicas_blk_dealloc
306 ! Purpose: NICAS block data deallocation
307 !----------------------------------------------------------------------
308 subroutine nicas_blk_dealloc(nicas_blk,nam,geom)
310 implicit none
311 
312 ! Passed variables
313 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
314 type(nam_type),target,intent(in) :: nam ! Namelist
315 type(geom_type),target,intent(in) :: geom ! Geometry
316 
317 ! Local variables
318 integer :: il0,il1,its,isbb
319 
320 ! Release memory
321 if (allocated(nicas_blk%vbot)) deallocate(nicas_blk%vbot)
322 if (allocated(nicas_blk%vtop)) deallocate(nicas_blk%vtop)
323 if (allocated(nicas_blk%nc2)) deallocate(nicas_blk%nc2)
324 if (allocated(nicas_blk%hfull)) then
325  do il0=1,geom%nl0i
326  call nicas_blk%hfull(il0)%dealloc
327  end do
328  deallocate(nicas_blk%hfull)
329 end if
330 call nicas_blk%vfull%dealloc
331 if (allocated(nicas_blk%sfull)) then
332  do il1=1,nicas_blk%nl1
333  call nicas_blk%sfull(il1)%dealloc
334  end do
335  deallocate(nicas_blk%sfull)
336 end if
337 if (allocated(nicas_blk%llev)) deallocate(nicas_blk%llev)
338 if (allocated(nicas_blk%s_to_c1)) deallocate(nicas_blk%s_to_c1)
339 if (allocated(nicas_blk%s_to_l1)) deallocate(nicas_blk%s_to_l1)
340 if (allocated(nicas_blk%c1_to_c0)) deallocate(nicas_blk%c1_to_c0)
341 if (allocated(nicas_blk%l1_to_l0)) deallocate(nicas_blk%l1_to_l0)
342 if (allocated(nicas_blk%c0_to_c1)) deallocate(nicas_blk%c0_to_c1)
343 if (allocated(nicas_blk%l0_to_l1)) deallocate(nicas_blk%l0_to_l1)
344 if (allocated(nicas_blk%mask_c1)) deallocate(nicas_blk%mask_c1)
345 if (allocated(nicas_blk%mask_c2)) deallocate(nicas_blk%mask_c2)
346 if (allocated(nicas_blk%c1l1_to_s)) deallocate(nicas_blk%c1l1_to_s)
347 if (allocated(nicas_blk%c1_to_proc)) deallocate(nicas_blk%c1_to_proc)
348 if (allocated(nicas_blk%s_to_proc)) deallocate(nicas_blk%s_to_proc)
349 if (allocated(nicas_blk%lcheck_sa)) deallocate(nicas_blk%lcheck_sa)
350 if (allocated(nicas_blk%lcheck_sb)) deallocate(nicas_blk%lcheck_sb)
351 if (allocated(nicas_blk%lcheck_sc)) deallocate(nicas_blk%lcheck_sc)
352 if (allocated(nicas_blk%c1a_to_c1)) deallocate(nicas_blk%c1a_to_c1)
353 if (allocated(nicas_blk%c1_to_c1a)) deallocate(nicas_blk%c1_to_c1a)
354 if (allocated(nicas_blk%c1b_to_c1)) deallocate(nicas_blk%c1b_to_c1)
355 if (allocated(nicas_blk%c1_to_c1b)) deallocate(nicas_blk%c1_to_c1b)
356 if (allocated(nicas_blk%c1bl1_to_sb)) deallocate(nicas_blk%c1bl1_to_sb)
357 if (allocated(nicas_blk%interph_lg)) deallocate(nicas_blk%interph_lg)
358 if (allocated(nicas_blk%interps_lg)) deallocate(nicas_blk%interps_lg)
359 if (allocated(nicas_blk%c1a_to_c0a)) deallocate(nicas_blk%c1a_to_c0a)
360 if (allocated(nicas_blk%sa_to_c0a)) deallocate(nicas_blk%sa_to_c0a)
361 if (allocated(nicas_blk%sa_to_l0)) deallocate(nicas_blk%sa_to_l0)
362 if (allocated(nicas_blk%sa_to_sb)) deallocate(nicas_blk%sa_to_sb)
363 if (allocated(nicas_blk%sc_to_sb)) deallocate(nicas_blk%sc_to_sb)
364 if (allocated(nicas_blk%sa_to_s)) deallocate(nicas_blk%sa_to_s)
365 if (allocated(nicas_blk%s_to_sa)) deallocate(nicas_blk%s_to_sa)
366 if (allocated(nicas_blk%sb_to_s)) deallocate(nicas_blk%sb_to_s)
367 if (allocated(nicas_blk%s_to_sb)) deallocate(nicas_blk%s_to_sb)
368 if (allocated(nicas_blk%sc_to_s)) deallocate(nicas_blk%sc_to_s)
369 if (allocated(nicas_blk%s_to_sc)) deallocate(nicas_blk%s_to_sc)
370 if (allocated(nicas_blk%sbb_to_s)) deallocate(nicas_blk%sbb_to_s)
371 if (allocated(nicas_blk%c1_to_c1bb)) deallocate(nicas_blk%c1_to_c1bb)
372 if (allocated(nicas_blk%c1bb_to_c1)) deallocate(nicas_blk%c1bb_to_c1)
373 if (allocated(nicas_blk%rh_c1)) deallocate(nicas_blk%rh_c1)
374 if (allocated(nicas_blk%rv_c1)) deallocate(nicas_blk%rv_c1)
375 if (allocated(nicas_blk%H11_c1)) deallocate(nicas_blk%H11_c1)
376 if (allocated(nicas_blk%H22_c1)) deallocate(nicas_blk%H22_c1)
377 if (allocated(nicas_blk%H33_c1)) deallocate(nicas_blk%H33_c1)
378 if (allocated(nicas_blk%H12_c1)) deallocate(nicas_blk%H12_c1)
379 if (allocated(nicas_blk%Hcoef)) then
380  do isbb=1,nicas_blk%nsbb
381  call nicas_blk%Hcoef(isbb)%dealloc
382  end do
383  deallocate(nicas_blk%Hcoef)
384 end if
385 
386 if (allocated(nicas_blk%distnorm)) then
387  do isbb=1,nicas_blk%nsbb
388  call nicas_blk%distnorm(isbb)%dealloc
389  end do
390  deallocate(nicas_blk%distnorm)
391 end if
392 if (allocated(nicas_blk%distnormv)) then
393  do isbb=1,nicas_blk%nsbb
394  call nicas_blk%distnormv(isbb)%dealloc
395  end do
396  deallocate(nicas_blk%distnormv)
397 end if
398 if (allocated(nicas_blk%rfac)) then
399  do isbb=1,nicas_blk%nsbb
400  call nicas_blk%rfac(isbb)%dealloc
401  end do
402  deallocate(nicas_blk%rfac)
403 end if
404 if (allocated(nicas_blk%coef)) then
405  do isbb=1,nicas_blk%nsbb
406  call nicas_blk%coef(isbb)%dealloc
407  end do
408  deallocate(nicas_blk%coef)
409 end if
410 if (allocated(nicas_blk%sc_nor_to_s)) deallocate(nicas_blk%sc_nor_to_s)
411 if (allocated(nicas_blk%s_to_sc_nor)) deallocate(nicas_blk%s_to_sc_nor)
412 if (allocated(nicas_blk%sb_to_sc_nor)) deallocate(nicas_blk%sb_to_sc_nor)
413 call nicas_blk%c_nor%dealloc
414 call nicas_blk%kdtree%dealloc
415 if (allocated(nicas_blk%sa_to_sc)) deallocate(nicas_blk%sa_to_sc)
416 if (allocated(nicas_blk%sb_to_sc)) deallocate(nicas_blk%sb_to_sc)
417 call nicas_blk%c%dealloc
418 if (allocated(nicas_blk%h)) then
419  do il0=1,geom%nl0i
420  call nicas_blk%h(il0)%dealloc
421  end do
422  deallocate(nicas_blk%h)
423 end if
424 call nicas_blk%v%dealloc
425 if (allocated(nicas_blk%s)) then
426  do il1=1,nicas_blk%nl1
427  call nicas_blk%s(il1)%dealloc
428  end do
429  deallocate(nicas_blk%s)
430 end if
431 if (allocated(nicas_blk%d)) then
432  do its=2,nam%nts
433  do il0=1,geom%nl0
434  call nicas_blk%d(il0,its)%dealloc
435  call nicas_blk%dinv(il0,its)%dealloc
436  end do
437  end do
438  deallocate(nicas_blk%d)
439  deallocate(nicas_blk%dinv)
440 end if
441 if (allocated(nicas_blk%sb_to_c1b)) deallocate(nicas_blk%sb_to_c1b)
442 if (allocated(nicas_blk%sb_to_l1)) deallocate(nicas_blk%sb_to_l1)
443 if (allocated(nicas_blk%norm)) deallocate(nicas_blk%norm)
444 if (allocated(nicas_blk%coef_ens)) deallocate(nicas_blk%coef_ens)
445 if (allocated(nicas_blk%sb_to_c1b)) deallocate(nicas_blk%sb_to_c1b)
446 call nicas_blk%com_AB%dealloc
447 call nicas_blk%com_AC%dealloc
448 call nicas_blk%com_AD%dealloc
449 call nicas_blk%com_ADinv%dealloc
450 
451 end subroutine nicas_blk_dealloc
452 
453 !----------------------------------------------------------------------
454 ! Subroutine: nicas_blk_compute_parameters
455 ! Purpose: compute NICAS parameters
456 !----------------------------------------------------------------------
457 subroutine nicas_blk_compute_parameters(nicas_blk,mpl,rng,nam,geom,cmat_blk)
459 implicit none
460 
461 ! Passed variables
462 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
463 type(mpl_type),intent(inout) :: mpl ! MPI data
464 type(rng_type),intent(inout) :: rng ! Random number generator
465 type(nam_type),intent(in) :: nam ! Namelist
466 type(geom_type),intent(in) :: geom ! Geometry
467 type(cmat_blk_type),intent(in) :: cmat_blk ! C matrix data block
468 
469 ! Local variables
470 integer :: il0i,il1
471 
472 ! Compute adaptive sampling
473 write(mpl%info,'(a7,a)') '','Compute adaptive sampling'
474 call flush(mpl%info)
475 call nicas_blk%compute_sampling(mpl,rng,nam,geom,cmat_blk)
476 
477 ! Compute horizontal interpolation data
478 write(mpl%info,'(a7,a)') '','Compute horizontal interpolation data'
479 call flush(mpl%info)
480 call nicas_blk%compute_interp_h(mpl,rng,nam,geom)
481 
482 ! Compute vertical interpolation data
483 write(mpl%info,'(a7,a)') '','Compute vertical interpolation data'
484 call flush(mpl%info)
485 call nicas_blk%compute_interp_v(geom)
486 
487 ! Compute subsampling horizontal interpolation data
488 write(mpl%info,'(a7,a)') '','Compute subsampling horizontal interpolation data'
489 call flush(mpl%info)
490 call nicas_blk%compute_interp_s(mpl,rng,nam,geom)
491 
492 ! Compute MPI distribution, halos A-B
493 write(mpl%info,'(a7,a)') '','Compute MPI distribution, halos A-B'
494 call flush(mpl%info)
495 call nicas_blk%compute_mpi_ab(mpl,geom)
496 
497 ! Compute convolution data
498 write(mpl%info,'(a7,a)') '','Compute convolution data'
499 call flush(mpl%info)
500 call nicas_blk%compute_convol(mpl,rng,nam,geom,cmat_blk)
501 
502 ! Compute MPI distribution, halo C
503 write(mpl%info,'(a7,a)') '','Compute MPI distribution, halo C'
504 call flush(mpl%info)
505 call nicas_blk%compute_mpi_c(mpl,geom)
506 
507 ! Compute normalization
508 write(mpl%info,'(a7,a)') '','Compute normalization'
509 call flush(mpl%info)
510 call nicas_blk%compute_normalization(mpl,nam,geom)
511 
512 ! Print results
513 write(mpl%info,'(a7,a,i4)') '','Parameters for processor #',mpl%myproc
514 write(mpl%info,'(a10,a,i8)') '','nc0 = ',geom%nc0
515 write(mpl%info,'(a10,a,i8)') '','nc0a = ',geom%nc0a
516 write(mpl%info,'(a10,a,i8)') '','nl0 = ',geom%nl0
517 write(mpl%info,'(a10,a,i8)') '','nc1 = ',nicas_blk%nc1
518 write(mpl%info,'(a10,a,i8)') '','nc1a = ',nicas_blk%nc1a
519 write(mpl%info,'(a10,a,i8)') '','nc1b = ',nicas_blk%nc1b
520 write(mpl%info,'(a10,a,i8)') '','nl1 = ',nicas_blk%nl1
521 do il1=1,nicas_blk%nl1
522  write(mpl%info,'(a10,a,i3,a,i8)') '','nc2(',il1,') = ',nicas_blk%nc2(il1)
523 end do
524 write(mpl%info,'(a10,a,i8)') '','ns = ',nicas_blk%ns
525 write(mpl%info,'(a10,a,i8)') '','nsa = ',nicas_blk%nsa
526 write(mpl%info,'(a10,a,i8)') '','nsb = ',nicas_blk%nsb
527 write(mpl%info,'(a10,a,i8)') '','nsc = ',nicas_blk%nsc
528 do il0i=1,geom%nl0i
529  write(mpl%info,'(a10,a,i3,a,i8)') '','h(',il0i,')%n_s = ',nicas_blk%h(il0i)%n_s
530 end do
531 write(mpl%info,'(a10,a,i8)') '','v%n_s = ',nicas_blk%v%n_s
532 do il1=1,nicas_blk%nl1
533  write(mpl%info,'(a10,a,i3,a,i8)') '','s(',il1,')%n_s = ',nicas_blk%s(il1)%n_s
534 end do
535 write(mpl%info,'(a10,a,i8)') '','c%n_s = ',nicas_blk%c%n_s
536 write(mpl%info,'(a10,a,i8)') '','c_nor%n_s = ',nicas_blk%c_nor%n_s
537 call flush(mpl%info)
538 
539 end subroutine nicas_blk_compute_parameters
540 
541 !----------------------------------------------------------------------
542 ! Subroutine: nicas_blk_compute_sampling
543 ! Purpose: compute NICAS sampling
544 !----------------------------------------------------------------------
545 subroutine nicas_blk_compute_sampling(nicas_blk,mpl,rng,nam,geom,cmat_blk)
547 implicit none
548 
549 ! Passed variables
550 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
551 type(mpl_type),intent(inout) :: mpl ! MPI data
552 type(rng_type),intent(inout) :: rng ! Random number generator
553 type(nam_type),intent(in) :: nam ! Namelist
554 type(geom_type),intent(in) :: geom ! Geometry
555 type(cmat_blk_type),intent(in) :: cmat_blk ! C matrix data block
556 
557 ! Local variables
558 integer :: il0,il0_prev,il1,ic0,ic1,ic2,is,ic0a,iproc
559 integer :: ncid,nc1_id,nl1_id,lon_c1_id,lat_c1_id,mask_c2_id
560 integer,allocatable :: c2_to_c1(:)
561 real(kind_real) :: rhs_sum(geom%nl0),rhs_avg(geom%nl0),rvs_sum(geom%nl0),rvs_avg(geom%nl0),norm(geom%nl0),distnorm(geom%nc0a)
562 real(kind_real) :: distnormmin,rv,rhs_minavg
563 real(kind_real),allocatable :: rhs_min(:),rhs_min_glb(:),rhs_c0(:),rhs_c1(:)
564 real(kind_real),allocatable :: lon_c1(:),lat_c1(:),mask_c2_real(:,:)
565 logical :: inside
566 logical,allocatable :: mask_hor_c0(:),mask_c1(:)
567 character(len=1024) :: filename
568 character(len=1024) :: subr = 'nicas_blk_compute_sampling'
569 
570 ! Allocation
571 allocate(rhs_min(geom%nc0a))
572 allocate(rhs_min_glb(geom%nc0))
573 allocate(nicas_blk%llev(geom%nl0))
574 
575 ! Reset random numbers seed
576 if (trim(nam%strategy)=='specific_multivariate') call rng%reseed(mpl)
577 
578 ! Compute support radii
579 norm = 1.0/real(geom%nc0_mask,kind_real)
580 rhs_sum = sum(cmat_blk%rhs,dim=1,mask=geom%mask_c0a)
581 call mpl%f_comm%allreduce(rhs_sum,rhs_avg,fckit_mpi_sum())
582 rhs_avg = rhs_avg*norm
583 rvs_sum = sum(cmat_blk%rvs,dim=1,mask=geom%mask_c0a)
584 call mpl%f_comm%allreduce(rvs_sum,rvs_avg,fckit_mpi_sum())
585 rvs_avg = rvs_avg*norm
586 write(mpl%info,'(a10,a)') '','Average support radii (H/V): '
587 do il0=1,geom%nl0
588  write(mpl%info,'(a13,a,i3,a,f10.2,a,f10.2,a)') '','Level ',nam%levs(il0),': '//trim(mpl%aqua),rhs_avg(il0)*reqkm, &
589  & trim(mpl%black)//' km / '//trim(mpl%aqua),rvs_avg(il0),trim(mpl%black)//' '//trim(mpl%vunitchar)
590 end do
591 call flush(mpl%info)
592 
593 ! Basic horizontal mesh defined with the minimum support radius
594 norm(1) = 1.0/real(count(geom%mask_hor_c0),kind_real)
595 rhs_min = huge(1.0)
596 do ic0a=1,geom%nc0a
597  ic0 = geom%c0a_to_c0(ic0a)
598  do il0=1,geom%nl0
599  if (geom%mask_c0(ic0,il0)) then
600  rhs_min(ic0a) = min(cmat_blk%rhs(ic0a,il0),rhs_min(ic0a))
601  end if
602  end do
603 end do
604 call mpl%f_comm%allreduce(sum(rhs_min,mask=geom%mask_hor_c0a),rhs_minavg,fckit_mpi_sum())
605 rhs_minavg = rhs_minavg*norm(1)
606 if (rhs_minavg>0.0) then
607  nicas_blk%nc1 = floor(2.0*maxval(geom%area)*nam%resol**2/(sqrt(3.0)*rhs_minavg**2))
608 else
609  nicas_blk%nc1 = geom%nc0
610 end if
611 nicas_blk%nc1 = min(nicas_blk%nc1,geom%nc0)
612 write(mpl%info,'(a10,a,i8)') '','Estimated nc1 from horizontal support radius: ',nicas_blk%nc1
613 call flush(mpl%info)
614 if (nicas_blk%nc1>nc1max) then
615  call mpl%warning('required nc1 larger than nc1max, resetting to nc1max')
616  nicas_blk%nc1 = nc1max
617  write(mpl%info,'(a10,a,f5.2)') '','Effective horizontal resolution: ',sqrt(real(nicas_blk%nc1,kind_real)*sqrt(3.0) &
618  & *rhs_minavg**2/(2.0*maxval(geom%area)))
619  call flush(mpl%info)
620 end if
621 if (nicas_blk%nc1<3) call mpl%abort('nicas_blk%nc1 lower than 3')
622 
623 ! Allocation
624 allocate(nicas_blk%c1_to_c0(nicas_blk%nc1))
625 
626 ! Communication
627 call mpl%loc_to_glb(geom%nc0a,rhs_min,geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,.true.,rhs_min_glb)
628 
629 ! Compute subset
630 write(mpl%info,'(a7,a)',advance='no') '','Compute horizontal subset C1: '
631 call flush(mpl%info)
632 
633 ! Allocation
634 allocate(mask_hor_c0(geom%nc0))
635 mask_hor_c0 = geom%mask_hor_c0
636 
637 if (test_no_point) then
638  ! Mask points on the last MPI task
639  if (mpl%nproc==1) call mpl%abort('at least 2 MPI tasks required for test_no_point')
640  do ic0=1,geom%nc0
641  iproc = geom%c0_to_proc(ic0)
642  if (iproc==mpl%nproc) mask_hor_c0(ic0) = .false.
643  end do
644 end if
645 
646 ! Compute subsampling
647 call rng%initialize_sampling(mpl,geom%nc0,geom%lon,geom%lat,mask_hor_c0,rhs_min_glb,nam%ntry,nam%nrep, &
648  & nicas_blk%nc1,nicas_blk%c1_to_c0,fast=nam%fast_sampling)
649 nicas_blk%c1_to_proc = geom%c0_to_proc(nicas_blk%c1_to_c0)
650 
651 ! Inverse conversion
652 allocate(nicas_blk%c0_to_c1(geom%nc0))
653 call msi(nicas_blk%c0_to_c1)
654 do ic1=1,nicas_blk%nc1
655  ic0 = nicas_blk%c1_to_c0(ic1)
656  nicas_blk%c0_to_c1(ic0) = ic1
657 end do
658 
659 ! Vertical sampling
660 write(mpl%info,'(a7,a)',advance='no') '','Compute vertical subset L1: '
661 call flush(mpl%info)
662 il0_prev = 1
663 do il0=1,geom%nl0
664  ! Look for convolution levels
665  if ((il0==1).or.(il0==geom%nl0)) then
666  ! Keep first and last levels
667  nicas_blk%llev(il0) = .true.
668  else
669  ! Compute minimum normalized distance with level il0_prev
670  distnorm = huge(1.0)
671  do ic0a=1,geom%nc0a
672  ic0 = geom%c0a_to_c0(ic0a)
673  if (geom%mask_c0(ic0,il0)) then
674  rv = sqrt(0.5*(cmat_blk%rvs(ic0a,il0)**2+cmat_blk%rvs(ic0a,il0_prev)**2))
675  if (rv>0.0) distnorm(ic0a) = abs(geom%vunit(ic0,il0)-geom%vunit(ic0,il0_prev))/rv
676  end if
677  end do
678  call mpl%f_comm%allreduce(minval(distnorm),distnormmin,fckit_mpi_min())
679  nicas_blk%llev(il0) = distnormmin>1.0/nam%resol
680  end if
681 
682  ! Update
683  if (nicas_blk%llev(il0)) il0_prev = il0
684 end do
685 nicas_blk%nl1 = count(nicas_blk%llev)
686 allocate(nicas_blk%l1_to_l0(nicas_blk%nl1))
687 il1 = 0
688 do il0=1,geom%nl0
689  if (nicas_blk%llev(il0)) then
690  write(mpl%info,'(i3,a)',advance='no') nam%levs(il0),' '
691  call flush(mpl%info)
692  il1 = il1+1
693  nicas_blk%l1_to_l0(il1) = il0
694  end if
695 end do
696 write(mpl%info,'(a)') ''
697 call flush(mpl%info)
698 
699 ! Find bottom and top for each point of S1
700 allocate(nicas_blk%vbot(nicas_blk%nc1))
701 allocate(nicas_blk%vtop(nicas_blk%nc1))
702 !$omp parallel do schedule(static) private(ic1,ic0,inside,il1,il0)
703 do ic1=1,nicas_blk%nc1
704  ic0 = nicas_blk%c1_to_c0(ic1)
705  inside = .false.
706  nicas_blk%vtop(ic1) = geom%nl0
707  do il1=1,nicas_blk%nl1
708  il0 = nicas_blk%l1_to_l0(il1)
709  if (.not.inside.and.geom%mask_c0(ic0,il0)) then
710  ! Bottom level
711  nicas_blk%vbot(ic1) = il0
712  inside = .true.
713  end if
714  if (inside.and.(.not.geom%mask_c0(ic0,il0))) then
715  ! Top level
716  nicas_blk%vtop(ic1) = il0
717  inside = .false.
718  end if
719  end do
720  if (nicas_blk%vbot(ic1)>nicas_blk%vtop(ic1)) call mpl%abort('non contiguous mask')
721 end do
722 !$omp end parallel do
723 
724 ! Inverse conversion
725 allocate(nicas_blk%l0_to_l1(geom%nl0))
726 call msi(nicas_blk%l0_to_l1)
727 do il1=1,nicas_blk%nl1
728  il0 = nicas_blk%l1_to_l0(il1)
729  nicas_blk%l0_to_l1(il0) = il1
730 end do
731 
732 ! Allocation
733 allocate(nicas_blk%nc2(nicas_blk%nl1))
734 allocate(nicas_blk%mask_c2(nicas_blk%nc1,nicas_blk%nl1))
735 allocate(lon_c1(nicas_blk%nc1))
736 allocate(lat_c1(nicas_blk%nc1))
737 allocate(mask_c1(nicas_blk%nc1))
738 allocate(rhs_c0(geom%nc0))
739 allocate(rhs_c1(nicas_blk%nc1))
740 
741 ! Initialization
742 lon_c1 = geom%lon(nicas_blk%c1_to_c0)
743 lat_c1 = geom%lat(nicas_blk%c1_to_c0)
744 
745 ! Horizontal subsampling
746 do il1=1,nicas_blk%nl1
747  write(mpl%info,'(a7,a,i3,a)',advance='no') '','Compute horizontal subset C2 (level ',il1,'): '
748  call flush(mpl%info)
749 
750  ! Initialization
751  mask_c1 = geom%mask_c0(nicas_blk%c1_to_c0,il0)
752 
753  ! Compute nc2
754  il0 = nicas_blk%l1_to_l0(il1)
755  nicas_blk%nc2(il1) = floor(2.0*geom%area(il0)*nam%resol**2/(sqrt(3.0)*rhs_avg(il0)**2))
756  nicas_blk%nc2(il1) = min(nicas_blk%nc2(il1),nicas_blk%nc1)
757  nicas_blk%nc2(il1) = min(nicas_blk%nc2(il1),count(mask_c1))
758  if (nicas_blk%nc2(il1)<3) call mpl%abort('nicas_blk%nc2 lower than 3')
759 
760  if (nicas_blk%nc2(il1)<nicas_blk%nc1) then
761  ! Allocation
762  allocate(c2_to_c1(nicas_blk%nc2(il1)))
763 
764  ! Local to global
765  call mpl%loc_to_glb(geom%nc0a,cmat_blk%rhs(:,il0),geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,.false.,rhs_c0)
766  rhs_c1 = rhs_c0(nicas_blk%c1_to_c0)
767 
768  ! Initialize sampling
769  call rng%initialize_sampling(mpl,nicas_blk%nc1,lon_c1,lat_c1,mask_c1,rhs_c1,nam%ntry,nam%nrep,nicas_blk%nc2(il1),c2_to_c1, &
770  & fast=nam%fast_sampling)
771 
772  ! Fill C2 mask
773  nicas_blk%mask_c2(:,il1) = .false.
774  do ic2=1,nicas_blk%nc2(il1)
775  ic1 = c2_to_c1(ic2)
776  nicas_blk%mask_c2(ic1,il1) = .true.
777  end do
778 
779  ! Release memory
780  deallocate(c2_to_c1)
781  else
782  if (mpl%main) then
783  write(mpl%info,'(a)') 'use all C1 points'
784  call flush(mpl%info)
785  end if
786 
787  ! Fill C2 mask
788  nicas_blk%mask_c2(:,il1) = .true.
789  end if
790 end do
791 
792 ! Size
793 nicas_blk%ns = sum(nicas_blk%nc2)
794 
795 ! Conversions
796 allocate(nicas_blk%s_to_c1(nicas_blk%ns))
797 allocate(nicas_blk%s_to_l1(nicas_blk%ns))
798 allocate(nicas_blk%s_to_proc(nicas_blk%ns))
799 is = 0
800 do il1=1,nicas_blk%nl1
801  do ic1=1,nicas_blk%nc1
802  if (nicas_blk%mask_c2(ic1,il1)) then
803  is = is+1
804  nicas_blk%s_to_c1(is) = ic1
805  nicas_blk%s_to_l1(is) = il1
806  nicas_blk%s_to_proc(is) = nicas_blk%c1_to_proc(ic1)
807  end if
808  end do
809 end do
810 
811 ! Conversions
812 allocate(nicas_blk%c1l1_to_s(nicas_blk%nc1,nicas_blk%nl1))
813 call msi(nicas_blk%c1l1_to_s)
814 do is=1,nicas_blk%ns
815  ic1 = nicas_blk%s_to_c1(is)
816  il1 = nicas_blk%s_to_l1(is)
817  nicas_blk%c1l1_to_s(ic1,il1) = is
818 end do
819 
820 ! Write grids
821 if (mpl%main.and.write_grids) then
822  ! Allocation
823  allocate(lon_c1(nicas_blk%nc1))
824  allocate(lat_c1(nicas_blk%nc1))
825  allocate(mask_c2_real(nicas_blk%nc1,nicas_blk%nl1))
826 
827  ! Copy data
828  lon_c1 = geom%lon(nicas_blk%c1_to_c0)*rad2deg
829  lat_c1 = geom%lat(nicas_blk%c1_to_c0)*rad2deg
830  call msr(mask_c2_real)
831  do il1=1,nicas_blk%nl1
832  do ic1=1,nicas_blk%nc1
833  if (nicas_blk%mask_c2(ic1,il1)) mask_c2_real(ic1,il1) = 1.0
834  end do
835  end do
836 
837  ! Create file
838  filename = trim(nam%prefix)//'_'//trim(nicas_blk%name)//'_grids.nc'
839  call mpl%ncerr(subr,nf90_create(trim(nam%datadir)//'/'//trim(filename),or(nf90_clobber,nf90_64bit_offset),ncid))
840 
841  ! Define dimensions
842  call mpl%ncerr(subr,nf90_def_dim(ncid,'nc1',nicas_blk%nc1,nc1_id))
843  call mpl%ncerr(subr,nf90_def_dim(ncid,'nl1',nicas_blk%nl1,nl1_id))
844 
845  ! Define variables
846  call mpl%ncerr(subr,nf90_def_var(ncid,'lon_c1',ncfloat,(/nc1_id/),lon_c1_id))
847  call mpl%ncerr(subr,nf90_def_var(ncid,'lat_c1',ncfloat,(/nc1_id/),lat_c1_id))
848  call mpl%ncerr(subr,nf90_def_var(ncid,'mask_c2',ncfloat,(/nc1_id,nl1_id/),mask_c2_id))
849  call mpl%ncerr(subr,nf90_put_att(ncid,mask_c2_id,'_FillValue',msvalr))
850 
851  ! End definition mode
852  call mpl%ncerr(subr,nf90_enddef(ncid))
853 
854  ! Write variables
855  call mpl%ncerr(subr,nf90_put_var(ncid,lon_c1_id,lon_c1))
856  call mpl%ncerr(subr,nf90_put_var(ncid,lat_c1_id,lat_c1))
857  call mpl%ncerr(subr,nf90_put_var(ncid,mask_c2_id,mask_c2_real))
858 
859  ! Close file
860  call mpl%ncerr(subr,nf90_close(ncid))
861 
862  ! Release memory
863  deallocate(lon_c1)
864  deallocate(lat_c1)
865  deallocate(mask_c2_real)
866 end if
867 
868 end subroutine nicas_blk_compute_sampling
869 
870 !----------------------------------------------------------------------
871 ! Subroutine: nicas_blk_compute_interp_h
872 ! Purpose: compute basic horizontal interpolation
873 !----------------------------------------------------------------------
874 subroutine nicas_blk_compute_interp_h(nicas_blk,mpl,rng,nam,geom)
876 implicit none
877 
878 ! Passed variables
879 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
880 type(mpl_type),intent(inout) :: mpl ! MPI data
881 type(rng_type),intent(inout) :: rng ! Random number generator
882 type(nam_type),intent(in) :: nam ! Namelist
883 type(geom_type),intent(in) :: geom ! Geometry
884 
885 ! Local variables
886 integer :: il0i
887 type(linop_type) :: hbase
888 
889 ! Allocation
890 allocate(nicas_blk%hfull(geom%nl0i))
891 
892 do il0i=1,geom%nl0i
893  ! Compute grid interpolation
894  call nicas_blk%hfull(il0i)%interp(mpl,rng,geom,il0i,nicas_blk%nc1,nicas_blk%c1_to_c0,nam%mask_check, &
895  & nicas_blk%vbot,nicas_blk%vtop,nam%nicas_interp,hbase)
896 end do
897 
898 end subroutine nicas_blk_compute_interp_h
899 
900 !----------------------------------------------------------------------
901 ! Subroutine: nicas_blk_compute_interp_v
902 ! Purpose: compute vertical interpolation
903 !----------------------------------------------------------------------
904 subroutine nicas_blk_compute_interp_v(nicas_blk,geom)
906 implicit none
907 
908 ! Passed variables
909 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
910 type(geom_type),intent(in) :: geom ! Geometry
911 
912 ! Local variables
913 integer :: ic1,ic0,jl0,il0,jl1,il0inf,il0sup
914 
915 ! Initialize vertical interpolation
916 nicas_blk%vfull%prefix = 'vfull'
917 nicas_blk%vfull%n_src = nicas_blk%nl1
918 nicas_blk%vfull%n_dst = geom%nl0
919 
920 ! Linear interpolation
921 nicas_blk%vfull%n_s = nicas_blk%nl1
922 il0inf = 1
923 do jl0=1,geom%nl0
924  if (nicas_blk%llev(jl0)) then
925  il0sup = jl0
926  do il0=il0inf+1,il0sup-1
927  nicas_blk%vfull%n_s = nicas_blk%vfull%n_s+2
928  end do
929  il0inf = jl0
930  end if
931 end do
932 call nicas_blk%vfull%alloc(nicas_blk%nc1)
933 
934 do jl1=1,nicas_blk%nl1
935  jl0 = nicas_blk%l1_to_l0(jl1)
936  nicas_blk%vfull%row(jl1) = jl0
937  nicas_blk%vfull%col(jl1) = jl0
938  do ic1=1,nicas_blk%nc1
939  nicas_blk%vfull%Svec(jl1,ic1) = 1.0
940  end do
941 end do
942 
943 nicas_blk%vfull%n_s = nicas_blk%nl1
944 il0inf = 1
945 do jl0=1,geom%nl0
946  if (nicas_blk%llev(jl0)) then
947  il0sup = jl0
948  do il0=il0inf+1,il0sup-1
949  nicas_blk%vfull%n_s = nicas_blk%vfull%n_s+1
950  nicas_blk%vfull%row(nicas_blk%vfull%n_s) = il0
951  nicas_blk%vfull%col(nicas_blk%vfull%n_s) = il0inf
952  do ic1=1,nicas_blk%nc1
953  ic0 = nicas_blk%c1_to_c0(ic1)
954  nicas_blk%vfull%Svec(nicas_blk%vfull%n_s,ic1) = abs(geom%vunit(ic0,il0sup)-geom%vunit(ic0,il0)) &
955  & /abs(geom%vunit(ic0,il0sup)-geom%vunit(ic0,il0inf))
956  end do
957 
958  nicas_blk%vfull%n_s = nicas_blk%vfull%n_s+1
959  nicas_blk%vfull%row(nicas_blk%vfull%n_s) = il0
960  nicas_blk%vfull%col(nicas_blk%vfull%n_s) = il0sup
961  do ic1=1,nicas_blk%nc1
962  ic0 = nicas_blk%c1_to_c0(ic1)
963  nicas_blk%vfull%Svec(nicas_blk%vfull%n_s,ic1) = abs(geom%vunit(ic0,il0)-geom%vunit(ic0,il0inf)) &
964  & /abs(geom%vunit(ic0,il0sup)-geom%vunit(ic0,il0inf))
965  end do
966  end do
967  il0inf = jl0
968  end if
969 end do
970 
971 ! Conversion
972 nicas_blk%vfull%col = nicas_blk%l0_to_l1(nicas_blk%vfull%col)
973 
974 ! Deallocate selected levels
975 deallocate(nicas_blk%llev)
976 
977 end subroutine nicas_blk_compute_interp_v
978 
979 !----------------------------------------------------------------------
980 ! Subroutine: nicas_blk_compute_interp_s
981 ! Purpose: compute horizontal subsampling interpolation
982 !----------------------------------------------------------------------
983 subroutine nicas_blk_compute_interp_s(nicas_blk,mpl,rng,nam,geom)
985 implicit none
986 
987 ! Passed variables
988 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
989 type(mpl_type),intent(inout) :: mpl ! MPI data
990 type(rng_type),intent(inout) :: rng ! Random number generator
991 type(nam_type),intent(in) :: nam ! Namelist
992 type(geom_type),intent(in) :: geom ! Geometry
993 
994 ! Local variables
995 integer :: il1,i_s
996 real(kind_real) :: renorm(nicas_blk%nc1)
997 real(kind_real) :: lon_c1(nicas_blk%nc1),lat_c1(nicas_blk%nc1)
998 real(kind_real),allocatable :: lon_row(:),lat_row(:),lon_col(:),lat_col(:)
999 logical :: mask_src(nicas_blk%nc1),mask_dst(nicas_blk%nc1)
1000 logical,allocatable :: valid(:)
1001 type(linop_type) :: stmp
1002 
1003 ! Allocation
1004 allocate(nicas_blk%sfull(nicas_blk%nl1))
1005 
1006 do il1=1,nicas_blk%nl1
1007  ! Initialize NICAS block data
1008  write(nicas_blk%sfull(il1)%prefix,'(a,i3.3)') 's_',il1
1009  nicas_blk%sfull(il1)%n_src = nicas_blk%nc1
1010  nicas_blk%sfull(il1)%n_dst = nicas_blk%nc1
1011 
1012  if (nicas_blk%nc2(il1)==nicas_blk%nc1) then
1013  ! No interpolation
1014  nicas_blk%sfull(il1)%n_s = nicas_blk%nc1
1015  call nicas_blk%sfull(il1)%alloc
1016  do i_s=1,nicas_blk%sfull(il1)%n_s
1017  nicas_blk%sfull(il1)%row(i_s) = i_s
1018  nicas_blk%sfull(il1)%col(i_s) = i_s
1019  nicas_blk%sfull(il1)%S(i_s) = 1.0
1020  end do
1021  else
1022  ! Initialization
1023  lon_c1 = geom%lon(nicas_blk%c1_to_c0)
1024  lat_c1 = geom%lat(nicas_blk%c1_to_c0)
1025  mask_src = nicas_blk%mask_c2(:,il1)
1026  mask_dst = .true.
1027 
1028  ! Compute interpolation
1029  call stmp%interp(mpl,rng,nicas_blk%nc1,lon_c1,lat_c1,mask_src,nicas_blk%nc1,lon_c1,lat_c1,mask_dst,nam%nicas_interp)
1030 
1031  ! Allocation
1032  allocate(valid(stmp%n_s))
1033  valid = .true.
1034 
1035  if (nam%mask_check) then
1036  write(mpl%info,'(a10,a,i3,a)',advance='no') '','Sublevel ',il1,': '
1037  call flush(mpl%info)
1038 
1039  ! Allocation
1040  allocate(lon_row(nicas_blk%nc1))
1041  allocate(lat_row(nicas_blk%nc1))
1042  allocate(lon_col(nicas_blk%nc1))
1043  allocate(lat_col(nicas_blk%nc1))
1044 
1045  ! Initialization
1046  lon_row = geom%lon(nicas_blk%c1_to_c0)
1047  lat_row = geom%lat(nicas_blk%c1_to_c0)
1048  lon_col = geom%lon(nicas_blk%c1_to_c0)
1049  lat_col = geom%lat(nicas_blk%c1_to_c0)
1050 
1051  ! Check mask boundaries
1052  call stmp%interp_check_mask(mpl,geom,valid,nicas_blk%l1_to_l0(il1),lon_row=lon_row,lat_row=lat_row, &
1053  & lon_col=lon_col,lat_col=lat_col)
1054 
1055  ! Release memory
1056  deallocate(lon_row)
1057  deallocate(lat_row)
1058  deallocate(lon_col)
1059  deallocate(lat_col)
1060  else
1061  write(mpl%info,'(a10,a,i3)') '','Sublevel ',il1
1062  call flush(mpl%info)
1063  end if
1064 
1065  ! Renormalization
1066  renorm = 0.0
1067  do i_s=1,stmp%n_s
1068  if (valid(i_s)) renorm(stmp%row(i_s)) = renorm(stmp%row(i_s))+stmp%S(i_s)
1069  end do
1070 
1071  ! Copy valid operations
1072  nicas_blk%sfull(il1)%n_s = count(valid)
1073  call nicas_blk%sfull(il1)%alloc
1074  nicas_blk%sfull(il1)%n_s = 0
1075  do i_s=1,stmp%n_s
1076  if (valid(i_s)) then
1077  nicas_blk%sfull(il1)%n_s = nicas_blk%sfull(il1)%n_s+1
1078  nicas_blk%sfull(il1)%row(nicas_blk%sfull(il1)%n_s) = stmp%row(i_s)
1079  nicas_blk%sfull(il1)%col(nicas_blk%sfull(il1)%n_s) = stmp%col(i_s)
1080  nicas_blk%sfull(il1)%S(nicas_blk%sfull(il1)%n_s) = stmp%S(i_s)/renorm(stmp%row(i_s))
1081  end if
1082  end do
1083 
1084  ! Release memory
1085  call stmp%dealloc
1086  deallocate(valid)
1087 
1088  ! Count points that are not interpolated
1089  call nicas_blk%sfull(il1)%interp_missing(mpl,nicas_blk%nc1,lon_c1,lat_c1,mask_dst,nam%nicas_interp)
1090  end if
1091 end do
1092 
1093 end subroutine nicas_blk_compute_interp_s
1094 
1095 !----------------------------------------------------------------------
1096 ! Subroutine: nicas_blk_compute_mpi_ab
1097 ! Purpose: compute NICAS MPI distribution, halos A-B
1098 !----------------------------------------------------------------------
1099 subroutine nicas_blk_compute_mpi_ab(nicas_blk,mpl,geom)
1101 implicit none
1102 
1103 ! Passed variables
1104 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
1105 type(mpl_type),intent(inout) :: mpl ! MPI data
1106 type(geom_type),intent(in) :: geom ! Geometry
1107 
1108 ! Local variables
1109 integer :: il0i,ic0,ic0a,iproc,ic1,jc1,ic1a,ic1b,il0,il1,isa,isb,i_s,i_s_loc,is,js,h_n_s_max,s_n_s_max,h_n_s_max_loc,s_n_s_max_loc
1110 integer,allocatable :: s_to_proc(:),interph_lg(:,:),interps_lg(:,:)
1111 integer,allocatable :: proc_to_nc1a(:),proc_to_nsa(:)
1112 logical,allocatable :: lcheck_c1a(:),lcheck_c1b_h(:),lcheck_c1b(:),lcheck_h(:,:),lcheck_s(:,:)
1113 
1114 ! Allocation
1115 h_n_s_max = 0
1116 do il0i=1,geom%nl0i
1117  h_n_s_max = max(h_n_s_max,nicas_blk%hfull(il0i)%n_s)
1118 end do
1119 s_n_s_max = 0
1120 do il1=1,nicas_blk%nl1
1121  s_n_s_max = max(s_n_s_max,nicas_blk%sfull(il1)%n_s)
1122 end do
1123 allocate(nicas_blk%h(geom%nl0i))
1124 allocate(nicas_blk%s(nicas_blk%nl1))
1125 allocate(lcheck_c1a(nicas_blk%nc1))
1126 allocate(lcheck_c1b_h(nicas_blk%nc1))
1127 allocate(lcheck_c1b(nicas_blk%nc1))
1128 allocate(nicas_blk%lcheck_sa(nicas_blk%ns))
1129 allocate(nicas_blk%lcheck_sb(nicas_blk%ns))
1130 allocate(lcheck_h(h_n_s_max,geom%nl0i))
1131 allocate(lcheck_s(s_n_s_max,nicas_blk%nl1))
1132 allocate(proc_to_nc1a(mpl%nproc))
1133 allocate(proc_to_nsa(mpl%nproc))
1134 allocate(s_to_proc(nicas_blk%ns))
1135 
1136 ! Halo definitions
1137 
1138 ! Halo A
1139 lcheck_c1a = .false.
1140 do ic1=1,nicas_blk%nc1
1141  ic0 = nicas_blk%c1_to_c0(ic1)
1142  if (geom%c0_to_proc(ic0)==mpl%myproc) lcheck_c1a(ic1) = .true.
1143 end do
1144 nicas_blk%lcheck_sa = .false.
1145 do is=1,nicas_blk%ns
1146  ic1 = nicas_blk%s_to_c1(is)
1147  ic0 = nicas_blk%c1_to_c0(ic1)
1148  if (geom%c0_to_proc(ic0)==mpl%myproc) nicas_blk%lcheck_sa(is) = .true.
1149 end do
1150 
1151 ! Halo B
1152 
1153 ! Horizontal interpolation
1154 lcheck_h = .false.
1155 lcheck_c1b_h = .false.
1156 do il0i=1,geom%nl0i
1157  do i_s=1,nicas_blk%hfull(il0i)%n_s
1158  ic0 = nicas_blk%hfull(il0i)%row(i_s)
1159  iproc = geom%c0_to_proc(ic0)
1160  if (iproc==mpl%myproc) then
1161  jc1 = nicas_blk%hfull(il0i)%col(i_s)
1162  lcheck_h(i_s,il0i) = .true.
1163  lcheck_c1b_h(jc1) = .true.
1164  end if
1165  end do
1166 end do
1167 
1168 ! Subsampling horizontal interpolation
1169 nicas_blk%lcheck_sb = .false.
1170 lcheck_s = .false.
1171 lcheck_c1b = lcheck_c1b_h
1172 do il1=1,nicas_blk%nl1
1173  do i_s=1,nicas_blk%sfull(il1)%n_s
1174  ic1 = nicas_blk%sfull(il1)%row(i_s)
1175  if (lcheck_c1b_h(ic1)) then
1176  jc1 = nicas_blk%sfull(il1)%col(i_s)
1177  js = nicas_blk%c1l1_to_s(jc1,il1)
1178  lcheck_c1b(jc1) = .true.
1179  nicas_blk%lcheck_sb(js) = .true.
1180  lcheck_s(i_s,il1) = .true.
1181  end if
1182  end do
1183 end do
1184 
1185 ! Check halos consistency
1186 do is=1,nicas_blk%ns
1187  if (nicas_blk%lcheck_sa(is).and.(.not.nicas_blk%lcheck_sb(is))) call mpl%abort('point in halo A but not in halo B')
1188 end do
1189 
1190 ! Sizes
1191 nicas_blk%nc1a = count(lcheck_c1a)
1192 call mpl%f_comm%allgather(nicas_blk%nc1a,proc_to_nc1a)
1193 nicas_blk%nsa = count(nicas_blk%lcheck_sa)
1194 call mpl%f_comm%allgather(nicas_blk%nsa,proc_to_nsa)
1195 do il0i=1,geom%nl0i
1196  nicas_blk%h(il0i)%n_s = count(lcheck_h(:,il0i))
1197 end do
1198 nicas_blk%nc1b = count(lcheck_c1b)
1199 nicas_blk%nsb = count(nicas_blk%lcheck_sb)
1200 do il1=1,nicas_blk%nl1
1201  nicas_blk%s(il1)%n_s = count(lcheck_s(:,il1))
1202 end do
1203 
1204 ! Global <-> local conversions for fields
1205 
1206 ! Halo A
1207 allocate(nicas_blk%c1a_to_c1(nicas_blk%nc1a))
1208 allocate(nicas_blk%c1_to_c1a(nicas_blk%nc1))
1209 ic1a = 0
1210 do ic1=1,nicas_blk%nc1
1211  if (lcheck_c1a(ic1)) then
1212  ic1a = ic1a+1
1213  nicas_blk%c1a_to_c1(ic1a) = ic1
1214  end if
1215 end do
1216 call mpl%glb_to_loc_index(nicas_blk%nc1a,nicas_blk%c1a_to_c1,nicas_blk%nc1,nicas_blk%c1_to_c1a)
1217 
1218 allocate(nicas_blk%sa_to_s(nicas_blk%nsa))
1219 allocate(nicas_blk%s_to_sa(nicas_blk%ns))
1220 isa = 0
1221 do is=1,nicas_blk%ns
1222  if (nicas_blk%lcheck_sa(is)) then
1223  isa = isa+1
1224  nicas_blk%sa_to_s(isa) = is
1225  end if
1226 end do
1227 call mpl%glb_to_loc_index(nicas_blk%nsa,nicas_blk%sa_to_s,nicas_blk%ns,nicas_blk%s_to_sa)
1228 
1229 ! Halo B
1230 allocate(nicas_blk%c1b_to_c1(nicas_blk%nc1b))
1231 allocate(nicas_blk%c1_to_c1b(nicas_blk%nc1))
1232 call msi(nicas_blk%c1_to_c1b)
1233 ic1b = 0
1234 do ic1=1,nicas_blk%nc1
1235  if (lcheck_c1b(ic1)) then
1236  ic1b = ic1b+1
1237  nicas_blk%c1b_to_c1(ic1b) = ic1
1238  nicas_blk%c1_to_c1b(ic1) = ic1b
1239  end if
1240 end do
1241 
1242 allocate(nicas_blk%sb_to_s(nicas_blk%nsb))
1243 allocate(nicas_blk%s_to_sb(nicas_blk%ns))
1244 call msi(nicas_blk%s_to_sb)
1245 isb = 0
1246 do is=1,nicas_blk%ns
1247  if (nicas_blk%lcheck_sb(is)) then
1248  isb = isb+1
1249  nicas_blk%sb_to_s(isb) = is
1250  nicas_blk%s_to_sb(is) = isb
1251  end if
1252 end do
1253 
1254 ! Inter-halo conversions
1255 allocate(nicas_blk%sa_to_sb(nicas_blk%nsa))
1256 do isa=1,nicas_blk%nsa
1257  is = nicas_blk%sa_to_s(isa)
1258  isb = nicas_blk%s_to_sb(is)
1259  nicas_blk%sa_to_sb(isa) = isb
1260 end do
1261 
1262 ! Global <-> local conversions for data
1263 h_n_s_max_loc = 0
1264 do il0i=1,geom%nl0i
1265  h_n_s_max_loc = max(h_n_s_max_loc,nicas_blk%h(il0i)%n_s)
1266 end do
1267 allocate(interph_lg(h_n_s_max_loc,geom%nl0i))
1268 do il0i=1,geom%nl0i
1269  i_s_loc = 0
1270  do i_s=1,nicas_blk%hfull(il0i)%n_s
1271  if (lcheck_h(i_s,il0i)) then
1272  i_s_loc = i_s_loc+1
1273  interph_lg(i_s_loc,il0i) = i_s
1274  end if
1275  end do
1276 end do
1277 s_n_s_max_loc = 0
1278 do il1=1,nicas_blk%nl1
1279  s_n_s_max_loc = max(s_n_s_max_loc,nicas_blk%s(il1)%n_s)
1280 end do
1281 allocate(interps_lg(s_n_s_max_loc,nicas_blk%nl1))
1282 do il1=1,nicas_blk%nl1
1283  i_s_loc = 0
1284  do i_s=1,nicas_blk%sfull(il1)%n_s
1285  if (lcheck_s(i_s,il1)) then
1286  i_s_loc = i_s_loc+1
1287  interps_lg(i_s_loc,il1) = i_s
1288  end if
1289  end do
1290 end do
1291 
1292 ! Local data
1293 
1294 ! Horizontal interpolation
1295 do il0i=1,geom%nl0i
1296  write(nicas_blk%h(il0i)%prefix,'(a,i3.3)') 'h_',il0i
1297  nicas_blk%h(il0i)%n_src = nicas_blk%nc1b
1298  nicas_blk%h(il0i)%n_dst = geom%nc0a
1299  call nicas_blk%h(il0i)%alloc
1300  do i_s_loc=1,nicas_blk%h(il0i)%n_s
1301  i_s = interph_lg(i_s_loc,il0i)
1302  nicas_blk%h(il0i)%row(i_s_loc) = geom%c0_to_c0a(nicas_blk%hfull(il0i)%row(i_s))
1303  nicas_blk%h(il0i)%col(i_s_loc) = nicas_blk%c1_to_c1b(nicas_blk%hfull(il0i)%col(i_s))
1304  nicas_blk%h(il0i)%S(i_s_loc) = nicas_blk%hfull(il0i)%S(i_s)
1305  end do
1306  call nicas_blk%h(il0i)%reorder(mpl)
1307 end do
1308 
1309 ! Vertical interpolation
1310 nicas_blk%v%prefix = 'v'
1311 nicas_blk%v%n_src = nicas_blk%vfull%n_src
1312 nicas_blk%v%n_dst = nicas_blk%vfull%n_dst
1313 nicas_blk%v%n_s = nicas_blk%vfull%n_s
1314 call nicas_blk%v%alloc(nicas_blk%nc1b)
1315 do i_s=1,nicas_blk%v%n_s
1316  nicas_blk%v%row(i_s) = nicas_blk%vfull%row(i_s)
1317  nicas_blk%v%col(i_s) = nicas_blk%vfull%col(i_s)
1318  do ic1b=1,nicas_blk%nc1b
1319  ic1 = nicas_blk%c1b_to_c1(ic1b)
1320  nicas_blk%v%Svec(i_s,ic1b) = nicas_blk%vfull%Svec(i_s,ic1)
1321  end do
1322 end do
1323 call nicas_blk%v%reorder(mpl)
1324 
1325 ! Subsampling horizontal interpolation
1326 do il1=1,nicas_blk%nl1
1327  write(nicas_blk%s(il1)%prefix,'(a,i3.3)') 's_',il1
1328  nicas_blk%s(il1)%n_src = nicas_blk%nc1b
1329  nicas_blk%s(il1)%n_dst = nicas_blk%nc1b
1330  call nicas_blk%s(il1)%alloc
1331  do i_s_loc=1,nicas_blk%s(il1)%n_s
1332  i_s = interps_lg(i_s_loc,il1)
1333  nicas_blk%s(il1)%row(i_s_loc) = nicas_blk%c1_to_c1b(nicas_blk%sfull(il1)%row(i_s))
1334  nicas_blk%s(il1)%col(i_s_loc) = nicas_blk%c1_to_c1b(nicas_blk%sfull(il1)%col(i_s))
1335  nicas_blk%s(il1)%S(i_s_loc) = nicas_blk%sfull(il1)%S(i_s)
1336  end do
1337  call nicas_blk%s(il1)%reorder(mpl)
1338 end do
1339 
1340 ! Conversions
1341 allocate(nicas_blk%c1a_to_c0a(nicas_blk%nc1a))
1342 allocate(nicas_blk%sa_to_c0a(nicas_blk%nsa))
1343 allocate(nicas_blk%sa_to_l0(nicas_blk%nsa))
1344 allocate(nicas_blk%sb_to_c1b(nicas_blk%nsb))
1345 allocate(nicas_blk%sb_to_l1(nicas_blk%nsb))
1346 allocate(nicas_blk%c1bl1_to_sb(nicas_blk%nc1b,nicas_blk%nl1))
1347 call msi(nicas_blk%c1bl1_to_sb)
1348 do ic1a=1,nicas_blk%nc1a
1349  ic1 = nicas_blk%c1a_to_c1(ic1a)
1350  ic0 = nicas_blk%c1_to_c0(ic1)
1351  ic0a = geom%c0_to_c0a(ic0)
1352  nicas_blk%c1a_to_c0a(ic1a) = ic0a
1353 end do
1354 do isa=1,nicas_blk%nsa
1355  is = nicas_blk%sa_to_s(isa)
1356  ic1 = nicas_blk%s_to_c1(is)
1357  ic0 = nicas_blk%c1_to_c0(ic1)
1358  ic0a = geom%c0_to_c0a(ic0)
1359  il1 = nicas_blk%s_to_l1(is)
1360  il0 = nicas_blk%l1_to_l0(il1)
1361  nicas_blk%sa_to_c0a(isa) = ic0a
1362  nicas_blk%sa_to_l0(isa) = il0
1363 end do
1364 do isb=1,nicas_blk%nsb
1365  is = nicas_blk%sb_to_s(isb)
1366  il1 = nicas_blk%s_to_l1(is)
1367  ic1 = nicas_blk%s_to_c1(is)
1368  ic1b = nicas_blk%c1_to_c1b(ic1)
1369  nicas_blk%sb_to_c1b(isb) = ic1b
1370  nicas_blk%sb_to_l1(isb) = il1
1371  nicas_blk%c1bl1_to_sb(ic1b,il1) = isb
1372 end do
1373 
1374 ! Setup communications
1375 s_to_proc = geom%c0_to_proc(nicas_blk%c1_to_c0(nicas_blk%s_to_c1))
1376 call nicas_blk%com_AB%setup(mpl,'com_AB',nicas_blk%ns,nicas_blk%nsa,nicas_blk%nsb,nicas_blk%sb_to_s,nicas_blk%sa_to_sb, &
1377  & s_to_proc,nicas_blk%s_to_sa)
1378 
1379 end subroutine nicas_blk_compute_mpi_ab
1380 
1381 !----------------------------------------------------------------------
1382 ! Subroutine: nicas_blk_compute_convol
1383 ! Purpose: compute convolution
1384 !----------------------------------------------------------------------
1385 subroutine nicas_blk_compute_convol(nicas_blk,mpl,rng,nam,geom,cmat_blk)
1387 implicit none
1388 
1389 ! Passed variables
1390 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
1391 type(mpl_type),intent(inout) :: mpl ! MPI data
1392 type(rng_type),intent(inout) :: rng ! Random number generator
1393 type(nam_type),intent(in) :: nam ! Namelist
1394 type(geom_type),intent(in) :: geom ! Geometry
1395 type(cmat_blk_type),intent(in) :: cmat_blk ! C matrix data block
1396 
1397 ! Local variables
1398 integer :: n_s_max,ithread,is,ic1,jc1,il1,il0,j,js,isb,ic1b,ic0,ic0a,ic1a,i_s,jc,kc,ks,jbd,jc0,jl0,jl1,ic1bb,isbb
1399 integer :: c_n_s(mpl%nthread)
1400 integer,allocatable :: nn(:),nn_index(:),inec(:),c_ind(:,:)
1401 real(kind_real) :: distvsq,rvsq
1402 real(kind_real),allocatable :: lon_c1(:),lat_c1(:),nn_dist(:)
1403 real(kind_real),allocatable :: rh_c1a(:,:),rv_c1a(:,:),rv_rfac_c1a(:,:),rv_rfac_c1(:,:),rv_coef_c1a(:,:),rv_coef_c1(:,:)
1404 real(kind_real),allocatable :: H11_c1a(:,:),H22_c1a(:,:),H33_c1a(:,:),H12_c1a(:,:),Hcoef_c1a(:,:),Hcoef_c1(:,:)
1405 real(kind_real),allocatable :: distnormv(:,:),rfac(:,:),coef(:,:),Hcoef(:,:)
1406 real(kind_real),allocatable :: c_S(:,:),c_S_conv(:)
1407 logical :: add_op
1408 logical,allocatable :: lcheck_c1bb(:)
1409 type(linop_type) :: ctmp,c(mpl%nthread)
1410 
1411 ! Associate
1412 associate(ib=>nicas_blk%ib)
1413 
1414 ! Set double-fit parameter
1415 nicas_blk%double_fit = cmat_blk%double_fit
1416 nicas_blk%anisotropic = cmat_blk%anisotropic
1417 
1418 ! Allocation
1419 allocate(lon_c1(nicas_blk%nc1))
1420 allocate(lat_c1(nicas_blk%nc1))
1421 allocate(nicas_blk%mask_c1(nicas_blk%nc1,nicas_blk%nl1))
1422 allocate(lcheck_c1bb(nicas_blk%nc1))
1423 
1424 ! Initialization
1425 lon_c1 = geom%lon(nicas_blk%c1_to_c0)
1426 lat_c1 = geom%lat(nicas_blk%c1_to_c0)
1427 nicas_blk%mask_c1 = .false.
1428 do is=1,nicas_blk%ns
1429  ic1 = nicas_blk%s_to_c1(is)
1430  il1 = nicas_blk%s_to_l1(is)
1431  nicas_blk%mask_c1(ic1,il1) = .true.
1432 end do
1433 
1434 ! Compute KD-tree
1435 write(mpl%info,'(a10,a)') '','Compute KD-tree'
1436 call flush(mpl%info)
1437 call nicas_blk%kdtree%create(mpl,nicas_blk%nc1,lon_c1,lat_c1)
1438 
1439 ! Find largest possible radius
1440 call mpl%f_comm%allreduce(maxval(cmat_blk%rh),nicas_blk%rhmax,fckit_mpi_max())
1441 if (nicas_blk%double_fit) then
1442  nicas_blk%rhmax = nicas_blk%rhmax*sqrt_r_dble
1443 else
1444  nicas_blk%rhmax = nicas_blk%rhmax*sqrt_r
1445 end if
1446 
1447 if (nam%lsqrt) then
1448  ! Copy
1449  nicas_blk%nc1bb = nicas_blk%nc1b
1450 else
1451  write(mpl%info,'(a10,a)',advance='no') '','Define extended halo: '
1452  call flush(mpl%info)
1453 
1454  ! Allocation
1455  allocate(nn(nicas_blk%nc1b))
1456 
1457  do ic1b=1,nicas_blk%nc1b
1458  ! Indices
1459  ic1 = nicas_blk%c1b_to_c1(ic1b)
1460  ic0 = nicas_blk%c1_to_c0(ic1)
1461 
1462  ! Count nearest neighbors
1463  call nicas_blk%kdtree%count_nearest_neighbors(geom%lon(ic0),geom%lat(ic0),nicas_blk%rhmax,nn(ic1b))
1464  end do
1465 
1466  ! Initialization
1467  call mpl%prog_init(nicas_blk%nc1b)
1468  lcheck_c1bb = .false.
1469 
1470  do ic1b=1,nicas_blk%nc1b
1471  ! Indices
1472  ic1 = nicas_blk%c1b_to_c1(ic1b)
1473  ic0 = nicas_blk%c1_to_c0(ic1)
1474 
1475  ! Allocation
1476  allocate(nn_index(nn(ic1b)))
1477  allocate(nn_dist(nn(ic1b)))
1478 
1479  ! Find nearest neighbors
1480  call nicas_blk%kdtree%find_nearest_neighbors(geom%lon(ic0),geom%lat(ic0),nn(ic1b),nn_index,nn_dist)
1481 
1482  ! Fill mask
1483  do j=1,nn(ic1b)
1484  jc1 = nn_index(j)
1485  lcheck_c1bb(jc1) = .true.
1486  end do
1487 
1488  ! Release memory
1489  deallocate(nn_index)
1490  deallocate(nn_dist)
1491 
1492  ! Update
1493  call mpl%prog_print(ic1b)
1494  end do
1495  write(mpl%info,'(a)') '100%'
1496  call flush(mpl%info)
1497 
1498  ! Halo size
1499  nicas_blk%nc1bb = count(lcheck_c1bb)
1500  write(mpl%info,'(a10,a,i6,a,i6)') '','Halo sizes nc1b / nc1bb: ',nicas_blk%nc1b,' / ',nicas_blk%nc1bb
1501 end if
1502 
1503 ! Allocation
1504 allocate(nicas_blk%c1bb_to_c1(nicas_blk%nc1bb))
1505 allocate(nicas_blk%c1_to_c1bb(nicas_blk%nc1))
1506 
1507 if (nam%lsqrt) then
1508  ! Copy
1509  nicas_blk%c1bb_to_c1 = nicas_blk%c1b_to_c1
1510  nicas_blk%c1_to_c1bb = nicas_blk%c1_to_c1b
1511  nicas_blk%nsbb = nicas_blk%nsb
1512 else
1513  ! Global <-> local conversions for fields
1514  call msi(nicas_blk%c1_to_c1bb)
1515  ic1bb = 0
1516  do ic1=1,nicas_blk%nc1
1517  if (lcheck_c1bb(ic1)) then
1518  ic1bb = ic1bb+1
1519  nicas_blk%c1bb_to_c1(ic1bb) = ic1
1520  nicas_blk%c1_to_c1bb(ic1) = ic1bb
1521  end if
1522  end do
1523 
1524  ! Count points in extended halo
1525  nicas_blk%nsbb = 0
1526  do is=1,nicas_blk%ns
1527  ic1 = nicas_blk%s_to_c1(is)
1528  if (lcheck_c1bb(ic1)) nicas_blk%nsbb = nicas_blk%nsbb+1
1529  end do
1530  write(mpl%info,'(a10,a,i6,a,i6)') '','Halo sizes nsb / nsbb: ',nicas_blk%nsb,' / ',nicas_blk%nsbb
1531 end if
1532 
1533 ! Allocation
1534 allocate(nicas_blk%sbb_to_s(nicas_blk%nsbb))
1535 
1536 if (nam%lsqrt) then
1537  ! Copy
1538  nicas_blk%sbb_to_s = nicas_blk%sb_to_s
1539 else
1540  ! Global <-> local conversions for fields
1541  isbb = 0
1542  do is=1,nicas_blk%ns
1543  ic1 = nicas_blk%s_to_c1(is)
1544  if (lcheck_c1bb(ic1)) then
1545  isbb = isbb+1
1546  nicas_blk%sbb_to_s(isbb) = is
1547  end if
1548  end do
1549 end if
1550 
1551 ! Compute horizontal and vertical parameters
1552 write(mpl%info,'(a10,a)') '','Compute horizontal and vertical parameters'
1553 call flush(mpl%info)
1554 
1555 ! Allocation
1556 allocate(rh_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1557 allocate(rv_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1558 allocate(nicas_blk%rh_c1(nicas_blk%nc1,nicas_blk%nl1))
1559 allocate(nicas_blk%rv_c1(nicas_blk%nc1,nicas_blk%nl1))
1560 if (nicas_blk%double_fit) then
1561  allocate(rv_rfac_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1562  allocate(rv_coef_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1563  allocate(rv_rfac_c1(nicas_blk%nc1,nicas_blk%nl1))
1564  allocate(rv_coef_c1(nicas_blk%nc1,nicas_blk%nl1))
1565  allocate(nicas_blk%rfac(nicas_blk%nsbb))
1566  allocate(nicas_blk%coef(nicas_blk%nsbb))
1567  allocate(nicas_blk%distnormv(nicas_blk%nsbb))
1568 end if
1569 if (nicas_blk%anisotropic) then
1570  allocate(h11_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1571  allocate(h22_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1572  allocate(h33_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1573  allocate(h12_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1574  allocate(hcoef_c1a(nicas_blk%nc1a,nicas_blk%nl1))
1575  allocate(hcoef_c1(nicas_blk%nc1,nicas_blk%nl1))
1576  allocate(nicas_blk%H11_c1(nicas_blk%nc1,nicas_blk%nl1))
1577  allocate(nicas_blk%H22_c1(nicas_blk%nc1,nicas_blk%nl1))
1578  allocate(nicas_blk%H33_c1(nicas_blk%nc1,nicas_blk%nl1))
1579  allocate(nicas_blk%H12_c1(nicas_blk%nc1,nicas_blk%nl1))
1580  allocate(nicas_blk%Hcoef(nicas_blk%nsbb))
1581 end if
1582 
1583 ! Copy and rescale
1584 write(mpl%info,'(a13,a)') '','Copy and rescale'
1585 call flush(mpl%info)
1586 do il1=1,nicas_blk%nl1
1587  do ic1a=1,nicas_blk%nc1a
1588  ! Copy
1589  ic0a = nicas_blk%c1a_to_c0a(ic1a)
1590  il0 = nicas_blk%l1_to_l0(il1)
1591  rh_c1a(ic1a,il1) = cmat_blk%rh(ic0a,il0)
1592  rv_c1a(ic1a,il1) = cmat_blk%rv(ic0a,il0)
1593  if (nicas_blk%double_fit) then
1594  rv_rfac_c1a(ic1a,il1) = cmat_blk%rv_rfac(ic0a,il0)
1595  rv_coef_c1a(ic1a,il1) = cmat_blk%rv_coef(ic0a,il0)
1596  end if
1597  if (nicas_blk%anisotropic) then
1598  h11_c1a(ic1a,il1) = cmat_blk%H11(ic0a,il0)
1599  h22_c1a(ic1a,il1) = cmat_blk%H22(ic0a,il0)
1600  h33_c1a(ic1a,il1) = cmat_blk%H33(ic0a,il0)
1601  h12_c1a(ic1a,il1) = cmat_blk%H12(ic0a,il0)
1602  hcoef_c1a(ic1a,il1) = cmat_blk%Hcoef(ic0a,il0)
1603  end if
1604 
1605  ! Square-root rescaling
1606  rh_c1a(ic1a,il1) = rh_c1a(ic1a,il1)*sqrt_r
1607  if (nicas_blk%double_fit) then
1608  rv_c1a(ic1a,il1) = rv_c1a(ic1a,il1)*sqrt_r_dble
1609  rv_rfac_c1a(ic1a,il1) = rv_rfac_c1a(ic1a,il1)*sqrt_rfac
1610  rv_coef_c1a(ic1a,il1) = rv_coef_c1a(ic1a,il1)*sqrt_coef
1611  else
1612  rv_c1a(ic1a,il1) = rv_c1a(ic1a,il1)*sqrt_r
1613  end if
1614  if (nicas_blk%anisotropic) then
1615  h11_c1a(ic1a,il1) = h11_c1a(ic1a,il1)/sqrt_r**2
1616  h22_c1a(ic1a,il1) = h22_c1a(ic1a,il1)/sqrt_r**2
1617  h33_c1a(ic1a,il1) = h33_c1a(ic1a,il1)/sqrt_r**2
1618  h12_c1a(ic1a,il1) = h12_c1a(ic1a,il1)/sqrt_r**2
1619  end if
1620  end do
1621 end do
1622 
1623 ! Communication
1624 write(mpl%info,'(a13,a)') '','Communication'
1625 call flush(mpl%info)
1626 call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,rh_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1627  & nicas_blk%rh_c1)
1628 call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,rv_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1629  & nicas_blk%rv_c1)
1630 if (nicas_blk%double_fit) then
1631  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,rv_rfac_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1632  & rv_rfac_c1)
1633  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,rv_coef_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1634  & rv_coef_c1)
1635 end if
1636 if (nicas_blk%anisotropic) then
1637  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,h11_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1638  & nicas_blk%H11_c1)
1639  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,h22_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1640  & nicas_blk%H22_c1)
1641  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,h33_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1642  & nicas_blk%H33_c1)
1643  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,h12_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1644  & nicas_blk%H12_c1)
1645  call mpl%loc_to_glb(nicas_blk%nl1,nicas_blk%nc1a,hcoef_c1a,nicas_blk%nc1,nicas_blk%c1_to_proc,nicas_blk%c1_to_c1a,.true., &
1646  & hcoef_c1)
1647 end if
1648 
1649 ! Release memory
1650 deallocate(rh_c1a)
1651 deallocate(rv_c1a)
1652 if (nicas_blk%double_fit) then
1653  deallocate(rv_rfac_c1a)
1654  deallocate(rv_coef_c1a)
1655 end if
1656 if (nicas_blk%anisotropic) then
1657  deallocate(h11_c1a)
1658  deallocate(h22_c1a)
1659  deallocate(h33_c1a)
1660  deallocate(h12_c1a)
1661  deallocate(hcoef_c1a)
1662 end if
1663 
1664 ! Allocation
1665 allocate(nicas_blk%distnorm(nicas_blk%nsbb))
1666 
1667 ! Compute distances
1668 if (nam%network) then
1669  call nicas_blk%compute_convol_network(mpl,rng,nam,geom)
1670 else
1671  call nicas_blk%compute_convol_distance(mpl,geom)
1672 end if
1673 
1674 ! Release memory
1675 deallocate(nicas_blk%rh_c1)
1676 deallocate(nicas_blk%rv_c1)
1677 if (nicas_blk%anisotropic) then
1678  deallocate(nicas_blk%H11_c1)
1679  deallocate(nicas_blk%H22_c1)
1680  deallocate(nicas_blk%H33_c1)
1681  deallocate(nicas_blk%H12_c1)
1682 end if
1683 
1684 ! Compute ball data
1685 write(mpl%info,'(a13,a)') '','Compute ball data'
1686 !$omp parallel do schedule(static) private(isbb,is,ic1,il1,ic0,il0,jbd,jc1,jl1,jc0,jl0,distvsq,rvsq), &
1687 !$omp& firstprivate(distnormv,rfac,coef,Hcoef)
1688 do isbb=1,nicas_blk%nsbb
1689  ! Indices
1690  is = nicas_blk%sbb_to_s(isbb)
1691  ic1 = nicas_blk%s_to_c1(is)
1692  il1 = nicas_blk%s_to_l1(is)
1693  ic0 = nicas_blk%c1_to_c0(ic1)
1694  il0 = nicas_blk%l1_to_l0(il1)
1695 
1696  ! Allocation
1697  if (nicas_blk%double_fit) then
1698  allocate(distnormv(nicas_blk%nc1,nicas_blk%nl1))
1699  allocate(rfac(nicas_blk%nc1,nicas_blk%nl1))
1700  allocate(coef(nicas_blk%nc1,nicas_blk%nl1))
1701  end if
1702  if (nicas_blk%anisotropic) allocate(hcoef(nicas_blk%nc1,nicas_blk%nl1))
1703 
1704  ! Initialization
1705  if (nicas_blk%double_fit) then
1706  call msr(distnormv)
1707  call msr(rfac)
1708  call msr(coef)
1709  end if
1710  if (nicas_blk%anisotropic) call msr(hcoef)
1711 
1712  do jbd=1,nicas_blk%distnorm(isbb)%nbd
1713  ! Indices
1714  jc1 = nicas_blk%distnorm(isbb)%bd_to_c1(jbd)
1715  jl1 = nicas_blk%distnorm(isbb)%bd_to_l1(jbd)
1716  jc0 = nicas_blk%c1_to_c0(jc1)
1717  jl0 = nicas_blk%l1_to_l0(jl1)
1718 
1719  if (nicas_blk%double_fit) then
1720  ! Vertical distance
1721  distvsq = (geom%vunit(ic0,il0)-geom%vunit(jc0,jl0))**2
1722  rvsq = 0.5*(nicas_blk%rv_c1(ic1,il1)**2+nicas_blk%rv_c1(jc1,jl1)**2)
1723  if (rvsq>0.0) then
1724  distnormv(jc1,jl1) = sqrt(distvsq/rvsq)
1725  elseif (distvsq>0.0) then
1726  distnormv(jc1,jl1) = 0.5*huge(0.0)
1727  end if
1728  rfac(ic1,il1) = sqrt(rv_rfac_c1(ic1,il1)*rv_rfac_c1(jc1,jl1))
1729  coef(ic1,il1) = sqrt(rv_coef_c1(ic1,il1)*rv_coef_c1(jc1,jl1))
1730  end if
1731  if (nicas_blk%anisotropic) hcoef(ic1,il1) = sqrt(hcoef_c1(ic1,il1)*hcoef_c1(jc1,jl1))
1732  end do
1733 
1734  ! Pack data
1735  if (nicas_blk%double_fit) then
1736  call nicas_blk%distnormv(isbb)%pack(nicas_blk%nc1,nicas_blk%nl1,distnormv)
1737  call nicas_blk%rfac(isbb)%pack(nicas_blk%nc1,nicas_blk%nl1,rfac)
1738  call nicas_blk%coef(isbb)%pack(nicas_blk%nc1,nicas_blk%nl1,coef)
1739  end if
1740  if (nicas_blk%anisotropic) call nicas_blk%Hcoef(isbb)%pack(nicas_blk%nc1,nicas_blk%nl1,hcoef)
1741 
1742  ! Release memory
1743  if (nicas_blk%double_fit) then
1744  deallocate(distnormv)
1745  deallocate(rfac)
1746  deallocate(coef)
1747  end if
1748  if (nicas_blk%anisotropic) deallocate(hcoef)
1749 end do
1750 !$omp end parallel do
1751 
1752 ! Release memory
1753 if (nicas_blk%double_fit) then
1754  deallocate(rv_rfac_c1)
1755  deallocate(rv_coef_c1)
1756 end if
1757 if (nicas_blk%anisotropic) deallocate(hcoef_c1)
1758 
1759 ! Compute weights
1760 call nicas_blk%compute_convol_weights(mpl,nam,geom,ctmp)
1761 
1762 ! Release memory
1763 do isbb=1,nicas_blk%nsbb
1764  call nicas_blk%distnorm(isbb)%dealloc
1765  if (nicas_blk%double_fit) then
1766  call nicas_blk%distnormv(isbb)%dealloc
1767  call nicas_blk%rfac(isbb)%dealloc
1768  call nicas_blk%coef(isbb)%dealloc
1769  end if
1770  if (nicas_blk%anisotropic) call nicas_blk%Hcoef(isbb)%dealloc
1771 end do
1772 deallocate(nicas_blk%distnorm)
1773 if (nicas_blk%double_fit) then
1774  deallocate(nicas_blk%distnormv)
1775  deallocate(nicas_blk%rfac)
1776  deallocate(nicas_blk%coef)
1777 end if
1778 if (nicas_blk%anisotropic) deallocate(nicas_blk%Hcoef)
1779 
1780 if (nam%lsqrt) then
1781  ! Copy
1782  nicas_blk%c = ctmp%copy()
1783 else
1784  ! Compute convolution inverse mapping
1785  allocate(inec(nicas_blk%ns))
1786  inec = 0
1787  do i_s=1,ctmp%n_s
1788  is = ctmp%col(i_s)
1789  inec(is) = inec(is)+1
1790  end do
1791  allocate(c_ind(maxval(inec),nicas_blk%ns))
1792  allocate(c_s(maxval(inec),nicas_blk%ns))
1793  call msi(c_ind)
1794  call msr(c_s)
1795  inec = 0
1796  do i_s=1,ctmp%n_s
1797  is = ctmp%col(i_s)
1798  js = ctmp%row(i_s)
1799  inec(is) = inec(is)+1
1800  c_ind(inec(is),is) = js
1801  c_s(inec(is),is) = ctmp%S(i_s)
1802  end do
1803 
1804  ! Initialization
1805  write(mpl%info,'(a10,a)',advance='no') '','Second pass: '
1806  call flush(mpl%info)
1807  call mpl%prog_init(nicas_blk%nsb)
1808  n_s_max = 100*nint(real(geom%nc0*geom%nl0)/real(mpl%nthread*mpl%nproc))
1809  c_n_s = 0
1810  do ithread=1,mpl%nthread
1811  c(ithread)%n_s = n_s_max
1812  call c(ithread)%alloc
1813  call msi(c(ithread)%row)
1814  call msi(c(ithread)%col)
1815  call msr(c(ithread)%S)
1816  end do
1817 
1818  ! Apply convolution
1819  !$omp parallel do schedule(static) private(isb,is,ithread,jc,js,kc,ks,add_op) firstprivate(c_S_conv)
1820  do isb=1,nicas_blk%nsb
1821  ! Indices
1822  is = nicas_blk%sb_to_s(isb)
1823  ithread = 1
1824 !$ ithread = omp_get_thread_num()+1
1825 
1826  ! Allocation
1827  allocate(c_s_conv(nicas_blk%ns))
1828 
1829  ! Initialization
1830  c_s_conv = 0.0
1831 
1832  ! Loop twice over points
1833  do jc=1,inec(is)
1834  js = c_ind(jc,is)
1835  do kc=1,inec(js)
1836  ks = c_ind(kc,js)
1837  c_s_conv(ks) = c_s_conv(ks)+c_s(jc,is)*c_s(kc,js)
1838  end do
1839  end do
1840 
1841  ! Store coefficient for convolution
1842  do js=1,nicas_blk%ns
1843  add_op = .false.
1844  if (nam%mpicom==1) then
1845  add_op = (nicas_blk%lcheck_sb(js).and.(is<=js)).or.(.not.nicas_blk%lcheck_sb(js))
1846  elseif (nam%mpicom==2) then
1847  add_op = nicas_blk%lcheck_sa(is).and.((nicas_blk%lcheck_sa(js).and.(is<=js)) &
1848  & .or.(.not.nicas_blk%lcheck_sa(js)))
1849  end if
1850  if (add_op) call c(ithread)%add_op(c_n_s(ithread),is,js,c_s_conv(js))
1851  end do
1852 
1853  ! Release memory
1854  deallocate(c_s_conv)
1855 
1856  ! Update
1857  call mpl%prog_print(isb)
1858  end do
1859  !$omp end parallel do
1860  write(mpl%info,'(a)') '100%'
1861  call flush(mpl%info)
1862 
1863  ! Gather data from threads
1864  call nicas_blk%c%gather(mpl,c_n_s,c)
1865 
1866  ! Release memory
1867  do ithread=1,mpl%nthread
1868  call c(ithread)%dealloc
1869  end do
1870 end if
1871 
1872 ! Set prefix
1873 nicas_blk%c%prefix = 'c'
1874 nicas_blk%c_nor%prefix = 'c_nor'
1875 
1876 ! End associate
1877 end associate
1878 
1879 end subroutine nicas_blk_compute_convol
1880 
1881 !----------------------------------------------------------------------
1882 ! Subroutine: nicas_blk_compute_convol_network
1883 ! Purpose: compute convolution with a network approach
1884 !----------------------------------------------------------------------
1885 subroutine nicas_blk_compute_convol_network(nicas_blk,mpl,rng,nam,geom)
1887 implicit none
1888 
1889 ! Passed variables
1890 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
1891 type(mpl_type),intent(inout) :: mpl ! MPI data
1892 type(rng_type),intent(inout) :: rng ! Random number generator
1893 type(nam_type),intent(in) :: nam ! Namelist
1894 type(geom_type),intent(in) :: geom ! Geometry
1895 
1896 ! Local variables
1897 integer :: net_nnbmax,is,ic0,ic1,il0,jl1,np,np_new,i,j,k,ip,kc1,jc1,il1,dkl1,kl1,jp,isbb,djl1,inr,jc0,jl0
1898 integer,allocatable :: net_nnb(:),net_inb(:,:),plist(:,:),plist_new(:,:)
1899 real(kind_real) :: distnorm_network,disttest
1900 real(kind_real) :: dnb,dx,dy,dz,disthsq,distvsq,rhsq,rvsq,H11,H22,H33,H12
1901 real(kind_real),allocatable :: distnorm(:,:),net_dnb(:,:,:,:)
1902 logical :: init,valid_arc,add_to_front
1903 type(mesh_type) :: mesh
1904 
1905 ! Allocation
1906 allocate(net_nnb(nicas_blk%nc1))
1907 
1908 ! Create mesh
1909 write(mpl%info,'(a10,a)') '','Create mesh'
1910 call flush(mpl%info)
1911 call mesh%create(mpl,rng,nicas_blk%nc1,geom%lon(nicas_blk%c1_to_c0),geom%lat(nicas_blk%c1_to_c0))
1912 
1913 ! Count neighbors
1914 write(mpl%info,'(a10,a)') '','Count neighbors'
1915 call flush(mpl%info)
1916 net_nnb = 0
1917 do ic1=1,nicas_blk%nc1
1918  inr = mesh%order_inv(ic1)
1919  i = mesh%lend(inr)
1920  init = .true.
1921  do while ((i/=mesh%lend(inr)).or.init)
1922  net_nnb(ic1) = net_nnb(ic1)+1
1923  i = mesh%lptr(i)
1924  init = .false.
1925  end do
1926 end do
1927 
1928 ! Allocation
1929 net_nnbmax = maxval(net_nnb)
1930 allocate(net_inb(net_nnbmax,nicas_blk%nc1))
1931 allocate(net_dnb(net_nnbmax,-1:1,nicas_blk%nc1,nicas_blk%nl1))
1932 
1933 ! Find mesh neighbors
1934 write(mpl%info,'(a10,a)') '','Find mesh neighbors'
1935 call flush(mpl%info)
1936 net_nnb = 0
1937 do ic1=1,nicas_blk%nc1
1938  inr = mesh%order_inv(ic1)
1939  i = mesh%lend(inr)
1940  init = .true.
1941  do while ((i/=mesh%lend(inr)).or.init)
1942  net_nnb(ic1) = net_nnb(ic1)+1
1943  net_inb(net_nnb(ic1),ic1) = mesh%order(abs(mesh%list(i)))
1944  i = mesh%lptr(i)
1945  init = .false.
1946  end do
1947 end do
1948 
1949 ! Compute mesh edges distances
1950 write(mpl%info,'(a10,a)',advance='no') '','Compute mesh edges distances: '
1951 call flush(mpl%info)
1952 call mpl%prog_init(nicas_blk%nc1)
1953 net_dnb = 1.0
1954 !$omp parallel do schedule(static) private(ic1,j,ic0,jc1,jc0,dnb,dx,dy,dz,il1,il0,valid_arc,djl1,jl1,jl0,H11,H22,H33,H12), &
1955 !$omp& private(disthsq,distvsq,rhsq,rvsq,distnorm_network)
1956 do ic1=1,nicas_blk%nc1
1957  do j=1,net_nnb(ic1)
1958  ! Indices
1959  ic0 = nicas_blk%c1_to_c0(ic1)
1960  jc1 = net_inb(j,ic1)
1961  jc0 = nicas_blk%c1_to_c0(jc1)
1962 
1963  if (geom%mask_hor_c0(jc0)) then
1964  if (nicas_blk%anisotropic) then
1965  ! Compute longitude/latitude differences
1966  dx = geom%lon(jc0)-geom%lon(ic0)
1967  dy = geom%lat(jc0)-geom%lat(ic0)
1968  call lonlatmod(dx,dy)
1969  dx = dx*cos(geom%lat(ic0))
1970  else
1971  ! Compute horizontal distance
1972  call sphere_dist(geom%lon(ic0),geom%lat(ic0),geom%lon(jc0),geom%lat(jc0),dnb)
1973  end if
1974 
1975  do il1=1,nicas_blk%nl1
1976  ! Check mask bounds
1977  il0 = nicas_blk%l1_to_l0(il1)
1978  valid_arc = .true.
1979  if (nam%mask_check) call geom%check_arc(il0,geom%lon(ic0),geom%lat(ic0),geom%lon(jc0),geom%lat(jc0),valid_arc)
1980 
1981  if (valid_arc) then
1982  do djl1=-1,1
1983  ! Index
1984  jl1 = max(1,min(il1+djl1,nicas_blk%nl1))
1985  jl0 = nicas_blk%l1_to_l0(jl1)
1986 
1987  if (geom%mask_c0(ic0,il0).and.geom%mask_c0(jc0,jl0)) then
1988  ! Squared support radii
1989  if (nicas_blk%anisotropic) then
1990  dz = geom%vunit(ic0,il0)-geom%vunit(jc0,jl0)
1991  h11 = 0.5*(nicas_blk%H11_c1(ic1,il1)+nicas_blk%H11_c1(jc1,jl1))
1992  h22 = 0.5*(nicas_blk%H22_c1(ic1,il1)+nicas_blk%H22_c1(jc1,jl1))
1993  h33 = 0.5*(nicas_blk%H33_c1(ic1,il1)+nicas_blk%H33_c1(jc1,jl1))
1994  h12 = 0.5*(nicas_blk%H12_c1(ic1,il1)+nicas_blk%H12_c1(jc1,jl1))
1995  net_dnb(j,djl1,ic1,il1) = sqrt(h11*dx**2+h22*dy**2+h33*dz**2+2.0*h12*dx*dy)*gc2gau
1996  else
1997  disthsq = dnb**2
1998  distvsq = (geom%vunit(ic0,il0)-geom%vunit(jc0,jl0))**2
1999  rhsq = 0.5*(nicas_blk%rh_c1(ic1,il1)**2+nicas_blk%rh_c1(jc1,jl1)**2)
2000  rvsq = 0.5*(nicas_blk%rv_c1(ic1,il1)**2+nicas_blk%rv_c1(jc1,jl1)**2)
2001  distnorm_network = 0.0
2002  if (rhsq>0.0) then
2003  distnorm_network = distnorm_network+disthsq/rhsq
2004  elseif (disthsq>0.0) then
2005  distnorm_network = distnorm_network+0.5*huge(0.0)
2006  end if
2007  if (rvsq>0.0) then
2008  distnorm_network = distnorm_network+distvsq/rvsq
2009  elseif (distvsq>0.0) then
2010  distnorm_network = distnorm_network+0.5*huge(0.0)
2011  end if
2012  net_dnb(j,djl1,ic1,il1) = sqrt(distnorm_network)
2013  end if
2014  end if
2015  end do
2016  end if
2017  end do
2018  end if
2019  end do
2020 
2021  ! Update
2022  call mpl%prog_print(ic1)
2023 end do
2024 !$omp end parallel do
2025 write(mpl%info,'(a)') '100%'
2026 call flush(mpl%info)
2027 
2028 ! Compute distances
2029 write(mpl%info,'(a10,a)',advance='no') '','Compute distances: '
2030 call flush(mpl%info)
2031 call mpl%prog_init(nicas_blk%nsbb)
2032 !$omp parallel do schedule(static) private(isbb,is,ic1,il1,np,np_new,jc1,jl1,k,kc1,dkl1,kl1,disttest,add_to_front,jp), &
2033 !$omp& firstprivate(distnorm,plist,plist_new)
2034 do isbb=1,nicas_blk%nsbb
2035  ! Indices
2036  is = nicas_blk%sbb_to_s(isbb)
2037  ic1 = nicas_blk%s_to_c1(is)
2038  il1 = nicas_blk%s_to_l1(is)
2039 
2040  ! Allocation
2041  allocate(distnorm(nicas_blk%nc1,nicas_blk%nl1))
2042  allocate(plist(nicas_blk%nc1*nicas_blk%nl1,2))
2043  allocate(plist_new(nicas_blk%nc1*nicas_blk%nl1,2))
2044 
2045  ! Initialize the front
2046  np = 1
2047  plist(1,1) = ic1
2048  plist(1,2) = il1
2049  distnorm = 1.0
2050  distnorm(ic1,il1) = 0.0
2051 
2052  do while (np>0)
2053  ! Propagate the front
2054  np_new = 0
2055 
2056  do ip=1,np
2057  ! Indices of the central point
2058  jc1 = plist(ip,1)
2059  jl1 = plist(ip,2)
2060 
2061  ! Loop over neighbors
2062  do k=1,net_nnb(jc1)
2063  kc1 = net_inb(k,jc1)
2064  do dkl1=-1,1
2065  kl1 = max(1,min(jl1+dkl1,nicas_blk%nl1))
2066  if (nicas_blk%mask_c1(kc1,kl1)) then
2067  disttest = distnorm(jc1,jl1)+net_dnb(k,dkl1,jc1,jl1)
2068  if (disttest<1.0) then
2069  ! Point is inside the support
2070  if (disttest<distnorm(kc1,kl1)) then
2071  ! Update distance
2072  distnorm(kc1,kl1) = disttest
2073 
2074  ! Check if the point should be added to the front (avoid duplicates)
2075  add_to_front = .true.
2076  do jp=1,np_new
2077  if ((plist_new(jp,1)==kc1).and.(plist_new(jp,2)==kl1)) then
2078  add_to_front = .false.
2079  exit
2080  end if
2081  end do
2082 
2083  if (add_to_front) then
2084  ! Add point to the front
2085  np_new = np_new+1
2086  plist_new(np_new,1) = kc1
2087  plist_new(np_new,2) = kl1
2088  end if
2089  end if
2090  end if
2091  end if
2092  end do
2093  end do
2094  end do
2095 
2096  ! Copy new front
2097  np = np_new
2098  plist(1:np,:) = plist_new(1:np,:)
2099  end do
2100 
2101  ! Pack data
2102  do il1=1,nicas_blk%nl1
2103  do ic1=1,nicas_blk%nc1
2104  if (supeq(distnorm(ic1,il1),1.0_kind_real)) call msr(distnorm(ic1,il1))
2105  end do
2106  end do
2107  call nicas_blk%distnorm(isbb)%pack(nicas_blk%nc1,nicas_blk%nl1,distnorm)
2108 
2109  ! Release memory
2110  deallocate(distnorm)
2111  deallocate(plist)
2112  deallocate(plist_new)
2113 
2114  ! Update
2115  call mpl%prog_print(isbb)
2116 end do
2117 write(mpl%info,'(a)') '100%'
2118 call flush(mpl%info)
2119 
2120 end subroutine nicas_blk_compute_convol_network
2121 
2122 !----------------------------------------------------------------------
2123 ! Subroutine: nicas_blk_compute_convol_distance
2124 ! Purpose: compute convolution with a distance approach
2125 !----------------------------------------------------------------------
2126 subroutine nicas_blk_compute_convol_distance(nicas_blk,mpl,geom)
2128 implicit none
2129 
2130 ! Passed variables
2131 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
2132 type(mpl_type),intent(inout) :: mpl ! MPI data
2133 type(geom_type),intent(in) :: geom ! Geometry
2134 
2135 ! Local variables
2136 integer :: nnmax,is,ic1,jc1,il1,il0,j,js,ic0,jc0,jl0,jl1
2137 integer :: ic1bb,isbb
2138 integer,allocatable :: nn(:),nn_index(:,:)
2139 real(kind_real) :: disthsq,distvsq,rhsq,rvsq
2140 real(kind_real) :: dx,dy,dz,H11,H22,H33,H12
2141 real(kind_real),allocatable :: distnorm(:,:),nn_dist(:,:)
2142 
2143 ! Allocation
2144 allocate(nn(nicas_blk%nc1bb))
2145 
2146 ! Count nearest neighbors
2147 write(mpl%info,'(a10,a)') '','Count nearest neighbors'
2148 call flush(mpl%info)
2149 do ic1bb=1,nicas_blk%nc1bb
2150  ! Indices
2151  ic1 = nicas_blk%c1bb_to_c1(ic1bb)
2152  ic0 = nicas_blk%c1_to_c0(ic1)
2153 
2154  ! Count nearest neighbors
2155  call nicas_blk%kdtree%count_nearest_neighbors(geom%lon(ic0),geom%lat(ic0),nicas_blk%rhmax,nn(ic1bb))
2156 end do
2157 nnmax = maxval(nn)
2158 write(mpl%info,'(a10,a,i6,a,f5.1,a)') '','Number of neighbors to find: ',nnmax,' (', &
2159 & real(nnmax,kind_real)/real(nicas_blk%nc1,kind_real)*100.0,'%)'
2160 
2161 ! Allocation
2162 allocate(nn_index(nnmax,nicas_blk%nc1bb))
2163 allocate(nn_dist(nnmax,nicas_blk%nc1bb))
2164 
2165 ! Find nearest neighbors
2166 write(mpl%info,'(a10,a)',advance='no') '','Find nearest neighbors: '
2167 call flush(mpl%info)
2168 call mpl%prog_init(nicas_blk%nc1bb)
2169 do ic1bb=1,nicas_blk%nc1bb
2170  ! Indices
2171  ic1 = nicas_blk%c1bb_to_c1(ic1bb)
2172  ic0 = nicas_blk%c1_to_c0(ic1)
2173 
2174  ! Find nearest neighbors
2175  call nicas_blk%kdtree%find_nearest_neighbors(geom%lon(ic0),geom%lat(ic0), &
2176  & nn(ic1bb),nn_index(1:nn(ic1bb),ic1bb),nn_dist(1:nn(ic1bb),ic1bb))
2177 
2178  ! Update
2179  call mpl%prog_print(ic1bb)
2180 end do
2181 write(mpl%info,'(a)') '100%'
2182 call flush(mpl%info)
2183 
2184 ! Compute distances
2185 write(mpl%info,'(a10,a)',advance='no') '','Compute distances: '
2186 call flush(mpl%info)
2187 call mpl%prog_init(nicas_blk%nsbb)
2188 !$omp parallel do schedule(static) private(isbb,is,ic1,ic1bb,ic0,il1,il0,j,jl1,jl0,js,jc1,jc0,disthsq,distvsq,rhsq,rvsq), &
2189 !$omp& private(dx,dy,dz,H11,H22,H33,H12) firstprivate(distnorm)
2190 do isbb=1,nicas_blk%nsbb
2191  ! Indices
2192  is = nicas_blk%sbb_to_s(isbb)
2193  ic1 = nicas_blk%s_to_c1(is)
2194  ic1bb = nicas_blk%c1_to_c1bb(ic1)
2195  ic0 = nicas_blk%c1_to_c0(ic1)
2196  il1 = nicas_blk%s_to_l1(is)
2197  il0 = nicas_blk%l1_to_l0(il1)
2198 
2199  ! Allocation
2200  allocate(distnorm(nicas_blk%nc1,nicas_blk%nl1))
2201 
2202  ! Initialization
2203  call msr(distnorm)
2204 
2205  ! Loop on nearest neighbors
2206  do j=1,nn(ic1bb)
2207  jc1 = nn_index(j,ic1bb)
2208  do jl1=1,nicas_blk%nl1
2209  if (nicas_blk%mask_c1(jc1,jl1)) then
2210  jc0 = nicas_blk%c1_to_c0(jc1)
2211  jl0 = nicas_blk%l1_to_l0(jl1)
2212  js = nicas_blk%c1l1_to_s(jc1,jl1)
2213 
2214  ! Normalized distance
2215  if (nicas_blk%anisotropic) then
2216  dx = geom%lon(jc0)-geom%lon(ic0)
2217  dy = geom%lat(jc0)-geom%lat(ic0)
2218  call lonlatmod(dx,dy)
2219  dx = dx*cos(geom%lat(ic0))
2220  dz = geom%vunit(ic0,il0)-geom%vunit(jc0,jl0)
2221  h11 = 0.5*(nicas_blk%H11_c1(ic1,il1)+nicas_blk%H11_c1(jc1,jl1))
2222  h22 = 0.5*(nicas_blk%H22_c1(ic1,il1)+nicas_blk%H22_c1(jc1,jl1))
2223  h33 = 0.5*(nicas_blk%H33_c1(ic1,il1)+nicas_blk%H33_c1(jc1,jl1))
2224  h12 = 0.5*(nicas_blk%H12_c1(ic1,il1)+nicas_blk%H12_c1(jc1,jl1))
2225  distnorm(jc1,jl1) = sqrt(h11*dx**2+h22*dy**2+h33*dz**2+2.0*h12*dx*dy)*gc2gau
2226  else
2227  disthsq = nn_dist(j,ic1bb)**2
2228  distvsq = (geom%vunit(ic0,il0)-geom%vunit(jc0,jl0))**2
2229  rhsq = 0.5*(nicas_blk%rh_c1(ic1,il1)**2+nicas_blk%rh_c1(jc1,jl1)**2)
2230  rvsq = 0.5*(nicas_blk%rv_c1(ic1,il1)**2+nicas_blk%rv_c1(jc1,jl1)**2)
2231  if (rhsq>0.0) then
2232  disthsq = disthsq/rhsq
2233  elseif (disthsq>0.0) then
2234  disthsq = 0.5*huge(0.0)
2235  end if
2236  if (rvsq>0.0) then
2237  distvsq = distvsq/rvsq
2238  elseif (distvsq>0.0) then
2239  distvsq = 0.5*huge(0.0)
2240  end if
2241  distnorm(jc1,jl1) = sqrt(disthsq+distvsq)
2242  end if
2243  end if
2244  end do
2245  end do
2246 
2247  ! Pack data
2248  do il1=1,nicas_blk%nl1
2249  do ic1=1,nicas_blk%nc1
2250  if (supeq(distnorm(ic1,il1),1.0_kind_real)) call msr(distnorm(ic1,il1))
2251  end do
2252  end do
2253  call nicas_blk%distnorm(isbb)%pack(nicas_blk%nc1,nicas_blk%nl1,distnorm)
2254 
2255  ! Release memory
2256  deallocate(distnorm)
2257 
2258  ! Update
2259  call mpl%prog_print(isbb)
2260 end do
2261 !$omp end parallel do
2262 write(mpl%info,'(a)') '100%'
2263 call flush(mpl%info)
2264 
2265 end subroutine nicas_blk_compute_convol_distance
2266 
2267 !----------------------------------------------------------------------
2268 ! Subroutine: nicas_blk_compute_convol_weights
2269 ! Purpose: compute convolution weights
2270 !----------------------------------------------------------------------
2271 subroutine nicas_blk_compute_convol_weights(nicas_blk,mpl,nam,geom,ctmp)
2273 implicit none
2274 
2275 ! Passed variables
2276 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
2277 type(mpl_type),intent(inout) :: mpl ! MPI data
2278 type(nam_type),intent(in) :: nam ! Namelist
2279 type(geom_type),intent(in) :: geom ! Geometry
2280 type(linop_type),intent(inout) :: ctmp ! Convolution operator
2281 
2282 ! Local variables
2283 integer :: n_s_max,ithread,is,ic1,jc1,il1,jl1,il0,jbd,js,ic0,ic1bb,isbb
2284 integer :: c_n_s(mpl%nthread),c_nor_n_s(mpl%nthread)
2285 real(kind_real) :: disth,S_test
2286 logical :: add_op
2287 type(linop_type) :: c(mpl%nthread),c_nor(mpl%nthread)
2288 
2289 ! Allocation
2290 n_s_max = 10*nint(real(geom%nc0*geom%nl0)/real(mpl%nthread*mpl%nproc))
2291 do ithread=1,mpl%nthread
2292  c(ithread)%n_s = n_s_max
2293  call c(ithread)%alloc
2294  c_nor(ithread)%n_s = n_s_max
2295  call c_nor(ithread)%alloc
2296 end do
2297 
2298 ! Initialization
2299 write(mpl%info,'(a10,a)',advance='no') '','Compute weights: '
2300 call flush(mpl%info)
2301 call mpl%prog_init(nicas_blk%nsbb)
2302 c_n_s = 0
2303 c_nor_n_s = 0
2304 
2305 ! Compute weights
2306 !$omp parallel do schedule(static) private(isbb,is,ithread,ic1,ic1bb,ic0,il1,il0,jbd,jc1,jl1,js,disth,S_test,add_op)
2307 do isbb=1,nicas_blk%nsbb
2308  ! Indices
2309  is = nicas_blk%sbb_to_s(isbb)
2310  ithread = 1
2311 !$ ithread = omp_get_thread_num()+1
2312  ic1 = nicas_blk%s_to_c1(is)
2313  ic1bb = nicas_blk%c1_to_c1bb(ic1)
2314  ic0 = nicas_blk%c1_to_c0(ic1)
2315  il1 = nicas_blk%s_to_l1(is)
2316  il0 = nicas_blk%l1_to_l0(il1)
2317 
2318  ! Count convolution operations
2319  do jbd=1,nicas_blk%distnorm(isbb)%nbd
2320  ! Indices
2321  jc1 = nicas_blk%distnorm(isbb)%bd_to_c1(jbd)
2322  jl1 = nicas_blk%distnorm(isbb)%bd_to_l1(jbd)
2323  js = nicas_blk%c1l1_to_s(jc1,jl1)
2324 
2325  if (nicas_blk%double_fit) then
2326  ! Double Gaspari-Cohn (1999) function
2327  disth = sqrt(nicas_blk%distnorm(isbb)%val(jbd)**2-nicas_blk%distnormv(isbb)%val(jbd)**2)
2328  s_test = gc99(mpl,disth)*((1.0+nicas_blk%coef(isbb)%val(jbd))*gc99(mpl,nicas_blk%distnormv(isbb)%val(jbd) &
2329  & /nicas_blk%rfac(isbb)%val(jbd))-nicas_blk%coef(isbb)%val(jbd)*gc99(mpl,nicas_blk%distnormv(isbb)%val(jbd)))
2330  else
2331  ! Gaspari-Cohn (1999) function
2332  s_test = gc99(mpl,nicas_blk%distnorm(isbb)%val(jbd))
2333  end if
2334 ! if (nicas_blk%anisotropic) S_test = S_test*nicas_blk%Hcoef(isbb)%val(jbd)
2335 
2336  if (abs(s_test)>abs(s_inf)) then
2337  ! Store coefficient for convolution
2338  if (nam%lsqrt) then
2339  add_op = .false.
2340  if (nam%mpicom==1) then
2341  add_op = (nicas_blk%lcheck_sb(js).and.(is<=js)).or.(.not.nicas_blk%lcheck_sb(js))
2342  elseif (nam%mpicom==2) then
2343  add_op = nicas_blk%lcheck_sa(is).and.((nicas_blk%lcheck_sa(js).and.(is<=js)) &
2344  & .or.(.not.nicas_blk%lcheck_sa(js)))
2345  end if
2346  else
2347  add_op = .true.
2348  end if
2349  if (add_op) call c(ithread)%add_op(c_n_s(ithread),is,js,s_test)
2350 
2351  ! Store coefficient for normalization
2352  add_op = nicas_blk%lcheck_sb(is).and.((nicas_blk%lcheck_sb(js).and.(is<=js)).or.(.not.nicas_blk%lcheck_sb(js)))
2353  if (add_op) call c_nor(ithread)%add_op(c_nor_n_s(ithread),is,js,s_test)
2354  end if
2355  end do
2356 
2357  ! Update
2358  call mpl%prog_print(isbb)
2359 end do
2360 !$omp end parallel do
2361 write(mpl%info,'(a)') '100%'
2362 call flush(mpl%info)
2363 
2364 ! Gather data from threads
2365 call ctmp%gather(mpl,c_n_s,c)
2366 call nicas_blk%c_nor%gather(mpl,c_nor_n_s,c_nor)
2367 
2368 ! Release memory
2369 do ithread=1,mpl%nthread
2370  call c(ithread)%dealloc
2371  call c_nor(ithread)%dealloc
2372 end do
2373 
2374 end subroutine nicas_blk_compute_convol_weights
2375 
2376 !----------------------------------------------------------------------
2377 ! Subroutine: nicas_blk_compute_mpi_c
2378 ! Purpose: compute NICAS MPI distribution, halo C
2379 !----------------------------------------------------------------------
2380 subroutine nicas_blk_compute_mpi_c(nicas_blk,mpl,geom)
2382 implicit none
2383 
2384 ! Passed variables
2385 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
2386 type(mpl_type),intent(inout) :: mpl ! MPI data
2387 type(geom_type),intent(in) :: geom ! Geometry
2388 
2389 ! Local variables
2390 integer :: isa,isb,isc,i_s,is,js
2391 integer,allocatable :: s_to_proc(:)
2392 logical,allocatable :: lcheck_sc_nor(:)
2393 
2394 ! Allocation
2395 allocate(nicas_blk%lcheck_sc(nicas_blk%ns))
2396 allocate(lcheck_sc_nor(nicas_blk%ns))
2397 allocate(s_to_proc(nicas_blk%ns))
2398 
2399 ! Halo definitions
2400 
2401 ! Halo C
2402 nicas_blk%lcheck_sc = nicas_blk%lcheck_sb
2403 do i_s=1,nicas_blk%c%n_s
2404  is = nicas_blk%c%row(i_s)
2405  js = nicas_blk%c%col(i_s)
2406  nicas_blk%lcheck_sc(is) = .true.
2407  nicas_blk%lcheck_sc(js) = .true.
2408 end do
2409 nicas_blk%nsc = count(nicas_blk%lcheck_sc)
2410 lcheck_sc_nor = nicas_blk%lcheck_sb
2411 do i_s=1,nicas_blk%c_nor%n_s
2412  is = nicas_blk%c_nor%row(i_s)
2413  js = nicas_blk%c_nor%col(i_s)
2414  lcheck_sc_nor(is) = .true.
2415  lcheck_sc_nor(js) = .true.
2416 end do
2417 nicas_blk%nsc_nor = count(lcheck_sc_nor)
2418 
2419 ! Check halos consistency
2420 do is=1,nicas_blk%ns
2421  if (nicas_blk%lcheck_sa(is).and.(.not.nicas_blk%lcheck_sc(is))) call mpl%abort('point in halo A but not in halo C')
2422  if (nicas_blk%lcheck_sb(is).and.(.not.nicas_blk%lcheck_sc(is))) call mpl%abort('point in halo B but not in halo C')
2423 end do
2424 
2425 ! Global <-> local conversions for fields
2426 
2427 ! Halo C
2428 allocate(nicas_blk%sc_to_s(nicas_blk%nsc))
2429 allocate(nicas_blk%s_to_sc(nicas_blk%ns))
2430 call msi(nicas_blk%s_to_sc)
2431 isc = 0
2432 do is=1,nicas_blk%ns
2433  if (nicas_blk%lcheck_sc(is)) then
2434  isc = isc+1
2435  nicas_blk%sc_to_s(isc) = is
2436  nicas_blk%s_to_sc(is) = isc
2437  end if
2438 end do
2439 
2440 allocate(nicas_blk%sc_nor_to_s(nicas_blk%nsc_nor))
2441 allocate(nicas_blk%s_to_sc_nor(nicas_blk%ns))
2442 call msi(nicas_blk%s_to_sc_nor)
2443 isc = 0
2444 do is=1,nicas_blk%ns
2445  if (lcheck_sc_nor(is)) then
2446  isc = isc+1
2447  nicas_blk%sc_nor_to_s(isc) = is
2448  nicas_blk%s_to_sc_nor(is) = isc
2449  end if
2450 end do
2451 
2452 ! Inter-halo conversions
2453 allocate(nicas_blk%sa_to_sc(nicas_blk%nsa))
2454 do isa=1,nicas_blk%nsa
2455  is = nicas_blk%sa_to_s(isa)
2456  isc = nicas_blk%s_to_sc(is)
2457  nicas_blk%sa_to_sc(isa) = isc
2458 end do
2459 allocate(nicas_blk%sb_to_sc(nicas_blk%nsb))
2460 allocate(nicas_blk%sc_to_sb(nicas_blk%nsc))
2461 allocate(nicas_blk%sb_to_sc_nor(nicas_blk%nsb))
2462 call msi(nicas_blk%sc_to_sb)
2463 do isb=1,nicas_blk%nsb
2464  is = nicas_blk%sb_to_s(isb)
2465  isc = nicas_blk%s_to_sc(is)
2466  nicas_blk%sb_to_sc(isb) = isc
2467  nicas_blk%sc_to_sb(isc) = isb
2468  isc = nicas_blk%s_to_sc_nor(is)
2469  nicas_blk%sb_to_sc_nor(isb) = isc
2470 end do
2471 
2472 ! Local data
2473 
2474 ! Convolution
2475 nicas_blk%c%n_src = nicas_blk%nsc
2476 nicas_blk%c%n_dst = nicas_blk%nsc
2477 do i_s=1,nicas_blk%c%n_s
2478  nicas_blk%c%row(i_s) = nicas_blk%s_to_sc(nicas_blk%c%row(i_s))
2479  nicas_blk%c%col(i_s) = nicas_blk%s_to_sc(nicas_blk%c%col(i_s))
2480 end do
2481 call nicas_blk%c%reorder(mpl)
2482 
2483 ! Convolution for normalization
2484 nicas_blk%c_nor%n_src = nicas_blk%nsc
2485 nicas_blk%c_nor%n_dst = nicas_blk%nsc
2486 do i_s=1,nicas_blk%c_nor%n_s
2487  nicas_blk%c_nor%row(i_s) = nicas_blk%s_to_sc_nor(nicas_blk%c_nor%row(i_s))
2488  nicas_blk%c_nor%col(i_s) = nicas_blk%s_to_sc_nor(nicas_blk%c_nor%col(i_s))
2489 end do
2490 call nicas_blk%c_nor%reorder(mpl)
2491 
2492 ! Setup communications
2493 s_to_proc = geom%c0_to_proc(nicas_blk%c1_to_c0(nicas_blk%s_to_c1))
2494 call nicas_blk%com_AC%setup(mpl,'com_AC',nicas_blk%ns,nicas_blk%nsa,nicas_blk%nsc,nicas_blk%sc_to_s,nicas_blk%sa_to_sc, &
2495  & s_to_proc,nicas_blk%s_to_sa)
2496 
2497 end subroutine nicas_blk_compute_mpi_c
2498 
2499 !----------------------------------------------------------------------
2500 ! Subroutine: nicas_blk_compute_normalization
2501 ! Purpose: compute normalization
2502 !----------------------------------------------------------------------
2503 subroutine nicas_blk_compute_normalization(nicas_blk,mpl,nam,geom)
2505 implicit none
2506 
2507 ! Passed variables
2508 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
2509 type(mpl_type),intent(inout) :: mpl ! MPI data
2510 type(nam_type),intent(in) :: nam ! Namelist
2511 type(geom_type),intent(in) :: geom ! Geometry
2512 
2513 ! Local variables
2514 integer :: il0i,i_s,ic1,ic1b,jc1b,is,js,isc,jsb,jsc,ic0,ic0a,il0,il1,ih,jv,nlr,ilr,ic,isc_add
2515 integer,allocatable :: ineh(:,:),inev(:),ines(:,:),inec(:),order(:),isc_list(:)
2516 integer,allocatable :: h_col(:,:,:),v_col(:,:),s_col(:,:,:),c_ind(:,:)
2517 real(kind_real) :: S_add
2518 real(kind_real),allocatable :: h_S(:,:,:),v_S(:,:,:),s_S(:,:,:),c_S(:,:)
2519 real(kind_real),allocatable :: list(:),S_list(:),S_list_tmp(:)
2520 
2521 ! Compute horizontal interpolation inverse mapping
2522 allocate(ineh(geom%nc0a,geom%nl0i))
2523 ineh = 0
2524 do il0i=1,geom%nl0i
2525  do i_s=1,nicas_blk%h(il0i)%n_s
2526  ic0a = nicas_blk%h(il0i)%row(i_s)
2527  ineh(ic0a,il0i) = ineh(ic0a,il0i)+1
2528  end do
2529 end do
2530 allocate(h_col(maxval(ineh),geom%nc0a,geom%nl0i))
2531 allocate(h_s(maxval(ineh),geom%nc0a,geom%nl0i))
2532 call msi(h_col)
2533 call msr(h_s)
2534 ineh = 0
2535 do il0i=1,geom%nl0i
2536  do i_s=1,nicas_blk%h(il0i)%n_s
2537  ic0a = nicas_blk%h(il0i)%row(i_s)
2538  ineh(ic0a,il0i) = ineh(ic0a,il0i)+1
2539  h_col(ineh(ic0a,il0i),ic0a,il0i) = nicas_blk%h(il0i)%col(i_s)
2540  h_s(ineh(ic0a,il0i),ic0a,il0i) = nicas_blk%h(il0i)%S(i_s)
2541  end do
2542 end do
2543 
2544 ! Compute vertical interpolation inverse mapping
2545 allocate(inev(geom%nl0))
2546 inev = 0
2547 do i_s=1,nicas_blk%v%n_s
2548  il0 = nicas_blk%v%row(i_s)
2549  inev(il0) = inev(il0)+1
2550 end do
2551 allocate(v_col(maxval(inev),geom%nl0))
2552 allocate(v_s(maxval(inev),nicas_blk%nc1b,geom%nl0))
2553 call msi(v_col)
2554 call msr(v_s)
2555 inev = 0
2556 do i_s=1,nicas_blk%v%n_s
2557  il0 = nicas_blk%v%row(i_s)
2558  inev(il0) = inev(il0)+1
2559  v_col(inev(il0),il0) = nicas_blk%v%col(i_s)
2560  do ic1b=1,nicas_blk%nc1b
2561  v_s(inev(il0),ic1b,il0) = nicas_blk%v%Svec(i_s,ic1b)
2562  end do
2563 end do
2564 
2565 ! Compute subsampling interpolation inverse mapping
2566 allocate(ines(nicas_blk%nc1b,nicas_blk%nl1))
2567 ines = 0
2568 do il1=1,nicas_blk%nl1
2569  do i_s=1,nicas_blk%s(il1)%n_s
2570  ic1b = nicas_blk%s(il1)%row(i_s)
2571  ines(ic1b,il1) = ines(ic1b,il1)+1
2572  end do
2573 end do
2574 allocate(s_col(maxval(ines),nicas_blk%nc1b,nicas_blk%nl1))
2575 allocate(s_s(maxval(ines),nicas_blk%nc1b,nicas_blk%nl1))
2576 call msi(s_col)
2577 call msr(s_s)
2578 ines = 0
2579 do il1=1,nicas_blk%nl1
2580  do i_s=1,nicas_blk%s(il1)%n_s
2581  ic1b = nicas_blk%s(il1)%row(i_s)
2582  ines(ic1b,il1) = ines(ic1b,il1)+1
2583  jc1b = nicas_blk%s(il1)%col(i_s)
2584  jsb = nicas_blk%c1bl1_to_sb(jc1b,il1)
2585  jsc = nicas_blk%sb_to_sc_nor(jsb)
2586  s_col(ines(ic1b,il1),ic1b,il1) = jsc
2587  s_s(ines(ic1b,il1),ic1b,il1) = nicas_blk%s(il1)%S(i_s)
2588  end do
2589 end do
2590 
2591 ! Compute convolution inverse mapping
2592 allocate(inec(nicas_blk%nsc_nor))
2593 inec = 0
2594 do i_s=1,nicas_blk%c_nor%n_s
2595  isc = nicas_blk%c_nor%col(i_s)
2596  jsc = nicas_blk%c_nor%row(i_s)
2597  if (jsc/=isc) then
2598  is = nicas_blk%sc_nor_to_s(isc)
2599  inec(isc) = inec(isc)+1
2600  js = nicas_blk%sc_nor_to_s(jsc)
2601  inec(jsc) = inec(jsc)+1
2602  end if
2603 end do
2604 allocate(c_ind(maxval(inec),nicas_blk%nsc_nor))
2605 allocate(c_s(maxval(inec),nicas_blk%nsc_nor))
2606 call msi(c_ind)
2607 call msr(c_s)
2608 inec = 0
2609 do i_s=1,nicas_blk%c_nor%n_s
2610  isc = nicas_blk%c_nor%col(i_s)
2611  jsc = nicas_blk%c_nor%row(i_s)
2612  if (jsc/=isc) then
2613  is = nicas_blk%sc_nor_to_s(isc)
2614  inec(isc) = inec(isc)+1
2615  c_ind(inec(isc),isc) = jsc
2616  c_s(inec(isc),isc) = nicas_blk%c_nor%S(i_s)
2617  js = nicas_blk%sc_nor_to_s(jsc)
2618  inec(jsc) = inec(jsc)+1
2619  c_ind(inec(jsc),jsc) = isc
2620  c_s(inec(jsc),jsc) = nicas_blk%c_nor%S(i_s)
2621  end if
2622 end do
2623 
2624 ! Re-order indices
2625 do isc=1,nicas_blk%nsc_nor
2626  ! Allocation
2627  allocate(order(inec(isc)))
2628  allocate(list(inec(isc)))
2629 
2630  ! Copy
2631  list = c_ind(1:inec(isc),isc)
2632 
2633  ! Order
2634  call qsort(inec(isc),list,order)
2635 
2636  ! Re-order
2637  c_ind(1:inec(isc),isc) = c_ind(order(1:inec(isc)),isc)
2638  c_s(1:inec(isc),isc) = c_s(order(1:inec(isc)),isc)
2639 
2640  ! Release memory
2641  deallocate(order)
2642  deallocate(list)
2643 end do
2644 
2645 ! Allocation
2646 allocate(nicas_blk%norm(geom%nc0a,geom%nl0))
2647 call msr(nicas_blk%norm)
2648 
2649 ! Compute normalization weights
2650 do il0=1,geom%nl0
2651  il0i = min(il0,geom%nl0i)
2652  write(mpl%info,'(a10,a,i3,a)',advance='no') '','Level ',nam%levs(il0),': '
2653  call flush(mpl%info)
2654  call mpl%prog_init(geom%nc0a)
2655 
2656  !$omp parallel do schedule(static) private(ic0a,ic0,nlr,isc_add,S_add,ih,ic1b,ic1,jv,il1,is,ilr,ic,isc,jsc), &
2657  !$omp& firstprivate(isc_list,S_list,S_list_tmp)
2658  do ic0a=1,geom%nc0a
2659  ! Index
2660  ic0 = geom%c0a_to_c0(ic0a)
2661 
2662  if (geom%mask_c0(ic0,il0)) then
2663  ! Allocation
2664  allocate(isc_list(ineh(ic0a,il0i)*inev(il0)*maxval(ines)))
2665  allocate(s_list(ineh(ic0a,il0i)*inev(il0)*maxval(ines)))
2666  allocate(s_list_tmp(nicas_blk%nsc_nor))
2667 
2668  ! Initialization
2669  isc_list = 0
2670  s_list = 0.0
2671 
2672  ! Adjoint interpolation
2673  nlr = 0
2674  do ih=1,ineh(ic0a,il0i)
2675  ic1b = h_col(ih,ic0a,il0i)
2676  ic1 = nicas_blk%c1b_to_c1(ic1b)
2677  do jv=1,inev(il0)
2678  il1 = v_col(jv,il0)
2679  if ((nicas_blk%l1_to_l0(il1)>=nicas_blk%vbot(ic1)).and.(nicas_blk%l1_to_l0(il1)<=nicas_blk%vtop(ic1))) then
2680  do is=1,ines(ic1b,il1)
2681  isc_add = s_col(is,ic1b,il1)
2682  s_add = h_s(ih,ic0a,il0i)*v_s(jv,ic1b,il0)*s_s(is,ic1b,il1)
2683  if (nlr==0) then
2684  ilr = 1
2685  nlr = 1
2686  else
2687  do ilr=1,nlr
2688  if (isc_add==isc_list(ilr)) exit
2689  end do
2690  if (ilr==nlr+1) nlr = nlr+1
2691  end if
2692  isc_list(ilr) = isc_add
2693  s_list(ilr) = s_list(ilr)+s_add
2694  end do
2695  end if
2696  end do
2697  end do
2698 
2699  ! Initialization
2700  s_list_tmp = 0.0
2701  do ilr=1,nlr
2702  isc = isc_list(ilr)
2703  s_list_tmp(isc) = s_list(ilr)
2704  end do
2705 
2706  ! Convolution
2707  do ilr=1,nlr
2708  isc = isc_list(ilr)
2709  do ic=1,inec(isc)
2710  jsc = c_ind(ic,isc)
2711  s_list_tmp(jsc) = s_list_tmp(jsc)+c_s(ic,isc)*s_list(ilr)
2712  end do
2713  end do
2714 
2715  ! Sum of squared values
2716  nicas_blk%norm(ic0a,il0) = sum(s_list_tmp**2)
2717 
2718  ! Normalization factor
2719  nicas_blk%norm(ic0a,il0) = 1.0/sqrt(nicas_blk%norm(ic0a,il0))
2720 
2721  ! Update
2722  call mpl%prog_print(ic0a)
2723 
2724  ! Release memory
2725  deallocate(isc_list)
2726  deallocate(s_list)
2727  deallocate(s_list_tmp)
2728  end if
2729  end do
2730  !$omp end parallel do
2731  write(mpl%info,'(a)') '100%'
2732  call flush(mpl%info)
2733 end do
2734 
2735 end subroutine nicas_blk_compute_normalization
2736 
2737 !----------------------------------------------------------------------
2738 ! Subroutine: nicas_blk_compute_adv
2739 ! Purpose: compute advection
2740 !----------------------------------------------------------------------
2741 subroutine nicas_blk_compute_adv(nicas_blk,mpl,rng,nam,geom,cmat_blk)
2743 implicit none
2744 
2745 ! Passed variables
2746 class(nicas_blk_type),intent(inout) :: nicas_blk ! NICAS data block
2747 type(mpl_type),intent(inout) :: mpl ! MPI data
2748 type(rng_type),intent(inout) :: rng ! Random number generator
2749 type(nam_type),intent(in) :: nam ! Namelist
2750 type(geom_type),intent(in) :: geom ! Geometry
2751 type(cmat_blk_type),intent(in) :: cmat_blk ! C matrix data block
2752 
2753 ! Local variables
2754 integer :: its,il0,ic0,ic0a,i_s,i_s_loc,iproc,jc0
2755 integer :: ic0d,d_n_s_max,d_n_s_max_loc
2756 integer :: ic0dinv,dinv_n_s_max,dinv_n_s_max_loc
2757 integer,allocatable :: c0d_to_c0(:),c0_to_c0d(:),c0a_to_c0d(:),interpd_lg(:,:,:)
2758 integer,allocatable :: c0dinv_to_c0(:),c0_to_c0dinv(:),c0a_to_c0dinv(:),interpdinv_lg(:,:,:)
2759 real(kind_real) :: displ_lon(geom%nc0,geom%nl0),displ_lat(geom%nc0,geom%nl0)
2760 logical :: mask_c0(geom%nc0)
2761 logical,allocatable :: lcheck_c0d(:),lcheck_d(:,:,:)
2762 logical,allocatable :: lcheck_c0dinv(:),lcheck_dinv(:,:,:)
2763 type(linop_type),allocatable :: dfull(:,:)
2764 type(linop_type),allocatable :: dinvfull(:,:)
2765 
2766 write(mpl%info,'(a7,a)') '','Compute advection'
2767 call flush(mpl%info)
2768 
2769 ! Allocation
2770 allocate(dfull(geom%nl0,2:nam%nts))
2771 allocate(dinvfull(geom%nl0,2:nam%nts))
2772 
2773 ! Initialization
2774 mask_c0 = .true.
2775 
2776 do its=2,nam%nts
2777  ! Local to global
2778  call mpl%loc_to_glb(geom%nl0,geom%nc0a,cmat_blk%displ_lon(:,:,its),geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,.true.,displ_lon)
2779  call mpl%loc_to_glb(geom%nl0,geom%nc0a,cmat_blk%displ_lat(:,:,its),geom%nc0,geom%c0_to_proc,geom%c0_to_c0a,.true.,displ_lat)
2780 
2781  do il0=1,geom%nl0
2782  ! Compute direct interpolation
2783  call dfull(il0,its)%interp(mpl,rng,geom%nc0,displ_lon(:,il0),displ_lat(:,il0),mask_c0,geom%nc0,geom%lon,geom%lat,mask_c0, &
2784  & nam%diag_interp)
2785 
2786  ! Compute inverse interpolation
2787  call dinvfull(il0,its)%interp(mpl,rng,geom%nc0,geom%lon,geom%lat,mask_c0,geom%nc0,displ_lon(:,il0),displ_lat(:,il0),mask_c0, &
2788  & nam%diag_interp)
2789  end do
2790 end do
2791 
2792 ! Allocation
2793 d_n_s_max = 0
2794 dinv_n_s_max = 0
2795 do its=2,nam%nts
2796  do il0=1,geom%nl0
2797  d_n_s_max = max(d_n_s_max,dfull(il0,its)%n_s)
2798  dinv_n_s_max = max(dinv_n_s_max,dinvfull(il0,its)%n_s)
2799  end do
2800 end do
2801 allocate(lcheck_c0d(geom%nc0))
2802 allocate(lcheck_c0dinv(geom%nc0))
2803 allocate(lcheck_d(d_n_s_max,geom%nl0,2:nam%nts))
2804 allocate(lcheck_dinv(dinv_n_s_max,geom%nl0,2:nam%nts))
2805 allocate(nicas_blk%d(geom%nl0,2:nam%nts))
2806 allocate(nicas_blk%dinv(geom%nl0,2:nam%nts))
2807 
2808 ! Halo definitions
2809 
2810 ! Halo A
2811 lcheck_c0d = .false.
2812 lcheck_c0dinv = .false.
2813 do ic0a=1,geom%nc0a
2814  ic0 = geom%c0a_to_c0(ic0a)
2815  lcheck_c0d(ic0) = .true.
2816  lcheck_c0dinv(ic0) = .true.
2817 end do
2818 
2819 ! Halo D
2820 lcheck_d = .false.
2821 lcheck_dinv = .false.
2822 do its=2,nam%nts
2823  do il0=1,geom%nl0
2824  do i_s=1,dfull(il0,its)%n_s
2825  ic0 = dfull(il0,its)%row(i_s)
2826  iproc = geom%c0_to_proc(ic0)
2827  if (iproc==mpl%myproc) then
2828  jc0 = dfull(il0,its)%col(i_s)
2829  lcheck_d(i_s,il0,its) = .true.
2830  lcheck_c0d(jc0) = .true.
2831  end if
2832  end do
2833  do i_s=1,dinvfull(il0,its)%n_s
2834  ic0 = dinvfull(il0,its)%row(i_s)
2835  iproc = geom%c0_to_proc(ic0)
2836  if (iproc==mpl%myproc) then
2837  jc0 = dinvfull(il0,its)%col(i_s)
2838  lcheck_dinv(i_s,il0,its) = .true.
2839  lcheck_c0dinv(jc0) = .true.
2840  end if
2841  end do
2842  end do
2843 end do
2844 
2845 ! Halo sizes
2846 do its=2,nam%nts
2847  do il0=1,geom%nl0
2848  nicas_blk%d(il0,its)%n_s = count(lcheck_d(:,il0,its))
2849  nicas_blk%dinv(il0,its)%n_s = count(lcheck_dinv(:,il0,its))
2850  end do
2851 end do
2852 nicas_blk%nc0d = count(lcheck_c0d)
2853 nicas_blk%nc0dinv = count(lcheck_c0dinv)
2854 
2855 ! Global <-> local conversions for fields
2856 allocate(c0d_to_c0(nicas_blk%nc0d))
2857 allocate(c0dinv_to_c0(nicas_blk%nc0dinv))
2858 allocate(c0_to_c0d(geom%nc0))
2859 allocate(c0_to_c0dinv(geom%nc0))
2860 call msi(c0_to_c0d)
2861 call msi(c0_to_c0dinv)
2862 ic0d = 0
2863 ic0dinv = 0
2864 do ic0=1,geom%nc0
2865  if (lcheck_c0d(ic0)) then
2866  ic0d = ic0d+1
2867  c0d_to_c0(ic0d) = ic0
2868  c0_to_c0d(ic0) = ic0d
2869  end if
2870  if (lcheck_c0dinv(ic0)) then
2871  ic0dinv = ic0dinv+1
2872  c0dinv_to_c0(ic0dinv) = ic0
2873  c0_to_c0dinv(ic0) = ic0dinv
2874  end if
2875 end do
2876 
2877 ! Inter-halo conversions
2878 allocate(c0a_to_c0d(geom%nc0a))
2879 allocate(c0a_to_c0dinv(geom%nc0a))
2880 do ic0a=1,geom%nc0a
2881  ic0 = geom%c0a_to_c0(ic0a)
2882  ic0d = c0_to_c0d(ic0)
2883  ic0dinv = c0_to_c0dinv(ic0)
2884  c0a_to_c0d(ic0a) = ic0d
2885  c0a_to_c0dinv(ic0a) = ic0dinv
2886 end do
2887 
2888 ! Global <-> local conversions for data
2889 d_n_s_max_loc = 0
2890 dinv_n_s_max_loc = 0
2891 do its=2,nam%nts
2892  do il0=1,geom%nl0
2893  d_n_s_max_loc = max(d_n_s_max_loc,nicas_blk%d(il0,its)%n_s)
2894  dinv_n_s_max_loc = max(dinv_n_s_max_loc,nicas_blk%dinv(il0,its)%n_s)
2895  end do
2896 end do
2897 allocate(interpd_lg(d_n_s_max_loc,geom%nl0,2:nam%nts))
2898 allocate(interpdinv_lg(dinv_n_s_max_loc,geom%nl0,2:nam%nts))
2899 do its=2,nam%nts
2900  do il0=1,geom%nl0
2901  i_s_loc = 0
2902  do i_s=1,dfull(il0,its)%n_s
2903  if (lcheck_d(i_s,il0,its)) then
2904  i_s_loc = i_s_loc+1
2905  interpd_lg(i_s_loc,il0,its) = i_s
2906  end if
2907  end do
2908  i_s_loc = 0
2909  do i_s=1,dinvfull(il0,its)%n_s
2910  if (lcheck_dinv(i_s,il0,its)) then
2911  i_s_loc = i_s_loc+1
2912  interpdinv_lg(i_s_loc,il0,its) = i_s
2913  end if
2914  end do
2915  end do
2916 end do
2917 
2918 ! Local data
2919 do its=2,nam%nts
2920  do il0=1,geom%nl0
2921  write(nicas_blk%d(il0,its)%prefix,'(a,i3.3,a,i2.2)') 'd_',il0,'_',its
2922  write(nicas_blk%dinv(il0,its)%prefix,'(a,i3.3,a,i2.2)') 'dinv_',il0,'_',its
2923  nicas_blk%d(il0,its)%n_src = nicas_blk%nc0d
2924  nicas_blk%dinv(il0,its)%n_src = nicas_blk%nc0dinv
2925  nicas_blk%d(il0,its)%n_dst = geom%nc0a
2926  nicas_blk%dinv(il0,its)%n_dst = geom%nc0a
2927  call nicas_blk%d(il0,its)%alloc
2928  call nicas_blk%dinv(il0,its)%alloc
2929  do i_s_loc=1,nicas_blk%d(il0,its)%n_s
2930  i_s = interpd_lg(i_s_loc,il0,its)
2931  nicas_blk%d(il0,its)%row(i_s_loc) = geom%c0_to_c0a(dfull(il0,its)%row(i_s))
2932  nicas_blk%d(il0,its)%col(i_s_loc) = c0_to_c0d(dfull(il0,its)%col(i_s))
2933  nicas_blk%d(il0,its)%S(i_s_loc) = dfull(il0,its)%S(i_s)
2934  end do
2935  do i_s_loc=1,nicas_blk%dinv(il0,its)%n_s
2936  i_s = interpdinv_lg(i_s_loc,il0,its)
2937  nicas_blk%dinv(il0,its)%row(i_s_loc) = geom%c0_to_c0a(dinvfull(il0,its)%row(i_s))
2938  nicas_blk%dinv(il0,its)%col(i_s_loc) = c0_to_c0dinv(dinvfull(il0,its)%col(i_s))
2939  nicas_blk%dinv(il0,its)%S(i_s_loc) = dinvfull(il0,its)%S(i_s)
2940  end do
2941  call nicas_blk%d(il0,its)%reorder(mpl)
2942  call nicas_blk%dinv(il0,its)%reorder(mpl)
2943  end do
2944 end do
2945 
2946 ! Setup communications
2947 call nicas_blk%com_AD%setup(mpl,'com_AD',geom%nc0,geom%nc0a,nicas_blk%nc0d,c0d_to_c0,c0a_to_c0d,geom%c0_to_proc,geom%c0_to_c0a)
2948 call nicas_blk%com_ADinv%setup(mpl,'com_ADinv',geom%nc0,geom%nc0a,nicas_blk%nc0dinv,c0dinv_to_c0,c0a_to_c0dinv, &
2949  & geom%c0_to_proc,geom%c0_to_c0a)
2950 
2951 ! Print results
2952 write(mpl%info,'(a7,a,i4)') '','Parameters for processor #',mpl%myproc
2953 write(mpl%info,'(a10,a,i8)') '','nc0d = ',nicas_blk%nc0d
2954 write(mpl%info,'(a10,a,i8)') '','nc0dinv = ',nicas_blk%nc0dinv
2955 do its=2,nam%nts
2956  do il0=1,geom%nl0
2957  write(mpl%info,'(a10,a,i3,a,i2,a,i8)') '','d(',il0,',',its,')%n_s = ',nicas_blk%d(il0,its)%n_s
2958  write(mpl%info,'(a10,a,i3,a,i2,a,i8)') '','dinv(',il0,',',its,')%n_s = ',nicas_blk%dinv(il0,its)%n_s
2959  end do
2960 end do
2961 call flush(mpl%info)
2962 
2963 end subroutine nicas_blk_compute_adv
2964 
2965 !----------------------------------------------------------------------
2966 ! Subroutine: nicas_blk_apply
2967 ! Purpose: apply NICAS method
2968 !----------------------------------------------------------------------
2969 subroutine nicas_blk_apply(nicas_blk,mpl,nam,geom,fld)
2971 implicit none
2972 
2973 ! Passed variables
2974 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
2975 type(mpl_type),intent(in) :: mpl ! MPI data
2976 type(nam_type),intent(in) :: nam ! Namelist
2977 type(geom_type),intent(in) :: geom ! Geometry
2978 real(kind_real),intent(inout) :: fld(geom%nc0a,geom%nl0) ! Field
2979 
2980 ! Local variables
2981 real(kind_real) :: alpha_a(nicas_blk%nsa),alpha_b(nicas_blk%nsb),alpha_c(nicas_blk%nsc)
2982 
2983 ! Adjoint interpolation
2984 call nicas_blk%apply_interp_ad(mpl,geom,fld,alpha_b)
2985 
2986 ! Communication
2987 if (nam%mpicom==1) then
2988  ! Initialization
2989  alpha_c = 0.0
2990 
2991  ! Copy zone B into zone C
2992  alpha_c(nicas_blk%sb_to_sc) = alpha_b
2993 elseif (nam%mpicom==2) then
2994  ! Halo reduction from zone B to zone A
2995  call nicas_blk%com_AB%red(mpl,alpha_b,alpha_a)
2996 
2997  ! Initialization
2998  alpha_c = 0.0
2999 
3000  ! Copy zone A into zone C
3001  alpha_c(nicas_blk%sa_to_sc) = alpha_a
3002 end if
3003 
3004 ! Convolution
3005 call nicas_blk%apply_convol(mpl,alpha_c)
3006 
3007 ! Halo reduction from zone C to zone A
3008 call nicas_blk%com_AC%red(mpl,alpha_c,alpha_a)
3009 
3010 ! Halo extension from zone A to zone B
3011 call nicas_blk%com_AB%ext(mpl,alpha_a,alpha_b)
3012 
3013 ! Interpolation
3014 call nicas_blk%apply_interp(mpl,geom,alpha_b,fld)
3015 
3016 end subroutine nicas_blk_apply
3017 
3018 !----------------------------------------------------------------------
3019 ! Subroutine: nicas_blk_apply_from_sqrt
3020 ! Purpose: apply NICAS method from its square-root formulation
3021 !----------------------------------------------------------------------
3022 subroutine nicas_blk_apply_from_sqrt(nicas_blk,mpl,geom,fld)
3024 implicit none
3025 
3026 ! Passed variables
3027 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3028 type(mpl_type),intent(in) :: mpl ! MPI data
3029 type(geom_type),intent(in) :: geom ! Geometry
3030 real(kind_real),intent(inout) :: fld(geom%nc0a,geom%nl0) ! Field
3031 
3032 ! Local variables
3033 real(kind_real) :: alpha(nicas_blk%nsa)
3034 
3035 ! Apply square-root adjoint
3036 call nicas_blk%apply_sqrt_ad(mpl,geom,fld,alpha)
3037 
3038 ! Apply square-root
3039 call nicas_blk%apply_sqrt(mpl,geom,alpha,fld)
3040 
3041 end subroutine nicas_blk_apply_from_sqrt
3042 
3043 !----------------------------------------------------------------------
3044 ! Subroutine: nicas_blk_apply_sqrt
3045 ! Purpose: apply NICAS method square-root
3046 !----------------------------------------------------------------------
3047 subroutine nicas_blk_apply_sqrt(nicas_blk,mpl,geom,alpha,fld)
3049 implicit none
3050 
3051 ! Passed variables
3052 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3053 type(mpl_type),intent(in) :: mpl ! MPI data
3054 type(geom_type),intent(in) :: geom ! Geometry
3055 real(kind_real),intent(in) :: alpha(nicas_blk%nsa) ! Subgrid field
3056 real(kind_real),intent(out) :: fld(geom%nc0a,geom%nl0) ! Field
3057 
3058 ! Local variable
3059 real(kind_real) :: alpha_a(nicas_blk%nsa),alpha_b(nicas_blk%nsb),alpha_c(nicas_blk%nsc)
3060 
3061 ! Initialization
3062 alpha_c = 0.0
3063 
3064 ! Copy zone A into zone C
3065 alpha_c(nicas_blk%sa_to_sc) = alpha
3066 
3067 ! Convolution
3068 call nicas_blk%apply_convol(mpl,alpha_c)
3069 
3070 ! Halo reduction from zone C to zone A
3071 call nicas_blk%com_AC%red(mpl,alpha_c,alpha_a)
3072 
3073 ! Halo extension from zone A to zone B
3074 call nicas_blk%com_AB%ext(mpl,alpha_a,alpha_b)
3075 
3076 ! Interpolation
3077 call nicas_blk%apply_interp(mpl,geom,alpha_b,fld)
3078 
3079 end subroutine nicas_blk_apply_sqrt
3080 
3081 !----------------------------------------------------------------------
3082 ! Subroutine: nicas_blk_apply_sqrt_ad
3083 ! Purpose: apply NICAS method square-root adjoint
3084 !----------------------------------------------------------------------
3085 subroutine nicas_blk_apply_sqrt_ad(nicas_blk,mpl,geom,fld,alpha)
3087 implicit none
3088 
3089 ! Passed variables
3090 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3091 type(mpl_type),intent(in) :: mpl ! MPI data
3092 type(geom_type),intent(in) :: geom ! Geometry
3093 real(kind_real),intent(in) :: fld(geom%nc0a,geom%nl0) ! Field
3094 real(kind_real),intent(out) :: alpha(nicas_blk%nsa) ! Subgrid field
3095 
3096 ! Local variable
3097 real(kind_real) :: alpha_b(nicas_blk%nsb),alpha_c(nicas_blk%nsc)
3098 
3099 ! Adjoint interpolation
3100 call nicas_blk%apply_interp_ad(mpl,geom,fld,alpha_b)
3101 
3102 ! Halo reduction from zone B to zone A
3103 call nicas_blk%com_AB%red(mpl,alpha_b,alpha)
3104 
3105 ! Initialization
3106 alpha_c = 0.0
3107 
3108 ! Copy zone A into zone C
3109 alpha_c(nicas_blk%sa_to_sc) = alpha
3110 
3111 ! Convolution
3112 call nicas_blk%apply_convol(mpl,alpha_c)
3113 
3114 ! Halo reduction from zone C to zone A
3115 call nicas_blk%com_AC%red(mpl,alpha_c,alpha)
3116 
3117 end subroutine nicas_blk_apply_sqrt_ad
3118 
3119 !----------------------------------------------------------------------
3120 ! Subroutine: nicas_blk_apply_interp
3121 ! Purpose: apply interpolation
3122 !----------------------------------------------------------------------
3123 subroutine nicas_blk_apply_interp(nicas_blk,mpl,geom,alpha,fld)
3125 implicit none
3126 
3127 ! Passed variables
3128 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3129 type(mpl_type),intent(in) :: mpl ! MPI data
3130 type(geom_type),intent(in) :: geom ! Geometry
3131 real(kind_real),intent(in) :: alpha(nicas_blk%nsb) ! Subgrid field
3132 real(kind_real),intent(out) :: fld(geom%nc0a,geom%nl0) ! Field
3133 
3134 ! Local variables
3135 real(kind_real) :: gamma(nicas_blk%nc1b,nicas_blk%nl1),delta(nicas_blk%nc1b,geom%nl0)
3136 
3137 ! Subsampling horizontal interpolation
3138 call nicas_blk%apply_interp_s(mpl,alpha,gamma)
3139 
3140 ! Vertical interpolation
3141 call nicas_blk%apply_interp_v(mpl,geom,gamma,delta)
3142 
3143 ! Horizontal interpolation
3144 call nicas_blk%apply_interp_h(mpl,geom,delta,fld)
3145 
3146 ! Normalization
3147 fld = fld*nicas_blk%norm
3148 
3149 end subroutine nicas_blk_apply_interp
3150 
3151 !----------------------------------------------------------------------
3152 ! Subroutine: nicas_blk_apply_interp_ad
3153 ! Purpose: apply interpolation adjoint
3154 !----------------------------------------------------------------------
3155 subroutine nicas_blk_apply_interp_ad(nicas_blk,mpl,geom,fld,alpha)
3157 implicit none
3158 
3159 ! Passed variables
3160 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3161 type(mpl_type),intent(in) :: mpl ! MPI data
3162 type(geom_type),intent(in) :: geom ! Geometry
3163 real(kind_real),intent(in) :: fld(geom%nc0a,geom%nl0) ! Field
3164 real(kind_real),intent(out) :: alpha(nicas_blk%nsb) ! Subgrid field
3165 
3166 ! Local variables
3167 real(kind_real) :: gamma(nicas_blk%nc1b,nicas_blk%nl1),delta(nicas_blk%nc1b,geom%nl0)
3168 real(kind_real) :: fld_tmp(geom%nc0a,geom%nl0)
3169 
3170 ! Normalization
3171 fld_tmp = fld*nicas_blk%norm
3172 
3173 ! Horizontal interpolation
3174 call nicas_blk%apply_interp_h_ad(mpl,geom,fld_tmp,delta)
3175 
3176 ! Vertical interpolation
3177 call nicas_blk%apply_interp_v_ad(mpl,geom,delta,gamma)
3178 
3179 ! Subsampling horizontal interpolation
3180 call nicas_blk%apply_interp_s_ad(mpl,gamma,alpha)
3181 
3182 end subroutine nicas_blk_apply_interp_ad
3183 
3184 !----------------------------------------------------------------------
3185 ! Subroutine: nicas_blk_apply_interp_h
3186 ! Purpose: apply horizontal interpolation
3187 !----------------------------------------------------------------------
3188 subroutine nicas_blk_apply_interp_h(nicas_blk,mpl,geom,delta,fld)
3190 implicit none
3191 
3192 ! Passed variables
3193 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3194 type(mpl_type),intent(in) :: mpl ! MPI data
3195 type(geom_type),intent(in) :: geom ! Geometry
3196 real(kind_real),intent(in) :: delta(nicas_blk%nc1b,geom%nl0) ! Subset Sc1 field, full levels
3197 real(kind_real),intent(out) :: fld(geom%nc0a,geom%nl0) ! Field
3198 
3199 ! Local variables
3200 integer :: il0
3201 
3202 ! Horizontal interpolation
3203 !$omp parallel do schedule(static) private(il0)
3204 do il0=1,geom%nl0
3205  call nicas_blk%h(min(il0,geom%nl0i))%apply(mpl,delta(:,il0),fld(:,il0),msdst=.false.)
3206 end do
3207 !$omp end parallel do
3208 
3209 end subroutine nicas_blk_apply_interp_h
3210 
3211 !----------------------------------------------------------------------
3212 ! Subroutine: nicas_blk_apply_interp_h_ad
3213 ! Purpose: apply horizontal interpolation adjoint
3214 !----------------------------------------------------------------------
3215 subroutine nicas_blk_apply_interp_h_ad(nicas_blk,mpl,geom,fld,delta)
3217 implicit none
3218 
3219 ! Passed variables
3220 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3221 type(mpl_type),intent(in) :: mpl ! MPI data
3222 type(geom_type),intent(in) :: geom ! Geometry
3223 real(kind_real),intent(in) :: fld(geom%nc0a,geom%nl0) ! Field
3224 real(kind_real),intent(out) :: delta(nicas_blk%nc1b,geom%nl0) ! Subset Sc1 field, full levels
3225 
3226 ! Local variables
3227 integer :: il0
3228 
3229 !$omp parallel do schedule(static) private(il0)
3230 do il0=1,geom%nl0
3231  call nicas_blk%h(min(il0,geom%nl0i))%apply_ad(mpl,fld(:,il0),delta(:,il0))
3232 end do
3233 !$omp end parallel do
3234 
3235 end subroutine nicas_blk_apply_interp_h_ad
3236 
3237 !----------------------------------------------------------------------
3238 ! Subroutine: nicas_blk_apply_interp_v
3239 ! Purpose: apply vertical interpolation
3240 !----------------------------------------------------------------------
3241 subroutine nicas_blk_apply_interp_v(nicas_blk,mpl,geom,gamma,delta)
3243 implicit none
3244 
3245 ! Passed variables
3246 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3247 type(mpl_type),intent(in) :: mpl ! MPI data
3248 type(geom_type),intent(in) :: geom ! Geometry
3249 real(kind_real),intent(in) :: gamma(nicas_blk%nc1b,nicas_blk%nl1) ! Subset Sc1 field, limited levels
3250 real(kind_real),intent(out) :: delta(nicas_blk%nc1b,geom%nl0) ! Subset Sc1 field, full levels
3251 
3252 ! Local variables
3253 integer :: ic1b
3254 real(kind_real),allocatable :: gamma_tmp(:),delta_tmp(:)
3255 
3256 ! Vertical interpolation
3257 !$omp parallel do schedule(static) private(ic1b) firstprivate(gamma_tmp,delta_tmp)
3258 do ic1b=1,nicas_blk%nc1b
3259  ! Allocation
3260  allocate(gamma_tmp(nicas_blk%nl1))
3261  allocate(delta_tmp(geom%nl0))
3262 
3263  ! Copy data
3264  gamma_tmp = gamma(ic1b,:)
3265 
3266  ! Apply interpolation
3267  call nicas_blk%v%apply(mpl,gamma_tmp,delta_tmp,ivec=ic1b,msdst=.false.)
3268 
3269  ! Copy data
3270  delta(ic1b,:) = delta_tmp
3271 
3272  ! Release memory
3273  deallocate(gamma_tmp)
3274  deallocate(delta_tmp)
3275 end do
3276 !$omp end parallel do
3277 
3278 end subroutine nicas_blk_apply_interp_v
3279 
3280 !----------------------------------------------------------------------
3281 ! Subroutine: nicas_blk_apply_interp_v_ad
3282 ! Purpose: apply vertical interpolation adjoint
3283 !----------------------------------------------------------------------
3284 subroutine nicas_blk_apply_interp_v_ad(nicas_blk,mpl,geom,delta,gamma)
3286 implicit none
3287 
3288 ! Passed variables
3289 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3290 type(mpl_type),intent(in) :: mpl ! MPI data
3291 type(geom_type),intent(in) :: geom ! Geometry
3292 real(kind_real),intent(in) :: delta(nicas_blk%nc1b,geom%nl0) ! Subset Sc1 field, full levels
3293 real(kind_real),intent(out) :: gamma(nicas_blk%nc1b,nicas_blk%nl1) ! Subset Sc1 field, limited levels
3294 
3295 ! Local variables
3296 integer :: ic1b
3297 real(kind_real),allocatable :: gamma_tmp(:),delta_tmp(:)
3298 
3299 ! Vertical interpolation
3300 !$omp parallel do schedule(static) private(ic1b) firstprivate(gamma_tmp,delta_tmp)
3301 do ic1b=1,nicas_blk%nc1b
3302  ! Allocation
3303  allocate(gamma_tmp(nicas_blk%nl1))
3304  allocate(delta_tmp(geom%nl0))
3305 
3306  ! Copy data
3307  delta_tmp = delta(ic1b,:)
3308 
3309  ! Apply interpolation
3310  call nicas_blk%v%apply_ad(mpl,delta_tmp,gamma_tmp,ivec=ic1b)
3311 
3312  ! Copy data
3313  gamma(ic1b,:) = gamma_tmp
3314 
3315  ! Release memory
3316  deallocate(gamma_tmp)
3317  deallocate(delta_tmp)
3318 end do
3319 !$omp end parallel do
3320 
3321 end subroutine nicas_blk_apply_interp_v_ad
3322 
3323 !----------------------------------------------------------------------
3324 ! Subroutine: nicas_blk_apply_interp_s
3325 ! Purpose: apply subsampling interpolation
3326 !----------------------------------------------------------------------
3327 subroutine nicas_blk_apply_interp_s(nicas_blk,mpl,alpha,gamma)
3329 implicit none
3330 
3331 ! Passed variables
3332 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3333 type(mpl_type),intent(in) :: mpl ! MPI data
3334 real(kind_real),intent(in) :: alpha(nicas_blk%nsb) ! Subgrid field
3335 real(kind_real),intent(out) :: gamma(nicas_blk%nc1b,nicas_blk%nl1) ! Subset Sc1 field, limited levels
3336 
3337 ! Local variables
3338 integer :: isb,il1
3339 real(kind_real) :: beta(nicas_blk%nc1b,nicas_blk%nl1)
3340 
3341 ! Initialization
3342 beta = 0.0
3343 
3344 ! Copy
3345 !$omp parallel do schedule(static) private(isb)
3346 do isb=1,nicas_blk%nsb
3347  beta(nicas_blk%sb_to_c1b(isb),nicas_blk%sb_to_l1(isb)) = alpha(isb)
3348 end do
3349 !$omp end parallel do
3350 
3351 ! Subsampling horizontal interpolation
3352 !$omp parallel do schedule(static) private(il1)
3353 do il1=1,nicas_blk%nl1
3354  call nicas_blk%s(il1)%apply(mpl,beta(:,il1),gamma(:,il1),msdst=.false.)
3355 end do
3356 !$omp end parallel do
3357 
3358 end subroutine nicas_blk_apply_interp_s
3359 
3360 !----------------------------------------------------------------------
3361 ! Subroutine: nicas_blk_apply_interp_s_ad
3362 ! Purpose: apply subsampling interpolation adjoint
3363 !----------------------------------------------------------------------
3364 subroutine nicas_blk_apply_interp_s_ad(nicas_blk,mpl,gamma,alpha)
3366 implicit none
3367 
3368 ! Passed variables
3369 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3370 type(mpl_type),intent(in) :: mpl ! MPI data
3371 real(kind_real),intent(in) :: gamma(nicas_blk%nc1b,nicas_blk%nl1) ! Subset Sc1 field, limited levels
3372 real(kind_real),intent(out) :: alpha(nicas_blk%nsb) ! Subgrid field
3373 
3374 ! Local variables
3375 integer :: il1,isb
3376 real(kind_real) :: beta(nicas_blk%nc1b,nicas_blk%nl1)
3377 
3378 ! Subsampling horizontal interpolation
3379 !$omp parallel do schedule(static) private(il1)
3380 do il1=1,nicas_blk%nl1
3381  call nicas_blk%s(il1)%apply_ad(mpl,gamma(:,il1),beta(:,il1))
3382 end do
3383 !$omp end parallel do
3384 
3385 ! Copy
3386 !$omp parallel do schedule(static) private(isb)
3387 do isb=1,nicas_blk%nsb
3388  alpha(isb) = beta(nicas_blk%sb_to_c1b(isb),nicas_blk%sb_to_l1(isb))
3389 end do
3390 !$omp end parallel do
3391 
3392 end subroutine nicas_blk_apply_interp_s_ad
3393 
3394 !----------------------------------------------------------------------
3395 ! Subroutine: nicas_blk_apply_convol
3396 ! Purpose: apply convolution
3397 !----------------------------------------------------------------------
3398 subroutine nicas_blk_apply_convol(nicas_blk,mpl,alpha)
3400 implicit none
3401 
3402 ! Passed variables
3403 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3404 type(mpl_type),intent(in) :: mpl ! MPI data
3405 real(kind_real),intent(inout) :: alpha(nicas_blk%nsc) ! Subgrid field
3406 
3407 ! Apply linear operator, symmetric
3408 call nicas_blk%c%apply_sym(mpl,alpha)
3409 
3410 end subroutine nicas_blk_apply_convol
3411 
3412 !----------------------------------------------------------------------
3413 ! Subroutine: nicas_blk_apply_adv
3414 ! Purpose: apply advection
3415 !----------------------------------------------------------------------
3416 subroutine nicas_blk_apply_adv(nicas_blk,mpl,nam,geom,fld)
3418 implicit none
3419 
3420 ! Passed variables
3421 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3422 type(mpl_type),intent(in) :: mpl ! MPI data
3423 type(nam_type),target,intent(in) :: nam ! Namelist
3424 type(geom_type),target,intent(in) :: geom ! Geometry
3425 real(kind_real),intent(inout) :: fld(geom%nc0a,geom%nl0,nam%nv,nam%nts) ! Field
3426 
3427 ! Local variables
3428 integer :: its,iv,il0
3429 real(kind_real) :: fld_d(nicas_blk%nc0d,geom%nl0)
3430 
3431 do its=2,nam%nts
3432  do iv=1,nam%nv
3433  ! Halo extension from zone A to zone D
3434  call nicas_blk%com_AD%ext(mpl,geom%nl0,fld(:,:,iv,its),fld_d)
3435 
3436  ! Interpolation
3437  !$omp parallel do schedule(static) private(il0)
3438  do il0=1,geom%nl0
3439  call nicas_blk%d(il0,its)%apply(mpl,fld_d(:,il0),fld(:,il0,iv,its),msdst=.false.)
3440  end do
3441  !$omp end parallel do
3442  end do
3443 end do
3444 
3445 end subroutine nicas_blk_apply_adv
3446 
3447 !----------------------------------------------------------------------
3448 ! Subroutine: nicas_blk_apply_adv_ad
3449 ! Purpose: apply advection
3450 !----------------------------------------------------------------------
3451 subroutine nicas_blk_apply_adv_ad(nicas_blk,mpl,nam,geom,fld)
3453 implicit none
3454 
3455 ! Passed variables
3456 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3457 type(mpl_type),intent(in) :: mpl ! MPI data
3458 type(nam_type),target,intent(in) :: nam ! Namelist
3459 type(geom_type),target,intent(in) :: geom ! Geometry
3460 real(kind_real),intent(inout) :: fld(geom%nc0a,geom%nl0,nam%nv,nam%nts) ! Field
3461 
3462 ! Local variables
3463 integer :: its,iv,il0
3464 real(kind_real) :: fld_d(nicas_blk%nc0d,geom%nl0)
3465 
3466 do its=2,nam%nts
3467  do iv=1,nam%nv
3468  ! Adjoint interpolation
3469  !$omp parallel do schedule(static) private(il0)
3470  do il0=1,geom%nl0
3471  call nicas_blk%d(il0,its)%apply_ad(mpl,fld(:,il0,iv,its),fld_d(:,il0))
3472  end do
3473  !$omp end parallel do
3474 
3475  ! Halo reduction from zone D to zone A
3476  call nicas_blk%com_AD%red(mpl,geom%nl0,fld_d,fld(:,:,iv,its))
3477  end do
3478 end do
3479 
3480 end subroutine nicas_blk_apply_adv_ad
3481 
3482 !----------------------------------------------------------------------
3483 ! Subroutine: nicas_blk_apply_adv_inv
3484 ! Purpose: apply inverse advection
3485 !----------------------------------------------------------------------
3486 subroutine nicas_blk_apply_adv_inv(nicas_blk,mpl,nam,geom,fld)
3488 implicit none
3489 
3490 ! Passed variables
3491 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3492 type(mpl_type),intent(in) :: mpl ! MPI data
3493 type(nam_type),target,intent(in) :: nam ! Namelist
3494 type(geom_type),target,intent(in) :: geom ! Geometry
3495 real(kind_real),intent(inout) :: fld(geom%nc0a,geom%nl0,nam%nv,nam%nts) ! Field
3496 
3497 ! Local variables
3498 integer :: its,iv,il0
3499 real(kind_real) :: fld_dinv(nicas_blk%nc0dinv,geom%nl0)
3500 
3501 do its=2,nam%nts
3502  do iv=1,nam%nv
3503  ! Halo extension from zone A to zone Dinv
3504  call nicas_blk%com_ADinv%ext(mpl,geom%nl0,fld(:,:,iv,its),fld_dinv)
3505 
3506  ! Interpolation
3507  !$omp parallel do schedule(static) private(il0)
3508  do il0=1,geom%nl0
3509  call nicas_blk%dinv(il0,its)%apply(mpl,fld_dinv(:,il0),fld(:,il0,iv,its),msdst=.false.)
3510  end do
3511  !$omp end parallel do
3512  end do
3513 end do
3514 
3515 end subroutine nicas_blk_apply_adv_inv
3516 
3517 !----------------------------------------------------------------------
3518 ! Subroutine: nicas_blk_test_adjoint
3519 ! Purpose: test NICAS adjoint accuracy
3520 !----------------------------------------------------------------------
3521 subroutine nicas_blk_test_adjoint(nicas_blk,mpl,rng,nam,geom)
3523 implicit none
3524 
3525 ! Passed variables
3526 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3527 type(mpl_type),intent(inout) :: mpl ! MPI data
3528 type(rng_type),intent(inout) :: rng ! Random number generator
3529 type(nam_type),intent(in) :: nam ! Namelist
3530 type(geom_type),intent(in) :: geom ! Geometry
3531 
3532 ! Local variables
3533 integer :: isb
3534 real(kind_real) :: sum1,sum2
3535 real(kind_real),allocatable :: alpha(:),alpha_save(:),alpha1(:),alpha1_save(:),alpha2(:),alpha2_save(:)
3536 real(kind_real),allocatable :: gamma(:,:),gamma_save(:,:),delta(:,:),delta_save(:,:)
3537 real(kind_real),allocatable :: fld(:,:),fld_save(:,:),fld1(:,:),fld1_save(:,:),fld2(:,:),fld2_save(:,:)
3538 
3539 ! Allocation
3540 allocate(alpha(nicas_blk%nsb))
3541 allocate(alpha_save(nicas_blk%nsb))
3542 allocate(gamma(nicas_blk%nc1b,nicas_blk%nl1))
3543 allocate(gamma_save(nicas_blk%nc1b,nicas_blk%nl1))
3544 allocate(delta(nicas_blk%nc1b,geom%nl0))
3545 allocate(delta_save(nicas_blk%nc1b,geom%nl0))
3546 allocate(fld(geom%nc0a,geom%nl0))
3547 allocate(fld_save(geom%nc0a,geom%nl0))
3548 
3549 ! Interpolation (subsampling)
3550 
3551 ! Initialization
3552 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha_save)
3553 gamma_save = 0
3554 do isb=1,nicas_blk%nsb
3555  call rng%rand_real(0.0_kind_real,1.0_kind_real,gamma_save(nicas_blk%sb_to_c1b(isb),nicas_blk%sb_to_l1(isb)))
3556 end do
3557 
3558 ! Adjoint test
3559 call nicas_blk%apply_interp_s(mpl,alpha_save,gamma)
3560 call nicas_blk%apply_interp_s_ad(mpl,gamma_save,alpha)
3561 
3562 ! Print result
3563 call mpl%dot_prod(alpha,alpha_save,sum1)
3564 call mpl%dot_prod(gamma,gamma_save,sum2)
3565 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Interpolation adjoint test (subsampling): ', &
3566  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3567 call flush(mpl%info)
3568 
3569 ! Interpolation (vertical)
3570 
3571 ! Initialization
3572 call rng%rand_real(0.0_kind_real,1.0_kind_real,gamma_save)
3573 call rng%rand_real(0.0_kind_real,1.0_kind_real,delta_save)
3574 
3575 ! Adjoint test
3576 call nicas_blk%apply_interp_v(mpl,geom,gamma_save,delta)
3577 call nicas_blk%apply_interp_v_ad(mpl,geom,delta_save,gamma)
3578 
3579 ! Print result
3580 call mpl%dot_prod(gamma,gamma_save,sum1)
3581 call mpl%dot_prod(delta,delta_save,sum2)
3582 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Interpolation adjoint test (vertical): ', &
3583  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3584 call flush(mpl%info)
3585 
3586 ! Interpolation (horizontal)
3587 
3588 ! Initialization
3589 call rng%rand_real(0.0_kind_real,1.0_kind_real,delta_save)
3590 call rng%rand_real(0.0_kind_real,1.0_kind_real,fld_save)
3591 
3592 ! Adjoint test
3593 call nicas_blk%apply_interp_h(mpl,geom,delta_save,fld)
3594 call nicas_blk%apply_interp_h_ad(mpl,geom,fld_save,delta)
3595 
3596 ! Print result
3597 call mpl%dot_prod(delta,delta_save,sum1)
3598 call mpl%dot_prod(fld,fld_save,sum2)
3599 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Interpolation adjoint test (horizontal): ', &
3600  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3601 call flush(mpl%info)
3602 
3603 ! Interpolation (total)
3604 
3605 ! Initialization
3606 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha_save)
3607 call rng%rand_real(0.0_kind_real,1.0_kind_real,fld_save)
3608 
3609 ! Adjoint test
3610 call nicas_blk%apply_interp(mpl,geom,alpha_save,fld)
3611 call nicas_blk%apply_interp_ad(mpl,geom,fld_save,alpha)
3612 
3613 ! Print result
3614 call mpl%dot_prod(alpha,alpha_save,sum1)
3615 call mpl%dot_prod(fld,fld_save,sum2)
3616 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Interpolation adjoint test (total): ', &
3617  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3618 call flush(mpl%info)
3619 
3620 ! Allocation
3621 allocate(alpha1(nicas_blk%nsc))
3622 allocate(alpha1_save(nicas_blk%nsc))
3623 allocate(alpha2(nicas_blk%nsc))
3624 allocate(alpha2_save(nicas_blk%nsc))
3625 
3626 ! Initialization
3627 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha1_save)
3628 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha2_save)
3629 alpha1 = alpha1_save
3630 alpha2 = alpha2_save
3631 
3632 ! Adjoint test
3633 call nicas_blk%apply_convol(mpl,alpha1)
3634 call nicas_blk%apply_convol(mpl,alpha2)
3635 
3636 ! Print result
3637 call mpl%dot_prod(alpha1,alpha2_save,sum1)
3638 call mpl%dot_prod(alpha2,alpha1_save,sum2)
3639 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Convolution adjoint test: ', &
3640  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3641 call flush(mpl%info)
3642 
3643 ! Allocation
3644 deallocate(alpha1)
3645 deallocate(alpha1_save)
3646 deallocate(alpha2)
3647 deallocate(alpha2_save)
3648 allocate(alpha1(nicas_blk%nsa))
3649 allocate(alpha1_save(nicas_blk%nsb))
3650 allocate(alpha2(nicas_blk%nsb))
3651 allocate(alpha2_save(nicas_blk%nsa))
3652 
3653 ! Initialization
3654 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha1_save)
3655 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha2_save)
3656 
3657 ! Adjoint test
3658 call nicas_blk%com_AB%red(mpl,alpha1_save,alpha1)
3659 call nicas_blk%com_AB%ext(mpl,alpha2_save,alpha2)
3660 
3661 ! Print result
3662 call mpl%dot_prod(alpha1,alpha2_save,sum1)
3663 call mpl%dot_prod(alpha2,alpha1_save,sum2)
3664 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Communication AB adjoint test: ', &
3665  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3666 call flush(mpl%info)
3667 
3668 ! Allocation
3669 deallocate(alpha1)
3670 deallocate(alpha1_save)
3671 deallocate(alpha2)
3672 deallocate(alpha2_save)
3673 allocate(alpha1(nicas_blk%nsa))
3674 allocate(alpha1_save(nicas_blk%nsc))
3675 allocate(alpha2(nicas_blk%nsc))
3676 allocate(alpha2_save(nicas_blk%nsa))
3677 
3678 ! Initialization
3679 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha1_save)
3680 call rng%rand_real(0.0_kind_real,1.0_kind_real,alpha2_save)
3681 
3682 ! Adjoint test
3683 call nicas_blk%com_AC%red(mpl,alpha1_save,alpha1)
3684 call nicas_blk%com_AC%ext(mpl,alpha2_save,alpha2)
3685 
3686 ! Print result
3687 call mpl%dot_prod(alpha1,alpha2_save,sum1)
3688 call mpl%dot_prod(alpha2,alpha1_save,sum2)
3689 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','Communication AC adjoint test: ', &
3690  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3691 call flush(mpl%info)
3692 
3693 ! Allocation
3694 allocate(fld1(geom%nc0a,geom%nl0))
3695 allocate(fld2(geom%nc0a,geom%nl0))
3696 allocate(fld1_save(geom%nc0,geom%nl0))
3697 allocate(fld2_save(geom%nc0,geom%nl0))
3698 
3699 ! Generate random field
3700 call rng%rand_real(0.0_kind_real,1.0_kind_real,fld1_save)
3701 call rng%rand_real(0.0_kind_real,1.0_kind_real,fld2_save)
3702 fld1 = fld1_save
3703 fld2 = fld2_save
3704 
3705 ! Adjoint test
3706 if (nam%lsqrt) then
3707  call nicas_blk%apply_from_sqrt(mpl,geom,fld1)
3708  call nicas_blk%apply_from_sqrt(mpl,geom,fld2)
3709 else
3710  call nicas_blk%apply(mpl,nam,geom,fld1)
3711  call nicas_blk%apply(mpl,nam,geom,fld2)
3712 end if
3713 
3714 ! Print result
3715 call mpl%dot_prod(fld1,fld2_save,sum1)
3716 call mpl%dot_prod(fld2,fld1_save,sum2)
3717 write(mpl%info,'(a7,a,e15.8,a,e15.8,a,e15.8)') '','NICAS adjoint test: ', &
3718  & sum1,' / ',sum2,' / ',2.0*abs(sum1-sum2)/abs(sum1+sum2)
3719 call flush(mpl%info)
3720 
3721 end subroutine nicas_blk_test_adjoint
3722 
3723 !----------------------------------------------------------------------
3724 ! Subroutine: nicas_blk_test_pos_def
3725 ! Purpose: test positive_definiteness
3726 !----------------------------------------------------------------------
3727 subroutine nicas_blk_test_pos_def(nicas_blk,mpl,rng,nam,geom)
3729 implicit none
3730 
3731 ! Passed variables
3732 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3733 type(mpl_type),intent(in) :: mpl ! MPI data
3734 type(rng_type),intent(inout) :: rng ! Random number generator
3735 type(nam_type),intent(in) :: nam ! Namelist
3736 type(geom_type),intent(in) :: geom ! Geometry
3737 
3738 ! Local variables
3739 integer :: iter
3740 real(kind_real) :: norm,num,den,egvmax,egvmax_prev,egvmin,egvmin_prev
3741 real(kind_real) :: fld(geom%nc0a,geom%nl0),fld_prev(geom%nc0a,geom%nl0)
3742 
3743 ! Power method to find the largest eigenvalue
3744 call rng%rand_real(0.0_kind_real,1.0_kind_real,fld_prev)
3745 call mpl%dot_prod(fld_prev,fld_prev,norm)
3746 fld_prev = fld_prev/norm
3747 egvmax_prev = huge(1.0)
3748 iter = 1
3749 do while (iter<=nitermax)
3750  ! Copy vector
3751  fld = fld_prev
3752 
3753  ! Apply NICAS
3754  if (nam%lsqrt) then
3755  call nicas_blk%apply_from_sqrt(mpl,geom,fld)
3756  else
3757  call nicas_blk%apply(mpl,nam,geom,fld)
3758  end if
3759 
3760  ! Compute Rayleigh quotient
3761  call mpl%dot_prod(fld,fld_prev,num)
3762  call mpl%dot_prod(fld_prev,fld_prev,den)
3763  egvmax = num/den
3764 
3765  ! Renormalize the vector
3766  call mpl%dot_prod(fld,fld,norm)
3767  fld = fld/norm
3768 
3769  ! Exit test
3770  if (abs(egvmax-egvmax_prev)<tol) exit
3771 
3772  ! Update
3773  iter = iter+1
3774  fld_prev = fld
3775  egvmax_prev = egvmax
3776 end do
3777 
3778 ! Power method to find the smallest eigenvalue
3779 call rng%rand_real(0.0_kind_real,1.0_kind_real,fld_prev)
3780 call mpl%dot_prod(fld_prev,fld_prev,norm)
3781 egvmin_prev = huge(1.0)
3782 fld_prev = fld_prev/norm
3783 egvmin_prev = huge(1.0)
3784 iter = 1
3785 do while (iter<=nitermax)
3786  ! Copy vector
3787  fld = fld_prev
3788 
3789  ! Apply C
3790  if (nam%lsqrt) then
3791  call nicas_blk%apply_from_sqrt(mpl,geom,fld)
3792  else
3793  call nicas_blk%apply(mpl,nam,geom,fld)
3794  end if
3795  fld = fld-egvmax*fld_prev
3796 
3797  ! Compute Rayleigh quotient
3798  call mpl%dot_prod(fld,fld_prev,num)
3799  call mpl%dot_prod(fld_prev,fld_prev,den)
3800  egvmin = num/den
3801 
3802  ! Renormalize the vector
3803  call mpl%dot_prod(fld,fld,norm)
3804  fld = fld/norm
3805 
3806  ! Exit test
3807  if (egvmax+egvmin<-tol*egvmax) then
3808  write(mpl%info,'(a7,a)') '','NICAS is not positive definite'
3809  call flush(mpl%info)
3810  exit
3811  end if
3812 
3813  ! Update
3814  iter = iter+1
3815  fld_prev = fld
3816  egvmin_prev = egvmin
3817 end do
3818 
3819 ! Non conclusive test
3820 if (iter==nitermax+1) write(mpl%info,'(a7,a,e15.8,a,i4,a,e15.8)') '','NICAS seems to be positive definite: difference ', &
3821  & egvmax+egvmin,' after ',nitermax,' iterations for a tolerance ',tol
3822 call flush(mpl%info)
3823 
3824 end subroutine nicas_blk_test_pos_def
3825 
3826 !----------------------------------------------------------------------
3827 ! Subroutine: nicas_blk_test_sqrt
3828 ! Purpose: test full/square-root equivalence
3829 !----------------------------------------------------------------------
3830 subroutine nicas_blk_test_sqrt(nicas_blk,mpl,rng,nam,geom,bpar,io,cmat_blk)
3832 implicit none
3833 
3834 ! Passed variables
3835 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3836 type(mpl_type),intent(inout) :: mpl ! MPI data
3837 type(rng_type),intent(inout) :: rng ! Random number generator
3838 type(nam_type),intent(inout) :: nam ! Namelist
3839 type(geom_type),intent(in) :: geom ! Geometry
3840 type(bpar_type),intent(in) :: bpar ! Block parameters
3841 type(io_type),intent(in) :: io ! I/O
3842 type(cmat_blk_type),intent(in) :: cmat_blk ! C matrix data block
3843 
3844 ! Local variables
3845 real(kind_real) :: fld(geom%nc0a,geom%nl0),fld_sqrt(geom%nc0a,geom%nl0)
3846 type(nicas_blk_type) :: nicas_blk_other
3847 
3848 ! Associate
3849 associate(ib=>nicas_blk%ib)
3850 
3851 ! Generate random field
3852 call rng%rand_real(-1.0_kind_real,1.0_kind_real,fld)
3853 fld_sqrt = fld
3854 
3855 ! Apply NICAS, initial version
3856 if (nam%lsqrt) then
3857  call nicas_blk%apply_from_sqrt(mpl,geom,fld_sqrt)
3858 else
3859  call nicas_blk%apply(mpl,nam,geom,fld)
3860 end if
3861 
3862 ! Switch lsqrt
3863 nam%lsqrt = .not.nam%lsqrt
3864 
3865 ! Compute NICAS parameters
3866 call nicas_blk_other%compute_parameters(mpl,rng,nam,geom,cmat_blk)
3867 
3868 ! Apply NICAS, other version
3869 if (nam%lsqrt) then
3870  call nicas_blk_other%apply_from_sqrt(mpl,geom,fld_sqrt)
3871 else
3872  ! Apply NICAS
3873  call nicas_blk_other%apply(mpl,nam,geom,fld)
3874 end if
3875 
3876 ! Compute dirac
3877 if (nam%check_dirac) call nicas_blk_other%test_dirac(mpl,nam,geom,bpar,io)
3878 
3879 ! Reset lsqrt value
3880 nam%lsqrt = .not.nam%lsqrt
3881 
3882 ! Print difference
3883 write(mpl%info,'(a7,a,f6.1,a)') '','NICAS full / square-root error:',sqrt(sum((fld_sqrt-fld)**2)/sum(fld**2))*100.0,'%'
3884 call flush(mpl%info)
3885 
3886 ! End associate
3887 end associate
3888 
3889 end subroutine nicas_blk_test_sqrt
3890 
3891 !----------------------------------------------------------------------
3892 ! Subroutine: nicas_blk_test_dirac
3893 ! Purpose: apply NICAS to diracs
3894 !----------------------------------------------------------------------
3895 subroutine nicas_blk_test_dirac(nicas_blk,mpl,nam,geom,bpar,io)
3897 implicit none
3898 
3899 ! Passed variables
3900 class(nicas_blk_type),intent(in) :: nicas_blk ! NICAS data block
3901 type(mpl_type),intent(inout) :: mpl ! MPI data
3902 type(nam_type),intent(in) :: nam ! Namelist
3903 type(geom_type),intent(in) :: geom ! Geometry
3904 type(bpar_type),intent(in) :: bpar ! Block parameters
3905 type(io_type),intent(in) :: io ! I/O
3906 
3907 ! Local variables
3908 integer :: il0,idir
3909 real(kind_real) :: val,valmin_tot,valmax_tot
3910 real(kind_real) :: fld(geom%nc0a,geom%nl0)
3911 character(len=1024) :: suffix,filename
3912 
3913 ! Associate
3914 associate(ib=>nicas_blk%ib)
3915 
3916 ! Generate dirac field
3917 fld = 0.0
3918 do idir=1,geom%ndir
3919  if (geom%iprocdir(idir)==mpl%myproc) fld(geom%ic0adir(idir),geom%il0dir(idir)) = 1.0
3920 end do
3921 
3922 ! Apply NICAS method
3923 if (nam%lsqrt) then
3924  call nicas_blk%apply_from_sqrt(mpl,geom,fld)
3925 else
3926  call nicas_blk%apply(mpl,nam,geom,fld)
3927 end if
3928 
3929 if (nam%lsqrt) then
3930  suffix = '_sqrt'
3931 else
3932  suffix = ''
3933 end if
3934 
3935 ! Write field
3936 filename = trim(nam%prefix)//'_dirac'
3937 call io%fld_write(mpl,nam,geom,filename,trim(bpar%blockname(ib))//'_dirac'//trim(suffix),fld)
3938 
3939 ! Print results
3940 write(mpl%info,'(a7,a)') '','Values at dirac points:'
3941 call flush(mpl%info)
3942 do idir=1,geom%ndir
3943  if (geom%iprocdir(idir)==mpl%myproc) val = fld(geom%ic0adir(idir),geom%il0dir(idir))
3944  call mpl%f_comm%broadcast(val,geom%iprocdir(idir)-1)
3945  write(mpl%info,'(a10,f6.1,a,f6.1,a,f10.7)') '',geom%londir(idir)*rad2deg,' / ',geom%latdir(idir)*rad2deg,': ',val
3946  call flush(mpl%info)
3947 end do
3948 write(mpl%info,'(a7,a)') '','Min - max: '
3949 call flush(mpl%info)
3950 do il0=1,geom%nl0
3951  call mpl%f_comm%allreduce(minval(fld(:,il0),mask=geom%mask_c0a(:,il0)),valmin_tot,fckit_mpi_min())
3952  call mpl%f_comm%allreduce(maxval(fld(:,il0),mask=geom%mask_c0a(:,il0)),valmax_tot,fckit_mpi_max())
3953  write(mpl%info,'(a10,a,i3,a,f10.7,a,f10.7)') '','Level ',nam%levs(il0),': ',valmin_tot,' - ',valmax_tot
3954  call flush(mpl%info)
3955 end do
3956 
3957 ! End associate
3958 end associate
3959 
3960 end subroutine nicas_blk_test_dirac
3961 
3962 end module type_nicas_blk
subroutine nicas_blk_compute_adv(nicas_blk, mpl, rng, nam, geom, cmat_blk)
subroutine nicas_blk_compute_convol_weights(nicas_blk, mpl, nam, geom, ctmp)
subroutine nicas_blk_compute_parameters(nicas_blk, mpl, rng, nam, geom, cmat_blk)
logical, parameter write_grids
subroutine nicas_blk_apply_interp_s_ad(nicas_blk, mpl, gamma, alpha)
real(kind_real), parameter, public gc2gau
Definition: tools_func.F90:19
subroutine nicas_blk_test_pos_def(nicas_blk, mpl, rng, nam, geom)
subroutine nicas_blk_apply(nicas_blk, mpl, nam, geom, fld)
subroutine nicas_blk_apply_adv(nicas_blk, mpl, nam, geom, fld)
subroutine nicas_blk_apply_interp_ad(nicas_blk, mpl, geom, fld, alpha)
real(kind_real), parameter, public rad2deg
Definition: tools_const.F90:17
subroutine nicas_blk_apply_interp_s(nicas_blk, mpl, alpha, gamma)
subroutine nicas_blk_apply_sqrt(nicas_blk, mpl, geom, alpha, fld)
subroutine nicas_blk_apply_convol(nicas_blk, mpl, alpha)
real(kind_real) function, public gc99(mpl, distnorm)
Definition: tools_func.F90:518
real(kind_real), parameter sqrt_r_dble
subroutine nicas_blk_compute_convol_distance(nicas_blk, mpl, geom)
subroutine balldata_alloc(balldata)
real(kind_real), parameter, public msvalr
Definition: tools_const.F90:24
subroutine nicas_blk_test_sqrt(nicas_blk, mpl, rng, nam, geom, bpar, io, cmat_blk)
subroutine nicas_blk_test_adjoint(nicas_blk, mpl, rng, nam, geom)
subroutine, public lonlatmod(lon, lat)
Definition: tools_func.F90:37
subroutine nicas_blk_compute_interp_h(nicas_blk, mpl, rng, nam, geom)
subroutine nicas_blk_compute_convol(nicas_blk, mpl, rng, nam, geom, cmat_blk)
subroutine nicas_blk_apply_sqrt_ad(nicas_blk, mpl, geom, fld, alpha)
subroutine nicas_blk_dealloc(nicas_blk, nam, geom)
subroutine, public vector_product(v1, v2, vp)
Definition: tools_func.F90:131
integer, parameter nc1max
real(kind_real), parameter tol
logical function, public supeq(x, y)
subroutine nicas_blk_compute_interp_s(nicas_blk, mpl, rng, nam, geom)
subroutine, public sphere_dist(lon_i, lat_i, lon_f, lat_f, dist)
Definition: tools_func.F90:67
subroutine nicas_blk_compute_interp_v(nicas_blk, geom)
real(kind_real), parameter sqrt_r
logical, parameter test_no_point
subroutine nicas_blk_compute_convol_network(nicas_blk, mpl, rng, nam, geom)
subroutine nicas_blk_apply_interp(nicas_blk, mpl, geom, alpha, fld)
subroutine nicas_blk_test_dirac(nicas_blk, mpl, nam, geom, bpar, io)
subroutine nicas_blk_apply_interp_h_ad(nicas_blk, mpl, geom, fld, delta)
real(kind_real), parameter, public deg2rad
Definition: tools_const.F90:16
real(kind=kind_real), parameter req
Earth radius at equator (m)
subroutine nicas_blk_apply_adv_ad(nicas_blk, mpl, nam, geom, fld)
subroutine nicas_blk_compute_mpi_ab(nicas_blk, mpl, geom)
subroutine nicas_blk_apply_adv_inv(nicas_blk, mpl, nam, geom, fld)
subroutine balldata_pack(balldata, nc1, nl1, val)
#define max(a, b)
Definition: mosaic_util.h:33
real(kind_real), parameter sqrt_rfac
subroutine nicas_blk_apply_from_sqrt(nicas_blk, mpl, geom, fld)
subroutine nicas_blk_compute_sampling(nicas_blk, mpl, rng, nam, geom, cmat_blk)
subroutine nicas_blk_apply_interp_h(nicas_blk, mpl, geom, delta, fld)
integer, parameter, public kind_real
subroutine nicas_blk_apply_interp_v_ad(nicas_blk, mpl, geom, delta, gamma)
#define min(a, b)
Definition: mosaic_util.h:32
real(kind_real), parameter sqrt_coef
real(kind_real), parameter s_inf
subroutine nicas_blk_compute_normalization(nicas_blk, mpl, nam, geom)
subroutine nicas_blk_compute_mpi_c(nicas_blk, mpl, geom)
integer, parameter nitermax
subroutine, public vector_triple_product(v1, v2, v3, p)
Definition: tools_func.F90:158
integer, parameter, public ncfloat
Definition: tools_nc.F90:27
subroutine nicas_blk_apply_interp_v(nicas_blk, mpl, geom, gamma, delta)
subroutine balldata_dealloc(balldata)
real(fp), parameter, public pi
real(kind_real), parameter, public reqkm
Definition: tools_const.F90:19