[ODE] Approximate Hydrodynamic Forces

David Whittaker david at csworkbench.com
Sat Apr 19 01:49:01 2003


>
> Hey David,
>
> This is what I got now. I works great.
>
> Could you have a look and let me know if you I should be doing anything
> different?
>
> Cheers,
>
> Ander
>
> note: I have added this to the .Net wrapper that I am using
>
> void BoxGeom::ApplyHydrodynamicForces(dReal linear_viscosity, dReal
> angular_viscosity, dReal density, Vector3 flow)
>     {
>         const dReal *lvel = dBodyGetLinearVel(this->_body->Id);
>         const dReal *avel = dBodyGetAngularVel(this->_body->Id);
>         const dReal *R = dBodyGetRotation(this->_body->Id);
>         dReal ss[3];
>         dGeomBoxGetLengths(this->_id, ss);
>
>         dReal AreaX = ss[1] * ss[2];
>         dReal AreaY = ss[0] * ss[2];
>         dReal AreaZ = ss[0] * ss[1];

You might consider making another dVector3 here that holds the compensated
velocity:
dVector3 compFlow;
compFlow[0] = lvel[0] - flow.x;
compFlow[1] = lvel[1] - flow.y;
compFlow[2] = lvel[2] - flow.z;

Use the stored values instead, and it'll save you 6 subtractions anyway
(and will probably exist completely in the fp stack).

>         dReal nx = (R[0] * (lvel[0] - flow.x) + R[4] * (lvel[1] -
> flow.y) +
> R[8] * (lvel[2]) - flow.z) * AreaX;

check your parenthesis here (lvel[2] - flow.z))

>         dReal ny = (R[1] * (lvel[0] - flow.x) + R[5] * (lvel[1] -
> flow.y) +
> R[9] * (lvel[2] - flow.z)) * AreaY;
>         dReal nz = (R[2] * (lvel[0] - flow.x) + R[6] * (lvel[1] -
> flow.y) +
> R[10] * (lvel[2] - flow.z)) * AreaZ;
>
>         dReal temp = -nx*linear_viscosity;
>         dBodyAddForce(this->_body->Id, temp*R[0], temp*R[4], temp*R[8]);
>
>         temp = -ny*linear_viscosity;
>         dBodyAddForce(this->_body->Id, temp*R[1], temp*R[5], temp*R[9]);
>
>         temp = -nz*linear_viscosity;
>         dBodyAddForce(this->_body->Id, temp*R[2], temp*R[6],
> temp*R[10]);
>
>         nx = (R[0] * avel[0] + R[4] * avel[1] + R[8] * avel[2]) * AreaZ;
> ny = (R[1] * avel[0] + R[5] * avel[1] + R[9] * avel[2]) * AreaX;
> nz = (R[2] * avel[0] + R[6] * avel[1] + R[10] * avel[2]) *
> AreaY;

Take a body that is rotating exactly around it's x axis, with a large
AreaY and a tiny AreaZ (i.e. A 1x1x100 box).  This box won't have as large
an nx as it should.  Perhaps one of the following might work better:

nx = dot(x, avel) * max(AreaY, AreaZ)
ny = dot(y, avel) * max(AreaX, AreaZ)
nz = dot(z, avel) * max(AreaX, AreaY)

or

nx = dot(x, avel) * (AreaY + AreaZ)
ny = dot(y, avel) * (AreaX + AreaZ)
nz = dot(z, avel) * (AreaX + AreaY)

or, probably most physical, but pretty expensive too:

dReal AreaDiagX = ss[0] * dSqrt(ss[1] * ss[1] + ss[2] * ss[2]);
dReal AreaDiagY = ss[1] * dSqrt(ss[0] * ss[0] + ss[2] * ss[2]);
dReal AreaDiagZ = ss[2] * dSqrt(ss[0] * ss[0] + ss[1] * ss[1]);

nx = dot(x, avel) * AreaDiagX;
ny = dot(y, avel) * AreaDiagY;
nz = dot(z, avel) * AreaDiagZ;

(excuse my dot shorthand... easier than typing out the first half again,
but the same).

>         temp = -nx * angular_viscosity;
>         dBodyAddTorque(this->_body->Id, temp * R[0], temp * R[4], temp *
>
> R[8]);
>
>         temp = -ny * angular_viscosity;
>         dBodyAddTorque(this->_body->Id, temp * R[1], temp * R[5], temp *
>
> R[9]);
>
>         temp = -nz * angular_viscosity;
>         dBodyAddTorque(this->_body->Id, temp * R[2], temp * R[6], temp *
>
> R[10]);
>
>         dMass m;
>         dBodyGetMass(this->_body->Id, &m);

When I wrote this up, I was thinking you would use the mass of the body
somewhere in the equation, did a little mid-email research, and determined
you wouldn't need it, but forgot to take it out.  The previous two lines
are useless.

>         dReal gravity[3];
>         dWorldGetGravity(this->_body->get_WorldId(), gravity);
>
>         temp = -density * ss[0] * ss[1] * ss[2];
>         dBodyAddForce(this->_body->Id, temp*gravity[0], temp*gravity[1],
>
> temp*gravity[2]);
>
>     }
>
> }
>
> _________________________________________________________________
> MSN Instant Messenger now available on Australian mobile phones. Go to
> http://ninemsn.com.au/mobilecentral/hotmail_messenger.asp