1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Alessandro Tasora, Radu Serban
13 // =============================================================================
14
15 #include "chrono/solver/ChSystemDescriptor.h"
16 #include "chrono/solver/ChConstraintTwoTuplesContactN.h"
17 #include "chrono/solver/ChConstraintTwoTuplesFrictionT.h"
18 #include "chrono/core/ChMatrix.h"
19
20 namespace chrono {
21
22 // Register into the object factory, to enable run-time
23 // dynamic creation and persistence
CH_FACTORY_REGISTER(ChSystemDescriptor)24 CH_FACTORY_REGISTER(ChSystemDescriptor)
25
26 #define CH_SPINLOCK_HASHSIZE 203
27
28 ChSystemDescriptor::ChSystemDescriptor() : n_q(0), n_c(0), c_a(1.0), freeze_count(false) {
29 vconstraints.clear();
30 vvariables.clear();
31 vstiffness.clear();
32 }
33
~ChSystemDescriptor()34 ChSystemDescriptor::~ChSystemDescriptor() {
35 vconstraints.clear();
36 vvariables.clear();
37 vstiffness.clear();
38 }
39
ComputeFeasabilityViolation(double & resulting_maxviolation,double & resulting_feasability)40 void ChSystemDescriptor::ComputeFeasabilityViolation(double& resulting_maxviolation, double& resulting_feasability) {
41 resulting_maxviolation = 0;
42 resulting_feasability = 0;
43
44 auto vc_size = vconstraints.size();
45
46 for (size_t ic = 0; ic < vc_size; ic++) {
47 // the the residual of the constraint..
48 double mres_i = vconstraints[ic]->Compute_c_i();
49
50 double candidate_violation = fabs(vconstraints[ic]->Violation(mres_i));
51
52 if (candidate_violation > resulting_maxviolation)
53 resulting_maxviolation = candidate_violation;
54
55 if (vconstraints[ic]->IsUnilateral()) {
56 double candidate_feas = fabs(mres_i * vconstraints[ic]->Get_l_i()); // =|c*l|
57 if (candidate_feas > resulting_feasability)
58 resulting_feasability = candidate_feas;
59 }
60 }
61 }
62
CountActiveVariables()63 int ChSystemDescriptor::CountActiveVariables() {
64 if (freeze_count) // optimization, avoid list count all times
65 return n_q;
66
67 auto vv_size = vvariables.size();
68
69 n_q = 0;
70 for (size_t iv = 0; iv < vv_size; iv++) {
71 if (vvariables[iv]->IsActive()) {
72 vvariables[iv]->SetOffset(n_q); // also store offsets in state and MC matrix
73 n_q += vvariables[iv]->Get_ndof();
74 }
75 }
76 return n_q;
77 }
78
CountActiveConstraints()79 int ChSystemDescriptor::CountActiveConstraints() {
80 if (freeze_count) // optimization, avoid list count all times
81 return n_c;
82
83 auto vc_size = vconstraints.size();
84
85 n_c = 0;
86 for (size_t ic = 0; ic < vc_size; ic++) {
87 if (vconstraints[ic]->IsActive()) {
88 vconstraints[ic]->SetOffset(n_c); // also store offsets in state and MC matrix
89 n_c++;
90 }
91 }
92 return n_c;
93 }
94
UpdateCountsAndOffsets()95 void ChSystemDescriptor::UpdateCountsAndOffsets() {
96 freeze_count = false;
97 CountActiveVariables();
98 CountActiveConstraints();
99 freeze_count = true;
100 }
101
ConvertToMatrixForm(ChSparseMatrix * Cq,ChSparseMatrix * H,ChSparseMatrix * E,ChVectorDynamic<> * Fvector,ChVectorDynamic<> * Bvector,ChVectorDynamic<> * Frict,bool only_bilaterals,bool skip_contacts_uv)102 void ChSystemDescriptor::ConvertToMatrixForm(ChSparseMatrix* Cq,
103 ChSparseMatrix* H,
104 ChSparseMatrix* E,
105 ChVectorDynamic<>* Fvector,
106 ChVectorDynamic<>* Bvector,
107 ChVectorDynamic<>* Frict,
108 bool only_bilaterals,
109 bool skip_contacts_uv) {
110 std::vector<ChConstraint*>& mconstraints = GetConstraintsList();
111 std::vector<ChVariables*>& mvariables = GetVariablesList();
112
113 auto mv_size = mvariables.size();
114 auto mc_size = mconstraints.size();
115 auto vs_size = vstiffness.size();
116
117 // Count bilateral and other constraints.. (if wanted, bilaterals only)
118
119 int mn_c = 0;
120 for (size_t ic = 0; ic < mc_size; ic++) {
121 if (mconstraints[ic]->IsActive())
122 if (!((mconstraints[ic]->GetMode() == CONSTRAINT_FRIC) && only_bilaterals))
123 if (!((dynamic_cast<ChConstraintTwoTuplesFrictionTall*>(mconstraints[ic])) && skip_contacts_uv)) {
124 mn_c++;
125 }
126 }
127
128 // Count active variables, by scanning through all variable blocks,
129 // and set offsets
130
131 n_q = CountActiveVariables();
132
133 // Reset and resize (if needed) auxiliary vectors
134
135 if (Cq)
136 Cq->resize(mn_c, n_q);
137 if (H)
138 H->resize(n_q, n_q);
139 if (E)
140 E->resize(mn_c, mn_c);
141 if (Fvector)
142 Fvector->setZero(n_q);
143 if (Bvector)
144 Bvector->setZero(mn_c);
145 if (Frict)
146 Frict->setZero(mn_c);
147
148 // Fills H submasses and 'f' vector,
149 // by looping on variables
150 int s_q = 0;
151 for (size_t iv = 0; iv < mv_size; iv++) {
152 if (mvariables[iv]->IsActive()) {
153 if (H)
154 mvariables[iv]->Build_M(*H, s_q, s_q, c_a); // .. fills H (often H=M , the mass)
155 if (Fvector)
156 Fvector->segment(s_q, vvariables[iv]->Get_ndof()) = vvariables[iv]->Get_fb(); // .. fills 'f'
157 s_q += mvariables[iv]->Get_ndof();
158 }
159 }
160
161 // If some stiffness / hessian matrix has been added to H ,
162 // also add it to the sparse H
163 if (H) {
164 for (size_t ik = 0; ik < vs_size; ik++) {
165 vstiffness[ik]->Build_K(*H, true);
166 }
167 }
168
169 // Fills Cq jacobian, E 'compliance' matrix , the 'b' vector and friction coeff.vector,
170 // by looping on constraints
171 int s_c = 0;
172 for (size_t ic = 0; ic < mc_size; ic++) {
173 if (mconstraints[ic]->IsActive())
174 if (!((mconstraints[ic]->GetMode() == CONSTRAINT_FRIC) && only_bilaterals))
175 if (!((dynamic_cast<ChConstraintTwoTuplesFrictionTall*>(mconstraints[ic])) && skip_contacts_uv)) {
176 if (Cq)
177 mconstraints[ic]->Build_Cq(*Cq, s_c); // .. fills Cq
178 if (E)
179 E->SetElement(s_c, s_c, mconstraints[ic]->Get_cfm_i()); // .. fills E ( = cfm )
180 if (Bvector)
181 (*Bvector)(s_c) = mconstraints[ic]->Get_b_i(); // .. fills 'b'
182 if (Frict) // .. fills vector of friction coefficients
183 {
184 (*Frict)(s_c) = -2; // mark with -2 flag for bilaterals (default)
185 if (auto mcon = dynamic_cast<ChConstraintTwoTuplesContactNall*>(mconstraints[ic]))
186 (*Frict)(s_c) =
187 mcon->GetFrictionCoefficient(); // friction coeff only in row of normal component
188 if (dynamic_cast<ChConstraintTwoTuplesFrictionTall*>(mconstraints[ic]))
189 (*Frict)(s_c) = -1; // mark with -1 flag for rows of tangential components
190 }
191 s_c++;
192 }
193 }
194 }
195
ConvertToMatrixForm(ChSparseMatrix * Z,ChVectorDynamic<> * rhs)196 void ChSystemDescriptor::ConvertToMatrixForm(ChSparseMatrix* Z, ChVectorDynamic<>* rhs) {
197 std::vector<ChConstraint*>& mconstraints = GetConstraintsList();
198 std::vector<ChVariables*>& mvariables = GetVariablesList();
199
200 auto mv_size = mvariables.size();
201 auto mc_size = mconstraints.size();
202 auto vs_size = vstiffness.size();
203
204 // Count constraints.
205 int mn_c = 0;
206 for (size_t ic = 0; ic < mc_size; ic++) {
207 if (mconstraints[ic]->IsActive())
208 mn_c++;
209 }
210
211 // Count active variables, by scanning through all variable blocks, and set offsets.
212 n_q = CountActiveVariables();
213
214 if (Z) {
215 Z->conservativeResize(n_q + mn_c, n_q + mn_c);
216 Z->setZeroValues();
217
218 // Fill Z with masses and inertias.
219 int s_q = 0;
220 for (size_t iv = 0; iv < mv_size; iv++) {
221 if (mvariables[iv]->IsActive()) {
222 // Masses and inertias in upper-left block of Z
223 mvariables[iv]->Build_M(*Z, s_q, s_q, c_a);
224 s_q += mvariables[iv]->Get_ndof();
225 }
226 }
227
228 // If present, add stiffness matrix K to upper-left block of Z.
229 for (size_t ik = 0; ik < vs_size; ik++) {
230 vstiffness[ik]->Build_K(*Z, true);
231 }
232
233 // Fill Z by looping over constraints.
234 int s_c = 0;
235 for (size_t ic = 0; ic < mc_size; ic++) {
236 if (mconstraints[ic]->IsActive()) {
237 // Constraint Jacobian in lower-left block of Z
238 mconstraints[ic]->Build_Cq(*Z, n_q + s_c);
239 // Transposed constraint Jacobian in upper-right block of Z
240 mconstraints[ic]->Build_CqT(*Z, n_q + s_c);
241 // E ( = cfm ) in lower-right block of Z
242 Z->SetElement(n_q + s_c, n_q + s_c, mconstraints[ic]->Get_cfm_i());
243 s_c++;
244 }
245 }
246 }
247
248 if (rhs) {
249 rhs->setZero(n_q + mn_c, 1);
250
251 // Fill rhs with forces.
252 int s_q = 0;
253 for (size_t iv = 0; iv < mv_size; iv++) {
254 if (mvariables[iv]->IsActive()) {
255 // Forces in upper section of rhs
256 rhs->segment(s_q, vvariables[iv]->Get_ndof()) = vvariables[iv]->Get_fb();
257 s_q += mvariables[iv]->Get_ndof();
258 }
259 }
260
261 // Fill rhs by looping over constraints.
262 int s_c = 0;
263 for (size_t ic = 0; ic < mc_size; ic++) {
264 if (mconstraints[ic]->IsActive()) {
265 // -b term in lower section of rhs
266 (*rhs)(n_q + s_c) = -(mconstraints[ic]->Get_b_i());
267 s_c++;
268 }
269 }
270 }
271 }
272
DumpLastMatrices(bool assembled,const char * path)273 void ChSystemDescriptor::DumpLastMatrices(bool assembled, const char* path) {
274 char filename[300];
275 try {
276 const char* numformat = "%.12g";
277
278 if (assembled) {
279 ChSparseMatrix Z;
280 ChVectorDynamic<double> rhs;
281 ConvertToMatrixForm(&Z, &rhs);
282
283 sprintf(filename, "%s%s", path, "Z.dat");
284 ChStreamOutAsciiFile file_Z(filename);
285 file_Z.SetNumFormat(numformat);
286 StreamOUTsparseMatlabFormat(Z, file_Z);
287
288 sprintf(filename, "%s%s", path, "rhs.dat");
289 ChStreamOutAsciiFile file_rhs(filename);
290 file_rhs.SetNumFormat(numformat);
291 StreamOUTdenseMatlabFormat(rhs, file_rhs);
292 } else {
293 ChSparseMatrix mdM;
294 ChSparseMatrix mdCq;
295 ChSparseMatrix mdE;
296 ChVectorDynamic<double> mdf;
297 ChVectorDynamic<double> mdb;
298 ChVectorDynamic<double> mdfric;
299 ConvertToMatrixForm(&mdCq, &mdM, &mdE, &mdf, &mdb, &mdfric);
300
301 sprintf(filename, "%s%s", path, "M.dat");
302 ChStreamOutAsciiFile file_M(filename);
303 file_M.SetNumFormat(numformat);
304 StreamOUTsparseMatlabFormat(mdM, file_M);
305
306 sprintf(filename, "%s%s", path, "Cq.dat");
307 ChStreamOutAsciiFile file_Cq(filename);
308 file_Cq.SetNumFormat(numformat);
309 StreamOUTsparseMatlabFormat(mdCq, file_Cq);
310
311 sprintf(filename, "%s%s", path, "E.dat");
312 ChStreamOutAsciiFile file_E(filename);
313 file_E.SetNumFormat(numformat);
314 StreamOUTsparseMatlabFormat(mdE, file_E);
315
316 sprintf(filename, "%s%s", path, "f.dat");
317 ChStreamOutAsciiFile file_f(filename);
318 file_f.SetNumFormat(numformat);
319 StreamOUTdenseMatlabFormat(mdf, file_f);
320
321 sprintf(filename, "%s%s", path, "b.dat");
322 ChStreamOutAsciiFile file_b(filename);
323 file_b.SetNumFormat(numformat);
324 StreamOUTdenseMatlabFormat(mdb, file_b);
325
326 sprintf(filename, "%s%s", path, "fric.dat");
327 ChStreamOutAsciiFile file_fric(filename);
328 file_fric.SetNumFormat(numformat);
329 StreamOUTdenseMatlabFormat(mdfric, file_fric);
330 }
331 } catch (const chrono::ChException &myexc) {
332 chrono::GetLog() << myexc.what();
333 }
334 }
335
BuildFbVector(ChVectorDynamic<> & Fvector)336 int ChSystemDescriptor::BuildFbVector(ChVectorDynamic<>& Fvector) {
337 n_q = CountActiveVariables();
338 Fvector.setZero(n_q);
339
340 auto vv_size = vvariables.size();
341
342 // Fills the 'f' vector
343 for (size_t iv = 0; iv < vv_size; iv++) {
344 if (vvariables[iv]->IsActive()) {
345 Fvector.segment(vvariables[iv]->GetOffset(), vvariables[iv]->Get_ndof()) = vvariables[iv]->Get_fb();
346 }
347 }
348 return n_q;
349 }
350
BuildBiVector(ChVectorDynamic<> & Bvector)351 int ChSystemDescriptor::BuildBiVector(ChVectorDynamic<>& Bvector) {
352 n_c = CountActiveConstraints();
353 Bvector.setZero(n_c);
354
355 auto vc_size = vconstraints.size();
356
357 // Fill the 'b' vector
358 for (size_t ic = 0; ic < vc_size; ic++) {
359 if (vconstraints[ic]->IsActive()) {
360 Bvector(vconstraints[ic]->GetOffset()) = vconstraints[ic]->Get_b_i();
361 }
362 }
363
364 return n_c;
365 }
366
BuildDiVector(ChVectorDynamic<> & Dvector)367 int ChSystemDescriptor::BuildDiVector(ChVectorDynamic<>& Dvector) {
368 n_q = CountActiveVariables();
369 n_c = CountActiveConstraints();
370 Dvector.setZero(n_q + n_c);
371
372 auto vv_size = vvariables.size();
373 auto vc_size = vconstraints.size();
374
375 // Fills the 'f' vector part
376 for (size_t iv = 0; iv < vv_size; iv++) {
377 if (vvariables[iv]->IsActive()) {
378 Dvector.segment(vvariables[iv]->GetOffset(), vvariables[iv]->Get_ndof()) = vvariables[iv]->Get_fb();
379 }
380 }
381
382 // Fill the '-b' vector (with flipped sign!)
383 for (size_t ic = 0; ic < vc_size; ic++) {
384 if (vconstraints[ic]->IsActive()) {
385 Dvector(vconstraints[ic]->GetOffset() + n_q) = -vconstraints[ic]->Get_b_i();
386 }
387 }
388
389 return n_q + n_c;
390 }
391
BuildDiagonalVector(ChVectorDynamic<> & Diagonal_vect)392 int ChSystemDescriptor::BuildDiagonalVector(ChVectorDynamic<>& Diagonal_vect) {
393 n_q = CountActiveVariables();
394 n_c = CountActiveConstraints();
395 Diagonal_vect.setZero(n_q + n_c);
396
397 auto vs_size = vstiffness.size();
398 auto vv_size = vvariables.size();
399 auto vc_size = vconstraints.size();
400
401 // Fill the diagonal values given by ChKblock objects , if any
402 // (This cannot be easily parallelized because of possible write concurrency).
403 for (size_t is = 0; is < vs_size; is++) {
404 vstiffness[is]->DiagonalAdd(Diagonal_vect);
405 }
406
407 // Get the 'M' diagonal terms given by ChVariables objects
408 for (size_t iv = 0; iv < vv_size; iv++) {
409 if (vvariables[iv]->IsActive()) {
410 vvariables[iv]->DiagonalAdd(Diagonal_vect, c_a);
411 }
412 }
413
414 // Get the 'E' diagonal terms (E_i = cfm_i )
415 for (size_t ic = 0; ic < vc_size; ic++) {
416 if (vconstraints[ic]->IsActive()) {
417 Diagonal_vect(vconstraints[ic]->GetOffset() + n_q) = vconstraints[ic]->Get_cfm_i();
418 }
419 }
420
421 return n_q + n_c;
422 }
423
FromVariablesToVector(ChVectorDynamic<> & mvector,bool resize_vector)424 int ChSystemDescriptor::FromVariablesToVector(ChVectorDynamic<>& mvector, bool resize_vector) {
425 // Count active variables and resize vector if necessary
426 if (resize_vector) {
427 n_q = CountActiveVariables();
428 mvector.setZero(n_q);
429 }
430
431 // Fill the vector
432 auto vv_size = vvariables.size();
433 for (size_t iv = 0; iv < vv_size; iv++) {
434 if (vvariables[iv]->IsActive()) {
435 mvector.segment(vvariables[iv]->GetOffset(), vvariables[iv]->Get_ndof()) = vvariables[iv]->Get_qb();
436 }
437 }
438
439 return n_q;
440 }
441
FromVectorToVariables(const ChVectorDynamic<> & mvector)442 int ChSystemDescriptor::FromVectorToVariables(const ChVectorDynamic<>& mvector) {
443 assert(CountActiveVariables() == mvector.rows());
444
445 // fetch from the vector
446 auto vv_size = vvariables.size();
447 for (size_t iv = 0; iv < vv_size; iv++) {
448 if (vvariables[iv]->IsActive()) {
449 vvariables[iv]->Get_qb() = mvector.segment(vvariables[iv]->GetOffset(), vvariables[iv]->Get_ndof());
450 }
451 }
452
453 return n_q;
454 }
455
FromConstraintsToVector(ChVectorDynamic<> & mvector,bool resize_vector)456 int ChSystemDescriptor::FromConstraintsToVector(ChVectorDynamic<>& mvector, bool resize_vector) {
457 // Count active constraints and resize vector if necessary
458 if (resize_vector) {
459 n_c = CountActiveConstraints();
460 mvector.setZero(n_c);
461 }
462
463 auto vc_size = (int)vconstraints.size();
464
465 // Fill the vector
466 for (size_t ic = 0; ic < vc_size; ic++) {
467 if (vconstraints[ic]->IsActive()) {
468 mvector(vconstraints[ic]->GetOffset()) = vconstraints[ic]->Get_l_i();
469 }
470 }
471
472 return n_c;
473 }
474
FromVectorToConstraints(const ChVectorDynamic<> & mvector)475 int ChSystemDescriptor::FromVectorToConstraints(const ChVectorDynamic<>& mvector) {
476 n_c = CountActiveConstraints();
477
478 assert(n_c == mvector.size());
479
480 auto vc_size = (int)vconstraints.size();
481
482 // Fill the vector
483 for (size_t ic = 0; ic < vc_size; ic++) {
484 if (vconstraints[ic]->IsActive()) {
485 vconstraints[ic]->Set_l_i(mvector(vconstraints[ic]->GetOffset()));
486 }
487 }
488
489 return n_c;
490 }
491
FromUnknownsToVector(ChVectorDynamic<> & mvector,bool resize_vector)492 int ChSystemDescriptor::FromUnknownsToVector(ChVectorDynamic<>& mvector, bool resize_vector) {
493 // Count active variables & constraints and resize vector if necessary
494 n_q = CountActiveVariables();
495 n_c = CountActiveConstraints();
496
497 if (resize_vector) {
498 mvector.setZero(n_q + n_c);
499 }
500
501 auto vv_size = (int)vvariables.size();
502 auto vc_size = (int)vconstraints.size();
503
504 // Fill the first part of vector, x.q ,with variables q
505 for (size_t iv = 0; iv < vv_size; iv++) {
506 if (vvariables[iv]->IsActive()) {
507 mvector.segment(vvariables[iv]->GetOffset(), vvariables[iv]->Get_ndof()) = vvariables[iv]->Get_qb();
508 }
509 }
510
511 // Fill the second part of vector, x.l, with constraint multipliers -l (with flipped sign!)
512 for (size_t ic = 0; ic < vc_size; ic++) {
513 if (vconstraints[ic]->IsActive()) {
514 mvector(vconstraints[ic]->GetOffset() + n_q) = -vconstraints[ic]->Get_l_i();
515 }
516 }
517
518 return n_q + n_c;
519 }
520
FromVectorToUnknowns(const ChVectorDynamic<> & mvector)521 int ChSystemDescriptor::FromVectorToUnknowns(const ChVectorDynamic<>& mvector) {
522 n_q = CountActiveVariables();
523 n_c = CountActiveConstraints();
524
525 assert((n_q + n_c) == mvector.size());
526
527 auto vv_size = vvariables.size();
528 auto vc_size = vconstraints.size();
529
530 // Fetch from the first part of vector (x.q = q)
531 for (size_t iv = 0; iv < vv_size; iv++) {
532 if (vvariables[iv]->IsActive()) {
533 vvariables[iv]->Get_qb() = mvector.segment(vvariables[iv]->GetOffset(), vvariables[iv]->Get_ndof());
534 }
535 }
536
537 // Fetch from the second part of vector (x.l = -l), with flipped sign!
538 for (size_t ic = 0; ic < vc_size; ic++) {
539 if (vconstraints[ic]->IsActive()) {
540 vconstraints[ic]->Set_l_i(-mvector(vconstraints[ic]->GetOffset() + n_q));
541 }
542 }
543
544 return n_q + n_c;
545 }
546
ShurComplementProduct(ChVectorDynamic<> & result,const ChVectorDynamic<> & lvector,std::vector<bool> * enabled)547 void ChSystemDescriptor::ShurComplementProduct(ChVectorDynamic<>& result,
548 const ChVectorDynamic<>& lvector,
549 std::vector<bool>* enabled) {
550 // currently, the case with ChKblock items is not supported (only diagonal M is supported, no K)
551 assert(vstiffness.size() == 0);
552 assert(lvector.size() == CountActiveConstraints());
553
554 result.setZero(n_c);
555
556 // Performs the sparse product result = [N]*l = [ [Cq][M^(-1)][Cq'] - [E] ] *l
557 // in different phases:
558
559 auto vv_size = vvariables.size();
560 auto vc_size = vconstraints.size();
561
562 // 1 - set the qb vector (aka speeds, in each ChVariable sparse data) as zero
563
564 for (size_t iv = 0; iv < vv_size; iv++) {
565 if (vvariables[iv]->IsActive())
566 vvariables[iv]->Get_qb().setZero();
567 }
568
569 // 2 - performs qb=[M^(-1)][Cq']*l by
570 // iterating over all constraints (when implemented in parallel this
571 // could be non-trivial because race conditions might occur -> reduction buffer etc.)
572 // Also, begin to add the cfm term ( -[E]*l ) to the result.
573
574 // ATTENTION: this loop cannot be parallelized! Concurrent write to some q may happen
575 for (size_t ic = 0; ic < vc_size; ic++) {
576 if (vconstraints[ic]->IsActive()) {
577 int s_c = vconstraints[ic]->GetOffset();
578
579 bool process = (!enabled) || (*enabled)[s_c];
580
581 if (process) {
582 double li = lvector(s_c);
583
584 // Compute qb += [M^(-1)][Cq']*l_i
585 // NOTE! concurrent update to same q data, risk of collision if parallel.
586 vconstraints[ic]->Increment_q(li); // computationally intensive
587
588 // Add constraint force mixing term result = cfm * l_i = [E]*l_i
589 result(s_c) = vconstraints[ic]->Get_cfm_i() * li;
590 }
591 }
592 }
593
594 // 3 - performs result=[Cq']*qb by
595 // iterating over all constraints
596
597 for (size_t ic = 0; ic < vc_size; ic++) {
598 if (vconstraints[ic]->IsActive()) {
599 bool process = (!enabled) || (*enabled)[vconstraints[ic]->GetOffset()];
600
601 if (process)
602 result(vconstraints[ic]->GetOffset()) += vconstraints[ic]->Compute_Cq_q(); // computationally intensive
603 else
604 result(vconstraints[ic]->GetOffset()) = 0; // not enabled constraints, just set to 0 result
605 }
606 }
607 }
608
SystemProduct(ChVectorDynamic<> & result,const ChVectorDynamic<> & x)609 void ChSystemDescriptor::SystemProduct(ChVectorDynamic<>& result, const ChVectorDynamic<>& x) {
610 n_q = CountActiveVariables();
611 n_c = CountActiveConstraints();
612
613 result.setZero(n_q + n_c);
614
615 auto vv_size = vvariables.size();
616 auto vc_size = vconstraints.size();
617 auto vs_size = vstiffness.size();
618
619 // 1) First row: result.q part = [M + K]*x.q + [Cq']*x.l
620
621 // 1.1) do M*x.q
622 for (size_t iv = 0; iv < vv_size; iv++) {
623 if (vvariables[iv]->IsActive()) {
624 vvariables[iv]->MultiplyAndAdd(result, x, c_a);
625 }
626 }
627
628 // 1.2) add also K*x.q (NON straight parallelizable - risk of concurrency in writing)
629 for (size_t ik = 0; ik < vs_size; ik++) {
630 vstiffness[ik]->MultiplyAndAdd(result, x);
631 }
632
633 // 1.3) add also [Cq]'*x.l (NON straight parallelizable - risk of concurrency in writing)
634 for (size_t ic = 0; ic < vc_size; ic++) {
635 if (vconstraints[ic]->IsActive()) {
636 vconstraints[ic]->MultiplyTandAdd(result, x(vconstraints[ic]->GetOffset() + n_q));
637 }
638 }
639
640 // 2) Second row: result.l part = [C_q]*x.q + [E]*x.l
641 for (size_t ic = 0; ic < vc_size; ic++) {
642 if (vconstraints[ic]->IsActive()) {
643 int s_c = vconstraints[ic]->GetOffset() + n_q;
644 vconstraints[ic]->MultiplyAndAdd(result(s_c), x); // result.l_i += [C_q_i]*x.q
645 result(s_c) += vconstraints[ic]->Get_cfm_i() * x(s_c); // result.l_i += [E]*x.l_i
646 }
647 }
648 }
649
ConstraintsProject(ChVectorDynamic<> & multipliers)650 void ChSystemDescriptor::ConstraintsProject(ChVectorDynamic<>& multipliers) {
651 FromVectorToConstraints(multipliers);
652
653 auto vc_size = vconstraints.size();
654
655 for (size_t ic = 0; ic < vc_size; ic++) {
656 if (vconstraints[ic]->IsActive())
657 vconstraints[ic]->Project();
658 }
659
660 FromConstraintsToVector(multipliers, false);
661 }
662
UnknownsProject(ChVectorDynamic<> & mx)663 void ChSystemDescriptor::UnknownsProject(ChVectorDynamic<>& mx) {
664 n_q = CountActiveVariables();
665
666 auto vc_size = vconstraints.size();
667
668 // vector -> constraints
669 // Fetch from the second part of vector (x.l = -l), with flipped sign!
670 for (size_t ic = 0; ic < vc_size; ic++) {
671 if (vconstraints[ic]->IsActive()) {
672 vconstraints[ic]->Set_l_i(-mx(vconstraints[ic]->GetOffset() + n_q));
673 }
674 }
675
676 // constraint projection!
677 for (size_t ic = 0; ic < vc_size; ic++) {
678 if (vconstraints[ic]->IsActive())
679 vconstraints[ic]->Project();
680 }
681
682 // constraints -> vector
683 // Fill the second part of vector, x.l, with constraint multipliers -l (with flipped sign!)
684 for (size_t ic = 0; ic < vc_size; ic++) {
685 if (vconstraints[ic]->IsActive()) {
686 mx(vconstraints[ic]->GetOffset() + n_q) = -vconstraints[ic]->Get_l_i();
687 }
688 }
689 }
690
691 } // end namespace chrono
692