I am trying to simulate noble gas interactions based on the Lennar Jones Potential.
And I ran into the problem that the interactions of the particles is apparently calculated in discrete steps so that the acceleration tends to either jump to unreasonably high values or doesn't change significantly when two particles approach each other.
The detection algorithm that I'm using looks as follows:
def accerlation(self):
index = 0
for particle, particle2 in itertools.combinations(self.particles, 2):
index += 1
x_diff = (particle.r[0] - particle2.r[0])*S
y_diff = (particle.r[1] - particle2.r[1])*S
distance = np.sqrt(x_diff**2 + y_diff**2)
if distance < criticaldistance1 and distance> criticaldistance2:
print("Interaction")
particle.a[0] -= 1/(Particle().m) *(LennardJones_Force(x_diff))
particle.a[1] -= 1/Particle().m *(LennardJones_Force(y_diff))
print(particle.a)
(The print commands are for debugging)
The Lennard Jones Force is simply a function that returns (24*epsilon*sigma**6*(Distance**6 - 2*sigma**6))/Distance**13, where epsilon and sigma are constant values.
If you can't spot a mistake there, the problem might also be in this part:
def Changeovertime(self):
self.Collision_Box() #elaxtic collsions with box
for particle in self.particles:
particle.r += self.dt * particle.v + self.dt**2*particle.a
particle.a_prior = particle.a
self.accerlation() #
particle.a = np.zeros(2) #
particle.v = (particle.v + self.dt/2 * (particle.a + particle.a_prior)) *self.scaling()
When I print the acceleration of a pair of particles during the animation it looks as follows:
[-3.21599405e-01 -1.05489024e-18]\
Interaction\
[-3.35299415e-14 2.61407475e-19]\
Interaction\
[-2.52825200e+31 -1.05489024e-07]\
Interaction\
[-6.70598831e-14 5.22814950e-19]\
Interaction\
[ 1.57188229e-01 -5.51566856e-19]\
Interaction\
[-6.70598831e-03 5.22814950e-08]\
Interaction\
[ 3.14376458e-01 -1.10313371e-18]\
Interaction\
[-3.35299416e-14 2.72195193e-19]\
Interaction\
[-6.70598831e-14 5.44390386e-19]\
(Note the jump from entry 2 to entry 3)
Without commenting on the rest of the code, the problem you see is due to the lines:
particle.a[0] -= 1/(Particle().m) *(LennardJones_Force(x_diff))
particle.a[1] -= 1/Particle().m *(LennardJones_Force(y_diff))
The force, and the acceleration, are vectors: you can not break them into x and y components like that. You have to calculate the force and project it into x and y (you can work with acceleration if you want).
force = LennardJones_Force(distance)
particle.a[0] -= 1/(particle.m) * force * x_diff/distance
particle.a[1] -= 1/(particle..m) * force * y_diff/distance
Please check the signs (they should be opposite for particle and particle2).
The huge jump you see is because two particles had a very similar x or y coordinate (even if they were far apart), and the miscalculated force was huge.
It seems that physics is not obeyed.
Verify that Newton's third law is implemented.\
Note that the moment these particles interact, an action-reaction pair is formed, so to ensure conservation of energy the force acting on particle j must be the same force acting on particle i (in direction and absolute value): Fx[i] = -Fx[j] (imagine i red and j blue!).
Here's a note: if the masses of these particles are equal and their values are 1, you can assume that acceleration equals force Fx[i] = ax[i]/1. Then, all that remains is to decompose these forces (Fr[i] and Fr[j]) into their components (Fx[i], Fy[i] and Fz[i] for Fr[i] and Fx[j], Fy[j] and Fz[j] for Fr[j]), always remembering that the force that particle j does on particle i is equal to the force that particle i does on particle j, being different only by their signs (different senses).
In computer practice, you do it this way:
def acceleration():
for i in range(0,N_particles):
for j in range(i+1,N_particles):
rij = np.sqrt((x[i] - x[j])**2 + (y[i] - y[j])**2 + (z[i] - z[j])**2)
if (rij < rmaxlj):
flj = (48*epsilon*(sigma**12/rij**13) + 24*self.epsilon*(sigma**6/rij**7))/rij**2
Fx[i] += flj*(x[i] - x[j])
Fy[i] += flj*(y[i] - y[j])
Fz[i] += flj*(z[i] - z[j])
Fx[j] -= flj*(x[i] - x[j])
Fy[j] -= flj*(y[i] - y[j])
Fz[j] -= flj*(z[i] - z[j])
return Fx, Fy, Fz
Note that all forces that are added to each component of particle j are "removed" from each component of particle i. This is actually Newton's third law in action!
PS.: these rmaxlj works as if you were using criticaldistance and also you can use i as 0 and j as 1
Test this and tell me later!
Related
So I'm currently working on a Java Processing program where I want to simulate high numbers of particles interacting with collision and gravity. This obviously causes some performance issue when particle count gets high, so I try my best to optimize and avoid expensive operations such as square-root, otherwise used in finding distance between two points.
However, now I'm wondering how I could do the algoritm that figures out the direction a particle should move, given it only knows the distance squared and the difference between particles' x and y (dx, dy).
Here's a snip of the code (yes, I know I should use vectors instead of seperate x/y-couples. Yes, I know I should eventually handle particles by grids and clusters for further optimization) Anyways:
void applyParticleGravity(){
int limit = 2*particleRadius+1; //Gravity no longer applied if particles are within collision reach of eachother.
float ax, ay, bx, by, dx, dy;
float distanceSquared, f;
float gpp = GPP; //Constant is used, since simulation currently assumes all particles have equal mass: GPP = Gravity constant * Particle Mass * Particle Mass
Vector direction = new Vector();
Particle a, b;
int nParticles = particles.size()-1; //"particles" is an arraylist with particles objects, each storing an x/y coordinate and velocity.
for (int i=0; i<nParticles; i++){
a = particles.get(i);
ax = a.x;
ay = a.y;
for (int j=i+1; j<nParticles; j++){
b = particles.get(j);
bx = b.x;
by = b.y;
dx = ax-bx;
dy = ay-by;
if (Math.abs(dx) > limit && Math.abs(dy) > limit){ //Not too close to eachother
distanceSquared = dx*dx + dy*dy; //Avoiding square roots
f = gpp/distanceSquared; //Gravity formula: Force = G*(m1*m2)/d^2
//Perform some trigonometric magic to decide direction.x and direction.y as a numbet between -1 and 1.
a.fx += f*direction.x; //Adds force to particle. At end of main iteration, x-position is increased by fx/mass and so forth.
a.fy += f*direction.y;
b.fx -= f*direction.x; //Apply inverse force to other particle (Newton's 3rd law)
b.fy -= f*direction.y;
}
}
}
}
Is there a more accurate way of deciding the x and y pull strength with some trigonometric magic without killing performance when particles are several hundreds? Something I thought about was doing some sort of (int)dx/dy with % operator or so and get an index of a pre-calculated array of values.
Anyone have a clue? Thanks!
hehe, I think we're working on the same kind of thing, except I'm using HTML5 canvas. I came across this trying to figure out the same thing. I didn't find anything but I figured out what I was going for, and I think it will work for you too.
You want an identity vector that points from one particle to the another. The length will be 1, and x and y will be between -1 and 1. Then you take this identity vector and multiply it by your force scalar, which you're already calculating
To "point at" one particle from another, without using square root, first get the heading (in radians) from particle1 to particle2:
heading = Math.atan2(dy, dx)
Note that y is first, I think this is how it works in Java. I used x first in Javascript and that worked for me.
Get the x and y components of this heading using sin/cos:
direction.x = Math.sin(heading)
direction.y = Math.cos(heading)
You can see an example here:
https://github.com/nijotz/triforces/blob/c7b85d06cf8a65713d9b84ae314d5a4a015876df/src/cljs/triforces/core.cljs#L41
It's Clojurescript, but it may help.
I'm going to develop carom board game. I'm having the problem with the collision of two pieces. How to find the collision point of two pieces. And then how to find the angle and distance the pieces travel after collision.I found the solution of the collision point at circle-circle collision. here the solution is described with trigonometry, but I want the solution with vector math. With which the problem of the distance covered after collision will also be solve easily.
You do not need to find the collision point for the collision computation itself. To detect a collision event, you only need to compare the distance of the centers go the sum of radii
sqrt(sqr(x2-x1)+sqr(y2-y1))<=r1+r2
or
dx*dx+dy*dy <= (r1+r2)*(r1+r2)
where (x1,y1) and (x2,y2) are the positions of disks 1 (with mass m1, radius r1 and velocity (vx1,vy1)) and 2. Differences are always 2 minus 1, dx=x2-x1 etc.
You will almost never get that the collision happens at the sample time of the time discretisation. With the above formula, the circles already have overlap. Depending on time step and general velocities this may be negligible or can result in severe over-shooting. The following simple computation assumes slow motion, i.e., very small overlap during the last time step.
The only thing that happens in the fully elastic collision of non-rotating disks is a change in velocity. This change has to happen only once, when further movement would further reduce the distance, i.e., if
dx*dvx+dy*dvy < 0
where dvx=vx2-vx1 etc.
Using these ideas, the computation looks like this (see https://stackoverflow.com/a/23193044/3088138 for details)
dx = x2-x1; dy = y2-y1;
dist2 = dx*dx + dy*dy;
R = r1+r2;
if ( dist2 <= R*R )
{
dvx=vx2-vx1; dvy=vy2-vy1;
dot = dx*dvx + dy*dvy;
if ( dot < 0 )
{
factor = 2/(m1+m2)*dot/dist2;
vx1 += m2*factor*dx;
vy1 += m2*factor*dy;
vx2 -= m1*factor*dx;
vy2 -= m1*factor*dy;
}
}
I am currently doing a small turn based cannon game with XNA 4.0. The game is very simple: the player chooses the speed and angle at which he desires to shoot his rocket in order to hit another player. There is also a randomly generated wind vector that affects the X trajectory of the rocket. I would like to add an AI so that the player could play against the computer in a single player mode.
The way I would like to implement the AI is very simple: find the velocity and angle that would make the rocket hit the player directly, and add a random modifier to those fields so that the AI doesn't hit another player each time.
This is the code I use in order to update the position and speed of the rocket:
Vector2 gravity = new Vector2(0, (float)400); // 400 is the sweet spot value that i have found works best for the gravity
Vector2 totalAcceleration = gravity + _terrain.WindDirection;
float deltaT = (float)gameTime.ElapsedGameTime.TotalSeconds; // Elapsed time since last update() call
foreach (Rocket rocket in _instantiatedRocketList)
{
rocket.RocketSpeed += Vector2.Multiply(gravity, deltaT); // Only changes the Y component
rocket.RocketSpeed += Vector2.Multiply(_terrain.WindDirection, deltaT); // Only changes the X component
rocket.RocketPosition += Vector2.Multiply(rocket.RocketSpeed, deltaT) + Vector2.Multiply(totalAcceleration, (float)0.5) * deltaT * deltaT;
// We update the angle of the rocket accordingly
rocket.RocketAngle = (float)Math.Atan2(rocket.RocketSpeed.X, -rocket.RocketSpeed.Y);
rocket.CreateSmokeParticles(3);
}
I know that the basic equations to find the final X and Y coordinates are:
X = V0 * cos(theta) * totalFlightTime
Y = V0 * sin(theta) * totalFlightTime - 0.5 * g * totalFlightTime^2
where X and Y are the coordinates of the player I want to hit, V0 the initial speed, theta the angle at witch the rocket is shot, totalFlightTime is, like the name says, the total flight time of the rocket until it reaches (X, Y) and g is the gravity (400 in my game).
Questions:
What I am having problems with, is knowing where to add the wind in those formulas (is it just adding "+ windDirection * totalFlightTime" in the X = equation?), and also what to do with those equations in order to do what I want to do (finding the initial speed and theta angle) since there are 3 variables (V0, theta and totalFlightTime) and only 2 equations?
Thanks for your time.
You can do this as follows:
Assuming there is no specific limit to V0 (i.e. the robot can fire the rocket at any desired speed) and using the substitutions
T=totalFlightTime
Vx=V0cos(theta)
Vy=V0sin(theta)
Choose an arbitrary value for Vx. Now your first equation simplifies to
X=VxT so T=X/Vx
to solve for T. Now substitute the value of T into the second equation and solve for Vy
Y=VyT + gT^2/2 so Vy = (Y - gT^2/2)/T
Finally you can now solve for V0 and theta
V0 = Sqrt(Vx^2 + Vy^2) and Theta = aTan(Vy/Vx)
Note that your initial choice of Vx will determine the trajectory the missile will take - if Vx is large then T will be small and the trajectory will be almost a straight line (like a bullet fired at a nearby target) - if Vx is small then T will be large and the trajectory will be an arc (like a mortar round's path). You dis start with three variables (V0, totalFlightTime, and theta) but they are dependent variables so choosing any one (or in this case Vx) plus the two equations solves for the other two. You could also pre-determine flight time and solve for Vx, Vy, theta and V0, or predetermine theta (although this would be tricky as some theta wouldn't provide a real solution.
Hi I have the following implementation of ball to ball collision detection in ruby, which works fine for most collisions. How ever there are some flaws when balls hit each other at certain angels.
I have put my implementation down here if you need more info tell me. But Im wondering more in general terms. What causes the balls to swirl around each other at certain angels of impact.
def ball_collider! ball
for ball2 in #balls do
next if ball.object_id == ball2.object_id
next unless box_overlap ball2.boundbox, ball.boundbox
next unless ball_overlap ball, ball2
dx = ball2.x - ball.x
dy = ball2.y - ball.y
dist=Math.sqrt(dx**2 + dy**2)
bonuce_point_x = ball2.x - (ball.radii + ball2.radii) * dx / dist
bonuce_point_y = ball2.y - (ball.radii + ball2.radii) * dy / dist
bounce_line = [[bonuce_point_x,bonuce_point_y],[bonuce_point_x-dy,bonuce_point_y+dx]]
ball2.bounce! bounce_line
ball.bounce! bounce_line
motion_left = ball.unmove! bounce_line, true
ball_controller! ball if motion_left > 0.1
end
end
def box_overlap box1, box2
return (box1[:width] + box2[:width] > (box1[:x] - box2[:x]).abs) && (box1[:width] + box2[:width] > (box1[:y] - box2[:y]).abs)
end
def ball_overlap ball1, ball2
dx = ball2.x - ball1.x
dy = ball2.y - ball1.y
return (dx**2 + dy**2) < (ball1.radii+ball2.radii)**2
end
In your physics model, you are presumably updating positions and doing collision checks at discrete time intervals. This means that when you detect a collision between a pair of balls, the actual collision would have taken place somewhat before that time, and your calculations will thus be based on the wrong movement vectors. You could do calculations to get the correct time of impact, but this could get messy due to other objects being involved in collisions with the two objects you're checking within the same time interval. Try increasing the frequency (ie. reducing your time intervals) to limit the problem.
As for why you get the "swirl" effect: the calculations will cause the balls to still be colliding with each other after your modify their vectors, even when they are now moving away from each other, which will again cause your next iteration to pull them towards each other's center again, and so on and so forth.
I have a point that moves (in one dimension), and I need it to move smoothly. So I think that it's velocity has to be a continuous function and I need to control the acceleration and then calculate it's velocity and position.
The algorithm doesn't seem something obvious to me, but I guess this must be a common problem, I just can't find the solution.
Notes:
The final destination of the object may change while it's moving and the movement needs to be smooth anyway.
I guess that a naive implementation would produce bouncing, and I need to avoid that.
This is a perfect candidate for using a "critically damped spring".
Conceptually you attach the point to the target point with a spring, or piece of elastic. The spring is damped so that you get no 'bouncing'. You can control how fast the system reacts by changing a constant called the "SpringConstant". This is essentially how strong the piece of elastic is.
Basically you apply two forces to the position, then integrate this over time. The first force is that applied by the spring, Fs = SpringConstant * DistanceToTarget. The second is the damping force, Fd = -CurrentVelocity * 2 * sqrt( SpringConstant ).
The CurrentVelocity forms part of the state of the system, and can be initialised to zero.
In each step, you multiply the sum of these two forces by the time step. This gives you the change of the value of the CurrentVelocity. Multiply this by the time step again and it will give you the displacement.
We add this to the actual position of the point.
In C++ code:
float CriticallyDampedSpring( float a_Target,
float a_Current,
float & a_Velocity,
float a_TimeStep )
{
float currentToTarget = a_Target - a_Current;
float springForce = currentToTarget * SPRING_CONSTANT;
float dampingForce = -a_Velocity * 2 * sqrt( SPRING_CONSTANT );
float force = springForce + dampingForce;
a_Velocity += force * a_TimeStep;
float displacement = a_Velocity * a_TimeStep;
return a_Current + displacement;
}
In systems I was working with a value of around 5 was a good point to start experimenting with the value of the spring constant. Set it too high will result in too fast a reaction, and too low the point will react too slowly.
Note, you might be best to make a class that keeps the velocity state rather than have to pass it into the function over and over.
I hope this is helpful, good luck :)
EDIT: In case it's useful for others, it's easy to apply this to 2 or 3 dimensions. In this case you can just apply the CriticallyDampedSpring independently once for each dimension. Depending on the motion you want you might find it better to work in polar coordinates (for 2D), or spherical coordinates (for 3D).
I'd do something like Alex Deem's answer for trajectory planning, but with limits on force and velocity:
In pseudocode:
xtarget: target position
vtarget: target velocity*
x: object position
v: object velocity
dt: timestep
F = Ki * (xtarget-x) + Kp * (vtarget-v);
F = clipMagnitude(F, Fmax);
v = v + F * dt;
v = clipMagnitude(v, vmax);
x = x + v * dt;
clipMagnitude(y, ymax):
r = magnitude(y) / ymax
if (r <= 1)
return y;
else
return y * (1/r);
where Ki and Kp are tuning constants, Fmax and vmax are maximum force and velocity. This should work for 1-D, 2-D, or 3-D situations (magnitude(y) = abs(y) in 1-D, otherwise use vector magnitude).
It's not quite clear exactly what you're after, but I'm going to assume the following:
There is some maximum acceleration;
You want the object to have stopped moving when it reaches the destination;
Unlike velocity, you do not require acceleration to be continuous.
Let A be the maximum acceleration (by which I mean the acceleration is always between -A and A).
The equation you want is
v_f^2 = v_i^2 + 2 a d
where v_f = 0 is the final velocity, v_i is the initial (current) velocity, and d is the distance to the destination (when you switch from acceleration A to acceleration -A -- that is, from speeding up to slowing down; here I'm assuming d is positive).
Solving:
d = v_i^2 / (2A)
is the distance. (The negatives cancel).
If the current distance remaining is greater than d, speed up as quickly as possible. Otherwise, begin slowing down.
Let's say you update the object's position every t_step seconds. Then:
new_position = old_position + old_velocity * t_step + (1/2)a(t_step)^2
new_velocity = old_velocity + a * t_step.
If the destination is between new_position and old_position (i.e., the object reached its destination in between updates), simply set new_position = destination.
You need an easing formula, which you would call at a set interval, passing in the time elapsed, start point, end point and duration you want the animation to be.
Doing time-based calculations will account for slow clients and other random hiccups. Since it calculates on time elapsed vs. the time in which it has to compkete, it will account for slow intervals between calls when returning how far along your point should be in the animation.
The jquery.easing plugin has a ton of easing functions you can look at:
http://gsgd.co.uk/sandbox/jquery/easing/
I've found it best to pass in 0 and 1 as my start and end point, since it will return a floating point between the two, you can easily apply it to the real value you are modifying using multiplication.