📄 kdtree2.f90
字号:
return endif endif end do ! ! if we are still here then we need to search mroe. ! call search(nfarther) endif endif end if end subroutine search real(kdkind) function dis2_from_bnd(x,amin,amax) result (res) real(kdkind), intent(in) :: x, amin,amax if (x > amax) then res = (x-amax)**2; return else if (x < amin) then res = (amin-x)**2; return else res = 0.0 return endif endif return end function dis2_from_bnd logical function box_in_search_range(node, sr) result(res) ! ! Return the distance from 'qv' to the CLOSEST corner of node's ! bounding box ! for all coordinates outside the box. Coordinates inside the box ! contribute nothing to the distance. ! type (tree_node), pointer :: node type (tree_search_record), pointer :: sr integer :: dimen, i real(kdkind) :: dis, ballsize real(kdkind) :: l, u dimen = sr%dimen ballsize = sr%ballsize dis = 0.0 res = .true. do i=1,dimen l = node%box(i)%lower u = node%box(i)%upper dis = dis + (dis2_from_bnd(sr%qv(i),l,u)) if (dis > ballsize) then res = .false. return endif end do res = .true. return end function box_in_search_range subroutine process_terminal_node(node) ! ! Look for actual near neighbors in 'node', and update ! the search results on the sr data structure. ! type (tree_node), pointer :: node ! real(kdkind), pointer :: qv(:) integer, pointer :: ind(:) real(kdkind), pointer :: data(:,:) ! integer :: dimen, i, indexofi, k, centeridx, correltime real(kdkind) :: ballsize, sd, newpri logical :: rearrange type(pq), pointer :: pqp ! ! copy values from sr to local variables ! ! ! Notice, making local pointers with an EXPLICIT lower bound ! seems to generate faster code. ! why? I don't know. qv => sr%qv(1:) pqp => sr%pq dimen = sr%dimen ballsize = sr%ballsize rearrange = sr%rearrange ind => sr%ind(1:) data => sr%Data(1:,1:) centeridx = sr%centeridx correltime = sr%correltime ! doing_correl = (centeridx >= 0) ! Do we have a decorrelation window? ! include_point = .true. ! by default include all points ! search through terminal bucket. mainloop: do i = node%l, node%u if (rearrange) then sd = 0.0 do k = 1,dimen sd = sd + (data(k,i) - qv(k))**2 if (sd>ballsize) cycle mainloop end do indexofi = ind(i) ! only read it if we have not broken out else indexofi = ind(i) sd = 0.0 do k = 1,dimen sd = sd + (data(k,indexofi) - qv(k))**2 if (sd>ballsize) cycle mainloop end do endif if (centeridx > 0) then ! doing correlation interval? if (abs(indexofi-centeridx) < correltime) cycle mainloop endif ! ! two choices for any point. The list so far is either undersized, ! or it is not. ! ! If it is undersized, then add the point and its distance ! unconditionally. If the point added fills up the working ! list then set the sr%ballsize, maximum distance bound (largest distance on ! list) to be that distance, instead of the initialized +infinity. ! ! If the running list is full size, then compute the ! distance but break out immediately if it is larger ! than sr%ballsize, "best squared distance" (of the largest element), ! as it cannot be a good neighbor. ! ! Once computed, compare to best_square distance. ! if it is smaller, then delete the previous largest ! element and add the new one. if (sr%nfound .lt. sr%nn) then ! ! add this point unconditionally to fill list. ! sr%nfound = sr%nfound +1 newpri = pq_insert(pqp,sd,indexofi) if (sr%nfound .eq. sr%nn) ballsize = newpri ! we have just filled the working list. ! put the best square distance to the maximum value ! on the list, which is extractable from the PQ. else ! ! now, if we get here, ! we know that the current node has a squared ! distance smaller than the largest one on the list, and ! belongs on the list. ! Hence we replace that with the current one. ! ballsize = pq_replace_max(pqp,sd,indexofi) endif end do mainloop ! ! Reset sr variables which may have changed during loop ! sr%ballsize = ballsize end subroutine process_terminal_node subroutine process_terminal_node_fixedball(node) ! ! 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. ! type (tree_node), pointer :: node ! real(kdkind), pointer :: qv(:) integer, pointer :: ind(:) real(kdkind), pointer :: data(:,:) ! integer :: nfound integer :: dimen, i, indexofi, k integer :: centeridx, correltime, nn real(kdkind) :: ballsize, sd logical :: rearrange ! ! copy values from sr to local variables ! qv => sr%qv(1:) dimen = sr%dimen ballsize = sr%ballsize rearrange = sr%rearrange ind => sr%ind(1:) data => sr%Data(1:,1:) centeridx = sr%centeridx correltime = sr%correltime nn = sr%nn ! number to search for nfound = sr%nfound ! search through terminal bucket. mainloop: do i = node%l, node%u ! ! two choices for any point. The list so far is either undersized, ! or it is not. ! ! If it is undersized, then add the point and its distance ! unconditionally. If the point added fills up the working ! list then set the sr%ballsize, maximum distance bound (largest distance on ! list) to be that distance, instead of the initialized +infinity. ! ! If the running list is full size, then compute the ! distance but break out immediately if it is larger ! than sr%ballsize, "best squared distance" (of the largest element), ! as it cannot be a good neighbor. ! ! Once computed, compare to best_square distance. ! if it is smaller, then delete the previous largest ! element and add the new one. ! which index to the point do we use? if (rearrange) then sd = 0.0 do k = 1,dimen sd = sd + (data(k,i) - qv(k))**2 if (sd>ballsize) cycle mainloop end do indexofi = ind(i) ! only read it if we have not broken out else indexofi = ind(i) sd = 0.0 do k = 1,dimen sd = sd + (data(k,indexofi) - qv(k))**2 if (sd>ballsize) cycle mainloop end do endif if (centeridx > 0) then ! doing correlation interval? if (abs(indexofi-centeridx)<correltime) cycle mainloop endif nfound = nfound+1 if (nfound .gt. sr%nalloc) then ! oh nuts, we have to add another one to the tree but ! there isn't enough room. sr%overflow = .true. else sr%results(nfound)%dis = sd sr%results(nfound)%idx = indexofi endif end do mainloop ! ! Reset sr variables which may have changed during loop ! sr%nfound = nfound end subroutine process_terminal_node_fixedball subroutine kdtree2_n_nearest_brute_force(tp,qv,nn,results) ! find the 'n' nearest neighbors to 'qv' by exhaustive search. ! only use this subroutine for testing, as it is SLOW! The ! whole point of a k-d tree is to avoid doing what this subroutine ! does. type (kdtree2), pointer :: tp real(kdkind), intent (In) :: qv(:) integer, intent (In) :: nn type(kdtree2_result) :: results(:) integer :: i, j, k real(kdkind), allocatable :: all_distances(:) ! .. allocate (all_distances(tp%n)) do i = 1, tp%n all_distances(i) = square_distance(tp%dimen,qv,tp%the_data(:,i)) end do ! now find 'n' smallest distances do i = 1, nn results(i)%dis = huge(1.0) results(i)%idx = -1 end do do i = 1, tp%n if (all_distances(i)<results(nn)%dis) then ! insert it somewhere on the list do j = 1, nn if (all_distances(i)<results(j)%dis) exit end do ! now we know 'j' do k = nn - 1, j, -1 results(k+1) = results(k) end do results(j)%dis = all_distances(i) results(j)%idx = i end if end do deallocate (all_distances) end subroutine kdtree2_n_nearest_brute_force subroutine kdtree2_r_nearest_brute_force(tp,qv,r2,nfound,results) ! find the nearest neighbors to 'qv' with distance**2 <= r2 by exhaustive search. ! only use this subroutine for testing, as it is SLOW! The ! whole point of a k-d tree is to avoid doing what this subroutine ! does. type (kdtree2), pointer :: tp real(kdkind), intent (In) :: qv(:) real(kdkind), intent (In) :: r2 integer, intent(out) :: nfound type(kdtree2_result) :: results(:) integer :: i, nalloc real(kdkind), allocatable :: all_distances(:) ! .. allocate (all_distances(tp%n)) do i = 1, tp%n all_distances(i) = square_distance(tp%dimen,qv,tp%the_data(:,i)) end do nfound = 0 nalloc = size(results,1) do i = 1, tp%n if (all_distances(i)< r2) then ! insert it somewhere on the list if (nfound .lt. nalloc) then nfound = nfound+1 results(nfound)%dis = all_distances(i) results(nfound)%idx = i endif end if enddo deallocate (all_distances) call kdtree2_sort_results(nfound,results) end subroutine kdtree2_r_nearest_brute_force subroutine kdtree2_sort_results(nfound,results) ! Use after search to sort results(1:nfound) in order of increasing ! distance. integer, intent(in) :: nfound type(kdtree2_result), target :: results(:) ! ! !THIS IS BUGGY WITH INTEL FORTRAN ! If (nfound .Gt. 1) Call heapsort(results(1:nfound)%dis,results(1:nfound)%ind,nfound) ! if (nfound .gt. 1) call heapsort_struct(results,nfound) return end subroutine kdtree2_sort_results subroutine heapsort(a,ind,n) ! ! Sort a(1:n) in ascending order, permuting ind(1:n) similarly. ! ! If ind(k) = k upon input, then it will give a sort index upon output. ! integer,intent(in) :: n real(kdkind), intent(inout) :: a(:) integer, intent(inout) :: ind(:) ! ! real(kdkind) :: value ! temporary for a value from a() integer :: ivalue ! temporary for a value from ind() integer :: i,j integer :: ileft,iright ileft=n/2+1 iright=n ! do i=1,n ! ind(i)=i ! Generate initial idum array ! end do if(n.eq.1) return do if(ileft > 1)then ileft=ileft-1 value=a(ileft); ivalue=ind(ileft) else value=a(iright); ivalue=ind(iright) a(iright)=a(1); ind(iright)=ind(1) iright=iright-1 if (iright == 1) then a(1)=value;ind(1)=ivalue return endif endif i=ileft j=2*ileft do while (j <= iright) if(j < iright) then if(a(j) < a(j+1)) j=j+1 endif if(value < a(j)) then a(i)=a(j); ind(i)=ind(j) i=j j=j+j else j=iright+1 endif end do a(i)=value; ind(i)=ivalue end do end subroutine heapsort subroutine heapsort_struct(a,n) ! ! Sort a(1:n) in ascending order ! ! integer,intent(in) :: n type(kdtree2_result),intent(inout) :: a(:) ! ! type(kdtree2_result) :: value ! temporary value integer :: i,j integer :: ileft,iright ileft=n/2+1 iright=n ! do i=1,n ! ind(i)=i ! Generate initial idum array ! end do if(n.eq.1) return do if(ileft > 1)then ileft=ileft-1 value=a(ileft) else value=a(iright) a(iright)=a(1) iright=iright-1 if (iright == 1) then a(1) = value return endif endif i=ileft j=2*ileft do while (j <= iright) if(j < iright) then if(a(j)%dis < a(j+1)%dis) j=j+1 endif if(value%dis < a(j)%dis) then a(i)=a(j); i=j j=j+j else j=iright+1 endif end do a(i)=value end do end subroutine heapsort_structend module kdtree2_module
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -