code clean up and optimization

This commit is contained in:
Xuchen Han
2019-09-15 12:06:28 -07:00
parent 109d9353af
commit 403eb62dfa
10 changed files with 86 additions and 147 deletions

View File

@@ -22,7 +22,7 @@
btDeformableBodySolver::btDeformableBodySolver()
: m_numNodes(0)
, m_cg(20)
, m_maxNewtonIterations(5)
, m_maxNewtonIterations(10)
, m_newtonTolerance(1e-4)
, m_lineSearch(true)
{
@@ -82,13 +82,12 @@ void btDeformableBodySolver::solveDeformableConstraints(btScalar solverdt)
do {
scale *= beta;
if (scale < 1e-8) {
//std::cout << "Could not find sufficient descent!" << std::endl;
return;
}
updateEnergy(scale);
f1 = m_objective->totalEnergy()+kineticEnergy();
f2 = f0 - alpha * scale * inner_product;
} while (!(f1 < f2)); // if anything here is nan then the search continues
} while (!(f1 < f2+SIMD_EPSILON)); // if anything here is nan then the search continues
revertDv();
updateDv(scale);
}
@@ -97,7 +96,6 @@ void btDeformableBodySolver::solveDeformableConstraints(btScalar solverdt)
computeStep(m_ddv, m_residual);
updateDv();
}
for (int j = 0; j < m_numNodes; ++j)
{
m_ddv[j].setZero();
@@ -157,7 +155,8 @@ btScalar btDeformableBodySolver::computeDescentStep(TVStack& ddv, const TVStack&
btScalar relative_tolerance = btMin(btScalar(0.5), std::sqrt(btMax(m_objective->computeNorm(residual), m_newtonTolerance)));
m_cg.solve(*m_objective, ddv, residual, relative_tolerance, false);
btScalar inner_product = m_cg.dot(residual, m_ddv);
btScalar tol = 1e-5 * m_objective->computeNorm(residual) * m_objective->computeNorm(m_ddv);
btScalar tol = 1e-3 * m_objective->computeNorm(residual) * m_objective->computeNorm(m_ddv);
btScalar res_norm = m_objective->computeNorm(residual);
if (inner_product < -tol)
{
std::cout << "Looking backwards!" << std::endl;
@@ -170,7 +169,6 @@ btScalar btDeformableBodySolver::computeDescentStep(TVStack& ddv, const TVStack&
else if (std::abs(inner_product) < tol)
{
std::cout << "Gradient Descent!" << std::endl;
btScalar res_norm = m_objective->computeNorm(residual);
btScalar scale = m_objective->computeNorm(m_ddv) / res_norm;
for (int i = 0; i < m_ddv.size();++i)
{
@@ -236,23 +234,7 @@ void btDeformableBodySolver::setConstraints()
btScalar btDeformableBodySolver::solveContactConstraints()
{
BT_PROFILE("setConstraint");
for (int i = 0; i < m_dv.size();++i)
{
m_dv[i].setZero();
}
btScalar maxSquaredResidual = m_objective->projection.update();
// m_objective->enforceConstraint(m_dv);
// m_objective->updateVelocity(m_dv);
int counter = 0;
for (int i = 0; i < m_softBodySet.size(); ++i)
{
btSoftBody* psb = m_softBodySet[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
m_dv[counter] = psb->m_nodes[j].m_v - m_backupVelocity[counter];
++counter;
}
}
return maxSquaredResidual;
}
@@ -304,7 +286,7 @@ void btDeformableBodySolver::backupVelocity()
}
}
void btDeformableBodySolver::backupVn()
void btDeformableBodySolver::setupDeformableSolve(bool implicit)
{
int counter = 0;
for (int i = 0; i < m_softBodySet.size(); ++i)
@@ -312,17 +294,12 @@ void btDeformableBodySolver::backupVn()
btSoftBody* psb = m_softBodySet[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
// Here:
// dv = 0 for nodes not in constraints
// dv = v_{n+1} - v_{n+1}^* for nodes in constraints
if (m_objective->projection.m_projectionsDict.find(psb->m_nodes[j].index)!=NULL)
if (implicit)
{
m_dv[counter] += m_backupVelocity[counter] - psb->m_nodes[j].m_vn;
m_backupVelocity[counter] = psb->m_nodes[j].m_vn;
}
// Now:
// dv = 0 for nodes not in constraints
// dv = v_{n+1} - v_n for nodes in constraints
m_backupVelocity[counter++] = psb->m_nodes[j].m_vn;
m_dv[counter] = psb->m_nodes[j].m_v - m_backupVelocity[counter];
++counter;
}
}
}

View File

@@ -77,13 +77,14 @@ public:
void predictDeformableMotion(btSoftBody* psb, btScalar dt);
void backupVelocity();
void backupVn();
void setupDeformableSolve(bool implicit);
void revertVelocity();
void updateVelocity();
bool updateNodes();
void computeStep(TVStack& dv, const TVStack& residual);
btScalar computeDescentStep(TVStack& ddv, const TVStack& residual);
virtual void predictMotion(btScalar solverdt);

View File

@@ -92,8 +92,6 @@ btScalar btDeformableRigidContactConstraint::solveConstraint()
btVector3 vb = getVb();
btVector3 vr = vb - va;
const btScalar dn = btDot(vr, cti.m_normal);
// if (dn > 0)
// return 0;
// dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
btScalar residualSquare = dn*dn;
btVector3 impulse = m_contact->m_c0 * vr;
@@ -136,8 +134,10 @@ btScalar btDeformableRigidContactConstraint::solveConstraint()
}
}
impulse = impulse_normal + impulse_tangent;
// apply impulse to deformable nodes involved and change their velocities
applyImpulse(impulse);
// apply impulse to the rigid/multibodies involved and change their velocities
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
btRigidBody* rigidCol = 0;

View File

@@ -174,12 +174,6 @@ void btDeformableContactProjection::enforceConstraint(TVStack& x)
btAlignedObjectArray<btDeformableFaceRigidContactConstraint*>& constraintsList = *m_faceRigidConstraints.getAtIndex(index);
// i is node index
int i = m_faceRigidConstraints.getKeyAtIndex(index).getUid1();
int numConstraints = 1;
// int numConstraints = constraintsList.size();
// if (m_nodeRigidConstraints.find(i) != NULL)
// {
// numConstraints += m_nodeRigidConstraints[i]->size();
// }
for (int j = 0; j < constraintsList.size(); ++j)
{
const btDeformableFaceRigidContactConstraint* constraint = constraintsList[j];
@@ -194,7 +188,7 @@ void btDeformableContactProjection::enforceConstraint(TVStack& x)
break;
}
}
x[i] += constraint->getDv(node) / btScalar(numConstraints);
x[i] += constraint->getDv(node);
}
}
// todo xuchenhan@: add deformable deformable constraints' contribution to dv
@@ -206,31 +200,6 @@ void btDeformableContactProjection::enforceConstraint(TVStack& x)
int i = m_staticConstraints.getKeyAtIndex(index).getUid1();
x[i] = constraint.getDv(constraint.m_node);
}
//
// for (int i = 0; i < x.size(); ++i)
// {
// x[i].setZero();
// if (m_staticConstraints.find(i) != NULL)
// {
// // if a node is fixed, dv = 0
// continue;
// }
// if (m_nodeRigidConstraints.find(i) != NULL)
// {
// btAlignedObjectArray<btDeformableNodeRigidContactConstraint>& constraintsList = *m_nodeRigidConstraints[i];
// for (int j = 0; j < constraintsList.size(); ++j)
// {
// const btDeformableNodeRigidContactConstraint& constraint = constraintsList[j];
//// x[i] += constraint.getDv(m_nodes->at(i));
// x[i] += constraint.getDv(constraint.getContact()->m_node);
// }
// }
// todo xuchenhan@
// if (m_faceRigidConstraints.find(i) != NULL)
// {
//
// }
// }
}
void btDeformableContactProjection::project(TVStack& x)
@@ -376,6 +345,7 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
}
}
// add friction contribution from Face vs. Node
if (m_nodeRigidConstraints.find(i) != NULL)
{
btAlignedObjectArray<btDeformableNodeRigidContactConstraint>& constraintsList = *m_nodeRigidConstraints[i];
@@ -388,7 +358,8 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
f[i] += constraint.getDv(node)* (1./node->m_im);
}
}
// todo xuchenhan@
// add friction contribution from Face vs. Rigid
if (m_faceRigidConstraints.find(i) != NULL)
{
btAlignedObjectArray<btDeformableFaceRigidContactConstraint*>& constraintsList = *m_faceRigidConstraints[i];
@@ -398,40 +369,17 @@ void btDeformableContactProjection::applyDynamicFriction(TVStack& f)
btSoftBody::Face* face = constraint->getContact()->m_face;
// it's ok to add the friction force generated by the entire impulse here because the normal component of the residual will be projected out anyway.
// todo xuchenhan@: figure out the index for m_faceRigidConstraints
// f[i] += constraint.getDv(face->m_n[0])* (1./face->m_n[0]->m_im);
// f[i] += constraint.getDv(face->m_n[1])* (1./face->m_n[1]->m_im);
// f[i] += constraint.getDv(face->m_n[2])* (1./face->m_n[2]->m_im);
for (int k = 0; k < 3; ++k)
{
if (face->m_n[0]->index == i)
{
f[i] += constraint->getDv(face->m_n[k])* (1./face->m_n[k]->m_im);
break;
}
}
}
}
}
// for (int index = 0; index < m_constraints.size(); ++index)
// {
// const DeformableContactConstraint& constraint = *m_constraints.getAtIndex(index);
// const btSoftBody::Node* node = constraint.m_node;
// if (node == NULL)
// continue;
// size_t i = m_constraints.getKeyAtIndex(index).getUid1();
// bool has_static_constraint = false;
//
// // apply dynamic friction force (scaled by dt) if the node does not have static friction constraint
// for (int j = 0; j < constraint.m_static.size(); ++j)
// {
// if (constraint.m_static[j])
// {
// has_static_constraint = true;
// break;
// }
// }
// for (int j = 0; j < constraint.m_total_tangent_dv.size(); ++j)
// {
// btVector3 friction_force = constraint.m_total_tangent_dv[j] * (1./node->m_im);
// if (!has_static_constraint)
// {
// f[i] += friction_force;
// }
// }
// }
}
void btDeformableContactProjection::reinitialize(bool nodeUpdated)

