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 CHSYSTEM_H
16 #define CHSYSTEM_H
17 
18 #include <cfloat>
19 #include <memory>
20 #include <cstdlib>
21 #include <cmath>
22 #include <cstring>
23 #include <iostream>
24 #include <list>
25 
26 #include "chrono/collision/ChCollisionSystem.h"
27 #include "chrono/core/ChGlobal.h"
28 #include "chrono/core/ChLog.h"
29 #include "chrono/core/ChMath.h"
30 #include "chrono/core/ChTimer.h"
31 #include "chrono/parallel/ChOpenMP.h"
32 #include "chrono/physics/ChAssembly.h"
33 #include "chrono/physics/ChBodyAuxRef.h"
34 #include "chrono/physics/ChContactContainer.h"
35 #include "chrono/physics/ChLinksAll.h"
36 #include "chrono/solver/ChSystemDescriptor.h"
37 #include "chrono/timestepper/ChAssemblyAnalysis.h"
38 #include "chrono/solver/ChSolver.h"
39 #include "chrono/timestepper/ChIntegrable.h"
40 #include "chrono/timestepper/ChTimestepper.h"
41 #include "chrono/timestepper/ChTimestepperHHT.h"
42 #include "chrono/timestepper/ChStaticAnalysis.h"
43 
44 namespace chrono {
45 
46 /// Physical system.
47 ///
48 /// This class is used to represent a multibody physical system,
49 /// so it acts also as a database for most items involved in
50 /// simulations, most noticeably objects of ChBody and ChLink
51 /// classes, which are used to represent mechanisms.
52 ///
53 /// Moreover, it also owns some global settings and features,
54 /// like the gravity acceleration, the global time and so on.
55 ///
56 /// This object will be responsible of performing the entire
57 /// physical simulation (dynamics, kinematics, statics, etc.),
58 /// so you need at least one ChSystem object in your program, in
59 /// order to perform simulations (you'll insert rigid bodies and
60 /// links into it..)
61 ///
62 /// Note that this is an abstract class, in your code you must
63 /// create a system from one of the concrete classes:
64 ///   @ref chrono::ChSystemNSC (for non-smooth contacts) or
65 ///   @ref chrono::ChSystemSMC (for smooth 'penalty' contacts).
66 ///
67 /// Further info at the @ref simulation_system  manual page.
68 
69 class ChApi ChSystem : public ChIntegrableIIorder {
70 
71   public:
72     /// Create a physical system.
73     ChSystem();
74 
75     /// Copy constructor
76     ChSystem(const ChSystem& other);
77 
78     /// Destructor
79     virtual ~ChSystem();
80 
81     /// "Virtual" copy constructor.
82     /// Concrete derived classes must implement this.
83     virtual ChSystem* Clone() const = 0;
84 
85     //
86     // PROPERTIES
87     //
88 
89     /// Sets the time step used for integration (dynamical simulation).
90     /// The lower this value, the more precise the simulation. Usually, values
91     /// about 0.01 s are enough for simple simulations. It may be modified automatically
92     /// by integration methods, if they support automatic time adaption.
SetStep(double m_step)93     void SetStep(double m_step) {
94         if (m_step > 0)
95             step = m_step;
96     }
97     /// Gets the current time step used for the integration (dynamical simulation).
GetStep()98     double GetStep() const { return step; }
99 
100     /// Sets the lower limit for time step (only needed if using
101     /// integration methods which support time step adaption).
SetStepMin(double m_step_min)102     void SetStepMin(double m_step_min) {
103         if (m_step_min > 0.)
104             step_min = m_step_min;
105     }
106     /// Gets the lower limit for time step
GetStepMin()107     double GetStepMin() const { return step_min; }
108 
109     /// Sets the upper limit for time step (only needed if using
110     /// integration methods which support time step adaption).
SetStepMax(double m_step_max)111     void SetStepMax(double m_step_max) {
112         if (m_step_max > step_min)
113             step_max = m_step_max;
114     }
115     /// Gets the upper limit for time step
GetStepMax()116     double GetStepMax() const { return step_max; }
117 
118     /// Set the method for time integration (time stepper type).
119     ///   - Suggested for fast dynamics with hard (NSC) contacts: EULER_IMPLICIT_LINEARIZED
120     ///   - Suggested for fast dynamics with hard (NSC) contacts and low inter-penetration: EULER_IMPLICIT_PROJECTED
121     ///   - Suggested for finite element smooth dynamics: HHT, EULER_IMPLICIT_LINEARIZED
122     ///
123     /// *Notes*:
124     ///   - for more advanced customization, use SetTimestepper()
125     ///   - old methods ANITESCU and TASORA were replaced by EULER_IMPLICIT_LINEARIZED and EULER_IMPLICIT_PROJECTED,
126     ///     respectively
127     void SetTimestepperType(ChTimestepper::Type type);
128 
129     /// Get the current method for time integration (time stepper type).
GetTimestepperType()130     ChTimestepper::Type GetTimestepperType() const { return timestepper->GetType(); }
131 
132     /// Set the timestepper object to be used for time integration.
SetTimestepper(std::shared_ptr<ChTimestepper> mstepper)133     void SetTimestepper(std::shared_ptr<ChTimestepper> mstepper) { timestepper = mstepper; }
134 
135     /// Get the timestepper currently used for time integration
GetTimestepper()136     std::shared_ptr<ChTimestepper> GetTimestepper() const { return timestepper; }
137 
138     /// Sets outer iteration limit for assembly constraints. When trying to keep constraints together,
139     /// the iterative process is stopped if this max.number of iterations (or tolerance) is reached.
SetMaxiter(int m_maxiter)140     void SetMaxiter(int m_maxiter) { maxiter = m_maxiter; }
141     /// Gets iteration limit for assembly constraints.
GetMaxiter()142     int GetMaxiter() const { return maxiter; }
143 
144     /// Change the default composition laws for contact surface materials
145     /// (coefficient of friction, cohesion, compliance, etc.)
146     virtual void SetMaterialCompositionStrategy(std::unique_ptr<ChMaterialCompositionStrategy>&& strategy);
147 
148     /// Accessor for the current composition laws for contact surface material.
GetMaterialCompositionStrategy()149     const ChMaterialCompositionStrategy& GetMaterialCompositionStrategy() const { return *composition_strategy; }
150 
151     /// For elastic collisions, with objects that have nonzero
152     /// restitution coefficient: objects will rebounce only if their
153     /// relative colliding speed is above this threshold. Default 0.15 m/s.
154     /// If this is too low, aliasing problems can happen with small high frequency
155     /// rebounces, and settling to static stacking might be more difficult.
SetMinBounceSpeed(double mval)156     void SetMinBounceSpeed(double mval) { min_bounce_speed = mval; }
157 
158     /// Objects will rebounce only if their relative colliding speed is above this threshold.
GetMinBounceSpeed()159     double GetMinBounceSpeed() const { return min_bounce_speed; }
160 
161     /// For the default stepper, you can limit the speed of exiting from penetration
162     /// situations. Usually set a positive value, about 0.1 .. 2 . (as exiting speed, in m/s)
SetMaxPenetrationRecoverySpeed(double mval)163     void SetMaxPenetrationRecoverySpeed(double mval) { max_penetration_recovery_speed = mval; }
164 
165     /// Get the limit on the speed for exiting from penetration situations (for Anitescu stepper)
GetMaxPenetrationRecoverySpeed()166     double GetMaxPenetrationRecoverySpeed() const { return max_penetration_recovery_speed; }
167 
168     /// Attach a solver (derived from ChSolver) for use by this system.
169     virtual void SetSolver(std::shared_ptr<ChSolver> newsolver);
170 
171     /// Access the solver currently associated with this system.
172     virtual std::shared_ptr<ChSolver> GetSolver();
173 
174     /// Choose the solver type, to be used for the simultaneous solution of the constraints
175     /// in dynamical simulations (as well as in kinematics, statics, etc.)
176     ///   - Suggested solver for speed, but lower precision: PSOR
177     ///   - Suggested solver for higher precision: BARZILAIBORWEIN or APGD
178     ///   - For problems that involve a stiffness matrix: GMRES, MINRES
179     ///
180     /// *Notes*:
181     ///   - This function is a shortcut, internally equivalent to a call to SetSolver().
182     ///   - Only a subset of available Chrono solvers can be set through this mechanism.
183     ///   - Prefer explicitly creating a solver, setting solver parameters, and then attaching the solver with
184     ///     SetSolver.
185     ///
186     /// \deprecated This function does not support all available Chrono solvers. Prefer using SetSolver.
187     void SetSolverType(ChSolver::Type type);
188 
189     /// Gets the current solver type.
GetSolverType()190     ChSolver::Type GetSolverType() const { return solver->GetType(); }
191 
192     /// Set the maximum number of iterations, if using an iterative solver.
193     /// \deprecated Prefer using SetSolver and setting solver parameters directly.
194     void SetSolverMaxIterations(int max_iters);
195 
196     /// Get the current maximum number of iterations, if using an iterative solver.
197     /// \deprecated Prefer using GetSolver and accessing solver statistics directly.
198     int GetSolverMaxIterations() const;
199 
200     /// Set the solver tolerance threshold (used with iterative solvers only).
201     /// Note that the stopping criteria differs from solver to solver.
202     void SetSolverTolerance(double tolerance);
203 
204     /// Get the current tolerance value (used with iterative solvers only).
205     double GetSolverTolerance() const;
206 
207     /// Set a solver tolerance threshold at force level (default: not specified).
208     /// Specify this value **only** if solving the problem at velocity level (e.g. solving a DVI problem).
209     /// If this tolerance is specified, it is multiplied by the current integration stepsize and overwrites the current
210     /// solver tolerance.  By default, this tolerance is invalid and hence the solver's own tolerance threshold is used.
SetSolverForceTolerance(double tolerance)211     void SetSolverForceTolerance(double tolerance) { tol_force = tolerance; }
212 
213     /// Get the current value of the force-level tolerance (used with iterative solvers only).
GetSolverForceTolerance()214     double GetSolverForceTolerance() const { return tol_force; }
215 
216     /// Instead of using the default 'system descriptor', you can create your own custom descriptor
217     /// (inherited from ChSystemDescriptor) and plug it into the system using this function.
218     void SetSystemDescriptor(std::shared_ptr<ChSystemDescriptor> newdescriptor);
219 
220     /// Access directly the 'system descriptor'.
GetSystemDescriptor()221     std::shared_ptr<ChSystemDescriptor> GetSystemDescriptor() { return descriptor; }
222 
223     /// Set the G (gravity) acceleration vector, affecting all the bodies in the system.
Set_G_acc(const ChVector<> & m_acc)224     void Set_G_acc(const ChVector<>& m_acc) { G_acc = m_acc; }
225 
226     /// Get the G (gravity) acceleration vector affecting all the bodies in the system.
Get_G_acc()227     const ChVector<>& Get_G_acc() const { return G_acc; }
228 
229     /// Get the simulation time of this system.
GetChTime()230     double GetChTime() const { return ch_time; }
231 
232     /// Set (overwrite) the simulation time of this system.
SetChTime(double time)233     void SetChTime(double time) { ch_time = time; }
234 
235     /// Set the number of OpenMP threads used by Chrono itself, Eigen, and the collision detection system.
236     /// <pre>
237     ///   num_threads_chrono    - used in FEA (parallel evaluation of internal forces and Jacobians) and
238     ///                           in SCM deformable terrain calculations.
239     ///   num_threads_collision - used in parallelization of collision detection (if applicable).
240     ///                           If passing 0, then num_threads_collision = num_threads_chrono.
241     ///   num_threads_eigen     - used in the Eigen sparse direct solvers and a few linear algebra operations.
242     ///                           Note that Eigen enables multi-threaded execution only under certain size conditions.
243     ///                           See the Eigen documentation.
244     ///                           If passing 0, then num_threads_eigen = num_threads_chrono.
245     /// By default (if this function is not called), the following values are used:
246     ///   num_threads_chrono = omp_get_num_procs()
247     ///   num_threads_collision = 1
248     ///   num_threads_eigen = 1
249     /// </pre>
250     /// Note that a derived class may ignore some or all of these settings.
251     virtual void SetNumThreads(int num_threads_chrono, int num_threads_collision = 0, int num_threads_eigen = 0);
252 
GetNumThreadsChrono()253     int GetNumThreadsChrono() const { return nthreads_chrono; }
GetNumthreadsCollision()254     int GetNumthreadsCollision() const { return nthreads_collision; }
GetNumthreadsEigen()255     int GetNumthreadsEigen() const { return nthreads_eigen; }
256 
257     //
258     // DATABASE HANDLING
259     //
260 
261     /// Get the underlying assembly containing all physics items.
GetAssembly()262     const ChAssembly& GetAssembly() const { return assembly; }
263 
264     /// Attach a body to the underlying assembly.
265     virtual void AddBody(std::shared_ptr<ChBody> body);
266 
267     /// Attach a link to the underlying assembly.
268     virtual void AddLink(std::shared_ptr<ChLinkBase> link);
269 
270     /// Attach a mesh to the underlying assembly.
271     virtual void AddMesh(std::shared_ptr<fea::ChMesh> mesh);
272 
273     /// Attach a ChPhysicsItem object that is not a body, link, or mesh.
274     virtual void AddOtherPhysicsItem(std::shared_ptr<ChPhysicsItem> item);
275 
276     /// Attach an arbitrary ChPhysicsItem (e.g. ChBody, ChParticles, ChLink, etc.) to the assembly.
277     /// It will take care of adding it to the proper list of bodies, links, meshes, or generic
278     /// physic item. (i.e. it calls AddBody(), AddLink(), AddMesh(), or AddOtherPhysicsItem()).
279     /// Note, you cannot call Add() during an Update (i.e. items like particle generators that
280     /// are already inserted in the assembly cannot call this) because not thread safe; instead,
281     /// use AddBatch().
282     void Add(std::shared_ptr<ChPhysicsItem> item);
283 
284     /// Items added in this way are added like in the Add() method, but not instantly,
285     /// they are simply queued in a batch of 'to add' items, that are added automatically
286     /// at the first Setup() call. This is thread safe.
AddBatch(std::shared_ptr<ChPhysicsItem> item)287     void AddBatch(std::shared_ptr<ChPhysicsItem> item) { assembly.AddBatch(item); }
288 
289     /// If some items are queued for addition in the assembly, using AddBatch(), this will
290     /// effectively add them and clean the batch. Called automatically at each Setup().
FlushBatch()291     void FlushBatch() { assembly.FlushBatch(); }
292 
293     /// Remove a body from this assembly.
RemoveBody(std::shared_ptr<ChBody> body)294     virtual void RemoveBody(std::shared_ptr<ChBody> body) { assembly.RemoveBody(body); }
295 
296     /// Remove a link from this assembly.
RemoveLink(std::shared_ptr<ChLinkBase> link)297     virtual void RemoveLink(std::shared_ptr<ChLinkBase> link) { assembly.RemoveLink(link); }
298 
299     /// Remove a mesh from the assembly.
RemoveMesh(std::shared_ptr<fea::ChMesh> mesh)300     virtual void RemoveMesh(std::shared_ptr<fea::ChMesh> mesh) { assembly.RemoveMesh(mesh); }
301 
302     /// Remove a ChPhysicsItem object that is not a body or a link
RemoveOtherPhysicsItem(std::shared_ptr<ChPhysicsItem> item)303     virtual void RemoveOtherPhysicsItem(std::shared_ptr<ChPhysicsItem> item) { assembly.RemoveOtherPhysicsItem(item); }
304 
305     /// Remove arbitrary ChPhysicsItem that was added to the underlying assembly.
306     void Remove(std::shared_ptr<ChPhysicsItem> item);
307 
308     /// Remove all bodies from the underlying assembly.
RemoveAllBodies()309     void RemoveAllBodies() { assembly.RemoveAllBodies(); }
310     /// Remove all links from the underlying assembly.
RemoveAllLinks()311     void RemoveAllLinks() { assembly.RemoveAllLinks(); }
312     /// Remove all meshes from the underlying assembly.
RemoveAllMeshes()313     void RemoveAllMeshes() { assembly.RemoveAllMeshes(); }
314     /// Remove all physics items not in the body, link, or mesh lists.
RemoveAllOtherPhysicsItems()315     void RemoveAllOtherPhysicsItems() { assembly.RemoveAllOtherPhysicsItems(); }
316 
317     /// Get the list of bodies.
Get_bodylist()318     const std::vector<std::shared_ptr<ChBody>>& Get_bodylist() const { return assembly.bodylist; }
319     /// Get the list of links.
Get_linklist()320     const std::vector<std::shared_ptr<ChLinkBase>>& Get_linklist() const { return assembly.linklist; }
321     /// Get the list of meshes.
Get_meshlist()322     const std::vector<std::shared_ptr<fea::ChMesh>>& Get_meshlist() const { return assembly.meshlist; }
323     /// Get the list of physics items that are not in the body or link lists.
Get_otherphysicslist()324     const std::vector<std::shared_ptr<ChPhysicsItem>>& Get_otherphysicslist() const {
325         return assembly.otherphysicslist;
326     }
327 
328     /// Search a body by its name.
SearchBody(const char * name)329     std::shared_ptr<ChBody> SearchBody(const char* name) { return assembly.SearchBody(name); }
330     /// Search a link by its name.
SearchLink(const char * name)331     std::shared_ptr<ChLinkBase> SearchLink(const char* name) { return assembly.SearchLink(name); }
332     /// Search a mesh by its name.
SearchMesh(const char * name)333     std::shared_ptr<fea::ChMesh> SearchMesh(const char* name) { return assembly.SearchMesh(name); }
334     /// Search from other ChPhysics items (not bodies, links, or meshes) by name.
SearchOtherPhysicsItem(const char * name)335     std::shared_ptr<ChPhysicsItem> SearchOtherPhysicsItem(const char* name) {
336         return assembly.SearchOtherPhysicsItem(name);
337     }
338     /// Search a marker by its name.
SearchMarker(const char * name)339     std::shared_ptr<ChMarker> SearchMarker(const char* name) { return assembly.SearchMarker(name); }
340     /// Search an item (body, link or other ChPhysics items) by name.
Search(const char * name)341     std::shared_ptr<ChPhysicsItem> Search(const char* name) { return assembly.Search(name); }
342     /// Search a body by its ID
SearchBodyID(int bodyID)343     std::shared_ptr<ChBody> SearchBodyID(int bodyID) { return assembly.SearchBodyID(bodyID); }
344     /// Search a marker by its unique ID.
SearchMarker(int markID)345     std::shared_ptr<ChMarker> SearchMarker(int markID) { return assembly.SearchMarker(markID); }
346 
347     /// Get the number of active bodies (excluding those that are sleeping or are fixed to ground).
GetNbodies()348     int GetNbodies() const { return assembly.GetNbodies(); }
349     /// Get the number of bodies that are in sleeping mode (excluding fixed bodies).
GetNbodiesSleeping()350     int GetNbodiesSleeping() const { return assembly.GetNbodiesSleeping(); }
351     /// Get the number of bodies that are fixed to ground.
GetNbodiesFixed()352     int GetNbodiesFixed() const { return assembly.GetNbodiesFixed(); }
353     /// Get the total number of bodies in the assembly, including the grounded and sleeping bodies.
GetNbodiesTotal()354     int GetNbodiesTotal() const { return assembly.GetNbodiesTotal(); }
355 
356     /// Get the number of links.
GetNlinks()357     int GetNlinks() const { return assembly.GetNlinks(); }
358 
359     /// Get the number of meshes.
GetNmeshes()360     int GetNmeshes() const { return assembly.GetNmeshes(); }
361 
362     /// Get the number of other physics items (other than bodies, links, or meshes).
GetNphysicsItems()363     int GetNphysicsItems() const { return assembly.GetNphysicsItems(); }
364 
365     /// Get the number of coordinates (considering 7 coords for rigid bodies because of the 4 dof of quaternions).
GetNcoords()366     int GetNcoords() const { return ncoords; }
367     /// Get the number of degrees of freedom of the assembly.
GetNdof()368     int GetNdof() const { return ndof; }
369     /// Get the number of scalar constraints added to the assembly, including constraints on quaternion norms.
GetNdoc()370     int GetNdoc() const { return ndoc; }
371     /// Get the number of system variables (coordinates plus the constraint multipliers, in case of quaternions).
GetNsysvars()372     int GetNsysvars() const { return nsysvars; }
373     /// Get the number of coordinates (considering 6 coords for rigid bodies, 3 transl.+3rot.)
GetNcoords_w()374     int GetNcoords_w() const { return ncoords_w; }
375     /// Get the number of scalar constraints added to the assembly.
GetNdoc_w()376     int GetNdoc_w() const { return ndoc_w; }
377     /// Get the number of scalar constraints added to the assembly (only bilaterals).
GetNdoc_w_C()378     int GetNdoc_w_C() const { return ndoc_w_C; }
379     /// Get the number of scalar constraints added to the assembly (only unilaterals).
GetNdoc_w_D()380     int GetNdoc_w_D() const { return ndoc_w_D; }
381     /// Get the number of system variables (coordinates plus the constraint multipliers).
GetNsysvars_w()382     int GetNsysvars_w() const { return nsysvars_w; }
383 
384     /// Get the number of scalar coordinates (ex. dim of position vector)
GetDOF()385     int GetDOF() const { return GetNcoords(); }
386     /// Get the number of scalar coordinates of variables derivatives (ex. dim of speed vector)
GetDOF_w()387     int GetDOF_w() const { return GetNcoords_w(); }
388     /// Get the number of scalar constraints, if any, in this item
GetDOC()389     int GetDOC() const { return GetNdoc_w(); }
390     /// Get the number of scalar constraints, if any, in this item (only bilateral constr.)
GetDOC_c()391     int GetDOC_c() const { return GetNdoc_w_C(); }
392     /// Get the number of scalar constraints, if any, in this item (only unilateral constr.)
GetDOC_d()393     int GetDOC_d() const { return GetNdoc_w_D(); }
394 
395     /// Write the hierarchy of contained bodies, markers, etc. in ASCII
396     /// readable form, mostly for debugging purposes. Level is the tab spacing at the left.
397     void ShowHierarchy(ChStreamOutAscii& m_file, int level = 0) const { assembly.ShowHierarchy(m_file, level); }
398 
399     /// Removes all bodies/marker/forces/links/contacts, also resets timers and events.
400     void Clear();
401 
402     /// Return the contact method supported by this system.
403     /// Contactables (bodies, FEA nodes, FEA traiangles, etc.) added to this system must be compatible.
404     virtual ChContactMethod GetContactMethod() const = 0;
405 
406     /// Create and return the pointer to a new body.
407     /// The body is consistent with the type of the collision system currently associated with this ChSystem.
408     /// Note that the body is *not* attached to this system.
409     virtual ChBody* NewBody();
410 
411     /// Create and return the pointer to a new body with auxiliary reference frame.
412     /// The body is consistent with the type of the collision system currently associated with this ChSystem.
413     /// Note that the body is *not* attached to this system.
414     virtual ChBodyAuxRef* NewBodyAuxRef();
415 
416     /// Given inserted markers and links, restores the
417     /// pointers of links to markers given the information
418     /// about the marker IDs. Will be made obsolete in future with new serialization systems.
419     void Reference_LM_byID();
420 
421     //
422     // STATISTICS
423     //
424 
425     /// Gets the number of contacts.
426     int GetNcontacts();
427 
428     /// Return the time (in seconds) spent for computing the time step.
GetTimerStep()429     virtual double GetTimerStep() const { return timer_step(); }
430     /// Return the time (in seconds) for time integration, within the time step.
GetTimerAdvance()431     virtual double GetTimerAdvance() const { return timer_advance(); }
432     /// Return the time (in seconds) for the solver, within the time step.
433     /// Note that this time excludes any calls to the solver's Setup function.
GetTimerLSsolve()434     virtual double GetTimerLSsolve() const { return timer_ls_solve(); }
435     /// Return the time (in seconds) for the solver Setup phase, within the time step.
GetTimerLSsetup()436     virtual double GetTimerLSsetup() const { return timer_ls_setup(); }
437     /// Return the time (in seconds) for calculating/loading Jacobian information, within the time step.
GetTimerJacobian()438     virtual double GetTimerJacobian() const { return timer_jacobian(); }
439     /// Return the time (in seconds) for runnning the collision detection step, within the time step.
GetTimerCollision()440     virtual double GetTimerCollision() const { return timer_collision(); }
441     /// Return the time (in seconds) for system setup, within the time step.
GetTimerSetup()442     virtual double GetTimerSetup() const { return timer_setup(); }
443     /// Return the time (in seconds) for updating auxiliary data, within the time step.
GetTimerUpdate()444     virtual double GetTimerUpdate() const { return timer_update(); }
445 
446     /// Return the time (in seconds) for broadphase collision detection, within the time step.
GetTimerCollisionBroad()447     double GetTimerCollisionBroad() const { return collision_system->GetTimerCollisionBroad(); }
448     /// Return the time (in seconds) for narrowphase collision detection, within the time step.
GetTimerCollisionNarrow()449     double GetTimerCollisionNarrow() const { return collision_system->GetTimerCollisionNarrow(); }
450 
451     /// Resets the timers.
ResetTimers()452     void ResetTimers() {
453         timer_step.reset();
454         timer_advance.reset();
455         timer_ls_solve.reset();
456         timer_ls_setup.reset();
457         timer_jacobian.reset();
458         timer_collision.reset();
459         timer_setup.reset();
460         timer_update.reset();
461         collision_system->ResetTimers();
462     }
463 
464   protected:
465     /// Pushes all ChConstraints and ChVariables contained in links, bodies, etc. into the system descriptor.
466     virtual void DescriptorPrepareInject(ChSystemDescriptor& mdescriptor);
467 
468     // Note: SetupInitial need not be typically called by a user, so it is currently marked protected
469     // (as it may need to be called by derived classes)
470 
471     /// Initial system setup before analysis.
472     /// This function performs an initial system setup, once system construction is completed and before an analysis.
473     void SetupInitial();
474 
475     /// Return the resultant applied force on the specified body.
476     /// This resultant force includes all external applied loads acting on the body (from gravity, loads, springs,
477     /// etc). However, this does *not* include any constraint forces. In particular, contact forces are not included if
478     /// using the NSC formulation, but are included when using the SMC formulation.
479     virtual ChVector<> GetBodyAppliedForce(ChBody* body);
480 
481     /// Return the resultant applied torque on the specified body.
482     /// This resultant torque includes all external applied loads acting on the body (from gravity, loads, springs,
483     /// etc). However, this does *not* include any constraint forces. In particular, contact torques are not included if
484     /// using the NSC formulation, but are included when using the SMC formulation.
485     virtual ChVector<> GetBodyAppliedTorque(ChBody* body);
486 
487   public:
488     /// Counts the number of bodies and links.
489     /// Computes the offsets of object states in the global state. Assumes that offset_x, offset_w, and offset_L are
490     /// already set as starting point for offsetting all the contained sub objects.
491     virtual void Setup();
492 
493     /// Updates all the auxiliary data and children of
494     /// bodies, forces, links, given their current state.
495     void Update(double mytime, bool update_assets = true);
496 
497     /// Updates all the auxiliary data and children of bodies, forces, links, given their current state.
498     void Update(bool update_assets = true);
499 
500     /// In normal usage, no system update is necessary at the beginning of a new dynamics step (since an update is
501     /// performed at the end of a step). However, this is not the case if external changes to the system are made. Most
502     /// such changes are discovered automatically (addition/removal of items, input of mesh loads). For special cases,
503     /// this function allows the user to trigger a system update at the beginning of the step immediately following this
504     /// call.
505     void ForceUpdate();
506 
507     void IntToDescriptor(const unsigned int off_v,
508                          const ChStateDelta& v,
509                          const ChVectorDynamic<>& R,
510                          const unsigned int off_L,
511                          const ChVectorDynamic<>& L,
512                          const ChVectorDynamic<>& Qc);
513     void IntFromDescriptor(const unsigned int off_v, ChStateDelta& v, const unsigned int off_L, ChVectorDynamic<>& L);
514 
515     void InjectVariables(ChSystemDescriptor& mdescriptor);
516 
517     void InjectConstraints(ChSystemDescriptor& mdescriptor);
518     void ConstraintsLoadJacobians();
519 
520     void InjectKRMmatrices(ChSystemDescriptor& mdescriptor);
521     void KRMmatricesLoad(double Kfactor, double Rfactor, double Mfactor);
522 
523     // Old bookkeeping system
524     void VariablesFbReset();
525     void VariablesFbLoadForces(double factor = 1);
526     void VariablesQbLoadSpeed();
527     void VariablesFbIncrementMq();
528     void VariablesQbSetSpeed(double step = 0);
529     void VariablesQbIncrementPosition(double step);
530     void ConstraintsBiReset();
531     void ConstraintsBiLoad_C(double factor = 1, double recovery_clamp = 0.1, bool do_clamp = false);
532     void ConstraintsBiLoad_Ct(double factor = 1);
533     void ConstraintsBiLoad_Qc(double factor = 1);
534     void ConstraintsFbLoadForces(double factor = 1);
535     void ConstraintsFetch_react(double factor = 1);
536 
537     //
538     // TIMESTEPPER INTERFACE
539     //
540 
541     /// Tells the number of position coordinates x in y = {x, v}
GetNcoords_x()542     virtual int GetNcoords_x() override { return GetNcoords(); }
543 
544     /// Tells the number of speed coordinates of v in y = {x, v} and  dy/dt={v, a}
GetNcoords_v()545     virtual int GetNcoords_v() override { return GetNcoords_w(); }
546 
547     /// Tells the number of lagrangian multipliers (constraints)
GetNconstr()548     virtual int GetNconstr() override { return GetNdoc_w(); }
549 
550     /// From system to state y={x,v}
551     virtual void StateGather(ChState& x, ChStateDelta& v, double& T) override;
552 
553     /// From state Y={x,v} to system. This also triggers an update operation.
554     virtual void StateScatter(const ChState& x,
555                               const ChStateDelta& v,
556                               const double T,
557                               bool full_update) override;
558 
559     /// From system to state derivative (acceleration), some timesteppers might need last computed accel.
560     virtual void StateGatherAcceleration(ChStateDelta& a) override;
561 
562     /// From state derivative (acceleration) to system, sometimes might be needed
563     virtual void StateScatterAcceleration(const ChStateDelta& a) override;
564 
565     /// From system to reaction forces (last computed) - some timestepper might need this
566     virtual void StateGatherReactions(ChVectorDynamic<>& L) override;
567 
568     /// From reaction forces to system, ex. store last computed reactions in ChLink objects for plotting etc.
569     virtual void StateScatterReactions(const ChVectorDynamic<>& L) override;
570 
571     /// Perform x_new = x + dx, for x in Y = {x, dx/dt}.\n
572     /// It takes care of the fact that x has quaternions, dx has angular vel etc.
573     /// NOTE: the system is not updated automatically after the state increment, so one might
574     /// need to call StateScatter() if needed.
575     virtual void StateIncrementX(ChState& x_new,         ///< resulting x_new = x + Dx
576                                  const ChState& x,       ///< initial state x
577                                  const ChStateDelta& Dx  ///< state increment Dx
578                                  ) override;
579 
580     /// Assuming a DAE of the form
581     /// <pre>
582     ///       M*a = F(x,v,t) + Cq'*L
583     ///       C(x,t) = 0
584     /// </pre>
585     /// this function computes the solution of the change Du (in a or v or x) for a Newton
586     /// iteration within an implicit integration scheme.
587     /// <pre>
588     ///  |Du| = [ G   Cq' ]^-1 * | R |
589     ///  |DL|   [ Cq  0   ]      | Qc|
590     /// </pre>
591     /// for residual R and  G = [ c_a*M + c_v*dF/dv + c_x*dF/dx ].\n
592     /// This function returns true if successful and false otherwise.
593     virtual bool StateSolveCorrection(
594         ChStateDelta& Dv,             ///< result: computed Dv
595         ChVectorDynamic<>& L,         ///< result: computed lagrangian multipliers, if any
596         const ChVectorDynamic<>& R,   ///< the R residual
597         const ChVectorDynamic<>& Qc,  ///< the Qc residual
598         const double c_a,             ///< the factor in c_a*M
599         const double c_v,             ///< the factor in c_v*dF/dv
600         const double c_x,             ///< the factor in c_x*dF/dv
601         const ChState& x,             ///< current state, x part
602         const ChStateDelta& v,        ///< current state, v part
603         const double T,               ///< current time T
604         bool force_state_scatter,     ///< if false, x and v are not scattered to the system
605         bool full_update,             ///< if true, perform a full update during scatter
606         bool force_setup              ///< if true, call the solver's Setup() function
607         ) override;
608 
609     /// Increment a vector R with the term c*F:
610     ///    R += c*F
611     virtual void LoadResidual_F(ChVectorDynamic<>& R,  ///< result: the R residual, R += c*F
612                                 const double c         ///< a scaling factor
613                                 ) override;
614 
615     /// Increment a vector R with a term that has M multiplied a given vector w:
616     ///    R += c*M*w
617     virtual void LoadResidual_Mv(ChVectorDynamic<>& R,        ///< result: the R residual, R += c*M*v
618                                  const ChVectorDynamic<>& w,  ///< the w vector
619                                  const double c               ///< a scaling factor
620                                  ) override;
621 
622     /// Increment a vectorR with the term Cq'*L:
623     ///    R += c*Cq'*L
624     virtual void LoadResidual_CqL(ChVectorDynamic<>& R,        ///< result: the R residual, R += c*Cq'*L
625                                   const ChVectorDynamic<>& L,  ///< the L vector
626                                   const double c               ///< a scaling factor
627                                   ) override;
628 
629     /// Increment a vector Qc with the term C:
630     ///    Qc += c*C
631     virtual void LoadConstraint_C(ChVectorDynamic<>& Qc,        ///< result: the Qc residual, Qc += c*C
632                                   const double c,               ///< a scaling factor
633                                   const bool do_clamp = false,  ///< enable optional clamping of Qc
634                                   const double clamp = 1e30     ///< clamping value
635                                   ) override;
636 
637     /// Increment a vector Qc with the term Ct = partial derivative dC/dt:
638     ///    Qc += c*Ct
639     virtual void LoadConstraint_Ct(ChVectorDynamic<>& Qc,  ///< result: the Qc residual, Qc += c*Ct
640                                    const double c          ///< a scaling factor
641                                    ) override;
642 
643     //
644     // UTILITY FUNCTIONS
645     //
646 
647     /// Executes custom processing at the end of step. By default it does nothing,
648     /// but if you inherit a special ChSystem you can implement this.
CustomEndOfStep()649     virtual void CustomEndOfStep() {}
650 
651     /// Perform the collision detection.
652     /// New contacts are inserted in the ChContactContainer object(s), and old ones are removed.
653     /// This is mostly called automatically by time integration.
654     double ComputeCollisions();
655 
656     /// Class to be used as a callback interface for user defined actions performed
657     /// at each collision detection step.  For example, additional contact points can
658     /// be added to the underlying contact container.
659     class ChApi CustomCollisionCallback {
660       public:
~CustomCollisionCallback()661         virtual ~CustomCollisionCallback() {}
OnCustomCollision(ChSystem * msys)662         virtual void OnCustomCollision(ChSystem* msys) {}
663     };
664 
665     /// Specify a callback object to be invoked at each collision detection step.
666     /// Multiple such callback objects can be registered with a system. If present,
667     /// their OnCustomCollision() method is invoked.
668     /// Use this if you want that some specific callback function is executed at each
669     /// collision detection step (ex. all the times that ComputeCollisions() is automatically
670     /// called by the integration method). For example some other collision engine could
671     /// add further contacts using this callback.
672     void RegisterCustomCollisionCallback(std::shared_ptr<CustomCollisionCallback> callback);
673 
674     /// Remove the given collision callback from this system.
675     void UnregisterCustomCollisionCallback(std::shared_ptr<CustomCollisionCallback> callback);
676 
677     /// Change the underlying collision detection system to the specified type.
678     /// By default, a ChSystem uses a Bullet-based collision detection engine
679     /// (collision::ChCollisionSystemType::BULLET).
680     virtual void SetCollisionSystemType(collision::ChCollisionSystemType type);
681 
682     /// Change the underlying collision system.
683     /// By default, a ChSystem uses a Bullet-based collision detection engine.
684     virtual void SetCollisionSystem(std::shared_ptr<collision::ChCollisionSystem> newcollsystem);
685 
686     /// Access the underlying collision system.
687     /// Usually this is not needed, as the collision system is automatically handled by the ChSystem.
GetCollisionSystem()688     std::shared_ptr<collision::ChCollisionSystem> GetCollisionSystem() const { return collision_system; }
689 
690     /// Change the underlying contact container given the specified type of the collision detection system.
691     /// Usually this is not needed, as the contact container is automatically handled by the ChSystem.
692     /// The default implementation is a no-op, since the default contact container for a ChSystem is suitable for all
693     /// types of supported collision detection systems.
SetContactContainer(collision::ChCollisionSystemType type)694     virtual void SetContactContainer(collision::ChCollisionSystemType type) {}
695 
696     /// Change the underlying contact container.
697     /// The contact container collects information from the underlying collision detection system required for contact
698     /// force generation. Usually this is not needed, as the contact container is automatically handled by the ChSystem.
699     /// Make sure the provided contact container is compatible with both the collision detection system and the contact
700     /// force formulation (NSC or SMC).
701     virtual void SetContactContainer(std::shared_ptr<ChContactContainer> contactcontainer);
702 
703     /// Access the underlying contact container.
704     /// Usually this is not needed, as the contact container is automatically handled by the ChSystem.
GetContactContainer()705     std::shared_ptr<ChContactContainer> GetContactContainer() const { return contact_container; }
706 
707     /// Turn on this feature to let the system put to sleep the bodies whose
708     /// motion has almost come to a rest. This feature will allow faster simulation
709     /// of large scenarios for real-time purposes, but it will affect the precision!
710     /// This functionality can be turned off selectively for specific ChBodies.
SetUseSleeping(bool ms)711     void SetUseSleeping(bool ms) { use_sleeping = ms; }
712 
713     /// Tell if the system will put to sleep the bodies whose motion has almost come to a rest.
GetUseSleeping()714     bool GetUseSleeping() const { return use_sleeping; }
715 
716   private:
717     /// Put bodies to sleep if possible. Also awakens sleeping bodies, if needed.
718     /// Returns true if some body changed from sleep to no sleep or viceversa,
719     /// returns false if nothing changed. In the former case, also performs Setup()
720     /// because the sleeping policy changed the totalDOFs and offsets.
721     bool ManageSleepingBodies();
722 
723     /// Performs a single dynamical simulation step, according to
724     /// current values of:  Y, time, step  (and other minor settings)
725     /// Depending on the integration type, it switches to one of the following:
726     virtual bool Integrate_Y();
727 
728   public:
729     // ---- DYNAMICS
730 
731     /// Advances the dynamical simulation for a single step, of length step_size.
732     /// This function is typically called many times in a loop in order to simulate up to a desired end time.
733     int DoStepDynamics(double step_size);
734 
735     /// Performs integration until the m_endtime is exactly
736     /// reached, but current time step may be automatically "retouched" to
737     /// meet exactly the m_endtime after n steps.
738     /// Useful when you want to advance the simulation in a
739     /// simulations (3d modeling software etc.) which needs updates
740     /// of the screen at a fixed rate (ex.30th of second)  while
741     /// the integration must use more steps.
742     bool DoFrameDynamics(double end_time);
743 
744     /// Given the current state, the sw simulates the
745     /// dynamical behavior of the system, until the end
746     /// time is reached, repeating many steps (maybe the step size
747     /// will be automatically changed if the integrator method supports
748     /// step size adaption).
749     bool DoEntireDynamics(double end_time);
750 
751     /// Like "DoEntireDynamics", but results are provided at uniform
752     /// steps "frame_step", using the DoFrameDynamics() many times.
753     bool DoEntireUniformDynamics(double end_time, double frame_step);
754 
755     /// Return the total number of time steps taken so far.
GetStepcount()756     size_t GetStepcount() const { return stepcount; }
757 
758     /// Reset to 0 the total number of time steps.
ResetStepcount()759     void ResetStepcount() { stepcount = 0; }
760 
761     /// Return the number of calls to the solver's Solve() function.
762     /// This counter is reset at each timestep.
GetSolverCallsCount()763     int GetSolverCallsCount() const { return solvecount; }
764 
765     /// Return the number of calls to the solver's Setup() function.
766     /// This counter is reset at each timestep.
GetSolverSetupCount()767     int GetSolverSetupCount() const { return setupcount; }
768 
769     /// Set this to "true" to enable automatic saving of solver matrices at each time
770     /// step, for debugging purposes. Note that matrices will be saved in the
771     /// working directory of the exe, with format 0001_01_H.dat 0002_01_H.dat
772     /// (if the timestepper requires multiple solves, also 0001_01. 0001_02.. etc.)
773     /// The matrices being saved are:
774     ///    dump_Z.dat   has the assembled optimization matrix (Matlab sparse format)
775     ///    dump_rhs.dat has the assembled RHS
776     ///    dump_H.dat   has usually H=M (mass), but could be also H=a*M+b*K+c*R or such. (Matlab sparse format)
777     ///    dump_Cq.dat  has the jacobians (Matlab sparse format)
778     ///    dump_E.dat   has the constr.compliance (Matlab sparse format)
779     ///    dump_f.dat   has the applied loads
780     ///    dump_b.dat   has the constraint rhs
781     /// as passed to the solver in the problem
782     /// <pre>
783     ///  | H -Cq'|*|q|- | f|= |0|
784     ///  | Cq -E | |l|  |-b|  |c|
785     /// </pre>
786     /// where l \f$\in Y, c \in Ny\f$, normal cone to Y
787 
SetDumpSolverMatrices(bool md)788     void SetDumpSolverMatrices(bool md) { dump_matrices = md; }
GetDumpSolverMatrices()789     bool GetDumpSolverMatrices() const { return dump_matrices; }
790 
791     /// Dump the current M mass matrix, K damping matrix, R damping matrix, Cq constraint jacobian
792     /// matrix (at the current configuration).
793     /// These can be later used for linearized motion, modal analysis, buckling analysis, etc.
794     /// The name of the files will be [path]_M.dat [path]_K.dat [path]_R.dat [path]_Cq.dat
795     /// Might throw ChException if file can't be saved.
796     void DumpSystemMatrices(bool save_M, bool save_K, bool save_R, bool save_Cq, const char* path);
797 
798     /// Compute the system-level mass matrix.
799     /// This function has a small overhead, because it must assembly the
800     /// sparse matrix -which is used only for the purpose of this function.
801     void GetMassMatrix(ChSparseMatrix* M);    ///< fill this system mass matrix
802 
803     /// Compute the system-level stiffness matrix, i.e. the jacobian -dF/dq where F are stiff loads.
804     /// Note that not all loads provide a jacobian, as this is optional in their implementation.
805     /// This function has a small overhead, because it must assembly the
806     /// sparse matrix -which is used only for the purpose of this function.
807     void GetStiffnessMatrix(ChSparseMatrix* K);    ///< fill this system stiffness matrix
808 
809     /// Compute the system-level damping matrix, i.e. the jacobian -dF/dv where F are stiff loads.
810     /// Note that not all loads provide a jacobian, as this is optional in their implementation.
811     /// This function has a small overhead, because it must assembly the
812     /// sparse matrix -which is used only for the purpose of this function.
813     void GetDampingMatrix(ChSparseMatrix* R);    ///< fill this system damping matrix
814 
815     /// Compute the system-level constraint jacobian matrix, i.e. the jacobian
816     /// Cq=-dC/dq where C are constraints (the lower left part of the KKT matrix).
817     /// This function has a small overhead, because it must assembly the
818     /// sparse matrix -which is used only for the purpose of this function.
819     void GetConstraintJacobianMatrix(ChSparseMatrix* Cq);  ///< fill this system damping matrix
820 
821     // ---- KINEMATICS
822 
823     /// Advances the kinematic simulation for a single step of given length.
824     bool DoStepKinematics(double step_size);
825 
826     /// Performs kinematics until the end time is exactly reached.
827     /// The current time step may be automatically adjusted to meet exactly the m_endtime after n steps.
828     bool DoFrameKinematics(double end_time);
829 
830     /// Given the current state, this kinematic simulation satisfies all the constraints with the "DoStepKinematics"
831     /// procedure for each time step, from the current time to the end time.
832     bool DoEntireKinematics(double end_time);
833 
834     // ---- CONSTRAINT ASSEMBLATION
835 
836     /// Given the current time and state, attempt to satisfy all constraints, using
837     /// a Newton-Raphson iteration loop. Used iteratively in inverse kinematics.
838     /// Action can be one of AssemblyLevel::POSITION, AssemblyLevel::VELOCITY, or
839     /// AssemblyLevel::ACCELERATION (or a combination of these)
840     /// Returns true if no errors and false if an error occurred (impossible assembly?)
841     bool DoAssembly(int action);
842 
843     /// Shortcut for full position/velocity/acceleration assembly.
844     bool DoFullAssembly();
845 
846     // ---- STATICS
847 
848     /// Perform a generic static analysis. Low level API, where the user creates and configures a
849     /// ChStaticAnalysis-inherited object by his own. For ready-to-use analysis, use
850     /// DoStaticLinear, DoStaticNonLinear, DoStaticNonlinearRheonomic etc. instead.
851     bool DoStaticAnalysis(std::shared_ptr<ChStaticAnalysis> analysis);
852 
853     /// Solve the position of static equilibrium (and the reactions).
854     /// This is a one-step only approach that solves the **linear** equilibrium.
855     /// Appropriate mostly for FEM problems with small deformations.
856     bool DoStaticLinear();
857 
858     /// Solve the position of static equilibrium (and the reactions).
859     /// This function solves the equilibrium for the nonlinear problem (large displacements).
860     /// This version uses a nonlinear static analysis solver with default parameters.
861     bool DoStaticNonlinear(int nsteps = 10, bool verbose = false);
862 
863     /// Solve the position of static equilibrium (and the reactions).
864     /// This function solves the equilibrium for the nonlinear problem (large displacements),
865     /// but differently from DoStaticNonlinear, it considers rheonomic constraints (ex. ChLinkMotorRotationSpeed)
866     /// that can impose steady-state speeds&accelerations to the mechanism, ex. to generate centrifugal forces in turbine blades.
867     /// This version uses a nonlinear static analysis solver with default parameters.
868     bool DoStaticNonlinearRheonomic(int nsteps = 10, bool verbose = false, std::shared_ptr<ChStaticNonLinearRheonomicAnalysis::IterationCallback> mcallback = nullptr);
869 
870     /// Finds the position of static equilibrium (and the reactions) starting from the current position.
871     /// Since a truncated iterative method is used, you may need to call this method multiple times in case of large
872     /// nonlinearities before coming to the precise static solution.
873     bool DoStaticRelaxing(int nsteps = 10);
874 
875     //
876     // SERIALIZATION
877     //
878 
879     /// Method to allow serialization of transient data to archives.
880     virtual void ArchiveOUT(ChArchiveOut& marchive);
881 
882     /// Method to allow deserialization of transient data from archives.
883     virtual void ArchiveIN(ChArchiveIn& marchive);
884 
885     /// Process a ".chr" binary file containing the full system object
886     /// hierarchy as exported -for example- by the R3D modeler, with chrono plug-in version,
887     /// or by using the FileWriteChR() function.
888     int FileProcessChR(ChStreamInBinary& m_file);
889 
890     /// Write a ".chr" binary file containing the full system object
891     /// hierarchy (bodies, forces, links, etc.) (deprecated function - obsolete)
892     int FileWriteChR(ChStreamOutBinary& m_file);
893 
894   protected:
895     ChAssembly assembly;
896 
897     std::shared_ptr<ChContactContainer> contact_container;  ///< the container of contacts
898 
899     ChVector<> G_acc;  ///< gravitational acceleration
900 
901     bool is_initialized;  ///< if false, an initial setup is required (i.e. a call to SetupInitial)
902     bool is_updated;      ///< if false, a new update is required (i.e. a call to Update)
903 
904     int ncoords;     ///< number of scalar coordinates (including 4th dimension of quaternions) for all active bodies
905     int ndoc;        ///< number of scalar constraints (including constr. on quaternions)
906     int nsysvars;    ///< number of variables (coords+lagrangian mult.), i.e. = ncoords+ndoc  for all active bodies
907     int ncoords_w;   ///< number of scalar coordinates when using 3 rot. dof. per body;  for all active bodies
908     int ndoc_w;      ///< number of scalar constraints  when using 3 rot. dof. per body;  for all active bodies
909     int nsysvars_w;  ///< number of variables when using 3 rot. dof. per body; i.e. = ncoords_w+ndoc_w
910     int ndof;        ///< number of degrees of freedom, = ncoords-ndoc =  ncoords_w-ndoc_w ,
911     int ndoc_w_C;    ///< number of scalar constraints C, when using 3 rot. dof. per body (excluding unilaterals)
912     int ndoc_w_D;    ///< number of scalar constraints D, when using 3 rot. dof. per body (only unilaterals)
913 
914     double ch_time;   ///< simulation time of the system
915     double step;      ///< time step
916     double step_min;  ///< min time step
917     double step_max;  ///< max time step
918 
919     double tol_force;  ///< tolerance for forces (used to obtain a tolerance for impulses)
920 
921     int maxiter;  ///< max iterations for nonlinear convergence in DoAssembly()
922 
923     bool use_sleeping;  ///< if true, put to sleep objects that come to rest
924 
925     std::shared_ptr<ChSystemDescriptor> descriptor;  ///< system descriptor
926     std::shared_ptr<ChSolver> solver;                ///< solver for DVI or DAE problem
927 
928     double min_bounce_speed;                ///< minimum speed for rebounce after impacts. Lower speeds are clamped to 0
929     double max_penetration_recovery_speed;  ///< limit for the speed of penetration recovery (positive, speed of exiting)
930 
931     size_t stepcount;  ///< internal counter for steps
932 
933     int setupcount;  ///< number of calls to the solver's Setup()
934     int solvecount;  ///< number of StateSolveCorrection (reset to 0 at each timestep of static analysis)
935 
936     bool dump_matrices;  ///< for debugging
937 
938     int ncontacts;  ///< total number of contacts
939 
940     collision::ChCollisionSystemType collision_system_type;                     ///< type of the collision engine
941     std::shared_ptr<collision::ChCollisionSystem> collision_system;             ///< collision engine
942     std::vector<std::shared_ptr<CustomCollisionCallback>> collision_callbacks;  ///< user-defined collision callbacks
943     std::unique_ptr<ChMaterialCompositionStrategy> composition_strategy;        /// material composition strategy
944 
945     // OpenMP
946     int nthreads_chrono;
947     int nthreads_eigen;
948     int nthreads_collision;
949 
950     // timers for profiling execution speed
951     ChTimer<double> timer_step;       ///< timer for integration step
952     ChTimer<double> timer_advance;    ///< timer for time integration
953     ChTimer<double> timer_ls_solve;   ///< timer for solver (excluding setup phase)
954     ChTimer<double> timer_ls_setup;   ///< timer for solver setup
955     ChTimer<double> timer_jacobian;   ///< timer for computing/loading Jacobian information
956     ChTimer<double> timer_collision;  ///< timer for collision detection
957     ChTimer<double> timer_setup;      ///< timer for system setup
958     ChTimer<double> timer_update;     ///< timer for system update
959 
960     std::shared_ptr<ChTimestepper> timestepper;  ///< time-stepper object
961 
962     bool last_err;  ///< indicates error over the last kinematic/dynamics/statics
963 
964     ChVectorDynamic<> applied_forces;  ///< system-wide vector of applied forces (lazy evaluation)
965     bool applied_forces_current;       ///< indicates if system-wide vector of forces is up-to-date
966 
967     // Friend class declarations
968 
969     friend class ChAssembly;
970     friend class ChBody;
971     friend class fea::ChMesh;
972 
973     friend class ChContactContainerNSC;
974     friend class ChContactContainerSMC;
975 };
976 
977 CH_CLASS_VERSION(ChSystem, 0)
978 
979 }  // end namespace chrono
980 
981 #endif
982