NaN exceptions being thrown from PhysicsSimulator.Update()

Topics: User Forum
Dec 12, 2006 at 8:54 PM
Hi!

I've got a little problem with Farseer: PhysicsSimulator.Update() sometimes throws an exception because a body's _angularVelocity is NaN (not-a-number). The exception gets thrown by Math.Sign() in Body.cs, Line 291:is N
> float rotationalDrag = _angularVelocity * angularVelocity * Math.Sign(angularVelocity);

My physics scene basically consists of about 300 static rectangles and one 32-edged CircleRigidBody that moves around the scene. The problem often surfaces when forces push the circle to scrape along one rectangle into a corner.

I tried to fix this by checking whether float.IsNaN(_angularVelocity) and then setting _angularVelocity to zero, but when _angularVelocity reaches NaN, something else seems to be messed up already.

Dec 12, 2006 at 9:22 PM
Investigated a bit further: In Arbiter.PreStepImpulse() (Arbiter.cs, Line #110) 10 contacts are reported

> _contactList0.Normal == {X:0.05860114 Y:-0.9982815}
> _contactList1.Normal == {X:NaN Y:NaN}

when the second contact gets enumerated, the NaN values cause the impulse vector to become NaN as well, resulting in NaN being assigned to the AngularVelocity property of _rigidBodyA and _rigidBodyB.

I'll try just skipping the contact if any of its normal vectors is NaN, let's see what happens...
Coordinator
Dec 12, 2006 at 9:50 PM
When you start seeing NaN's, it is usually a sign that the physics engine is "blowing-up". This is usually caused by un-realistic parameters set on Rigid Bodies.

What are some of the settings you are using?

I always try to convert my units to meters and use "real" world parameters. Things are much more stable that way.

Try playing with some of the parameters and if it doesn't go away, let me know.
Dec 12, 2006 at 9:56 PM
I've tracked down where the first NaN value comes into existence:

It's in GridCell.Evaluate() (GridCell.cs, Line #39). A point {X:0.007773876 Y:-0.3260798} is evaluated. After ComputeTopBottom() and ComputerLeftRight() have been called, the following is true:

> top == bottom == -0.0900000259
> left == right == -0.09000002

thus feature.Normal is first assigned a normal vector of {X:0.0 Y:0.0} and then feature.Normal.Normalize() makes it go NaN.

Could it be that my dynamic object has penetrated a wall due to speed and is exactly in the center of it?
Or has it something to do with the fact that the dynamic object is hitting a static wall while touching another wall that's perpendicular to the first one?
Dec 12, 2006 at 10:02 PM
Thanks, I didn't fiddle around with the parameters much. My scene basically is built of

~300 x RectangleRigidBody
.IsStatic = true
.FrictionCoefficient = 0.01

1 x CircleRigidBody (32 edges, radius 0.125)
.Mass = 0.125
.FrictionCoefficient = 0.3

All other properties left at the default values. The entire scene fits in a region of a bounding box -10.0, -10.0 to 10.0, 10.0 - so float instability because of huge numbers also shouldn't be a problem.

I'll try playing around with these values a bit, maybe the problem goes away!
Dec 12, 2006 at 10:13 PM
Tried several settings, but the NaN keeps poping up quite often. As far as I can tell, none of my settings is unrealistic. Neither huge dimensions nor excessive speeds are involved. Maybe I can put together a small repro case later this week that demonstrates this problem.

In the meantime, I managed to fight it down by rejecting zero-length normals, in GridCell.Evaluate(), GridCell.cs Line #56, I added this code snippet. I double-checked what happens when the if strikes and the simulation doesn't show any visible misbehavior.

> feature.Normal.Normalize();
>
> if(float.IsNaN(feature.Normal.X) || float.IsNaN(feature.Normal.Y))
> feature.Normal = Vector2.UnitY;
>
> return feature;

Dec 14, 2006 at 6:56 PM
I had this happen a few times as well, but found it to be my moment of inertia to be the problem. I had a value of like 1.2x10-32 (ie really small). it would be fine until it hit a piece just right, and then with that small of moi, it would (I am assuming) try to rotate it so fast the engine returned NaN to the different velocities. I would at least try to set your moi higher and see if it fixes it for you.

Gudy
Dec 14, 2006 at 10:03 PM
Hmmmmm. Of course as soon as I say that, I get the error again. Scratch the moi idea. I have been playing around for a while now and can duplicate it, but can't see why it would be doing it. I also checked the latest demo version and was able to get it to crash with the same error without any code changes. there are 2 ways to get it to crash 1) run the demo and let the pieces fall. then resize the window (doesn't matter to what size) then hit the up arrow to change gravity to up. when the pieces hit the top, it will crash (at least on my system). The second way to crash it is to bump the gravity up in the demo to bump the gravity up. I got it to crash at 4, but only once, but at 5 and 6, it is pretty easy to get it to crash. The peices are moving pretty good in the demo, but in my project, using geometries with many vertices, it will do it as much lower speeds. Hope this helps

Gudy
Coordinator
Dec 15, 2006 at 1:07 PM
I will look into it. Thanks for telling me how to recreate it.
Coordinator
Dec 15, 2006 at 1:31 PM
Also, one thing you might try to limit this "blow-up" is to increase the RotationalDrag a bit. That should help stabalize things.
Dec 15, 2006 at 2:01 PM
I tried numbers up to 1000 and still get it, however, not as much. Thanks for your help.

Gudy
Dec 30, 2006 at 10:24 PM
Had the same problem (at least I think its the same).

After debugging I found out it's because I changed objects from static to non-static and back mid run.

It screwed stuff up several steps prior to it crashing. To fix it I changed the following

internal bool ContainsDisposedRigidBody()
{
return _rigidBodyA.IsDisposed || _rigidBodyB.IsDisposed;
}

to

return _rigidBodyA.IsDisposed || rigidBodyB.IsDisposed || (rigidBodyA.IsStatic && _rigidBodyB.IsStatic);

Hope this helps.
Coordinator
Dec 31, 2006 at 1:35 AM
I've also added a "fix" for this in the next release. It's a bit of a hack, but it should help the NaN issue.
Feb 3, 2008 at 12:23 PM
Edited Feb 3, 2008 at 12:24 PM
I was also having this problem, in the latest Farseer release too. Following devboy's advice I was able to fix it though. The fix went into the ContainsDisposedGeom function.