View File

@@ -39,7 +39,7 @@ btScalar btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlyIteration
printf("residual = %f at iteration #%d\n", m_leastSquaresResidual, iteration);
#endif
m_analyticsData.m_numSolverCalls++;
std::cout << m_leastSquaresResidual << std::endl;
std::cout << "Contact Residual = " << m_leastSquaresResidual << std::endl;
m_analyticsData.m_numIterationsUsed = iteration+1;
m_analyticsData.m_islandId = -2;
if (numBodies>0)

View File

@@ -185,20 +185,21 @@ void btDeformableMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep)
void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep)
{
// save v_{n+1}^* velocity after explicit forces
m_deformableBodySolver->backupVelocity();
if (!m_implicit)
{
// save v_{n+1}^* velocity after explicit forces
m_deformableBodySolver->backupVelocity();
}
// set up constraints among multibodies and between multibodies and deformable bodies
setupConstraints();
solveMultiBodyRelatedConstraints();
m_deformableBodySolver->m_objective->projection.setProjection();
if (m_implicit)
{
// at this point dv = v_{n+1} - v_{n+1}^*
// modify dv such that dv = v_{n+1} - v_n
// modify m_backupVelocity so that it stores v_n instead of v_{n+1}^* as needed by Newton
m_deformableBodySolver->backupVn();
}
// for explicit scheme, m_backupVelocity = v_{n+1}^*
// for implicit scheme, m_backupVelocity = v_n
// Here, set dv = v_{n+1} - v_n for nodes in contact
m_deformableBodySolver->setupDeformableSolve(m_implicit);
// At this point, dv should be golden for nodes in contact
m_deformableBodySolver->solveDeformableConstraints(timeStep);

View File

@@ -31,7 +31,7 @@ public:
m_lambda_damp = damping * m_lambda;
}
btDeformableNeoHookeanForce(btScalar mu, btScalar lambda, btScalar damping = 0.05): m_mu(mu), m_lambda(lambda)
btDeformableNeoHookeanForce(btScalar mu, btScalar lambda, btScalar damping = 0): m_mu(mu), m_lambda(lambda)
{
m_mu_damp = damping * m_mu;
m_lambda_damp = damping * m_lambda;
@@ -50,6 +50,8 @@ public:
virtual void addScaledDampingForce(btScalar scale, TVStack& force)
{
if (m_mu_damp == 0 && m_lambda_damp == 0)
return;
int numNodes = getNumNodes();
btAssert(numNodes <= force.size());
btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
@@ -69,10 +71,10 @@ public:
size_t id3 = node3->index;
btMatrix3x3 dF = DsFromVelocity(node0, node1, node2, node3) * tetra.m_Dm_inverse;
btMatrix3x3 dP;
firstPiolaDampingDifferential(tetra.m_F, dF, dP);
firstPiolaDampingDifferential(psb->m_tetraScratches[j], dF, dP);
btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
// damping force differential
btScalar scale1 = scale * tetra.m_element_measure;
force[id0] -= scale1 * df_on_node0;
@@ -89,25 +91,22 @@ public:
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_tetras.size(); ++j)
for (int j = 0; j < psb->m_tetraScratches.size(); ++j)
{
btSoftBody::Tetra& tetra = psb->m_tetras[j];
energy += tetra.m_element_measure * elasticEnergyDensity(tetra);
btSoftBody::TetraScratch& s = psb->m_tetraScratches[j];
energy += tetra.m_element_measure * elasticEnergyDensity(s);
}
}
return energy;
}
double elasticEnergyDensity(const btSoftBody::Tetra& t)
double elasticEnergyDensity(const btSoftBody::TetraScratch& s)
{
double density = 0;
btMatrix3x3 F = t.m_F;
btMatrix3x3 C = F.transpose()*F;
double J = F.determinant();
double trace = C[0].getX() + C[1].getY() + C[2].getZ();
density += m_mu * 0.5 * (trace - 3.);
density += m_lambda * 0.5 * (J - 1. - 0.75 * m_mu / m_lambda)* (J - 1. - 0.75 * m_mu / m_lambda);
density -= m_mu * 0.5 * log(trace+1);
density += m_mu * 0.5 * (s.m_trace - 3.);
density += m_lambda * 0.5 * (s.m_J - 1. - 0.75 * m_mu / m_lambda)* (s.m_J - 1. - 0.75 * m_mu / m_lambda);
density -= m_mu * 0.5 * log(s.m_trace+1);
return density;
}
@@ -123,7 +122,7 @@ public:
{
btSoftBody::Tetra& tetra = psb->m_tetras[j];
btMatrix3x3 P;
firstPiola(tetra.m_F,P);
firstPiola(psb->m_tetraScratches[j],P);
btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
@@ -148,6 +147,8 @@ public:
virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
{
if (m_mu_damp == 0 && m_lambda_damp == 0)
return;
int numNodes = getNumNodes();
btAssert(numNodes <= df.size());
btVector3 grad_N_hat_1st_col = btVector3(-1,-1,-1);
@@ -167,10 +168,10 @@ public:
size_t id3 = node3->index;
btMatrix3x3 dF = Ds(id0, id1, id2, id3, dv) * tetra.m_Dm_inverse;
btMatrix3x3 dP;
firstPiolaDampingDifferential(tetra.m_F, dF, dP);
firstPiolaDampingDifferential(psb->m_tetraScratches[j], dF, dP);
btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
// damping force differential
btScalar scale1 = scale * tetra.m_element_measure;
df[id0] -= scale1 * df_on_node0;
@@ -202,7 +203,7 @@ public:
size_t id3 = node3->index;
btMatrix3x3 dF = Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
btMatrix3x3 dP;
firstPiolaDifferential(tetra.m_F, dF, dP);
firstPiolaDifferential(psb->m_tetraScratches[j], dF, dP);
btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
@@ -216,34 +217,25 @@ public:
}
}
void firstPiola(const btMatrix3x3& F, btMatrix3x3& P)
void firstPiola(const btSoftBody::TetraScratch& s, btMatrix3x3& P)
{
btMatrix3x3 C = F.transpose()*F;
btScalar J = F.determinant();
btScalar trace = C[0].getX() + C[1].getY() + C[2].getZ();
P = F * m_mu * ( 1. - 1. / (trace + 1.)) + F.adjoint().transpose() * (m_lambda * (J - 1.) - 0.75 * m_mu);
P = s.m_F * m_mu * ( 1. - 1. / (s.m_trace + 1.)) + s.m_cofF * (m_lambda * (s.m_J - 1.) - 0.75 * m_mu);
}
void firstPiolaDifferential(const btMatrix3x3& F, const btMatrix3x3& dF, btMatrix3x3& dP)
void firstPiolaDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
{
btScalar J = F.determinant();
btMatrix3x3 C = F.transpose()*F;
btScalar trace = C[0].getX() + C[1].getY() + C[2].getZ();
dP = dF * m_mu * ( 1. - 1. / (trace + 1.)) + F * (2*m_mu) * DotProduct(F, dF) * (1./((1.+trace)*(1.+trace)));
dP = dF * m_mu * ( 1. - 1. / (s.m_trace + 1.)) + s.m_F * (2*m_mu) * DotProduct(s.m_F, dF) * (1./((1.+s.m_trace)*(1.+s.m_trace)));
addScaledCofactorMatrixDifferential(F, dF, m_lambda*(J-1.) - 0.75*m_mu, dP);
dP += F.adjoint().transpose() * m_lambda * DotProduct(F.adjoint().transpose(), dF);
addScaledCofactorMatrixDifferential(s.m_F, dF, m_lambda*(s.m_J-1.) - 0.75*m_mu, dP);
dP += s.m_cofF * m_lambda * DotProduct(s.m_cofF, dF);
}
void firstPiolaDampingDifferential(const btMatrix3x3& F, const btMatrix3x3& dF, btMatrix3x3& dP)
void firstPiolaDampingDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
{
btScalar J = F.determinant();
btMatrix3x3 C = F.transpose()*F;
btScalar trace = C[0].getX() + C[1].getY() + C[2].getZ();
dP = dF * m_mu_damp * ( 1. - 1. / (trace + 1.)) + F * (2*m_mu_damp) * DotProduct(F, dF) * (1./((1.+trace)*(1.+trace)));
addScaledCofactorMatrixDifferential(F, dF, m_lambda_damp*(J-1.) - 0.75*m_mu_damp, dP);
dP += F.adjoint().transpose() * m_lambda_damp * DotProduct(F.adjoint().transpose(), dF);
dP = dF * m_mu_damp * ( 1. - 1. / (s.m_trace + 1.)) + s.m_F * (2*m_mu_damp) * DotProduct(s.m_F, dF) * (1./((1.+s.m_trace)*(1.+s.m_trace)));
addScaledCofactorMatrixDifferential(s.m_F, dF, m_lambda_damp*(s.m_J-1.) - 0.75*m_mu_damp, dP);
dP += s.m_cofF * m_lambda_damp * DotProduct(s.m_cofF, dF);
}
btScalar DotProduct(const btMatrix3x3& A, const btMatrix3x3& B)

