📄 kdtree2.f90
字号:
! .. v => tp%the_data(1:,1:) ind => tp%ind(1:) smin = v(c,ind(l)) smax = smin ulocal = u do i = l + 2, ulocal, 2 lmin = v(c,ind(i-1)) lmax = v(c,ind(i)) if (lmin>lmax) then t = lmin lmin = lmax lmax = t end if if (smin>lmin) smin = lmin if (smax<lmax) smax = lmax end do if (i==ulocal+1) then last = v(c,ind(ulocal)) if (smin>last) smin = last if (smax<last) smax = last end if interv%lower = smin interv%upper = smax end subroutine spread_in_coordinate subroutine kdtree2_destroy(tp) ! Deallocates all memory for the tree, except input data matrix ! .. Structure Arguments .. type (kdtree2), pointer :: tp ! .. call destroy_node(tp%root) deallocate (tp%ind) nullify (tp%ind) if (tp%rearrange) then deallocate(tp%rearranged_data) nullify(tp%rearranged_data) endif deallocate(tp) return contains recursive subroutine destroy_node(np) ! .. Structure Arguments .. type (tree_node), pointer :: np ! .. ! .. Intrinsic Functions .. intrinsic ASSOCIATED ! .. if (associated(np%left)) then call destroy_node(np%left) nullify (np%left) end if if (associated(np%right)) then call destroy_node(np%right) nullify (np%right) end if if (associated(np%box)) deallocate(np%box) deallocate(np) return end subroutine destroy_node end subroutine kdtree2_destroy subroutine kdtree2_n_nearest(tp,qv,nn,results) ! Find the 'nn' vectors in the tree nearest to 'qv' in euclidean norm ! returning their indexes and distances in 'indexes' and 'distances' ! arrays already allocated passed to this subroutine. type (kdtree2), pointer :: tp real(kdkind), target, intent (In) :: qv(:) integer, intent (In) :: nn type(kdtree2_result), target :: results(:) sr%ballsize = huge(1.0) sr%qv => qv sr%nn = nn sr%nfound = 0 sr%centeridx = -1 sr%correltime = 0 sr%overflow = .false. sr%results => results sr%nalloc = nn ! will be checked sr%ind => tp%ind sr%rearrange = tp%rearrange if (tp%rearrange) then sr%Data => tp%rearranged_data else sr%Data => tp%the_data endif sr%dimen = tp%dimen call validate_query_storage(nn) sr%pq = pq_create(results) call search(tp%root) if (tp%sort) then call kdtree2_sort_results(nn, results) endif! deallocate(sr%pqp) return end subroutine kdtree2_n_nearest subroutine kdtree2_n_nearest_around_point(tp,idxin,correltime,nn,results) ! Find the 'nn' vectors in the tree nearest to point 'idxin', ! with correlation window 'correltime', returing results in ! results(:), which must be pre-allocated upon entry. type (kdtree2), pointer :: tp integer, intent (In) :: idxin, correltime, nn type(kdtree2_result), target :: results(:) allocate (sr%qv(tp%dimen)) sr%qv = tp%the_data(:,idxin) ! copy the vector sr%ballsize = huge(1.0) ! the largest real(kdkind) number sr%centeridx = idxin sr%correltime = correltime sr%nn = nn sr%nfound = 0 sr%dimen = tp%dimen sr%nalloc = nn sr%results => results sr%ind => tp%ind sr%rearrange = tp%rearrange if (sr%rearrange) then sr%Data => tp%rearranged_data else sr%Data => tp%the_data endif call validate_query_storage(nn) sr%pq = pq_create(results) call search(tp%root) if (tp%sort) then call kdtree2_sort_results(nn, results) endif deallocate (sr%qv) return end subroutine kdtree2_n_nearest_around_point subroutine kdtree2_r_nearest(tp,qv,r2,nfound,nalloc,results) ! find the nearest neighbors to point 'idxin', within SQUARED ! Euclidean distance 'r2'. Upon ENTRY, nalloc must be the ! size of memory allocated for results(1:nalloc). Upon ! EXIT, nfound is the number actually found within the ball. ! ! Note that if nfound .gt. nalloc then more neighbors were found ! than there were storage to store. The resulting list is NOT ! the smallest ball inside norm r^2 ! ! Results are NOT sorted unless tree was created with sort option. type (kdtree2), pointer :: tp real(kdkind), target, intent (In) :: qv(:) real(kdkind), intent(in) :: r2 integer, intent(out) :: nfound integer, intent (In) :: nalloc type(kdtree2_result), target :: results(:) ! sr%qv => qv sr%ballsize = r2 sr%nn = 0 ! flag for fixed ball search sr%nfound = 0 sr%centeridx = -1 sr%correltime = 0 sr%results => results call validate_query_storage(nalloc) sr%nalloc = nalloc sr%overflow = .false. sr%ind => tp%ind sr%rearrange= tp%rearrange if (tp%rearrange) then sr%Data => tp%rearranged_data else sr%Data => tp%the_data endif sr%dimen = tp%dimen ! !sr%dsl = Huge(sr%dsl) ! set to huge positive values !sr%il = -1 ! set to invalid indexes ! call search(tp%root) nfound = sr%nfound if (tp%sort) then call kdtree2_sort_results(nfound, results) endif if (sr%overflow) then write (*,*) 'KD_TREE_TRANS: warning! return from kdtree2_r_nearest found more neighbors' write (*,*) 'KD_TREE_TRANS: than storage was provided for. Answer is NOT smallest ball' write (*,*) 'KD_TREE_TRANS: with that number of neighbors! I.e. it is wrong.' endif return end subroutine kdtree2_r_nearest subroutine kdtree2_r_nearest_around_point(tp,idxin,correltime,r2,& nfound,nalloc,results) ! ! Like kdtree2_r_nearest, but around a point 'idxin' already existing ! in the data set. ! ! Results are NOT sorted unless tree was created with sort option. ! type (kdtree2), pointer :: tp integer, intent (In) :: idxin, correltime, nalloc real(kdkind), intent(in) :: r2 integer, intent(out) :: nfound type(kdtree2_result), target :: results(:) ! .. ! .. Intrinsic Functions .. intrinsic HUGE ! .. allocate (sr%qv(tp%dimen)) sr%qv = tp%the_data(:,idxin) ! copy the vector sr%ballsize = r2 sr%nn = 0 ! flag for fixed r search sr%nfound = 0 sr%centeridx = idxin sr%correltime = correltime sr%results => results sr%nalloc = nalloc sr%overflow = .false. call validate_query_storage(nalloc) ! sr%dsl = HUGE(sr%dsl) ! set to huge positive values ! sr%il = -1 ! set to invalid indexes sr%ind => tp%ind sr%rearrange = tp%rearrange if (tp%rearrange) then sr%Data => tp%rearranged_data else sr%Data => tp%the_data endif sr%rearrange = tp%rearrange sr%dimen = tp%dimen ! !sr%dsl = Huge(sr%dsl) ! set to huge positive values !sr%il = -1 ! set to invalid indexes ! call search(tp%root) nfound = sr%nfound if (tp%sort) then call kdtree2_sort_results(nfound,results) endif if (sr%overflow) then write (*,*) 'KD_TREE_TRANS: warning! return from kdtree2_r_nearest found more neighbors' write (*,*) 'KD_TREE_TRANS: than storage was provided for. Answer is NOT smallest ball' write (*,*) 'KD_TREE_TRANS: with that number of neighbors! I.e. it is wrong.' endif deallocate (sr%qv) return end subroutine kdtree2_r_nearest_around_point function kdtree2_r_count(tp,qv,r2) result(nfound) ! Count the number of neighbors within square distance 'r2'. type (kdtree2), pointer :: tp real(kdkind), target, intent (In) :: qv(:) real(kdkind), intent(in) :: r2 integer :: nfound ! .. ! .. Intrinsic Functions .. intrinsic HUGE ! .. sr%qv => qv sr%ballsize = r2 sr%nn = 0 ! flag for fixed r search sr%nfound = 0 sr%centeridx = -1 sr%correltime = 0 nullify(sr%results) ! for some reason, FTN 95 chokes on '=> null()' sr%nalloc = 0 ! we do not allocate any storage but that's OK ! for counting. sr%ind => tp%ind sr%rearrange = tp%rearrange if (tp%rearrange) then sr%Data => tp%rearranged_data else sr%Data => tp%the_data endif sr%dimen = tp%dimen ! !sr%dsl = Huge(sr%dsl) ! set to huge positive values !sr%il = -1 ! set to invalid indexes ! sr%overflow = .false. call search(tp%root) nfound = sr%nfound return end function kdtree2_r_count function kdtree2_r_count_around_point(tp,idxin,correltime,r2) & result(nfound) ! Count the number of neighbors within square distance 'r2' around ! point 'idxin' with decorrelation time 'correltime'. ! type (kdtree2), pointer :: tp integer, intent (In) :: correltime, idxin real(kdkind), intent(in) :: r2 integer :: nfound ! .. ! .. ! .. Intrinsic Functions .. intrinsic HUGE ! .. allocate (sr%qv(tp%dimen)) sr%qv = tp%the_data(:,idxin) sr%ballsize = r2 sr%nn = 0 ! flag for fixed r search sr%nfound = 0 sr%centeridx = idxin sr%correltime = correltime nullify(sr%results) sr%nalloc = 0 ! we do not allocate any storage but that's OK ! for counting. sr%ind => tp%ind sr%rearrange = tp%rearrange if (sr%rearrange) then sr%Data => tp%rearranged_data else sr%Data => tp%the_data endif sr%dimen = tp%dimen ! !sr%dsl = Huge(sr%dsl) ! set to huge positive values !sr%il = -1 ! set to invalid indexes ! sr%overflow = .false. call search(tp%root) nfound = sr%nfound return end function kdtree2_r_count_around_point subroutine validate_query_storage(n) ! ! make sure we have enough storage for n ! integer, intent(in) :: n if (size(sr%results,1) .lt. n) then write (*,*) 'KD_TREE_TRANS: you did not provide enough storage for results(1:n)' stop return endif return end subroutine validate_query_storage function square_distance(d, iv,qv) result (res) ! distance between iv[1:n] and qv[1:n] ! .. Function Return Value .. ! re-implemented to improve vectorization. real(kdkind) :: res ! .. ! .. ! .. Scalar Arguments .. integer :: d ! .. ! .. Array Arguments .. real(kdkind) :: iv(:),qv(:) ! .. ! .. res = sum( (iv(1:d)-qv(1:d))**2 ) end function square_distance recursive subroutine search(node) ! ! This is the innermost core routine of the kd-tree search. Along ! with "process_terminal_node", it is the performance bottleneck. ! ! This version uses a logically complete secondary search of ! "box in bounds", whether the sear ! type (Tree_node), pointer :: node ! .. type(tree_node),pointer :: ncloser, nfarther ! integer :: cut_dim, i ! .. real(kdkind) :: qval, dis real(kdkind) :: ballsize real(kdkind), pointer :: qv(:) type(interval), pointer :: box(:) if ((associated(node%left) .and. associated(node%right)) .eqv. .false.) then ! we are on a terminal node if (sr%nn .eq. 0) then call process_terminal_node_fixedball(node) else call process_terminal_node(node) endif else ! we are not on a terminal node qv => sr%qv(1:) cut_dim = node%cut_dim qval = qv(cut_dim) if (qval < node%cut_val) then ncloser => node%left nfarther => node%right dis = (node%cut_val_right - qval)**2! extra = node%cut_val - qval else ncloser => node%right nfarther => node%left dis = (node%cut_val_left - qval)**2! extra = qval- node%cut_val_left endif if (associated(ncloser)) call search(ncloser) ! we may need to search the second node. if (associated(nfarther)) then ballsize = sr%ballsize! dis=extra**2 if (dis <= ballsize) then ! ! we do this separately as going on the first cut dimen is often ! a good idea. ! note that if extra**2 < sr%ballsize, then the next ! check will also be false. ! box => node%box(1:) do i=1,sr%dimen if (i .ne. cut_dim) then dis = dis + dis2_from_bnd(qv(i),box(i)%lower,box(i)%upper) if (dis > ballsize) then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -