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 CHINTEGRABLE_H
16 #define CHINTEGRABLE_H
17 
18 #include <cstdlib>
19 
20 #include "chrono/core/ChApiCE.h"
21 #include "chrono/core/ChMath.h"
22 #include "chrono/timestepper/ChState.h"
23 
24 namespace chrono {
25 
26 // -----------------------------------------------------------------------------
27 
28 /// Interface class for all objects that support time integration.
29 /// Derived concrete classes can use time integrators for the ChTimestepper hierarchy.
30 class ChApi ChIntegrable {
31   public:
32     /// Return the number of coordinates in the state Y.
33     virtual int GetNcoords_y() = 0;
34 
35     /// Return the number of coordinates in the state increment.
36     /// This is a base implementation that works in many cases where dim(Y) = dim(dy),
37     /// but it can be overridden in the case that y contains quaternions for rotations
38     /// rather than simple y+dy
GetNcoords_dy()39     virtual int GetNcoords_dy() { return GetNcoords_y(); }
40 
41     /// Return the number of lagrangian multipliers (constraints).
42     /// By default returns 0.
GetNconstr()43     virtual int GetNconstr() { return 0; }
44 
45     /// Set up the system state.
StateSetup(ChState & y,ChStateDelta & dy)46     virtual void StateSetup(ChState& y, ChStateDelta& dy) {
47         y.resize(GetNcoords_y());
48         dy.resize(GetNcoords_dy());
49     }
50 
51     /// Gather system state in specified array.
52     /// Optionally, they will copy system private state, if any, to Y.
StateGather(ChState & y,double & T)53     virtual void StateGather(ChState& y, double& T) {}
54 
55     /// Scatter the states from the provided array to the system.
56     /// This function is called by time integrators every time they modify the Y state.
57     /// In some cases, the ChIntegrable object might contain dependent data structures
58     /// that might need an update at each change of Y. If so, this function must be overridden.
StateScatter(const ChState & y,const double T,bool full_update)59     virtual void StateScatter(const ChState& y, const double T, bool full_update) {}
60 
61     /// Gather from the system the state derivatives in specified array.
62     /// Optional: the integrable object might contain last computed state derivative, some integrators might reuse it.
StateGatherDerivative(ChStateDelta & Dydt)63     virtual void StateGatherDerivative(ChStateDelta& Dydt) {}
64 
65     /// Scatter the state derivatives from the provided array to the system.
66     /// Optional: the integrable object might need to store last computed state derivative, ex. for plotting etc.
StateScatterDerivative(const ChStateDelta & Dydt)67     virtual void StateScatterDerivative(const ChStateDelta& Dydt) {}
68 
69     /// Gather from the system the Lagrange multipliers in specified array.
70     /// Optional: the integrable object might contain Lagrange multipliers (reaction in constraints)
StateGatherReactions(ChVectorDynamic<> & L)71     virtual void StateGatherReactions(ChVectorDynamic<>& L) {}
72 
73     /// Scatter the Lagrange multipliers from the provided array to the system.
74     /// Optional: the integrable object might contain Lagrange multipliers (reaction in constraints)
StateScatterReactions(const ChVectorDynamic<> & L)75     virtual void StateScatterReactions(const ChVectorDynamic<>& L) {}
76 
77     /// Solve for state derivatives: dy/dt = f(y,t).
78     /// Given current state y , computes the state derivative dy/dt and Lagrange multipliers L (if any).
79     /// NOTE: some solvers (ex in DVI) cannot compute a classical derivative dy/dt when v is a function of
80     /// bounded variation, and f or L are distributions (e.g., when there are impulses and discontinuities),
81     /// so they compute a finite Dy through a finite dt. This is the reason why this function has an optional
82     /// parameter dt. In a DVI setting, one computes Dy, and returns Dy*(1/dt) here in Dydt parameter; if the
83     /// original Dy has to be known, just multiply Dydt*dt. The same for impulses: a DVI would compute
84     /// impulses I, and return L=I*(1/dt).
85     /// NOTES:
86     ///    - derived classes must take care of calling StateScatter(y,T) before computing Dy, only if
87     ///      force_state_scatter = true (otherwise it is assumed state is already in sync)
88     ///    - derived classes must take care of resizing Dy and L if needed.
89     ///
90     /// This function must return true if successful and false otherwise.
91     virtual bool StateSolve(ChStateDelta& Dydt,        ///< result: computed Dydt
92                             ChVectorDynamic<>& L,      ///< result: computed lagrangian multipliers, if any
93                             const ChState& y,          ///< current state y
94                             const double T,            ///< current time T
95                             const double dt,           ///< timestep (if needed, ex. in DVI)
96                             bool force_state_scatter,  ///< if false, y and T are not scattered to the system
97                             bool full_update           ///< if true, perform a full update during scatter
98                             ) = 0;
99 
100     /// Increment state array: y_new = y + Dy.
101     /// This is a base implementation that works in many cases, but it can be overridden
102     /// in the case that y contains quaternions for rotations, in which case rot. exponential is needed
103     /// instead of simply doing y+Dy.
104     /// NOTE: the system is not updated automatically after the state increment, so one might
105     /// need to call StateScatter().
106     virtual void StateIncrement(ChState& y_new,         ///< resulting y_new = y + Dy
107                                 const ChState& y,       ///< initial state y
108                                 const ChStateDelta& Dy  ///< state increment Dy
109                                 );
110 
111     //
112     // Functions required by implicit integration schemes
113     //
114 
115     /// Assuming an explicit ODE
116     /// <pre>
117     ///    H*dy/dt = F(y,t)
118     /// </pre>
119     /// or an explicit DAE
120     /// <pre>
121     ///    H*dy/dt = F(y,t) + Cq*L
122     ///     C(y,t) = 0
123     /// </pre>
124     /// this function must compute the state increment as required for a Newton iteration within an implicit integration
125     /// scheme.
126     /// For an ODE:
127     /// <pre>
128     ///  Dy = [ c_a*H + c_b*dF/dy ]^-1 * R
129     ///  Dy = [ G ]^-1 * R
130     /// </pre>
131     /// For a DAE with constraints:
132     /// <pre>
133     ///  |Dy| = [ G   Cq' ]^-1 * | R |
134     ///  |DL|   [ Cq  0   ]      | Qc|
135     /// </pre>
136     /// where R is a given residual and dF/dy is the Jacobian of F.
137     ///
138     /// This function must return true if successful and false otherwise.
StateSolveCorrection(ChStateDelta & Dy,ChVectorDynamic<> & L,const ChVectorDynamic<> & R,const ChVectorDynamic<> & Qc,const double a,const double b,const ChState & y,const double T,const double dt,bool force_state_scatter,bool full_update,bool force_setup)139     virtual bool StateSolveCorrection(ChStateDelta& Dy,             ///< result: computed Dy
140                                       ChVectorDynamic<>& L,         ///< result: computed lagrangian multipliers, if any
141                                       const ChVectorDynamic<>& R,   ///< the R residual
142                                       const ChVectorDynamic<>& Qc,  ///< the Qc residual
143                                       const double a,               ///< the factor in c_a*H
144                                       const double b,               ///< the factor in c_b*dF/dy
145                                       const ChState& y,             ///< current state y
146                                       const double T,               ///< current time T
147                                       const double dt,              ///< timestep (if needed)
148                                       bool force_state_scatter,     ///< if false, y is not scattered to the system
149                                       bool full_update,             ///< if true, perform a full update during scatter
150                                       bool force_setup              ///< if true, call the solver's Setup() function
151     ) {
152         throw ChException("StateSolveCorrection() not implemented, implicit integrators cannot be used. ");
153     }
154 
155     /// Increment a vector R (usually the residual in a Newton Raphson iteration
156     /// for solving an implicit integration step) with a term that has H multiplied a given vector w:
157     ///    R += c*H*w
LoadResidual_Hv(ChVectorDynamic<> & R,const ChVectorDynamic<> & v,const double c)158     virtual void LoadResidual_Hv(ChVectorDynamic<>& R,        ///< result: the R residual, R += c*M*v
159                                  const ChVectorDynamic<>& v,  ///< the v vector
160                                  const double c               ///< a scaling factor
161                                  ) {
162         throw ChException("LoadResidual_Hv() not implemented, implicit integrators cannot be used. ");
163     }
164 
165     /// Increment a vector R (usually the residual in a Newton Raphson iteration
166     /// for solving an implicit integration step) with the term c*F:
167     ///    R += c*F
LoadResidual_F(ChVectorDynamic<> & R,const double c)168     virtual void LoadResidual_F(ChVectorDynamic<>& R,  ///< result: the R residual, R += c*F
169                                 const double c         ///< a scaling factor
170                                 ) {
171         throw ChException("LoadResidual_F() not implemented, implicit integrators cannot be used. ");
172     }
173 
174     /// Increment a vector R (usually the residual in a Newton Raphson iteration
175     /// for solving an implicit integration step) with the term Cq'*L:
176     ///    R += c*Cq'*L
LoadResidual_CqL(ChVectorDynamic<> & R,const ChVectorDynamic<> & L,const double c)177     virtual void LoadResidual_CqL(ChVectorDynamic<>& R,        ///< result: the R residual, R += c*Cq'*L
178                                   const ChVectorDynamic<>& L,  ///< the L vector
179                                   const double c               ///< a scaling factor
180                                   ) {
181         throw ChException("LoadResidual_CqL() not implemented, implicit integrators cannot be used. ");
182     }
183 
184     /// Increment a vector Qc (usually the residual in a Newton Raphson iteration
185     /// for solving an implicit integration step, constraint part) with the term C:
186     ///    Qc += c*C
187     virtual void LoadConstraint_C(ChVectorDynamic<>& Qc,        ///< result: the Qc residual, Qc += c*C
188                                   const double c,               ///< a scaling factor
189                                   const bool do_clamp = false,  ///< enable optional clamping of Qc
190                                   const double mclam = 1e30     ///< clamping value
191                                   ) {
192         throw ChException("LoadConstraint_C() not implemented, implicit integrators cannot be used. ");
193     }
194 
195     /// Increment a vector Qc (usually the residual in a Newton Raphson iteration
196     /// for solving an implicit integration step, constraint part) with the term Ct = partial derivative dC/dt:
197     ///    Qc += c*Ct
LoadConstraint_Ct(ChVectorDynamic<> & Qc,const double c)198     virtual void LoadConstraint_Ct(ChVectorDynamic<>& Qc,  ///< result: the Qc residual, Qc += c*Ct
199                                    const double c          ///< a scaling factor
200                                    ) {
201         throw ChException("LoadConstraint_Ct() not implemented, implicit integrators cannot be used. ");
202     }
203 };
204 
205 // -----------------------------------------------------------------------------
206 
207 /// Special subcase: II-order differential system.
208 /// Interface class for all objects that support time integration with state y that is second order:
209 ///     y = {x, v} , dy/dt={v, a}
210 /// with positions x, speeds v=dx/dt, and accelerations a=ddx/dtdt.
211 /// Such systems permit the use of special integrators that can exploit the particular system structure.
212 class ChApi ChIntegrableIIorder : public ChIntegrable {
213   public:
214     /// Return the number of position coordinates x in y = {x, v}
215     virtual int GetNcoords_x() = 0;
216 
217     /// Return the number of speed coordinates of v in y = {x, v} and  dy/dt={v, a}
218     /// This is a base implementation that works in many cases where dim(v) = dim(x), but
219     /// might be less ex. if x uses quaternions and v uses angular vel.
GetNcoords_v()220     virtual int GetNcoords_v() { return GetNcoords_x(); }
221 
222     /// Return the number of acceleration coordinates of a in dy/dt={v, a}
223     /// This is a default implementation that works in almost all cases, as dim(a) = dim(v),
GetNcoords_a()224     virtual int GetNcoords_a() { return GetNcoords_v(); }
225 
226     /// Set up the system state with separate II order components x, v, a
227     /// for y = {x, v} and  dy/dt={v, a}
228     virtual void StateSetup(ChState& x, ChStateDelta& v, ChStateDelta& a);
229 
230     /// From system to state y={x,v}
231     /// Optionally, they will copy system private state, if any, to y={x,v}
StateGather(ChState & x,ChStateDelta & v,double & T)232     virtual void StateGather(ChState& x, ChStateDelta& v, double& T) {}
233 
234     /// Scatter the states from the provided arrays to the system.
235     /// This function is called by time integrators all times they modify the Y state.
236     /// In some cases, the ChIntegrable object might contain dependent data structures
237     /// that might need an update at each change of Y. If so, this function must be overridden.
StateScatter(const ChState & x,const ChStateDelta & v,const double T,bool full_update)238     virtual void StateScatter(const ChState& x, const ChStateDelta& v, const double T, bool full_update) {}
239 
240     /// Gather from the system the acceleration in specified array.
241     /// Optional: the integrable object might contain last computed state derivative, some integrators might use it.
StateGatherAcceleration(ChStateDelta & a)242     virtual void StateGatherAcceleration(ChStateDelta& a) {}
243 
244     /// Scatter the acceleration from the provided array to the system.
245     /// Optional: the integrable object might contain last computed state derivative, some integrators might use it.
StateScatterAcceleration(const ChStateDelta & a)246     virtual void StateScatterAcceleration(const ChStateDelta& a) {}
247 
248     /// Solve for accelerations: a = f(x,v,t)
249     /// Given current state y={x,v} , computes acceleration a in the state derivative dy/dt={v,a} and
250     /// lagrangian multipliers L (if any).
251     /// NOTES
252     ///  - some solvers (ex in DVI) cannot compute a classical derivative dy/dt when v is a function
253     ///    of bounded variation, and f or L are distributions (e.g., when there are impulses and
254     ///    discontinuities), so they compute a finite Dv through a finite dt. This is the reason why
255     ///    this function has an optional parameter dt. In a DVI setting, one computes Dv, and returns
256     ///    Dv*(1/dt) here in Dvdt parameter; if the original Dv has to be known, just multiply Dvdt*dt later.
257     ///    The same for impulses: a DVI would compute impulses I, and return L=I*(1/dt).
258     ///  - derived classes must take care of calling StateScatter(y,T) before computing Dy, only if
259     ///    force_state_scatter = true (otherwise it is assumed state is already in sync)
260     ///  - derived classes must take care of resizing Dv if needed.
261     ///
262     /// This function must return true if successful and false otherwise.
263     ///
264     /// This default implementation uses the same functions already used for implicit integration.
265     /// WARNING: this implementation avoids the computation of the analytical expression for Qc, but
266     /// at the cost of three StateScatter updates (always complete updates).
267     virtual bool StateSolveA(ChStateDelta& Dvdt,        ///< result: computed a for a=dv/dt
268                              ChVectorDynamic<>& L,      ///< result: computed lagrangian multipliers, if any
269                              const ChState& x,          ///< current state, x
270                              const ChStateDelta& v,     ///< current state, v
271                              const double T,            ///< current time T
272                              const double dt,           ///< timestep (if needed)
273                              bool force_state_scatter,  ///< if false, x,v and T are not scattered to the system
274                              bool full_update           ///< if true, perform a full update during scatter
275     );
276 
277     /// Increment state array:  x_new = x + dx    for x in    Y = {x, dx/dt}
278     /// This is a base implementation that works in many cases, but it can be overridden
279     /// in the case that x contains quaternions for rotations
280     /// NOTE: the system is not updated automatically after the state increment, so one might
281     /// need to call StateScatter() if needed.
282     virtual void StateIncrementX(ChState& x_new,         ///< resulting x_new = x + Dx
283                                  const ChState& x,       ///< initial state x
284                                  const ChStateDelta& Dx  ///< state increment Dx
285                                  );
286 
287     //
288     // Functions required by implicit integration schemes
289     //
290 
291     /// Assuming an explicit ODE in the form
292     /// <pre>
293     ///        M*a = F(x,v,t)
294     /// </pre>
295     /// or an explicit DAE in the form
296     /// <pre>
297     ///        M*a = F(x,v,t) + Cq'*L
298     ///     C(x,t) = 0
299     /// </pre>
300     /// this function must compute the solution of the change Du (in a or v or x) for a Newton iteration within an
301     /// implicit integration scheme.
302     /// If in ODE case: <pre>
303     ///  Du = [ c_a*M + c_v*dF/dv + c_x*dF/dx ]^-1 * R
304     ///  Du = [ G ]^-1 * R
305     /// </pre>
306     /// If with DAE constraints:
307     /// <pre>
308     ///  |Du| = [ G   Cq' ]^-1 * | R |
309     ///  |DL|   [ Cq  0   ]      | Qc|
310     /// </pre>
311     /// where R is a given residual, dF/dv and dF/dx, dF/dv are jacobians (that are also
312     /// -R and -K, damping and stiffness (tangent) matrices in many mechanical problems, note the minus sign!).
313     /// It is up to the derived class how to solve such linear system.
314     ///
315     /// This function must return true if successful and false otherwise.
StateSolveCorrection(ChStateDelta & Dv,ChVectorDynamic<> & L,const ChVectorDynamic<> & R,const ChVectorDynamic<> & Qc,const double c_a,const double c_v,const double c_x,const ChState & x,const ChStateDelta & v,const double T,bool force_state_scatter,bool full_update,bool force_setup)316     virtual bool StateSolveCorrection(
317         ChStateDelta& Dv,             ///< result: computed Dv
318         ChVectorDynamic<>& L,         ///< result: computed lagrangian multipliers, if any
319         const ChVectorDynamic<>& R,   ///< the R residual
320         const ChVectorDynamic<>& Qc,  ///< the Qc residual
321         const double c_a,             ///< the factor in c_a*M
322         const double c_v,             ///< the factor in c_v*dF/dv
323         const double c_x,             ///< the factor in c_x*dF/dv
324         const ChState& x,             ///< current state, x part
325         const ChStateDelta& v,        ///< current state, v part
326         const double T,               ///< current time T
327         bool force_state_scatter,     ///< if false, x and v are not scattered to the system
328         bool full_update,             ///< if true, perform a full update during scatter
329         bool force_setup              ///< if true, call the solver's Setup() function
330     ) {
331         throw ChException("StateSolveCorrection() not implemented, implicit integrators cannot be used. ");
332     }
333 
334     /// Assuming   M*a = F(x,v,t) + Cq'*L
335     ///         C(x,t) = 0
336     /// increment a vector R (usually the residual in a Newton Raphson iteration
337     /// for solving an implicit integration step) with the term c*F:
338     ///    R += c*F
LoadResidual_F(ChVectorDynamic<> & R,const double c)339     virtual void LoadResidual_F(ChVectorDynamic<>& R,  ///< result: the R residual, R += c*F
340                                 const double c         ///< a scaling factor
341                                 ) override {
342         throw ChException("LoadResidual_F() not implemented, implicit integrators cannot be used. ");
343     }
344 
345     /// Assuming   M*a = F(x,v,t) + Cq'*L
346     ///         C(x,t) = 0
347     /// increment a vector R (usually the residual in a Newton Raphson iteration
348     /// for solving an implicit integration step) with a term that has M multiplied a given vector w:
349     ///    R += c*M*w
LoadResidual_Mv(ChVectorDynamic<> & R,const ChVectorDynamic<> & w,const double c)350     virtual void LoadResidual_Mv(ChVectorDynamic<>& R,        ///< result: the R residual, R += c*M*v
351                                  const ChVectorDynamic<>& w,  ///< the w vector
352                                  const double c               ///< a scaling factor
353                                  ) {
354         throw ChException("LoadResidual_Mv() not implemented, implicit integrators cannot be used. ");
355     }
356 
357     /// Assuming   M*a = F(x,v,t) + Cq'*L
358     ///         C(x,t) = 0
359     /// increment a vectorR (usually the residual in a Newton Raphson iteration
360     /// for solving an implicit integration step) with the term Cq'*L:
361     ///    R += c*Cq'*L
LoadResidual_CqL(ChVectorDynamic<> & R,const ChVectorDynamic<> & L,const double c)362     virtual void LoadResidual_CqL(ChVectorDynamic<>& R,        ///< result: the R residual, R += c*Cq'*L
363                                   const ChVectorDynamic<>& L,  ///< the L vector
364                                   const double c               ///< a scaling factor
365                                   ) override {
366         throw ChException("LoadResidual_CqL() not implemented, implicit integrators cannot be used. ");
367     }
368 
369     /// Assuming   M*a = F(x,v,t) + Cq'*L
370     ///         C(x,t) = 0
371     /// Increment a vector Qc (usually the residual in a Newton Raphson iteration
372     /// for solving an implicit integration step, constraint part) with the term C:
373     ///    Qc += c*C
374     virtual void LoadConstraint_C(ChVectorDynamic<>& Qc,        ///< result: the Qc residual, Qc += c*C
375                                   const double c,               ///< a scaling factor
376                                   const bool do_clamp = false,  ///< enable optional clamping of Qc
377                                   const double mclam = 1e30     ///< clamping value
378                                   ) override {
379         throw ChException("LoadConstraint_C() not implemented, implicit integrators cannot be used. ");
380     }
381 
382     /// Assuming   M*a = F(x,v,t) + Cq'*L
383     ///         C(x,t) = 0
384     /// Increment a vector Qc (usually the residual in a Newton Raphson iteration
385     /// for solving an implicit integration step, constraint part) with the term Ct = partial derivative dC/dt:
386     ///    Qc += c*Ct
LoadConstraint_Ct(ChVectorDynamic<> & Qc,const double c)387     virtual void LoadConstraint_Ct(ChVectorDynamic<>& Qc,  ///< result: the Qc residual, Qc += c*Ct
388                                    const double c          ///< a scaling factor
389                                    ) override {
390         throw ChException("LoadConstraint_Ct() not implemented, implicit integrators cannot be used. ");
391     }
392 
393     //
394     // OVERRIDE ChIntegrable BASE MEMBERS TO SUPPORT 1st ORDER INTEGRATORS:
395     //
396 
397     // The following functions override the members in the base ChIntegrable class
398     // using a default bookkeeping that allows you to use timesteppers for 1st
399     // order integration with this II order system. The trick is that
400     // the x and v state parts are assembled into y={x,y} as this is needed,
401     // and viceversa. Same for dy/dt={v,a}.
402     // NOTE: PERFORMANCE WARNING: this default bookkeeping requires temporary allocation
403     //  and deallocation of temporary vectors and some copies.
404     // NOTE: performance penalty is not a big issue since one should try to use
405     //   custom II order timesteppers if possible.
406     // NOTE: children classes does not need to override those default functions.
407 
408     /// Return the number of coordinates in the state Y.
409     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
GetNcoords_y()410     virtual int GetNcoords_y() override { return GetNcoords_x() + GetNcoords_v(); }
411 
412     /// Return the number of coordinates in the state increment.
413     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
GetNcoords_dy()414     virtual int GetNcoords_dy() override { return GetNcoords_v() + GetNcoords_a(); }
415 
416     /// Gather system state in specified array.
417     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
418     /// PERFORMANCE WARNING! temporary vectors allocated on heap. This is only to support
419     /// compatibility with 1st order integrators.
420     virtual void StateGather(ChState& y, double& T) override;
421 
422     /// Scatter the states from the provided array to the system.
423     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
424     /// PERFORMANCE WARNING! temporary vectors allocated on heap. This is only to support
425     /// compatibility with 1st order integrators.
426     virtual void StateScatter(const ChState& y, const double T, bool full_update) override;
427 
428     /// Gather from the system the state derivatives in specified array.
429     /// The integrable object might contain last computed state derivative, some integrators might reuse it.
430     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
431     /// PERFORMANCE WARNING! temporary vectors allocated on heap. This is only to support
432     /// compatibility with 1st order integrators.
433     virtual void StateGatherDerivative(ChStateDelta& Dydt) override;
434 
435     /// Scatter the state derivatives from the provided array to the system.
436     /// The integrable object might need to store last computed state derivative, ex. for plotting etc.
437     /// NOTE! the velocity in dsdt={v,a} is not scattered to the II order integrable, only acceleration is scattered!
438     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
439     /// PERFORMANCE WARNING! temporary vectors allocated on heap. This is only to support
440     /// compatibility with 1st order integrators.
441     virtual void StateScatterDerivative(const ChStateDelta& Dydt) override;
442 
443     /// Increment state array: y_new = y + Dy.
444     /// This is a base implementation that works in many cases.
445     /// It calls StateIncrementX() if used on x in y={x, dx/dt}.
446     /// It calls StateIncrementX() for x, and a normal sum for dx/dt if used on y in y={x, dx/dt}
447     virtual void StateIncrement(ChState& y_new,         ///< resulting y_new = y + Dy
448                                 const ChState& y,       ///< initial state y
449                                 const ChStateDelta& Dy  ///< state increment Dy
450                                 ) override;
451 
452     /// Solve for state derivatives: dy/dt = f(y,t).
453     /// (overrides base - just a fallback to enable using with plain 1st order timesteppers)
454     /// PERFORMANCE WARNING! temporary vectors allocated on heap. This is only to support
455     /// compatibility with 1st order integrators.
456     virtual bool StateSolve(ChStateDelta& dydt,        ///< result: computed dydt
457                             ChVectorDynamic<>& L,      ///< result: computed lagrangian multipliers, if any
458                             const ChState& y,          ///< current state y
459                             const double T,            ///< current time T
460                             const double dt,           ///< timestep (if needed, ex. in DVI)
461                             bool force_state_scatter,  ///< if false, y and T are not scattered to the system
462                             bool full_update           ///< if true, perform a full update during scatter
463                             ) override;
464 
465     /// Override of method for Ist order implicit integrators.
466     /// This is disabled here because implicit integrators for Ist order cannot be used for a IInd order system.
StateSolveCorrection(ChStateDelta & Dy,ChVectorDynamic<> & L,const ChVectorDynamic<> & R,const ChVectorDynamic<> & Qc,const double a,const double b,const ChState & y,const double T,const double dt,bool force_state_scatter,bool full_update,bool force_setup)467     virtual bool StateSolveCorrection(ChStateDelta& Dy,
468                                       ChVectorDynamic<>& L,
469                                       const ChVectorDynamic<>& R,
470                                       const ChVectorDynamic<>& Qc,
471                                       const double a,
472                                       const double b,
473                                       const ChState& y,
474                                       const double T,
475                                       const double dt,
476                                       bool force_state_scatter,
477                                       bool full_update,
478                                       bool force_setup) override final {
479         throw ChException(
480             "StateSolveCorrection() not implemented for ChIntegrableIIorder, implicit integrators for Ist order cannot "
481             "be used. ");
482     }
483 
484   private:
485     using ChIntegrable::StateSetup;
486 };
487 
488 // -----------------------------------------------------------------------------
489 
490 /// Custom operator "+" that takes care of incremental update of a state y by an increment Dy.
491 /// "y_new = y + Dy", invokes the specialized StateIncrement() in the ChIntegrable. If none is
492 /// provided, this defaults to a simple vector sum
493 inline ChState operator+(const ChState& y, const ChStateDelta& Dy) {
494     ChState result(y.size(), y.GetIntegrable());
495     y.GetIntegrable()->StateIncrement(result, y, Dy);
496     return result;
497 }
498 inline ChState& operator+=(ChState& y, const ChStateDelta& Dy) {
499     ChState tmp_y(y);
500     y.GetIntegrable()->StateIncrement(y, tmp_y, Dy);
501     return y;
502 }
503 
504 /// Custom operator "+" that takes care of incremental update of a state y by an increment Dy
505 /// "y_new = Dy + y", invokes the specialized StateIncrement() in the ChIntegrable. If none is
506 /// provided, this defaults to a simple vector sum
507 inline ChState operator+(const ChStateDelta& Dy, const ChState& y) {
508     ChState result(y.size(), y.GetIntegrable());
509     y.GetIntegrable()->StateIncrement(result, y, Dy);
510     return result;
511 }
512 
513 /// Custom operator "-" that takes care of incremental update of a state y by an increment Dy.
514 /// "y_new = y - Dy", invokes the specialized StateIncrement() in the ChIntegrable. If none is
515 /// provided, this defaults to a simple vector sum
516 inline ChState operator-(const ChState& y, const ChStateDelta& Dy) {
517     ChState result(y.size(), y.GetIntegrable());
518     y.GetIntegrable()->StateIncrement(result, y, Dy*-1);
519     return result;
520 }
521 inline ChState& operator-=(ChState& y, const ChStateDelta& Dy) {
522     ChState tmp_y(y);
523     y.GetIntegrable()->StateIncrement(y, tmp_y, Dy*-1);
524     return y;
525 }
526 
527 /// Custom operator "-" that takes care of incremental update of a state y by an increment Dy
528 /// "y_new = Dy - y", invokes the specialized StateIncrement() in the ChIntegrable. If none is
529 /// provided, this defaults to a simple vector sum
530 inline ChState operator-(const ChStateDelta& Dy, const ChState& y) {
531     ChState result(y.size(), y.GetIntegrable());
532     y.GetIntegrable()->StateIncrement(result, y, Dy*-1);
533     return result;
534 }
535 }  // end namespace chrono
536 
537 #endif
538