nphysics2d/solver/
moreau_jean_solver.rs

1use na::{DVector, RealField};
2use ncollide::query::ContactId;
3
4use crate::counters::Counters;
5use crate::detection::ColliderContactManifold;
6use crate::joint::{JointConstraint, JointConstraintSet};
7use crate::material::MaterialsCoefficientsTable;
8use crate::object::{BodyHandle, BodySet, ColliderHandle, ColliderSet};
9use crate::solver::{
10    ConstraintSet, ContactModel, IntegrationParameters, NonlinearSORProx, SORProx,
11};
12
13/// Moreau-Jean time-stepping scheme.
14pub struct MoreauJeanSolver<N: RealField + Copy, Handle: BodyHandle, CollHandle: ColliderHandle> {
15    jacobians: Vec<N>,
16    // FIXME: use a Vec or a DVector?
17    mj_lambda_vel: DVector<N>,
18    ext_vels: DVector<N>,
19    contact_model: Box<dyn ContactModel<N, Handle, CollHandle>>,
20    contact_constraints: ConstraintSet<N, Handle, CollHandle, ContactId>,
21    joint_constraints: ConstraintSet<N, Handle, CollHandle, usize>,
22    internal_constraints: Vec<Handle>,
23}
24
25impl<N: RealField + Copy, Handle: BodyHandle, CollHandle: ColliderHandle>
26    MoreauJeanSolver<N, Handle, CollHandle>
27{
28    /// Create a new time-stepping scheme with the given contact model.
29    pub fn new(contact_model: Box<dyn ContactModel<N, Handle, CollHandle>>) -> Self {
30        MoreauJeanSolver {
31            jacobians: Vec::new(),
32            mj_lambda_vel: DVector::zeros(0),
33            ext_vels: DVector::zeros(0),
34            contact_model,
35            contact_constraints: ConstraintSet::new(),
36            joint_constraints: ConstraintSet::new(),
37            internal_constraints: Vec::new(),
38        }
39    }
40
41    /// Sets the contact model.
42    pub fn set_contact_model(&mut self, model: Box<dyn ContactModel<N, Handle, CollHandle>>) {
43        self.contact_model = model
44    }
45
46    /// Perform one step of the time-stepping scheme.
47    pub fn step<
48        Colliders: ColliderSet<N, Handle, Handle = CollHandle>,
49        Constraints: JointConstraintSet<N, Handle>,
50    >(
51        &mut self,
52        counters: &mut Counters,
53        bodies: &mut dyn BodySet<N, Handle = Handle>,
54        colliders: &Colliders,
55        joints: &mut Constraints,
56        manifolds: &[ColliderContactManifold<N, Handle, CollHandle>],
57        island: &[Handle],
58        island_joints: &[Constraints::Handle],
59        parameters: &IntegrationParameters<N>,
60        coefficients: &MaterialsCoefficientsTable<N>,
61    ) {
62        counters.assembly_started();
63        self.assemble_system(
64            counters,
65            parameters,
66            coefficients,
67            bodies,
68            joints,
69            manifolds,
70            island,
71            island_joints,
72        );
73        counters.assembly_completed();
74        counters.set_nconstraints(
75            self.contact_constraints.velocity.len() + self.joint_constraints.velocity.len(),
76        );
77
78        counters.velocity_resolution_started();
79        self.solve_velocity_constraints(parameters, bodies);
80        self.cache_impulses(parameters, bodies, joints, island_joints);
81        counters.velocity_resolution_completed();
82
83        counters.velocity_update_started();
84        self.update_velocities_and_integrate(parameters, bodies, island);
85        counters.velocity_update_completed();
86
87        counters.position_resolution_started();
88        self.solve_position_constraints(parameters, bodies, colliders, joints, island_joints);
89        counters.position_resolution_completed();
90    }
91
92    // FIXME: this comment is bad.
93    /// Perform one sub-step of the time-stepping scheme as part of a CCD integration.
94    pub fn step_ccd<
95        Colliders: ColliderSet<N, Handle, Handle = CollHandle>,
96        Constraints: JointConstraintSet<N, Handle>,
97    >(
98        &mut self,
99        counters: &mut Counters,
100        bodies: &mut dyn BodySet<N, Handle = Handle>,
101        colliders: &Colliders,
102        joints: &mut Constraints,
103        manifolds: &[ColliderContactManifold<N, Handle, CollHandle>],
104        ccd_bodies: &[Handle],
105        island: &[Handle],
106        island_joints: &[Constraints::Handle],
107        parameters: &IntegrationParameters<N>,
108        coefficients: &MaterialsCoefficientsTable<N>,
109    ) {
110        self.assemble_system(
111            counters,
112            parameters,
113            coefficients,
114            bodies,
115            joints,
116            manifolds,
117            island,
118            island_joints,
119        );
120        self.solve_position_constraints(parameters, bodies, colliders, joints, island_joints);
121        for ccd_body in ccd_bodies {
122            bodies.get_mut(*ccd_body).unwrap().validate_advancement();
123        }
124
125        self.solve_velocity_constraints(parameters, bodies);
126        self.update_velocities_and_integrate(parameters, bodies, island);
127    }
128
129    fn assemble_system<Constraints: JointConstraintSet<N, Handle>>(
130        &mut self,
131        counters: &mut Counters,
132        parameters: &IntegrationParameters<N>,
133        coefficients: &MaterialsCoefficientsTable<N>,
134        bodies: &mut dyn BodySet<N, Handle = Handle>,
135        joints: &mut Constraints,
136        manifolds: &[ColliderContactManifold<N, Handle, CollHandle>],
137        island: &[Handle],
138        island_joints: &[Constraints::Handle],
139    ) {
140        self.internal_constraints.clear();
141        let mut system_ndofs = 0;
142
143        for handle in island {
144            let body = try_continue!(bodies.get_mut(*handle));
145            body.set_companion_id(system_ndofs);
146            let ndofs = body.status_dependent_ndofs();
147            assert!(
148                ndofs != 0,
149                "Internal error: an island cannot contain a non-dynamic body."
150            );
151
152            system_ndofs += ndofs;
153
154            if ndofs != 0 && body.has_active_internal_constraints() {
155                self.internal_constraints.push(*handle)
156            }
157        }
158
159        self.resize_buffers(system_ndofs);
160        self.contact_constraints.clear();
161        self.joint_constraints.clear();
162
163        /*
164         * Initialize M^{-1} h * dt
165         */
166        for handle in island {
167            let body = try_continue!(bodies.get(*handle));
168            let id = body.companion_id();
169            let accs = body.generalized_acceleration();
170
171            self.ext_vels
172                .rows_mut(id, accs.len())
173                .axpy(parameters.dt(), &accs, N::zero());
174        }
175
176        /*
177         *
178         * Compute jacobian sizes.
179         *
180         */
181        let mut jacobian_sz = 0;
182        let mut ground_jacobian_sz = 0;
183
184        for handle in island_joints {
185            if let Some(joint) = joints.get(*handle) {
186                let (b1, b2) = joint.anchors();
187                if let (Some(body1), Some(body2)) = (bodies.get(b1.0), bodies.get(b2.0)) {
188                    let ndofs1 = body1.status_dependent_ndofs();
189                    let ndofs2 = body2.status_dependent_ndofs();
190
191                    let nconstraints = joint.num_velocity_constraints();
192                    let sz = nconstraints * 2 * (ndofs1 + ndofs2);
193
194                    if ndofs1 == 0 || ndofs2 == 0 {
195                        ground_jacobian_sz += sz;
196                    } else {
197                        jacobian_sz += sz;
198                    }
199                }
200            }
201        }
202
203        for m in manifolds {
204            let ndofs1 = try_continue!(bodies.get(m.body1())).status_dependent_ndofs();
205            let ndofs2 = try_continue!(bodies.get(m.body2())).status_dependent_ndofs();
206            let sz = self.contact_model.num_velocity_constraints(m) * (ndofs1 + ndofs2) * 2;
207
208            if ndofs1 == 0 || ndofs2 == 0 {
209                ground_jacobian_sz += sz;
210            } else {
211                jacobian_sz += sz;
212            }
213        }
214
215        self.jacobians
216            .resize(jacobian_sz + ground_jacobian_sz, N::zero());
217
218        /*
219         *
220         * Initialize constraints.
221         *
222         */
223        let mut j_id = 0;
224        let mut ground_j_id = jacobian_sz;
225
226        for handle in island_joints {
227            if let Some(joint) = joints.get_mut(*handle) {
228                joint.velocity_constraints(
229                    parameters,
230                    bodies,
231                    &self.ext_vels,
232                    &mut ground_j_id,
233                    &mut j_id,
234                    &mut self.jacobians,
235                    &mut self.joint_constraints.velocity,
236                );
237            }
238        }
239
240        counters.custom_started();
241        self.contact_model.constraints(
242            parameters,
243            coefficients,
244            bodies,
245            &self.ext_vels,
246            manifolds,
247            &mut ground_j_id,
248            &mut j_id,
249            &mut self.jacobians,
250            &mut self.contact_constraints,
251        );
252        counters.custom_completed();
253
254        for handle in &self.internal_constraints {
255            if let Some(body) = bodies.get_mut(*handle) {
256                let ext_vels = self.ext_vels.rows(body.companion_id(), body.ndofs());
257                body.setup_internal_velocity_constraints(&ext_vels, parameters);
258            }
259        }
260    }
261
262    fn solve_velocity_constraints(
263        &mut self,
264        parameters: &IntegrationParameters<N>,
265        bodies: &mut dyn BodySet<N, Handle = Handle>,
266    ) {
267        SORProx::solve(
268            bodies,
269            &mut self.contact_constraints.velocity,
270            &mut self.joint_constraints.velocity,
271            &self.internal_constraints,
272            &mut self.mj_lambda_vel,
273            &self.jacobians,
274            parameters.max_velocity_iterations,
275        );
276    }
277
278    fn solve_position_constraints<
279        Colliders: ColliderSet<N, Handle, Handle = CollHandle>,
280        Constraints: JointConstraintSet<N, Handle>,
281    >(
282        &mut self,
283        parameters: &IntegrationParameters<N>,
284        bodies: &mut dyn BodySet<N, Handle = Handle>,
285        colliders: &Colliders,
286        joints: &mut Constraints,
287        island_joints: &[Constraints::Handle],
288    ) {
289        // XXX: avoid the systematic clone.
290        // This is needed for cases where we perform the position resolution
291        // before the velocity resolution.
292        let mut jacobians = self.jacobians.clone();
293        NonlinearSORProx::solve(
294            parameters,
295            bodies,
296            colliders,
297            &mut self.contact_constraints.position.unilateral,
298            joints,
299            island_joints,
300            &self.internal_constraints,
301            &mut jacobians,
302            parameters.max_position_iterations,
303        );
304    }
305
306    fn cache_impulses<Constraints: JointConstraintSet<N, Handle>>(
307        &mut self,
308        parameters: &IntegrationParameters<N>,
309        _bodies: &mut dyn BodySet<N, Handle = Handle>,
310        joints: &mut Constraints,
311        island_joints: &[Constraints::Handle],
312    ) {
313        self.contact_model.cache_impulses(&self.contact_constraints);
314
315        for handle in island_joints {
316            if let Some(j) = joints.get_mut(*handle) {
317                j.cache_impulses(&self.joint_constraints.velocity, parameters.inv_dt());
318            }
319        }
320    }
321
322    fn resize_buffers(&mut self, ndofs: usize) {
323        // XXX: use resize functions instead of reallocating.
324        self.mj_lambda_vel = DVector::zeros(ndofs);
325        self.ext_vels = DVector::zeros(ndofs);
326    }
327
328    fn update_velocities_and_integrate(
329        &mut self,
330        parameters: &IntegrationParameters<N>,
331        bodies: &mut dyn BodySet<N, Handle = Handle>,
332        island: &[Handle],
333    ) {
334        for handle in island {
335            let body = try_continue!(bodies.get_mut(*handle));
336            let id = body.companion_id();
337            let ndofs = body.ndofs();
338
339            {
340                let mut mb_vels = body.generalized_velocity_mut();
341                mb_vels += self.ext_vels.rows(id, ndofs);
342                mb_vels += self.mj_lambda_vel.rows(id, ndofs);
343            }
344
345            body.integrate(parameters);
346        }
347    }
348}