GLAMERDOC++
Gravitational Lensing Code Library
quadTree.h
1 
7 //**********************************************************************************************************
8 /*
9  * quadTree.cpp
10  *
11  */
12 
13 /*
14  * Programmer: R Ben Metcalf
15  */
16 #ifndef QUAD_TREE_H_
17 #define QUAD_TREE_H_
18 
19 //#include "utilities_slsim.h"
20 //#include "utilities.h"
21 #include "Tree.h"
22 #include "qTreeNB.h"
23 
43 template<typename PType>
45 public:
47  PType *xpt
48  ,IndexType Npoints
49  ,float mass_fixed = -1
50  ,float size_fixed = -1
51  ,PosType my_inv_area = 0
52  ,int bucket = 5
53  ,PosType theta_force = 0.1
54  ,bool my_periodic_buffer = false
55  ,PosType my_inv_screening_scale = 0
56  ,PosType maximum_range = -1
57  );
58 
60 
61  void force2D(PosType const *ray,PosType *alpha,KappaType *kappa,KappaType *gamma
62  ,KappaType *phi) const;
63 
64  void force2D_recur(const PosType *ray,PosType *alpha,KappaType *kappa
65  ,KappaType *gamma,KappaType *phi);
66 
68  void neighbors(PosType ray[],PosType rmax,std::list<IndexType> &neighbors) const;
69  //void neighbors(PosType ray[],PosType rmax,std::vector<PType *> &neighbors) const;
70 
71  void printParticlesInBranch(unsigned long number);
72 
73  void printBranchs(int level = -1);
74 
75 protected:
76 
77  PType *xxp;
78  bool MultiMass;
79  double mass_fixed = 0.0;
80  bool MultiRadius;
81  double size_fixed = 0.0;
82  double inv_area;
83 
84  IndexType Nparticles;
85  //PosType sigma_background;
86  int Nbucket;
87 
88  PosType force_theta;
89  PosType max_range;
90 
91  std::unique_ptr<QTreeNB<PType> > tree;
92  std::vector<IndexType> index;
93  std::vector<PosType> workspace;
94 
95  PosType realray[2];
96  int incell,incell2;
97 
100  PosType inv_screening_scale2;
101  PosType original_xl; // x-axis size of simulation used for peridic buffering. Requrement that it top branch be square my make it differ from the size of top branch.
102  PosType original_yl; // x-axis size of simulation used for peridic buffering.
103 
104  //QTreeNB<PType> * BuildQTreeNB(PType *xp,IndexType Nparticles,IndexType *particles);
105  void BuildQTreeNB(PType *xp,IndexType Nparticles);
106  void _BuildQTreeNB(IndexType nparticles,IndexType *particles);
107 
108  inline short WhichQuad(PosType *x,QBranchNB &branch);
109 
110  //inline bool atLeaf();
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]);
113  }
114  //int cutbox(PosType *ray,PosType *p1,PosType *p2,float rmax);
115 
116  void CalcMoments();
117  void rotate_coordinates(PosType **coord);
118 
119  // Internal profiles for a Gaussian particle
120  inline PosType alpha_h(PosType r2s2,PosType sigma) const{
121  return (sigma > 0.0 ) ? ( exp(-0.5*r2s2) - 1.0 ) : -1.0;
122  }
123  inline PosType kappa_h(PosType r2s2,PosType sigma) const{
124  return 0.5*r2s2*exp(-0.5*r2s2);
125  }
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;
128  }
129  inline PosType phi_h(PosType r2s2,PosType sigma) const{
130  //ERROR_MESSAGE(); // not yet written
131  //exit(1);
132  return 0;
133  }
134 
135 
136  /* cubic B-spline kernel for particle profile
137 
138  The lensing quantities are added to and a point mass is subtracted
139  */
140  inline void b_spline_profile(
141  PosType *xcm // vector in Mpc connecting ray to center of particle
142  ,PosType r // distance from center in Mpc
143  ,PosType Mass // mass in solar masses
144  ,PosType size // size scale in Mpc
145  ,PosType *alpha // deflection angle times Sigma_crit
146  ,KappaType *kappa // surface density
147  ,KappaType *gamma // shear times Sigma_crit
148  ,KappaType *phi
149  ) const {
150 
151  PosType q = r/size;
152  PosType M,sigma;
153  if(q > 2){
154  sigma = 0;
155  M = 1;
156  }else{
157  PosType q2=q*q,q3=q2*q,q4=q2*q2,q5=q4*q;
158 
159  sigma = (8 - 12*q + 6*q2 - q3)/4;
160  if(q > 1){
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;
164  }else{
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;
167 
168  *phi += Mass*( phiintconst + 10*(q2/2 - 3*q4/4 + 3*q5/50)/7
169  )/PI;
170  }
171  }
172 
173  // deflection * Sig_crit / Mass
174  PosType alpha_r = (M-1)/PI/r;
175  PosType gt = alpha_r/r - sigma;
176 
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;
183  }
184 
185  /* Exponential kernel for particle profile
186 
187  The lensing quantities are added to and a point mass is subtracted
188  */
189  inline void exponential_profile(
190  PosType *xcm
191  ,PosType rcm2 // distance from center in Mpc
192  ,PosType Mass
193  ,PosType size // size scale in Mpc
194  ,PosType *alpha
195  ,KappaType *kappa
196  ,KappaType *gamma
197  ,KappaType *phi
198  ) const {
199 
200 
201  PosType prefac = Mass/rcm2/PI;
202  PosType arg1 = rcm2/(size*size);
203 
204  PosType tmp = (alpha_h(arg1,size) + 1.0)*prefac;
205  alpha[0] += tmp*xcm[0];
206  alpha[1] += tmp*xcm[1];
207 
208  *kappa += kappa_h(arg1,size)*prefac;
209 
210  tmp = (gamma_h(arg1,size) + 2.0)*prefac/rcm2;
211 
212  gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
213  gamma[1] += xcm[0]*xcm[1]*tmp;
214 
215  // TODO: makes sure the normalization of phi_h agrees with this
216  //*phi += (phi_h(arg1,size) + 0.5*log(rcm2))*prefac*rcm2;
217  }
218 
219  //QTreeNB<PType> * rotate_simulation(PType *xp,IndexType Nparticles,IndexType *particles
220  // ,PosType **coord,PosType theta,float *rsph,float *mass
221  // ,bool MultiRadius,bool MultiMass);
222  //QTreeNB<PType> * rotate_project(PType *xp,IndexType Nparticles,IndexType *particles
223  // ,PosType **coord,PosType theta,float *rsph,float *mass
224  // ,bool MultiRadius,bool MultiMass);
225  void cuttoffscale(QTreeNB<PType> * tree,PosType *theta);
226 
227  void walkTree_recur(QBranchNB *branch,PosType const *ray,PosType *alpha,KappaType *kappa,KappaType *gamma,KappaType *phi);
228 
229  void walkTree_iter(QBiterator<PType> &treeit, PosType const *ray,PosType *alpha,KappaType *kappa
230  ,KappaType *gamma,KappaType *phi) const;
231 
232  PosType phiintconst;
233 };
234 
237 template<typename PType>
239  PType *xpt
240  ,IndexType Npoints
241  ,float mass_fixed
242  ,float size_fixed
243  ,PosType my_inv_area
244  ,int bucket
245  ,PosType theta_force
246  ,bool my_periodic_buffer
247  ,PosType my_inv_screening_scale
248  ,PosType maximum_range
249 
250 ):
251 xxp(xpt)
252 ,inv_area(my_inv_area)
253 ,Nparticles(Npoints)
254 ,Nbucket(bucket)
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)
259 {
260  index.resize(Npoints);
261  IndexType ii;
262  if(mass_fixed <= 0 ) MultiMass = true; else MultiMass = false;
263  if(size_fixed <= 0 ) MultiRadius = true; else MultiRadius = false;
264 
265  for(ii=0;ii<Npoints;++ii) index[ii] = ii;
266 
267  if(Npoints > 0){
268  BuildQTreeNB(xxp,Npoints);
269  CalcMoments();
270  }
271 
272  phiintconst = (120*log(2.) - 631.)/840 + 19./70;
273 
274  return;
275 }
276 
278 template<typename PType>
280 {
281  if(Nparticles == 0) return;
282  return;
283 }
284 
285 template<typename PType>
286 //QTreeNB<PType> * TreeQuadParticles<PType>::BuildQTreeNB(PType *xxp,IndexType Nparticles,IndexType *particles){
287 void TreeQuadParticles<PType>::BuildQTreeNB(PType *xxp,IndexType Nparticles){
288  IndexType i;
289  short j;
290  PosType p1[2],p2[2];
291 
292  for(j=0;j<2;++j){
293  p1[j]=xxp[0][j];
294  p2[j]=xxp[0][j];
295  }
296 
297  // Find borders that enclose all particles
298  for(i=0;i<Nparticles;++i){
299  for(j=0;j<2;++j){
300  if(xxp[i][j] < p1[j] ) p1[j]=xxp[i][j];
301  if(xxp[i][j] > p2[j] ) p2[j]=xxp[i][j];
302  }
303  }
304 
305  if(Nparticles == 1){
306  p1[0]=-0.25;
307  p1[1]=-0.25;
308  p2[0]=0.25;
309  p2[1]=0.25;
310  }
311 
312  // store true dimensions of simulation
313  PosType lengths[2] = {p2[0]-p1[0],p2[1]-p1[1]};
314  original_xl = lengths[0];
315  original_yl = lengths[1];
316 
317  if(lengths[0] == 0 || lengths[1] == 0){
318  throw std::invalid_argument("particles in same place.");
319  }
320 
321  // If region is not square, make it square.
322  j = lengths[0] > lengths[1] ? 1 : 0;
323  p2[j] = p1[j] + lengths[!j];
324 
325  /* Initialize tree root */
326  //tree = new QTreeNB<PType>(xxp,particles,Nparticles,p1,p2);
327  tree.reset( new QTreeNB<PType>(xxp,index.data(),Nparticles,p1,p2) );
328 
329  /* build the tree */
330  workspace.resize(Nparticles);
331  _BuildQTreeNB(Nparticles,index.data());
332  workspace.clear();
333  workspace.shrink_to_fit();
334 
335  /* visit every branch to find center of mass and cutoff scale */
336  tree->moveTop();
337 
338  return;
339 }
340 
342 template<typename PType>
343 inline short TreeQuadParticles<PType>::WhichQuad(PosType *x,QBranchNB &branch){
344  return (x[0] < branch.center[0]) + 2*(x[1] < branch.center[1]);
345 }
346 
348 template<typename PType>
349 void TreeQuadParticles<PType>::_BuildQTreeNB(IndexType nparticles,IndexType *particles){
350 
351  QBranchNB *cbranch = tree->current; // pointer to current branch
352  IndexType i,j,cut,cut2;
353 
354  cbranch->center[0] = (cbranch->boundary_p1[0] + cbranch->boundary_p2[0])/2;
355  cbranch->center[1] = (cbranch->boundary_p1[1] + cbranch->boundary_p2[1])/2;
356  cbranch->quad[0] = cbranch->quad[1]=cbranch->quad[2]=0;
357  cbranch->mass = 0.0;
358 
359  double theta_range = 2*force_theta;
360  if(max_range > 0){
361  double boxsize = 1.732*(cbranch->boundary_p2[0] - cbranch->boundary_p1[0]);
362  theta_range = boxsize / MAX(sqrt(cbranch->center[0]*cbranch->center[0]
363  + cbranch->center[1]*cbranch->center[1] )
364  - max_range, boxsize );
365  }
366 
367  // leaf case
368  if(cbranch->nparticles <= Nbucket
369  || force_theta > theta_range
370  ){
371  PosType r;
372  cbranch->Nbig_particles = 0;
373  PosType boxsize = cbranch->boundary_p2[0] - cbranch->boundary_p1[0];
374  for(i=0;i<cbranch->nparticles;++i){
375  r = xxp[particles[i]*MultiRadius].size();
376  if(r < boxsize) ++cbranch->Nbig_particles;
377  }
378  if(cbranch->Nbig_particles){
379  //cbranch->big_particles = new IndexType[cbranch->Nbig_particles];
380  cbranch->big_particles.reset(new IndexType[cbranch->Nbig_particles]);
381 
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];
385  }
386  }else{
387  cbranch->big_particles.reset(nullptr);
388  }
389 
390  return;
391  }
392 
393  // find particles too big to be in children
394 
395  //PosType *x = new PosType[cbranch->nparticles];
396  PosType *x = workspace.data();
397 
398  cbranch->Nbig_particles=0;
399 
400  if(MultiRadius){
401  // store the particles that are too large to be in a child at the end of the list of particles in cbranch
402  for(i=0;i<cbranch->nparticles;++i){
403  x[i] = xxp[particles[i]].size();
404  }
405  PosType maxsize = (cbranch->boundary_p2[0]-cbranch->boundary_p1[0])/2;
406 
407  // sort particles in size
408  //quicksort(particles,x,cbranch->nparticles);
409  Utilities::quickPartition(maxsize,&cut,particles,x,cbranch->nparticles);
410 
411  if(cut < cbranch->nparticles){
412  if(tree->atTop()){
413  cbranch->Nbig_particles = cut2 = cbranch->nparticles-cut;
414  }else{
415  Utilities::quickPartition(2*maxsize,&cut2,&particles[cut],&x[cut],cbranch->nparticles-cut);
416  cbranch->Nbig_particles = cut2;
417  }
418 
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];
421  }
422 
423  }else{
424  //x[0] = xxp[0].Size();
425  x[0] = size_fixed;
426  if(x[0] > (cbranch->boundary_p2[0]-cbranch->boundary_p1[0])/2
427  && x[0] < (cbranch->boundary_p2[0]-cbranch->boundary_p1[0])){
428  cbranch->Nbig_particles = cbranch->nparticles;
429  //cbranch->big_particles = cbranch->particles;
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]];
432  }
433  }
434 
435  assert( cbranch->nparticles >= cbranch->Nbig_particles );
436  IndexType NpInChildren = cbranch->nparticles;// - cbranch->Nbig_particles;
437  assert(NpInChildren >= 0);
438 
439  if(NpInChildren == 0){
440  //delete[] x;
441  return;
442  }
443 
444  IndexType cutx,cuty;
445  PosType xcut,ycut;
446 
447  QBranchNB *child0 = new QBranchNB(cbranch);
448  QBranchNB *child1 = new QBranchNB(cbranch);
449  QBranchNB *child2 = new QBranchNB(cbranch);
450  QBranchNB *child3 = new QBranchNB(cbranch);
451 
452  tree->attachChildrenToCurrent(child0,child1,child2,child3);
453 
454  // initialize boundaries of children
455 
456  child0->boundary_p1[0]=cbranch->center[0];
457  child0->boundary_p1[1]=cbranch->center[1];
458  child0->boundary_p2[0]=cbranch->boundary_p2[0];
459  child0->boundary_p2[1]=cbranch->boundary_p2[1];
460 
461  child1->boundary_p1[0]=cbranch->boundary_p1[0];
462  child1->boundary_p1[1]=cbranch->center[1];
463  child1->boundary_p2[0]=cbranch->center[0];
464  child1->boundary_p2[1]=cbranch->boundary_p2[1];
465 
466  child2->boundary_p1[0]=cbranch->center[0];
467  child2->boundary_p1[1]=cbranch->boundary_p1[1];
468  child2->boundary_p2[0]=cbranch->boundary_p2[0];
469  child2->boundary_p2[1]=cbranch->center[1];
470 
471  child3->boundary_p1[0]=cbranch->boundary_p1[0];
472  child3->boundary_p1[1]=cbranch->boundary_p1[1];
473  child3->boundary_p2[0]=cbranch->center[0];
474  child3->boundary_p2[1]=cbranch->center[1];
475 
476 
477  // **** makes sure force does not require nbucket at leaf
478 
479  xcut = cbranch->center[0];
480  ycut = cbranch->center[1];
481 
482  // divide along y direction
483  for(i=0;i<NpInChildren;++i) x[i] = tree->xxp[particles[i]][1];
484  Utilities::quickPartition(ycut,&cuty,particles,x,NpInChildren);
485 
486  if(cuty > 0){
487  // divide first group in the x direction
488  for(i=0;i<cuty;++i) x[i] = tree->xxp[particles[i]][0];
489  Utilities::quickPartition(xcut,&cutx,particles,x,cuty);
490 
491  child3->nparticles=cutx;
492  assert(child3->nparticles >= 0);
493  if(child3->nparticles > 0)
494  child3->particles = particles;
495  else child3->particles = NULL;
496 
497  child2->nparticles = cuty - cutx;
498  assert(child2->nparticles >= 0);
499  if(child2->nparticles > 0)
500  child2->particles = &particles[cutx];
501  else child2->particles = NULL;
502 
503  }else{
504  child3->nparticles = 0;
505  child3->particles = NULL;
506 
507  child2->nparticles = 0;
508  child2->particles = NULL;
509  }
510 
511  if(cuty < NpInChildren){
512  // divide second group in the x direction
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);
515 
516  child1->nparticles=cutx;
517  assert(child1->nparticles >= 0);
518  if(child1->nparticles > 0)
519  child1->particles = &particles[cuty];
520  else child1->particles = NULL;
521 
522  child0->nparticles=NpInChildren - cuty - cutx;
523  assert(child0->nparticles >= 0);
524  if(child0->nparticles > 0)
525  child0->particles = &particles[cuty + cutx];
526  else child0->particles = NULL;
527 
528  }else{
529  child1->nparticles = 0;
530  child1->particles = NULL;
531 
532  child0->nparticles = 0;
533  child0->particles = NULL;
534  }
535 
536  //delete[] x;
537 
538  tree->moveToChild(0);
539  _BuildQTreeNB(child0->nparticles,child0->particles);
540  tree->moveUp();
541 
542  tree->moveToChild(1);
543  _BuildQTreeNB(child1->nparticles,child1->particles);
544  tree->moveUp();
545 
546  tree->moveToChild(2);
547  _BuildQTreeNB(child2->nparticles,child2->particles);
548  tree->moveUp();
549 
550  tree->moveToChild(3);
551  _BuildQTreeNB(child3->nparticles,child3->particles);
552  tree->moveUp();
553 
554  return;
555 }
556 
557 // calculates moments of the mass and the cutoff scale for each box
558 template<typename PType>
560 
561  //*** make compatable
562  IndexType i;
563  PosType rcom,xcm[2],xcut;
564  QBranchNB *cbranch;
565  PosType tmp;
566  double absmass; // absolute magnitude of mass
567 
568  tree->moveTop();
569  do{
570  cbranch=tree->current; /* pointer to current branch */
571 
572  cbranch->rmax = sqrt( pow(cbranch->boundary_p2[0]-cbranch->boundary_p1[0],2)
573  + pow(cbranch->boundary_p2[1]-cbranch->boundary_p1[1],2) );
574 
575  // calculate mass
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());
579  }
580  // calculate center of mass
581  cbranch->center[0]=cbranch->center[1]=0;
582  for(i=0;i<cbranch->nparticles;++i){
583  tmp = fabs(xxp[cbranch->particles[i]*MultiMass].mass());
584 
585  //tmp = haloON ? halos[cbranch->particles[i]*MultiMass].mass : masses[cbranch->particles[i]*MultiMass];
586  cbranch->center[0] += tmp*tree->xxp[cbranch->particles[i]][0]/absmass;
587  cbranch->center[1] += tmp*tree->xxp[cbranch->particles[i]][1]/absmass;
588  }
590  // calculate quadropole moment of branch
592  cbranch->quad[0]=cbranch->quad[1]=cbranch->quad[2]=0;
593  for(i=0;i<cbranch->nparticles;++i){
594  xcm[0]=tree->xxp[cbranch->particles[i]][0]-cbranch->center[0];
595  xcm[1]=tree->xxp[cbranch->particles[i]][1]-cbranch->center[1];
596  xcut = pow(xcm[0],2) + pow(xcm[1],2);
597  tmp = xxp[cbranch->particles[i]*MultiMass].mass();
598 
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;
602  }
603 
604  // largest distance from center of mass of cell
605  for(i=0,rcom=0.0;i<2;++i) rcom += ( pow(cbranch->center[i]-cbranch->boundary_p1[i],2) > pow(cbranch->center[i]-cbranch->boundary_p2[i],2) ) ?
606  pow(cbranch->center[i]-cbranch->boundary_p1[i],2) : pow(cbranch->center[i]-cbranch->boundary_p2[i],2);
607 
608  rcom=sqrt(rcom);
609 
610  if(force_theta > 0.0){
611  cbranch->r2crit_angle = 1.15470*rcom/(force_theta);
612  cbranch->r2crit_angle *= cbranch->r2crit_angle;
613  }else cbranch->r2crit_angle=1.0e100;
614 
615  }while(tree->WalkStep(true));
616 
617  return;
618 }
619 
621 template<typename PType>
623  IndexType i;
624  short j;
625  PosType tmp[3];
626 
627  /* rotate particle positions */
628  for(i=0;i<tree->top->nparticles;++i){
629  for(j=0;j<3;++j) tmp[j]=0.0;
630  for(j=0;j<3;++j){
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];
634  }
635  for(j=0;j<3;++j) xxp[i][j]=tmp[j];
636  }
637  return;
638 }
639 
662 template<typename PType>
663 void TreeQuadParticles<PType>::force2D(const PosType *ray,PosType *alpha,KappaType *kappa,KappaType *gamma,KappaType *phi) const{
664 
665  alpha[0]=alpha[1]=gamma[0]=gamma[1]=gamma[2]=0.0;
666  *kappa=*phi=0.0;
667 
668  if(Nparticles == 0) return;
669 
670  assert(tree);
671  QBiterator<PType> it(tree);
672 
673  if(periodic_buffer){
674  PosType tmp_ray[2];
675 
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);
681  }
682  }
683  }else{
684  walkTree_iter(it,ray,alpha,kappa,gamma,phi);
685  }
686 
687  // Subtract off uniform mass sheet to compensate for the extra mass
688  // added to the universe in the halos.
689  //alpha[0] -= ray[0]*sigma_background*(inv_screening_scale2 == 0);
690  //alpha[1] -= ray[1]*sigma_background*(inv_screening_scale2 == 0);
691  //*kappa -= sigma_background;
692 
693  return;
694 }
695 
698 template<typename PType>
699 void TreeQuadParticles<PType>::neighbors(PosType ray[],PosType rmax,std::list<IndexType> &neighbors) const{
700  QBiterator<PType> it(tree);
701  neighbors.clear();
702 
703  PosType r2 = rmax*rmax;
704  bool decend=true;
705  it.movetop();
706  do{
707  int cut = Utilities::cutbox(ray,(*it)->boundary_p1,(*it)->boundary_p2,rmax);
708  decend = true;
709 
710  if(cut == 0){ // box outside circle
711  decend = false;
712  }else if(cut == 1){ // whole box inside circle
713  for(int i=0;i<(*it)->nparticles;++i) neighbors.push_back((*it)->particles[i]);
714  decend = false;
715  }else if((*it)->child0 == NULL){ // at leaf
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]);
719  }
720  decend = false;
721  }
722  }while(it.TreeWalkStep(decend));
723 
724 }
725 
726 template<typename PType>
728  QBiterator<PType> &treeit,
729  const PosType *ray
730  ,PosType *alpha
731  ,KappaType *kappa
732  ,KappaType *gamma
733  ,KappaType *phi
734  ) const {
735 
736  PosType xcm[2],rcm2cell,rcm2,tmp,boxarea;
737  IndexType i;
738  bool allowDescent=true;
739  unsigned long count=0,tmp_index;
740  PosType prefac;
741  //bool notscreen = true;
742 
743  assert(tree);
744 
745  treeit.movetop();
746  //tree->moveTop();
747  do{
748  ++count;
749  allowDescent=false;
750 
751  /*
752  if(inv_screening_scale2 != 0) notscreen = BoxIntersectCircle(ray,3*sqrt(1.0/inv_screening_scale2)
753  ,(*treeit)->boundary_p1
754  ,(*treeit)->boundary_p2);
755  else notscreen = true;
756  */
757  //if(tree->current->nparticles > 0)
758  if((*treeit)->nparticles > 0)
759  {
760 
761  xcm[0]=(*treeit)->center[0]-ray[0];
762  xcm[1]=(*treeit)->center[1]-ray[1];
763 
764  rcm2cell = xcm[0]*xcm[0] + xcm[1]*xcm[1];
765 
766  boxarea = ((*treeit)->boundary_p2[0]-(*treeit)->boundary_p1[0])*((*treeit)->boundary_p2[0]-(*treeit)->boundary_p1[0]);
767 
768  if( rcm2cell < ((*treeit)->rcrit_angle)*((*treeit)->rcrit_angle) || rcm2cell < 5.83*boxarea)
769  {
770 
771  // includes rcrit_particle constraint
772  allowDescent=true;
773 
774 
775  // Treat all particles in a leaf as a point particle
776  if(treeit.atLeaf())
777  {
778 
779  for(i = 0 ; i < (*treeit)->nparticles ; ++i)
780  {
781 
782  xcm[0] = tree->xp[(*treeit)->particles[i]][0] - ray[0];
783  xcm[1] = tree->xp[(*treeit)->particles[i]][1] - ray[1];
784 
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;
788 
789  //tmp_index = MultiMass*(*treeit)->particles[i];
790 
791  //if(haloON){ prefac = halos[tmp_index]->get_mass(); }
792  //else{ prefac = masses[tmp_index]; }
793 
794  double mass;
795  if(MultiMass) mass = xxp[(*treeit)->particles[i]].Mass();
796  else mass = mass_fixed;
797 
798  prefac = mass/rcm2/PI*screening;
799  tmp = -mass*( screening/rcm2/PI - inv_area);
800 
801  alpha[0] += tmp*xcm[0];
802  alpha[1] += tmp*xcm[1];
803 
804  tmp = -2.0*prefac/rcm2;
805 
806  gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
807  gamma[1] += xcm[0]*xcm[1]*tmp;
808 
809  *kappa -= mass*inv_area;
810  *phi += (prefac*log(rcm2) - mass*inv_area)*rcm2*0.5;
811 
812  } // end of for
813  } // end of if(tree->atLeaf())
814 
815 
816  // Find the particles that intersect with ray and add them individually.
817  if(rcm2cell < 5.83*boxarea)
818  {
819 
820  for(i = 0 ; i < (*treeit)->Nbig_particles ; ++i)
821  {
822 
823  tmp_index = (*treeit)->big_particles[i];
824 
825  xcm[0] = tree->xp[tmp_index][0] - ray[0];
826  xcm[1] = tree->xp[tmp_index][1] - ray[1];
827 
828  rcm2 = xcm[0]*xcm[0] + xcm[1]*xcm[1];
829 
830  if(rcm2 < 1e-20) rcm2 = 1e-20;
831 
832  //PosType size = sizes[tmp_index*MultiRadius];
833  PosType size = xxp[tmp_index*MultiRadius].size();
834 
835  // intersecting, subtract the point particle
836  if(rcm2 < 4*size*size)
837  {
838  b_spline_profile(xcm,sqrt(rcm2),xxp[MultiMass*tmp_index].Mass(),size,alpha,kappa,gamma,phi);
839  }
840 
841  }
842  }
843 
844  }
845  else
846  { // use whole cell
847 
848  allowDescent=false;
849 
850  // monopole
851  double screening = exp(-rcm2cell*inv_screening_scale2);
852  //double tmp = -1.0*(*treeit)->mass/rcm2cell/PI*screening;
853  double tmp = (*treeit)->mass*( inv_area - screening/rcm2cell/PI );
854 
855  alpha[0] += tmp*xcm[0];
856  alpha[1] += tmp*xcm[1];
857 
858  { // taken out to speed up
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;
862 
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;
865  }
866 
867  // quadrapole contribution
868  // the kappa and gamma are not calculated to this order
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;
873 
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;
876 
877  alpha[0] += tmp*xcm[0];
878  alpha[1] += tmp*xcm[1];
879 
880  *kappa -= (*treeit)->mass * inv_area;
881  *phi -= 0.5*(*treeit)->mass*inv_area;
882  }
883  }
884  }while(treeit.TreeWalkStep(allowDescent));
885 
886 
887  // Subtract off uniform mass sheet to compensate for the extra mass
888  // added to the universe in the halos.
889  //alpha[0] -= ray[0]*sigma_background*(inv_screening_scale2 == 0.0);
890  //alpha[1] -= ray[1]*sigma_background*(inv_screening_scale2 == 0.0);
891  //{ // taken out to speed up
892  // *kappa -= sigma_background;
893  // // *phi -= sigma_background * sigma_background ;
894  //}
895 
896  return;
897 }
898 
899 
924 template<typename PType>
925 void TreeQuadParticles<PType>::force2D_recur(const PosType *ray,PosType *alpha,KappaType *kappa,KappaType *gamma,KappaType *phi){
926 
927 
928  alpha[0]=alpha[1]=gamma[0]=gamma[1]=gamma[2]=0.0;
929  *kappa=*phi=0.0;
930 
931  if(Nparticles == 0) return;
932  assert(tree);
933 
934  //walkTree_recur(tree->top,ray,&alpha[0],kappa,&gamma[0],phi);
935 
936  if(periodic_buffer){
937  PosType tmp_ray[2],tmp_c[2];
938 
939  // for points outside of primary zone shift to primary zone
940  //if(inbox(ray,tree->top->boundary_p1,tree->top->boundary_p2)){
941  tmp_c[0] = ray[0];
942  tmp_c[1] = ray[1];
943  /*}else{
944  int di[2];
945  PosType center[2] = { (tree->top->boundary_p1[0] + tree->top->boundary_p2[0])/2 ,
946  (tree->top->boundary_p1[1] + tree->top->boundary_p2[1])/2 };
947 
948  di[0] = (int)( 2*(ray[0] - center[0])/lx );
949  di[1] = (int)( 2*(ray[1] - center[1])/ly );
950 
951  di[0] = (di[0] > 0) ? (di[0] + 1)/2 : (di[0] - 1)/2;
952  di[1] = (di[1] > 0) ? (di[1] + 1)/2 : (di[1] - 1)/2;
953 
954  tmp_c[0] = ray[0] - lx * di[0];
955  tmp_c[1] = ray[1] - ly * di[1];
956 
957  assert(inbox(tmp_c,tree->top->boundary_p1,tree->top->boundary_p2));
958  }*/
959 
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);
965  }
966  }
967  }else{
968  walkTree_recur(tree->top,ray,alpha,kappa,gamma,phi);
969  }
970 
971  // Subtract off uniform mass sheet to compensate for the extra mass
972  // added to the universe in the halos.
973  //alpha[0] -= ray[0]*sigma_background*(inv_screening_scale2 == 0);
974  //alpha[1] -= ray[1]*sigma_background*(inv_screening_scale2 == 0);
975 
976  //*kappa -= sigma_background;
977 
978  return;
979 }
980 
981 
982 template<typename PType>
983 void TreeQuadParticles<PType>::walkTree_recur(QBranchNB *branch,PosType const *ray,PosType *alpha,KappaType *kappa,KappaType *gamma, KappaType *phi){
984 
985  PosType xcm[2],rcm2cell,rcm2,tmp,boxsize2;
986  IndexType i;
987  std::size_t tmp_index;
988  PosType prefac;
989  /*bool notscreen = true;
990 
991  if(inv_screening_scale2 != 0) notscreen = BoxIntersectCircle(ray,3*sqrt(1.0/inv_screening_scale2), branch->boundary_p1, branch->boundary_p2);
992  */
993  if(branch->nparticles > 0)
994  {
995  xcm[0]=branch->center[0]-ray[0];
996  xcm[1]=branch->center[1]-ray[1];
997 
998  rcm2cell = xcm[0]*xcm[0] + xcm[1]*xcm[1];
999 
1000  boxsize2 = (branch->boundary_p2[0]-branch->boundary_p1[0])*(branch->boundary_p2[0]-branch->boundary_p1[0]);
1001 
1002  if( rcm2cell < branch->r2crit_angle || rcm2cell < 5.83*boxsize2)
1003  {
1004 
1005  // Treat all particles in a leaf as a point particle
1006  if(tree->atLeaf(branch))
1007  {
1008 
1009  for(i = 0 ; i < branch->nparticles ; ++i){
1010 
1011  xcm[0] = tree->xxp[branch->particles[i]][0] - ray[0];
1012  xcm[1] = tree->xxp[branch->particles[i]][1] - ray[1];
1013 
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;
1017 
1018  tmp_index = MultiMass*branch->particles[i];
1019 
1020  //if(haloON ) { prefac = halos[tmp_index]->get_mass(); }
1021  //else{ prefac = masses[tmp_index]; }
1022  double mass = xxp[tmp_index].mass();
1023  prefac = mass*screening/rcm2/PI;
1024  //prefac /= rcm2*PI/screening;
1025 
1026 
1027  alpha[0] += (inv_area*mass - prefac)*xcm[0];
1028  alpha[1] += (inv_area*mass - prefac)*xcm[1];
1029 
1030  {
1031  tmp = -2.0*prefac/rcm2;
1032 
1033  gamma[0] += 0.5*(xcm[0]*xcm[0]-xcm[1]*xcm[1])*tmp;
1034  gamma[1] += xcm[0]*xcm[1]*tmp;
1035 
1036  *kappa -= mass*inv_area;
1037  *phi += prefac*rcm2*0.5*log(rcm2) - mass*inv_area*rcm2/2;
1038  }
1039  }
1040  }
1041 
1042  // Find the particles that intersect with ray and add them individually.
1043  if(rcm2cell < 5.83*boxsize2)
1044  {
1045 
1046  for(i = 0 ; i < branch->Nbig_particles ; ++i)
1047  {
1048 
1049  tmp_index = branch->big_particles[i];
1050 
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];
1054 
1056  if(rcm2 < 1e-20) rcm2 = 1e-20;
1057 
1058  PosType size = xxp[tmp_index*MultiRadius].size();
1059 
1060  // intersecting, subtract the point particle
1061  if(rcm2 < 4*size*size)
1062  {
1063 
1064  b_spline_profile(xcm,sqrt(rcm2),xxp[MultiMass*tmp_index].mass(),size,alpha,kappa,gamma,phi);
1065 
1066  }
1067 
1068  }
1069  }
1070 
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]);
1079 
1080  }
1081  else
1082  { // use whole cell
1083 
1084  double screening = exp(-rcm2cell*inv_screening_scale2);
1085  double tmp = branch->mass*inv_area - branch->mass/rcm2cell/PI*screening;
1086 
1087  alpha[0] += tmp*xcm[0];
1088  alpha[1] += tmp*xcm[1];
1089 
1090  { // taken out to speed up
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;
1094 
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;
1097  }
1098 
1099  // quadrapole contribution
1100  // the kappa and gamma are not calculated to this order
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;
1105 
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;
1108 
1109  alpha[0] += tmp*xcm[0];
1110  alpha[1] += tmp*xcm[1];
1111 
1112  *kappa -= inv_area * branch->mass;
1113  *phi -= 0.5*branch->mass*rcm2cell*inv_area;
1114 
1115  return;
1116  }
1117 
1118  }
1119  return;
1120 }
1121 
1125 template<typename PType>
1126 void TreeQuadParticles<PType>::printParticlesInBranch(unsigned long number){
1127  unsigned long i;
1128 
1129  tree->moveTop();
1130  do{
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;
1136  }
1137  return;
1138  }
1139  }while(tree->WalkStep(true));
1140 
1141  return;
1142 }
1147 template<typename PType>
1149 
1150  bool decend = true;
1151  tree->moveTop();
1152  do{
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;
1156  else decend = true;
1157  }while(tree->WalkStep(decend));
1158 
1159  return;
1160 };
1161 
1162 #endif /* QUAD_TREE_H_ */
TreeQuadParticles::TreeQuadParticles
TreeQuadParticles(PType *xpt, IndexType Npoints, float mass_fixed=-1, float size_fixed=-1, PosType my_inv_area=0, int bucket=5, PosType theta_force=0.1, bool my_periodic_buffer=false, PosType my_inv_screening_scale=0, PosType maximum_range=-1)
Constructor meant for point particles, simulation particles.
Definition: quadTree.h:238
TreeQuadParticles::WhichQuad
short WhichQuad(PosType *x, QBranchNB &branch)
returns an index for which of the four quadrangles of the branch the point x[] is in
Definition: quadTree.h:343
TreeQuadParticles
TreeQuadParticles is a class for calculating the deflection, kappa and gamma by tree method.
Definition: quadTree.h:44
TreeQuadParticles::periodic_buffer
bool periodic_buffer
if true there is one layer of peridic buffering
Definition: quadTree.h:99
QBranchNB::Nbig_particles
IndexType Nbig_particles
the number of particles that aren't in children
Definition: qTreeNB.h:52
QBranchNB::rmax
PosType rmax
largest dimension of box
Definition: qTreeNB.h:82
TreeQuadParticles::~TreeQuadParticles
~TreeQuadParticles()
Particle positions and other data are not destroyed.
Definition: quadTree.h:279
QBiterator
A iterator class fore TreeStruct that allows for movement through the tree without changing anything ...
Definition: qTreeNB.h:173
QBranchNB::particles
IndexType * particles
array of particles in QBranchNB
Definition: qTreeNB.h:45
QBranchNB::boundary_p1
PosType boundary_p1[2]
bottom, left, back corner of box
Definition: qTreeNB.h:62
QBranchNB::r2crit_angle
PosType r2crit_angle
the critical distance below which a branch is opened in the
Definition: qTreeNB.h:84
TreeQuadParticles::neighbors
void neighbors(PosType ray[], PosType rmax, std::list< IndexType > &neighbors) const
find all points within rmax of ray in 2D
QBranchNB::quad
PosType quad[3]
quadropole moment of branch
Definition: qTreeNB.h:80
QBranchNB
Box representing a branch in a tree. It has four children. Used in QTreeNB which is used in TreeQuad.
Definition: qTreeNB.h:31
TreeQuadParticles::_BuildQTreeNB
void _BuildQTreeNB(IndexType nparticles, IndexType *particles)
tree must be created and first branch must be set before start
Definition: quadTree.h:349
QBranchNB::center
PosType center[2]
center of mass
Definition: qTreeNB.h:56
QBranchNB::boundary_p2
PosType boundary_p2[2]
top, right, front corner of box
Definition: qTreeNB.h:64
TreeQuadParticles::rotate_coordinates
void rotate_coordinates(PosType **coord)
simple rotates the coordinates in the xp array
Definition: quadTree.h:622
QTreeNB
QTreeNB: Tree structure used for force calculation with particles (i.e. stars, Nbody or halos).
Definition: qTreeNB.h:98