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 #ifndef CHCONSTRAINTTUPLE_H 16 #define CHCONSTRAINTTUPLE_H 17 18 #include "chrono/solver/ChConstraint.h" 19 #include "chrono/solver/ChVariables.h" 20 21 namespace chrono { 22 23 /// This is a container for 'half' of a constraint, and contains a tuple of 24 /// 1 or 2 or 3 differently-sized jacobian chunks. For instance, this might 25 /// happen because you want a constraint between an edge (i.e. two xyz variables, each 26 /// per end nodes) and a triangle face (i.e. three xyz variables, each per corner), so 27 /// the jacobian row matrix is split in 2 + 3 chunks, here as two tuples. 28 /// The complete constraint, ChConstraintTwoTuples, will use two of these classes. 29 /// Template T is a class of ChVariableTupleCarrier_Nvars type 30 31 template <class T> 32 class ChConstraintTuple_1vars { 33 protected: 34 ChVariables* variables; ///< The constrained object 35 ChRowVectorN<double, T::nvars1> Cq; ///< The [Cq] jacobian of the constraint 36 ChVectorN<double, T::nvars1> Eq; ///< The [Eq] product [Eq]=[invM]*[Cq]' 37 38 public: 39 /// Default constructor ChConstraintTuple_1vars()40 ChConstraintTuple_1vars() : variables(nullptr) { 41 Cq.setZero(); 42 Eq.setZero(); 43 } 44 45 /// Copy constructor ChConstraintTuple_1vars(const ChConstraintTuple_1vars & other)46 ChConstraintTuple_1vars(const ChConstraintTuple_1vars& other) { 47 variables = other.variables; 48 Cq = other.Cq; 49 Eq = other.Eq; 50 } 51 ~ChConstraintTuple_1vars()52 ~ChConstraintTuple_1vars() {} 53 54 /// Assignment operator: copy from other object 55 ChConstraintTuple_1vars& operator=(const ChConstraintTuple_1vars& other) { 56 variables = other.variables; 57 Cq = other.Cq; 58 Eq = other.Eq; 59 return *this; 60 } 61 Get_Cq()62 ChRowVectorRef Get_Cq() { return Cq; } 63 Get_Eq()64 ChVectorRef Get_Eq() { return Eq; } 65 GetVariables()66 ChVariables* GetVariables() { return variables; } 67 SetVariables(T & m_tuple_carrier)68 void SetVariables(T& m_tuple_carrier) { 69 if (!m_tuple_carrier.GetVariables1()) { 70 throw ChException("ERROR. SetVariables() getting null pointer. \n"); 71 } 72 variables = m_tuple_carrier.GetVariables1(); 73 } 74 Update_auxiliary(double & g_i)75 void Update_auxiliary(double& g_i) { 76 // 1- Assuming jacobians are already computed, now compute 77 // the matrices [Eq]=[invM]*[Cq]' and [Eq] 78 if (variables->IsActive()) { 79 variables->Compute_invMb_v(Eq, Cq.transpose()); 80 } 81 82 // 2- Compute g_i = [Cq_i]*[invM_i]*[Cq_i]' + cfm_i 83 if (variables->IsActive()) { 84 g_i += Cq * Eq; 85 } 86 } 87 Compute_Cq_q()88 double Compute_Cq_q() { 89 double ret = 0; 90 91 if (variables->IsActive()) { 92 ret += Cq * variables->Get_qb(); 93 } 94 95 return ret; 96 } 97 Increment_q(const double deltal)98 void Increment_q(const double deltal) { 99 if (variables->IsActive()) { 100 variables->Get_qb() += Eq * deltal; 101 } 102 } 103 MultiplyAndAdd(double & result,const ChVectorDynamic<double> & vect)104 void MultiplyAndAdd(double& result, const ChVectorDynamic<double>& vect) const { 105 if (variables->IsActive()) { 106 result += Cq * vect.segment(variables->GetOffset(), T::nvars1); 107 } 108 } 109 MultiplyTandAdd(ChVectorDynamic<double> & result,double l)110 void MultiplyTandAdd(ChVectorDynamic<double>& result, double l) { 111 if (variables->IsActive()) { 112 result.segment(variables->GetOffset(), T::nvars1) += Cq.transpose() * l; 113 } 114 } 115 Build_Cq(ChSparseMatrix & storage,int insrow)116 void Build_Cq(ChSparseMatrix& storage, int insrow) { 117 if (variables->IsActive()) 118 PasteMatrix(storage, Cq, insrow, variables->GetOffset()); 119 } 120 Build_CqT(ChSparseMatrix & storage,int inscol)121 void Build_CqT(ChSparseMatrix& storage, int inscol) { 122 if (variables->IsActive()) 123 PasteMatrix(storage, Cq.transpose(), variables->GetOffset(), inscol); 124 } 125 }; 126 127 /// Case of tuple with reference to 2 ChVariable objects: 128 129 template <class T> 130 class ChConstraintTuple_2vars { 131 protected: 132 ChVariables* variables_1; 133 ChVariables* variables_2; 134 135 /// The [Cq] jacobian of the constraint, split in horizontal chunks 136 ChRowVectorN<double, T::nvars1> Cq_1; 137 ChRowVectorN<double, T::nvars2> Cq_2; 138 139 /// The [Eq] product [Eq]=[invM]*[Cq]' 140 ChVectorN<double, T::nvars1> Eq_1; 141 ChVectorN<double, T::nvars2> Eq_2; 142 143 public: 144 /// Default constructor ChConstraintTuple_2vars()145 ChConstraintTuple_2vars() : variables_1(nullptr), variables_2(nullptr) { 146 Cq_1.setZero(); 147 Cq_2.setZero(); 148 } 149 150 /// Copy constructor ChConstraintTuple_2vars(const ChConstraintTuple_2vars & other)151 ChConstraintTuple_2vars(const ChConstraintTuple_2vars& other) { 152 variables_1 = other.variables_1; 153 variables_2 = other.variables_2; 154 Cq_1 = other.Cq_1; 155 Cq_2 = other.Cq_2; 156 Eq_1 = other.Eq_1; 157 Eq_2 = other.Eq_2; 158 } 159 ~ChConstraintTuple_2vars()160 ~ChConstraintTuple_2vars() {} 161 162 /// Assignment operator: copy from other object 163 ChConstraintTuple_2vars& operator=(const ChConstraintTuple_2vars& other) { 164 variables_1 = other.variables_1; 165 variables_2 = other.variables_2; 166 Cq_1 = other.Cq_1; 167 Cq_2 = other.Cq_2; 168 Eq_1 = other.Eq_1; 169 Eq_2 = other.Eq_2; 170 return *this; 171 } 172 Get_Cq_1()173 ChRowVectorRef Get_Cq_1() { return Cq_1; } Get_Cq_2()174 ChRowVectorRef Get_Cq_2() { return Cq_2; } 175 Get_Eq_1()176 ChVectorRef Get_Eq_1() { return Eq_1; } Get_Eq_2()177 ChVectorRef Get_Eq_2() { return Eq_2; } 178 GetVariables_1()179 ChVariables* GetVariables_1() { return variables_1; } GetVariables_2()180 ChVariables* GetVariables_2() { return variables_2; } 181 SetVariables(T & m_tuple_carrier)182 void SetVariables(T& m_tuple_carrier) { 183 if (!m_tuple_carrier.GetVariables1() || !m_tuple_carrier.GetVariables2()) { 184 throw ChException("ERROR. SetVariables() getting null pointer. \n"); 185 } 186 variables_1 = m_tuple_carrier.GetVariables1(); 187 variables_2 = m_tuple_carrier.GetVariables2(); 188 } 189 Update_auxiliary(double & g_i)190 void Update_auxiliary(double& g_i) { 191 // 1- Assuming jacobians are already computed, now compute 192 // the matrices [Eq_a]=[invM_a]*[Cq_a]' and [Eq_b] 193 if (variables_1->IsActive()) { 194 variables_1->Compute_invMb_v(Eq_1, Cq_1.transpose()); 195 } 196 if (variables_2->IsActive()) { 197 variables_2->Compute_invMb_v(Eq_2, Cq_2.transpose()); 198 } 199 200 // 2- Compute g_i = [Cq_i]*[invM_i]*[Cq_i]' + cfm_i 201 if (variables_1->IsActive()) { 202 g_i += Cq_1 * Eq_1; 203 } 204 if (variables_2->IsActive()) { 205 g_i += Cq_2 * Eq_2; 206 } 207 } 208 Compute_Cq_q()209 double Compute_Cq_q() { 210 double ret = 0; 211 212 if (variables_1->IsActive()) { 213 ret += Cq_1 * variables_1->Get_qb(); 214 } 215 216 if (variables_2->IsActive()) { 217 ret += Cq_2 * variables_2->Get_qb(); 218 } 219 220 return ret; 221 } 222 Increment_q(const double deltal)223 void Increment_q(const double deltal) { 224 if (variables_1->IsActive()) { 225 variables_1->Get_qb() += Eq_1 * deltal; 226 } 227 228 if (variables_2->IsActive()) { 229 variables_2->Get_qb() += Eq_2 * deltal; 230 } 231 } 232 MultiplyAndAdd(double & result,const ChVectorDynamic<double> & vect)233 void MultiplyAndAdd(double& result, const ChVectorDynamic<double>& vect) const { 234 if (variables_1->IsActive()) { 235 result += Cq_1 * vect.segment(variables_1->GetOffset(), T::nvars1); 236 } 237 238 if (variables_2->IsActive()) { 239 result += Cq_2 * vect.segment(variables_2->GetOffset(), T::nvars2); 240 } 241 } 242 MultiplyTandAdd(ChVectorDynamic<double> & result,double l)243 void MultiplyTandAdd(ChVectorDynamic<double>& result, double l) { 244 if (variables_1->IsActive()) { 245 result.segment(variables_1->GetOffset(), T::nvars1) += Cq_1.transpose() * l; 246 } 247 248 if (variables_2->IsActive()) { 249 result.segment(variables_2->GetOffset(), T::nvars2) += Cq_2.transpose() * l; 250 } 251 } 252 Build_Cq(ChSparseMatrix & storage,int insrow)253 void Build_Cq(ChSparseMatrix& storage, int insrow) { 254 if (variables_1->IsActive()) 255 PasteMatrix(storage, Cq_1, insrow, variables_1->GetOffset()); 256 if (variables_2->IsActive()) 257 PasteMatrix(storage, Cq_2, insrow, variables_2->GetOffset()); 258 } 259 Build_CqT(ChSparseMatrix & storage,int inscol)260 void Build_CqT(ChSparseMatrix& storage, int inscol) { 261 if (variables_1->IsActive()) 262 PasteMatrix(storage, Cq_1.transpose(), variables_1->GetOffset(), inscol); 263 if (variables_2->IsActive()) 264 PasteMatrix(storage, Cq_2.transpose(), variables_2->GetOffset(), inscol); 265 } 266 }; 267 268 /// Case of tuple with reference to 3 ChVariable objects: 269 270 template <class T> 271 class ChConstraintTuple_3vars { 272 protected: 273 ChVariables* variables_1; 274 ChVariables* variables_2; 275 ChVariables* variables_3; 276 277 /// The [Cq] jacobian of the constraint, split in horizontal chunks 278 ChRowVectorN<double, T::nvars1> Cq_1; 279 ChRowVectorN<double, T::nvars2> Cq_2; 280 ChRowVectorN<double, T::nvars3> Cq_3; 281 282 /// The [Eq] product [Eq]=[invM]*[Cq]' 283 ChVectorN<double, T::nvars1> Eq_1; 284 ChVectorN<double, T::nvars2> Eq_2; 285 ChVectorN<double, T::nvars3> Eq_3; 286 287 public: 288 /// Default constructor ChConstraintTuple_3vars()289 ChConstraintTuple_3vars() : variables_1(nullptr), variables_2(nullptr), variables_3(nullptr) { 290 Cq_1.setZero(); 291 Cq_2.setZero(); 292 Cq_3.setZero(); 293 } 294 295 /// Copy constructor ChConstraintTuple_3vars(const ChConstraintTuple_3vars & other)296 ChConstraintTuple_3vars(const ChConstraintTuple_3vars& other) { 297 variables_1 = other.variables_1; 298 variables_2 = other.variables_2; 299 variables_3 = other.variables_3; 300 Cq_1 = other.Cq_1; 301 Cq_2 = other.Cq_2; 302 Cq_3 = other.Cq_3; 303 Eq_1 = other.Eq_1; 304 Eq_2 = other.Eq_2; 305 Eq_3 = other.Eq_3; 306 } 307 ~ChConstraintTuple_3vars()308 ~ChConstraintTuple_3vars() {} 309 310 /// Assignment operator: copy from other object 311 ChConstraintTuple_3vars& operator=(const ChConstraintTuple_3vars& other) { 312 variables_1 = other.variables_1; 313 variables_2 = other.variables_2; 314 variables_3 = other.variables_3; 315 Cq_1 = other.Cq_1; 316 Cq_2 = other.Cq_2; 317 Cq_3 = other.Cq_3; 318 Eq_1 = other.Eq_1; 319 Eq_2 = other.Eq_2; 320 Eq_3 = other.Eq_3; 321 return *this; 322 } 323 Get_Cq_1()324 ChRowVectorRef Get_Cq_1() { return Cq_1; } Get_Cq_2()325 ChRowVectorRef Get_Cq_2() { return Cq_2; } Get_Cq_3()326 ChRowVectorRef Get_Cq_3() { return Cq_3; } 327 Get_Eq_1()328 ChVectorRef Get_Eq_1() { return Eq_1; } Get_Eq_2()329 ChVectorRef Get_Eq_2() { return Eq_2; } Get_Eq_3()330 ChVectorRef Get_Eq_3() { return Eq_3; } 331 GetVariables_1()332 ChVariables* GetVariables_1() { return variables_1; } GetVariables_2()333 ChVariables* GetVariables_2() { return variables_2; } GetVariables_3()334 ChVariables* GetVariables_3() { return variables_3; } 335 SetVariables(T & m_tuple_carrier)336 void SetVariables(T& m_tuple_carrier) { 337 if (!m_tuple_carrier.GetVariables1() || !m_tuple_carrier.GetVariables2() || !m_tuple_carrier.GetVariables3()) { 338 throw ChException("ERROR. SetVariables() getting null pointer. \n"); 339 } 340 variables_1 = m_tuple_carrier.GetVariables1(); 341 variables_2 = m_tuple_carrier.GetVariables2(); 342 variables_3 = m_tuple_carrier.GetVariables3(); 343 } 344 Update_auxiliary(double & g_i)345 void Update_auxiliary(double& g_i) { 346 // 1- Assuming jacobians are already computed, now compute 347 // the matrices [Eq_a]=[invM_a]*[Cq_a]' and [Eq_b] 348 if (variables_1->IsActive()) { 349 variables_1->Compute_invMb_v(Eq_1, Cq_1.transpose()); 350 } 351 if (variables_2->IsActive()) { 352 variables_2->Compute_invMb_v(Eq_2, Cq_2.transpose()); 353 } 354 if (variables_3->IsActive()) { 355 variables_3->Compute_invMb_v(Eq_3, Cq_3.transpose()); 356 } 357 358 // 2- Compute g_i = [Cq_i]*[invM_i]*[Cq_i]' + cfm_i 359 if (variables_1->IsActive()) { 360 g_i += Cq_1 * Eq_1; 361 } 362 if (variables_2->IsActive()) { 363 g_i += Cq_2 * Eq_2; 364 } 365 if (variables_3->IsActive()) { 366 g_i += Cq_3 * Eq_3; 367 } 368 } 369 Compute_Cq_q()370 double Compute_Cq_q() { 371 double ret = 0; 372 373 if (variables_1->IsActive()) { 374 ret += Cq_1 * variables_1->Get_qb(); 375 } 376 377 if (variables_2->IsActive()) { 378 ret += Cq_2 * variables_2->Get_qb(); 379 } 380 381 if (variables_3->IsActive()) { 382 ret += Cq_3 * variables_3->Get_qb(); 383 } 384 385 return ret; 386 } 387 Increment_q(const double deltal)388 void Increment_q(const double deltal) { 389 if (variables_1->IsActive()) { 390 variables_1->Get_qb() += Eq_1 * deltal; 391 } 392 393 if (variables_2->IsActive()) { 394 variables_2->Get_qb() += Eq_2 * deltal; 395 } 396 397 if (variables_3->IsActive()) { 398 variables_3->Get_qb() += Eq_3 * deltal; 399 } 400 } 401 MultiplyAndAdd(double & result,const ChVectorDynamic<double> & vect)402 void MultiplyAndAdd(double& result, const ChVectorDynamic<double>& vect) const { 403 if (variables_1->IsActive()) { 404 result += Cq_1 * vect.segment(variables_1->GetOffset(), T::nvars1); 405 } 406 407 if (variables_2->IsActive()) { 408 result += Cq_2 * vect.segment(variables_2->GetOffset(), T::nvars2); 409 } 410 411 if (variables_3->IsActive()) { 412 result += Cq_3 * vect.segment(variables_3->GetOffset(), T::nvars3); 413 } 414 } 415 MultiplyTandAdd(ChVectorDynamic<double> & result,double l)416 void MultiplyTandAdd(ChVectorDynamic<double>& result, double l) { 417 if (variables_1->IsActive()) { 418 result.segment(variables_1->GetOffset(), T::nvars1) += Cq_1.transpose() * l; 419 } 420 421 if (variables_2->IsActive()) { 422 result.segment(variables_2->GetOffset(), T::nvars2) += Cq_2.transpose() * l; 423 } 424 425 if (variables_3->IsActive()) { 426 result.segment(variables_3->GetOffset(), T::nvars3) += Cq_3.transpose() * l; 427 } 428 } 429 Build_Cq(ChSparseMatrix & storage,int insrow)430 void Build_Cq(ChSparseMatrix& storage, int insrow) { 431 if (variables_1->IsActive()) 432 PasteMatrix(storage, Cq_1, insrow, variables_1->GetOffset()); 433 if (variables_2->IsActive()) 434 PasteMatrix(storage, Cq_2, insrow, variables_2->GetOffset()); 435 if (variables_3->IsActive()) 436 PasteMatrix(storage, Cq_3, insrow, variables_3->GetOffset()); 437 } 438 Build_CqT(ChSparseMatrix & storage,int inscol)439 void Build_CqT(ChSparseMatrix& storage, int inscol) { 440 if (variables_1->IsActive()) 441 PasteMatrix(storage, Cq_1.transpose(), variables_1->GetOffset(), inscol); 442 if (variables_2->IsActive()) 443 PasteMatrix(storage, Cq_2.transpose(), variables_2->GetOffset(), inscol); 444 if (variables_3->IsActive()) 445 PasteMatrix(storage, Cq_3.transpose(), variables_3->GetOffset(), inscol); 446 } 447 }; 448 449 450 /// Case of tuple with reference to 4 ChVariable objects: 451 452 template <class T> 453 class ChConstraintTuple_4vars { 454 protected: 455 ChVariables* variables_1; 456 ChVariables* variables_2; 457 ChVariables* variables_3; 458 ChVariables* variables_4; 459 460 /// The [Cq] jacobian of the constraint, split in horizontal chunks 461 ChRowVectorN<double, T::nvars1> Cq_1; 462 ChRowVectorN<double, T::nvars2> Cq_2; 463 ChRowVectorN<double, T::nvars3> Cq_3; 464 ChRowVectorN<double, T::nvars4> Cq_4; 465 466 /// The [Eq] product [Eq]=[invM]*[Cq]' 467 ChVectorN<double, T::nvars1> Eq_1; 468 ChVectorN<double, T::nvars2> Eq_2; 469 ChVectorN<double, T::nvars3> Eq_3; 470 ChVectorN<double, T::nvars4> Eq_4; 471 472 public: 473 /// Default constructor ChConstraintTuple_4vars()474 ChConstraintTuple_4vars() : variables_1(nullptr), variables_2(nullptr), variables_3(nullptr), variables_4(nullptr) { 475 Cq_1.setZero(); 476 Cq_2.setZero(); 477 Cq_3.setZero(); 478 Cq_4.setZero(); 479 } 480 481 /// Copy constructor ChConstraintTuple_4vars(const ChConstraintTuple_4vars & other)482 ChConstraintTuple_4vars(const ChConstraintTuple_4vars& other) { 483 variables_1 = other.variables_1; 484 variables_2 = other.variables_2; 485 variables_3 = other.variables_3; 486 variables_4 = other.variables_4; 487 Cq_1 = other.Cq_1; 488 Cq_2 = other.Cq_2; 489 Cq_3 = other.Cq_3; 490 Cq_4 = other.Cq_4; 491 Eq_1 = other.Eq_1; 492 Eq_2 = other.Eq_2; 493 Eq_3 = other.Eq_3; 494 Eq_4 = other.Eq_4; 495 } 496 ~ChConstraintTuple_4vars()497 ~ChConstraintTuple_4vars() {} 498 499 /// Assignment operator: copy from other object 500 ChConstraintTuple_4vars& operator=(const ChConstraintTuple_4vars& other) { 501 variables_1 = other.variables_1; 502 variables_2 = other.variables_2; 503 variables_3 = other.variables_3; 504 variables_4 = other.variables_4; 505 Cq_1 = other.Cq_1; 506 Cq_2 = other.Cq_2; 507 Cq_3 = other.Cq_3; 508 Cq_4 = other.Cq_4; 509 Eq_1 = other.Eq_1; 510 Eq_2 = other.Eq_2; 511 Eq_3 = other.Eq_3; 512 Eq_4 = other.Eq_4; 513 return *this; 514 } 515 Get_Cq_1()516 ChRowVectorRef Get_Cq_1() { return Cq_1; } Get_Cq_2()517 ChRowVectorRef Get_Cq_2() { return Cq_2; } Get_Cq_3()518 ChRowVectorRef Get_Cq_3() { return Cq_3; } Get_Cq_4()519 ChRowVectorRef Get_Cq_4() { return Cq_4; } 520 Get_Eq_1()521 ChVectorRef Get_Eq_1() { return Eq_1; } Get_Eq_2()522 ChVectorRef Get_Eq_2() { return Eq_2; } Get_Eq_3()523 ChVectorRef Get_Eq_3() { return Eq_3; } Get_Eq_4()524 ChVectorRef Get_Eq_4() { return Eq_4; } 525 GetVariables_1()526 ChVariables* GetVariables_1() { return variables_1; } GetVariables_2()527 ChVariables* GetVariables_2() { return variables_2; } GetVariables_3()528 ChVariables* GetVariables_3() { return variables_3; } GetVariables_4()529 ChVariables* GetVariables_4() { return variables_4; } 530 SetVariables(T & m_tuple_carrier)531 void SetVariables(T& m_tuple_carrier) { 532 if (!m_tuple_carrier.GetVariables1() || !m_tuple_carrier.GetVariables2() || !m_tuple_carrier.GetVariables3() || !m_tuple_carrier.GetVariables4() ) { 533 throw ChException("ERROR. SetVariables() getting null pointer. \n"); 534 } 535 variables_1 = m_tuple_carrier.GetVariables1(); 536 variables_2 = m_tuple_carrier.GetVariables2(); 537 variables_3 = m_tuple_carrier.GetVariables3(); 538 variables_4 = m_tuple_carrier.GetVariables4(); 539 } 540 Update_auxiliary(double & g_i)541 void Update_auxiliary(double& g_i) { 542 // 1- Assuming jacobians are already computed, now compute 543 // the matrices [Eq_a]=[invM_a]*[Cq_a]' and [Eq_b] 544 if (variables_1->IsActive()) { 545 variables_1->Compute_invMb_v(Eq_1, Cq_1.transpose()); 546 } 547 if (variables_2->IsActive()) { 548 variables_2->Compute_invMb_v(Eq_2, Cq_2.transpose()); 549 } 550 if (variables_3->IsActive()) { 551 variables_3->Compute_invMb_v(Eq_3, Cq_3.transpose()); 552 } 553 if (variables_4->IsActive()) { 554 variables_4->Compute_invMb_v(Eq_4, Cq_4.transpose()); 555 } 556 557 // 2- Compute g_i = [Cq_i]*[invM_i]*[Cq_i]' + cfm_i 558 if (variables_1->IsActive()) { 559 g_i += Cq_1 * Eq_1; 560 } 561 if (variables_2->IsActive()) { 562 g_i += Cq_2 * Eq_2; 563 } 564 if (variables_3->IsActive()) { 565 g_i += Cq_3 * Eq_3; 566 } 567 if (variables_4->IsActive()) { 568 g_i += Cq_4 * Eq_4; 569 } 570 } 571 Compute_Cq_q()572 double Compute_Cq_q() { 573 double ret = 0; 574 575 if (variables_1->IsActive()) { 576 ret += Cq_1 * variables_1->Get_qb(); 577 } 578 579 if (variables_2->IsActive()) { 580 ret += Cq_2 * variables_2->Get_qb(); 581 } 582 583 if (variables_3->IsActive()) { 584 ret += Cq_3 * variables_3->Get_qb(); 585 } 586 587 if (variables_4->IsActive()) { 588 ret += Cq_4 * variables_4->Get_qb(); 589 } 590 591 return ret; 592 } 593 Increment_q(const double deltal)594 void Increment_q(const double deltal) { 595 if (variables_1->IsActive()) { 596 variables_1->Get_qb() += Eq_1 * deltal; 597 } 598 599 if (variables_2->IsActive()) { 600 variables_2->Get_qb() += Eq_2 * deltal; 601 } 602 603 if (variables_3->IsActive()) { 604 variables_3->Get_qb() += Eq_3 * deltal; 605 } 606 607 if (variables_4->IsActive()) { 608 variables_4->Get_qb() += Eq_4 * deltal; 609 } 610 } 611 MultiplyAndAdd(double & result,const ChVectorDynamic<double> & vect)612 void MultiplyAndAdd(double& result, const ChVectorDynamic<double>& vect) const { 613 if (variables_1->IsActive()) { 614 result += Cq_1 * vect.segment(variables_1->GetOffset(), T::nvars1); 615 } 616 617 if (variables_2->IsActive()) { 618 result += Cq_2 * vect.segment(variables_2->GetOffset(), T::nvars2); 619 } 620 621 if (variables_3->IsActive()) { 622 result += Cq_3 * vect.segment(variables_3->GetOffset(), T::nvars3); 623 } 624 625 if (variables_4->IsActive()) { 626 result += Cq_4 * vect.segment(variables_4->GetOffset(), T::nvars4); 627 } 628 } 629 MultiplyTandAdd(ChVectorDynamic<double> & result,double l)630 void MultiplyTandAdd(ChVectorDynamic<double>& result, double l) { 631 if (variables_1->IsActive()) { 632 result.segment(variables_1->GetOffset(), T::nvars1) += Cq_1.transpose() * l; 633 } 634 635 if (variables_2->IsActive()) { 636 result.segment(variables_2->GetOffset(), T::nvars2) += Cq_2.transpose() * l; 637 } 638 639 if (variables_3->IsActive()) { 640 result.segment(variables_3->GetOffset(), T::nvars3) += Cq_3.transpose() * l; 641 } 642 643 if (variables_4->IsActive()) { 644 result.segment(variables_4->GetOffset(), T::nvars4) += Cq_4.transpose() * l; 645 } 646 } 647 Build_Cq(ChSparseMatrix & storage,int insrow)648 void Build_Cq(ChSparseMatrix& storage, int insrow) { 649 if (variables_1->IsActive()) 650 PasteMatrix(storage, Cq_1, insrow, variables_1->GetOffset()); 651 if (variables_2->IsActive()) 652 PasteMatrix(storage, Cq_2, insrow, variables_2->GetOffset()); 653 if (variables_3->IsActive()) 654 PasteMatrix(storage, Cq_3, insrow, variables_3->GetOffset()); 655 if (variables_4->IsActive()) 656 PasteMatrix(storage, Cq_4, insrow, variables_4->GetOffset()); 657 } 658 Build_CqT(ChSparseMatrix & storage,int inscol)659 void Build_CqT(ChSparseMatrix& storage, int inscol) { 660 if (variables_1->IsActive()) 661 PasteMatrix(storage, Cq_1.transpose(), variables_1->GetOffset(), inscol); 662 if (variables_2->IsActive()) 663 PasteMatrix(storage, Cq_2.transpose(), variables_2->GetOffset(), inscol); 664 if (variables_3->IsActive()) 665 PasteMatrix(storage, Cq_3.transpose(), variables_3->GetOffset(), inscol); 666 if (variables_4->IsActive()) 667 PasteMatrix(storage, Cq_4.transpose(), variables_4->GetOffset(), inscol); 668 } 669 }; 670 671 /// This is a set of 'helper' classes that make easier to manage the templated 672 /// structure of the tuple constraints. 673 674 template <int N1> 675 class ChVariableTupleCarrier_1vars { 676 public: 677 typedef ChConstraintTuple_1vars<ChVariableTupleCarrier_1vars<N1>> type_constraint_tuple; 678 static const int nvars1 = N1; ~ChVariableTupleCarrier_1vars()679 virtual ~ChVariableTupleCarrier_1vars() {} 680 virtual ChVariables* GetVariables1() = 0; 681 }; 682 683 template <int N1, int N2> 684 class ChVariableTupleCarrier_2vars { 685 public: 686 typedef ChConstraintTuple_2vars<ChVariableTupleCarrier_2vars<N1, N2>> type_constraint_tuple; 687 static int const nvars1 = N1; 688 static int const nvars2 = N2; ~ChVariableTupleCarrier_2vars()689 virtual ~ChVariableTupleCarrier_2vars() {} 690 virtual ChVariables* GetVariables1() = 0; 691 virtual ChVariables* GetVariables2() = 0; 692 }; 693 694 template <int N1, int N2, int N3> 695 class ChVariableTupleCarrier_3vars { 696 public: 697 typedef ChConstraintTuple_3vars<ChVariableTupleCarrier_3vars<N1, N2, N3>> type_constraint_tuple; 698 static int const nvars1 = N1; 699 static int const nvars2 = N2; 700 static int const nvars3 = N3; ~ChVariableTupleCarrier_3vars()701 virtual ~ChVariableTupleCarrier_3vars() {} 702 virtual ChVariables* GetVariables1() = 0; 703 virtual ChVariables* GetVariables2() = 0; 704 virtual ChVariables* GetVariables3() = 0; 705 }; 706 707 template <int N1, int N2, int N3, int N4> 708 class ChVariableTupleCarrier_4vars { 709 public: 710 typedef ChConstraintTuple_4vars<ChVariableTupleCarrier_4vars<N1, N2, N3, N4>> type_constraint_tuple; 711 static int const nvars1 = N1; 712 static int const nvars2 = N2; 713 static int const nvars3 = N3; 714 static int const nvars4 = N4; ~ChVariableTupleCarrier_4vars()715 virtual ~ChVariableTupleCarrier_4vars() {} 716 virtual ChVariables* GetVariables1() = 0; 717 virtual ChVariables* GetVariables2() = 0; 718 virtual ChVariables* GetVariables3() = 0; 719 virtual ChVariables* GetVariables4() = 0; 720 }; 721 722 } // end namespace chrono 723 724 #endif 725