/* pickshell: pick a random point on a sphere of specified radius. */ static inline mwvector pickShell(dsfmt_t* dsfmtState, real rad) { real rsq, rsc; mwvector vec; do /* pick point in NDIM-space */ { vec = mwRandomUnitPoint(dsfmtState); rsq = mw_sqrv(vec); /* compute radius squared */ } while (rsq > 1.0); /* reject if outside sphere */ rsc = rad / mw_sqrt(rsq); /* compute scaling factor */ mw_incmulvs(vec, rsc); /* rescale to radius given */ return vec; }
static mwvector nbGravity_Exact(const NBodyCtx* ctx, NBodyState* st, const Body* p) { int i; const int nbody = st->nbody; mwvector a = ZERO_VECTOR; const real eps2 = ctx->eps2; for (i = 0; i < nbody; ++i) { const Body* b = &st->bodytab[i]; mwvector dr = mw_subv(Pos(b), Pos(p)); real drSq = mw_sqrv(dr) + eps2; real drab = mw_sqrt(drSq); real phii = Mass(b) / drab; real mor3 = phii / drSq; mw_incaddv(a, mw_mulvs(dr, mor3)); } return a; }
/* * nbodyGravity: Walk the tree starting at the root to do force * calculations. * * * Random notes: * - Not inlined without inline from multiple calls in * mapForceBody(). Measurably better with the inline, but only * slightly. */ static inline mwvector nbGravity(const NBodyCtx* ctx, NBodyState* st, const Body* p) { mwbool skipSelf = FALSE; mwvector pos0 = Pos(p); mwvector acc0 = ZERO_VECTOR; const NBodyNode* q = (const NBodyNode*) st->tree.root; /* Start at the root */ while (q != NULL) /* while not at end of scan */ { mwvector dr = mw_subv(Pos(q), pos0); /* Then compute distance */ real drSq = mw_sqrv(dr); /* and distance squared */ if (isBody(q) || (drSq >= Rcrit2(q))) /* If is a body or far enough away to approximate */ { if (mw_likely((const Body*) q != p)) /* self-interaction? */ { real drab, phii, mor3; /* Compute gravity */ drSq += ctx->eps2; /* use standard softening */ drab = mw_sqrt(drSq); phii = Mass(q) / drab; mor3 = phii / drSq; acc0.x += mor3 * dr.x; acc0.y += mor3 * dr.y; acc0.z += mor3 * dr.z; if (ctx->useQuad && isCell(q)) /* if cell, add quad term */ { real dr5inv, drQdr, phiQ; mwvector Qdr; /* form Q * dr */ Qdr.x = Quad(q).xx * dr.x + Quad(q).xy * dr.y + Quad(q).xz * dr.z; Qdr.y = Quad(q).xy * dr.x + Quad(q).yy * dr.y + Quad(q).yz * dr.z; Qdr.z = Quad(q).xz * dr.x + Quad(q).yz * dr.y + Quad(q).zz * dr.z; /* form dr * Q * dr */ drQdr = Qdr.x * dr.x + Qdr.y * dr.y + Qdr.z * dr.z; dr5inv = 1.0 / (sqr(drSq) * drab); /* form dr^-5 */ /* get quad. part of phi */ phiQ = 2.5 * (dr5inv * drQdr) / drSq; acc0.x += phiQ * dr.x; acc0.y += phiQ * dr.y; acc0.z += phiQ * dr.z; /* acceleration */ acc0.x -= dr5inv * Qdr.x; acc0.y -= dr5inv * Qdr.y; acc0.z -= dr5inv * Qdr.z; } } else { skipSelf = TRUE; /* Encountered self */ } q = Next(q); /* Follow next link */ } else { q = More(q); /* Follow to the next level if need to go deeper */ } } if (!skipSelf) { /* If a body does not encounter itself in its traversal of the * tree, it is "tree incest" */ nbReportTreeIncest(ctx, st); } return acc0; }