SABER
tools_func.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: tools_func
3 !> Usual functions
4 ! Author: Benjamin Menetrier
5 ! Licensing: this code is distributed under the CeCILL-C license
6 ! Copyright © 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
7 !----------------------------------------------------------------------
8 module tools_func
9 
10 use iso_c_binding
11 use atlas_module, only: atlas_geometry
13 use tools_const, only: pi,deg2rad,rad2deg
15 use tools_repro, only: inf,sup,infeq,small
16 use type_mpl, only: mpl_type
17 
18 implicit none
19 
20 real(kind_real),parameter :: gc2gau = 0.28 ! GC99 support radius to Gaussian Daley length-scale (empirical)
21 real(kind_real),parameter :: gau2gc = 3.57 ! Gaussian Daley length-scale to GC99 support radius (empirical)
22 real(kind_real),parameter :: dmin = 1.0e-12_kind_real ! Minimum tensor diagonal value
23 real(kind_real),parameter :: condmax = 1.0e3 ! Maximum tensor conditioning number
24 integer,parameter :: m = 0 ! Number of implicit iteration for the Matern function (0: Gaussian)
25 
26 interface
27  function c_fletcher32(n,var) bind(c,name='fletcher32') result(hash)
28  use iso_c_binding
29  integer(kind=c_int32_t) :: n
30  integer(kind=c_int16_t) :: var(*)
31  integer(kind=c_int32_t) :: hash
32  end function c_fletcher32
33 end interface
34 
35 private
36 public :: gc2gau,gau2gc,dmin,m
39 
40 contains
41 
42 !----------------------------------------------------------------------
43 ! Function: fletcher32
44 !> Fletcher-32 checksum algorithm
45 !----------------------------------------------------------------------
46 function fletcher32(var)
47 
48 implicit none
49 
50 ! Passed variables
51 real(kind_real),intent(in) :: var(:) !< Variable
52 
53 ! Returned variable
54 integer :: fletcher32
55 
56 ! Call C function
57 fletcher32 = c_fletcher32(size(transfer(var,(/0_kind_short/))),transfer(var,(/0_kind_short/)))
58 
59 end function fletcher32
60 
61 !----------------------------------------------------------------------
62 ! Subroutine: lonlatmod
63 !> Set latitude between -pi/2 and pi/2 and longitude between -pi and pi
64 !----------------------------------------------------------------------
65 subroutine lonlatmod(lon,lat)
66 
67 implicit none
68 
69 ! Passed variables
70 real(kind_real),intent(inout) :: lon !< Longitude (radians)
71 real(kind_real),intent(inout) :: lat !< Latitude (radians)
72 
73 ! Check latitude bounds
74 if (lat>0.5*pi) then
75  lat = pi-lat
76  lon = lon+pi
77 elseif (lat<-0.5*pi) then
78  lat = -pi-lat
79  lon = lon+pi
80 end if
81 
82 ! Check longitude bounds
83 if (lon>pi) then
84  lon = lon-2.0*pi
85 elseif (lon<-pi) then
86  lon = lon+2.0*pi
87 end if
88 
89 end subroutine lonlatmod
90 
91 !----------------------------------------------------------------------
92 ! Function: lonlathash
93 !> Define a unique real from a lon/lat pair
94 !----------------------------------------------------------------------
95 function lonlathash(lon,lat,il)
96 
97 implicit none
98 
99 ! Passed variables
100 real(kind_real),intent(in) :: lon !< Longitude (radians)
101 real(kind_real),intent(in) :: lat !< Latitude (radians)
102 integer,intent(in),optional :: il !< Level
103 
104 ! Returned variable
105 real(kind_real) :: lonlathash
106 
107 ! Local variables
108 real(kind_real) :: lontmp,lattmp
109 
110 ! Set correct lon/lat
111 lontmp = lon
112 lattmp = lat
113 call lonlatmod(lontmp,lattmp)
114 
115 ! Hash value
116 lonlathash = aint((lontmp+pi)*1.0e6)+(lattmp+0.5*pi)*1.0e-1
117 if (present(il)) lonlathash = lonlathash+real(il*1e7,kind_real)
118 
119 end function lonlathash
120 
121 !----------------------------------------------------------------------
122 ! Subroutine: sphere_dist
123 !> Compute the great-circle distance between two points
124 !----------------------------------------------------------------------
125 subroutine sphere_dist(lon_i,lat_i,lon_f,lat_f,dist)
126 
127 implicit none
128 
129 ! Passed variable
130 real(kind_real),intent(in) :: lon_i !< Initial point longitude (radians)
131 real(kind_real),intent(in) :: lat_i !< Initial point latitude (radians)
132 real(kind_real),intent(in) :: lon_f !< Final point longitude (radians)
133 real(kind_real),intent(in) :: lat_f !< Final point longilatitudetude (radians)
134 real(kind_real),intent(out) :: dist !< Great-circle distance
135 
136 ! Local variables
137 type(atlas_geometry) :: ageometry
138 
139 ! Create ATLAS geometry
140 ageometry = atlas_geometry("UnitSphere")
141 
142 ! Compute distance
143 dist = ageometry%distance(lon_i*rad2deg,lat_i*rad2deg,lon_f*rad2deg,lat_f*rad2deg)
144 
145 end subroutine sphere_dist
146 
147 !----------------------------------------------------------------------
148 ! Subroutine: reduce_arc
149 !> Reduce arc to a given distance
150 !----------------------------------------------------------------------
151 subroutine reduce_arc(lon_i,lat_i,lon_f,lat_f,maxdist,dist)
152 
153 implicit none
154 
155 ! Passed variables
156 real(kind_real),intent(in) :: lon_i !< Initial point longitude (radians)
157 real(kind_real),intent(in) :: lat_i !< Initial point latitude (radians)
158 real(kind_real),intent(inout) :: lon_f !< Final point longitude (radians)
159 real(kind_real),intent(inout) :: lat_f !< Final point latitude (radians)
160 real(kind_real),intent(in) :: maxdist !< Maximum distance
161 real(kind_real),intent(out) :: dist !< Effective distance
162 
163 ! Local variable
164 real(kind_real) :: theta
165 
166 ! Compute distance
167 call sphere_dist(lon_i,lat_i,lon_f,lat_f,dist)
168 
169 ! Check with the maximum distance
170 if (sup(dist,maxdist)) then
171  ! Compute bearing
172  theta = atan2(sin(lon_f-lon_i)*cos(lat_f),cos(lat_i)*sin(lat_f)-sin(lat_i)*cos(lat_f)*cos(lon_f-lon_i))
173 
174  ! Reduce distance
175  dist = maxdist
176 
177  ! Compute new point
178  lat_f = asin(sin(lat_i)*cos(dist)+cos(lat_i)*sin(dist)*cos(theta))
179  lon_f = lon_i+atan2(sin(theta)*sin(dist)*cos(lat_i),cos(dist)-sin(lat_i)*sin(lat_f))
180 end if
181 
182 end subroutine reduce_arc
183 
184 !----------------------------------------------------------------------
185 ! Subroutine: lonlat2xyz
186 !> Convert longitude/latitude to cartesian coordinates
187 !----------------------------------------------------------------------
188 subroutine lonlat2xyz(mpl,lon,lat,x,y,z)
189 
190 implicit none
191 
192 ! Passed variables
193 type(mpl_type),intent(inout) :: mpl !< MPI data
194 real(kind_real),intent(in) :: lon !< Longitude (radians)
195 real(kind_real),intent(in) :: lat !< Latitude (radians)
196 real(kind_real),intent(out) :: x !< X coordinate
197 real(kind_real),intent(out) :: y !< Y coordinate
198 real(kind_real),intent(out) :: z !< Z coordinate
199 
200 ! Local variables
201 type(atlas_geometry) :: ageometry
202 character(len=1024),parameter :: subr = 'lonlat2xyz'
203 
204 if (mpl%msv%isnot(lat).and.mpl%msv%isnot(lon)) then
205  ! Check longitude/latitude
206  if (inf(lon,-pi).and.sup(lon,pi)) call mpl%abort(subr,'wrong longitude')
207  if (inf(lat,-0.5*pi).and.sup(lat,-0.5*pi)) call mpl%abort(subr,'wrong latitude')
208 
209  ! Create ATLAS geometry
210  ageometry = atlas_geometry("UnitSphere")
211 
212  ! Convert to x/y/z
213  call ageometry%lonlat2xyz(lon*rad2deg,lat*rad2deg,x,y,z)
214 else
215  ! Missing values
216  x = mpl%msv%valr
217  y = mpl%msv%valr
218  z = mpl%msv%valr
219 end if
220 
221 end subroutine lonlat2xyz
222 
223 !----------------------------------------------------------------------
224 ! Subroutine: xyz2lonlat
225 !> Convert longitude/latitude to cartesian coordinates
226 !----------------------------------------------------------------------
227 subroutine xyz2lonlat(mpl,x,y,z,lon,lat)
228 
229 implicit none
230 
231 ! Passed variables
232 type(mpl_type),intent(in) :: mpl !< MPI data
233 real(kind_real),intent(in) :: x !< X coordinate
234 real(kind_real),intent(in) :: y !< Y coordinate
235 real(kind_real),intent(in) :: z !< Z coordinate
236 real(kind_real),intent(out) :: lon !< Longitude (radians)
237 real(kind_real),intent(out) :: lat !< Latitude (radians)
238 
239 ! Local variables
240 type(atlas_geometry) :: ageometry
241 
242 if (mpl%msv%isnot(x).and.mpl%msv%isnot(y).and.mpl%msv%isnot(z)) then
243  ! Create ATLAS geometry
244  ageometry = atlas_geometry("UnitSphere")
245 
246  ! Convert to lon/lat
247  call ageometry%xyz2lonlat(x,y,z,lon,lat)
248 
249  ! Copy coordinates
250  lon = lon*deg2rad
251  lat = lat*deg2rad
252 else
253  ! Missing values
254  lon = mpl%msv%valr
255  lat = mpl%msv%valr
256 end if
257 
258 end subroutine xyz2lonlat
259 
260 !----------------------------------------------------------------------
261 ! Subroutine: vector_product
262 !> Compute normalized vector product
263 !----------------------------------------------------------------------
264 subroutine vector_product(v1,v2,vp)
265 
266 implicit none
267 
268 ! Passed variables
269 real(kind_real),intent(in) :: v1(3) !< First vector
270 real(kind_real),intent(in) :: v2(3) !< Second vector
271 real(kind_real),intent(out) :: vp(3) !< Vector product
272 
273 ! Local variable
274 real(kind_real) :: r
275 
276 ! Vector product
277 vp(1) = v1(2)*v2(3)-v1(3)*v2(2)
278 vp(2) = v1(3)*v2(1)-v1(1)*v2(3)
279 vp(3) = v1(1)*v2(2)-v1(2)*v2(1)
280 
281 ! Normalization
282 r = sqrt(sum(vp**2))
283 if (r>0.0) vp = vp/r
284 
285 end subroutine vector_product
286 
287 !----------------------------------------------------------------------
288 ! Subroutine: vector_triple_product
289 !> Compute vector triple product
290 !----------------------------------------------------------------------
291 subroutine vector_triple_product(v1,v2,v3,p,cflag)
292 
293 implicit none
294 
295 ! Passed variables
296 real(kind_real),intent(in) :: v1(3) !< First vector
297 real(kind_real),intent(in) :: v2(3) !< Second vector
298 real(kind_real),intent(in) :: v3(3) !< Third vector
299 real(kind_real),intent(out) :: p !< Triple product
300 logical,intent(out) :: cflag !< Confidence flag
301 
302 ! Local variable
303 integer :: i
304 real(kind_real) :: terms(6)
305 
306 ! Terms
307 terms(1) = v1(2)*v2(3)*v3(1)
308 terms(2) = -v1(3)*v2(2)*v3(1)
309 terms(3) = v1(3)*v2(1)*v3(2)
310 terms(4) = -v1(1)*v2(3)*v3(2)
311 terms(5) = v1(1)*v2(2)*v3(3)
312 terms(6) = -v1(2)*v2(1)*v3(3)
313 
314 ! Sum
315 p = sum(terms)
316 
317 ! Confidence flag
318 cflag = .true.
319 do i=1,6
320  if ((abs(terms(i))>0.0).and.small(p,terms(i))) cflag = .false.
321 end do
322 
323 end subroutine vector_triple_product
324 
325 !----------------------------------------------------------------------
326 ! Subroutine: add
327 !> Check if value missing and add if not missing
328 !----------------------------------------------------------------------
329 subroutine add(mpl,val,cumul,num,wgt)
330 
331 implicit none
332 
333 ! Passed variables
334 type(mpl_type),intent(in) :: mpl !< MPI data
335 real(kind_real),intent(in) :: val !< Value to add
336 real(kind_real),intent(inout) :: cumul !< Cumul
337 real(kind_real),intent(inout) :: num !< Number of values
338 real(kind_real),intent(in),optional :: wgt !< Weight
339 
340 ! Local variables
341 real(kind_real) :: lwgt
342 
343 ! Initialize weight
344 lwgt = 1.0
345 if (present(wgt)) lwgt = wgt
346 
347 ! Add value to cumul
348 if (mpl%msv%isnot(val)) then
349  cumul = cumul+lwgt*val
350  num = num+lwgt
351 end if
352 
353 end subroutine add
354 
355 !----------------------------------------------------------------------
356 ! Subroutine: divide
357 !> Check if value missing and divide if not missing
358 !----------------------------------------------------------------------
359 subroutine divide(mpl,val,num)
360 
361 implicit none
362 
363 ! Passed variables
364 type(mpl_type),intent(in) :: mpl !< MPI data
365 real(kind_real),intent(inout) :: val !< Value to divide
366 real(kind_real),intent(in) :: num !< Divider
367 
368 ! Divide cumul by num
369 if (abs(num)>0.0) then
370  val = val/num
371 else
372  val = mpl%msv%valr
373 end if
374 
375 end subroutine divide
376 
377 !----------------------------------------------------------------------
378 ! Subroutine: fit_diag
379 !> Compute diagnostic fit function
380 !----------------------------------------------------------------------
381 subroutine fit_diag(mpl,nc3,nl0r,nl0,l0rl0_to_l0,disth,distv,coef,rh,rv,fit)
382 
383 implicit none
384 
385 ! Passed variables
386 type(mpl_type),intent(inout) :: mpl !< MPI data
387 integer,intent(in) :: nc3 !< Number of classes
388 integer,intent(in) :: nl0r !< Effective number of levels
389 integer,intent(in) :: nl0 !< Number of levels
390 integer,intent(in) :: l0rl0_to_l0(nl0r,nl0) !< Effective level to level
391 real(kind_real),intent(in) :: disth(nc3) !< Horizontal distance
392 real(kind_real),intent(in) :: distv(nl0,nl0) !< Vertical distance
393 real(kind_real),intent(in) :: coef(nl0) !< Diagonal coefficient
394 real(kind_real),intent(in) :: rh(nl0) !< Horizontal support radius
395 real(kind_real),intent(in) :: rv(nl0) !< Vertical support radius
396 real(kind_real),intent(out) :: fit(nc3,nl0r,nl0) !< Fit
397 
398 ! Local variables
399 integer :: jl0r,jl0,djl0,il0,kl0r,kl0,ic3,jc3,djc3,kc3,ip,jp,np,np_new,nc3max
400 integer :: plist(nc3*nl0r,2),plist_new(nc3*nl0r,2)
401 real(kind_real) :: rhsq,rvsq,distvsq,disttest,rhmax
402 real(kind_real) :: predistnorm(-1:1,nc3,-1:1,nl0),distnorm(nc3,nl0r)
403 logical :: add_to_front
404 
405 ! Initialization
406 fit = 0.0
407 
408 ! Find maximum class
409 rhmax = maxval(rh)
410 nc3max = 0
411 do ic3=1,nc3
412  if (disth(ic3)>rhmax) exit
413  nc3max = ic3
414 end do
415 
416 ! Precompute normalized local distances
417 predistnorm = 1.0
418 do il0=1,nl0
419  do djl0=-1,1
420  ! Level index
421  jl0 = max(1,min(il0+djl0,nl0))
422 
423  ! Averaged fit parameters
424  if (mpl%msv%isnot(rh(il0)).and.mpl%msv%isnot(rh(jl0))) then
425  rhsq = 0.5*(rh(il0)**2+rh(jl0)**2)
426  else
427  rhsq = 0.0
428  end if
429  if (mpl%msv%isnot(rv(il0)).and.mpl%msv%isnot(rv(jl0))) then
430  rvsq = 0.5*(rv(il0)**2+rv(jl0)**2)
431  else
432  rvsq = 0.0
433  end if
434 
435  ! Squared vertical distance
436  if (rvsq>0.0) then
437  distvsq = distv(jl0,il0)**2/rvsq
438  elseif (il0/=jl0) then
439  distvsq = 1.0
440  else
441  distvsq = 0.0
442  end if
443 
444  do ic3=1,nc3max
445  do djc3=-1,1
446  ! Horizontal index
447  jc3 = max(1,min(ic3+djc3,nc3max))
448 
449  ! Squared normalized distance initialization (squared vertical component)
450  predistnorm(djc3,ic3,djl0,il0) = distvsq
451 
452  ! Add squared horizontal component to squared normalized distance
453  if (rhsq>0.0) then
454  predistnorm(djc3,ic3,djl0,il0) = predistnorm(djc3,ic3,djl0,il0)+(disth(jc3)-disth(ic3))**2/rhsq
455  elseif (ic3/=jc3) then
456  predistnorm(djc3,ic3,djl0,il0) = predistnorm(djc3,ic3,djl0,il0)+1.0
457  end if
458 
459  ! Get normalized distance
460  predistnorm(djc3,ic3,djl0,il0) = sqrt(predistnorm(djc3,ic3,djl0,il0))
461  end do
462  end do
463  end do
464 end do
465 
466 ! Compte fit
467 do il0=1,nl0
468  ! Initialize the front
469  np = 1
470  plist = mpl%msv%vali
471  plist(1,1) = 1
472  do jl0r=1,nl0r
473  if (l0rl0_to_l0(jl0r,il0)==il0) plist(1,2) = jl0r
474  end do
475  distnorm = 1.0
476  distnorm(plist(1,1),plist(1,2)) = 0.0
477 
478  do while (np>0)
479  ! Propagate the front
480  np_new = 0
481 
482  do ip=1,np
483  ! Indices of the central point
484  jc3 = plist(ip,1)
485  jl0r = plist(ip,2)
486  jl0 = l0rl0_to_l0(jl0r,il0)
487 
488  ! Loop over neighbors
489  do kc3=max(jc3-1,1),min(jc3+1,nc3max)
490  do kl0r=max(jl0r-1,1),min(jl0r+1,nl0r)
491  kl0 = l0rl0_to_l0(kl0r,il0)
492  disttest = distnorm(jc3,jl0r)+predistnorm(kc3-jc3,jc3,kl0-jl0,jl0)
493 
494  if (disttest<1.0) then
495  ! Point is inside the support
496  if (disttest<distnorm(kc3,kl0r)) then
497  ! Update distance
498  distnorm(kc3,kl0r) = disttest
499 
500  ! Check if the point should be added to the front (avoid duplicates)
501  add_to_front = .true.
502  do jp=1,np_new
503  if ((plist_new(jp,1)==kc3).and.(plist_new(jp,2)==kl0r)) then
504  add_to_front = .false.
505  exit
506  end if
507  end do
508 
509  if (add_to_front) then
510  ! Add point to the front
511  np_new = np_new+1
512  plist_new(np_new,1) = kc3
513  plist_new(np_new,2) = kl0r
514  end if
515  end if
516  end if
517  end do
518  end do
519  end do
520 
521  ! Copy new front
522  np = np_new
523  plist(1:np,:) = plist_new(1:np,:)
524  end do
525 
526  do jl0r=1,nl0r
527  ! Level index
528  jl0 = l0rl0_to_l0(jl0r,il0)
529 
530  do jc3=1,nc3
531  ! Fit function
532  fit(jc3,jl0r,il0) = fit_func(mpl,distnorm(jc3,jl0r))
533  end do
534  end do
535 end do
536 
537 ! Diagonal coefficient
538 do il0=1,nl0
539  do jl0r=1,nl0r
540  jl0 = l0rl0_to_l0(jl0r,il0)
541  fit(:,jl0r,il0) = fit(:,jl0r,il0)*sqrt(coef(il0)*coef(jl0))
542  end do
543 end do
544 
545 ! Set to missing values if no value available
546 do il0=1,nl0
547  if (mpl%msv%is(coef(il0)).or.mpl%msv%is(rh(il0)).or.mpl%msv%is(rv(il0))) fit(:,:,il0) = mpl%msv%valr
548  do jl0r=1,nl0r
549  jl0 = l0rl0_to_l0(jl0r,il0)
550  if (mpl%msv%is(coef(jl0)).or.mpl%msv%is(rh(jl0)).or.mpl%msv%is(rv(jl0))) fit(:,jl0r,il0) = mpl%msv%valr
551  end do
552 end do
553 
554 end subroutine fit_diag
555 
556 !----------------------------------------------------------------------
557 ! Function: gc99
558 !> Gaspari and Cohn (1999) function, with the support radius as a parameter
559 !----------------------------------------------------------------------
560 function gc99(distnorm)
561 
562 ! Passed variables
563 real(kind_real),intent(in) :: distnorm !< Normalized distance
564 
565 ! Returned variable
566 real(kind_real) :: gc99
567 
568 ! Gaspari and Cohn (1999) function
569 if (distnorm<0.5) then
570  gc99 = -8.0*distnorm**5+8.0*distnorm**4+5.0*distnorm**3-20.0/3.0*distnorm**2+1.0
571 else if (distnorm<1.0) then
572  gc99 = 8.0/3.0*distnorm**5-8.0*distnorm**4+5.0*distnorm**3+20.0/3.0*distnorm**2-10.0*distnorm+4.0-1.0/(3.0*distnorm)
573 else
574  gc99 = 0.0
575 end if
576 
577 end function gc99
578 
579 !----------------------------------------------------------------------
580 ! Function: fit_func
581 !> Fit_function
582 !----------------------------------------------------------------------
583 function fit_func(mpl,distnorm)
584 
585 ! Passed variables
586 type(mpl_type),intent(inout) :: mpl !< MPI data
587 real(kind_real),intent(in) :: distnorm !< Normalized distance
588 
589 ! Returned variable
590 real(kind_real) :: fit_func
591 
592 ! Local variables
593 character(len=1024),parameter :: subr = 'fit_func'
594 
595 ! Distance check bound
596 if (distnorm<0.0) call mpl%abort(subr,'negative normalized distance')
597 
598 ! Gaspari and Cohn (1999) function
599 fit_func = gc99(distnorm)
600 
601 ! Enforce positivity
602 fit_func = max(fit_func,0.0_kind_real)
603 
604 end function fit_func
605 
606 !----------------------------------------------------------------------
607 ! Subroutine: fit_lct
608 !> LCT fit
609 !----------------------------------------------------------------------
610 subroutine fit_lct(mpl,nc,nl0,dxsq,dysq,dxdy,dzsq,dmask,nscales,D,coef,fit)
611 
612 implicit none
613 
614 ! Passed variables
615 type(mpl_type),intent(inout) :: mpl !< MPI data
616 integer,intent(in) :: nc !< Number of classes
617 integer,intent(in) :: nl0 !< Number of levels
618 real(kind_real),intent(in) :: dxsq(nc,nl0) !< Zonal separation squared
619 real(kind_real),intent(in) :: dysq(nc,nl0) !< Meridian separation squared
620 real(kind_real),intent(in) :: dxdy(nc,nl0) !< Zonal x meridian separations product
621 real(kind_real),intent(in) :: dzsq(nc,nl0) !< Vertical separation squared
622 logical,intent(in) :: dmask(nc,nl0) !< Mask
623 integer,intent(in) :: nscales !< Number of LCT scales
624 real(kind_real),intent(in) :: d(4,nscales) !< LCT components
625 real(kind_real),intent(in) :: coef(nscales) !< LCT coefficients
626 real(kind_real),intent(out) :: fit(nc,nl0) !< Fit
627 
628 ! Local variables
629 integer :: jl0,jc3,iscales
630 real(kind_real) :: dcoef(nscales),d11,d22,d33,d12,h11,h22,h33,h12,rsq
631 
632 ! Initialization
633 fit = mpl%msv%valr
634 
635 ! Coefficients
636 dcoef = max(dmin,min(coef,1.0_kind_real))
637 dcoef = dcoef/sum(dcoef)
638 
639 do iscales=1,nscales
640  ! Ensure positive-definiteness of D
641  d11 = max(dmin,d(1,iscales))
642  d22 = max(dmin,d(2,iscales))
643  if (nl0>1) then
644  d33 = max(dmin,d(3,iscales))
645  else
646  d33 = 0.0
647  end if
648  d12 = sqrt(d11*d22)*max(-1.0_kind_real+dmin,min(d(4,iscales),1.0_kind_real-dmin))
649 
650  ! Inverse D to get H
651  call lct_d2h(mpl,d11,d22,d33,d12,h11,h22,h33,h12)
652 
653  ! Homogeneous anisotropic approximation
654  do jl0=1,nl0
655  do jc3=1,nc
656  if (dmask(jc3,jl0)) then
657  ! Initialization
658  if (iscales==1) fit(jc3,jl0) = 0.0
659 
660  ! Squared distance
661  rsq = h11*dxsq(jc3,jl0)+h22*dysq(jc3,jl0)+h33*dzsq(jc3,jl0)+2.0*h12*dxdy(jc3,jl0)
662 
663  if (m==0) then
664  ! Gaussian function
665  if (rsq<40.0) fit(jc3,jl0) = fit(jc3,jl0)+dcoef(iscales)*exp(-0.5*rsq)
666  else
667  ! Matern function
668  fit(jc3,jl0) = fit(jc3,jl0)+dcoef(iscales)*matern(mpl,m,sqrt(rsq))
669  end if
670  end if
671  end do
672  end do
673 end do
674 
675 end subroutine fit_lct
676 
677 !----------------------------------------------------------------------
678 ! Subroutine: lct_d2h
679 !> From D (Daley tensor) to H (local correlation tensor)
680 !----------------------------------------------------------------------
681 subroutine lct_d2h(mpl,D11,D22,D33,D12,H11,H22,H33,H12)
682 
683 implicit none
684 
685 ! Passed variables
686 type(mpl_type),intent(inout) :: mpl!< MPI data
687 real(kind_real),intent(in) :: d11 !< Daley tensor component 11
688 real(kind_real),intent(in) :: d22 !< Daley tensor component 22
689 real(kind_real),intent(in) :: d33 !< Daley tensor component 33
690 real(kind_real),intent(in) :: d12 !< Daley tensor component 12
691 real(kind_real),intent(out) :: h11 !< Local correlation tensor component 11
692 real(kind_real),intent(out) :: h22 !< Local correlation tensor component 22
693 real(kind_real),intent(out) :: h33 !< Local correlation tensor component 33
694 real(kind_real),intent(out) :: h12 !< Local correlation tensor component 12
695 
696 ! Local variables
697 real(kind_real) :: det
698 character(len=1024),parameter :: subr = 'lct_d2h'
699 
700 ! Compute horizontal determinant
701 det = d11*d22-d12**2
702 
703 ! Inverse D to get H
704 if (det>0.0) then
705  h11 = d22/det
706  h22 = d11/det
707  h12 = -d12/det
708 else
709  call mpl%abort(subr,'non-invertible tensor')
710 end if
711 if (d33>0.0) then
712  h33 = 1.0/d33
713 else
714  h33 = 0.0
715 end if
716 
717 end subroutine lct_d2h
718 
719 !----------------------------------------------------------------------
720 ! Subroutine: lct_h2r
721 !> From H (local correlation tensor) to support radii
722 !----------------------------------------------------------------------
723 subroutine lct_h2r(mpl,H11,H22,H33,H12,rh,rv)
724 
725 implicit none
726 
727 ! Passed variables
728 type(mpl_type),intent(inout) :: mpl !< MPI data
729 real(kind_real),intent(in) :: h11 !< Local correlation tensor component 11
730 real(kind_real),intent(in) :: h22 !< Local correlation tensor component 22
731 real(kind_real),intent(in) :: h33 !< Local correlation tensor component 33
732 real(kind_real),intent(in) :: h12 !< Local correlation tensor component 12
733 real(kind_real),intent(out) :: rh !< Horizontal support radius
734 real(kind_real),intent(out) :: rv !< Vertical support radius
735 
736 ! Local variables
737 real(kind_real) :: tr,det,diff
738 character(len=1024),parameter :: subr = 'lct_h2r'
739 
740 ! Check diagonal positivity
741 if ((h11<0.0).or.(h22<0.0)) call mpl%abort(subr,'negative diagonal LCT coefficients')
742 
743 ! Compute horizontal trace
744 tr = h11+h22
745 
746 ! Compute horizontal determinant
747 det = h11*h22-h12**2
748 
749 ! Compute horizontal support radius
750 diff = 0.25*(h11-h22)**2+h12**2
751 if ((det>0.0).and..not.(diff<0.0)) then
752  if (0.5*tr>sqrt(diff)) then
753  rh = gau2gc/sqrt(0.5*tr-sqrt(diff))
754  else
755  call mpl%abort(subr,'non positive-definite LCT (eigenvalue)')
756  end if
757 else
758  call mpl%abort(subr,'non positive-definite LCT (determinant)')
759 end if
760 
761 ! Compute vertical support radius
762 if (h33>0.0) then
763  rv = gau2gc/sqrt(h33)
764 else
765  rv = 0.0
766 end if
767 
768 end subroutine lct_h2r
769 
770 !----------------------------------------------------------------------
771 ! Subroutine: lct_r2d
772 !> From support radius to Daley tensor diagonal element
773 !----------------------------------------------------------------------
774 subroutine lct_r2d(r,D)
775 
776 implicit none
777 
778 ! Passed variables
779 real(kind_real),intent(in) :: r !< Support radius
780 real(kind_real),intent(out) :: d !< Daley tensor diagonal element
781 
782 ! Convert from support radius to Daley length-scale and square
783 d = (gc2gau*r)**2
784 
785 end subroutine lct_r2d
786 
787 !----------------------------------------------------------------------
788 ! Subroutine: check_cond
789 !> Check tensor conditioning
790 !----------------------------------------------------------------------
791 subroutine check_cond(d1,d2,nod,valid)
792 
793 implicit none
794 
795 ! Passed variables
796 real(kind_real),intent(in) :: d1 !< First diagonal coefficient
797 real(kind_real),intent(in) :: d2 !< Second diagonal coefficient
798 real(kind_real),intent(in) :: nod !< Normalized off-diagonal coefficient
799 logical,intent(out) :: valid !< Conditioning validity
800 
801 ! Local variables
802 real(kind_real) :: det,tr,diff,ev1,ev2
803 
804 ! Compute trace and determinant
805 tr = d1+d2
806 det = d1*d2*(1.0-nod**2)
807 diff = 0.25*(d1-d2)**2+d1*d2*nod**2
808 
809 if ((det>0.0).and..not.(diff<0.0)) then
810  ! Compute eigenvalues
811  ev1 = 0.5*tr+sqrt(diff)
812  ev2 = 0.5*tr-sqrt(diff)
813 
814  if (ev2>0.0) then
815  ! Check conditioning
816  valid = inf(ev1,condmax*ev2)
817  else
818  ! Lowest negative eigenvalue is negative
819  valid = .false.
820  end if
821 else
822  ! Non-positive definite tensor
823  valid = .false.
824 end if
825 
826 end subroutine check_cond
827 
828 !----------------------------------------------------------------------
829 ! Function: matern
830 !> Compute the normalized diffusion function from eq. (55) of Mirouze and Weaver (2013), for the 3d case (d = 3)
831 !----------------------------------------------------------------------
832 real(kind_real) function matern(mpl,M,x)
833 
834 implicit none
835 
836 ! Passed variables
837 type(mpl_type),intent(inout) :: mpl !< MPI data
838 integer,intent(in) :: m !< Matern function order
839 real(kind_real),intent(in) :: x !< Argument
840 
841 ! Local variables
842 integer :: j
843 real(kind_real) :: xtmp,beta
844 character(len=1024),parameter :: subr = 'matern'
845 
846 ! Check
847 if (m<2) call mpl%abort(subr,'M should be larger than 2')
848 if (mod(m,2)>0) call mpl%abort(subr,'M should be even')
849 
850 ! Initialization
851 matern = 0.0
852 beta = 1.0
853 xtmp = x*sqrt(real(2*m-5,kind_real))
854 
855 do j=0,m-3
856  ! Update sum
857  matern = matern+beta*(xtmp)**(m-2-j)
858 
859  ! Update beta
860  beta = beta*real((j+1+m-2)*(-j+m-2),kind_real)/real(2*(j+1),kind_real)
861 end do
862 
863 ! Last term and normalization
864 matern = matern/beta+1.0
865 
866 ! Exponential factor
867 matern = matern*exp(-xtmp)
868 
869 end function matern
870 
871 !----------------------------------------------------------------------
872 ! Subroutine: cholesky
873 !> Compute cholesky decomposition
874 ! Author: Original FORTRAN77 version by Michael Healy, modifications by AJ Miller, FORTRAN90 version by John Burkardt.
875 !----------------------------------------------------------------------
876 subroutine cholesky(mpl,n,a,u,ierr)
877 
878 implicit none
879 
880 ! Passed variables
881 type(mpl_type),intent(inout) :: mpl !< MPI data
882 integer,intent(in) :: n !< Matrix rank
883 real(kind_real),intent(in) :: a(n,n) !< Matrix
884 real(kind_real),intent(out) :: u(n,n) !< Matrix square-root
885 integer,intent(out) :: ierr !< Error status
886 
887 ! Local variables
888 integer :: nn,i,j,ij
889 real(kind_real),allocatable :: apack(:),upack(:)
890 
891 ! Allocation
892 nn = (n*(n+1))/2
893 allocate(apack(nn))
894 allocate(upack(nn))
895 
896 ! Pack matrix
897 ij = 0
898 do i=1,n
899  do j=1,i
900  ij = ij+1
901  apack(ij) = a(i,j)
902  end do
903 end do
904 
905 ! Cholesky decomposition
906 call asa007_cholesky(mpl,n,nn,apack,upack,ierr)
907 
908 ! Unpack matrix
909 ij = 0
910 u = 0.0
911 do i=1,n
912  do j=1,i
913  ij = ij+1
914  u(i,j) = upack(ij)
915  end do
916 end do
917 
918 ! Release memory
919 deallocate(apack)
920 deallocate(upack)
921 
922 end subroutine cholesky
923 
924 !----------------------------------------------------------------------
925 ! Subroutine: syminv
926 !> Compute inverse of a symmetric matrix
927 ! Author: Original FORTRAN77 version by Michael Healy, modifications by AJ Miller, FORTRAN90 version by John Burkardt.
928 !----------------------------------------------------------------------
929 subroutine syminv(mpl,n,a,c,ierr)
930 
931 implicit none
932 
933 ! Passed variables
934 type(mpl_type),intent(inout) :: mpl !< MPI data
935 integer,intent(in) :: n !< Matrix rank
936 real(kind_real),intent(in) :: a(n,n) !< Matrix
937 real(kind_real),intent(out) :: c(n,n) !< Matrix inverse
938 integer,intent(out) :: ierr !< Error status
939 
940 ! Local variables
941 integer :: nn,i,j,ij
942 real(kind_real),allocatable :: apack(:),cpack(:)
943 
944 ! Allocation
945 nn = (n*(n+1))/2
946 allocate(apack(nn))
947 allocate(cpack(nn))
948 
949 ! Pack matrix
950 ij = 0
951 do i=1,n
952  do j=1,i
953  ij = ij+1
954  apack(ij) = a(i,j)
955  end do
956 end do
957 
958 ! Matrix inversion
959 call asa007_syminv(mpl,n,nn,apack,cpack,ierr)
960 
961 ! Unpack matrix
962 ij = 0
963 do i=1,n
964  do j=1,i
965  ij = ij+1
966  c(i,j) = cpack(ij)
967  c(j,i) = c(i,j)
968  end do
969 end do
970 
971 ! Release memory
972 deallocate(apack)
973 deallocate(cpack)
974 
975 end subroutine syminv
976 
977 !----------------------------------------------------------------------
978 ! Subroutine: pseudoinv
979 ! Purpose: Compute pseudo inverse of a symmetric matrix.
980 ! Author: This routine is from WRFDA.
981 !----------------------------------------------------------------------
982 subroutine pseudoinv(mpl,n,a,c,ierr,mmax,var_th)
983 
984 implicit none
985 
986 ! Passed variables
987 type(mpl_type),intent(inout) :: mpl ! MPI data
988 integer,intent(in) :: n ! Matrix rank
989 real(kind_real),intent(in) :: a(n,n) ! Matrix
990 real(kind_real),intent(out) :: c(n,n) ! Matrix inverse
991 integer,intent(out) :: ierr ! Error status
992 integer,intent(in),optional :: mmax ! Dominant mode
993 real(kind_real),intent(in),optional :: var_th ! Variance threshold
994 
995 ! Local variables
996 integer :: k,k2,m,lmmax
997 real(kind_real),allocatable :: work(:,:),evec(:,:),eval(:),laminvet(:,:)
998 real(kind_real),allocatable :: summ,total_variance,cumul_variance
999 character(len=1024),parameter :: subr = 'pseudoinv'
1000 
1001 ! Allocation
1002 allocate(work(n,n))
1003 allocate(evec(n,n))
1004 allocate(eval(n))
1005 allocate(laminvet(n,n))
1006 
1007 ! Initialization
1008 work = a
1009 laminvet = 0.0
1010 
1011 ! EOF decomposition
1012 call da_eof_decomposition(n,work,evec,eval,ierr)
1013 
1014 ! Select dominant mode
1015 if (present(mmax)) then
1016  ! Input argument
1017  lmmax = mmax
1018 else
1019  if (present(var_th)) then
1020  ! Based on variance threshold
1021  summ = 0.0
1022  do m=1,n
1023  summ = summ+eval(m)
1024  end do
1025  total_variance = summ
1026  cumul_variance = 0.0
1027  lmmax = n
1028  do m=1,n
1029  cumul_variance = cumul_variance+eval(m)/total_variance
1030  if (cumul_variance>1.0-var_th ) then
1031  lmmax = m-1
1032  exit
1033  end if
1034  end do
1035  else
1036  call mpl%abort(subr,'either dominant mode or variance threshold should be specified')
1037  end if
1038 end if
1039 if (lmmax>n) call mpl%abort(subr,'dominant mode should smaller than the matrix rank')
1040 
1041 ! Lam{-1} . E^T:
1042 do k=1,n
1043  do m=1,lmmax
1044  laminvet(m,k) = evec(k,m)/eval(m)
1045  end do
1046 end do
1047 
1048 ! <a,a>^{-1} = E . Lam{-1} . E^T:
1049 do k=1,n
1050  do k2=1,k
1051  summ = 0.0
1052  do m=1,n
1053  summ = summ+evec(k,m)*laminvet(m,k2)
1054  end do
1055  c(k,k2) = summ
1056  end do
1057 end do
1058 
1059 ! Symmetry
1060 do k=1,n
1061  do k2=k+1,n
1062  c(k,k2) = c(k2,k)
1063  end do
1064 end do
1065 
1066 ! Release memory
1067 deallocate(work)
1068 deallocate(evec)
1069 deallocate(eval)
1070 deallocate(laminvet)
1071 
1072 end subroutine pseudoinv
1073 
1074 !----------------------------------------------------------------------
1075 ! Subroutine: da_eof_decomposition
1076 ! Purpose: Compute eigenvectors E and eigenvalues L of covariance matrix.
1077 !! B_{x} defined by equation: E^{T} B_{x} E = L, given input kz x kz matrix.
1078 ! Author: This routine is from WRFDA.
1079 !----------------------------------------------------------------------
1080 subroutine da_eof_decomposition(kz,bx,e,l,ierr)
1081 
1082 implicit none
1083 
1084 ! Passed variables
1085 integer, intent(in) :: kz ! Dimension of error matrix
1086 real(kind_real),intent(in) :: bx(1:kz,1:kz) ! Vert. background error
1087 real(kind_real),intent(out) :: e(1:kz,1:kz) ! Eigenvectors of Bx
1088 real(kind_real),intent(out) :: l(1:kz) ! Eigenvalues of Bx
1089 integer,intent(out) :: ierr ! Error status
1090 
1091 ! Local variables
1092 integer :: work,m,info
1093 real(kind_real) :: work_array(1:3*kz-1),ecopy(1:kz,1:kz),lcopy(1:kz)
1094 
1095 ! Initialization
1096 work = 3*kz-1
1097 ecopy = bx
1098 lcopy = 0.0
1099 
1100 ! Perform global eigenvalue decomposition using LAPACK software
1101 call dsyev('V','U',kz,ecopy,kz,lcopy,work_array,work,ierr)
1102 
1103 ! Swap order of eigenvalues, vectors so 1st is one with most variance
1104 do m=1,kz
1105  l(m) = lcopy(kz+1-m)
1106  e(1:kz,m) = ecopy(1:kz,kz+1-m)
1107 end do
1108 
1109 end subroutine da_eof_decomposition
1110 
1111 !----------------------------------------------------------------------
1112 ! Subroutine: histogram
1113 !> Compute bins and histogram from a list of values
1114 !----------------------------------------------------------------------
1115 subroutine histogram(mpl,nlist,list,nbins,histmin,histmax,bins,hist)
1116 
1117 implicit none
1118 
1119 ! Passed variables
1120 type(mpl_type),intent(inout) :: mpl !< MPI data
1121 integer,intent(in) :: nlist !< List size
1122 real(kind_real),intent(in) :: list(nlist) !< List
1123 integer,intent(in) :: nbins !< Number of bins
1124 real(kind_real),intent(in) :: histmin !< Histogram minimum
1125 real(kind_real),intent(in) :: histmax !< Histogram maximum
1126 real(kind_real),intent(out) :: bins(nbins+1) !< Bins
1127 real(kind_real),intent(out) :: hist(nbins) !< Histogram
1128 
1129 ! Local variables
1130 integer :: ibins,ilist
1131 real(kind_real) :: delta
1132 logical :: found
1133 character(len=1024) :: subr = 'histogram'
1134 
1135 ! Check data
1136 if (nbins<=0) call mpl%abort(subr,'the number of bins should be positive')
1137 if (histmax>histmin) then
1138  if (minval(list,mask=mpl%msv%isnot(list))<histmin) call mpl%abort(subr,'values below histogram minimum')
1139  if (maxval(list,mask=mpl%msv%isnot(list))>histmax) call mpl%abort(subr,'values over histogram maximum')
1140 
1141  ! Compute bins
1142  delta = (histmax-histmin)/real(nbins,kind_real)
1143  bins(1) = histmin
1144  do ibins=2,nbins
1145  bins(ibins) = histmin+real(ibins-1,kind_real)*delta
1146  end do
1147  bins(nbins+1) = histmax
1148 
1149  ! Extend first and last bins
1150  bins(1) = bins(1)-1.0e-6*delta
1151  bins(nbins+1) = bins(nbins+1)+1.0e-6*delta
1152 
1153  ! Compute histogram
1154  hist = 0.0
1155  do ilist=1,nlist
1156  if (mpl%msv%isnot(list(ilist))) then
1157  ibins = 0
1158  found = .false.
1159  do while (.not.found)
1160  ibins = ibins+1
1161  if (ibins>nbins) call mpl%abort(subr,'bin not found')
1162  if (infeq(bins(ibins),list(ilist)).and.inf(list(ilist),bins(ibins+1))) then
1163  hist(ibins) = hist(ibins)+1.0
1164  found = .true.
1165  end if
1166  end do
1167  end if
1168  end do
1169  if (abs(sum(hist)-real(count(mpl%msv%isnot(list)),kind_real))>0.5) &
1170  & call mpl%abort(subr,'histogram sum is not equal to the number of valid elements')
1171 else
1172  bins = mpl%msv%valr
1173  hist = 0.0
1174 end if
1175 
1176 end subroutine histogram
1177 
1178 end module tools_func
tools_func::sphere_dist
subroutine, public sphere_dist(lon_i, lat_i, lon_f, lat_f, dist)
Compute the great-circle distance between two points.
Definition: tools_func.F90:126
tools_repro::sup
logical function, public sup(x, y)
Superior test for reals.
Definition: tools_repro.F90:92
tools_repro::inf
logical function, public inf(x, y)
Inferior test for reals.
Definition: tools_repro.F90:53
tools_func::fit_func
real(kind_real) function, public fit_func(mpl, distnorm)
Fit_function.
Definition: tools_func.F90:584
tools_func::pseudoinv
subroutine, public pseudoinv(mpl, n, a, c, ierr, mmax, var_th)
Definition: tools_func.F90:983
tools_func::fit_diag
subroutine, public fit_diag(mpl, nc3, nl0r, nl0, l0rl0_to_l0, disth, distv, coef, rh, rv, fit)
Compute diagnostic fit function.
Definition: tools_func.F90:382
tools_const
Define usual constants and missing values.
Definition: tools_const.F90:8
tools_func::add
subroutine, public add(mpl, val, cumul, num, wgt)
Check if value missing and add if not missing.
Definition: tools_func.F90:330
tools_func::check_cond
subroutine, public check_cond(d1, d2, nod, valid)
Check tensor conditioning.
Definition: tools_func.F90:792
tools_func::syminv
subroutine, public syminv(mpl, n, a, c, ierr)
Compute inverse of a symmetric matrix.
Definition: tools_func.F90:930
tools_kinds::kind_short
integer, parameter, public kind_short
Definition: tools_kinds.F90:17
tools_func::vector_triple_product
subroutine, public vector_triple_product(v1, v2, v3, p, cflag)
Compute vector triple product.
Definition: tools_func.F90:292
tools_func
Usual functions.
Definition: tools_func.F90:8
tools_func::dmin
real(kind_real), parameter, public dmin
Definition: tools_func.F90:22
tools_func::lonlat2xyz
subroutine, public lonlat2xyz(mpl, lon, lat, x, y, z)
Convert longitude/latitude to cartesian coordinates.
Definition: tools_func.F90:189
tools_func::histogram
subroutine, public histogram(mpl, nlist, list, nbins, histmin, histmax, bins, hist)
Compute bins and histogram from a list of values.
Definition: tools_func.F90:1116
tools_func::condmax
real(kind_real), parameter condmax
Definition: tools_func.F90:23
tools_asa007
Inverse of symmetric positive definite matrix routines.
Definition: tools_asa007.F90:13
tools_func::da_eof_decomposition
subroutine da_eof_decomposition(kz, bx, e, l, ierr)
Definition: tools_func.F90:1081
tools_func::lct_d2h
subroutine, public lct_d2h(mpl, D11, D22, D33, D12, H11, H22, H33, H12)
From D (Daley tensor) to H (local correlation tensor)
Definition: tools_func.F90:682
tools_func::fit_lct
subroutine, public fit_lct(mpl, nc, nl0, dxsq, dysq, dxdy, dzsq, dmask, nscales, D, coef, fit)
LCT fit.
Definition: tools_func.F90:611
tools_func::gc2gau
real(kind_real), parameter, public gc2gau
Definition: tools_func.F90:20
tools_repro::small
logical function, public small(x, y)
Small value test.
Definition: tools_repro.F90:157
tools_func::gc99
real(kind_real) function gc99(distnorm)
Gaspari and Cohn (1999) function, with the support radius as a parameter.
Definition: tools_func.F90:561
tools_func::m
integer, parameter, public m
Definition: tools_func.F90:24
tools_func::gau2gc
real(kind_real), parameter, public gau2gc
Definition: tools_func.F90:21
tools_repro
Reproducibility functions.
Definition: tools_repro.F90:8
tools_func::matern
real(kind_real) function matern(mpl, M, x)
Compute the normalized diffusion function from eq. (55) of Mirouze and Weaver (2013),...
Definition: tools_func.F90:833
tools_func::lct_r2d
subroutine, public lct_r2d(r, D)
From support radius to Daley tensor diagonal element.
Definition: tools_func.F90:775
tools_asa007::asa007_cholesky
subroutine, public asa007_cholesky(mpl, n, nn, a, u, ierr)
Compute cholesky decomposition.
Definition: tools_asa007.F90:33
tools_func::cholesky
subroutine, public cholesky(mpl, n, a, u, ierr)
Compute cholesky decomposition.
Definition: tools_func.F90:877
tools_func::xyz2lonlat
subroutine, public xyz2lonlat(mpl, x, y, z, lon, lat)
Convert longitude/latitude to cartesian coordinates.
Definition: tools_func.F90:228
tools_repro::infeq
logical function, public infeq(x, y)
Inferior or equal test for reals.
Definition: tools_repro.F90:73
fletcher32
uint32_t fletcher32(uint32_t *n, uint16_t const *var)
Definition: tools_func.c:12
tools_func::reduce_arc
subroutine, public reduce_arc(lon_i, lat_i, lon_f, lat_f, maxdist, dist)
Reduce arc to a given distance.
Definition: tools_func.F90:152
tools_asa007::asa007_syminv
subroutine, public asa007_syminv(mpl, n, nn, a, c, ierr)
Compute inverse of a symmetric matrix.
Definition: tools_asa007.F90:112
tools_func::lonlathash
real(kind_real) function, public lonlathash(lon, lat, il)
Define a unique real from a lon/lat pair.
Definition: tools_func.F90:96
tools_func::vector_product
subroutine, public vector_product(v1, v2, vp)
Compute normalized vector product.
Definition: tools_func.F90:265
tools_kinds
Kinds definition.
Definition: tools_kinds.F90:8
tools_func::lct_h2r
subroutine, public lct_h2r(mpl, H11, H22, H33, H12, rh, rv)
From H (local correlation tensor) to support radii.
Definition: tools_func.F90:724
tools_const::rad2deg
real(kind_real), parameter, public rad2deg
Definition: tools_const.F90:16
tools_const::deg2rad
real(kind_real), parameter, public deg2rad
Definition: tools_const.F90:15
type_mpl
MPI parameters derived type.
Definition: type_mpl.F90:8
tools_func::lonlatmod
subroutine, public lonlatmod(lon, lat)
Set latitude between -pi/2 and pi/2 and longitude between -pi and pi.
Definition: tools_func.F90:66
tools_const::pi
real(kind_real), parameter, public pi
Definition: tools_const.F90:14
tools_func::divide
subroutine, public divide(mpl, val, num)
Check if value missing and divide if not missing.
Definition: tools_func.F90:360
type_mpl::mpl_type
Definition: type_mpl.F90:24
tools_kinds::kind_real
integer, parameter, public kind_real
Definition: tools_kinds.F90:18
tools_func::c_fletcher32
Definition: tools_func.F90:27