21 template <
typename T,
typename D = PosType>
32 ,D *(*Mypos)(T&) = [](T& in){
return in.x;}
33 ):Nparticles(Npoints),median_cut(median),Nbucket(bucket),realray(dimensions),
36 index.resize(Nparticles);
37 for(IndexType ii=0;ii<Npoints;++ii) index[ii] = ii;
54 void PointsWithinEllipse(D center[2],
float a_max,
float a_min,
float posangle,std::list<unsigned long> &neighborkist);
57 ,std::vector<IndexType> &neighbors);
61 void pop(IndexType index_of_point){
66 while(index[n] != index_of_point && n < Nparticles) ++n;
67 if(n == Nparticles)
return;
69 std::shared_ptr<BranchV> leaf;
74 long p = current->branch_index - index.data();
75 if(atLeaf() && n >= p && n < p + current->nparticles ){
79 current->branch_index -= 1;
81 }
while(TreeWalkStep(
true));
83 assert(leaf->child1_ptr==
nullptr);
84 assert(leaf->child2_ptr==
nullptr);
87 while(leaf != top_ptr){
88 if(leaf->nparticles > 0) leaf->nparticles -= 1;
91 leaf->nparticles -= 1;
94 for(
size_t i = n ; i < Nparticles - 1 ; ++i){
95 index[i] = index[i+1];
112 for(
int i=0 ; i<current->level ; ++i ) std::cout <<
" ";
113 std::cout << current->level <<
" " << current->nparticles <<
" : ";
114 for(
int i=0 ; i<current->nparticles ; ++i){
115 std::cout << *(current->branch_index+i) <<
" " ;
117 std::cout << std::endl;
118 }
while(TreeWalkStep(
true));
119 std::cout << std::endl;
130 IndexType nparticles;
133 unsigned long number;
140 std::shared_ptr<BranchV> child1_ptr;
141 std::shared_ptr<BranchV> child2_ptr;
149 BranchV(
int my_Ndim,IndexType *my_branch_index,IndexType my_nparticles
150 ,D my_boundary_p1[],D my_boundary_p2[]
151 ,
int my_level,
unsigned long my_BranchVnumber)
152 :Ndim(my_Ndim),
branch_index(my_branch_index),nparticles(my_nparticles)
153 ,
level(my_level),number(my_BranchVnumber)
160 for(
size_t i=0;i<Ndim;++i){
165 child1_ptr =
nullptr;
166 child2_ptr =
nullptr;
174 nparticles = branch.nparticles;
176 number = branch.number;
182 for(
size_t i=0;i<Ndim;++i){
187 child1_ptr =
nullptr;
188 child2_ptr =
nullptr;
202 std::vector<IndexType> index;
203 IndexType Nparticles;
210 std::vector<D> workspace;
212 std::shared_ptr<BranchV> top_ptr;
213 std::shared_ptr<BranchV> current;
221 void _BuildTree(IndexType nparticles,IndexType *tmp_index);
223 void _PointsWithin(D *ray,
float *rmax,std::list<unsigned long> &neighborkist);
234 void getCurrent(IndexType *branch_index,IndexType *nparticles);
235 unsigned long getNbranches();
238 void moveToChild(
int child);
239 void attachChildToCurrent(IndexType *branch_index,IndexType nparticles
240 ,D boundary_p1[],D boundary_p2[]
242 void attachChildToCurrent(BranchV &data,
int child);
243 bool TreeWalkStep(
bool allowDescent);
245 inline bool atLeaf(){
246 return (current->child1_ptr ==
nullptr)*(current->child2_ptr ==
nullptr);
248 inline bool inbox(
const D* center,D *p1,D *p2){
250 for(
int i=0;i<
Ndimensions;++i) tt *= (center[i]>=p1[i]);
257 int cutbox(
const D *center,D *p1,D *p2,
float rmax);
285 template <
typename T,
typename D>
291 ,std::list <unsigned long> &neighborlist
296 if(rmax < rmin){
float tmp = rmax; rmax=rmin; rmin=tmp;}
298 if(rmax <=0.0 || rmin <= 0.0){ neighborlist.clear();
return; }
301 PointsWithinCircle(ray,rmax,neighborlist);
306 for( std::list<unsigned long>::iterator it = neighborlist.begin();it != neighborlist.end();){
307 x = points[*it][0]*cs - points[*it][1]*sn;
308 y = points[*it][0]*sn + points[*it][1]*cs;
309 if( ( pow(x/rmax,2) + pow(y/rmin,2) ) > 1) it = neighborlist.erase(it);
315 template <
typename T,
typename D>
319 ,std::list <unsigned long> &neighborlist
322 neighborlist.clear();
326 for(
int j=0 ; j<Ndimensions ; ++j) realray[j]=ray[j];
330 if( inbox(ray,current->boundary_p1,current->boundary_p2) == 0 ){
332 for(
int i=0 ; i<Ndimensions ; ++i){
333 ray[i] = (ray[i] > current->boundary_p1[i]) ? ray[i] : current->boundary_p1[i];
334 ray[i] = (ray[i] < current->boundary_p2[i]) ? ray[i] : current->boundary_p2[i];
340 _PointsWithin(ray,&rmax,neighborlist);
349 template <
typename T,
typename D>
359 if( inbox(ray,current->boundary_p1,current->boundary_p2) ){
374 for(
int j=0;j<Ndimensions;++j) ray[j]=realray[j];
377 for(i=0;i<current->nparticles;++i){
378 for(j=0,radius=0.0;j<2;++j) radius+=pow(position(points[current->branch_index[i]])[j]-ray[j],2);
379 if( radius < *rmax**rmax ){
380 neighborlist.push_back(current->branch_index[i]);
386 for(i=0;i<current->nparticles;++i){
387 neighborlist.push_back(current->branch_index[i]);
396 if(current->child1_ptr !=
nullptr){
398 _PointsWithin(ray,rmax,neighborlist);
404 if(current->child2_ptr !=
nullptr){
406 _PointsWithin(ray,rmax,neighborlist);
411 if( (incell2==1) && (incell==0) ){
412 if(current->child1_ptr !=
nullptr){
414 _PointsWithin(ray,rmax,neighborlist);
423 pass = cutbox(ray,current->boundary_p1,current->boundary_p2,*rmax);
429 for(i=0;i<current->nparticles;++i){
430 for(j=0,radius=0.0;j<2;++j) radius+=pow(position(points[current->branch_index[i]])[j]-ray[j],2);
431 if( radius < *rmax**rmax ){
432 neighborlist.push_back(current->branch_index[i]);
441 if(current->child1_ptr !=
nullptr){
443 _PointsWithin(ray,rmax,neighborlist);
447 if(current->child2_ptr !=
nullptr){
449 _PointsWithin(ray,rmax,neighborlist);
462 template <
typename T,
typename D>
466 ,std::vector<D> &radii
467 ,std::vector<IndexType> &neighbors
473 if(top_ptr->nparticles <= Nneighbors){
475 std::vector<D> tmp(Nparticles);
476 std::vector<size_t> sort_index(Nparticles);
477 for(
int i = 0 ; i< Nparticles ; ++i){
478 tmp[i] = pow(position(points[i])[0]-ray[0],2) + pow(position(points[i])[1]-ray[1],2);
482 std::sort(sort_index.begin(),sort_index.end(),[&tmp](
size_t i,
size_t j){return tmp[i] < tmp[j];});
484 radii.resize(Nparticles);
485 neighbors.resize(Nparticles);
487 for(
int i = 0 ; i< Nparticles ; ++i){
488 neighbors[i] = index[sort_index[i]];
489 radii[i] = tmp[sort_index[i]];
495 radii.resize(Nneighbors+Nbucket);
496 neighbors.resize(Nneighbors+Nbucket);
500 for(i=0;i<Nbucket+Nneighbors;++i){
501 radii[i] = (10*(top_ptr->boundary_p2[0]-top_ptr->boundary_p1[0]));
505 for(
int j=0;j<Ndimensions;++j) realray[j]=ray[j];
508 if( inbox(ray,current->boundary_p1,current->boundary_p2) == 0 ){
511 for(j=0;j<Ndimensions;++j){
512 ray[j] = (ray[j] > current->boundary_p1[j]) ? ray[j] : current->boundary_p1[j];
513 ray[j] = (ray[j] < current->boundary_p2[j]) ? ray[j] : current->boundary_p2[j];
518 _NearestNeighbors(ray,Nneighbors,neighbors.data(),radii.data());
520 neighbors.resize(Nneighbors);
521 radii.resize(Nneighbors);
528 template <
typename T,
typename D>
538 D rneighbors[1+Nbucket];
539 IndexType neighbors[1+Nbucket];
541 if(top_ptr->nparticles < 1){
543 printf(
"ERROR: in NearestNeighbors, number of neighbors > total number of particles\n");
544 throw std::runtime_error(
"Asked for too many neighbors");
548 for(i=0;i<Nbucket+1;++i){
549 rneighbors[i] = (10*(top_ptr->boundary_p2[0]-top_ptr->boundary_p1[0]));
553 for(
int j=0;j<Ndimensions;++j) realray.x[j]=ray[j];
556 if( inbox(ray,current->boundary_p1,current->boundary_p2) == 0 ){
559 for(
int j=0;j<Ndimensions;++j){
560 ray[j] = (ray[j] > current->boundary_p1[j]) ? ray[j] : current->boundary_p1[j];
561 ray[j] = (ray[j] < current->boundary_p2[j]) ? ray[j] : current->boundary_p2[j];
566 _NearestNeighbors(ray,1,neighbors,rneighbors);
568 neighbor = neighbors[0];
569 radius = rneighbors[0];
574 template <
typename T,
typename D>
583 if( inbox(ray,current->boundary_p1,current->boundary_p2) ){
586 if( current->nparticles <= Nneighbors+Nbucket ){
588 for(j=0;j<Ndimensions;++j) ray[j]=realray[j];
591 for(i=0;i<current->nparticles;++i){
592 for(j=0,rneighbors[i]=0.0;j<Ndimensions;++j){
593 rneighbors[i] += pow(position(points[current->branch_index[i]])[j]-ray[j],2);
595 rneighbors[i]=sqrt( rneighbors[i] );
597 neighbors[i]=current->branch_index[i];
600 Utilities::quicksort(neighbors,rneighbors,current->nparticles);
604 if(current->child1_ptr !=
nullptr){
606 _NearestNeighbors(ray,Nneighbors,neighbors,rneighbors);
613 if(current->child2_ptr !=
nullptr){
616 _NearestNeighbors(ray,Nneighbors,neighbors,rneighbors);
622 if( (incellNB2==1) && (incell==0) ){
623 if(current->child1_ptr !=
nullptr){
625 _NearestNeighbors(ray,Nneighbors,neighbors,rneighbors);
633 if( cutbox(ray,current->boundary_p1,current->boundary_p2,rneighbors[Nneighbors-1]) ){
635 if( (current->child1_ptr ==
nullptr)*(current->child2_ptr ==
nullptr)){
638 for(i=Nneighbors;i<(current->nparticles+Nneighbors);++i){
639 for(j=0,rneighbors[i]=0.0;j<Ndimensions;++j){
640 rneighbors[i]+=pow(position(points[current->branch_index[i-Nneighbors]])[j]-ray[j],2);
642 rneighbors[i]=sqrt( rneighbors[i] );
644 neighbors[i]=current->branch_index[i-Nneighbors];
647 Utilities::quicksort(neighbors,rneighbors,Nneighbors+Nbucket);
651 if(current->child1_ptr !=
nullptr){
653 _NearestNeighbors(ray,Nneighbors,neighbors,rneighbors);
657 if(current->child2_ptr !=
nullptr){
659 _NearestNeighbors(ray,Nneighbors,neighbors,rneighbors);
668 template <
typename T,
typename D>
672 std::vector<D> p1(Ndimensions),p2(Ndimensions);
675 for(j=0;j<Ndimensions;++j){
676 p1[j] = position(points[0])[j];
677 p2[j] = position(points[0])[j];
680 for(i=0;i<Nparticles;++i){
681 for(j=0;j<Ndimensions;++j){
682 if(position(points[i])[j] < p1[j] ) p1[j] = position(points[i])[j];
683 if(position(points[i])[j] > p2[j] ) p2[j] = position(points[i])[j];
688 top_ptr.reset(
new BranchV(Ndimensions,index.data(),Nparticles,p1.data(),p2.data(),0,0));
692 ERROR_MESSAGE(); fprintf(stderr,
"allocation failure in NewTree()\n");
698 workspace.resize(Nparticles);
699 _BuildTree(Nparticles,index.data());
701 workspace.shrink_to_fit();
704 for(j=0;j<Ndimensions;++j){
709 top_ptr.reset(
new BranchV(Ndimensions,index.data(),0,p1.data(),p2.data(),0,0));
713 ERROR_MESSAGE(); fprintf(stderr,
"allocation failure in NewTree()\n");
723 template <
typename T,
typename D>
725 IndexType i,cut,dimension;
726 BranchV branch1(*current),branch2(*current);
728 std::shared_ptr<BranchV> cbranch;
733 if(cbranch->nparticles <= Nbucket){
741 dimension=(cbranch->level % Ndimensions);
744 D *x = workspace.data();
745 for(i=0;i<cbranch->nparticles;++i) x[i] = position(points[tmp_index[i]])[dimension];
748 Utilities::quicksort(tmp_index,x,cbranch->nparticles);
750 cut=(cbranch->nparticles)/2;
751 branch1.boundary_p2[dimension]=x[cut];
752 branch2.boundary_p1[dimension]=x[cut];
754 xcut=(cbranch->boundary_p1[dimension]+cbranch->boundary_p2[dimension])/2;
755 branch1.boundary_p2[dimension]=xcut;
756 branch2.boundary_p1[dimension]=xcut;
758 Utilities::quickPartition(xcut,&cut,tmp_index
759 ,x,cbranch->nparticles);
763 branch1.prev_ptr = cbranch;
764 branch1.nparticles=cut;
766 branch2.prev_ptr = cbranch;
767 branch2.nparticles=cbranch->nparticles - cut;
768 if(cut < (cbranch->nparticles) )
769 branch2.branch_index = &tmp_index[cut];
770 else branch2.branch_index=
nullptr;
772 if(branch1.nparticles > 0) attachChildToCurrent(branch1,1);
773 if(branch2.nparticles > 0) attachChildToCurrent(branch2,2);
776 if( (cbranch->child1_ptr !=
nullptr) && (cbranch->child2_ptr !=
nullptr) ){
777 cbranch->child1_ptr->brother_ptr = cbranch->child2_ptr;
778 cbranch->child2_ptr->brother_ptr = cbranch->brother_ptr;
780 if( (cbranch->child1_ptr ==
nullptr) && (cbranch->child2_ptr !=
nullptr) )
781 cbranch->child2_ptr->brother_ptr = cbranch->brother_ptr;
782 if( (cbranch->child1_ptr !=
nullptr) && (cbranch->child2_ptr ==
nullptr) )
783 cbranch->child1_ptr->brother_ptr = cbranch->brother_ptr;
786 if( branch1.nparticles > 0 ){
788 _BuildTree(branch1.nparticles,branch1.branch_index);
792 if(branch2.nparticles > 0 ){
794 _BuildTree(branch2.nparticles,branch2.branch_index);
802 template <
typename T,
typename D>
864 template <
typename T,
typename D>
866 return(Nbranches == 0);
875 template <
typename T,
typename D>
880 fprintf(stderr,
"Tree Error: calling atTop() on empty tree\n");
883 return(current == top_ptr);
892 template <
typename T,
typename D>
897 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: calling atTop() on empty tree\n");
901 if( (current->child1 ==
nullptr) || (current->child2 ==
nullptr) )
return true;
909 template <
typename T,
typename D>
912 return(current ==
nullptr);
920 template <
typename T,
typename D>
925 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: calling getCurrent() when current is off end\n");
929 *nparticles = current->nparticles;
930 branch_index = current->branch_index;
939 template <
typename T,
typename D>
952 template <
typename T,
typename D>
957 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: calling moveTop() on empty tree\n");
972 template <
typename T,
typename D>
976 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: call to moveUp() when current is off end\n");
979 if( current == top_ptr ){
980 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: call to moveUp() tried to move off the top\n");
984 current = current->prev_ptr;
994 template <
typename T,
typename D>
999 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: calling moveChildren() when current is off end\n");
1003 if( current->child1_ptr ==
nullptr ){
1004 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: moveToChild() typing to move to child1 when it doesn't exist\n");
1007 current = current->child1_ptr;
1010 if( current->child2_ptr ==
nullptr ){
1011 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: moveToChild() typing to move to child2 when it doesn't exist\n");
1014 current = current->child2_ptr;
1025 template <
typename T,
typename D>
1027 ,D boundary_p1[],D boundary_p2[]
1031 std::shared_ptr<BranchV> branchV(
new BranchV(Ndimensions,branch_index,nparticles,boundary_p1,boundary_p2
1032 ,current->level+1,Nbranches));
1039 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: calling attachChildToCurrent() when current is off end\n");
1043 branchV->prev_ptr = current;
1046 if(current->child1_ptr !=
nullptr){
1047 ERROR_MESSAGE(); fprintf(stderr,
"Tree Error: calling attachChildToCurrent() when child1 alread exists\n");
1050 current->child1_ptr = branchV;
1053 if(current->child2_ptr !=
nullptr){
1055 fprintf(stderr,
"Tree Error: calling attachChildToCurrent() when child2 alread exists\n current level=%i Nbranches=%li\n"
1056 ,current->level,Nbranches);
1059 current->child2_ptr = branchV;
1066 template <
typename T,
typename D>
1069 attachChildToCurrent(data.branch_index,data.nparticles
1070 ,data.boundary_p1,data.boundary_p2,child);
1075 template <
typename T,
typename D>
1077 if(allowDescent && current->child1_ptr !=
nullptr){
1081 if(allowDescent && current->child2_ptr !=
nullptr){
1086 if(current->brother_ptr !=
nullptr){
1087 current = current->brother_ptr;
1096 template <
typename T,
typename D>
1098 int intersection = 1,inside=1;
1099 for(
int i=0 ; i<Ndimensions ; ++i){
1100 intersection *= ( (center[i] + rmax) > p1[i] )*( (center[i] - rmax) < p2[i] );
1101 inside *= ( (center[i] - rmax) > p1[i] )*( (center[i] + rmax) < p2[i] );
1104 return intersection + inside;