Truss Simulation - ProkopHapala/SimpleSimulationEngine GitHub Wiki
Linearized Truss Elasticity
- See
class SoftBodyLinearized
in SoftBody.h and- also function (
SoftBody::evalForceLinearizedBonds( )
andSoftBody::linearizedBonds( )
may be relevant
- also function (
- Simple C++ implementation of LBFGS
Normally we calculate spring force due to bond between two points as
d = p[j] - p[i];
l = length(d);
h = h/l;
dl = l-l0;
f = h*(dl*k);
There are several problem with this approach:
- numerical stability - the calculation of the length $l$ is numerically inaccurate because we subtract two large close number at two places.
d=p[j]-p[i];
is numerically inaccurate when the points{\vec p}_i
and{\vec p}_j
are close to each other but far from the origin ${\vec p}_0=(0,0,0)$. This can happen easily e.g. for space-ship simulation which has short sticks with lengh $~1[m]$ at the distant end of girders $~10000[m]$ from the center. Here we immediaterly loose 4-orders of numerical precission.dl = l-l0
- is numerically inaccurate especially assuming that stick are rather stiff and usually cannot be strained more than $~1%$. Then this inaccurate value is magnified by multiplication by stiffness $k$ which is typically very large.
- cost of sqrt() evaluation hidden in the calculation of
length(d){ l2=dot(d,d); return sqrt(l2); };
.
Both these problems can be minimized by using modified linearized algorithm where we first precalculate normalized direction vectors and than use deflections of points form the center.
void linearizedDynamics(int nsub=10){
preCalc();
// --- this low accuracy loop can be done e.g. on GPU in single-precission
for(int i=0;i<nsub;i++){
evalTrussForces_Linearized();
movePoints_Linearized ();
}
postCalc();
}
double3 points[nPoint];
int2 bond2point[nBond];
float l0s [nBond]; // lenght of each bond
float dl0s[nBond];
float3 hbs [nBond]; // direction of each bond
float3 dpos[nPoint]; // deflections of points from equlibrium
// --- high-precision pre-calculation
void preCalc(){
for(int ib=0;ib<nBond;ib++){
int2 b = bond2point[ib];
double3 d = points[b.y]-points[b.x];
double l = length(d);
hbs[ib] = (float3)( d/l );
dl0[ib] = (float )( l - l0s[ib] );
}
for(int i=0;i<nPoint;i++){ dpos[i]={0.f,0.f,0.f}; dvel[i]={0.f,0.f,0.f}; }
}
void postCalc(){
for(int i=0;i<nPoint;i++){
vel[i] += dvel[i];
pos[i] += dpo [i]t;
}
}
// --- low-precision relaxation
void evalTrussForcesLinearized(){
for(int ib=0;ib<Bond;ib++){
int2 b = bond2point[ib];
float3 h = hbs[ib];
float3 dl = dl0s[ib] + dot( h, dpos[b.y]-dpos[b.x] );
float3 f = h*(dl*k);
forces[b.x] += f;
forces[b.y] -= f;
}
}
void movePointsLinearized(){
for(int i=0;i<nPoint;i++){
// ToDo: here may be done another step of linearization ( assuming movement by constant velocity? )
// e.g. nerby point may move with fast velocity in the same direction. We may subtract this velocity to avoid large dpos[] ?
dvel[i] += forces[i]*(dt/m);
dpos[i] += dvel [i]*dt;
}
}