SABER
tools_func.F90
Go to the documentation of this file.
1 # 1 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/tools_func.fypp"
2 # 1 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/../instrumentation.fypp" 1
3 # 1 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/../subr_list.fypp" 1
4 !----------------------------------------------------------------------
5 ! Header: subr_list
6 !> Subroutines/functions list
7 ! Author: Benjamin Menetrier
8 ! Licensing: this code is distributed under the CeCILL-C license
9 ! Copyright 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
10 !----------------------------------------------------------------------
11 
12 # 726 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/../subr_list.fypp"
13 # 2 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/../instrumentation.fypp" 2
14 !----------------------------------------------------------------------
15 ! Header: instrumentation
16 !> Instrumentation functions
17 ! Author: Benjamin Menetrier
18 ! Licensing: this code is distributed under the CeCILL-C license
19 ! Copyright 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
20 !----------------------------------------------------------------------
21 
22 # 112 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/../instrumentation.fypp"
23 # 2 "/Users/miesch/JEDI/code/working_copy/public/fv3-bundle/saber/src/saber/bump/tools_func.fypp" 2
24 !----------------------------------------------------------------------
25 ! Module: tools_func
26 !> Usual functions
27 ! Author: Benjamin Menetrier
28 ! Licensing: this code is distributed under the CeCILL-C license
29 ! Copyright 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
30 !----------------------------------------------------------------------
31 module tools_func
32 
33 use atlas_module, only: atlas_geometry
34 use iso_c_binding, only: c_int16_t,c_int32_t
35 use tools_asa007, only: cholesky,syminv
38 use tools_qsort, only: qsort
39 use tools_repro, only: inf,sup,infeq,small
40 use type_mpl, only: mpl_type
41 
42 
43 implicit none
44 
45 real(kind_real),parameter :: gc2gau = 0.28_kind_real !< GC99 support radius to Gaussian Daley length-scale (empirical)
46 real(kind_real),parameter :: gau2gc = 3.57_kind_real !< Gaussian Daley length-scale to GC99 support radius (empirical)
47 real(kind_real),parameter :: dmin = 1.0e-12_kind_real !< Minimum tensor diagonal value
48 real(kind_real),parameter :: condmax = thousand !< Maximum tensor conditioning number
49 integer,parameter :: m = 0 !< Number of implicit iteration for the Matern function (0: Gaussian)
50 
51 interface
52  function c_fletcher32(n,var) bind(c,name='fletcher32') result(hash)
53  use iso_c_binding, only: c_int16_t,c_int32_t
54  integer(c_int32_t) :: n
55  integer(c_int16_t) :: var(*)
56  integer(c_int32_t) :: hash
57  end function c_fletcher32
58 end interface
59 interface fletcher32
60  module procedure func_fletcher32
61 end interface
62 interface lonlatmod
63  module procedure func_lonlatmod
64 end interface
65 interface gridhash
66  module procedure func_gridhash
67 end interface
69  module procedure func_independent_levels
70 end interface
71 interface lonlathash
72  module procedure func_lonlathash
73 end interface
74 interface sphere_dist
75  module procedure func_sphere_dist
76 end interface
77 interface lonlat2xyz
78  module procedure func_lonlat2xyz
79 end interface
80 interface xyz2lonlat
81  module procedure func_xyz2lonlat
82 end interface
83 interface vector_product
84  module procedure func_vector_product
85 end interface
86 interface det
87  module procedure func_det
88 end interface
89 interface order_cc
90  module procedure func_order_cc
91 end interface
92 interface add
93  module procedure func_add
94 end interface
95 interface divide
96  module procedure func_divide
97 end interface
98 interface fit_diag
99  module procedure func_fit_diag
100 end interface
101 interface gc99
102  module procedure func_gc99
103 end interface
104 interface fit_func
105  module procedure func_fit_func
106 end interface
107 interface fit_lct
108  module procedure func_fit_lct
109 end interface
110 interface lct_d2h
111  module procedure func_lct_d2h
112 end interface
113 interface lct_h2r
114  module procedure func_lct_h2r
115 end interface
116 interface lct_r2d
117  module procedure func_lct_r2d
118 end interface
119 interface check_cond
120  module procedure func_check_cond
121 end interface
122 interface matern
123  module procedure func_matern
124 end interface
125 interface cholesky
126  module procedure func_cholesky
127 end interface
128 interface syminv
129  module procedure func_syminv
130 end interface
131 interface histogram
132  module procedure func_histogram
133 end interface
134 interface cx_to_cxa
135  module procedure func_cx_to_cxa
136 end interface
137 interface cx_to_proc
138  module procedure func_cx_to_proc
139 end interface
140 interface cx_to_cxu
141  module procedure func_cx_to_cxu
142 end interface
143 
144 private
145 public :: gc2gau,gau2gc,dmin,m
149 
150 contains
151 
152 !----------------------------------------------------------------------
153 ! Function: func_fletcher32
154 !> Fletcher-32 checksum algorithm
155 !----------------------------------------------------------------------
156 function func_fletcher32(var) result(value)
157 
158 implicit none
159 
160 ! Passed variables
161 real(kind_real),intent(in) :: var(:) !< Variable
162 
163 ! Returned variable
164 integer :: value
165 
166 ! Set name
167 
168 
169 ! Probe in
170 
171 
172 ! Call C function
173 value = c_fletcher32(size(transfer(var,(/0_kind_short/))),transfer(var,(/0_kind_short/)))
174 
175 ! Probe out
176 
177 
178 end function func_fletcher32
179 
180 !----------------------------------------------------------------------
181 ! Subroutine: func_lonlatmod
182 !> Set latitude between -pi/2 and pi/2 and longitude between -pi and pi
183 !----------------------------------------------------------------------
184 subroutine func_lonlatmod(lon,lat)
185 
186 implicit none
187 
188 ! Passed variables
189 real(kind_real),intent(inout) :: lon !< Longitude (radians)
190 real(kind_real),intent(inout) :: lat !< Latitude (radians)
191 
192 ! Set name
193 
194 
195 ! Probe in
196 
197 
198 ! Check latitude bounds
199 if (lat>half*pi) then
200  lat = pi-lat
201  lon = lon+pi
202 elseif (lat<-half*pi) then
203  lat = -pi-lat
204  lon = lon+pi
205 end if
206 
207 ! Check longitude bounds
208 if (lon>pi) then
209  lon = lon-two*pi
210 elseif (lon<-pi) then
211  lon = lon+two*pi
212 end if
213 
214 ! Same zero longitude for poles
215 if (abs(lat)>(half-1.0e-6_kind_real)*pi) lon = zero
216 
217 ! Probe out
218 
219 
220 end subroutine func_lonlatmod
221 
222 !----------------------------------------------------------------------
223 ! Subroutine: func_gridhash
224 !> Compute grid hash profile
225 !----------------------------------------------------------------------
226 subroutine func_gridhash(ncx,nlx,lon_cx,lat_cx,mask_cx,grid_hash)
227 
228 implicit none
229 
230 ! Passed variables
231 integer,intent(in) :: ncx !< Number of points
232 integer,intent(in) :: nlx !< Number of levels
233 real(kind_real),intent(in) :: lon_cx(ncx) !< Longitude (radians)
234 real(kind_real),intent(in) :: lat_cx(ncx) !< Latitude (radians)
235 logical,intent(in) :: mask_cx(ncx,nlx) !< Mask
236 integer,intent(out) :: grid_hash(0:nlx) !< Grid hash profile
237 
238 ! Local variables
239 integer :: ilx,ncx_eff,icx_eff,icx
240 real(kind_real),allocatable :: lonlat(:)
241 
242 ! Set name
243 
244 
245 ! Probe in
246 
247 
248 do ilx=1,nlx
249  ! Count points in the mask
250  ncx_eff = count(mask_cx(:,ilx))
251 
252  if (ncx_eff>0) then
253  ! Allocation
254  allocate(lonlat(2*ncx_eff))
255 
256  ! Copy lonlat
257  icx_eff = 0
258  do icx=1,ncx
259  if (mask_cx(icx,ilx)) then
260  icx_eff = icx_eff+1
261  lonlat(icx_eff) = lon_cx(icx)
262  icx_eff = icx_eff+1
263  lonlat(icx_eff) = lat_cx(icx)
264  end if
265  end do
266 
267  ! Compute hash
268  grid_hash(ilx) = fletcher32(lonlat)
269 
270  ! Release memory
271  deallocate(lonlat)
272  else
273  grid_hash(ilx) = 0
274  end if
275 end do
276 
277 ! Final grid hash
278 grid_hash(0) = fletcher32(real(grid_hash(1:nlx),kind_real))
279 
280 ! Probe out
281 
282 
283 end subroutine func_gridhash
284 
285 !----------------------------------------------------------------------
286 ! Subroutine: func_independent_levels
287 !> Compute independent levels
288 !----------------------------------------------------------------------
289 subroutine func_independent_levels(mpl,nlx,grid_hash,nlxi,lx_to_lxi,lxi_to_lx,ifmt)
290 
291 implicit none
292 
293 ! Passed variables
294 type(mpl_type),intent(inout) :: mpl !< MPI data
295 integer,intent(in) :: nlx !< Number of levels
296 integer,intent(in) :: grid_hash(nlx) !< Grid hash profile
297 integer,intent(out) :: nlxi !< Number of independent levels
298 integer,intent(out) :: lx_to_lxi(nlx) !< Levels to independent levels
299 integer,intent(out) :: lxi_to_lx(nlx) !< Independent levels to levels
300 integer,intent(in) :: ifmt !< Indentation
301 
302 ! Local variables
303 integer :: ilx,ilxi,jlx,jlxi,n
304 integer :: proc_to_grid_hash(mpl%nproc),grid_hash_glb(nlx)
305 character(len=1024) :: cfmt
306 
307 ! Set name
308 
309 
310 ! Probe in
311 
312 
313 ! Compute global hash value
314 do ilx=1,nlx
315  call mpl%f_comm%allgather(grid_hash(ilx),proc_to_grid_hash)
316  grid_hash_glb(ilx) = fletcher32(real(proc_to_grid_hash,kind_real))
317 end do
318 
319 ! Count independent levels
320 nlxi = 1
321 do ilx=2,nlx
322  if (all(grid_hash_glb(1:ilx-1)/=grid_hash_glb(ilx))) nlxi = nlxi+1
323 end do
324 
325 ! Initialization
326 lxi_to_lx = mpl%msv%vali
327 
328 ! Get independent level
329 ilx = 1
330 ilxi = 1
331 lx_to_lxi(ilx) = ilxi
332 lxi_to_lx(ilxi) = ilx
333 do ilx=2,nlx
334  if (all(grid_hash_glb(1:ilx-1)/=grid_hash_glb(ilx))) then
335  ! New independent level
336  ilxi = ilxi+1
337  lx_to_lxi(ilx) = ilxi
338  lxi_to_lx(ilxi) = ilx
339  else
340  ! Similar level
341  do jlx=1,ilx-1
342  if (grid_hash_glb(jlx)==grid_hash_glb(ilx)) then
343  jlxi = lx_to_lxi(jlx)
344  lx_to_lxi(ilx) = jlxi
345  exit
346  end if
347  end do
348  end if
349 end do
350 
351 ! Print levels
352 write(cfmt,'(a,i2.2,a)') '(a',ifmt,',a)'
353 write(mpl%info,trim(cfmt)) '','Compute independent levels: '
354 call mpl%flush(.false.)
355 do ilxi=1,nlxi
356  ilx = lxi_to_lx(ilxi)
357  n = count(lx_to_lxi==ilxi)
358  if (n<10) then
359  cfmt = '(i3,a,i1,a)'
360  elseif (n<100) then
361  cfmt = '(i3,a,i2,a)'
362  else
363  cfmt = '(i3,a,i3,a)'
364  end if
365  write(mpl%info,trim(cfmt)) ilx,'[',n,'] '
366  call mpl%flush(.false.)
367 end do
368 write(mpl%info,'(a)') ''
369 call mpl%flush
370 
371 ! Probe out
372 
373 
374 end subroutine func_independent_levels
375 
376 !----------------------------------------------------------------------
377 ! Function: func_lonlathash
378 !> Define a unique real from a lon/lat pair
379 !----------------------------------------------------------------------
380 function func_lonlathash(lon,lat,il) result(value)
381 
382 implicit none
383 
384 ! Passed variables
385 real(kind_real),intent(in) :: lon !< Longitude (radians)
386 real(kind_real),intent(in) :: lat !< Latitude (radians)
387 integer,intent(in),optional :: il !< Level
388 
389 ! Returned variable
390 real(kind_real) :: value
391 
392 ! Local variables
393 real(kind_real) :: lontmp,lattmp
394 
395 ! Set name
396 
397 
398 ! Probe in
399 
400 
401 ! Set correct lon/lat
402 lontmp = lon
403 lattmp = lat
404 call lonlatmod(lontmp,lattmp)
405 
406 ! Hash value
407 value = aint((lontmp+pi)*1.0e7_kind_real)+(lattmp+half*pi)*tenth
408 if (present(il)) value = value+real(il*1e8,kind_real)
409 
410 ! Probe out
411 
412 
413 end function func_lonlathash
414 
415 !----------------------------------------------------------------------
416 ! Subroutine: func_sphere_dist
417 !> Compute the great-circle distance between two points
418 !----------------------------------------------------------------------
419 subroutine func_sphere_dist(lon_i,lat_i,lon_f,lat_f,dist)
420 
421 implicit none
422 
423 ! Passed variable
424 real(kind_real),intent(in) :: lon_i !< Initial point longitude (radians)
425 real(kind_real),intent(in) :: lat_i !< Initial point latitude (radians)
426 real(kind_real),intent(in) :: lon_f !< Final point longitude (radians)
427 real(kind_real),intent(in) :: lat_f !< Final point latitude (radians)
428 real(kind_real),intent(out) :: dist !< Great-circle distance
429 
430 ! Local variables
431 type(atlas_geometry) :: ageometry
432 
433 ! Set name
434 
435 
436 ! Probe in
437 
438 
439 ! Create ATLAS geometry
440 ageometry = atlas_geometry('UnitSphere')
441 
442 ! Compute distance
443 dist = ageometry%distance(lon_i*rad2deg,lat_i*rad2deg,lon_f*rad2deg,lat_f*rad2deg)
444 
445 ! Probe out
446 
447 
448 end subroutine func_sphere_dist
449 
450 !----------------------------------------------------------------------
451 ! Subroutine: func_lonlat2xyz
452 !> Convert longitude/latitude to cartesian coordinates
453 !----------------------------------------------------------------------
454 subroutine func_lonlat2xyz(mpl,lon,lat,x,y,z)
455 
456 implicit none
457 
458 ! Passed variables
459 type(mpl_type),intent(inout) :: mpl !< MPI data
460 real(kind_real),intent(in) :: lon !< Longitude (radians)
461 real(kind_real),intent(in) :: lat !< Latitude (radians)
462 real(kind_real),intent(out) :: x !< X coordinate
463 real(kind_real),intent(out) :: y !< Y coordinate
464 real(kind_real),intent(out) :: z !< Z coordinate
465 
466 ! Local variables
467 type(atlas_geometry) :: ageometry
468 
469 ! Set name
470 
471 
472 ! Probe in
473 
474 
475 if (mpl%msv%isnot(lat).and.mpl%msv%isnot(lon)) then
476  ! Check longitude/latitude
477  if (inf(lon,-pi).and.sup(lon,pi)) call mpl%abort('func_lonlat2xyz','wrong longitude')
478  if (inf(lat,-half*pi).and.sup(lat,-half*pi)) call mpl%abort('func_lonlat2xyz','wrong latitude')
479 
480  ! Create ATLAS geometry
481  ageometry = atlas_geometry('UnitSphere')
482 
483  ! Convert to x/y/z
484  call ageometry%lonlat2xyz(lon*rad2deg,lat*rad2deg,x,y,z)
485 else
486  ! Missing values
487  x = mpl%msv%valr
488  y = mpl%msv%valr
489  z = mpl%msv%valr
490 end if
491 
492 ! Probe out
493 
494 
495 end subroutine func_lonlat2xyz
496 
497 !----------------------------------------------------------------------
498 ! Subroutine: func_xyz2lonlat
499 !> Convert longitude/latitude to cartesian coordinates
500 !----------------------------------------------------------------------
501 subroutine func_xyz2lonlat(mpl,x,y,z,lon,lat)
502 
503 implicit none
504 
505 ! Passed variables
506 type(mpl_type),intent(in) :: mpl !< MPI data
507 real(kind_real),intent(in) :: x !< X coordinate
508 real(kind_real),intent(in) :: y !< Y coordinate
509 real(kind_real),intent(in) :: z !< Z coordinate
510 real(kind_real),intent(out) :: lon !< Longitude (radians)
511 real(kind_real),intent(out) :: lat !< Latitude (radians)
512 
513 ! Local variables
514 type(atlas_geometry) :: ageometry
515 
516 ! Set name
517 
518 
519 ! Probe in
520 
521 
522 if (mpl%msv%isnot(x).and.mpl%msv%isnot(y).and.mpl%msv%isnot(z)) then
523  ! Create ATLAS geometry
524  ageometry = atlas_geometry('UnitSphere')
525 
526  ! Convert to lon/lat
527  call ageometry%xyz2lonlat(x,y,z,lon,lat)
528 
529  ! Copy coordinates
530  lon = lon*deg2rad
531  lat = lat*deg2rad
532 else
533  ! Missing values
534  lon = mpl%msv%valr
535  lat = mpl%msv%valr
536 end if
537 
538 ! Probe out
539 
540 
541 end subroutine func_xyz2lonlat
542 
543 !----------------------------------------------------------------------
544 ! Subroutine: func_vector_product
545 !> Compute normalized vector product
546 !----------------------------------------------------------------------
547 subroutine func_vector_product(v1,v2,vp)
548 
549 implicit none
550 
551 ! Passed variables
552 real(kind_real),intent(in) :: v1(3) !< First vector
553 real(kind_real),intent(in) :: v2(3) !< Second vector
554 real(kind_real),intent(out) :: vp(3) !< Vector product
555 
556 ! Local variable
557 real(kind_real) :: r
558 
559 ! Set name
560 
561 
562 ! Probe in
563 
564 
565 ! Vector product
566 vp(1) = v1(2)*v2(3)-v1(3)*v2(2)
567 vp(2) = v1(3)*v2(1)-v1(1)*v2(3)
568 vp(3) = v1(1)*v2(2)-v1(2)*v2(1)
569 
570 ! Normalization
571 r = sqrt(sum(vp**2))
572 if (r>zero) vp = vp/r
573 
574 ! Probe out
575 
576 
577 end subroutine func_vector_product
578 
579 !----------------------------------------------------------------------
580 ! Subroutine: func_det
581 !> Compute determinant (vector triple product)
582 !----------------------------------------------------------------------
583 subroutine func_det(v1,v2,v3,p,cflag)
584 
585 implicit none
586 
587 ! Passed variables
588 real(kind_real),intent(in) :: v1(3) !< First vector
589 real(kind_real),intent(in) :: v2(3) !< Second vector
590 real(kind_real),intent(in) :: v3(3) !< Third vector
591 real(kind_real),intent(out) :: p !< Determinant
592 logical,intent(out) :: cflag !< Confidence flag
593 
594 ! Local variable
595 integer :: i
596 real(kind_real) :: terms(6)
597 
598 ! Set name
599 
600 
601 ! Probe in
602 
603 
604 ! Terms
605 terms(1) = v1(2)*v2(3)*v3(1)
606 terms(2) = -v1(3)*v2(2)*v3(1)
607 terms(3) = v1(3)*v2(1)*v3(2)
608 terms(4) = -v1(1)*v2(3)*v3(2)
609 terms(5) = v1(1)*v2(2)*v3(3)
610 terms(6) = -v1(2)*v2(1)*v3(3)
611 
612 ! Sum
613 p = sum(terms)
614 
615 ! Confidence flag
616 cflag = .true.
617 do i=1,6
618  if ((abs(terms(i))>zero).and.small(p,terms(i))) cflag = .false.
619 end do
620 
621 ! Probe out
622 
623 
624 end subroutine func_det
625 
626 !----------------------------------------------------------------------
627 ! Subroutine: func_order_cc
628 !> Order points in counter-clockwise order with respect to a central point
629 !----------------------------------------------------------------------
630 subroutine func_order_cc(mpl,lon,lat,n,x,y,z,order,diff)
631 
632 implicit none
633 
634 ! Passed variables
635 type(mpl_type),intent(inout) :: mpl !< MPI data
636 real(kind_real),intent(in) :: lon !< Longitude of the central point
637 real(kind_real),intent(in) :: lat !< Latitude of the central point
638 integer :: n !< Number of points
639 real(kind_real),intent(in) :: x(n) !< List of X-coordinates
640 real(kind_real),intent(in) :: y(n) !< List of Y-coordinates
641 real(kind_real),intent(in) :: z(n) !< List of Z-coordinates
642 integer,intent(out) :: order(n) !< Counter-clockwise order
643 real(kind_real),intent(out),optional :: diff(n) !< Angles differences
644 
645 ! Local variable
646 integer :: i
647 real(kind_real) :: rvec(3),costheta,sintheta,p(3),rvecxv(3),v(3),list(n)
648 real(kind_real),allocatable :: list_save(:)
649 
650 ! Set name
651 
652 
653 ! Probe in
654 
655 
656 ! Rotation vector in cartesian coordinates
657 call lonlat2xyz(mpl,lon-half*pi,zero,rvec(1),rvec(2),rvec(3))
658 
659 ! Rotation angle
660 costheta = cos(half*pi-lat)
661 sintheta = sin(half*pi-lat)
662 
663 ! Compute angle
664 do i=1,n
665  ! Rodrigues' rotation
666  p = (/x(i),y(i),z(i)/)
667  call vector_product(rvec,p,rvecxv)
668  v = p*costheta+rvecxv*sintheta+rvec*sum(rvec*p)*(one-costheta)
669 
670  ! Angle
671  list(i) = atan2(v(2),v(1))
672 end do
673 
674 if (present(diff)) then
675  ! Allocation
676  allocate(list_save(n))
677 
678  ! Copy
679  list_save = list
680 end if
681 
682 ! Sort angles in counter-clockwise order
683 call qsort(n,list,order)
684 
685 if (present(diff)) then
686  ! Get angles differences
687  diff(order(1)) = list_save(order(1))-list_save(order(n))+two*pi
688  do i=2,n
689  diff(order(i)) = list_save(order(i))-list_save(order(i-1))
690  end do
691 
692  ! Release memory
693  deallocate(list_save)
694 end if
695 
696 ! Probe out
697 
698 
699 end subroutine func_order_cc
700 
701 !----------------------------------------------------------------------
702 ! Subroutine: func_add
703 !> Check if value missing and add if not missing
704 !----------------------------------------------------------------------
705 subroutine func_add(mpl,val,cumul,num,wgt)
706 
707 implicit none
708 
709 ! Passed variables
710 type(mpl_type),intent(in) :: mpl !< MPI data
711 real(kind_real),intent(in) :: val !< Value to add
712 real(kind_real),intent(inout) :: cumul !< Cumul
713 real(kind_real),intent(inout) :: num !< Number of values
714 real(kind_real),intent(in),optional :: wgt !< Weight
715 
716 ! Local variables
717 real(kind_real) :: lwgt
718 
719 ! Set name
720 
721 
722 ! Probe in
723 
724 
725 ! Initialize weight
726 lwgt = one
727 if (present(wgt)) lwgt = wgt
728 
729 ! Add value to cumul
730 if (mpl%msv%isnot(val)) then
731  cumul = cumul+lwgt*val
732  num = num+lwgt
733 end if
734 
735 ! Probe out
736 
737 
738 end subroutine func_add
739 
740 !----------------------------------------------------------------------
741 ! Subroutine: func_divide
742 !> Check if value missing and divide if not missing
743 !----------------------------------------------------------------------
744 subroutine func_divide(mpl,val,num)
745 
746 implicit none
747 
748 ! Passed variables
749 type(mpl_type),intent(in) :: mpl !< MPI data
750 real(kind_real),intent(inout) :: val !< Value to divide
751 real(kind_real),intent(in) :: num !< Divider
752 
753 ! Set name
754 
755 
756 ! Probe in
757 
758 
759 ! Divide cumul by num
760 if (abs(num)>zero) then
761  val = val/num
762 else
763  val = mpl%msv%valr
764 end if
765 
766 ! Probe out
767 
768 
769 end subroutine func_divide
770 
771 !----------------------------------------------------------------------
772 ! Subroutine: func_fit_diag
773 !> Compute diagnostic fit function
774 !----------------------------------------------------------------------
775 subroutine func_fit_diag(mpl,nc3,nl0r,nl0,l0rl0_to_l0,disth,distv,coef,rh,rv,fit)
776 
777 implicit none
778 
779 ! Passed variables
780 type(mpl_type),intent(inout) :: mpl !< MPI data
781 integer,intent(in) :: nc3 !< Number of classes
782 integer,intent(in) :: nl0r !< Effective number of levels
783 integer,intent(in) :: nl0 !< Number of levels
784 integer,intent(in) :: l0rl0_to_l0(nl0r,nl0) !< Effective level to level
785 real(kind_real),intent(in) :: disth(nc3) !< Horizontal distance
786 real(kind_real),intent(in) :: distv(nl0,nl0) !< Vertical distance
787 real(kind_real),intent(in) :: coef(nl0) !< Diagonal coefficient
788 real(kind_real),intent(in) :: rh(nl0) !< Horizontal support radius
789 real(kind_real),intent(in) :: rv(nl0) !< Vertical support radius
790 real(kind_real),intent(out) :: fit(nc3,nl0r,nl0) !< Fit
791 
792 ! Local variables
793 integer :: jl0r,jl0,djl0,il0,kl0r,kl0,ic3,jc3,djc3,kc3,ip,jp,np,np_new,nc3max
794 integer :: plist(nc3*nl0r,2),plist_new(nc3*nl0r,2)
795 real(kind_real) :: rhsq,rvsq,distvsq,disttest,rhmax
796 real(kind_real) :: predistnorm(-1:1,nc3,-1:1,nl0),distnorm(nc3,nl0r)
797 logical :: add_to_front
798 
799 ! Set name
800 
801 
802 ! Probe in
803 
804 
805 ! Initialization
806 fit = zero
807 
808 ! Find maximum class
809 rhmax = maxval(rh)
810 nc3max = 0
811 do ic3=1,nc3
812  if (disth(ic3)>rhmax) exit
813  nc3max = ic3
814 end do
815 
816 ! Precompute normalized local distances
817 predistnorm = one
818 do il0=1,nl0
819  do djl0=-1,1
820  ! Level index
821  jl0 = max(1,min(il0+djl0,nl0))
822 
823  ! Averaged fit parameters
824  if (mpl%msv%isnot(rh(il0)).and.mpl%msv%isnot(rh(jl0))) then
825  rhsq = half*(rh(il0)**2+rh(jl0)**2)
826  else
827  rhsq = zero
828  end if
829  if (mpl%msv%isnot(rv(il0)).and.mpl%msv%isnot(rv(jl0))) then
830  rvsq = half*(rv(il0)**2+rv(jl0)**2)
831  else
832  rvsq = zero
833  end if
834 
835  ! Squared vertical distance
836  if (rvsq>zero) then
837  distvsq = distv(jl0,il0)**2/rvsq
838  elseif (il0/=jl0) then
839  distvsq = one
840  else
841  distvsq = zero
842  end if
843 
844  do ic3=1,nc3max
845  do djc3=-1,1
846  ! Horizontal index
847  jc3 = max(1,min(ic3+djc3,nc3max))
848 
849  ! Squared normalized distance initialization (squared vertical component)
850  predistnorm(djc3,ic3,djl0,il0) = distvsq
851 
852  ! Add squared horizontal component to squared normalized distance
853  if (rhsq>zero) then
854  predistnorm(djc3,ic3,djl0,il0) = predistnorm(djc3,ic3,djl0,il0)+(disth(jc3)-disth(ic3))**2/rhsq
855  elseif (ic3/=jc3) then
856  predistnorm(djc3,ic3,djl0,il0) = predistnorm(djc3,ic3,djl0,il0)+one
857  end if
858 
859  ! Get normalized distance
860  predistnorm(djc3,ic3,djl0,il0) = sqrt(predistnorm(djc3,ic3,djl0,il0))
861  end do
862  end do
863  end do
864 end do
865 
866 ! Compte fit
867 do il0=1,nl0
868  ! Initialize the front
869  np = 1
870  plist = mpl%msv%vali
871  plist(1,1) = 1
872  do jl0r=1,nl0r
873  if (l0rl0_to_l0(jl0r,il0)==il0) plist(1,2) = jl0r
874  end do
875  distnorm = one
876  distnorm(plist(1,1),plist(1,2)) = zero
877 
878  do while (np>0)
879  ! Propagate the front
880  np_new = 0
881 
882  do ip=1,np
883  ! Indices of the central point
884  jc3 = plist(ip,1)
885  jl0r = plist(ip,2)
886  jl0 = l0rl0_to_l0(jl0r,il0)
887 
888  ! Loop over neighbors
889  do kc3=max(jc3-1,1),min(jc3+1,nc3max)
890  do kl0r=max(jl0r-1,1),min(jl0r+1,nl0r)
891  kl0 = l0rl0_to_l0(kl0r,il0)
892  disttest = distnorm(jc3,jl0r)+predistnorm(kc3-jc3,jc3,kl0-jl0,jl0)
893 
894  if (disttest<one) then
895  ! Point is inside the support
896  if (disttest<distnorm(kc3,kl0r)) then
897  ! Update distance
898  distnorm(kc3,kl0r) = disttest
899 
900  ! Check if the point should be added to the front (avoid duplicates)
901  add_to_front = .true.
902  do jp=1,np_new
903  if ((plist_new(jp,1)==kc3).and.(plist_new(jp,2)==kl0r)) then
904  add_to_front = .false.
905  exit
906  end if
907  end do
908 
909  if (add_to_front) then
910  ! Add point to the front
911  np_new = np_new+1
912  plist_new(np_new,1) = kc3
913  plist_new(np_new,2) = kl0r
914  end if
915  end if
916  end if
917  end do
918  end do
919  end do
920 
921  ! Copy new front
922  np = np_new
923  plist(1:np,:) = plist_new(1:np,:)
924  end do
925 
926  do jl0r=1,nl0r
927  ! Level index
928  jl0 = l0rl0_to_l0(jl0r,il0)
929 
930  do jc3=1,nc3
931  ! Fit function
932  fit(jc3,jl0r,il0) = fit_func(mpl,distnorm(jc3,jl0r))
933  end do
934  end do
935 end do
936 
937 ! Diagonal coefficient
938 do il0=1,nl0
939  do jl0r=1,nl0r
940  jl0 = l0rl0_to_l0(jl0r,il0)
941  fit(:,jl0r,il0) = fit(:,jl0r,il0)*sqrt(coef(il0)*coef(jl0))
942  end do
943 end do
944 
945 ! Set to missing values if no value available
946 do il0=1,nl0
947  if (mpl%msv%is(coef(il0)).or.mpl%msv%is(rh(il0)).or.mpl%msv%is(rv(il0))) fit(:,:,il0) = mpl%msv%valr
948  do jl0r=1,nl0r
949  jl0 = l0rl0_to_l0(jl0r,il0)
950  if (mpl%msv%is(coef(jl0)).or.mpl%msv%is(rh(jl0)).or.mpl%msv%is(rv(jl0))) fit(:,jl0r,il0) = mpl%msv%valr
951  end do
952 end do
953 
954 ! Probe out
955 
956 
957 end subroutine func_fit_diag
958 
959 !----------------------------------------------------------------------
960 ! Function: func_gc99
961 !> Gaspari and Cohn (1999) function, with the support radius as a parameter
962 !----------------------------------------------------------------------
963 function func_gc99(distnorm) result(value)
964 
965 ! Passed variables
966 real(kind_real),intent(in) :: distnorm !< Normalized distance
967 
968 ! Returned variable
969 real(kind_real) :: value
970 
971 ! Set name
972 
973 
974 ! Probe in
975 
976 
977 ! Gaspari and Cohn (1999) function
978 if (distnorm<half) then
979  value = one-distnorm
980  value = one+eight/five*distnorm*value
981  value = one-three/four*distnorm*value
982  value = one-20.0_kind_real/three*distnorm**2*value
983 else if (distnorm<one) then
984  value = one-distnorm/three
985  value = one-eight/five*distnorm*value
986  value = one+three/four*distnorm*value
987  value = one-two/three*distnorm*value
988  value = one-five/two*distnorm*value
989  value = one-12.0_kind_real*distnorm*value
990  value = -value/(three*distnorm)
991 else
992  value = zero
993 end if
994 
995 ! Probe out
996 
997 
998 end function func_gc99
999 
1000 !----------------------------------------------------------------------
1001 ! Function: func_fit_func
1002 !> Fit_function
1003 !----------------------------------------------------------------------
1004 function func_fit_func(mpl,distnorm) result(value)
1005 
1006 ! Passed variables
1007 type(mpl_type),intent(inout) :: mpl !< MPI data
1008 real(kind_real),intent(in) :: distnorm !< Normalized distance
1009 
1010 ! Returned variable
1011 real(kind_real) :: value
1012 
1013 ! Set name
1014 
1015 
1016 ! Probe in
1017 
1018 
1019 ! Distance check bound
1020 if (distnorm<zero) call mpl%abort('func_fit_func','negative normalized distance')
1021 
1022 ! Gaspari and Cohn (1999) function
1023 value = gc99(distnorm)
1024 
1025 ! Enforce positivity
1026 value = max(value,zero)
1027 
1028 ! Probe out
1029 
1030 
1031 end function func_fit_func
1032 
1033 !----------------------------------------------------------------------
1034 ! Subroutine: func_fit_lct
1035 !> LCT fit
1036 !----------------------------------------------------------------------
1037 subroutine func_fit_lct(mpl,nc,nl0,dxsq,dysq,dxdy,dzsq,dmask,nscales,D,coef,fit)
1038 
1039 implicit none
1040 
1041 ! Passed variables
1042 type(mpl_type),intent(inout) :: mpl !< MPI data
1043 integer,intent(in) :: nc !< Number of classes
1044 integer,intent(in) :: nl0 !< Number of levels
1045 real(kind_real),intent(in) :: dxsq(nc,nl0) !< Zonal separation squared
1046 real(kind_real),intent(in) :: dysq(nc,nl0) !< Meridian separation squared
1047 real(kind_real),intent(in) :: dxdy(nc,nl0) !< Zonal x meridian separations product
1048 real(kind_real),intent(in) :: dzsq(nc,nl0) !< Vertical separation squared
1049 logical,intent(in) :: dmask(nc,nl0) !< Mask
1050 integer,intent(in) :: nscales !< Number of LCT scales
1051 real(kind_real),intent(in) :: D(4,nscales) !< LCT components
1052 real(kind_real),intent(in) :: coef(nscales) !< LCT coefficients
1053 real(kind_real),intent(out) :: fit(nc,nl0) !< Fit
1054 
1055 ! Local variables
1056 integer :: jl0,jc3,iscales
1057 real(kind_real) :: Dcoef(nscales),D11,D22,D33,D12,H11,H22,H33,H12,rsq
1058 
1059 ! Set name
1060 
1061 
1062 ! Probe in
1063 
1064 
1065 ! Initialization
1066 fit = mpl%msv%valr
1067 
1068 ! Coefficients
1069 dcoef = max(dmin,min(coef,one))
1070 dcoef = dcoef/sum(dcoef)
1071 
1072 do iscales=1,nscales
1073  ! Ensure positive-definiteness of D
1074  d11 = max(dmin,d(1,iscales))
1075  d22 = max(dmin,d(2,iscales))
1076  if (nl0>1) then
1077  d33 = max(dmin,d(3,iscales))
1078  else
1079  d33 = zero
1080  end if
1081  d12 = sqrt(d11*d22)*max(-one+dmin,min(d(4,iscales),one-dmin))
1082 
1083  ! Inverse D to get H
1084  call lct_d2h(mpl,d11,d22,d33,d12,h11,h22,h33,h12)
1085 
1086  ! Homogeneous anisotropic approximation
1087  do jl0=1,nl0
1088  do jc3=1,nc
1089  if (dmask(jc3,jl0)) then
1090  ! Initialization
1091  if (iscales==1) fit(jc3,jl0) = zero
1092 
1093  ! Squared distance
1094  rsq = h11*dxsq(jc3,jl0)+h22*dysq(jc3,jl0)+h33*dzsq(jc3,jl0)+two*h12*dxdy(jc3,jl0)
1095 
1096  if (m==0) then
1097  ! Gaussian function
1098  if (rsq<40.0_kind_real) fit(jc3,jl0) = fit(jc3,jl0)+dcoef(iscales)*exp(-half*rsq)
1099  else
1100  ! Matern function
1101  fit(jc3,jl0) = fit(jc3,jl0)+dcoef(iscales)*matern(mpl,m,sqrt(rsq))
1102  end if
1103  end if
1104  end do
1105  end do
1106 end do
1107 
1108 ! Probe out
1109 
1110 
1111 end subroutine func_fit_lct
1112 
1113 !----------------------------------------------------------------------
1114 ! Subroutine: func_lct_d2h
1115 !> From D (Daley tensor) to H (local correlation tensor)
1116 !----------------------------------------------------------------------
1117 subroutine func_lct_d2h(mpl,D11,D22,D33,D12,H11,H22,H33,H12)
1118 
1119 implicit none
1120 
1121 ! Passed variables
1122 type(mpl_type),intent(inout) :: mpl!< MPI data
1123 real(kind_real),intent(in) :: D11 !< Daley tensor component 11
1124 real(kind_real),intent(in) :: D22 !< Daley tensor component 22
1125 real(kind_real),intent(in) :: D33 !< Daley tensor component 33
1126 real(kind_real),intent(in) :: D12 !< Daley tensor component 12
1127 real(kind_real),intent(out) :: H11 !< Local correlation tensor component 11
1128 real(kind_real),intent(out) :: H22 !< Local correlation tensor component 22
1129 real(kind_real),intent(out) :: H33 !< Local correlation tensor component 33
1130 real(kind_real),intent(out) :: H12 !< Local correlation tensor component 12
1131 
1132 ! Local variables
1133 real(kind_real) :: det
1134 
1135 ! Set name
1136 
1137 
1138 ! Probe in
1139 
1140 
1141 ! Compute horizontal determinant
1142 det = d11*d22-d12**2
1143 
1144 ! Inverse D to get H
1145 if (det>zero) then
1146  h11 = d22/det
1147  h22 = d11/det
1148  h12 = -d12/det
1149 else
1150  call mpl%abort('func_lct_d2h','non-invertible tensor')
1151 end if
1152 if (d33>zero) then
1153  h33 = one/d33
1154 else
1155  h33 = zero
1156 end if
1157 
1158 ! Probe out
1159 
1160 
1161 end subroutine func_lct_d2h
1162 
1163 !----------------------------------------------------------------------
1164 ! Subroutine: func_lct_h2r
1165 !> From H (local correlation tensor) to support radii
1166 !----------------------------------------------------------------------
1167 subroutine func_lct_h2r(mpl,H11,H22,H33,H12,rh,rv)
1168 
1169 implicit none
1170 
1171 ! Passed variables
1172 type(mpl_type),intent(inout) :: mpl !< MPI data
1173 real(kind_real),intent(in) :: H11 !< Local correlation tensor component 11
1174 real(kind_real),intent(in) :: H22 !< Local correlation tensor component 22
1175 real(kind_real),intent(in) :: H33 !< Local correlation tensor component 33
1176 real(kind_real),intent(in) :: H12 !< Local correlation tensor component 12
1177 real(kind_real),intent(out) :: rh !< Horizontal support radius
1178 real(kind_real),intent(out) :: rv !< Vertical support radius
1179 
1180 ! Local variables
1181 real(kind_real) :: tr,det,diff
1182 
1183 ! Set name
1184 
1185 
1186 ! Probe in
1187 
1188 
1189 ! Check diagonal positivity
1190 if ((h11<zero).or.(h22<zero)) call mpl%abort('func_lct_h2r','negative diagonal LCT coefficients')
1191 
1192 ! Compute horizontal trace
1193 tr = h11+h22
1194 
1195 ! Compute horizontal determinant
1196 det = h11*h22-h12**2
1197 
1198 ! Compute horizontal support radius
1199 diff = quarter*(h11-h22)**2+h12**2
1200 if ((det>zero).and..not.(diff<zero)) then
1201  if (half*tr>sqrt(diff)) then
1202  rh = gau2gc/sqrt(half*tr-sqrt(diff))
1203  else
1204  call mpl%abort('func_lct_h2r','non positive-definite LCT (eigenvalue)')
1205  end if
1206 else
1207  call mpl%abort('func_lct_h2r','non positive-definite LCT (determinant)')
1208 end if
1209 
1210 ! Compute vertical support radius
1211 if (h33>zero) then
1212  rv = gau2gc/sqrt(h33)
1213 else
1214  rv = zero
1215 end if
1216 
1217 ! Probe out
1218 
1219 
1220 end subroutine func_lct_h2r
1221 
1222 !----------------------------------------------------------------------
1223 ! Subroutine: func_lct_r2d
1224 !> From support radius to Daley tensor diagonal element
1225 !----------------------------------------------------------------------
1226 subroutine func_lct_r2d(r,D)
1227 
1228 implicit none
1229 
1230 ! Passed variables
1231 real(kind_real),intent(in) :: r !< Support radius
1232 real(kind_real),intent(out) :: D !< Daley tensor diagonal element
1233 
1234 ! Set name
1235 
1236 
1237 ! Probe in
1238 
1239 
1240 ! Convert from support radius to Daley length-scale and square
1241 d = (gc2gau*r)**2
1242 
1243 ! Probe out
1244 
1245 
1246 end subroutine func_lct_r2d
1247 
1248 !----------------------------------------------------------------------
1249 ! Subroutine: func_check_cond
1250 !> Check tensor conditioning
1251 !----------------------------------------------------------------------
1252 subroutine func_check_cond(d1,d2,nod,valid)
1253 
1254 implicit none
1255 
1256 ! Passed variables
1257 real(kind_real),intent(in) :: d1 !< First diagonal coefficient
1258 real(kind_real),intent(in) :: d2 !< Second diagonal coefficient
1259 real(kind_real),intent(in) :: nod !< Normalized off-diagonal coefficient
1260 logical,intent(out) :: valid !< Conditioning validity
1261 
1262 ! Local variables
1263 real(kind_real) :: det,tr,diff,ev1,ev2
1264 
1265 ! Set name
1266 
1267 
1268 ! Probe in
1269 
1270 
1271 ! Compute trace and determinant
1272 tr = d1+d2
1273 det = d1*d2*(one-nod**2)
1274 diff = quarter*(d1-d2)**2+d1*d2*nod**2
1275 
1276 if ((det>zero).and..not.(diff<zero)) then
1277  ! Compute eigenvalues
1278  ev1 = half*tr+sqrt(diff)
1279  ev2 = half*tr-sqrt(diff)
1280 
1281  if (ev2>zero) then
1282  ! Check conditioning
1283  valid = inf(ev1,condmax*ev2)
1284  else
1285  ! Lowest negative eigenvalue is negative
1286  valid = .false.
1287  end if
1288 else
1289  ! Non-positive definite tensor
1290  valid = .false.
1291 end if
1292 
1293 ! Probe out
1294 
1295 
1296 end subroutine func_check_cond
1297 
1298 !----------------------------------------------------------------------
1299 ! Function: func_matern
1300 !> Compute the normalized diffusion function from eq. (55) of Mirouze and Weaver (2013), for the 3d case (d = 3)
1301 !----------------------------------------------------------------------
1302 function func_matern(mpl,M,x) result(value)
1303 
1304 implicit none
1305 
1306 ! Passed variables
1307 type(mpl_type),intent(inout) :: mpl !< MPI data
1308 integer,intent(in) :: m !< Matern function order
1309 real(kind_real),intent(in) :: x !< Argument
1310 
1311 ! Returned variable
1312 real(kind_real) :: value
1313 
1314 ! Local variables
1315 integer :: j
1316 real(kind_real) :: xtmp,beta
1317 
1318 ! Set name
1319 
1320 
1321 ! Probe in
1322 
1323 
1324 ! Check
1325 if (m<2) call mpl%abort('func_matern','M should be larger than 2')
1326 if (mod(m,2)>0) call mpl%abort('func_matern','M should be even')
1327 
1328 ! Initialization
1329 value = zero
1330 beta = one
1331 xtmp = x*sqrt(real(2*m-5,kind_real))
1332 
1333 do j=0,m-3
1334  ! Update sum
1335  value = value+beta*(xtmp)**(m-2-j)
1336 
1337  ! Update beta
1338  beta = beta*real((j+1+m-2)*(-j+m-2),kind_real)/real(2*(j+1),kind_real)
1339 end do
1340 
1341 ! Last term and normalization
1342 value = value/beta+one
1343 
1344 ! Exponential factor
1345 value = value*exp(-xtmp)
1346 
1347 ! Probe out
1348 
1349 
1350 end function func_matern
1351 
1352 !----------------------------------------------------------------------
1353 ! Subroutine: func_cholesky
1354 !> Compute cholesky decomposition
1355 ! Author: Original FORTRAN77 version by Michael Healy, modifications by AJ Miller, FORTRAN90 version by John Burkardt.
1356 !----------------------------------------------------------------------
1357 subroutine func_cholesky(mpl,n,a,u)
1358 
1359 implicit none
1360 
1361 ! Passed variables
1362 type(mpl_type),intent(inout) :: mpl !< MPI data
1363 integer,intent(in) :: n !< Matrix rank
1364 real(kind_real),intent(in) :: a(n,n) !< Matrix
1365 real(kind_real),intent(out) :: u(n,n) !< Matrix square-root
1366 
1367 ! Local variables
1368 integer :: nn,i,j,ij
1369 real(kind_real),allocatable :: apack(:),upack(:)
1370 
1371 ! Set name
1372 
1373 
1374 ! Probe in
1375 
1376 
1377 ! Allocation
1378 nn = (n*(n+1))/2
1379 allocate(apack(nn))
1380 allocate(upack(nn))
1381 
1382 ! Pack matrix
1383 ij = 0
1384 do i=1,n
1385  do j=1,i
1386  ij = ij+1
1387  apack(ij) = a(i,j)
1388  end do
1389 end do
1390 
1391 ! Cholesky decomposition
1392 call cholesky(mpl,n,nn,apack,upack)
1393 
1394 ! Unpack matrix
1395 ij = 0
1396 u = zero
1397 do i=1,n
1398  do j=1,i
1399  ij = ij+1
1400  u(i,j) = upack(ij)
1401  end do
1402 end do
1403 
1404 ! Release memory
1405 deallocate(apack)
1406 deallocate(upack)
1407 
1408 ! Probe out
1409 
1410 
1411 end subroutine func_cholesky
1412 
1413 !----------------------------------------------------------------------
1414 ! Subroutine: func_syminv
1415 !> Compute inverse of a symmetric matrix
1416 ! Author: Original FORTRAN77 version by Michael Healy, modifications by AJ Miller, FORTRAN90 version by John Burkardt.
1417 !----------------------------------------------------------------------
1418 subroutine func_syminv(mpl,n,a,c)
1419 
1420 implicit none
1421 
1422 ! Passed variables
1423 type(mpl_type),intent(inout) :: mpl !< MPI data
1424 integer,intent(in) :: n !< Matrix rank
1425 real(kind_real),intent(in) :: a(n,n) !< Matrix
1426 real(kind_real),intent(out) :: c(n,n) !< Matrix inverse
1427 
1428 ! Local variables
1429 integer :: nn,i,j,ij
1430 real(kind_real),allocatable :: apack(:),cpack(:)
1431 
1432 ! Set name
1433 
1434 
1435 ! Probe in
1436 
1437 
1438 ! Allocation
1439 nn = (n*(n+1))/2
1440 allocate(apack(nn))
1441 allocate(cpack(nn))
1442 
1443 ! Pack matrix
1444 ij = 0
1445 do i=1,n
1446  do j=1,i
1447  ij = ij+1
1448  apack(ij) = a(i,j)
1449  end do
1450 end do
1451 
1452 ! Matrix inversion
1453 call syminv(mpl,n,nn,apack,cpack)
1454 
1455 ! Unpack matrix
1456 ij = 0
1457 do i=1,n
1458  do j=1,i
1459  ij = ij+1
1460  c(i,j) = cpack(ij)
1461  c(j,i) = c(i,j)
1462  end do
1463 end do
1464 
1465 ! Release memory
1466 deallocate(apack)
1467 deallocate(cpack)
1468 
1469 ! Probe out
1470 
1471 
1472 end subroutine func_syminv
1473 
1474 !----------------------------------------------------------------------
1475 ! Subroutine: func_histogram
1476 !> Compute bins and histogram from a list of values
1477 !----------------------------------------------------------------------
1478 subroutine func_histogram(mpl,nlist,list,nbins,histmin,histmax,bins,hist)
1479 
1480 implicit none
1481 
1482 ! Passed variables
1483 type(mpl_type),intent(inout) :: mpl !< MPI data
1484 integer,intent(in) :: nlist !< List size
1485 real(kind_real),intent(in) :: list(nlist) !< List
1486 integer,intent(in) :: nbins !< Number of bins
1487 real(kind_real),intent(in) :: histmin !< Histogram minimum
1488 real(kind_real),intent(in) :: histmax !< Histogram maximum
1489 real(kind_real),intent(out) :: bins(nbins+1) !< Bins
1490 real(kind_real),intent(out) :: hist(nbins) !< Histogram
1491 
1492 ! Local variables
1493 integer :: ibins,ilist
1494 real(kind_real) :: delta
1495 logical :: found
1496 
1497 ! Set name
1498 
1499 
1500 ! Probe in
1501 
1502 
1503 ! Check data
1504 if (nbins<=0) call mpl%abort('func_histogram','the number of bins should be positive')
1505 if (histmax>histmin) then
1506  if (minval(list,mask=mpl%msv%isnot(list))<histmin) call mpl%abort('func_histogram','values below histogram minimum')
1507  if (maxval(list,mask=mpl%msv%isnot(list))>histmax) call mpl%abort('func_histogram','values over histogram maximum')
1508 
1509  ! Compute bins
1510  delta = (histmax-histmin)/real(nbins,kind_real)
1511  bins(1) = histmin
1512  do ibins=2,nbins
1513  bins(ibins) = histmin+real(ibins-1,kind_real)*delta
1514  end do
1515  bins(nbins+1) = histmax
1516 
1517  ! Extend first and last bins
1518  bins(1) = bins(1)-1.0e-6_kind_real*delta
1519  bins(nbins+1) = bins(nbins+1)+1.0e-6_kind_real*delta
1520 
1521  ! Compute histogram
1522  hist = zero
1523  do ilist=1,nlist
1524  if (mpl%msv%isnot(list(ilist))) then
1525  ibins = 0
1526  found = .false.
1527  do while (.not.found)
1528  ibins = ibins+1
1529  if (ibins>nbins) call mpl%abort('func_histogram','bin not found')
1530  if (infeq(bins(ibins),list(ilist)).and.inf(list(ilist),bins(ibins+1))) then
1531  hist(ibins) = hist(ibins)+one
1532  found = .true.
1533  end if
1534  end do
1535  end if
1536  end do
1537  if (abs(sum(hist)-real(count(mpl%msv%isnot(list)),kind_real))>half) &
1538  & call mpl%abort('func_histogram','histogram sum is not equal to the number of valid elements')
1539 else
1540  bins = mpl%msv%valr
1541  hist = zero
1542 end if
1543 
1544 ! Probe out
1545 
1546 
1547 end subroutine func_histogram
1548 
1549 !----------------------------------------------------------------------
1550 ! Function: func_cx_to_cxa
1551 !> Conversion from global to halo A on subset Scx
1552 !----------------------------------------------------------------------
1553 function func_cx_to_cxa(nproc,proc_to_cx_offset,icx) result(icxa)
1554 
1555 implicit none
1556 
1557 ! Passed variables
1558 integer,intent(in) :: nproc !< Number of processors
1559 integer,intent(in) :: proc_to_cx_offset(nproc) !< Processor to offset on subset Scx
1560 integer,intent(in) :: icx !< Global index
1561 
1562 ! Returned variable
1563 integer :: icxa
1564 
1565 ! Local variable
1566 integer :: iproc
1567 
1568 ! Set name
1569 
1570 
1571 ! Probe in
1572 
1573 
1574 ! Find processor
1575 iproc = cx_to_proc(nproc,proc_to_cx_offset,icx)
1576 
1577 ! Get halo A index
1578 icxa = icx-proc_to_cx_offset(iproc)
1579 
1580 ! Probe out
1581 
1582 
1583 end function func_cx_to_cxa
1584 
1585 !----------------------------------------------------------------------
1586 ! Function: func_cx_to_proc
1587 !> Conversion from global to processor on subset Scx
1588 !----------------------------------------------------------------------
1589 function func_cx_to_proc(nproc,proc_to_cx_offset,icx) result(iproc)
1590 
1591 implicit none
1592 
1593 ! Passed variables
1594 integer,intent(in) :: nproc !< Number of processors
1595 integer,intent(in) :: proc_to_cx_offset(nproc) !< Processor to offset on subset Scx
1596 integer,intent(in) :: icx !< Global index
1597 
1598 ! Returned variable
1599 integer :: iproc
1600 
1601 ! Set name
1602 
1603 
1604 ! Probe in
1605 
1606 
1607 ! Find processor
1608 do iproc=1,nproc-1
1609  if ((proc_to_cx_offset(iproc)<icx).and.(icx<=proc_to_cx_offset(iproc+1))) then
1610 
1611  return
1612  end if
1613 end do
1614 
1615 ! Probe out
1616 
1617 
1618 end function func_cx_to_proc
1619 
1620 !----------------------------------------------------------------------
1621 ! Function: func_cx_to_cxu
1622 !> Conversion from global to universe on subset Scx
1623 !----------------------------------------------------------------------
1624 function func_cx_to_cxu(nproc,proc_to_cx_offset,proc_to_ncxa,myuniverse,icx) result(icxu)
1625 
1626 implicit none
1627 
1628 ! Passed variables
1629 integer,intent(in) :: nproc !< Number of processors
1630 integer,intent(in) :: proc_to_cx_offset(nproc) !< Processor to offset on subset Scx
1631 integer,intent(in) :: proc_to_ncxa(nproc) !< Processor to halo A size for subset Scx
1632 logical,intent(in) :: myuniverse(nproc) !< Task universe
1633 integer,intent(in) :: icx !< Global index
1634 
1635 ! Returned variable
1636 integer :: icxu
1637 
1638 ! Local variable
1639 integer :: iproc,icxa,offset,jproc
1640 
1641 ! Set name
1642 
1643 
1644 ! Probe in
1645 
1646 
1647 ! Find processor
1648 iproc = cx_to_proc(nproc,proc_to_cx_offset,icx)
1649 
1650 if (myuniverse(iproc)) then
1651  ! Get halo A index
1652  icxa = icx-proc_to_cx_offset(iproc)
1653 
1654  ! Compute universe offset
1655  offset = 0
1656  do jproc=1,iproc-1
1657  if (myuniverse(jproc)) offset = offset+proc_to_ncxa(jproc)
1658  end do
1659 
1660  ! Get universe index
1661  icxu = offset+icxa
1662 else
1663  ! Not in my universe
1664  icxu = 0
1665 end if
1666 
1667 ! Probe out
1668 
1669 
1670 end function func_cx_to_cxu
1671 
1672 end module tools_func
Subroutines/functions list.
Subroutines/functions list.
Definition: tools_const.F90:31
real(kind_real), parameter, public ten
Ten.
Definition: tools_const.F90:48
real(kind_real), parameter, public one
One.
Definition: tools_const.F90:42
real(kind_real), parameter, public three
Three.
Definition: tools_const.F90:44
real(kind_real), parameter, public half
Half.
Definition: tools_const.F90:41
real(kind_real), parameter, public five
Five.
Definition: tools_const.F90:46
real(kind_real), parameter, public pi
Pi.
Definition: tools_const.F90:51
real(kind_real), parameter, public deg2rad
Degree to radian.
Definition: tools_const.F90:52
real(kind_real), parameter, public zero
Zero.
Definition: tools_const.F90:37
real(kind_real), parameter, public rad2deg
Radian to degree.
Definition: tools_const.F90:53
real(kind_real), parameter, public eight
Eight.
Definition: tools_const.F90:47
real(kind_real), parameter, public thousand
Thousand.
Definition: tools_const.F90:50
real(kind_real), parameter, public hundredth
Hundredth.
Definition: tools_const.F90:38
real(kind_real), parameter, public four
Four.
Definition: tools_const.F90:45
real(kind_real), parameter, public tenth
Tenth.
Definition: tools_const.F90:39
real(kind_real), parameter, public two
Two.
Definition: tools_const.F90:43
real(kind_real), parameter, public quarter
Quarter.
Definition: tools_const.F90:40
Subroutines/functions list.
Definition: tools_func.F90:31
real(kind_real) function func_lonlathash(lon, lat, il)
Define a unique real from a lon/lat pair.
Definition: tools_func.F90:381
integer function func_fletcher32(var)
Fletcher-32 checksum algorithm.
Definition: tools_func.F90:157
subroutine func_syminv(mpl, n, a, c)
Compute inverse of a symmetric matrix.
subroutine func_order_cc(mpl, lon, lat, n, x, y, z, order, diff)
Order points in counter-clockwise order with respect to a central point.
Definition: tools_func.F90:631
subroutine func_lct_r2d(r, D)
From support radius to Daley tensor diagonal element.
integer function func_cx_to_cxa(nproc, proc_to_cx_offset, icx)
Conversion from global to halo A on subset Scx.
subroutine func_fit_lct(mpl, nc, nl0, dxsq, dysq, dxdy, dzsq, dmask, nscales, D, coef, fit)
LCT fit.
integer function func_cx_to_cxu(nproc, proc_to_cx_offset, proc_to_ncxa, myuniverse, icx)
Conversion from global to universe on subset Scx.
real(kind_real) function func_gc99(distnorm)
Gaspari and Cohn (1999) function, with the support radius as a parameter.
Definition: tools_func.F90:964
real(kind_real), parameter, public dmin
Minimum tensor diagonal value.
Definition: tools_func.F90:47
subroutine func_lct_d2h(mpl, D11, D22, D33, D12, H11, H22, H33, H12)
From D (Daley tensor) to H (local correlation tensor)
real(kind_real) function func_matern(mpl, M, x)
Compute the normalized diffusion function from eq. (55) of Mirouze and Weaver (2013),...
subroutine func_check_cond(d1, d2, nod, valid)
Check tensor conditioning.
subroutine func_sphere_dist(lon_i, lat_i, lon_f, lat_f, dist)
Compute the great-circle distance between two points.
Definition: tools_func.F90:420
subroutine func_xyz2lonlat(mpl, x, y, z, lon, lat)
Convert longitude/latitude to cartesian coordinates.
Definition: tools_func.F90:502
subroutine func_lonlatmod(lon, lat)
Set latitude between -pi/2 and pi/2 and longitude between -pi and pi.
Definition: tools_func.F90:185
subroutine func_cholesky(mpl, n, a, u)
Compute cholesky decomposition.
subroutine func_lct_h2r(mpl, H11, H22, H33, H12, rh, rv)
From H (local correlation tensor) to support radii.
subroutine func_add(mpl, val, cumul, num, wgt)
Check if value missing and add if not missing.
Definition: tools_func.F90:706
integer, parameter, public m
Number of implicit iteration for the Matern function (0: Gaussian)
Definition: tools_func.F90:49
subroutine func_gridhash(ncx, nlx, lon_cx, lat_cx, mask_cx, grid_hash)
Compute grid hash profile.
Definition: tools_func.F90:227
subroutine func_divide(mpl, val, num)
Check if value missing and divide if not missing.
Definition: tools_func.F90:745
subroutine func_histogram(mpl, nlist, list, nbins, histmin, histmax, bins, hist)
Compute bins and histogram from a list of values.
real(kind_real), parameter condmax
Maximum tensor conditioning number.
Definition: tools_func.F90:48
integer function func_cx_to_proc(nproc, proc_to_cx_offset, icx)
Conversion from global to processor on subset Scx.
real(kind_real) function func_fit_func(mpl, distnorm)
Fit_function.
subroutine func_det(v1, v2, v3, p, cflag)
Compute determinant (vector triple product)
Definition: tools_func.F90:584
subroutine func_vector_product(v1, v2, vp)
Compute normalized vector product.
Definition: tools_func.F90:548
subroutine func_independent_levels(mpl, nlx, grid_hash, nlxi, lx_to_lxi, lxi_to_lx, ifmt)
Compute independent levels.
Definition: tools_func.F90:290
subroutine func_fit_diag(mpl, nc3, nl0r, nl0, l0rl0_to_l0, disth, distv, coef, rh, rv, fit)
Compute diagnostic fit function.
Definition: tools_func.F90:776
real(kind_real), parameter, public gc2gau
GC99 support radius to Gaussian Daley length-scale (empirical)
Definition: tools_func.F90:45
subroutine func_lonlat2xyz(mpl, lon, lat, x, y, z)
Convert longitude/latitude to cartesian coordinates.
Definition: tools_func.F90:455
real(kind_real), parameter, public gau2gc
Gaussian Daley length-scale to GC99 support radius (empirical)
Definition: tools_func.F90:46
Kinds definition.
Definition: tools_kinds.F90:9
integer, parameter, public kind_short
Short integer kind.
Definition: tools_kinds.F90:18
integer, parameter, public kind_real
Real kind alias for the whole code.
Definition: tools_kinds.F90:25
Generic ranks, dimensions and types.
Definition: tools_qsort.F90:46
Generic ranks, dimensions and types.
Definition: tools_repro.F90:42
Generic ranks, dimensions and types.
Definition: type_mpl.F90:42