View File

@@ -2905,6 +2905,13 @@ void btSoftBody::updateDeformation()
c1.getY(), c2.getY(), c3.getY(),
c1.getZ(), c2.getZ(), c3.getZ());
t.m_F = Ds * t.m_Dm_inverse;
btSoftBody::TetraScratch& s = m_tetraScratches[i];
s.m_F = t.m_F;
s.m_J = t.m_F.determinant();
btMatrix3x3 C = t.m_F.transpose()*t.m_F;
s.m_trace = C[0].getX() + C[1].getY() + C[2].getZ();
s.m_cofF = t.m_F.adjoint().transpose();
}
}
//
@@ -3431,7 +3438,7 @@ void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap
docollideFace.m_rigidBody = prb1;
docollideFace.dynmargin = basemargin + timemargin;
docollideFace.stamargin = basemargin;
// m_fdbvt.collideTV(m_fdbvt.m_root, volume, docollideFace);
m_fdbvt.collideTV(m_fdbvt.m_root, volume, docollideFace);
}
break;
}

View File

@@ -300,6 +300,16 @@ public:
btMatrix3x3 m_F;
btScalar m_element_measure;
};
/* TetraScratch */
struct TetraScratch
{
btMatrix3x3 m_F; // deformation gradient F
btScalar m_trace; // trace of F^T * F
btScalar m_J; // det(F)
btMatrix3x3 m_cofF; // cofactor of F
};
/* RContact */
struct RContact
{
@@ -745,6 +755,7 @@ public:
tFaceArray m_faces; // Faces
tFaceArray m_renderFaces; // Faces
tTetraArray m_tetras; // Tetras
btAlignedObjectArray<TetraScratch> m_tetraScratches;
tAnchorArray m_anchors; // Anchors
tRContactArray m_rcontacts; // Rigid contacts
btAlignedObjectArray<DeformableNodeRigidContact> m_nodeRigidContacts;

View File

@@ -1233,6 +1233,7 @@ if(face&&face[0])
}
}
psb->initializeDmInverse();
psb->m_tetraScratches.resize(psb->m_tetras.size());
printf("Nodes: %u\r\n", psb->m_nodes.size());
printf("Links: %u\r\n", psb->m_links.size());
printf("Faces: %u\r\n", psb->m_faces.size());
@@ -1374,6 +1375,7 @@ btSoftBody* btSoftBodyHelpers::CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo,
psb->initializeDmInverse();
psb->m_tetraScratches.resize(psb->m_tetras.size());
printf("Nodes: %u\r\n", psb->m_nodes.size());
printf("Links: %u\r\n", psb->m_links.size());
printf("Faces: %u\r\n", psb->m_faces.size());