I want to reverse my gravitational force algorithm to produce locations in the "past" of multiple bodies interacting. It's trivial to produce locations in the future by running the algorithm multiple times on the set of bodies but reversing this to write out positions of bodies' previous positions has stumped me. I don't want to store the past positions and since this is deterministic, it should be possible to somehow run the algorithm backwards but I'm not sure how.
In the snippet element
each of the bodies that are tested from universe
in the loop, tick
is the delta time.
function forces(other) {
if (element === other) {
return;
}
var distancePoint = element.point.sub(other.point);
var normal = Math.sqrt(100.0 + distancePoint.lengthSq());
var mag = GravatationalConstant /
Math.pow(normal, 3);
var distPointMulOtherMass = distancePoint
.mul(mag * other.mass);
element.acceleration = element.acceleration.sub(distPointMulOtherMass);
other.acceleration = other
.acceleration
.add(distancePoint
.mul(mag * element.mass)
);
}
element.acceleration = new Point(0,0,0,0);
universe.forEach(forces);
element.velocity = element.velocity.add(element.acceleration.mul(ticks));
element.point = element.point.add(element.velocity.mul(0.5 * ticks));
I tried sending a negative tick as well as negative gravitational constant, but the positions it produces for the "past" didn't seem to follow what the elements appeared to do in the real past.
I don't know much about physics but I was wondering if there is a small change that could be done to reverse this algorithm.
Thanks to Graeme Niedermayer, I've updated my gravity algorithm to the inverse square law and using negative time it appears to produce positions in the past!
function forces(other) {
if (element === other) {
return;
}
var distancePoint = element.point.sub(other.point);
const forceElementMass = GravatationalConstant * element.mass * other.mass /
Math.pow(element.mass,2)
const forceOtherMass = GravatationalConstant * element.mass * other.mass /
Math.pow(other.mass,2)
element.acceleration = element.acceleration
.sub(distancePoint.mul(forceOtherMass))
other.acceleration = other.acceleration
.add(distancePoint.mul(forceElementMass))
}
const ticks = forwards ? dt : -dt;
element.acceleration = new Point(0,0,0,0);
universe.forEach(forces);
element.velocity = element.velocity.add(element.acceleration.mul(ticks));
element.point = element.point.add(element.velocity.mul(0.5 * ticks));
Outlined circles are at the current position and the "past" positions are others fading out to zero opacity.
Realised that I used the wrong equation in Update 1 (both force constants used the same mass object). I looked into a few more examples and have updated the code, but now I'm not sure where i should add the delta time ticks
which is currently just set to 1 for forwards and -1 back backwards. Below is an image of what is looks like if I multiply the acceleration by ticks
before adding it to the velocity each frame body.velocity = body.velocity.add(body.acceleration.mul(ticks))
or if I make one of the masses negative const force = G * body.mass * (forward ? other.mass : -other.mass) / d ** 2
.
As you can see the "past" positions (red outline) of the green body go over to the left and above. I was hoping to have them appear to "follow" the current position but I'm not sure how to reverse or invert the equation to show the "past" positions, basically if the body was traveling in the opposite direction. Is there a way to do this?
In this next image I have multiplied the velocity by delta time ticks
before adding it to the position body.point = body.point.add(body.velocity.mul(ticks))
this results in a similar path to a recorded path the body traveled (by writing each position to an array and drawing a line between those positions) but it is slightly off. This solution is similar to what I was seeing in Update 1. Is there a reason that this is "almost" correct?
Code below is without any additions to reverse the position.
function forces(other, ticks) {
if (body === other) {
return;
}
// Calculate direction of force
var distanceVector = other.point.sub(body.point)
// Distance between objects
var d = distanceVector.mag()
// Normalize vector (distance doesn't matter here, we just want this vector for direction)
const forceNormalized = distanceVector.normalized()
// Calculate gravitational force magnitude
const G = 6.674
const force = G * body.mass * other.mass / d ** 2
// Get force vector --> magnitude * direction
const magDirection = forceNormalized.mul(force)
const f = magDirection.div(body.mass)
body.acceleration = body.acceleration.add(f)
}
body.acceleration = body.acceleration.mul(0)
universe.forEach(body => forces(body, ticks))
body.velocity = body.velocity.add(body.acceleration)
body.point = body.point.add(body.velocity)
I ended up removing the negative mass and the velocity multiplied by ticks and just reversed the way the acceleration is applied to the position:
if (forward) {
universe.forEach(body => forces(body, ticks));
body.velocity = body.velocity.add(body.acceleration)
body.point = body.point.add(body.velocity)
} else {
body.point = body.point.sub(body.velocity)
universe.forEach(body => forces(body, ticks));
body.velocity = body.velocity.sub(body.acceleration)
}
Resulting in being able to generate positions forwards and backwards in time from the current position. In the image it appears so the "past" positions follow the recorded trail of the current position.
To generate a step in the "past" it subtracts the current velocity from the current position, putting it in the last position it was in. Next it gets the acceleration by checking the forces from other bodies then subtracts the new acceleration (using negative mass would do the same) from the velocity so the next position in the "past" will be correct.
You should be able to make one of the masses negative.
The reason why negative time doesn't work is because you are implicit using euler's method. Euler's method is unstable when using negative steps.
Also the physics you using is also a little weird. Gravity is usually a squared law.