43 template<
typename PType>
49 ,
float mass_fixed = -1
50 ,
float size_fixed = -1
51 ,PosType my_inv_area = 0
53 ,PosType theta_force = 0.1
54 ,
bool my_periodic_buffer =
false
55 ,PosType my_inv_screening_scale = 0
56 ,PosType maximum_range = -1
61 void force2D(PosType
const *ray,PosType *alpha,KappaType *kappa,KappaType *gamma
62 ,KappaType *phi)
const;
64 void force2D_recur(
const PosType *ray,PosType *alpha,KappaType *kappa
65 ,KappaType *gamma,KappaType *phi);
71 void printParticlesInBranch(
unsigned long number);
73 void printBranchs(
int level = -1);
79 double mass_fixed = 0.0;
81 double size_fixed = 0.0;
91 std::unique_ptr<QTreeNB<PType> > tree;
92 std::vector<IndexType> index;
93 std::vector<PosType> workspace;
100 PosType inv_screening_scale2;
105 void BuildQTreeNB(PType *xp,IndexType Nparticles);
111 inline bool inbox(
const PosType *ray,
const PosType *p1,
const PosType *p2){
112 return (ray[0]>=p1[0])*(ray[0]<=p2[0])*(ray[1]>=p1[1])*(ray[1]<=p2[1]);
120 inline PosType alpha_h(PosType r2s2,PosType sigma)
const{
121 return (sigma > 0.0 ) ? ( exp(-0.5*r2s2) - 1.0 ) : -1.0;
123 inline PosType kappa_h(PosType r2s2,PosType sigma)
const{
124 return 0.5*r2s2*exp(-0.5*r2s2);
126 inline PosType gamma_h(PosType r2s2,PosType sigma)
const{
127 return (sigma > 0.0 ) ? (-2.0 + (2.0 + r2s2)*exp(-0.5*r2s2) ) : -2.0;
129 inline PosType phi_h(PosType r2s2,PosType sigma)
const{
140 inline void b_spline_profile(
157 PosType q2=q*q,q3=q2*q,q4=q2*q2,q5=q4*q;
159 sigma = (8 - 12*q + 6*q2 - q3)/4;
161 sigma *= 10/size/size/7/PI;
162 M = (-1 + 20*q2*(1 - q + 3*q2/8 - q3/20) )/7;
163 *phi += Mass*(-1232. + 1200*q2 - 800.*q3 + 225.*q4 - 24*q5 + 120*log(2./q) )/840/PI;
165 sigma = 10*( sigma - 1 + 3*q - 3*q2 + q3)/size/size/7/PI;
166 M = 10*q2*(1 - 3*q/4 + 3*q3/10)/7;
168 *phi += Mass*( phiintconst + 10*(q2/2 - 3*q4/4 + 3*q5/50)/7
174 PosType alpha_r = (M-1)/PI/r;
175 PosType gt = alpha_r/r - sigma;
177 alpha[0] -= Mass*alpha_r*xcm[0]/r;
178 alpha[1] -= Mass*alpha_r*xcm[1]/r;
179 gamma[0] -= gt*Mass*(xcm[0]*xcm[0]-xcm[1]*xcm[1])/r/r;
180 gamma[1] -= gt*Mass*2*xcm[0]*xcm[1]/r/r;
181 *kappa += Mass*sigma;
182 *phi -= Mass*log(r)/PI;
189 inline void exponential_profile(
201 PosType prefac = Mass/rcm2/PI;
202 PosType arg1 = rcm2/(size*size);
204 PosType tmp = (alpha_h(arg1,size) + 1.0)*prefac;
205 alpha[0] += tmp*xcm[0];
206 alpha[1] += tmp*xcm[1];
208 *kappa += kappa_h(arg1,size)*prefac;
210 tmp = (gamma_h(arg1,size) + 2.0)*prefac/rcm2;
212 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
213 gamma[1] += xcm[0]*xcm[1]*tmp;
227 void walkTree_recur(
QBranchNB *branch,PosType
const *ray,PosType *alpha,KappaType *kappa,KappaType *gamma,KappaType *phi);
229 void walkTree_iter(
QBiterator<PType> &treeit, PosType
const *ray,PosType *alpha,KappaType *kappa
230 ,KappaType *gamma,KappaType *phi)
const;
237 template<
typename PType>
246 ,
bool my_periodic_buffer
247 ,PosType my_inv_screening_scale
248 ,PosType maximum_range
252 ,inv_area(my_inv_area)
255 ,force_theta(theta_force)
256 ,max_range(maximum_range)
257 ,periodic_buffer(my_periodic_buffer)
258 ,inv_screening_scale2(my_inv_screening_scale*my_inv_screening_scale)
260 index.resize(Npoints);
262 if(mass_fixed <= 0 ) MultiMass =
true;
else MultiMass =
false;
263 if(size_fixed <= 0 ) MultiRadius =
true;
else MultiRadius =
false;
265 for(ii=0;ii<Npoints;++ii) index[ii] = ii;
268 BuildQTreeNB(xxp,Npoints);
272 phiintconst = (120*log(2.) - 631.)/840 + 19./70;
278 template<
typename PType>
281 if(Nparticles == 0)
return;
285 template<
typename PType>
298 for(i=0;i<Nparticles;++i){
300 if(xxp[i][j] < p1[j] ) p1[j]=xxp[i][j];
301 if(xxp[i][j] > p2[j] ) p2[j]=xxp[i][j];
313 PosType lengths[2] = {p2[0]-p1[0],p2[1]-p1[1]};
314 original_xl = lengths[0];
315 original_yl = lengths[1];
317 if(lengths[0] == 0 || lengths[1] == 0){
318 throw std::invalid_argument(
"particles in same place.");
322 j = lengths[0] > lengths[1] ? 1 : 0;
323 p2[j] = p1[j] + lengths[!j];
327 tree.reset(
new QTreeNB<PType>(xxp,index.data(),Nparticles,p1,p2) );
330 workspace.resize(Nparticles);
331 _BuildQTreeNB(Nparticles,index.data());
333 workspace.shrink_to_fit();
342 template<
typename PType>
344 return (x[0] < branch.
center[0]) + 2*(x[1] < branch.
center[1]);
348 template<
typename PType>
352 IndexType i,j,cut,cut2;
359 double theta_range = 2*force_theta;
362 theta_range = boxsize / MAX(sqrt(cbranch->
center[0]*cbranch->
center[0]
364 - max_range, boxsize );
368 if(cbranch->nparticles <= Nbucket
369 || force_theta > theta_range
374 for(i=0;i<cbranch->nparticles;++i){
375 r = xxp[particles[i]*MultiRadius].size();
380 cbranch->big_particles.reset(
new IndexType[cbranch->
Nbig_particles]);
382 for(i=0,j=0;i<cbranch->nparticles;++i){
383 r = xxp[particles[i]*MultiRadius].size();
384 if(r < boxsize) cbranch->big_particles[j++] = particles[i];
387 cbranch->big_particles.reset(
nullptr);
396 PosType *x = workspace.data();
402 for(i=0;i<cbranch->nparticles;++i){
403 x[i] = xxp[particles[i]].size();
409 Utilities::quickPartition(maxsize,&cut,particles,x,cbranch->nparticles);
411 if(cut < cbranch->nparticles){
415 Utilities::quickPartition(2*maxsize,&cut2,&particles[cut],&x[cut],cbranch->nparticles-cut);
419 cbranch->big_particles.reset(
new IndexType[cbranch->
Nbig_particles]);
420 for(i=cut;i<(cut+cut2);++i) cbranch->big_particles[i-cut] = particles[i];
430 cbranch->big_particles.reset(
new IndexType[cbranch->
Nbig_particles]);
431 for(i=0;i<cbranch->nparticles;++i) cbranch->big_particles[i] = cbranch->
particles[particles[i]];
436 IndexType NpInChildren = cbranch->nparticles;
437 assert(NpInChildren >= 0);
439 if(NpInChildren == 0){
452 tree->attachChildrenToCurrent(child0,child1,child2,child3);
479 xcut = cbranch->
center[0];
480 ycut = cbranch->
center[1];
483 for(i=0;i<NpInChildren;++i) x[i] = tree->xxp[particles[i]][1];
484 Utilities::quickPartition(ycut,&cuty,particles,x,NpInChildren);
488 for(i=0;i<cuty;++i) x[i] = tree->xxp[particles[i]][0];
489 Utilities::quickPartition(xcut,&cutx,particles,x,cuty);
491 child3->nparticles=cutx;
492 assert(child3->nparticles >= 0);
493 if(child3->nparticles > 0)
497 child2->nparticles = cuty - cutx;
498 assert(child2->nparticles >= 0);
499 if(child2->nparticles > 0)
504 child3->nparticles = 0;
507 child2->nparticles = 0;
511 if(cuty < NpInChildren){
513 for(i=cuty;i<NpInChildren;++i) x[i-cuty] = tree->xxp[particles[i]][0];
514 Utilities::quickPartition(xcut,&cutx,&particles[cuty],x,NpInChildren-cuty);
516 child1->nparticles=cutx;
517 assert(child1->nparticles >= 0);
518 if(child1->nparticles > 0)
522 child0->nparticles=NpInChildren - cuty - cutx;
523 assert(child0->nparticles >= 0);
524 if(child0->nparticles > 0)
525 child0->
particles = &particles[cuty + cutx];
529 child1->nparticles = 0;
532 child0->nparticles = 0;
538 tree->moveToChild(0);
539 _BuildQTreeNB(child0->nparticles,child0->
particles);
542 tree->moveToChild(1);
543 _BuildQTreeNB(child1->nparticles,child1->
particles);
546 tree->moveToChild(2);
547 _BuildQTreeNB(child2->nparticles,child2->
particles);
550 tree->moveToChild(3);
551 _BuildQTreeNB(child3->nparticles,child3->
particles);
558 template<
typename PType>
563 PosType rcom,xcm[2],xcut;
570 cbranch=tree->current;
576 for(i=0,cbranch->mass=0,absmass=0;i<cbranch->nparticles;++i){
577 cbranch->mass += xxp[cbranch->
particles[i]*MultiMass].mass();
578 absmass += fabs(xxp[cbranch->
particles[i]*MultiMass].mass());
582 for(i=0;i<cbranch->nparticles;++i){
583 tmp = fabs(xxp[cbranch->
particles[i]*MultiMass].mass());
593 for(i=0;i<cbranch->nparticles;++i){
596 xcut = pow(xcm[0],2) + pow(xcm[1],2);
597 tmp = xxp[cbranch->
particles[i]*MultiMass].mass();
599 cbranch->
quad[0] += (xcut-2*xcm[0]*xcm[0])*tmp;
600 cbranch->
quad[1] += (xcut-2*xcm[1]*xcm[1])*tmp;
601 cbranch->
quad[2] += -2*xcm[0]*xcm[1]*tmp;
610 if(force_theta > 0.0){
615 }
while(tree->WalkStep(
true));
621 template<
typename PType>
628 for(i=0;i<tree->top->nparticles;++i){
629 for(j=0;j<3;++j) tmp[j]=0.0;
631 tmp[0]+=coord[0][j]*xxp[i][j];
632 tmp[1]+=coord[1][j]*xxp[i][j];
633 tmp[2]+=coord[2][j]*xxp[i][j];
635 for(j=0;j<3;++j) xxp[i][j]=tmp[j];
662 template<
typename PType>
665 alpha[0]=alpha[1]=gamma[0]=gamma[1]=gamma[2]=0.0;
668 if(Nparticles == 0)
return;
676 for(
int i = -1;i<2;++i){
677 for(
int j = -1;j<2;++j){
678 tmp_ray[0] = ray[0] + i*original_xl;
679 tmp_ray[1] = ray[1] + j*original_yl;
680 walkTree_iter(it,tmp_ray,alpha,kappa,gamma,phi);
684 walkTree_iter(it,ray,alpha,kappa,gamma,phi);
698 template<
typename PType>
703 PosType r2 = rmax*rmax;
707 int cut = Utilities::cutbox(ray,(*it)->boundary_p1,(*it)->boundary_p2,rmax);
713 for(
int i=0;i<(*it)->nparticles;++i) neighbors.push_back((*it)->particles[i]);
715 }
else if((*it)->child0 == NULL){
716 for(
int i=0;i<(*it)->nparticles;++i){
717 if( (tree->xxp[(*it)->particles[i]][0] - ray[0])*(tree->xxp[(*it)->particles[i]][0] - ray[0])
718 + (tree->xxp[(*it)->particles[i]][1] - ray[1])*(tree->xxp[(*it)->particles[i]][1] - ray[1]) < r2) neighbors.push_back((*it)->particles[i]);
722 }
while(it.TreeWalkStep(decend));
726 template<
typename PType>
736 PosType xcm[2],rcm2cell,rcm2,tmp,boxarea;
738 bool allowDescent=
true;
739 unsigned long count=0,tmp_index;
758 if((*treeit)->nparticles > 0)
761 xcm[0]=(*treeit)->center[0]-ray[0];
762 xcm[1]=(*treeit)->center[1]-ray[1];
764 rcm2cell = xcm[0]*xcm[0] + xcm[1]*xcm[1];
766 boxarea = ((*treeit)->boundary_p2[0]-(*treeit)->boundary_p1[0])*((*treeit)->boundary_p2[0]-(*treeit)->boundary_p1[0]);
768 if( rcm2cell < ((*treeit)->rcrit_angle)*((*treeit)->rcrit_angle) || rcm2cell < 5.83*boxarea)
779 for(i = 0 ; i < (*treeit)->nparticles ; ++i)
782 xcm[0] = tree->xp[(*treeit)->particles[i]][0] - ray[0];
783 xcm[1] = tree->xp[(*treeit)->particles[i]][1] - ray[1];
785 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
786 double screening = exp(-rcm2*inv_screening_scale2);
787 if(rcm2 < 1e-20) rcm2 = 1e-20;
795 if(MultiMass) mass = xxp[(*treeit)->particles[i]].Mass();
796 else mass = mass_fixed;
798 prefac = mass/rcm2/PI*screening;
799 tmp = -mass*( screening/rcm2/PI - inv_area);
801 alpha[0] += tmp*xcm[0];
802 alpha[1] += tmp*xcm[1];
804 tmp = -2.0*prefac/rcm2;
806 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
807 gamma[1] += xcm[0]*xcm[1]*tmp;
809 *kappa -= mass*inv_area;
810 *phi += (prefac*log(rcm2) - mass*inv_area)*rcm2*0.5;
817 if(rcm2cell < 5.83*boxarea)
820 for(i = 0 ; i < (*treeit)->Nbig_particles ; ++i)
823 tmp_index = (*treeit)->big_particles[i];
825 xcm[0] = tree->xp[tmp_index][0] - ray[0];
826 xcm[1] = tree->xp[tmp_index][1] - ray[1];
828 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
830 if(rcm2 < 1e-20) rcm2 = 1e-20;
833 PosType size = xxp[tmp_index*MultiRadius].size();
836 if(rcm2 < 4*size*size)
838 b_spline_profile(xcm,sqrt(rcm2),xxp[MultiMass*tmp_index].Mass(),size,alpha,kappa,gamma,phi);
851 double screening = exp(-rcm2cell*inv_screening_scale2);
853 double tmp = (*treeit)->mass*( inv_area - screening/rcm2cell/PI );
855 alpha[0] += tmp*xcm[0];
856 alpha[1] += tmp*xcm[1];
859 tmp=-2.0*(*treeit)->mass/PI/rcm2cell/rcm2cell*screening;
860 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
861 gamma[1] += xcm[0]*xcm[1]*tmp;
863 *phi += 0.5*(*treeit)->mass*log( rcm2cell )/PI*screening;
864 *phi -= 0.5*( (*treeit)->quad[0]*xcm[0]*xcm[0] + (*treeit)->quad[1]*xcm[1]*xcm[1] + 2*(*treeit)->quad[2]*xcm[0]*xcm[1] )/(PI*rcm2cell*rcm2cell)*screening;
869 alpha[0] -= ((*treeit)->quad[0]*xcm[0] + (*treeit)->quad[2]*xcm[1])
870 /(rcm2cell*rcm2cell)/PI*screening;
871 alpha[1] -= ((*treeit)->quad[1]*xcm[1] + (*treeit)->quad[2]*xcm[0])
872 /(rcm2cell*rcm2cell)/PI*screening;
874 tmp = 4*((*treeit)->quad[0]*xcm[0]*xcm[0] + (*treeit)->quad[1]*xcm[1]*xcm[1]
875 + 2*(*treeit)->quad[2]*xcm[0]*xcm[1])/(rcm2cell*rcm2cell*rcm2cell)/PI*screening;
877 alpha[0] += tmp*xcm[0];
878 alpha[1] += tmp*xcm[1];
880 *kappa -= (*treeit)->mass * inv_area;
881 *phi -= 0.5*(*treeit)->mass*inv_area;
884 }
while(treeit.TreeWalkStep(allowDescent));
924 template<
typename PType>
928 alpha[0]=alpha[1]=gamma[0]=gamma[1]=gamma[2]=0.0;
931 if(Nparticles == 0)
return;
937 PosType tmp_ray[2],tmp_c[2];
960 for(
int i = -1;i<2;++i){
961 for(
int j = -1;j<2;++j){
962 tmp_ray[0] = tmp_c[0] + i*original_xl;
963 tmp_ray[1] = tmp_c[1] + j*original_yl;
964 walkTree_recur(tree->top,tmp_ray,alpha,kappa,gamma,phi);
968 walkTree_recur(tree->top,ray,alpha,kappa,gamma,phi);
982 template<
typename PType>
985 PosType xcm[2],rcm2cell,rcm2,tmp,boxsize2;
987 std::size_t tmp_index;
993 if(branch->nparticles > 0)
995 xcm[0]=branch->
center[0]-ray[0];
996 xcm[1]=branch->
center[1]-ray[1];
998 rcm2cell = xcm[0]*xcm[0] + xcm[1]*xcm[1];
1002 if( rcm2cell < branch->r2crit_angle || rcm2cell < 5.83*boxsize2)
1006 if(tree->atLeaf(branch))
1009 for(i = 0 ; i < branch->nparticles ; ++i){
1011 xcm[0] = tree->xxp[branch->
particles[i]][0] - ray[0];
1012 xcm[1] = tree->xxp[branch->
particles[i]][1] - ray[1];
1014 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
1015 double screening = exp(-rcm2*inv_screening_scale2);
1016 if(rcm2 < 1e-20) rcm2 = 1e-20;
1018 tmp_index = MultiMass*branch->
particles[i];
1022 double mass = xxp[tmp_index].mass();
1023 prefac = mass*screening/rcm2/PI;
1027 alpha[0] += (inv_area*mass - prefac)*xcm[0];
1028 alpha[1] += (inv_area*mass - prefac)*xcm[1];
1031 tmp = -2.0*prefac/rcm2;
1033 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
1034 gamma[1] += xcm[0]*xcm[1]*tmp;
1036 *kappa -= mass*inv_area;
1037 *phi += prefac*rcm2*0.5*log(rcm2) - mass*inv_area*rcm2/2;
1043 if(rcm2cell < 5.83*boxsize2)
1049 tmp_index = branch->big_particles[i];
1051 xcm[0] = tree->xxp[tmp_index][0] - ray[0];
1052 xcm[1] = tree->xxp[tmp_index][1] - ray[1];
1053 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
1056 if(rcm2 < 1e-20) rcm2 = 1e-20;
1058 PosType size = xxp[tmp_index*MultiRadius].size();
1061 if(rcm2 < 4*size*size)
1064 b_spline_profile(xcm,sqrt(rcm2),xxp[MultiMass*tmp_index].mass(),size,alpha,kappa,gamma,phi);
1071 if(branch->child0 != NULL)
1072 walkTree_recur(branch->child0,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1073 if(branch->child1 != NULL)
1074 walkTree_recur(branch->child1,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1075 if(branch->child2 != NULL)
1076 walkTree_recur(branch->child2,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1077 if(branch->child3 != NULL)
1078 walkTree_recur(branch->child3,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1084 double screening = exp(-rcm2cell*inv_screening_scale2);
1085 double tmp = branch->mass*inv_area - branch->mass/rcm2cell/PI*screening;
1087 alpha[0] += tmp*xcm[0];
1088 alpha[1] += tmp*xcm[1];
1091 tmp=-2.0*branch->mass/PI/rcm2cell/rcm2cell*screening;
1092 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
1093 gamma[1] += xcm[0]*xcm[1]*tmp;
1095 *phi += 0.5*tree->current->mass*log( rcm2cell )/PI*screening;
1096 *phi -= 0.5*( tree->current->quad[0]*xcm[0]*xcm[0] + tree->current->quad[1]*xcm[1]*xcm[1] + 2*tree->current->quad[2]*xcm[0]*xcm[1] )/(PI*rcm2cell*rcm2cell)*screening;
1101 alpha[0] -= (branch->
quad[0]*xcm[0] + branch->
quad[2]*xcm[1])
1102 /(rcm2cell*rcm2cell)/PI*screening;
1103 alpha[1] -= (branch->
quad[1]*xcm[1] + branch->
quad[2]*xcm[0])
1104 /(rcm2cell*rcm2cell)/PI*screening;
1106 tmp = 4*(branch->
quad[0]*xcm[0]*xcm[0] + branch->
quad[1]*xcm[1]*xcm[1]
1107 + 2*branch->
quad[2]*xcm[0]*xcm[1])/(rcm2cell*rcm2cell*rcm2cell)/PI*screening;
1109 alpha[0] += tmp*xcm[0];
1110 alpha[1] += tmp*xcm[1];
1112 *kappa -= inv_area * branch->mass;
1113 *phi -= 0.5*branch->mass*rcm2cell*inv_area;
1125 template<
typename PType>
1131 if(tree->current->number == number){
1132 std::cout << tree->current->nparticles << std::endl;
1133 for(i=0;i<tree->current->nparticles;++i){
1134 std::cout << xxp[tree->current->particles[i]][0] <<
" "
1135 << xxp[tree->current->particles[i]][1] << std::endl;
1139 }
while(tree->WalkStep(
true));
1147 template<
typename PType>
1153 std::cout << tree->current->boundary_p1[0] <<
" " << tree->current->boundary_p1[1] <<
" "
1154 << tree->current->boundary_p2[0] <<
" " << tree->current->boundary_p2[1] << std::endl;
1155 if(tree->current->level == level) decend =
false;
1157 }
while(tree->WalkStep(decend));