@@ -164,7 +164,7 @@ Eigen::VectorXd FrictionPotential::smooth_contact_force(
164164
165165 tbb::enumerable_thread_specific<Eigen::VectorXd> storage (
166166 Eigen::VectorXd::Zero (velocities.size ()));
167-
167+
168168 tbb::parallel_for (
169169 tbb::blocked_range<size_t >(size_t (0 ), collisions.size ()),
170170 [&](const tbb::blocked_range<size_t >& r) {
@@ -176,8 +176,8 @@ Eigen::VectorXd FrictionPotential::smooth_contact_force(
176176 local_force = smooth_contact_force (
177177 collision, collision.dof (rest_positions, edges, faces),
178178 collision.dof (lagged_displacements, edges, faces),
179- collision.dof (velocities, edges, faces), //
180- dmin, no_mu);
179+ collision.dof (velocities, edges, faces),
180+ no_mu);
181181
182182 const std::array<long , 4 > vis =
183183 collision.vertex_ids (mesh.edges (), mesh.faces ());
@@ -197,7 +197,7 @@ Eigen::SparseMatrix<double> FrictionPotential::smooth_contact_force_jacobian(
197197 const Eigen::MatrixXd& rest_positions,
198198 const Eigen::MatrixXd& lagged_displacements,
199199 const Eigen::MatrixXd& velocities,
200- const ParameterType & params,
200+ const ParameterType& params,
201201 const DiffWRT wrt,
202202 const double dmin) const
203203{
@@ -213,6 +213,8 @@ Eigen::SparseMatrix<double> FrictionPotential::smooth_contact_force_jacobian(
213213 tbb::enumerable_thread_specific<std::vector<Eigen::Triplet<double >>>
214214 storage;
215215
216+ const Eigen::MatrixXd lagged_positions = rest_positions + lagged_displacements;
217+
216218 tbb::parallel_for (
217219 tbb::blocked_range<size_t >(size_t (0 ), collisions.size ()),
218220 [&](const tbb::blocked_range<size_t >& r) {
@@ -221,15 +223,22 @@ Eigen::SparseMatrix<double> FrictionPotential::smooth_contact_force_jacobian(
221223 for (size_t i = r.begin (); i < r.end (); i++) {
222224 const FrictionCollision& collision = collisions[i];
223225
224- // This jacobian doesn't include the derivatives of normal contact force
226+ // This jacobian doesn't include the derivatives of normal
227+ // contact force
225228 const MatrixMax<
226229 double , FrictionPotential::element_size,
227230 FrictionPotential::element_size>
228- local_force_jacobian = smooth_contact_force_jacobian (
229- collision, collision.dof (rest_positions, edges, faces),
230- collision.dof (lagged_displacements, edges, faces),
231- collision.dof (velocities, edges, faces), //
232- wrt, dmin);
231+ local_force_jacobian =
232+ collision.normal_force_magnitude
233+ * force_jacobian_unit (
234+ collision,
235+ collision.dof (lagged_positions, edges, faces),
236+ collision.dof (velocities, edges, faces), wrt);
237+ // smooth_contact_force_jacobian(
238+ // collision, collision.dof(rest_positions, edges, faces),
239+ // collision.dof(lagged_displacements, edges, faces),
240+ // collision.dof(velocities, edges, faces), //
241+ // wrt);
233242
234243 const std::array<long , 4 > vis =
235244 collision.vertex_ids (mesh.edges (), mesh.faces ());
@@ -245,35 +254,42 @@ Eigen::SparseMatrix<double> FrictionPotential::smooth_contact_force_jacobian(
245254 local_force = smooth_contact_force (
246255 collision, collision.dof (rest_positions, edges, faces),
247256 collision.dof (lagged_displacements, edges, faces),
248- collision.dof (velocities, edges, faces), //
249- dmin, false );
250-
251- std::cout << " local fric force " << local_force.transpose () << " \n\n " ;
257+ collision.dof (velocities, edges, faces),
258+ false , true );
252259
260+ // normal_force_grad is the gradient of contact force norm
253261 Eigen::VectorXd normal_force_grad;
254262 std::vector<long > cc_vert_ids;
255- Eigen::MatrixXd Xt = rest_positions + lagged_displacements;
256- if (dim == 2 )
257- {
258- auto cc = collision.smooth_collision_2d ;
259- const Eigen::VectorXd contact_grad = cc->gradient (cc->dof (Xt, edges, faces), params);
260- const Eigen::MatrixXd contact_hess = cc->hessian (cc->dof (Xt, edges, faces), params);
261- normal_force_grad = (1 / contact_grad.squaredNorm ()) * (contact_hess * contact_grad);
262- auto tmp_ids = cc->vertex_ids (edges, faces);
263- cc_vert_ids = std::vector (tmp_ids.begin (), tmp_ids.end ());
264- }
265- else if (dim == 3 )
266263 {
267- auto cc = collision.smooth_collision_3d ;
268- const Eigen::VectorXd contact_grad = cc->gradient (cc->dof (Xt, edges, faces), params);
269- const Eigen::MatrixXd contact_hess = cc->hessian (cc->dof (Xt, edges, faces), params);
270- normal_force_grad = (1 / contact_grad.squaredNorm ()) * (contact_hess * contact_grad);
271- auto tmp_ids = cc->vertex_ids (edges, faces);
272- cc_vert_ids = std::vector (tmp_ids.begin (), tmp_ids.end ());
264+ Eigen::MatrixXd Xt = rest_positions + lagged_displacements;
265+ if (dim == 2 ) {
266+ auto cc = collision.smooth_collision_2d ;
267+ const Eigen::VectorXd contact_grad =
268+ cc->gradient (cc->dof (Xt, edges, faces), params);
269+ const Eigen::MatrixXd contact_hess =
270+ cc->hessian (cc->dof (Xt, edges, faces), params);
271+ normal_force_grad = (1 / contact_grad.norm ())
272+ * (contact_hess * contact_grad);
273+ auto tmp_ids = cc->vertex_ids (edges, faces);
274+ cc_vert_ids =
275+ std::vector (tmp_ids.begin (), tmp_ids.end ());
276+ } else if (dim == 3 ) {
277+ auto cc = collision.smooth_collision_3d ;
278+ const Eigen::VectorXd contact_grad =
279+ cc->gradient (cc->dof (Xt, edges, faces), params);
280+ const Eigen::MatrixXd contact_hess =
281+ cc->hessian (cc->dof (Xt, edges, faces), params);
282+ normal_force_grad = (1 / contact_grad.norm ())
283+ * (contact_hess * contact_grad);
284+ auto tmp_ids = cc->vertex_ids (edges, faces);
285+ cc_vert_ids =
286+ std::vector (tmp_ids.begin (), tmp_ids.end ());
287+ }
273288 }
274289
275290 local_jacobian_to_global_triplets (
276- local_force * normal_force_grad.transpose (), vis, cc_vert_ids, dim, jac_triplets);
291+ local_force * normal_force_grad.transpose (), vis,
292+ cc_vert_ids, dim, jac_triplets);
277293 }
278294 });
279295
@@ -291,10 +307,12 @@ Eigen::SparseMatrix<double> FrictionPotential::smooth_contact_force_jacobian(
291307 // if (wrt == DiffWRT::REST_POSITIONS) {
292308 // for (int i = 0; i < collisions.size(); i++) {
293309 // const FrictionCollision& collision = collisions[i];
294- // assert(collision.weight_gradient.size() == rest_positions.size());
295- // if (collision.weight_gradient.size() != rest_positions.size()) {
310+ // assert(collision.weight_gradient.size() ==
311+ // rest_positions.size()); if (collision.weight_gradient.size() !=
312+ // rest_positions.size()) {
296313 // throw std::runtime_error(
297- // "Shape derivative is not computed for friction collision!");
314+ // "Shape derivative is not computed for friction
315+ // collision!");
298316 // }
299317
300318 // Vector<double, -1, FrictionPotential::element_size> local_force =
@@ -564,6 +582,87 @@ FrictionPotential::force_jacobian(
564582 // Compute β
565583 const VectorMax2d beta = collision.compute_closest_point (lagged_positions);
566584
585+ // Compute Γ
586+ const MatrixMax<double , 3 , FrictionPotential::element_size> Gamma =
587+ collision.relative_velocity_matrix (beta);
588+
589+ // Compute T = ΓᵀP
590+ const MatrixMax<double , FrictionPotential::element_size, 2 > T =
591+ Gamma.transpose () * P;
592+
593+ // Compute τ = PᵀΓv
594+ const VectorMax2d tau = P.transpose () * Gamma * velocities;
595+
596+ // Compute f₁(‖τ‖)/‖τ‖
597+ const double tau_norm = tau.norm ();
598+ const double f1_over_norm_tau = f1_SF_over_x (tau_norm, epsv ());
599+
600+ // Premultiplied values
601+ const Vector<double , -1 , FrictionPotential::element_size> T_times_tau =
602+ T * tau;
603+
604+ // ------------------------------------------------------------------------
605+ // Compute J = ∇F = ∇(-μ N f₁(‖τ‖)/‖τ‖ T τ)
606+ MatrixMax<
607+ double , FrictionPotential::element_size,
608+ FrictionPotential::element_size>
609+ J = MatrixMax<
610+ double , FrictionPotential::element_size,
611+ FrictionPotential::element_size>::Zero (n, n);
612+
613+ // = -μ f₁(‖τ‖)/‖τ‖ (T τ) [∇N]ᵀ
614+ if (need_jac_N_or_T) {
615+ J = f1_over_norm_tau * T_times_tau * grad_N.transpose ();
616+ }
617+
618+ // NOTE: ∇ₓw(x) is not local to the collision pair (i.e., it involves more
619+ // than the 4 collisioning vertices), so we do not have enough information
620+ // here to compute the gradient. Instead this should be handled outside of
621+ // the function. For a simple multiplicitive model (∑ᵢ wᵢ Fᵢ) this can be
622+ // done easily.
623+ J *= -collision.weight * collision.mu ;
624+
625+ J += N
626+ * force_jacobian_unit (
627+ collision, lagged_positions, velocities, wrt);
628+
629+ return J;
630+ }
631+
632+ MatrixMax<
633+ double ,
634+ FrictionPotential::element_size,
635+ FrictionPotential::element_size>
636+ FrictionPotential::force_jacobian_unit (
637+ const FrictionCollision& collision,
638+ const Vector<double , -1 , FrictionPotential::element_size>&
639+ lagged_positions, // = x + u^t
640+ const Vector<double , -1 , FrictionPotential::element_size>&
641+ velocities, // = v
642+ const DiffWRT wrt) const
643+ {
644+ // x is the rest position
645+ // u is the displacment at the begginging of the lagged solve
646+ // v is the current velocity
647+ //
648+ // τ = T(x + u)ᵀv is the tangential sliding velocity
649+ // F(x, u, v) = -μ f₁(‖τ‖)/‖τ‖ T(x + u) τ
650+ //
651+ // Compute ∇F
652+ assert (lagged_positions.size () == velocities.size ());
653+ const int n = lagged_positions.size ();
654+ const int dim = n / collision.num_vertices ();
655+ assert (n % collision.num_vertices () == 0 );
656+
657+ const bool need_jac_N_or_T = wrt != DiffWRT::VELOCITIES;
658+
659+ // Compute P
660+ const MatrixMax<double , 3 , 2 > P =
661+ collision.compute_tangent_basis (lagged_positions);
662+
663+ // Compute β
664+ const VectorMax2d beta = collision.compute_closest_point (lagged_positions);
665+
567666 // Compute Γ
568667 const MatrixMax<double , 3 , FrictionPotential::element_size> Gamma =
569668 collision.relative_velocity_matrix (beta);
@@ -653,25 +752,20 @@ FrictionPotential::force_jacobian(
653752 double , FrictionPotential::element_size,
654753 FrictionPotential::element_size>::Zero (n, n);
655754
656- // = -μ f₁(‖τ‖)/‖τ‖ (T τ) [∇N]ᵀ
657- if (need_jac_N_or_T) {
658- J = f1_over_norm_tau * T_times_tau * grad_N.transpose ();
659- }
660-
661755 // + -μ N T τ [∇(f₁(‖τ‖)/‖τ‖)]
662- J += N * T_times_tau * grad_f1_over_norm_tau.transpose ();
756+ J += T_times_tau * grad_f1_over_norm_tau.transpose ();
663757
664758 // + -μ N f₁(‖τ‖)/‖τ‖ [∇T] τ
665759 if (need_jac_N_or_T) {
666- const VectorMax2d scaled_tau = N * f1_over_norm_tau * tau;
760+ const VectorMax2d scaled_tau = f1_over_norm_tau * tau;
667761 for (int i = 0 ; i < n; i++) {
668762 // ∂J/∂xᵢ = ∂T/∂xᵢ * τ
669763 J.col (i) += jac_T.middleRows (i * n, n) * scaled_tau;
670764 }
671765 }
672766
673767 // + -μ N f₁(‖τ‖)/‖τ‖ T [∇τ]
674- J += N * f1_over_norm_tau * T * jac_tau;
768+ J += f1_over_norm_tau * T * jac_tau;
675769
676770 // NOTE: ∇ₓw(x) is not local to the collision pair (i.e., it involves more
677771 // than the 4 collisioning vertices), so we do not have enough information
@@ -683,16 +777,17 @@ FrictionPotential::force_jacobian(
683777 return J;
684778}
685779
686- Vector<double , -1 , FrictionPotential::element_size> FrictionPotential::smooth_contact_force (
780+ Vector<double , -1 , FrictionPotential::element_size>
781+ FrictionPotential::smooth_contact_force (
687782 const FrictionCollision& collision,
688783 const Vector<double , -1 , FrictionPotential::element_size>&
689784 rest_positions, // = x
690785 const Vector<double , -1 , FrictionPotential::element_size>&
691786 lagged_displacements, // = u
692787 const Vector<double , -1 , FrictionPotential::element_size>&
693788 velocities, // = v
694- const double dmin ,
695- const bool no_mu ) const
789+ const bool no_mu ,
790+ const bool no_contact_force_multiplier ) const
696791{
697792 // x is the rest position
698793 // u is the displacment at the begginging of the lagged solve
@@ -739,21 +834,19 @@ Vector<double, -1, FrictionPotential::element_size> FrictionPotential::smooth_co
739834
740835 // F = -μ N f₁(‖τ‖)/‖τ‖ T τ
741836 // NOTE: no_mu -> leave mu out of this function (i.e., assuming mu = 1)
742- return -collision.weight * (no_mu ? 1.0 : collision.mu ) * N
743- * f1_over_norm_tau * T * tau;
837+ return -collision.weight * (no_mu ? 1.0 : collision.mu )
838+ * (no_contact_force_multiplier ? 1.0 : N) * f1_over_norm_tau * T * tau;
744839}
745840
746- Eigen::MatrixXd
747- FrictionPotential::smooth_contact_force_jacobian (
841+ Eigen::MatrixXd FrictionPotential::smooth_contact_force_jacobian (
748842 const FrictionCollision& collision,
749843 const Vector<double , -1 , FrictionPotential::element_size>&
750844 rest_positions, // = x
751845 const Vector<double , -1 , FrictionPotential::element_size>&
752846 lagged_displacements, // = u
753847 const Vector<double , -1 , FrictionPotential::element_size>&
754848 velocities, // = v
755- const DiffWRT wrt,
756- const double dmin) const
849+ const DiffWRT wrt) const
757850{
758851 // x is the rest position
759852 // u is the displacment at the begginging of the lagged solve
@@ -779,7 +872,7 @@ FrictionPotential::smooth_contact_force_jacobian(
779872 rest_positions + lagged_displacements; // = x + u
780873 const bool need_jac_N_or_T = wrt != DiffWRT::VELOCITIES;
781874
782- // Compute ∇N
875+ // Compute ∇N -- commented, compute it outside
783876 // Vector<double, -1, FrictionPotential::element_size> grad_N;
784877 // if (need_jac_N_or_T) {
785878 // // ∇ₓN = ∇ᵤN
0 commit comments