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 <cmath>
16 
17 #include "chrono/timestepper/ChTimestepper.h"
18 
19 namespace chrono {
20 
21 // -----------------------------------------------------------------------------
22 
23 // Trick to avoid putting the following mapper macro inside the class definition in .h file:
24 // enclose macros in local 'my_enum_mappers', just to avoid avoiding cluttering of the parent class.
25 class my_enum_mappers : public ChTimestepper {
26   public:
27     CH_ENUM_MAPPER_BEGIN(Type);
28     CH_ENUM_VAL(Type::EULER_IMPLICIT);
29     CH_ENUM_VAL(Type::EULER_IMPLICIT_LINEARIZED);
30     CH_ENUM_VAL(Type::EULER_IMPLICIT_PROJECTED);
31     CH_ENUM_VAL(Type::TRAPEZOIDAL);
32     CH_ENUM_VAL(Type::TRAPEZOIDAL_LINEARIZED);
33     CH_ENUM_VAL(Type::HHT);
34     CH_ENUM_VAL(Type::HEUN);
35     CH_ENUM_VAL(Type::RUNGEKUTTA45);
36     CH_ENUM_VAL(Type::EULER_EXPLICIT);
37     CH_ENUM_VAL(Type::LEAPFROG);
38     CH_ENUM_VAL(Type::NEWMARK);
39     CH_ENUM_VAL(Type::CUSTOM);
40     CH_ENUM_MAPPER_END(Type);
41 };
42 
ArchiveOUT(ChArchiveOut & archive)43 void ChTimestepper::ArchiveOUT(ChArchiveOut& archive) {
44     // version number
45     archive.VersionWrite<ChTimestepper>();
46     // method type:
47     my_enum_mappers::Type_mapper typemapper;
48     Type type = GetType();
49     archive << CHNVP(typemapper(type), "timestepper_type");
50     // serialize all member data:
51     archive << CHNVP(verbose);
52     archive << CHNVP(Qc_do_clamp);
53     archive << CHNVP(Qc_clamping);
54 }
55 
ArchiveIN(ChArchiveIn & archive)56 void ChTimestepper::ArchiveIN(ChArchiveIn& archive) {
57     // version number
58     /*int version =*/ archive.VersionRead<ChTimestepper>();
59     // method type:
60     my_enum_mappers::Type_mapper typemapper;
61     Type type = GetType();
62     archive >> CHNVP(typemapper(type), "timestepper_type");
63     // stream in all member data:
64     archive >> CHNVP(verbose);
65     archive >> CHNVP(Qc_do_clamp);
66     archive >> CHNVP(Qc_clamping);
67 }
68 // -----------------------------------------------------------------------------
69 
70 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperEulerExpl)71 CH_FACTORY_REGISTER(ChTimestepperEulerExpl)
72 
73 // Euler explicit timestepper.
74 // This performs the typical  y_new = y+ dy/dt * dt integration with Euler formula.
75 void ChTimestepperEulerExpl::Advance(const double dt) {
76     // setup main vectors
77     GetIntegrable()->StateSetup(Y, dYdt);
78 
79     // setup auxiliary vectors
80     L.setZero(GetIntegrable()->GetNconstr());
81 
82     GetIntegrable()->StateGather(Y, T);  // state <- system
83 
84     GetIntegrable()->StateSolve(dYdt, L, Y, T, dt, false, false);  // dY/dt = f(Y,T)
85 
86     // Euler formula!
87     //   y_new= y + dy/dt * dt
88 
89     Y = Y + dYdt * dt;  //  also: GetIntegrable().StateIncrement(y_new, y, Dy);
90 
91     T += dt;
92 
93     GetIntegrable()->StateScatter(Y, T, true);            // state -> system
94     GetIntegrable()->StateScatterDerivative(dYdt);  // -> system auxiliary data
95     GetIntegrable()->StateScatterReactions(L);      // -> system auxiliary data
96 }
97 
98 // -----------------------------------------------------------------------------
99 
100 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperEulerExplIIorder)101 CH_FACTORY_REGISTER(ChTimestepperEulerExplIIorder)
102 
103 // Euler explicit timestepper customized for II order.
104 // (It gives the same results of ChTimestepperEulerExpl,
105 // but this performs a bit faster because it can exploit
106 // the special structure of ChIntegrableIIorder)
107 // This performs the typical
108 //    x_new = x + v * dt
109 //    v_new = v + a * dt
110 // integration with Euler formula.
111 void ChTimestepperEulerExplIIorder::Advance(const double dt) {
112     // downcast
113     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
114 
115     // setup main vectors
116     mintegrable->StateSetup(X, V, A);
117 
118     // setup auxiliary vectors
119     Dv.setZero(mintegrable->GetNcoords_v(), GetIntegrable());
120     L.setZero(mintegrable->GetNconstr());
121 
122     mintegrable->StateGather(X, V, T);  // state <- system
123 
124     mintegrable->StateSolveA(A, L, X, V, T, dt, false, false);  // Dv/dt = f(x,v,T)
125 
126     // Euler formula!
127 
128     X = X + V * dt;  // x_new= x + v * dt
129 
130     V = V + A * dt;  // v_new= v + a * dt
131 
132     T += dt;
133 
134     mintegrable->StateScatter(X, V, T, true);  // state -> system
135     mintegrable->StateScatterAcceleration(A);  // -> system auxiliary data
136     mintegrable->StateScatterReactions(L);     // -> system auxiliary data
137 }
138 
139 // -----------------------------------------------------------------------------
140 
141 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperEulerSemiImplicit)142 CH_FACTORY_REGISTER(ChTimestepperEulerSemiImplicit)
143 
144 // Euler semi-implicit timestepper
145 // This performs the typical
146 //    v_new = v + a * dt
147 //    x_new = x + v_new * dt
148 // integration with Euler semi-implicit formula.
149 void ChTimestepperEulerSemiImplicit::Advance(const double dt) {
150     // downcast
151     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
152 
153     // setup main vectors
154     mintegrable->StateSetup(X, V, A);
155 
156     // setup auxiliary vectors
157     L.setZero(mintegrable->GetNconstr());
158 
159     mintegrable->StateGather(X, V, T);  // state <- system
160 
161     mintegrable->StateSolveA(A, L, X, V, T, dt, false, false);  // Dv/dt = f(x,v,T)   Dv = f(x,v,T)*dt
162 
163     // Semi-implicit Euler formula!   (note the order of update of x and v, respect to original Euler II order explicit)
164 
165     V = V + A * dt;  // v_new= v + a * dt
166 
167     X = X + V * dt;  // x_new= x + v_new * dt
168 
169     T += dt;
170 
171     mintegrable->StateScatter(X, V, T, true);  // state -> system
172     mintegrable->StateScatterAcceleration(A);  // -> system auxiliary data
173     mintegrable->StateScatterReactions(L);     // -> system auxiliary data
174 }
175 
176 // -----------------------------------------------------------------------------
177 
178 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperRungeKuttaExpl)179 CH_FACTORY_REGISTER(ChTimestepperRungeKuttaExpl)
180 
181 // Performs a step of a 4th order explicit Runge-Kutta integration scheme.
182 void ChTimestepperRungeKuttaExpl::Advance(const double dt) {
183     // setup main vectors
184     GetIntegrable()->StateSetup(Y, dYdt);
185 
186     // setup auxiliary vectors
187     int n_y = GetIntegrable()->GetNcoords_y();
188     int n_dy = GetIntegrable()->GetNcoords_dy();
189     int n_c = GetIntegrable()->GetNconstr();
190     y_new.setZero(n_y, GetIntegrable());
191     Dydt1.setZero(n_dy, GetIntegrable());
192     Dydt2.setZero(n_dy, GetIntegrable());
193     Dydt3.setZero(n_dy, GetIntegrable());
194     Dydt4.setZero(n_dy, GetIntegrable());
195     L.setZero(n_c);
196 
197     GetIntegrable()->StateGather(Y, T);  // state <- system
198 
199     GetIntegrable()->StateSolve(Dydt1, L, Y, T, dt,
200                                 false,  // no need to scatter state before computation
201                                 false   // full update? (not used since no scatter)
202     );
203 
204     y_new = Y + Dydt1 * 0.5 * dt;  // integrable.StateIncrement(y_new, Y, Dydt1*0.5*dt);
205     GetIntegrable()->StateSolve(Dydt2, L, y_new, T + dt * 0.5, dt, true, true);
206 
207     y_new = Y + Dydt2 * 0.5 * dt;  // integrable.StateIncrement(y_new, Y, Dydt2*0.5*dt);
208     GetIntegrable()->StateSolve(Dydt3, L, y_new, T + dt * 0.5, dt, true, true);
209 
210     y_new = Y + Dydt3 * dt;  // integrable.StateIncrement(y_new, Y, Dydt3*dt);
211     GetIntegrable()->StateSolve(Dydt4, L, y_new, T + dt, dt, true, true);
212 
213     Y = Y + (Dydt1 + Dydt2 * 2.0 + Dydt3 * 2.0 + Dydt4) * (1. / 6.) * dt;  // integrable.StateIncrement(...);
214     dYdt = Dydt4;                                                          // to check
215     T += dt;
216 
217     GetIntegrable()->StateScatter(Y, T, true);            // state -> system
218     GetIntegrable()->StateScatterDerivative(dYdt);  // -> system auxiliary data
219     GetIntegrable()->StateScatterReactions(L);      // -> system auxiliary data
220 }
221 
222 // -----------------------------------------------------------------------------
223 
224 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperHeun)225 CH_FACTORY_REGISTER(ChTimestepperHeun)
226 
227 // Performs a step of a Heun explicit integrator. It is like a 2nd Runge Kutta.
228 void ChTimestepperHeun::Advance(const double dt) {
229     // setup main vectors
230     GetIntegrable()->StateSetup(Y, dYdt);
231 
232     // setup auxiliary vectors
233     int n_y = GetIntegrable()->GetNcoords_y();
234     int n_dy = GetIntegrable()->GetNcoords_dy();
235     int n_c = GetIntegrable()->GetNconstr();
236     y_new.setZero(n_y, GetIntegrable());
237     Dydt1.setZero(n_dy, GetIntegrable());
238     Dydt2.setZero(n_dy, GetIntegrable());
239     L.setZero(n_c);
240 
241     GetIntegrable()->StateGather(Y, T);  // state <- system
242 
243     GetIntegrable()->StateSolve(Dydt1, L, Y, T, dt,
244                                 false,  // no need to scatter state before computation
245                                 false   // full update? ( not used, since no scatter)
246     );
247     y_new = Y + Dydt1 * dt;
248     GetIntegrable()->StateSolve(Dydt2, L, y_new, T + dt, dt, true, true);
249 
250     Y = Y + (Dydt1 + Dydt2) * (dt / 2.);
251     dYdt = Dydt2;
252     T += dt;
253 
254     GetIntegrable()->StateScatter(Y, T, true);            // state -> system
255     GetIntegrable()->StateScatterDerivative(dYdt);  // -> system auxiliary data
256     GetIntegrable()->StateScatterReactions(L);      // -> system auxiliary data
257 }
258 
259 // -----------------------------------------------------------------------------
260 
261 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperLeapfrog)262 CH_FACTORY_REGISTER(ChTimestepperLeapfrog)
263 
264 // Performs a step of a Leapfrog explicit integrator.
265 // It is a symplectic method, with 2nd order accuracy,
266 // at least when F depends on positions only.
267 // Note: uses last step acceleration: changing or resorting
268 // the numbering of DOFs will invalidate it.
269 // Suggestion: use the ChTimestepperEulerSemiImplicit, it gives
270 // the same accuracy with a bit of faster performance.
271 void ChTimestepperLeapfrog::Advance(const double dt) {
272     // downcast
273     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
274 
275     // setup main vectors
276     mintegrable->StateSetup(X, V, A);
277 
278     // setup auxiliary vectors
279     L.setZero(mintegrable->GetNconstr());
280     Aold.setZero(mintegrable->GetNcoords_v(), GetIntegrable());
281 
282     mintegrable->StateGather(X, V, T);  // state <- system
283     mintegrable->StateGatherAcceleration(Aold);
284 
285     // advance X (uses last A)
286     X = X + V * dt + Aold * (0.5 * dt * dt);
287 
288     // computes new A  (NOTE!!true for imposing a state-> system scatter update,because X changed..)
289     mintegrable->StateSolveA(A, L, X, V, T, dt, true, true);  // Dv/dt = f(x,v,T)   Dv = f(x,v,T)*dt
290 
291     // advance V
292 
293     V = V + (Aold + A) * (0.5 * dt);
294 
295     T += dt;
296 
297     mintegrable->StateScatter(X, V, T, true);  // state -> system
298     mintegrable->StateScatterAcceleration(A);  // -> system auxiliary data
299     mintegrable->StateScatterReactions(L);     // -> system auxiliary data
300 }
301 
302 // -----------------------------------------------------------------------------
303 
304 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperEulerImplicit)305 CH_FACTORY_REGISTER(ChTimestepperEulerImplicit)
306 
307 // Performs a step of Euler implicit for II order systems
308 void ChTimestepperEulerImplicit::Advance(const double dt) {
309     // downcast
310     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
311 
312     // setup main vectors
313     mintegrable->StateSetup(X, V, A);
314 
315     // setup auxiliary vectors
316     Dv.setZero(mintegrable->GetNcoords_v(), GetIntegrable());
317     Dl.setZero(mintegrable->GetNconstr());
318     Xnew.setZero(mintegrable->GetNcoords_x(), mintegrable);
319     Vnew.setZero(mintegrable->GetNcoords_v(), mintegrable);
320     R.setZero(mintegrable->GetNcoords_v());
321     Qc.setZero(mintegrable->GetNconstr());
322     L.setZero(mintegrable->GetNconstr());
323 
324     mintegrable->StateGather(X, V, T);  // state <- system
325 
326     // Extrapolate a prediction as warm start
327 
328     Xnew = X + V * dt;
329     Vnew = V;  //+ A()*dt;
330 
331     // use Newton Raphson iteration to solve implicit Euler for v_new
332     //
333     // [ M - dt*dF/dv - dt^2*dF/dx    Cq' ] [ Dv     ] = [ M*(v_old - v_new) + dt*f + dt*Cq'*l ]
334     // [ Cq                           0   ] [ -dt*Dl ] = [ -C/dt  ]
335 
336     numiters = 0;
337     numsetups = 0;
338     numsolves = 0;
339 
340     for (int i = 0; i < this->GetMaxiters(); ++i) {
341         mintegrable->StateScatter(Xnew, Vnew, T + dt, false);  // state -> system
342         R.setZero();
343         Qc.setZero();
344         mintegrable->LoadResidual_F(R, dt);
345         mintegrable->LoadResidual_Mv(R, (V - Vnew), 1.0);
346         mintegrable->LoadResidual_CqL(R, L, dt);
347         mintegrable->LoadConstraint_C(Qc, 1.0 / dt, Qc_do_clamp, Qc_clamping);
348 
349         if (verbose)
350             GetLog() << " Euler iteration=" << i << "  |R|=" << R.lpNorm<Eigen::Infinity>()
351                      << "  |Qc|=" << Qc.lpNorm<Eigen::Infinity>() << "\n";
352 
353         if ((R.lpNorm<Eigen::Infinity>() < abstolS) && (Qc.lpNorm<Eigen::Infinity>() < abstolL))
354             break;
355 
356         mintegrable->StateSolveCorrection(  //
357             Dv, Dl, R, Qc,                  //
358             1.0,                            // factor for  M
359             -dt,                            // factor for  dF/dv
360             -dt * dt,                       // factor for  dF/dx
361             Xnew, Vnew, T + dt,             // not used here (scatter = false)
362             false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
363             false,                          // full update? (not used, since no scatter)
364             true                            // always call the solver's Setup
365         );
366 
367         numiters++;
368         numsetups++;
369         numsolves++;
370 
371         Dl *= (1.0 / dt);  // Note it is not -(1.0/dt) because we assume StateSolveCorrection already flips sign of Dl
372         L += Dl;
373 
374         Vnew += Dv;
375 
376         Xnew = X + Vnew * dt;
377     }
378 
379     mintegrable->StateScatterAcceleration(
380         (Vnew - V) * (1 / dt));  // -> system auxiliary data (i.e acceleration as measure, fits DVI/MDI)
381 
382     X = Xnew;
383     V = Vnew;
384     T += dt;
385 
386     mintegrable->StateScatter(X, V, T, true);     // state -> system
387     mintegrable->StateScatterReactions(L);  // -> system auxiliary data
388 }
389 
390 // -----------------------------------------------------------------------------
391 
392 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperEulerImplicitLinearized)393 CH_FACTORY_REGISTER(ChTimestepperEulerImplicitLinearized)
394 
395 // Performs a step of Euler implicit for II order systems
396 // using the Anitescu/Stewart/Trinkle single-iteration method,
397 // that is a bit like an implicit Euler where one performs only
398 // the first NR corrector iteration.
399 // If the solver in StateSolveCorrection is a CCP complementarity
400 // solver, this is the typical Anitescu stabilized timestepper for DVIs.
401 void ChTimestepperEulerImplicitLinearized::Advance(const double dt) {
402     // downcast
403     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
404 
405     // setup main vectors
406     mintegrable->StateSetup(X, V, A);
407 
408     // setup auxiliary vectors
409     Dl.setZero(mintegrable->GetNconstr());
410     R.setZero(mintegrable->GetNcoords_v());
411     Qc.setZero(mintegrable->GetNconstr());
412     L.setZero(mintegrable->GetNconstr());
413 
414     mintegrable->StateGather(X, V, T);  // state <- system
415 
416     mintegrable->StateGatherReactions(L);  // state <- system (may be needed for warm starting StateSolveCorrection)
417     L *= dt;                               // because reactions = forces, here L = impulses
418 
419     Vold = V;
420 
421     // solve only 1st NR step, using v_new = 0, so  Dv = v_new , therefore
422     //
423     // [ M - dt*dF/dv - dt^2*dF/dx    Cq' ] [ Dv     ] = [ M*(v_old - v_new) + dt*f]
424     // [ Cq                           0   ] [ -dt*Dl ] = [ -C/dt - Ct ]
425     //
426     // becomes the Anitescu/Trinkle timestepper:
427     //
428     // [ M - dt*dF/dv - dt^2*dF/dx    Cq' ] [ v_new  ] = [ M*(v_old) + dt*f]
429     // [ Cq                           0   ] [ -dt*l  ] = [ -C/dt - Ct ]
430 
431     mintegrable->LoadResidual_F(R, dt);
432     mintegrable->LoadResidual_Mv(R, V, 1.0);
433     mintegrable->LoadConstraint_C(Qc, 1.0 / dt, Qc_do_clamp, Qc_clamping);
434     mintegrable->LoadConstraint_Ct(Qc, 1.0);
435 
436     mintegrable->StateSolveCorrection(  //
437         V, L, R, Qc,                    //
438         1.0,                            // factor for  M
439         -dt,                            // factor for  dF/dv
440         -dt * dt,                       // factor for  dF/dx
441         X, V, T + dt,                   // not needed
442         false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
443         false,                          // full update? (not used, since no scatter)
444         true                            // force a call to the solver's Setup() function
445     );
446 
447     L *= (1.0 / dt);  // Note it is not -(1.0/dt) because we assume StateSolveCorrection already flips sign of Dl
448 
449     mintegrable->StateScatterAcceleration(
450         (V - Vold) * (1 / dt));  // -> system auxiliary data (i.e acceleration as measure, fits DVI/MDI)
451 
452     X += V * dt;
453 
454     T += dt;
455 
456     mintegrable->StateScatter(X, V, T, true);  // state -> system
457     mintegrable->StateScatterReactions(L);     // -> system auxiliary data
458 }
459 
460 // -----------------------------------------------------------------------------
461 
462 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperEulerImplicitProjected)463 CH_FACTORY_REGISTER(ChTimestepperEulerImplicitProjected)
464 
465 // Performs a step of Euler implicit for II order systems
466 // using a semi implicit Euler without constr.stabilization, followed by a projection,
467 // that is: a speed problem followed by a position problem that
468 // keeps constraint drifting 'closed' by using a projection.
469 // If the solver in StateSolveCorrection is a CCP complementarity
470 // solver, this is the Tasora stabilized timestepper for DVIs.
471 void ChTimestepperEulerImplicitProjected::Advance(const double dt) {
472     // downcast
473     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
474 
475     // setup main vectors
476     mintegrable->StateSetup(X, V, A);
477 
478     // setup auxiliary vectors
479     Dl.setZero(mintegrable->GetNconstr());
480     R.setZero(mintegrable->GetNcoords_v());
481     Qc.setZero(mintegrable->GetNconstr());
482     L.setZero(mintegrable->GetNconstr());
483 
484     mintegrable->StateGather(X, V, T);  // state <- system
485 
486     Vold = V;
487 
488     // 1
489     // Do a  Anitescu/Trinkle timestepper (it could be without the C/dt correction):
490     //
491     // [ M - dt*dF/dv - dt^2*dF/dx    Cq' ] [ v_new  ] = [ M*(v_old) + dt*f]
492     // [ Cq                           0   ] [ -dt*l  ] = [ -Ct ]
493 
494     mintegrable->LoadResidual_F(R, dt);
495     mintegrable->LoadResidual_Mv(R, V, 1.0);
496     mintegrable->LoadConstraint_C(Qc, 1.0 / dt, Qc_do_clamp, 0);  // may be avoided
497     mintegrable->LoadConstraint_Ct(Qc, 1.0);
498 
499     mintegrable->StateSolveCorrection(  //
500         V, L, R, Qc,                    //
501         1.0,                            // factor for  M
502         -dt,                            // factor for  dF/dv
503         -dt * dt,                       // factor for  dF/dx
504         X, V, T + dt,                   // not needed
505         false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
506         false,                          // full update? (not used, since no scatter)
507         true                            // force a call to the solver's Setup() function
508     );
509 
510     L *= (1.0 / dt);  // Note it is not -(1.0/dt) because we assume StateSolveCorrection already flips sign of Dl
511 
512     mintegrable->StateScatterAcceleration(
513         (V - Vold) * (1 / dt));  // -> system auxiliary data (i.e acceleration as measure, fits DVI/MDI)
514 
515     X += V * dt;
516 
517     T += dt;
518 
519     mintegrable->StateScatter(X, V, T, false);  // state -> system
520     mintegrable->StateScatterReactions(L);      // -> system auxiliary data
521 
522     // 2
523     // Do the position stabilization (single NR step on constraints, with mass matrix as metric)
524 
525     Dl.setZero(mintegrable->GetNconstr());
526     R.setZero(mintegrable->GetNcoords_v());
527     Qc.setZero(mintegrable->GetNconstr());
528     L.setZero(mintegrable->GetNconstr());
529     Vold.setZero(mintegrable->GetNcoords_v(), V.GetIntegrable());
530 
531     //
532     // [ M       Cq' ] [ dpos ] = [  0 ]
533     // [ Cq       0  ] [ l    ] = [ -C ]
534 
535     mintegrable->LoadConstraint_C(Qc, 1.0, false, 0);
536 
537     mintegrable->StateSolveCorrection(  //
538         Vold, L, R, Qc,                 //
539         1.0,                            // factor for  M
540         0,                              // factor for  dF/dv
541         0,                              // factor for  dF/dx
542         X, V, T,                        // not needed
543         false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
544         false,                          // full update? (not used, since no scatter)
545         true                            // force a call to the solver's Setup() function
546     );
547 
548     X += Vold;  // here we used 'Vold' as 'dpos' to recycle Vold and avoid allocating a new vector dpos
549 
550     mintegrable->StateScatter(X, V, T, true);  // state -> system
551 }
552 
553 // -----------------------------------------------------------------------------
554 
555 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperTrapezoidal)556 CH_FACTORY_REGISTER(ChTimestepperTrapezoidal)
557 
558 // Performs a step of trapezoidal implicit for II order systems
559 // NOTE this is a modified version of the trapezoidal for DAE: the
560 // original derivation would lead to a scheme that produces oscillatory
561 // reactions in constraints, so this is a modified version that is first
562 // order in constraint reactions. Use damped HHT or damped Newmark for
563 // more advanced options.
564 void ChTimestepperTrapezoidal::Advance(const double dt) {
565     // downcast
566     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
567 
568     // setup main vectors
569     mintegrable->StateSetup(X, V, A);
570 
571     // setup auxiliary vectors
572     Dv.setZero(mintegrable->GetNcoords_v(), GetIntegrable());
573     Dl.setZero(mintegrable->GetNconstr());
574     Xnew.setZero(mintegrable->GetNcoords_x(), mintegrable);
575     Vnew.setZero(mintegrable->GetNcoords_v(), mintegrable);
576     L.setZero(mintegrable->GetNconstr());
577     R.setZero(mintegrable->GetNcoords_v());
578     Rold.setZero(mintegrable->GetNcoords_v());
579     Qc.setZero(mintegrable->GetNconstr());
580 
581     mintegrable->StateGather(X, V, T);  // state <- system
582     // mintegrable->StateGatherReactions(L); // <- system  assume l_old = 0;  otherwise DAE gives oscillatory reactions
583 
584     // extrapolate a prediction as a warm start
585 
586     Xnew = X + V * dt;
587     Vnew = V;  // +A()*dt;
588 
589     // use Newton Raphson iteration to solve implicit trapezoidal for v_new
590     //
591     // [M-dt/2*dF/dv-dt^2/4*dF/dx  Cq'] [Dv      ] = [M*(v_old - v_new) + dt/2(f_old + f_new  + Cq*l_old + Cq*l_new)]
592     // [Cq                          0 ] [-dt/2*Dl] = [-C/dt                                                         ]
593 
594     mintegrable->LoadResidual_F(Rold, dt * 0.5);  // dt/2*f_old
595     mintegrable->LoadResidual_Mv(Rold, V, 1.0);   // M*v_old
596     // mintegrable->LoadResidual_CqL(Rold, L, dt*0.5); // dt/2*l_old   assume L_old = 0
597 
598     numiters = 0;
599     numsetups = 0;
600     numsolves = 0;
601 
602     for (int i = 0; i < this->GetMaxiters(); ++i) {
603         mintegrable->StateScatter(Xnew, Vnew, T + dt, false);  // state -> system
604         R = Rold;
605         Qc.setZero();
606         mintegrable->LoadResidual_F(R, dt * 0.5);                               // + dt/2*f_new
607         mintegrable->LoadResidual_Mv(R, Vnew, -1.0);                            // - M*v_new
608         mintegrable->LoadResidual_CqL(R, L, dt * 0.5);                          // + dt/2*Cq*l_new
609         mintegrable->LoadConstraint_C(Qc, 1.0 / dt, Qc_do_clamp, Qc_clamping);  // -C/dt
610 
611         if (verbose)
612             GetLog() << " Trapezoidal iteration=" << i << "  |R|=" << R.lpNorm<Eigen::Infinity>()
613                      << "  |Qc|=" << Qc.lpNorm<Eigen::Infinity>() << "\n";
614 
615         if ((R.lpNorm<Eigen::Infinity>() < abstolS) && (Qc.lpNorm<Eigen::Infinity>() < abstolL))
616             break;
617 
618         mintegrable->StateSolveCorrection(  //
619             Dv, Dl, R, Qc,                  //
620             1.0,                            // factor for  M
621             -dt * 0.5,                      // factor for  dF/dv
622             -dt * dt * 0.25,                // factor for  dF/dx
623             Xnew, Vnew, T + dt,             // not used here (scatter = false)
624             false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
625             false,                          // full update? (not used, since no scatter)
626             true                            // always force a call to the solver's Setup() function
627         );
628 
629         numiters++;
630         numsetups++;
631         numsolves++;
632 
633         Dl *= (2.0 / dt);  // Note it is not -(2.0/dt) because we assume StateSolveCorrection already flips sign of Dl
634         L += Dl;
635 
636         Vnew += Dv;
637 
638         Xnew = X + ((Vnew + V) * (dt * 0.5));  // Xnew = Xold + h/2(Vnew+Vold)
639     }
640 
641     mintegrable->StateScatterAcceleration(
642         (Vnew - V) * (1 / dt));  // -> system auxiliary data (i.e acceleration as measure, fits DVI/MDI)
643 
644     X = Xnew;
645     V = Vnew;
646     T += dt;
647 
648     mintegrable->StateScatter(X, V, T, true);  // state -> system
649     mintegrable->StateScatterReactions(L *=
650                                        0.5);  // -> system auxiliary data   (*=0.5 cause we used the hack of l_old = 0)
651 }
652 
653 // -----------------------------------------------------------------------------
654 
655 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperTrapezoidalLinearized)656 CH_FACTORY_REGISTER(ChTimestepperTrapezoidalLinearized)
657 
658 // Performs a step of trapezoidal implicit linearized for II order systems
659 void ChTimestepperTrapezoidalLinearized::Advance(const double dt) {
660     // downcast
661     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
662 
663     // setup main vectors
664     mintegrable->StateSetup(X, V, A);
665 
666     // setup auxiliary vectors
667     Dv.setZero(mintegrable->GetNcoords_v(), GetIntegrable());
668     Dl.setZero(mintegrable->GetNconstr());
669     Xnew.setZero(mintegrable->GetNcoords_x(), mintegrable);
670     Vnew.setZero(mintegrable->GetNcoords_v(), mintegrable);
671     L.setZero(mintegrable->GetNconstr());
672     R.setZero(mintegrable->GetNcoords_v());
673     Rold.setZero(mintegrable->GetNcoords_v());
674     Qc.setZero(mintegrable->GetNconstr());
675 
676     mintegrable->StateGather(X, V, T);  // state <- system
677     // mintegrable->StateGatherReactions(L); // <- system  assume l_old = 0;
678 
679     // extrapolate a prediction as a warm start
680 
681     Xnew = X + V * dt;
682     Vnew = V;
683 
684     // solve implicit trapezoidal for v_new
685     //
686     // [M-dt/2*dF/dv-dt^2/4*dF/dx  Cq'] [Dv      ] = [M*(v_old - v_new) + dt/2(f_old + f_new  + Cq*l_old + Cq*l_new)]
687     // [Cq                          0 ] [-dt/2*Dl] = [-C/dt                                                         ]
688 
689     mintegrable->LoadResidual_F(Rold, dt * 0.5);  // dt/2*f_old
690     mintegrable->LoadResidual_Mv(Rold, V, 1.0);   // M*v_old
691     // mintegrable->LoadResidual_CqL(Rold, L, dt*0.5); // dt/2*l_old  assume l_old = 0;
692 
693     mintegrable->StateScatter(Xnew, Vnew, T + dt, false);  // state -> system
694     R = Rold;
695     Qc.setZero();
696     mintegrable->LoadResidual_F(R, dt * 0.5);     // + dt/2*f_new
697     mintegrable->LoadResidual_Mv(R, Vnew, -1.0);  // - M*v_new
698     // mintegrable->LoadResidual_CqL(R, L, dt*0.5); // + dt/2*Cq*l_new  assume l_old = 0;
699     mintegrable->LoadConstraint_C(Qc, 1.0 / dt, Qc_do_clamp, Qc_clamping);  // -C/dt
700 
701     mintegrable->StateSolveCorrection(  //
702         Dv, Dl, R, Qc,                  //
703         1.0,                            // factor for  M
704         -dt * 0.5,                      // factor for  dF/dv
705         -dt * dt * 0.25,                // factor for  dF/dx
706         Xnew, Vnew, T + dt,             // not used here (scatter = false)
707         false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
708         false,                          // full update? (not used, since no scatter)
709         true                            // force a call to the solver's Setup() function
710     );
711 
712     numiters = 1;
713     numsetups = 1;
714     numsolves = 1;
715 
716     Dl *= (2.0 / dt);  // Note it is not -(2.0/dt) because we assume StateSolveCorrection already flips sign of Dl
717     L += Dl;
718 
719     Vnew += Dv;
720 
721     Xnew = X + ((Vnew + V) * (dt * 0.5));  // Xnew = Xold + h/2(Vnew+Vold)
722 
723     X = Xnew;
724     V = Vnew;
725     T += dt;
726 
727     mintegrable->StateScatter(X, V, T, true);                 // state -> system
728     mintegrable->StateScatterAcceleration((Dv *= (1 / dt)));  // -> system auxiliary data (i.e acceleration as measure)
729     mintegrable->StateScatterReactions(L *= 0.5);             // -> system auxiliary data (*=0.5 because use l_old = 0)
730 }
731 
732 // -----------------------------------------------------------------------------
733 
734 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperTrapezoidalLinearized2)735 CH_FACTORY_REGISTER(ChTimestepperTrapezoidalLinearized2)
736 
737 // Performs a step of trapezoidal implicit linearized for II order systems
738 //*** SIMPLIFIED VERSION -DOES NOT WORK - PREFER ChTimestepperTrapezoidalLinearized
739 void ChTimestepperTrapezoidalLinearized2::Advance(const double dt) {
740     // downcast
741     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
742 
743     // setup main vectors
744     mintegrable->StateSetup(X, V, A);
745 
746     // setup auxiliary vectors
747     Dv.setZero(mintegrable->GetNcoords_v(), GetIntegrable());
748     Xnew.setZero(mintegrable->GetNcoords_x(), mintegrable);
749     Vnew.setZero(mintegrable->GetNcoords_v(), mintegrable);
750     L.setZero(mintegrable->GetNconstr());
751     R.setZero(mintegrable->GetNcoords_v());
752     Qc.setZero(mintegrable->GetNconstr());
753 
754     mintegrable->StateGather(X, V, T);  // state <- system
755 
756     // extrapolate a prediction as a warm start
757 
758     Xnew = X + V * dt;
759     Vnew = V;
760 
761     // use Newton Raphson iteration to solve implicit trapezoidal for v_new
762     //
763     // [ M - dt/2*dF/dv - dt^2/4*dF/dx    Cq' ] [ v_new    ] = [ M*(v_old) + dt/2(f_old + f_new)]
764     // [ Cq                               0   ] [ -dt/2*L ] m= [ -C/dt                          ]
765 
766     mintegrable->LoadResidual_F(R, dt * 0.5);  // dt/2*f_old
767     mintegrable->LoadResidual_Mv(R, V, 1.0);   // M*v_old
768 
769     mintegrable->StateScatter(Xnew, Vnew, T + dt, false);  // state -> system
770     Qc.setZero();
771     mintegrable->LoadResidual_F(R, dt * 0.5);                               // + dt/2*f_new
772     mintegrable->LoadConstraint_C(Qc, 1.0 / dt, Qc_do_clamp, Qc_clamping);  // -C/dt
773 
774     mintegrable->StateSolveCorrection(  //
775         Vnew, L, R, Qc,                 //
776         1.0,                            // factor for  M
777         -dt * 0.5,                      // factor for  dF/dv
778         -dt * dt * 0.25,                // factor for  dF/dx
779         Xnew, Vnew, T + dt,             // not used here (scatter = false)
780         false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
781         false,                          // full update? (not used, since no scatter)
782         true                            // force a call to the solver's Setup() function
783     );
784 
785     numiters = 1;
786     numsetups = 1;
787     numsolves = 1;
788 
789     L *= (2.0 / dt);  // Note it is not -(2.0/dt) because we assume StateSolveCorrection already flips sign of Dl
790 
791     X += ((Vnew + V) * (dt * 0.5));  // Xnew = Xold + h/2(Vnew+Vold)
792 
793     mintegrable->StateScatterAcceleration(
794         (Vnew - V) * (1 / dt));  // -> system auxiliary data (i.e acceleration as measure, fits DVI/MDI)
795 
796     V = Vnew;
797 
798     T += dt;
799 
800     mintegrable->StateScatter(X, V, T, true);  // state -> system
801     mintegrable->StateScatterReactions(L);     // -> system auxiliary data
802 }
803 
804 // -----------------------------------------------------------------------------
805 
806 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChTimestepperNewmark)807 CH_FACTORY_REGISTER(ChTimestepperNewmark)
808 
809 // Set the numerical damping parameter gamma and the beta parameter.
810 void ChTimestepperNewmark::SetGammaBeta(double mgamma, double mbeta) {
811     gamma = mgamma;
812     if (gamma < 0.5)
813         gamma = 0.5;
814     if (gamma > 1)
815         gamma = 1;
816     beta = mbeta;
817     if (beta < 0)
818         beta = 0;
819     if (beta > 1)
820         beta = 1;
821 }
822 
823 // Performs a step of Newmark constrained implicit for II order DAE systems
Advance(const double dt)824 void ChTimestepperNewmark::Advance(const double dt) {
825     // downcast
826     ChIntegrableIIorder* mintegrable = (ChIntegrableIIorder*)this->integrable;
827 
828     // setup main vectors
829     mintegrable->StateSetup(X, V, A);
830 
831     // setup auxiliary vectors
832     Da.setZero(mintegrable->GetNcoords_a(), GetIntegrable());
833     Dl.setZero(mintegrable->GetNconstr());
834     Xnew.setZero(mintegrable->GetNcoords_x(), mintegrable);
835     Vnew.setZero(mintegrable->GetNcoords_v(), mintegrable);
836     Anew.setZero(mintegrable->GetNcoords_a(), mintegrable);
837     R.setZero(mintegrable->GetNcoords_v());
838     Rold.setZero(mintegrable->GetNcoords_v());
839     Qc.setZero(mintegrable->GetNconstr());
840     L.setZero(mintegrable->GetNconstr());
841 
842     mintegrable->StateGather(X, V, T);  // state <- system
843     mintegrable->StateGatherAcceleration(A);
844 
845     // extrapolate a prediction as a warm start
846 
847     Vnew = V;
848     Xnew = X + Vnew * dt;
849 
850     // use Newton Raphson iteration to solve implicit Newmark for a_new
851 
852     //
853     // [ M - dt*gamma*dF/dv - dt^2*beta*dF/dx    Cq' ] [ Da   ] = [ -M*(a_new) + f_new + Cq*l_new ]
854     // [ Cq                                      0   ] [ Dl   ] = [ -1/(beta*dt^2)*C              ]
855 
856     numiters = 0;
857     numsetups = 0;
858     numsolves = 0;
859     bool call_setup = true;
860 
861     for (int i = 0; i < this->GetMaxiters(); ++i) {
862         mintegrable->StateScatter(Xnew, Vnew, T + dt, false);  // state -> system
863 
864         R.setZero(mintegrable->GetNcoords_v());
865         Qc.setZero(mintegrable->GetNconstr());
866         mintegrable->LoadResidual_F(R, 1.0);                                                    //  f_new
867         mintegrable->LoadResidual_CqL(R, L, 1.0);                                               //   Cq'*l_new
868         mintegrable->LoadResidual_Mv(R, Anew, -1.0);                                            //  - M*a_new
869         mintegrable->LoadConstraint_C(Qc, (1.0 / (beta * dt * dt)), Qc_do_clamp, Qc_clamping);  //  - 1/(beta*dt^2)*C
870 
871         if (verbose)
872             GetLog() << " Newmark iteration=" << i << "  |R|=" << R.lpNorm<Eigen::Infinity>()
873                      << "  |Qc|=" << Qc.lpNorm<Eigen::Infinity>() << "\n";
874 
875         if ((R.lpNorm<Eigen::Infinity>() < abstolS) && (Qc.lpNorm<Eigen::Infinity>() < abstolL)) {
876             if (verbose) {
877                 GetLog() << " Newmark NR converged (" << i << ")." << "  T = " << T + dt << "  h = " << dt << "\n";
878             }
879             break;
880         }
881 
882         if (verbose && modified_Newton && call_setup)
883                 GetLog() << " Newmark call Setup.\n";
884 
885         mintegrable->StateSolveCorrection(  //
886             Da, Dl, R, Qc,                  //
887             1.0,                            // factor for  M
888             -dt * gamma,                    // factor for  dF/dv
889             -dt * dt * beta,                // factor for  dF/dx
890             Xnew, Vnew, T + dt,             // not used here (scatter = false)
891             false,                          // do not scatter update to Xnew Vnew T+dt before computing correction
892             false,                          // full update? (not used, since no scatter)
893             call_setup                      // force a call to the solver's Setup() function
894         );
895 
896         numiters++;
897         numsolves++;
898         if (call_setup) {
899             numsetups++;
900         }
901 
902         // If using modified Newton, do not call Setup again
903         call_setup = !modified_Newton;
904 
905         L += Dl;  // Note it is not -= Dl because we assume StateSolveCorrection flips sign of Dl
906         Anew += Da;
907 
908         Xnew = X + V * dt + A * (dt * dt * (0.5 - beta)) + Anew * (dt * dt * beta);
909 
910         Vnew = V + A * (dt * (1.0 - gamma)) + Anew * (dt * gamma);
911     }
912 
913     X = Xnew;
914     V = Vnew;
915     A = Anew;
916     T += dt;
917 
918     mintegrable->StateScatter(X, V, T, true);  // state -> system
919     mintegrable->StateScatterAcceleration(A);  // -> system auxiliary data
920     mintegrable->StateScatterReactions(L);     // -> system auxiliary data
921 }
922 
ArchiveOUT(ChArchiveOut & archive)923 void ChTimestepperNewmark::ArchiveOUT(ChArchiveOut& archive) {
924     // version number
925     archive.VersionWrite<ChTimestepperNewmark>();
926     // serialize parent class:
927     ChTimestepperIIorder::ArchiveOUT(archive);
928     ChImplicitIterativeTimestepper::ArchiveOUT(archive);
929     // serialize all member data:
930     archive << CHNVP(beta);
931     archive << CHNVP(gamma);
932 }
933 
ArchiveIN(ChArchiveIn & archive)934 void ChTimestepperNewmark::ArchiveIN(ChArchiveIn& archive) {
935     // version number
936     /*int version =*/ archive.VersionRead<ChTimestepperNewmark>();
937     // deserialize parent class:
938     ChTimestepperIIorder::ArchiveIN(archive);
939     ChImplicitIterativeTimestepper::ArchiveIN(archive);
940     // stream in all member data:
941     archive >> CHNVP(beta);
942     archive >> CHNVP(gamma);
943 }
944 
945 }  // end namespace chrono
946