GCC Code Coverage Report


Directory: ./
File: include/pinocchio/algorithm/pgs-solver.hxx
Date: 2024-08-27 18:20:05
Exec Total Coverage
Lines: 0 66 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //
2 // Copyright (c) 2022 INRIA
3 //
4
5 #ifndef __pinocchio_algorithm_pgs_solver_hxx__
6 #define __pinocchio_algorithm_pgs_solver_hxx__
7
8 #include <limits>
9 #include "pinocchio/algorithm/constraints/coulomb-friction-cone.hpp"
10
11 namespace pinocchio
12 {
13 template<typename _Scalar>
14 template<
15 typename MatrixLike,
16 typename VectorLike,
17 typename ConstraintAllocator,
18 typename VectorLikeOut>
19 bool PGSContactSolverTpl<_Scalar>::solve(
20 const MatrixLike & G,
21 const Eigen::MatrixBase<VectorLike> & g,
22 const std::vector<CoulombFrictionConeTpl<Scalar>, ConstraintAllocator> & cones,
23 const Eigen::DenseBase<VectorLikeOut> & x_sol,
24 const Scalar over_relax)
25
26 {
27 typedef CoulombFrictionConeTpl<Scalar> CoulombFrictionCone;
28 typedef Eigen::Matrix<Scalar, 2, 1> Vector2;
29 typedef Eigen::Matrix<Scalar, 3, 1> Vector3;
30 // typedef Eigen::Matrix<Scalar,6,1> Vector6;
31
32 PINOCCHIO_CHECK_INPUT_ARGUMENT(
33 over_relax < Scalar(2) && over_relax > Scalar(0), "over_relax should lie in ]0,2[.")
34 PINOCCHIO_CHECK_ARGUMENT_SIZE(g.size(), this->getProblemSize());
35 PINOCCHIO_CHECK_ARGUMENT_SIZE(G.rows(), this->getProblemSize());
36 PINOCCHIO_CHECK_ARGUMENT_SIZE(G.cols(), this->getProblemSize());
37 PINOCCHIO_CHECK_ARGUMENT_SIZE(x_sol.size(), this->getProblemSize());
38
39 const size_t nc = cones.size(); // num constraints
40
41 int it = 0;
42 PINOCCHIO_EIGEN_MALLOC_NOT_ALLOWED();
43
44 #ifdef PINOCCHIO_WITH_HPP_FCL
45 timer.start();
46 #endif // PINOCCHIO_WITH_HPP_FCL
47
48 Scalar complementarity, proximal_metric, dual_feasibility;
49 bool abs_prec_reached = false, rel_prec_reached = false;
50 x = x_sol;
51 Scalar x_previous_norm_inf = x.template lpNorm<Eigen::Infinity>();
52 for (; it < this->max_it; ++it)
53 {
54 x_previous = x;
55 complementarity = Scalar(0);
56 dual_feasibility = Scalar(0);
57 for (size_t cone_id = 0; cone_id < nc; ++cone_id)
58 {
59 Vector3 velocity; // tmp variable
60 const Eigen::DenseIndex row_id = 3 * cone_id;
61 const CoulombFrictionCone & cone = cones[cone_id];
62
63 const auto G_block = G.template block<3, 3>(row_id, row_id, 3, 3);
64 auto x_segment = x.template segment<3>(row_id);
65
66 velocity.noalias() = G.template middleRows<3>(row_id) * x + g.template segment<3>(row_id);
67
68 // Normal update
69 Scalar & fz = x_segment.coeffRef(2);
70 const Scalar fz_previous = fz;
71 fz -= Scalar(over_relax / G_block.coeff(2, 2)) * velocity[2];
72 fz = math::max(Scalar(0), fz);
73
74 // Account for the fz updated value
75 velocity += G_block.col(2) * (fz - fz_previous);
76
77 // Tangential update
78 const Scalar min_D_tangent = math::min(G_block.coeff(0, 0), G_block.coeff(1, 1));
79 auto f_tangent = x_segment.template head<2>();
80 const Vector2 f_tangent_previous = f_tangent;
81
82 assert(min_D_tangent > 0 && "min_D_tangent is zero");
83 f_tangent -= over_relax / min_D_tangent * velocity.template head<2>();
84 const Scalar f_tangent_norm = f_tangent.norm();
85
86 const Scalar mu_fz = cone.mu * fz;
87 if (f_tangent_norm > mu_fz) // Project in the circle of radius mu_fz
88 f_tangent *= mu_fz / f_tangent_norm;
89
90 // Account for the f_tangent updated value
91 velocity.noalias() = G_block.template leftCols<2>() * (f_tangent - f_tangent_previous);
92
93 // Compute problem feasibility
94 Scalar contact_complementarity = cone.computeContactComplementarity(velocity, x_segment);
95 assert(
96 contact_complementarity >= Scalar(0) && "contact_complementarity should be positive");
97 complementarity = math::max(complementarity, contact_complementarity);
98 velocity += cone.computeNormalCorrection(velocity);
99 const Vector3 velocity_proj = cone.dual().project(velocity) - velocity;
100 Scalar contact_dual_feasibility = velocity_proj.norm();
101 dual_feasibility = math::max(dual_feasibility, contact_dual_feasibility);
102 }
103
104 // Checking stopping residual
105 if (
106 check_expression_if_real<Scalar, false>(complementarity <= this->absolute_precision)
107 && check_expression_if_real<Scalar, false>(dual_feasibility <= this->absolute_precision))
108 abs_prec_reached = true;
109 else
110 abs_prec_reached = false;
111
112 proximal_metric = (x - x_previous).template lpNorm<Eigen::Infinity>();
113 const Scalar x_norm_inf = x.template lpNorm<Eigen::Infinity>();
114 if (check_expression_if_real<Scalar, false>(
115 proximal_metric
116 <= this->relative_precision * math::max(x_norm_inf, x_previous_norm_inf)))
117 rel_prec_reached = true;
118 else
119 rel_prec_reached = false;
120
121 if (abs_prec_reached || rel_prec_reached)
122 break;
123
124 x_previous_norm_inf = x_norm_inf;
125 }
126
127 #ifdef PINOCCHIO_WITH_HPP_FCL
128 timer.stop();
129 #endif // PINOCCHIO_WITH_HPP_FCL
130
131 PINOCCHIO_EIGEN_MALLOC_ALLOWED();
132
133 this->absolute_residual = math::max(complementarity, dual_feasibility);
134 this->relative_residual = proximal_metric;
135 this->it = it;
136 x_sol.const_cast_derived() = x;
137
138 if (abs_prec_reached || rel_prec_reached)
139 return true;
140
141 return false;
142 }
143 } // namespace pinocchio
144
145 #endif // ifndef __pinocchio_algorithm_pgs_solver_hxx__
146