Earlier quoted context omitted.
Yes, the author uses a globally-adaptive time stepper, which is only efficient for very small N. There are adaptive time step methods that are local, and those are used for large systems. If you see bodies flung out after close passes, three solutions are available: reduce the time step, use a higher order time integrator, and (the most common method) add regularization. Regularization (often called "softening") remo…
>Regularization (often called "softening") removes the singularity by adding a constant to the squared distance. So 1 over zero becomes one over a small-ish and finite number. IIRC that is what I did in the end. It is fudge, but it works.
Writing N-body gravity simulations code in Python
41–50 of 51 posts
Re: Writing N-body gravity simulations code in Python
#42In Step 2 (Gravity), why are we summing over the cube of the distance between the bodies in the denominator? Edit: To answer myself, I think this is because one of the factors is to normalize the vector between the two bodies to length 1, and the other two factors are the standard inverse square relationship.
You got it. The familiar inverse square formula uses a unit vector: a = G * m1 * m2 / |r|^2 * r_unit r_unit = r / |r| a = G * m1 * m2 / |r|^3 * r
F = G * m1 * m2 / |r|^2 * r_unit
F = G * m1 * m2 / |r|^3 * r
Or as acceleration, by dividing out an `m` using `F=ma`: a = G * m / |r|^2 * r_unit
a = G * m / |r|^3 * rRe: Writing N-body gravity simulations code in Python
#43ParallelNBodyPerformance Public
Re: Writing N-body gravity simulations code in Python
#44Earlier quoted context omitted.
You got it. The familiar inverse square formula uses a unit vector: a = G * m1 * m2 / |r|^2 * r_unit r_unit = r / |r| a = G * m1 * m2 / |r|^3 * r
The force itself is `G * m1 * m2 / (r^2)`. That's a pure magnitude. The direction of the force is just the unit vector going from m1 to m2. You need it to be a unit vector or else you're multiplying up to something higher than that force. However, I don't get why you'd ever cube the 'r'. Never seen that. I don't think it's right, tbh.
It's pulled out of the unit vector. Might be more clear if I notated the vector bits a bit:
old : new
r : r_vec
|r| : r_mag
r_unit : r_dir
As you know, a vector is a magnitude and direction: r_dir = r_vec / r_mag
So the formulas from before become (also correctly labeled as `F` per my other comment): F = G * m1 * m2 / r_mag^2 * r_dir
F = G * m1 * m2 / r_mag^2 * r_vec / r_mag
F = G * m1 * m2 / r_mag^3 * r_vecRe: Writing N-body gravity simulations code in Python
#45Earlier quoted context omitted.
>Regularization (often called "softening") removes the singularity by adding a constant to the squared distance. So 1 over zero becomes one over a small-ish and finite number. IIRC that is what I did in the end. It is fudge, but it works.
It is a fudge if you really are trying to simulate true point masses. Mathematically, it's solving for the force between fuzzy blobs of mass.
Re: Writing N-body gravity simulations code in Python
#46Earlier quoted context omitted.
The force itself is `G * m1 * m2 / (r^2)`. That's a pure magnitude. The direction of the force is just the unit vector going from m1 to m2. You need it to be a unit vector or else you're multiplying up to something higher than that force. However, I don't get why you'd ever cube the 'r'. Never seen that. I don't think it's right, tbh.
> I don't get why you'd ever cube the 'r'. It's pulled out of the unit vector. Might be more clear if I notated the vector bits a bit: old : new r : r_vec |r| : r_mag r_unit : r_dir As you know, a vector is a magnitude and direction: r_dir = r_vec / r_mag So the formulas from before become (also correctly labeled as `F` per my other comment): F = G * m1 * m2 / r_mag^2 * r_dir F = G * m1 * m2 / r_mag^2 * r_vec / r_mag…
This makes sense to do in computer code also because if you were going to raise r_mag to a power, you might as well raise it to 3 instead of 2, because it's not extra cost, but you do avoid the three divisions, by never calculating a unit vector. Back when I was doing this work, was decades ago and I had no idea about cost of floating points. Thanks for explaining!
Re: Writing N-body gravity simulations code in Python
#47Earlier quoted context omitted.
> I don't get why you'd ever cube the 'r'. It's pulled out of the unit vector. Might be more clear if I notated the vector bits a bit: old : new r : r_vec |r| : r_mag r_unit : r_dir As you know, a vector is a magnitude and direction: r_dir = r_vec / r_mag So the formulas from before become (also correctly labeled as `F` per my other comment): F = G * m1 * m2 / r_mag^2 * r_dir F = G * m1 * m2 / r_mag^2 * r_vec / r_mag…
Ok, I see what you're doing. Your multiplying the force vector by a non unit-vector, and then dividing back out the linear amount to correct for it. You never see this in a physics book because it's a computational hack, probably because it saves you the CPU cost of not having to do the 3 division operations it takes to get each component (X,Y,Z) of the unit vector. This makes sense to do in computer code also becaus…
Also fun is that taking the magnitude involves a square root that can sometimes be avoided, but that doesn't really help us here because of the power of three. If the denominator were squared we could just use `r_mag^2 = r_x^2 + r_y^2`, but we still need the root to get the direction. It is kinda interesting though that in 2d it expands to a power of `3/2`:
F_vec = G * m1 * m2 / (r_x^2 + r_y^2) ^ (3/2) * r_vecRe: Writing N-body gravity simulations code in Python
#48Earlier quoted context omitted.
Decades ago ... I think it was Computer Recreations column in "Scientific American" ... the strategy, since computers were less-abled then, was to advance all the bodies by some amount of time — call it a "tick" — when bodies got close, the "tick" got smaller: therefore the calculations more nuanced, precise. Further apart and you could run the solar system on generalities.
Cut the time interval shorter and shorter, and then BAM you've independently discovered calculus.
Re: Writing N-body gravity simulations code in Python
#49Earlier quoted context omitted.
Ok, I see what you're doing. Your multiplying the force vector by a non unit-vector, and then dividing back out the linear amount to correct for it. You never see this in a physics book because it's a computational hack, probably because it saves you the CPU cost of not having to do the 3 division operations it takes to get each component (X,Y,Z) of the unit vector. This makes sense to do in computer code also becaus…
Glad I could help! Also fun is that taking the magnitude involves a square root that can sometimes be avoided, but that doesn't really help us here because of the power of three. If the denominator were squared we could just use `r_mag^2 = r_x^2 + r_y^2`, but we still need the root to get the direction. It is kinda interesting though that in 2d it expands to a power of `3/2`: F_vec = G * m1 * m2 / (r_x^2 + r_y^2) ^ (…
But that doesn't mean that therefore there's no correct physics equations (for gravity) involving the cube of a distance, even when there's only squares in these "laws" of physics.
In both cases the power of 2, as well as 3/2, is there merely to "cancel out" the fact that you didn't use a unit vector (in the numerator) and therefore need to divide that out in the denominator, to end up scaling the force magnitude against a unit vector.
Re: Writing N-body gravity simulations code in Python
#50For comparison, the famous Debian language benchmark competition: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
And for those who have access 2022 "N-Body Performance With a kD-Tree: Comparing Rust to Other Languages" https://ieeexplore.ieee.org/document/10216574 2025 "Parallel N-Body Performance Comparison: Julia, Rust, and More" https://link.springer.com/chapter/10.1007/978-3-031-85638-9_...