-4

My gravity simulation acts more like a gravity slingshot. Once the two bodies pass over each other, they accelerate far more than they decelerate on the other side. It's not balanced. It won't oscillate around an attractor.

How do other gravity simulators get around it? example: http://www.testtubegames.com/gravity.html, if you create 2 bodies they will just oscillate back and forth, not drifting any further apart than their original distance even though they move through each other as in my example.

That's how it should be. But in my case, as soon as they get close they just shoot away from each other to the edges of the imaginary galaxy never to come back for a gazillion years.

edit: Here is a video of the bug https://i.stack.imgur.com/uRSRI.jpg

Here is a minimal test case to run in processing.

//Constants: 

float v;

int unit = 1; //1 pixel = 1 meter

float x;
float y;

float alx;
float aly;

float g = 6.67408 * pow(10, -11) * sq(unit); //g constant

float m1 = (1 * pow(10, 15)); // attractor mass
float m2 = 1; //object mass

void setup() {
size (200,200);
  a = 0;
  v = 0;

  x = width/2; // object x
  y = 0;       // object y

  alx = width/2; //attractor x
  aly = height/2; //attractor y
}

void draw() {
  background(0);
  getAcc();
  applyAcc();

  fill(0,255,0);
  ellipse(x, y, 10, 10); //object
  fill(255,0,0);
  ellipse(alx, aly, 10, 10); //attractor
}


void applyAcc() {
  a = getAcc();
  v += a * (1/frameRate); //add acceleration to velocity
  y += v * (1/frameRate); //add velocity to Y
  a = 0;
}

