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