Skip to content

Commit 79c3cb5

Browse files
committed
FIX: biais vector
1 parent 5e48e06 commit 79c3cb5

File tree

3 files changed

+97
-298
lines changed

3 files changed

+97
-298
lines changed

bioptim/examples/toy_examples/holonomic_constraints/test_frame_alignment_lagrange_2d.py renamed to bioptim/examples/toy_examples/holonomic_constraints/frame_alignment_lagrange_2d.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ def main():
170170
ocp, bio_model = prepare_ocp(biorbd_model_path=model_path, n_shooting=10, final_time=2.0)
171171

172172
solver = Solver.IPOPT()
173-
solver.set_linear_solver("ma57")
174173
sol = ocp.solve(solver)
175174

176175
print(f"Optimization finished in {sol.real_time_to_optimize:.2f} s")

bioptim/models/biorbd/holonomic_biorbd_model.py

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from biorbd_casadi import (
77
GeneralizedCoordinates,
88
)
9-
from casadi import MX, DM, vertcat, horzcat, Function, solve, rootfinder, inv, nlpsol
9+
from casadi import MX, DM, vertcat, horzcat, Function, solve, rootfinder, inv, nlpsol, jacobian
1010

1111
from .biorbd_model import BiorbdModel
1212
from ...models.protocols.holonomic_constraints import HolonomicConstraintsList
@@ -491,7 +491,79 @@ def biais_vector(self, q: MX, qdot: MX) -> MX:
491491
partitioned_constraints_jacobian_v = partitioned_constraints_jacobian[:, self.nb_independent_joints :]
492492
partitioned_constraints_jacobian_v_inv = inv(partitioned_constraints_jacobian_v)
493493

494-
return -partitioned_constraints_jacobian_v_inv @ self.holonomic_constraints_jacobian(qdot) @ qdot
494+
# return -partitioned_constraints_jacobian_v_inv @ self.holonomic_constraints_jacobian(qdot) @ qdot
495+
# return -partitioned_constraints_jacobian_v_inv @ self._holonomic_constraints_jacobian_time_derivative_finite_difference(q, qdot) @ qdot
496+
# return -partitioned_constraints_jacobian_v_inv @ self._holonomic_constraints_jacobian_time_derivative(q, qdot) @ qdot
497+
return -partitioned_constraints_jacobian_v_inv @ self.holonomic_constraints_double_derivative(q, qdot, MX())
498+
499+
500+
def _holonomic_constraints_jacobian_time_derivative_finite_difference(
501+
self, q: MX, qdot: MX, epsilon: float = 1e-8
502+
) -> MX:
503+
"""
504+
Compute Jdot = dJ/dt = (∂J/∂q) * qdot using finite differences.
505+
506+
Args:
507+
q: Configuration vector (n,)
508+
qdot: Velocity vector (n,)
509+
epsilon: Finite difference step size
510+
511+
Returns:
512+
Jdot: Time derivative of Jacobian (m, n) where m = number of constraints
513+
"""
514+
n = q.shape[0]
515+
J0 = self.holonomic_constraints_jacobian(q)
516+
m = J0.shape[0]
517+
518+
Jdot = MX.zeros(m, n)
519+
520+
for i in range(n):
521+
# Perturb only q_i
522+
q_plus = MX(q)
523+
q_plus[i] += epsilon
524+
J_plus = self.holonomic_constraints_jacobian(q_plus)
525+
526+
q_minus = MX(q)
527+
q_minus[i] -= epsilon
528+
J_minus = self.holonomic_constraints_jacobian(q_minus)
529+
530+
# approximated by finite difference
531+
dJ_dqi = (J_plus - J_minus) / (2 * epsilon)
532+
533+
# Contract: Jdot += (∂J/∂q_i) * qdot_i
534+
Jdot += dJ_dqi * qdot[i]
535+
536+
return Jdot
537+
538+
def _holonomic_constraints_jacobian_time_derivative(
539+
self, q: MX, qdot: MX,
540+
) -> MX:
541+
"""
542+
Compute Jdot = dJ/dt = (∂J/∂q) * qdot using finite differences.
543+
544+
Args:
545+
q: Configuration vector (n,)
546+
qdot: Velocity vector (n,)
547+
548+
Returns:
549+
Jdot: Time derivative of Jacobian (m, n) where m = number of constraints
550+
551+
Note:
552+
$$\dot{J} = \frac{dJ}{dt} = \frac{\partial J}{\partial q} \dot{q} = \sum_{k=1}^{n} \frac{\partial J}{\partial q_k} \dot{q}_k$$
553+
"""
554+
n = q.shape[0]
555+
J0 = self.holonomic_constraints_jacobian(q)
556+
m = J0.shape[0]
557+
558+
Jdot = MX.zeros(m, n)
559+
for k in range(n):
560+
# Compute the partial derivative of J with respect to q_k
561+
dJ_dqk = (J0, q[k]) # Shape (m, n)
562+
563+
# Contract: Jdot += (∂J/∂q_k) * qdot_k
564+
Jdot += dJ_dqk @ qdot[k]
565+
566+
return Jdot
495567

496568
def state_from_partition(self, state_u: MX, state_v: MX) -> MX:
497569
"""

0 commit comments

Comments
 (0)