double OctTree_t::EvaluatePotential(const HBTReal targetPos[3], const HBTReal targetMass) /*return specific physical potential, GM/Rphysical. * targetPos[] is comoving. * if targetMass!=0, then the self-potential from targetMass is excluded. * do not set targetMass (i.e., keep to 0.) if target is outside the particlelist of tree*/ { OctTreeCell_t *nop = 0; HBTInt no; double r2, dx, dy, dz, mass, r, u, h, h_inv, wp; double pot, pos_x, pos_y, pos_z; pos_x = targetPos[0]; pos_y = targetPos[1]; pos_z = targetPos[2]; h = 2.8 * HBTConfig.SofteningHalo; h_inv = 1.0 / h; pot=targetMass/HBTConfig.SofteningHalo; //to cancle out the self-potential added during tree walk. no = NumberOfParticles;//start from root node while(no >= 0) { if(no < NumberOfParticles) /* single particle */ { dx = Snapshot->GetComovingPosition(no)[0] - pos_x; dy = Snapshot->GetComovingPosition(no)[1] - pos_y; dz = Snapshot->GetComovingPosition(no)[2] - pos_z; if(HBTConfig.PeriodicBoundaryOn) { dx=NEAREST(dx); dy=NEAREST(dy); dz=NEAREST(dz); } mass = Snapshot->GetMass(no); no = NextnodeFromParticle[no]; r2 = dx * dx + dy * dy + dz * dz; } else { nop = &Nodes[no]; dx = nop->way.s[0] - pos_x; dy = nop->way.s[1] - pos_y; dz = nop->way.s[2] - pos_z; if(HBTConfig.PeriodicBoundaryOn) { dx=NEAREST(dx); dy=NEAREST(dy); dz=NEAREST(dz); } mass = nop->way.mass; r2 = dx * dx + dy * dy + dz * dz; /* we have an internal node. Need to check opening criterion */ if((nop->way.len * nop->way.len )>( r2 * HBTConfig.TreeNodeOpenAngleSquare)) { /* open cell */ no = nop->way.nextnode; continue; } no = nop->way.sibling; /* node can be used */ } r = sqrt(r2); if(r >= h) pot -= mass / r; else { u = r * h_inv; if(u < 0.5) wp = -2.8 + u * u * (5.333333333333 + u * u * (6.4 * u - 9.6)); else wp = -3.2 + 0.066666666667 / u + u * u * (10.666666666667 + u * (-16.0 + u * (9.6 - 2.133333333333 * u))); pot += mass * h_inv * wp; } } return pot*PhysicalConst::G/Snapshot->ScaleFactor; }
HBTInt treesearch_infect_particles(HBTInt seed, HBTInt grpid, struct ParticleGroup *GrpTags, HBTReal PPos[][3]) { /*tag all the particles that are linked to seed with grpid * Note if system stack size is too small, this recursive routine may crash * in that case you should set: ulimit -s unlimited (bash) before running. **/ HBTInt numngb, totnumngb, no, p; double dx, dy, dz, r2, h2; union NODE *this; HBTReal *searchcenter; searchcenter=PPos[GrpTags[seed].PIndex]; //~ h2 = radius * radius; numngb = 0; no = NumPart; while(no >= 0)//infect neighbours { if(no < NumPart) /* single particle */ { *pInfected = no; no = Nextnode[*pInfected]; if(GrpTags[*pInfected].GrpID>=0) //already tagged continue; p = GrpTags[*pInfected].PIndex; dx = PPos[p][0] - searchcenter[0]; #ifdef PERIODIC_BDR dx=NEAREST(dx); #endif if(dx < -LinkLength) continue; if(dx > LinkLength) continue; dy =PPos[p][1] - searchcenter[1]; #ifdef PERIODIC_BDR dy=NEAREST(dy); #endif if(dy < -LinkLength) continue; if(dy > LinkLength) continue; dz = PPos[p][2] - searchcenter[2]; #ifdef PERIODIC_BDR dz=NEAREST(dz); #endif if(dz < -LinkLength) continue; if(dz > LinkLength) continue; r2 = dx * dx + dy * dy + dz * dz; if(r2 < LinkLength2) //confirm the infection (fill the stack) { GrpTags[*pInfected].GrpID=grpid; numngb++; pInfected++; } } else { this = &Nodes[no]; no = Nodes[no].way.sibling; /* in case the node can be discarded */ //since way.s[3] is CoM rather than center of cube,compare with Len rather than Lenhalf to allow for misaligned CoM if((NEAREST(this->way.s[0] - searchcenter[0]) + this->way.len) < -LinkLength) continue; if((NEAREST(this->way.s[0] - searchcenter[0]) - this->way.len) > LinkLength) continue; if((NEAREST(this->way.s[1] - searchcenter[1]) + this->way.len) < -LinkLength) continue; if((NEAREST(this->way.s[1] - searchcenter[1]) - this->way.len) > LinkLength) continue; if((NEAREST(this->way.s[2] - searchcenter[2]) + this->way.len) < -LinkLength) continue; if((NEAREST(this->way.s[2] - searchcenter[2]) - this->way.len) > LinkLength) continue; no = this->way.nextnode; /* ok, we need to open the node */ } } //~ printf("ngb=%d ",numngb); totnumngb=numngb; while(numngb>0)//pop the stack { pInfected--; totnumngb+=treesearch_infect_particles(*pInfected,grpid, GrpTags, PPos); numngb--; } return totnumngb; //total number of infected particles (excluding the seed particle) }
int ngb_treefind_variable(float searchcenter[3], float hguess) { int numngb, no, p; double dx, dy, dz, r2, h2; struct NODE *this; h2 = hguess * hguess; numngb = 0; no = NumPart; while(no >= 0) { if(no < NumPart) /* single particle */ { p = no; no = Nextnode[no]; dx = NEAREST(P[p].Pos[0] - searchcenter[0]); if(dx < -hguess) continue; if(dx > hguess) continue; dy = NEAREST(P[p].Pos[1] - searchcenter[1]); if(dy < -hguess) continue; if(dy > hguess) continue; dz = NEAREST(P[p].Pos[2] - searchcenter[2]); if(dz < -hguess) continue; if(dz > hguess) continue; r2 = dx * dx + dy * dy + dz * dz; if(r2 < h2) { R2list[numngb].r2 = r2; R2list[numngb].index = p; numngb++; } } else { this = &Nodes[no]; no = Nodes[no].u.d.sibling; /* in case the node can be discarded */ if((NEAREST(this->center[0] - searchcenter[0]) + 0.5 * this->len) < -hguess) continue; if((NEAREST(this->center[0] - searchcenter[0]) - 0.5 * this->len) > hguess) continue; if((NEAREST(this->center[1] - searchcenter[1]) + 0.5 * this->len) < -hguess) continue; if((NEAREST(this->center[1] - searchcenter[1]) - 0.5 * this->len) > hguess) continue; if((NEAREST(this->center[2] - searchcenter[2]) + 0.5 * this->len) < -hguess) continue; if((NEAREST(this->center[2] - searchcenter[2]) - 0.5 * this->len) > hguess) continue; no = this->u.d.nextnode; /* ok, we need to open the node */ } } /* printf("numngb=%d\n", numngb); */ return numngb; }
HBTInt treesearch_sphere(HBTReal searchcenter[3], HBTReal radius,HBTInt *PIndex,HBTReal PPos[][3]) {/*find a list of particles from PIndex within radius around searchcenter * return the number of neighbors * also store distance^2 and ID in the global variables NgbR2 and NgbID */ HBTInt numngb, no, p; double dx, dy, dz, r2, h2; union NODE *this; h2 = radius * radius; numngb = 0; no = NumPart; while(no >= 0) { if(no < NumPart) /* single particle */ { p = PIndex[no]; no = Nextnode[no]; dx = PPos[p][0] - searchcenter[0]; #ifdef PERIODIC_BDR dx=NEAREST(dx); #endif if(dx < -radius) continue; if(dx > radius) continue; dy =PPos[p][1] - searchcenter[1]; #ifdef PERIODIC_BDR dy=NEAREST(dy); #endif if(dy < -radius) continue; if(dy > radius) continue; dz = PPos[p][2] - searchcenter[2]; #ifdef PERIODIC_BDR dz=NEAREST(dz); #endif if(dz < -radius) continue; if(dz > radius) continue; r2 = dx * dx + dy * dy + dz * dz; if(r2 < h2) { NgbR2[numngb]= r2; NgbID[numngb]= p; numngb++; if(numngb==NgbNMax) { NgbNMax*=2; NgbR2=realloc(NgbR2,sizeof(HBTReal)*NgbNMax); NgbID=realloc(NgbID,sizeof(HBTInt)*NgbNMax); } } } else { this = &Nodes[no]; no = Nodes[no].way.sibling; /* in case the node can be discarded */ //since way.s[3] is CoM rather than center of cube,compare with Len rather than Lenhalf to allow for misaligned CoM if((NEAREST(this->way.s[0] - searchcenter[0]) + this->way.len) < -radius) continue; if((NEAREST(this->way.s[0] - searchcenter[0]) - this->way.len) > radius) continue; if((NEAREST(this->way.s[1] - searchcenter[1]) + this->way.len) < -radius) continue; if((NEAREST(this->way.s[1] - searchcenter[1]) - this->way.len) > radius) continue; if((NEAREST(this->way.s[2] - searchcenter[2]) + this->way.len) < -radius) continue; if((NEAREST(this->way.s[2] - searchcenter[2]) - this->way.len) > radius) continue; no = this->way.nextnode; /* ok, we need to open the node */ } } /* fprintf(Logfile,"numngb=%d\n", numngb); */ return numngb; }