118 inline bool inbox(
const PosType *ray,
const PosType *p1,
const PosType *p2){
119 return (ray[0]>=p1[0])*(ray[0]<=p2[0])*(ray[1]>=p1[1])*(ray[1]<=p2[1]);
127 inline PosType alpha_h(PosType r2s2,PosType sigma)
const{
128 return (sigma > 0.0 ) ? ( exp(-0.5*r2s2) - 1.0 ) : -1.0;
130 inline PosType kappa_h(PosType r2s2,PosType sigma)
const{
131 return 0.5*r2s2*exp(-0.5*r2s2);
133 inline PosType gamma_h(PosType r2s2,PosType sigma)
const{
134 return (sigma > 0.0 ) ? (-2.0 + (2.0 + r2s2)*exp(-0.5*r2s2) ) : -2.0;
136 inline PosType phi_h(PosType r2s2,PosType sigma)
const{
147 inline void b_spline_profile(
164 PosType q2=q*q,q3=q2*q,q4=q2*q2,q5=q4*q;
166 sigma = (8 - 12*q + 6*q2 - q3)/4;
168 sigma *= 10/size/size/7/PI;
169 M = (-1 + 20*q2*(1 - q + 3*q2/8 - q3/20) )/7;
170 *phi += Mass*(-1232. + 1200*q2 - 800.*q3 + 225.*q4 - 24*q5 + 120*log(2./q) )/840/PI;
172 sigma = 10*( sigma - 1 + 3*q - 3*q2 + q3)/size/size/7/PI;
173 M = 10*q2*(1 - 3*q/4 + 3*q3/10)/7;
175 *phi += Mass*( phiintconst + 10*(q2/2 - 3*q4/4 + 3*q5/50)/7
181 alpha_r = (M-1)/PI/r;
182 gt = alpha_r/r - sigma;
184 alpha[0] -= Mass*alpha_r*xcm[0]/r;
185 alpha[1] -= Mass*alpha_r*xcm[1]/r;
186 gamma[0] -= gt*Mass*(xcm[0]*xcm[0]-xcm[1]*xcm[1])/r/r;
187 gamma[1] -= gt*Mass*2*xcm[0]*xcm[1]/r/r;
188 *kappa += Mass*sigma;
189 *phi -= Mass*log(r)/PI;
196 inline void exponential_profile(
208 PosType prefac = Mass/rcm2/PI;
209 PosType arg1 = rcm2/(size*size);
211 PosType tmp = (alpha_h(arg1,size) + 1.0)*prefac;
212 alpha[0] += tmp*xcm[0];
213 alpha[1] += tmp*xcm[1];
216 *kappa += kappa_h(arg1,size)*prefac;
218 tmp = (gamma_h(arg1,size) + 2.0)*prefac/rcm2;
220 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
221 gamma[1] += xcm[0]*xcm[1]*tmp;
235 void walkTree_recur(
QBranchNB *branch,PosType
const *ray,PosType *alpha,KappaType *kappa,KappaType *gamma,KappaType *phi);
237 void walkTree_iter(
QBiterator<PType> &treeit, PosType
const *ray,PosType *alpha,KappaType *kappa
238 ,KappaType *gamma,KappaType *phi)
const;
247template<
typename PType>
256 ,
bool my_periodic_buffer
257 ,PosType my_inv_screening_scale
258 ,PosType maximum_range
262,inv_area(my_inv_area)
265,force_theta(theta_force)
266,max_range(maximum_range)
267,periodic_buffer(my_periodic_buffer)
268,inv_screening_scale2(my_inv_screening_scale*my_inv_screening_scale)
270 index.resize(Npoints);
272 if(mass_fixed <= 0 ) MultiMass =
true;
else MultiMass =
false;
273 if(size_fixed <= 0 ) MultiRadius =
true;
else MultiRadius =
false;
275 for(ii=0;ii<Npoints;++ii) index[ii] = ii;
278 BuildQTreeNB(xxp,Npoints);
282 phiintconst = (120*log(2.) - 631.)/840 + 19./70;
288template<
typename PType>
291 if(Nparticles == 0)
return;
295template<
typename PType>
308 for(i=0;i<Nparticles;++i){
310 if(xxp[i][j] < p1[j] ) p1[j]=xxp[i][j];
311 if(xxp[i][j] > p2[j] ) p2[j]=xxp[i][j];
323 PosType lengths[2] = {p2[0]-p1[0],p2[1]-p1[1]};
324 original_xl = lengths[0];
325 original_yl = lengths[1];
327 if(lengths[0] == 0 || lengths[1] == 0){
328 throw std::invalid_argument(
"particles in same place.");
332 j = lengths[0] > lengths[1] ? 1 : 0;
333 p2[j] = p1[j] + lengths[!j];
337 tree.reset(
new QTreeNB<PType>(xxp,index.data(),Nparticles,p1,p2) );
340 workspace.resize(Nparticles);
341 _BuildQTreeNB(Nparticles,index.data());
343 workspace.shrink_to_fit();
353template<
typename PType>
355 return (x[0] < branch.
center[0]) + 2*(x[1] < branch.
center[1]);
359template<
typename PType>
363 IndexType i,j,cut,cut2;
370 double theta_range = 2*force_theta;
373 theta_range = boxsize / MAX(sqrt(cbranch->
center[0]*cbranch->
center[0]
375 - max_range, boxsize );
379 if(cbranch->nparticles <= Nbucket
380 || force_theta > theta_range
384 for(i=0;i<cbranch->nparticles;++i){
385 r = xxp[particles[i]*MultiRadius].size();
390 cbranch->big_particles.reset(
new IndexType[cbranch->
Nbig_particles]);
392 for(i=0,j=0;i<cbranch->nparticles;++i){
393 r = xxp[particles[i]*MultiRadius].size();
397 cbranch->big_particles.reset(
nullptr);
406 PosType *x = workspace.data();
412 for(i=0;i<cbranch->nparticles;++i){
413 x[i] = xxp[particles[i]].size();
419 Utilities::quickPartition(maxsize,&cut,particles,x,cbranch->nparticles);
421 if(cut < cbranch->nparticles){
425 Utilities::quickPartition(2*maxsize,&cut2,&particles[cut],&x[cut],cbranch->nparticles-cut);
429 cbranch->big_particles.reset(
new IndexType[cbranch->
Nbig_particles]);
430 for(i=cut;i<(cut+cut2);++i) cbranch->big_particles[i-cut] = particles[i];
440 cbranch->big_particles.reset(
new IndexType[cbranch->
Nbig_particles]);
441 for(i=0;i<cbranch->nparticles;++i) cbranch->big_particles[i] = cbranch->
particles[particles[i]];
446 IndexType NpInChildren = cbranch->nparticles;
447 assert(NpInChildren >= 0);
449 if(NpInChildren == 0){
462 tree->attachChildrenToCurrent(child0,child1,child2,child3);
489 xcut = cbranch->
center[0];
490 ycut = cbranch->
center[1];
493 for(i=0;i<NpInChildren;++i) x[i] = tree->xxp[particles[i]][1];
494 Utilities::quickPartition(ycut,&cuty,particles,x,NpInChildren);
498 for(i=0;i<cuty;++i) x[i] = tree->xxp[particles[i]][0];
499 Utilities::quickPartition(xcut,&cutx,particles,x,cuty);
501 child3->nparticles=cutx;
502 assert(child3->nparticles >= 0);
503 if(child3->nparticles > 0)
507 child2->nparticles = cuty - cutx;
508 assert(child2->nparticles >= 0);
509 if(child2->nparticles > 0)
514 child3->nparticles = 0;
517 child2->nparticles = 0;
521 if(cuty < NpInChildren){
523 for(i=cuty;i<NpInChildren;++i) x[i-cuty] = tree->xxp[particles[i]][0];
524 Utilities::quickPartition(xcut,&cutx,&particles[cuty],x,NpInChildren-cuty);
526 child1->nparticles=cutx;
527 assert(child1->nparticles >= 0);
528 if(child1->nparticles > 0)
532 child0->nparticles=NpInChildren - cuty - cutx;
533 assert(child0->nparticles >= 0);
534 if(child0->nparticles > 0)
535 child0->
particles = &particles[cuty + cutx];
539 child1->nparticles = 0;
542 child0->nparticles = 0;
548 tree->moveToChild(0);
549 _BuildQTreeNB(child0->nparticles,child0->
particles);
552 tree->moveToChild(1);
553 _BuildQTreeNB(child1->nparticles,child1->
particles);
556 tree->moveToChild(2);
557 _BuildQTreeNB(child2->nparticles,child2->
particles);
560 tree->moveToChild(3);
561 _BuildQTreeNB(child3->nparticles,child3->
particles);
568template<
typename PType>
573 PosType rcom,xcm[2],xcut;
580 cbranch=tree->current;
586 for(i=0,cbranch->mass=0,absmass=0;i<cbranch->nparticles;++i){
587 cbranch->mass += xxp[cbranch->
particles[i]*MultiMass].mass();
588 absmass += fabs(xxp[cbranch->
particles[i]*MultiMass].mass());
592 for(i=0;i<cbranch->nparticles;++i){
593 tmp = fabs(xxp[cbranch->
particles[i]*MultiMass].mass());
603 for(i=0;i<cbranch->nparticles;++i){
606 xcut = pow(xcm[0],2) + pow(xcm[1],2);
607 tmp = xxp[cbranch->
particles[i]*MultiMass].mass();
609 cbranch->
quad[0] += (xcut-2*xcm[0]*xcm[0])*tmp;
610 cbranch->
quad[1] += (xcut-2*xcm[1]*xcm[1])*tmp;
611 cbranch->
quad[2] += -2*xcm[0]*xcm[1]*tmp;
616 pow(cbranch->
center[i]-cbranch->
boundary_p1[i],2) : pow(cbranch->center[i]-cbranch->boundary_p2[i],2);
620 if(force_theta > 0.0){
625 }
while(tree->WalkStep(
true));
631template<
typename PType>
638 for(i=0;i<tree->top->nparticles;++i){
639 for(j=0;j<3;++j) tmp[j]=0.0;
641 tmp[0]+=coord[0][j]*xxp[i][j];
642 tmp[1]+=coord[1][j]*xxp[i][j];
643 tmp[2]+=coord[2][j]*xxp[i][j];
645 for(j=0;j<3;++j) xxp[i][j]=tmp[j];
670template<
typename PType>
673 alpha[0]=alpha[1]=gamma[0]=gamma[1]=gamma[2]=0.0;
676 if(Nparticles == 0)
return;
684 for(
int i = -1;i<2;++i){
685 for(
int j = -1;j<2;++j){
686 tmp_ray[0] = ray[0] + i*original_xl;
687 tmp_ray[1] = ray[1] + j*original_yl;
688 walkTree_iter(it,tmp_ray,alpha,kappa,gamma,phi);
692 walkTree_iter(it,ray,alpha,kappa,gamma,phi);
706template<
typename PType>
711 PosType r2 = rmax*rmax;
715 int cut = Utilities::cutbox(ray,(*it)->boundary_p1,(*it)->boundary_p2,rmax);
721 for(
int i=0;i<(*it)->nparticles;++i) neighbors.push_back((*it)->particles[i]);
723 }
else if((*it)->child0 == NULL){
724 for(
int i=0;i<(*it)->nparticles;++i){
725 if( (tree->xxp[(*it)->particles[i]][0] - ray[0])*(tree->xxp[(*it)->particles[i]][0] - ray[0])
726 + (tree->xxp[(*it)->particles[i]][1] - ray[1])*(tree->xxp[(*it)->particles[i]][1] - ray[1]) < r2) neighbors.push_back((*it)->particles[i]);
730 }
while(it.TreeWalkStep(decend));
734template<
typename PType>
744 PosType xcm[2],rcm2cell,rcm2,tmp,boxsize2;
746 bool allowDescent=
true;
747 unsigned long count=0,tmp_index;
766 if((*treeit)->nparticles > 0)
769 xcm[0]=(*treeit)->center[0]-ray[0];
770 xcm[1]=(*treeit)->center[1]-ray[1];
772 rcm2cell = xcm[0]*xcm[0] + xcm[1]*xcm[1];
774 boxsize2 = ((*treeit)->boundary_p2[0]-(*treeit)->boundary_p1[0])*((*treeit)->boundary_p2[0]-(*treeit)->boundary_p1[0]);
776 if( rcm2cell < ((*treeit)->rcrit_angle)*((*treeit)->rcrit_angle) || rcm2cell < 5.83*boxsize2)
787 for(i = 0 ; i < (*treeit)->nparticles ; ++i)
790 xcm[0] = tree->xp[(*treeit)->particles[i]][0] - ray[0];
791 xcm[1] = tree->xp[(*treeit)->particles[i]][1] - ray[1];
793 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
794 double screening = exp(-rcm2*inv_screening_scale2);
795 if(rcm2 < 1e-20) rcm2 = 1e-20;
803 if(MultiMass) mass = xxp[(*treeit)->particles[i]].Mass();
804 else mass = mass_fixed;
806 prefac = mass/rcm2/PI*screening;
807 tmp = -mass*( screening/rcm2/PI - inv_area);
809 alpha[0] += tmp*xcm[0];
810 alpha[1] += tmp*xcm[1];
812 tmp = -2.0*prefac/rcm2;
814 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
815 gamma[1] += xcm[0]*xcm[1]*tmp;
817 *kappa -= mass*inv_area;
818 *phi += (prefac*log(rcm2) - mass*inv_area)*rcm2*0.5;
825 if(rcm2cell < 5.83*boxsize2)
828 for(i = 0 ; i < (*treeit)->Nbig_particles ; ++i)
831 tmp_index = (*treeit)->big_particles[i];
833 xcm[0] = tree->xp[tmp_index][0] - ray[0];
834 xcm[1] = tree->xp[tmp_index][1] - ray[1];
836 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
838 if(rcm2 < 1e-20) rcm2 = 1e-20;
841 PosType size = xxp[tmp_index*MultiRadius].size();
844 if(rcm2 < 4*size*size)
846 b_spline_profile(xcm,sqrt(rcm2),xxp[MultiMass*tmp_index].Mass(),size,alpha,kappa,gamma,phi);
859 double screening = exp(-rcm2cell*inv_screening_scale2);
861 double tmp = (*treeit)->mass*( inv_area - screening/rcm2cell/PI );
863 alpha[0] += tmp*xcm[0];
864 alpha[1] += tmp*xcm[1];
867 tmp=-2.0*(*treeit)->mass/PI/rcm2cell/rcm2cell*screening;
868 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
869 gamma[1] += xcm[0]*xcm[1]*tmp;
871 *phi += 0.5*(*treeit)->mass*log( rcm2cell )/PI*screening;
872 *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;
877 alpha[0] -= ((*treeit)->quad[0]*xcm[0] + (*treeit)->quad[2]*xcm[1])
878 /(rcm2cell*rcm2cell)/PI*screening;
879 alpha[1] -= ((*treeit)->quad[1]*xcm[1] + (*treeit)->quad[2]*xcm[0])
880 /(rcm2cell*rcm2cell)/PI*screening;
882 tmp = 4*((*treeit)->quad[0]*xcm[0]*xcm[0] + (*treeit)->quad[1]*xcm[1]*xcm[1]
883 + 2*(*treeit)->quad[2]*xcm[0]*xcm[1])/(rcm2cell*rcm2cell*rcm2cell)/PI*screening;
885 alpha[0] += tmp*xcm[0];
886 alpha[1] += tmp*xcm[1];
888 *kappa -= (*treeit)->mass * inv_area;
889 *phi -= 0.5*(*treeit)->mass*inv_area;
892 }
while(treeit.TreeWalkStep(allowDescent));
932template<
typename PType>
936 alpha[0]=alpha[1]=gamma[0]=gamma[1]=gamma[2]=0.0;
939 if(Nparticles == 0)
return;
945 PosType tmp_ray[2],tmp_c[2];
968 for(
int i = -1;i<2;++i){
969 for(
int j = -1;j<2;++j){
970 tmp_ray[0] = tmp_c[0] + i*original_xl;
971 tmp_ray[1] = tmp_c[1] + j*original_yl;
972 walkTree_recur(tree->top,tmp_ray,alpha,kappa,gamma,phi);
976 walkTree_recur(tree->top,ray,alpha,kappa,gamma,phi);
990template<
typename PType>
993 PosType xcm[2],rcm2cell,rcm2,tmp,boxsize2;
995 std::size_t tmp_index;
1001 if(branch->nparticles > 0)
1003 xcm[0]=branch->
center[0]-ray[0];
1004 xcm[1]=branch->
center[1]-ray[1];
1006 rcm2cell = xcm[0]*xcm[0] + xcm[1]*xcm[1];
1010 if( rcm2cell < branch->r2crit_angle || rcm2cell < 5.83*boxsize2)
1014 if(tree->atLeaf(branch))
1017 for(i = 0 ; i < branch->nparticles ; ++i){
1019 xcm[0] = tree->xxp[branch->
particles[i]][0] - ray[0];
1020 xcm[1] = tree->xxp[branch->
particles[i]][1] - ray[1];
1022 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
1023 double screening = exp(-rcm2*inv_screening_scale2);
1024 if(rcm2 < 1e-20) rcm2 = 1e-20;
1026 tmp_index = MultiMass*branch->
particles[i];
1030 double mass = xxp[tmp_index].mass();
1031 prefac = mass*screening/rcm2/PI;
1035 alpha[0] += (inv_area*mass - prefac)*xcm[0];
1036 alpha[1] += (inv_area*mass - prefac)*xcm[1];
1039 tmp = -2.0*prefac/rcm2;
1041 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
1042 gamma[1] += xcm[0]*xcm[1]*tmp;
1044 *kappa -= mass*inv_area;
1045 *phi += prefac*rcm2*0.5*log(rcm2) - mass*inv_area*rcm2/2;
1051 if(rcm2cell < 5.83*boxsize2)
1057 tmp_index = branch->big_particles[i];
1059 xcm[0] = tree->xxp[tmp_index][0] - ray[0];
1060 xcm[1] = tree->xxp[tmp_index][1] - ray[1];
1061 rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
1064 if(rcm2 < 1e-20) rcm2 = 1e-20;
1066 PosType size = xxp[tmp_index*MultiRadius].size();
1069 if(rcm2 < 4*size*size)
1072 b_spline_profile(xcm,sqrt(rcm2),xxp[MultiMass*tmp_index].mass(),size,alpha,kappa,gamma,phi);
1079 if(branch->child0 != NULL)
1080 walkTree_recur(branch->child0,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1081 if(branch->child1 != NULL)
1082 walkTree_recur(branch->child1,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1083 if(branch->child2 != NULL)
1084 walkTree_recur(branch->child2,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1085 if(branch->child3 != NULL)
1086 walkTree_recur(branch->child3,&ray[0],&alpha[0],kappa,&gamma[0],&phi[0]);
1092 double screening = exp(-rcm2cell*inv_screening_scale2);
1093 double tmp = branch->mass*inv_area - branch->mass/rcm2cell/PI*screening;
1095 alpha[0] += tmp*xcm[0];
1096 alpha[1] += tmp*xcm[1];
1099 tmp=-2.0*branch->mass/PI/rcm2cell/rcm2cell*screening;
1100 gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
1101 gamma[1] += xcm[0]*xcm[1]*tmp;
1103 *phi += 0.5*tree->current->mass*log( rcm2cell )/PI*screening;
1104 *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;
1109 alpha[0] -= (branch->
quad[0]*xcm[0] + branch->
quad[2]*xcm[1])
1110 /(rcm2cell*rcm2cell)/PI*screening;
1111 alpha[1] -= (branch->
quad[1]*xcm[1] + branch->
quad[2]*xcm[0])
1112 /(rcm2cell*rcm2cell)/PI*screening;
1114 tmp = 4*(branch->
quad[0]*xcm[0]*xcm[0] + branch->
quad[1]*xcm[1]*xcm[1]
1115 + 2*branch->
quad[2]*xcm[0]*xcm[1])/(rcm2cell*rcm2cell*rcm2cell)/PI*screening;
1117 alpha[0] += tmp*xcm[0];
1118 alpha[1] += tmp*xcm[1];
1120 *kappa -= inv_area * branch->mass;
1121 *phi -= 0.5*branch->mass*rcm2cell*inv_area;
1133template<
typename PType>
1139 if(tree->current->number == number){
1140 std::cout << tree->current->nparticles << std::endl;
1141 for(i=0;i<tree->current->nparticles;++i){
1142 std::cout << xxp[tree->current->particles[i]][0] <<
" "
1143 << xxp[tree->current->particles[i]][1] << std::endl;
1147 }
while(tree->WalkStep(
true));
1155template<
typename PType>
1161 std::cout << tree->current->boundary_p1[0] <<
" " << tree->current->boundary_p1[1] <<
" "
1162 << tree->current->boundary_p2[0] <<
" " << tree->current->boundary_p2[1] << std::endl;
1163 if(tree->current->level == level) decend =
false;
1165 }
while(tree->WalkStep(decend));