FV3 Bundle
tools_kdtree2.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: tools_kdtree2
3 ! Purpose: K-d tree routines
4 ! Source: https://github.com/jmhodges/kdtree2
5 ! Author: Matthew Kennel, Institute for Nonlinear Science (2004)
6 ! Original licensing: Academic Free License version 1.1
7 ! Modified by Benjamin Menetrier for BUMP
8 ! Licensing: this code is distributed under the CeCILL-C license
9 ! Copyright © 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
10 !----------------------------------------------------------------------
12  use tools_func, only: sphere_dist
14  use tools_kinds, only: kind_real
15  use tools_repro, only: inf,infeq,sup
16  use tools_stripack, only: scoord
17  ! K-D tree routines in Fortran 90 by Matt Kennel.
18  ! Original program was written in Sather by Steve Omohundro and
19  ! Matt Kennel. Only the Euclidean metric is supported.
20  !
21  !
22  ! This module is identical to 'kd_tree', except that the order
23  ! of subscripts is reversed in the data file.
24  ! In otherwords for an embedding of N D-dimensional vectors, the
25  ! data file is here, in natural Fortran order data(1:D, 1:N)
26  ! because Fortran lays out columns first,
27  !
28  ! whereas conventionally (C-style) it is data(1:N,1:D)
29  ! as in the original kd_tree module.
30  !
31  !-------------DATA TYPE, CREATION, DELETION---------------------
32  private
34  !---------------------------------------------------------------
35  !-------------------SEARCH ROUTINES-----------------------------
36  public :: kdtree2_n_nearest
37  ! Return fixed number of nearest neighbors around arbitrary vector
38  !
39  public :: kdtree2_r_count
40  ! Count points within a fixed ball of arb vector
41  !----------------------------------------------------------------
42 
43  integer, parameter :: bucket_size = 12
44  ! The maximum number of points to keep in a terminal node.
45 
46  type interval
47  real(kind_real) :: lower,upper
48  end type interval
49 
50  type :: tree_node
51  ! an internal tree node
52  private
53  integer :: cut_dim
54  ! the dimension to cut
55  real(kind_real) :: cut_val
56  ! where to cut the dimension
57  real(kind_real) :: cut_val_left, cut_val_right
58  ! improved cutoffs knowing the spread in child boxes.
59  integer :: l, u
60  type(tree_node), pointer :: left, right
61  type(interval), pointer :: box(:) => null()
62  ! child pointers
63  ! Points included in this node are indexes[k] with k \in [l,u]
64  end type tree_node
65 
66  type :: kdtree2
67  ! Global information about the tree, one per tree
68  integer :: n=0
69  ! total # of points
70  real(kind_real), pointer :: the_data(:,:) => null()
71  ! pointer to the actual data array
72  !
73  ! IMPORTANT NOTE: IT IS DIMENSIONED the_data(1:d,1:N)
74  ! which may be opposite of what may be conventional.
75  ! This is, because in Fortran, the memory layout is such that
76  ! the first dimension is in sequential order. Hence, with
77  ! (1:d,1:N), all components of the vector will be in consecutive
78  ! memory locations. The search time is dominated by the
79  ! evaluation of distances in the terminal nodes. Putting all
80  ! vector components in consecutive memory location improves
81  ! memory cache locality, and hence search speed, and may enable
82  ! vectorization on some processors and compilers.
83 
84  integer, pointer :: ind(:) => null()
85  ! permuted index into the data, so that indexes[l..u] of some
86  ! bucket represent the indexes of the actual points in that
87  ! bucket.
88  logical :: sort = .false.
89  ! do we always sort output results?
90  logical :: rearrange = .true.
91  real(kind_real), pointer :: rearranged_data(:,:) => null()
92  ! if (rearrange .eqv. .true.) then rearranged_data has been
93  ! created so that rearranged_data(:,i) = the_data(:,ind(i)),
94  ! permitting search to use more cache-friendly rearranged_data, at
95  ! some initial computation and storage cost.
96  type(tree_node), pointer :: root => null()
97  ! root pointer of the tree
98  end type kdtree2
99 
100 
102  !
103  ! One of these is created for each search.
104  !
105  private
106  !
107  ! Many fields are copied from the tree structure, in order to
108  ! speed up the search.
109  !
110  integer :: nn, nfound
111  real(kind_real) :: ballsize
112  integer :: centeridx=999, correltime=9999
113  ! exclude points within 'correltime' of 'centeridx', iff centeridx >= 0
114  integer :: nalloc ! how much allocated for results(:)?
115  logical :: rearrange ! are the data rearranged or original?
116  ! did the # of points found overflow the storage provided?
117  logical :: overflow
118  real(kind_real), pointer :: qv(:) ! query vector
119  type(kdtree2_result), pointer :: results(:) ! results
120  type(pq) :: pq
121  real(kind_real), pointer :: data(:,:) ! temp pointer to data
122  integer, pointer :: ind(:) ! temp pointer to indexes
123  end type tree_search_record
124 
125  type(tree_search_record), save, target :: sr ! A GLOBAL VARIABLE for search
126 
127 contains
128 
129  function kdtree2_create(input_data,sort,rearrange) result (mr)
130 ! Function: kdtree2_create
131 ! Purpose: create the actual tree structure, given an input array of data
132 
133 
134  ! Note, input data is input_data(1:d,1:N), NOT the other way around.
135  ! THIS IS THE REVERSE OF THE PREVIOUS VERSION OF THIS MODULE.
136  ! The reason for it is cache friendliness, improving performance.
137  !
138  ! Optional arguments: if sort .eqv. .true. then output results
139  ! will be sorted by increasing distance.
140  ! default=.false., as it is faster to not sort.
141  !
142  ! if rearrange .eqv. .true. then an internal
143  ! copy of the data, rearranged by terminal node,
144  ! will be made for cache friendliness.
145  ! default=.true., as it speeds searches, but
146  ! building takes longer, and extra memory is used.
147  !
148  ! .. Function Return Cut_value ..
149  type(kdtree2), pointer :: mr
150  logical, intent(in), optional :: sort
151  logical, intent(in), optional :: rearrange
152  ! ..
153  ! .. Array Arguments ..
154  real(kind_real), target :: input_data(:,:)
155  !
156  integer :: i
157  ! ..
158  allocate (mr)
159  mr%the_data => input_data
160  ! pointer assignment
161 
162  mr%n = size(input_data,2)
163 
164  call build_tree(mr)
165 
166  if (present(sort)) then
167  mr%sort = sort
168  else
169  mr%sort = .false.
170  endif
171 
172  if (present(rearrange)) then
173  mr%rearrange = rearrange
174  else
175  mr%rearrange = .true.
176  endif
177 
178  allocate(mr%rearranged_data(3,mr%n))
179  if (mr%rearrange) then
180  do i=1,mr%n
181  mr%rearranged_data(:,i) = mr%the_data(:,mr%ind(i))
182  enddo
183  else
184  mr%rearranged_data = mr%the_data
185  endif
186 
187  end function kdtree2_create
188 
189  subroutine build_tree(tp)
190 ! Subroutine: build_tree
191 ! Purpose: build tree
192  type(kdtree2), pointer :: tp
193  ! ..
194  integer :: j
195  type(tree_node), pointer :: dummy => null()
196  ! ..
197  allocate (tp%ind(tp%n))
198  forall (j=1:tp%n)
199  tp%ind(j) = j
200  end forall
201  tp%root => build_tree_for_range(tp,1,tp%n, dummy)
202  end subroutine build_tree
203 
204  recursive function build_tree_for_range(tp,l,u,parent) result (res)
205 ! Function: build_tree_for_range
206 ! Purpose: build tree
207 
208  ! .. Function Return Cut_value ..
209  type(tree_node), pointer :: res
210  ! ..
211  ! .. Structure Arguments ..
212  type(kdtree2), pointer :: tp
213  type(tree_node),pointer :: parent
214  ! ..
215  ! .. Scalar Arguments ..
216  integer, intent (In) :: l, u
217  ! ..
218  ! .. Local Scalars ..
219  integer :: i, c, m
220  logical :: recompute
221  real(kind_real) :: average
222 
223  ! first compute min and max
224  allocate (res)
225  allocate(res%box(3))
226 
227  ! First, compute an APPROXIMATE bounding box of all points associated with this node.
228  if ( u < l ) then
229  ! no points in this box
230  nullify(res)
231  return
232  end if
233 
234  if ((u-l)<=bucket_size) then
235  !
236  ! always compute true bounding box for terminal nodes.
237  !
238  do i=1,3
239  call spread_in_coordinate(tp,i,l,u,res%box(i))
240  end do
241  res%cut_dim = 0
242  res%cut_val = 0.0
243  res%l = l
244  res%u = u
245  res%left =>null()
246  res%right => null()
247  else
248  !
249  ! modify approximate bounding box. This will be an
250  ! overestimate of the true bounding box, as we are only recomputing
251  ! the bounding box for the dimension that the parent split on.
252  !
253  ! Going to a true bounding box computation would significantly
254  ! increase the time necessary to build the tree, and usually
255  ! has only a very small difference. This box is not used
256  ! for searching but only for deciding which coordinate to split on.
257  !
258  do i=1,3
259  recompute=.true.
260  if (associated(parent)) then
261  if (i .ne. parent%cut_dim) then
262  recompute=.false.
263  end if
264  endif
265  if (recompute) then
266  call spread_in_coordinate(tp,i,l,u,res%box(i))
267  else
268  res%box(i) = parent%box(i)
269  endif
270  end do
271 
272 
273  c = maxloc(res%box%upper-res%box%lower,1)
274  !
275  ! c is the identity of which coordinate has the greatest spread.
276  !
277 
278  if (.false.) then
279  ! select exact median to have fully balanced tree.
280  m = (l+u)/2
281  call select_on_coordinate(tp%the_data,tp%ind,c,m,l,u)
282  else
283  !
284  ! select point halfway between min and max, as per A. Moore,
285  ! who says this helps in some degenerate cases, or
286  ! actual arithmetic average.
287  !
288  if (.true.) then
289  ! actually compute average
290  average = sum(tp%the_data(c,tp%ind(l:u))) / real(u-l+1,kind_real)
291  else
292  average = (res%box(c)%upper + res%box(c)%lower)/2.0
293  endif
294 
295  res%cut_val = average
296  m = select_on_coordinate_value(tp%the_data,tp%ind,c,average,l,u)
297  endif
298 
299  ! moves indexes around
300  res%cut_dim = c
301  res%l = l
302  res%u = u
303 ! res%cut_val = tp%the_data(c,tp%ind(m))
304 
305  res%left => build_tree_for_range(tp,l,m,res)
306  res%right => build_tree_for_range(tp,m+1,u,res)
307 
308  if (associated(res%right) .eqv. .false.) then
309  res%box = res%left%box
310  res%cut_val_left = res%left%box(c)%upper
311  res%cut_val = res%cut_val_left
312  elseif (associated(res%left) .eqv. .false.) then
313  res%box = res%right%box
314  res%cut_val_right = res%right%box(c)%lower
315  res%cut_val = res%cut_val_right
316  else
317  res%cut_val_right = res%right%box(c)%lower
318  res%cut_val_left = res%left%box(c)%upper
319  res%cut_val = (res%cut_val_left + res%cut_val_right)/2
320 
321 
322  ! now remake the true bounding box for self.
323  ! Since we are taking unions (in effect) of a tree structure,
324  ! this is much faster than doing an exhaustive
325  ! search over all points
326  res%box%upper = max(res%left%box%upper,res%right%box%upper)
327  res%box%lower = min(res%left%box%lower,res%right%box%lower)
328  endif
329  end if
330  end function build_tree_for_range
331 
332  integer function select_on_coordinate_value(v,ind,c,alpha,li,ui) &
333  result(res)
334 ! Function: select_on_coordinate_value
335 ! Purpose: move elts of ind around between l and u, so that all points <= than alpha (in c cooordinate) are first, and then all points > alpha are second
336 
337  ! Algorithm (matt kennel).
338  !
339  ! Consider the list as having three parts: on the left,
340  ! the points known to be <= alpha. On the right, the points
341  ! known to be > alpha, and in the middle, the currently unknown
342  ! points. The algorithm is to scan the unknown points, starting
343  ! from the left, and swapping them so that they are added to
344  ! the left stack or the right stack, as appropriate.
345  !
346  ! The algorithm finishes when the unknown stack is empty.
347  !
348  ! .. Scalar Arguments ..
349  integer, intent (In) :: c, li, ui
350  real(kind_real), intent(in) :: alpha
351  ! ..
352  real(kind_real) :: v(1:,1:)
353  integer :: ind(1:)
354  integer :: tmp
355  ! ..
356  integer :: lb, rb
357  !
358  ! The points known to be <= alpha are in
359  ! [l,lb-1]
360  !
361  ! The points known to be > alpha are in
362  ! [rb+1,u].
363  !
364  ! Therefore we add new points into lb or
365  ! rb as appropriate. When lb=rb
366  ! we are done. We return the location of the last point <= alpha.
367  !
368  !
369  lb = li; rb = ui
370 
371  do while (lb < rb)
372  if ( infeq(v(c,ind(lb)),alpha) ) then
373  ! it is good where it is.
374  lb = lb+1
375  else
376  ! swap it with rb.
377  tmp = ind(lb); ind(lb) = ind(rb); ind(rb) = tmp
378  rb = rb-1
379  endif
380  end do
381 
382  ! now lb .eq. ub
383  if (infeq(v(c,ind(lb)),alpha)) then
384  res = lb
385  else
386  res = lb-1
387  endif
388 
389  end function select_on_coordinate_value
390 
391  subroutine select_on_coordinate(v,ind,c,k,li,ui)
392 ! Subroutine: select_on_coordinate
393 ! Purpose: move elts of ind around between l and u, so that the kth element is >= those below, <= those above, in the coordinate c
394 
395  ! .. Scalar Arguments ..
396  integer, intent (In) :: c, k, li, ui
397  ! ..
398  integer :: i, l, m, s, t, u
399  ! ..
400  real(kind_real) :: v(:,:)
401  integer :: ind(:)
402  ! ..
403  l = li
404  u = ui
405  do while (l<u)
406  t = ind(l)
407  m = l
408  do i = l + 1, u
409  if (inf(v(c,ind(i)),v(c,t))) then
410  m = m + 1
411  s = ind(m)
412  ind(m) = ind(i)
413  ind(i) = s
414  end if
415  end do
416  s = ind(l)
417  ind(l) = ind(m)
418  ind(m) = s
419  if (m<=k) l = m + 1
420  if (m>=k) u = m - 1
421  end do
422  end subroutine select_on_coordinate
423 
424  subroutine spread_in_coordinate(tp,c,l,u,interv)
425 ! Subroutine: spread_in_coordinate
426 ! Purpose: return lower bound in 'smin', and upper in 'smax', the spread in coordinate 'c', between l and u.
427 
428  ! .. Structure Arguments ..
429  type(kdtree2), pointer :: tp
430  type(interval), intent(out) :: interv
431  ! ..
432  ! .. Scalar Arguments ..
433  integer, intent (In) :: c, l, u
434  ! ..
435  ! .. Local Scalars ..
436  real(kind_real) :: last, lmax, lmin, t, smin,smax
437  integer :: i, ulocal
438  ! ..
439  ! .. Local Arrays ..
440  real(kind_real), pointer :: v(:,:)
441  integer, pointer :: ind(:)
442  ! ..
443  v => tp%the_data(1:,1:)
444  ind => tp%ind(1:)
445  smin = v(c,ind(l))
446  smax = smin
447 
448  ulocal = u
449 
450  do i = l + 2, ulocal, 2
451  lmin = v(c,ind(i-1))
452  lmax = v(c,ind(i))
453  if (sup(lmin,lmax)) then
454  t = lmin
455  lmin = lmax
456  lmax = t
457  end if
458  if (sup(smin,lmin)) smin = lmin
459  if (inf(smax,lmax)) smax = lmax
460  end do
461  if (i==ulocal+1) then
462  last = v(c,ind(ulocal))
463  if (sup(smin,last)) smin = last
464  if (inf(smax,last)) smax = last
465  end if
466 
467  interv%lower = smin
468  interv%upper = smax
469 
470  end subroutine spread_in_coordinate
471 
472  subroutine kdtree2_destroy(tp)
473 ! Subroutine: kdtree2_destroy
474 ! Purpose: deallocates all memory for the tree, except input data matrix
475 
476  ! .. Structure Arguments ..
477  type(kdtree2), pointer :: tp
478  ! ..
479  call destroy_node(tp%root)
480 
481  deallocate (tp%ind)
482  nullify (tp%ind)
483 
484  deallocate(tp%rearranged_data)
485  nullify(tp%rearranged_data)
486 
487  deallocate(tp)
488  return
489 
490  contains
491  recursive subroutine destroy_node(np)
492 ! Subroutine: destroy_node
493 ! Purpose: destroy node
494 
495  ! .. Structure Arguments ..
496  type(tree_node), pointer :: np
497  ! ..
498  ! .. Intrinsic Functions ..
499  intrinsic ASSOCIATED
500  ! ..
501  if (associated(np%left)) then
502  call destroy_node(np%left)
503  nullify (np%left)
504  end if
505  if (associated(np%right)) then
506  call destroy_node(np%right)
507  nullify (np%right)
508  end if
509  if (associated(np%box)) deallocate(np%box)
510  deallocate(np)
511  return
512 
513  end subroutine destroy_node
514 
515  end subroutine kdtree2_destroy
516 
517  subroutine kdtree2_n_nearest(tp,qv,nn,results)
518 ! Subroutine: kdtree2_n_nearest
519 ! Purpose: find the 'nn' vectors in the tree nearest to 'qv' in euclidean norm
520 
521  ! Returning their indexes and distances in 'indexes' and 'distances'
522  ! Arrays already allocated passed to this subroutine.
523  type(kdtree2), pointer :: tp
524  real(kind_real), target, intent (In) :: qv(:)
525  integer, intent (In) :: nn
526  type(kdtree2_result), target :: results(:)
527 
528 
529  sr%ballsize = huge(1.0)
530  sr%qv => qv
531  sr%nn = nn
532  sr%nfound = 0
533  sr%centeridx = -1
534  sr%correltime = 0
535  sr%overflow = .false.
536 
537  sr%results => results
538 
539  sr%nalloc = nn ! will be checked
540 
541  sr%ind => tp%ind
542  sr%rearrange = tp%rearrange
543  sr%Data => tp%rearranged_data
544 
545  call validate_query_storage(nn)
546  sr%pq = pq_create(results)
547 
548  call search(tp%root)
549 
550  if (tp%sort) then
551  call kdtree2_sort_results(nn, results)
552  endif
553 ! deallocate(sr%pqp)
554  return
555  end subroutine kdtree2_n_nearest
556 
557  function kdtree2_r_count(tp,qv,r2) result(nfound)
558 ! Function: kdtree2_r_count
559 ! Purpose: count the number of neighbors within square distance 'r2'
560 
561  type(kdtree2), pointer :: tp
562  real(kind_real), target, intent (In) :: qv(:)
563  real(kind_real), intent(in) :: r2
564  integer :: nfound
565  ! ..
566  ! .. Intrinsic Functions ..
567  intrinsic huge
568  ! ..
569  sr%qv => qv
570  sr%ballsize = r2
571 
572  sr%nn = 0 ! flag for fixed r search
573  sr%nfound = 0
574  sr%centeridx = -1
575  sr%correltime = 0
576 
577  nullify(sr%results) ! for some reason, FTN 95 chokes on '=> null()'
578 
579  sr%nalloc = 0 ! we do not allocate any storage but that's OK
580  ! for counting.
581  sr%ind => tp%ind
582  sr%rearrange = tp%rearrange
583  sr%Data => tp%rearranged_data
584 
585  !
586  !sr%dsl = Huge(sr%dsl) ! set to huge positive values
587  !sr%il = -1 ! set to invalid indexes
588  !
589  sr%overflow = .false.
590 
591  call search(tp%root)
592 
593  nfound = sr%nfound
594 
595  return
596  end function kdtree2_r_count
597 
598  subroutine validate_query_storage(n)
599 ! Subroutine: validate_query_storage
600 ! Purpose: make sure we have enough storage for n
601 
602  integer, intent(in) :: n
603 
604  if (size(sr%results,1) .lt. n) then
605  write (*,*) 'KD_TREE_TRANS: you did not provide enough storage for results(1:n)'
606  stop
607  return
608  endif
609 
610  return
611  end subroutine validate_query_storage
612 
613  function square_distance(iv, qv) result (res)
614 ! Function: square_distance
615 ! Purpose: distance between iv[1:n] and qv[1:n]
616 
617  ! .. Function Return Value ..
618  ! re-implemented to improve vectorization.
619  real(kind_real) :: res
620  ! ..
621  ! .. Array Arguments ..
622  real(kind_real),intent(in) :: iv(3),qv(3)
623  ! ..
624  ! ..
625  ! Quadratic norm
626  res = sum( (iv-qv)**2 )
627  end function square_distance
628 
629  function sdistance(iv, qv) result (res)
630 ! Function: sdistance
631 ! Purpose: spherical distance between iv[1:n] and qv[1:n]
632 
633  ! .. Function Return Value ..
634  ! re-implemented to improve vectorization.
635  real(kind_real) :: res, ilat, ilon, ir, qlat, qlon, qr
636  ! ..
637  ! .. Array Arguments ..
638  real(kind_real),intent(in) :: iv(3),qv(3)
639  ! ..
640  ! ..
641  ! .. Back to spherical coordinates
642  call scoord(iv(1),iv(2),iv(3),ilat,ilon,ir)
643  call scoord(qv(1),qv(2),qv(3),qlat,qlon,qr)
644 
645  ! Distance on sphere
646  call sphere_dist(ilon,ilat,qlon,qlat,res)
647 
648  end function sdistance
649 
650  recursive subroutine search(node)
651 ! Subroutine: validate_query_storage
652 ! Purpose: innermost core routine of the kd-tree search
653 
654  ! Along with "process_terminal_node", it is the performance bottleneck.
655  !
656  ! This version uses a logically complete secondary search of
657  ! "box in bounds", whether the sear
658  !
659  type(tree_node), pointer :: node
660  ! ..
661  type(tree_node),pointer :: ncloser, nfarther
662  !
663  integer :: cut_dim, i
664  ! ..
665  real(kind_real) :: qval, dis
666  real(kind_real) :: ballsize
667  real(kind_real), pointer :: qv(:)
668  type(interval), pointer :: box(:)
669 
670  if ((associated(node%left) .and. associated(node%right)) .eqv. .false.) then
671  ! we are on a terminal node
672  if (sr%nn .eq. 0) then
674  else
675  call process_terminal_node(node)
676  endif
677  else
678  ! we are not on a terminal node
679  qv => sr%qv(1:)
680  cut_dim = node%cut_dim
681  qval = qv(cut_dim)
682 
683  if (inf(qval,node%cut_val)) then
684  ncloser => node%left
685  nfarther => node%right
686  dis = (node%cut_val_right - qval)**2
687 ! extra = node%cut_val - qval
688  else
689  ncloser => node%right
690  nfarther => node%left
691  dis = (node%cut_val_left - qval)**2
692 ! extra = qval- node%cut_val_left
693  endif
694 
695  if (associated(ncloser)) call search(ncloser)
696 
697  ! we may need to search the second node.
698  if (associated(nfarther)) then
699  ballsize = sr%ballsize
700 ! dis=extra**2
701  if (infeq(dis,ballsize)) then
702  !
703  ! we do this separately as going on the first cut dimen is often
704  ! a good idea.
705  ! note that if extra**2 < sr%ballsize, then the next
706  ! check will also be false.
707  !
708  box => node%box(1:)
709  do i=1,3
710  if (i .ne. cut_dim) then
711  dis = dis + dis2_from_bnd(qv(i),box(i)%lower,box(i)%upper)
712  if (sup(dis,ballsize)) then
713  return
714  endif
715  endif
716  end do
717 
718  !
719  ! if we are still here then we need to search mroe.
720  !
721  call search(nfarther)
722  endif
723  endif
724  end if
725  end subroutine search
726 
727  real(kind_real) function dis2_from_bnd(x,amin,amax) result (res)
728 ! Function: dis2_from_bnd
729 ! Purpose: compute squared distance
730 
731  real(kind_real), intent(in) :: x, amin,amax
732 
733  if (sup(x,amax)) then
734  res = (x-amax)**2;
735  return
736  else
737  if (inf(x,amin)) then
738  res = (amin-x)**2;
739  return
740  else
741  res = 0.0
742  return
743  endif
744  endif
745  return
746  end function dis2_from_bnd
747 
748  subroutine process_terminal_node(node)
749 ! Subroutine: process_terminal_node
750 ! Purpose: Look for actual near neighbors in 'node', and update the search results on the sr data structure
751 
752  type(tree_node), pointer :: node
753  !
754  real(kind_real), pointer :: qv(:)
755  integer, pointer :: ind(:)
756  real(kind_real), pointer :: data(:,:)
757  !
758  integer :: i, indexofi, centeridx, correltime
759  real(kind_real) :: ballsize, sd, ssd, newpri
760  logical :: rearrange
761  type(pq), pointer :: pqp
762  !
763  ! copy values from sr to local variables
764  !
765  !
766  ! Notice, making local pointers with an EXPLICIT lower bound
767  ! seems to generate faster code.
768  ! why? I don't know.
769  qv => sr%qv(1:)
770  pqp => sr%pq
771  ballsize = sr%ballsize
772  rearrange = sr%rearrange
773  ind => sr%ind(1:)
774  data => sr%Data(1:,1:)
775  centeridx = sr%centeridx
776  correltime = sr%correltime
777 
778  ! doing_correl = (centeridx >= 0) ! Do we have a decorrelation window?
779  ! include_point = .true. ! by default include all points
780  ! search through terminal bucket.
781 
782  mainloop: do i = node%l, node%u
783  if (rearrange) then
784  sd = square_distance(data(:,i), qv)
785  ssd = sdistance(data(:,i), qv)
786  indexofi = ind(i) ! only read it if we have not broken out
787  else
788  indexofi = ind(i)
789  sd = square_distance(data(:,indexofi), qv)
790  ssd = sdistance(data(:,indexofi), qv)
791  endif
792  if (sup(sd,ballsize)) cycle mainloop
793 
794  if (centeridx > 0) then ! doing correlation interval?
795  if (abs(indexofi-centeridx) < correltime) cycle mainloop
796  endif
797 
798 
799  !
800  ! two choices for any point. The list so far is either undersized,
801  ! or it is not.
802  !
803  ! If it is undersized, then add the point and its distance
804  ! unconditionally. If the point added fills up the working
805  ! list then set the sr%ballsize, maximum distance bound (largest distance on
806  ! list) to be that distance, instead of the initialized +infinity.
807  !
808  ! If the running list is full size, then compute the
809  ! distance but break out immediately if it is larger
810  ! than sr%ballsize, "best squared distance" (of the largest element),
811  ! as it cannot be a good neighbor.
812  !
813  ! Once computed, compare to best_square distance.
814  ! if it is smaller, then delete the previous largest
815  ! element and add the new one.
816 
817  if (sr%nfound .lt. sr%nn) then
818  !
819  ! add this point unconditionally to fill list.
820  !
821  sr%nfound = sr%nfound +1
822  newpri = pq_insert(pqp,sd,ssd,indexofi)
823  if (sr%nfound .eq. sr%nn) ballsize = newpri
824  ! we have just filled the working list.
825  ! put the best square distance to the maximum value
826  ! on the list, which is extractable from the PQ.
827 
828  else
829  !
830  ! now, if we get here,
831  ! we know that the current node has a squared
832  ! distance smaller than the largest one on the list, and
833  ! belongs on the list.
834  ! Hence we replace that with the current one.
835  !
836  ballsize = pq_replace_max(pqp,sd,ssd,indexofi)
837  endif
838  end do mainloop
839  !
840  ! Reset sr variables which may have changed during loop
841  !
842  sr%ballsize = ballsize
843 
844  end subroutine process_terminal_node
845 
846  subroutine process_terminal_node_fixedball(node)
847 ! Subroutine: process_terminal_node_fixedball
848 ! Purpose: look for actual near neighbors in 'node', and update the search results on the sr data structure, i.e. save all within a fixed ball.
849 
850  type(tree_node), pointer :: node
851  !
852  real(kind_real), pointer :: qv(:)
853  integer, pointer :: ind(:)
854  real(kind_real), pointer :: data(:,:)
855  !
856  integer :: nfound
857  integer :: i, indexofi
858  integer :: centeridx, correltime, nn
859  real(kind_real) :: ballsize, sd, ssd
860  logical :: rearrange
861 
862  !
863  ! copy values from sr to local variables
864  !
865  qv => sr%qv(1:)
866  ballsize = sr%ballsize
867  rearrange = sr%rearrange
868  ind => sr%ind(1:)
869  data => sr%Data(1:,1:)
870  centeridx = sr%centeridx
871  correltime = sr%correltime
872  nn = sr%nn ! number to search for
873  nfound = sr%nfound
874 
875  ! search through terminal bucket.
876  mainloop: do i = node%l, node%u
877 
878  !
879  ! two choices for any point. The list so far is either undersized,
880  ! or it is not.
881  !
882  ! If it is undersized, then add the point and its distance
883  ! unconditionally. If the point added fills up the working
884  ! list then set the sr%ballsize, maximum distance bound (largest distance on
885  ! list) to be that distance, instead of the initialized +infinity.
886  !
887  ! If the running list is full size, then compute the
888  ! distance but break out immediately if it is larger
889  ! than sr%ballsize, "best squared distance" (of the largest element),
890  ! as it cannot be a good neighbor.
891  !
892  ! Once computed, compare to best_square distance.
893  ! if it is smaller, then delete the previous largest
894  ! element and add the new one.
895 
896  ! which index to the point do we use?
897 
898  if (rearrange) then
899  sd = square_distance(data(:,i), qv)
900  ssd = sdistance(data(:,i), qv)
901  indexofi = ind(i) ! only read it if we have not broken out
902  else
903  indexofi = ind(i)
904  sd = square_distance(data(:,indexofi), qv)
905  ssd = sdistance(data(:,indexofi), qv)
906  endif
907  if (sup(sd,ballsize)) cycle mainloop
908 
909  if (centeridx > 0) then ! doing correlation interval?
910  if (abs(indexofi-centeridx)<correltime) cycle mainloop
911  endif
912 
913  nfound = nfound+1
914  if (nfound .gt. sr%nalloc) then
915  ! oh nuts, we have to add another one to the tree but
916  ! there isn't enough room.
917  sr%overflow = .true.
918  else
919  sr%results(nfound)%dis = sd
920  sr%results(nfound)%sdis = ssd
921  sr%results(nfound)%idx = indexofi
922  endif
923  end do mainloop
924  !
925  ! Reset sr variables which may have changed during loop
926  !
927  sr%nfound = nfound
928  end subroutine process_terminal_node_fixedball
929 
930  subroutine kdtree2_sort_results(nfound,results)
931 ! Subroutine: kdtree2_sort_results
932 ! Purpose: use after search to sort results(1:nfound) in order of increasing distance
933  integer, intent(in) :: nfound
934  type(kdtree2_result), target :: results(:)
935  !
936  !
937 
938  !THIS IS BUGGY WITH INTEL FORTRAN
939  ! If (nfound .Gt. 1) Call heapsort(results(1:nfound)%dis,results(1:nfound)%ind,nfound)
940  !
941  if (nfound .gt. 1) call heapsort_struct(results,nfound)
942 
943  return
944  end subroutine kdtree2_sort_results
945 
946  subroutine heapsort_struct(a,n)
947 ! Subroutine: heapsort_struct
948 ! Purpose: sort a(1:n) in ascending order
949 
950  integer,intent(in) :: n
951  type(kdtree2_result),intent(inout) :: a(:)
952 
953  !
954  !
955  type(kdtree2_result) :: value ! temporary value
956 
957  integer :: i,j
958  integer :: ileft,iright
959 
960  ileft=n/2+1
961  iright=n
962 
963  ! do i=1,n
964  ! ind(i)=i
965  ! Generate initial idum array
966  ! end do
967 
968  if(n.eq.1) return
969 
970  do
971  if(ileft > 1)then
972  ileft=ileft-1
973  value=a(ileft)
974  else
975  value=a(iright)
976  a(iright)=a(1)
977  iright=iright-1
978  if (iright == 1) then
979  a(1) = value
980  return
981  endif
982  endif
983  i=ileft
984  j=2*ileft
985  do while (j <= iright)
986  if(j < iright) then
987  if(inf(a(j)%dis,a(j+1)%dis)) j=j+1
988  endif
989  if(inf(value%dis,a(j)%dis)) then
990  a(i)=a(j);
991  i=j
992  j=j+j
993  else
994  j=iright+1
995  endif
996  end do
997  a(i)=value
998  end do
999  end subroutine heapsort_struct
1000 
1001 end module tools_kdtree2
integer function, public kdtree2_r_count(tp, qv, r2)
logical function, public sup(x, y)
Definition: tools_repro.F90:85
subroutine build_tree(tp)
subroutine heapsort_struct(a, n)
subroutine validate_query_storage(n)
real(kind_real) function, public pq_insert(a, dis, sdis, idx)
subroutine, public kdtree2_destroy(tp)
real(kind_real) function square_distance(iv, qv)
subroutine process_terminal_node_fixedball(node)
recursive subroutine destroy_node(np)
recursive subroutine search(node)
type(kdtree2) function, pointer, public kdtree2_create(input_data, sort, rearrange)
integer, parameter bucket_size
subroutine, public sphere_dist(lon_i, lat_i, lon_f, lat_f, dist)
Definition: tools_func.F90:67
logical function, public infeq(x, y)
Definition: tools_repro.F90:66
subroutine process_terminal_node(node)
subroutine select_on_coordinate(v, ind, c, k, li, ui)
type(tree_search_record), target, save sr
real(kind_real) function, public pq_replace_max(a, dis, sdis, idx)
#define max(a, b)
Definition: mosaic_util.h:33
subroutine, public kdtree2_n_nearest(tp, qv, nn, results)
type(pq) function, public pq_create(results_in)
subroutine, public scoord(px, py, pz, plat, plon, pnrm)
real(kind_real) function sdistance(iv, qv)
integer, parameter, public kind_real
real(kind_real) function dis2_from_bnd(x, amin, amax)
logical function, public inf(x, y)
Definition: tools_repro.F90:47
#define min(a, b)
Definition: mosaic_util.h:32
integer function select_on_coordinate_value(v, ind, c, alpha, li, ui)
recursive type(tree_node) function, pointer build_tree_for_range(tp, l, u, parent)
subroutine spread_in_coordinate(tp, c, l, u, interv)
subroutine kdtree2_sort_results(nfound, results)