void snapstack(bodyptr btab, bodyptr bt1, int nb1, bodyptr bt2, int nb2, string *tags) { vector deltar, deltav; bodyptr bp; int i; setvect(deltar, burststring(getparam("deltar"), ", ")); setvect(deltav, burststring(getparam("deltav"), ", ")); for (i = 0; i < nb1; i++) { bp = NthBody(btab, i); memcpy(bp, NthBody(bt1, i), SizeofBody); if (set_member(tags, PosTag)) { ADDMULVS(Pos(bp), deltar, 0.5); } if (set_member(tags, VelTag)) { ADDMULVS(Vel(bp), deltav, 0.5); } } for (i = 0; i < nb2; i++) { bp = NthBody(btab, i + nb1); memcpy(bp, NthBody(bt2, i), SizeofBody); if (set_member(tags, PosTag)) { ADDMULVS(Pos(bp), deltar, -0.5); } if (set_member(tags, VelTag)) { ADDMULVS(Vel(bp), deltav, -0.5); } } }
void calculateCenterOfMass(cellptr cell) { /* Center of mass position */ vector cmPos; vector tempV; nodeptr q; int i; /* Init the cell's total mass */ Mass(cell) = 0.0; /* Init the cell's center of mass position */ CLRV(cmPos); /* Loop over the subnodes */ for (i = 0; i < NCHILD; i++) { /* Skipping empty child nodes */ if ((q = Child(cell)[i]) != NULL) { /* If node is a cell */ if (Type(q) == CELL) /* Recursively do the same */ calculateCenterOfMass((cellptr) q); /* Accumulate total mass */ Mass(cell) = Mass(q); /* Accumulate center of mass */ ADDMULVS(cmPos, Pos(q), Mass(q)); } } /* Usually, cell has mass */ if (Mass(cell) > 0.0) { /* Find center of mass position */ DIVVS(cmPos, cmPos, Mass(cell)); } else { /* If no mass inside */ SETV(cmPos, Pos(cell)); } SETV(Pos(cell), cmPos); }
local void sumforces(bodyptr btab, int nbody, bodyptr gtab, int ngrav, real eps2) { bodyptr bp, gp; double phi0, acc0[NDIM]; vector pos0, dr; real dr2, dr2i, dr1i, mdr1i, mdr3i; for (bp = btab; bp < NthBody(btab, nbody); bp = NextBody(bp)) { phi0 = 0.0; CLRV(acc0); SETV(pos0, Pos(bp)); for (gp = gtab; gp < NthBody(gtab, ngrav); gp = NextBody(gp)) { DOTPSUBV(dr2, dr, Pos(gp), pos0); dr2i = ((real) 1.0) / (dr2 + eps2); dr1i = rsqrt(dr2i); mdr1i = Mass(gp) * dr1i; mdr3i = mdr1i * dr2i; phi0 -= mdr1i; ADDMULVS(acc0, dr, mdr3i); } Phi(bp) = phi0; SETV(Acc(bp), acc0); } }
local void stepsystem(void) { bodyptr p1, p2, p; p1 = bodytab + MAX(nstatic, 0); // set dynamic body range p2 = bodytab + nbody + MIN(nstatic, 0); for (p = p1; p < p2; p++) { // loop over body range ADDMULVS(Vel(p), Acc(p), 0.5 * dtime); // advance v by 1/2 step ADDMULVS(Pos(p), Vel(p), dtime); // advance r by 1 step } treeforce(); for (p = p1; p < p2; p++) { // loop over body range ADDMULVS(Vel(p), Acc(p), 0.5 * dtime); // advance v by 1/2 step } nstep++; // count another time step tnow = tnow + dtime; // finally, advance time }
local void sum1force(bodyptr btab, int nbody, int i0, real eps2) { bodyptr bp0, bp; double phi0, acc0[NDIM]; vector pos0, dr; real dr2, drab, mri, mr3i; int j; bp0 = NthBody(btab, i0); phi0 = 0.0; CLRV(acc0); SETV(pos0, Pos(bp0)); for (j = 0; j < nbody; j++) if (j != i0) { bp = NthBody(btab, j); DOTPSUBV(dr2, dr, Pos(bp), pos0); dr2 += eps2; drab = rsqrt(dr2); mri = Mass(bp) / drab; phi0 -= mri; mr3i = mri / dr2; ADDMULVS(acc0, dr, mr3i); } Phi(bp0) = phi0; SETV(Acc(bp0), acc0); }
void snaptrak(void) { bodyptr bp, gp; int nzero; if (traktab == NULL) { ntrak = 0; for (bp = bodytab; bp < NthBody(bodytab, nbody); bp = NextBody(bp)) ntrak = MAX(ntrak, Group(bp)); eprintf("[%s: allocating %d groups]\n", getprog(), ntrak); traktab = (bodyptr) allocate(ntrak * SizeofBody); } for (gp = traktab; gp < NthBody(traktab, ntrak); gp = NextBody(gp)) { Mass(gp) = 0.0; CLRV(Pos(gp)); CLRV(Vel(gp)); Key(gp) = 0; } for (bp = bodytab; bp < NthBody(bodytab, nbody); bp = NextBody(bp)) { if (Group(bp) > ntrak) error("snaptrak: cant expand group array\n"); if (Group(bp) > 0) { gp = NthBody(traktab, Group(bp) - 1); Mass(gp) += Mass(bp); ADDMULVS(Pos(gp), Pos(bp), Mass(bp)); ADDMULVS(Vel(gp), Vel(bp), Mass(bp)); Key(gp)++; } } nzero = 0; for (gp = traktab; gp < NthBody(traktab, ntrak); gp = NextBody(gp)) if (Mass(gp) != 0.0) { DIVVS(Pos(gp), Pos(gp), Mass(gp)); DIVVS(Vel(gp), Vel(gp), Mass(gp)); } else nzero++; if (nzero > 0) eprintf("[%s: %d groups have zero mass]\n", getprog(), nzero); }
void snapcmacc(vector cmacc, bodyptr btab, int nbody, int woff) { double wtot, cmtmp[NDIM]; bodyptr bp; wtot = 0.0; CLRV(cmtmp); for (bp = btab; bp < NthBody(btab, nbody); bp = NextBody(bp)) { wtot = wtot + Weight(bp, woff); ADDMULVS(cmtmp, Acc(bp), Weight(bp, woff)); } DIVVS(cmacc, cmtmp, wtot); }
local void sumnode(cellptr start, cellptr finish, vector pos0, real *phi0, vector acc0) { real eps2, dr2, dr2i, dr1i, mdr1i, mdr3i; vector dr; eps2 = eps * eps; // premultiply softening for (cellptr p = start; p < finish; p++) { // loop over node list DOTPSUBV(dr2, dr, Pos(p), pos0); // compute sep. vector // and square of distance dr2i = ((real) 1.0) / (dr2 + eps2); // perform only division dr1i = rsqrt(dr2i); // set inverse soft distance mdr1i = Mass(p) * dr1i; // form partial potential mdr3i = mdr1i * dr2i; // form scale factor for dr *phi0 -= mdr1i; // sum potential ADDMULVS(acc0, dr, mdr3i); // sum acceleration } }
local void sumnode(cellptr start, cellptr finish, vector pos0, real *phi0, vector acc0) { cellptr p; real eps2, dr2, drab, phi_p, mr3i; vector dr; eps2 = eps * eps; /* avoid extra multiplys */ for (p = start; p < finish; p++) { /* loop over node list */ DOTPSUBV(dr2, dr, Pos(p), pos0); /* compute separation */ /* and distance squared */ dr2 += eps2; /* add standard softening */ drab = rsqrt(dr2); /* form scalar "distance" */ phi_p = Mass(p) / drab; /* get partial potential */ *phi0 -= phi_p; /* decrement tot potential */ mr3i = phi_p / dr2; /* form scale factor for dr */ ADDMULVS(acc0, dr, mr3i); /* sum partial acceleration */ } }
// treeforce: supervise force calculation. // _______________________________________ local void treeforce(void) { bodyptr p1, p2, p; real r, mr3i; p1 = bodytab + MAX(nstatic, 0); // set dynamic body range p2 = bodytab + nbody + MIN(nstatic, 0); for (p = bodytab; p < bodytab+nbody; p++) // loop over all bodies Update(p) = (testcalc ? p1 <= p && p < p2 : TRUE); // flag bodies to update maketree(bodytab, nbody); // construct tree structure gravcalc(); // compute current forces forcereport(); // print force statistics #if defined(EXTGRAV) for (p = bodytab; p < bodytab+nbody; p++) // loop over all bodies if (Update(p) && gravgsp != NULL) { // update in extern field? r = absv(Pos(p)); // get distance from origin mr3i = - mass_gsp(gravgsp, r) / (r*r*r); ADDMULVS(Acc(p), Pos(p), mr3i); // add extern acc and phi Phi(p) += phi_gsp(gravgsp, r); } #endif }
int main(int argc, string argv[]) { stream istr, ostr, gstr; real tnow, tgrav, eps2, tstop, dtime, tout, Mhqm, ahqm, bhqm, tol; real decrit, epot0, demin, demax, derms, de2avg, enow, denow; int nbody, ngrav; bodyptr btab = NULL, gtab = NULL, bp; string bdtags[MaxBodyFields], grtags[MaxBodyFields], *optags; gsprof *gravgsp = NULL; bool decrit_inc = FALSE; initparam(argv, defv); new_field(&EinitPBF, RealType, EinitTag); // define initial energy field layout_body(bodytags, Precision, NDIM); // layout necessary fields istr = stropen(getparam("in"), "r"); get_history(istr); if (! get_snap(istr, &btab, &nbody, &tnow, bdtags, TRUE)) error("%s: can't read input snapshot\n", getprog()); if (! (set_member(bdtags, PosTag) && set_member(bdtags, VelTag))) error("%s: required data missing from input snapshot\n", getprog()); #if defined(NBDGRAV) gstr = stropen(getparam("grav"), "r"); get_history(gstr); if (! get_snap(gstr, >ab, &ngrav, &tgrav, grtags, FALSE)) error("%s: can't read gravity snapshot\n", getprog()); if (! (set_member(grtags, MassTag) && set_member(grtags, PosTag))) error("%s: required data missing from gravity snapshot\n", getprog()); eps2 = rsqr(getdparam("eps")); #elif defined(GSPGRAV) gstr = stropen(getparam("grav"), "r"); get_history(gstr); gravgsp = get_gsprof(gstr); // read GSP for grav. field #elif defined(HQMGRAV) Mhqm = getdparam("M"); ahqm = getdparam("a"); bhqm = getdparam("b"); tol = getdparam("tol"); #endif ostr = stropen(getparam("out"), "w"); put_history(ostr); tstop = getdparam("tstop"); dtime = getdparam("dtime"); decrit = getdparam("decrit"); optags = burststring(getparam("outputs"), ","); #if defined(NBDGRAV) sumforces(btab, nbody, gtab, ngrav, eps2); // prime the pump... #elif defined(GSPGRAV) gspforces(btab, nbody, gravgsp); #elif defined(HQMGRAV) hqmforces(btab, nbody, Mhqm, ahqm, bhqm, tol); #endif epot0 = 0.0; // use as energy scale for (bp = btab; bp < NthBody(btab, nbody); bp = NextBody(bp)) { epot0 += Phi(bp) / nbody; // compute avg. potential Einit(bp) = Phi(bp) + dotvp(Vel(bp), Vel(bp)) / 2; } eprintf("[%s: initial average potential = %g]\n", getprog(), epot0); put_snap(ostr, &btab, &nbody, &tnow, optags); fflush(NULL); tout = tnow + getdparam("dtout"); demin = demax = derms = 0.0; // track maximum errors while (tnow < tstop) { // enter main loop for (bp = btab; bp < NthBody(btab, nbody); bp = NextBody(bp)) { ADDMULVS(Vel(bp), Acc(bp), 0.5 * dtime); // step velocities by dt/2 ADDMULVS(Pos(bp), Vel(bp), dtime); // step positions by dt } tnow = tnow + dtime; // step time to new value #if defined(NBDGRAV) if (! getbparam("frozen")) if (! get_snap(gstr, >ab, &ngrav, &tgrav, grtags, TRUE)) error("%s: can't read gravity snapshot\n", getprog()); sumforces(btab, nbody, gtab, ngrav, eps2); // get new accelerations #elif defined(GSPGRAV) gspforces(btab, nbody, gravgsp); #elif defined(HQMGRAV) hqmforces(btab, nbody, Mhqm, ahqm, bhqm, tol); #endif de2avg = 0.0; for (bp = btab; bp < NthBody(btab, nbody); bp = NextBody(bp)) { ADDMULVS(Vel(bp), Acc(bp), 0.5 * dtime); // step velocities by dt/2 enow = 0.5 * dotvp(Vel(bp), Vel(bp)) + Phi(bp); denow = (enow - Einit(bp)) / ABS(epot0); // compute rel. energy change demin = MIN(demin, denow); demax = MAX(demax, denow); de2avg += rsqr(denow) / nbody; } derms = MAX(derms, rsqrt(de2avg)); if (demin < -decrit || demax > decrit) { eprintf("[%s: warning: energy error exceeds %.4e at time = %-12.8f\n" " min,max,rms = %.6g,%.6g,%.6g threshold now %.4e]\n", getprog(), decrit, tnow, demin, demax, rsqrt(de2avg), decrit * rsqrt(2.0)); decrit = decrit * rsqrt(2.0); decrit_inc = TRUE; } if (tout <= tnow) { put_snap(ostr, &btab, &nbody, &tnow, optags); tout = tout + getdparam("dtout"); } fflush(NULL); } eprintf(decrit_inc ? "[%s: WARNING: energy error: min,max,rms = %.6g,%.6g,%.6g]\n" : "[%s: energy error: min,max,rms = %.6g,%.6g,%.6g]\n", getprog(), demin, demax, derms); return (0); }