float getAcc() {
float a = 0;
  float d = dist(x, y, alx, aly); //distance to attractor
  float gravity = (g * m1 * m2)/sq(d); //gforce

  a += gravity/m2;

 if (y > aly){
 a *= -1;} 
 return a;
}
Bodhi1
  • 149
  • 10
  • What do you mean by "clamp the distance"? Can you produce a [minimal test case](https://stackoverflow.com/help/mcve)? – Oliver Charlesworth Apr 02 '18 at 18:34
  • I mean d = constrain(d, 30, 99999999); where 30 is the minimum value for the distance between two objects and 9999999 is the max. That means gravity won't increase past a certain point as it gets too close. This is a horrible "patch" to the problem though, that's why I didn't include it in the code. – Bodhi1 Apr 02 '18 at 18:36
  • Can you please post a [mcve]? – Kevin Workman Apr 02 '18 at 18:39
  • Ok, one second @ Kevin – Bodhi1 Apr 02 '18 at 18:50
  • For starters, just use `double` for everything. – chrylis -cautiouslyoptimistic- Apr 02 '18 at 18:50
  • This is quite strange code - why are you setting a global in `getAcc()`, rather than just returning a value? The `+=` that @Benjamin pointed out in an (now-deleted) answer is likely the issue here - you're adding to an uninitialised variable. – Oliver Charlesworth Apr 02 '18 at 18:53
  • I added the minimum verifiable example, the reason for using globals is for simplicity in the example, but the problem occurs regardless. a should be initialized in setup() before the function is run. – Bodhi1 Apr 02 '18 at 18:57
  • @chrylis, same problem when using vectors, which should be doubles already? – Bodhi1 Apr 02 '18 at 19:08
  • I added a video of the phenomena – Bodhi1 Apr 02 '18 at 19:22

3 Answers3

1

Your distance doesn't include width of the object, so the objects effectively occupy the same space at the same time.

The way to "cap gravity" as suggested above is add a normal force when the outer edges touch, if it's a physical simulation.

MGreene
  • 21
  • 6
  • Good point, I was thinking before that because all mass has gravity, once they contact the matter that is overlapped should be pulling them in the opposite direction, and when they are on top of eachother the gravity should cancel out because matter is pulling in all directions. Only the matter that isn't overlapped should be accounted for. In this case, calculating the intersectional area and subtracting that mass from the calculation, and the center of mass would have to recalculated <--- this seems like the hard part. – Bodhi1 Apr 03 '18 at 19:00
  • Super computationally expensive though. Maybe each particle would be made of an array of gravity particles that add up to the total gravity of an object, and each gravity particle gets turned off on collision. But that would mean checking the distance between every particle...... – Bodhi1 Apr 03 '18 at 19:10
  • It wouldn't really help for super dense small objects because things accelerate out of control before they even touch though. – Bodhi1 Apr 03 '18 at 19:15
  • This gave me an idea. I decided to try a modified verlet strategy, factoring in overlapping area, and sampling 10 times per frame. It is now able to pass through other bodies and pass the pendulum test with outrageous accuracy (down to the centimeter as long as the simulation doesn't run very long which I haven't tested yet) – Bodhi1 Apr 04 '18 at 02:16
  • This is so epic – Bodhi1 Apr 04 '18 at 02:21
  • If things accelerate out of control, possibly your step size is too large, the 1/framerate factor? Maybe your unit sizes for mass are unreasonable? – MGreene Apr 04 '18 at 19:54
  • I'm unclear on what you're trying to model exactly. You could add a momentum damping factor based on velocity, which you already have, o?r 1/distance if that works for your model, though it's not really a model of anything physical. If you fall out of a plane you accelerate for a while, but you stop as the drag from the air builds based on your speed. One other thing I notice here is you don't check whether the distance is 0. Finally, for the overlap, you could do an integral approximation to get "effective volume" and "effective center of mass". – MGreene Apr 04 '18 at 20:06
  • Actually hang on, the math is just totally goofy here. Can dist() return negative? It needs to. – MGreene Apr 04 '18 at 20:53
  • v and y don't just change by the new acceleration amount- a better approximation would average the previous and new amounts. – MGreene Apr 04 '18 at 21:04
  • Yes, I ended up averaging the change in acceleration as well as factoring in the overlapping mass, which would pull in all directions and cancel each other out. – Bodhi1 Nov 22 '18 at 15:08
0

You should get into the habit of debugging your code. Which line of code is behaving differently from what you expected?

For example, if I were you I would start by printing out the value of gravity every time you calculate it:

float gravity = (g * m1 * m2)/sq(d); //gforce
println(gravity);

You'll notice that your gravity value skyrockets as your circles get closer to each other. And this makes sense, because you're dividing by sq(d). Ad d gets smaller, your gravity increases.

You could simply cap your gravity value so it doesn't go off the charts anymore:

float gravity = (g * m1 * m2)/sq(d);

if(gravity > 100){
  gravity = 100; 
}

Alternatively you could cap d so it never goes below a certain value, but the result is the same.

In the end you'll find that this is not going to be as easy as you expected. You're going to have to tune the parameters quite a bit so your simulation works how you want.

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
  • I've tried clamping in both ways you described, but I was hoping to find a solution that involves integrating in a way that conserves energy as clamping distance or acceleration doesn't really deal with the fundamental problem of energy not being conserved. – Bodhi1 Apr 02 '18 at 19:31
  • @Bodhi1 Please keep in mind that your code is a simulation, not real life. It doesn't know anything about conservation of energy. Simulations like this involve a ton of hand-tuned parameters and clamped values. It's a very manual process to get right. – Kevin Workman Apr 02 '18 at 19:33
  • Nonetheless, the mathematical precision of some examples like http://www.testtubegames.com/gravity.html lead me to believe there is a mathematical solution that is better than Eulers method to integrate acceleration which solves the energy conservation problem. – Bodhi1 Apr 02 '18 at 20:21
  • @Bodhi1 Have you looked at the source code of the simulation? I'd be willing to bet they're just capping the gravity and/or velocity and/or distance. – Kevin Workman Apr 02 '18 at 20:37
  • Unfortunately it's closed source, but it would be really interesting to know how they achieved their results. – Bodhi1 Apr 02 '18 at 22:54
0

Working demo here: https://beta.observablehq.com/@shaunlebron/1d-gravity

I followed the solution posted by the author of the sim that inspired this question here:

-First off, shrinking the timestep is always helpful. My simulation runs, as a baseline, about 40 ‘steps’ per frame, and 30 frames per second.

-To deal with the exact issue you talk about, I think modeling the bodies not as pure point masses - but rather spherical masses with a certain radius will be vital. That prevents the force of gravity from diverging to infinity. So, for instance, if you drop an asteroid into a star in my simulation (with collisions turned off), the force of gravity will increase as the asteroid gets closer, up until it reaches the surface of the star, at which point the force will begin to decrease. And the moment it’s at the center of the star (or nearby), the force will be zero (or nearly zero) - instead of near-infinite.

In my demo, I just completed turned off gravity when two objects are close enough together. Seems to work well enough.

Shaun Lebron
  • 2,501
  • 28
  • 29
  • That's great demo code and I appreciate the well thought out response, however I noticed the demo code does suffer the same problem where a bit of energy is added on each 'revolution', straying further and further from the 'sun'. – Bodhi1 Nov 22 '18 at 15:09
  • thanks, i didn't notice energy being added. did you end up fully solving this? is there something you can share? – Shaun Lebron Nov 23 '18 at 05:34
  • For orbits, I was able to solve it by using Verlet integration, and averaging the change of acceleration. For bodies passing through each-other, I calculated the new center of gravity according to the intersectional area. – Bodhi1 Nov 24 '18 at 05:06
  • Also, getting an accurate time-step helps, especially if you iterate multiple times per frame. – Bodhi1 Nov 24 '18 at 05:14
  • do you have source code? or could you create a notebook to demonstrate like I did? – Shaun Lebron Nov 24 '18 at 13:21