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: Radu Serban
13 // =============================================================================
14 
15 #include "chrono/physics/ChLinkSpringCB.h"
16 
17 namespace chrono {
18 
19 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChLinkSpringCB)20 CH_FACTORY_REGISTER(ChLinkSpringCB)
21 
22 ChLinkSpringCB::ChLinkSpringCB()
23     : m_force_fun(nullptr), m_ode_fun(nullptr), m_nstates(0), m_rest_length(0), m_force(0), m_variables(nullptr) {}
24 
ChLinkSpringCB(const ChLinkSpringCB & other)25 ChLinkSpringCB::ChLinkSpringCB(const ChLinkSpringCB& other) : ChLinkMarkers(other) {
26     m_rest_length = other.m_rest_length;
27     m_force = other.m_force;
28     m_force_fun = other.m_force_fun;
29     m_ode_fun = other.m_ode_fun;
30     m_nstates = other.m_nstates;
31     m_states = other.m_states;
32     m_rhs = other.m_rhs;
33     if (other.m_variables) {
34         m_variables = new ChVariablesGenericDiagonalMass(other.m_variables->Get_ndof());
35         (*m_variables) = (*other.m_variables);
36     }
37 }
38 
Clone() const39 ChLinkSpringCB* ChLinkSpringCB::Clone() const {
40     return new ChLinkSpringCB(*this);
41 }
42 
~ChLinkSpringCB()43 ChLinkSpringCB::~ChLinkSpringCB() {
44     delete m_variables;
45 }
46 
RegisterODE(ODE * functor)47 void ChLinkSpringCB::RegisterODE(ODE* functor) {
48     m_ode_fun = functor;
49     m_nstates = functor->GetNumStates();
50     m_states.resize(m_nstates);
51     m_rhs.resize(m_nstates);
52     functor->SetInitialConditions(m_states, this);
53     m_variables = new ChVariablesGenericDiagonalMass(m_nstates);
54     m_variables->GetMassDiagonal().Constant(m_nstates, 1);
55 }
56 
Initialize(std::shared_ptr<ChBody> body1,std::shared_ptr<ChBody> body2,bool pos_are_relative,ChVector<> pos1,ChVector<> pos2,bool auto_rest_length,double rest_length)57 void ChLinkSpringCB::Initialize(std::shared_ptr<ChBody> body1,
58                                 std::shared_ptr<ChBody> body2,
59                                 bool pos_are_relative,
60                                 ChVector<> pos1,
61                                 ChVector<> pos2,
62                                 bool auto_rest_length,
63                                 double rest_length) {
64     // First, initialize as all links with markers.
65     // In this case, create the two markers also!.
66     ChLinkMarkers::Initialize(body1, body2, CSYSNORM);
67 
68     if (pos_are_relative) {
69         marker1->Impose_Rel_Coord(ChCoordsys<>(pos1, QUNIT));
70         marker2->Impose_Rel_Coord(ChCoordsys<>(pos2, QUNIT));
71     } else {
72         marker1->Impose_Abs_Coord(ChCoordsys<>(pos1, QUNIT));
73         marker2->Impose_Abs_Coord(ChCoordsys<>(pos2, QUNIT));
74     }
75 
76     ChVector<> AbsDist = marker1->GetAbsCoord().pos - marker2->GetAbsCoord().pos;
77     dist = AbsDist.Length();
78 
79     m_rest_length = auto_rest_length ? dist : rest_length;
80 }
81 
82 // -----------------------------------------------------------------------------
83 
UpdateForces(double time)84 void ChLinkSpringCB::UpdateForces(double time) {
85     // Allow the base class to update itself (possibly adding its own forces)
86     ChLinkMarkers::UpdateForces(time);
87 
88     // Invoke the provided functor to evaluate force
89     m_force = m_force_fun ? (*m_force_fun)(time, m_rest_length, dist, dist_dt, this) : 0;
90 
91     // Add to existing force.
92     C_force += m_force * relM.pos.GetNormalized();
93 }
94 
Update(double time,bool update_assets)95 void ChLinkSpringCB::Update(double time, bool update_assets) {
96     ChLinkMarkers::Update(time, update_assets);
97 
98     // Evaluate ODE right-hand side at current state
99     if (m_ode_fun) {
100         m_ode_fun->CalculateRHS(time, m_states, m_rhs, this);
101     }
102 }
103 
104 // -----------------------------------------------------------------------------
105 
IntStateGather(const unsigned int off_x,ChState & x,const unsigned int off_v,ChStateDelta & v,double & T)106 void ChLinkSpringCB::IntStateGather(const unsigned int off_x,  // offset in x state vector
107                                     ChState& x,                // state vector, position part
108                                     const unsigned int off_v,  // offset in v state vector
109                                     ChStateDelta& v,           // state vector, speed part
110                                     double& T                  // time
111 ) {
112     if (!m_variables)
113         return;
114 
115     x.segment(off_x, m_nstates).setZero();
116     v.segment(off_v, m_nstates) = m_states;
117     T = GetChTime();
118 }
119 
IntStateScatter(const unsigned int off_x,const ChState & x,const unsigned int off_v,const ChStateDelta & v,const double T,bool full_update)120 void ChLinkSpringCB::IntStateScatter(const unsigned int off_x,  // offset in x state vector
121                                      const ChState& x,          // state vector, position part
122                                      const unsigned int off_v,  // offset in v state vector
123                                      const ChStateDelta& v,     // state vector, speed part
124                                      const double T,            // time
125                                      bool full_update           // perform complete update
126 ) {
127     Update(T, full_update);
128 
129     if (!m_variables)
130         return;
131 
132     m_states = v.segment(off_v, m_nstates);
133 }
134 
IntStateGatherAcceleration(const unsigned int off_a,ChStateDelta & a)135 void ChLinkSpringCB::IntStateGatherAcceleration(const unsigned int off_a, ChStateDelta& a) {
136     if (!m_variables)
137         return;
138 
139     a.segment(off_a, m_nstates) = m_rhs;
140 }
141 
IntStateScatterAcceleration(const unsigned int off_a,const ChStateDelta & a)142 void ChLinkSpringCB::IntStateScatterAcceleration(const unsigned int off_a, const ChStateDelta& a) {
143     //// RADU: correct?!?
144     // do nothing here
145 }
146 
IntLoadResidual_F(const unsigned int off,ChVectorDynamic<> & R,const double c)147 void ChLinkSpringCB::IntLoadResidual_F(const unsigned int off,  // offset in R residual
148                                        ChVectorDynamic<>& R,    // result: the R residual, R += c*F
149                                        const double c           // a scaling factor
150 ) {
151     ChLinkMarkers::IntLoadResidual_F(off, R, c);
152 
153     if (!m_variables)
154         return;
155 
156     // add forcing term for internal states
157     R.segment(off, m_nstates) += c * m_rhs;
158 }
159 
IntLoadResidual_Mv(const unsigned int off,ChVectorDynamic<> & R,const ChVectorDynamic<> & v,const double c)160 void ChLinkSpringCB::IntLoadResidual_Mv(const unsigned int off,      // offset in R residual
161                                         ChVectorDynamic<>& R,        // result: the R residual, R += c*M*v
162                                         const ChVectorDynamic<>& v,  // the v vector
163                                         const double c               // a scaling factor
164 ) {
165     if (!m_variables)
166         return;
167 
168     R.segment(off, m_nstates) += c * v.segment(off, m_nstates);
169 }
170 
IntToDescriptor(const unsigned int off_v,const ChStateDelta & v,const ChVectorDynamic<> & R,const unsigned int off_L,const ChVectorDynamic<> & L,const ChVectorDynamic<> & Qc)171 void ChLinkSpringCB::IntToDescriptor(const unsigned int off_v,  // offset in v, R
172                                      const ChStateDelta& v,
173                                      const ChVectorDynamic<>& R,
174                                      const unsigned int off_L,  // offset in L, Qc
175                                      const ChVectorDynamic<>& L,
176                                      const ChVectorDynamic<>& Qc) {
177     if (!m_variables)
178         return;
179 
180     m_variables->Get_qb() = v.segment(off_v, m_nstates);
181     m_variables->Get_fb() = R.segment(off_v, m_nstates);
182 }
183 
IntFromDescriptor(const unsigned int off_v,ChStateDelta & v,const unsigned int off_L,ChVectorDynamic<> & L)184 void ChLinkSpringCB::IntFromDescriptor(const unsigned int off_v,  // offset in v
185                                        ChStateDelta& v,
186                                        const unsigned int off_L,  // offset in L
187                                        ChVectorDynamic<>& L) {
188     if (!m_variables)
189         return;
190 
191     v.segment(off_v, m_nstates) = m_variables->Get_qb();
192 }
193 
194 // -----------------------------------------------------------------------------
195 
InjectVariables(ChSystemDescriptor & mdescriptor)196 void ChLinkSpringCB::InjectVariables(ChSystemDescriptor& mdescriptor) {
197     ChLinkMarkers::InjectVariables(mdescriptor);
198 
199     if (!m_variables)
200         return;
201 
202     m_variables->SetDisabled(!IsActive());
203     mdescriptor.InsertVariables(m_variables);
204 }
205 
VariablesFbReset()206 void ChLinkSpringCB::VariablesFbReset() {
207     if (!m_variables)
208         return;
209 
210     m_variables->Get_fb().setZero();
211 }
212 
VariablesFbLoadForces(double factor)213 void ChLinkSpringCB::VariablesFbLoadForces(double factor) {
214     if (!m_variables)
215         return;
216 
217     m_variables->Get_fb() = m_rhs;
218 }
219 
VariablesQbLoadSpeed()220 void ChLinkSpringCB::VariablesQbLoadSpeed() {
221     if (!m_variables)
222         return;
223 
224     m_variables->Get_qb() = m_states;
225 }
226 
VariablesQbSetSpeed(double step)227 void ChLinkSpringCB::VariablesQbSetSpeed(double step) {
228     if (!m_variables)
229         return;
230 
231     m_states = m_variables->Get_qb();
232 }
233 
VariablesFbIncrementMq()234 void ChLinkSpringCB::VariablesFbIncrementMq() {
235     if (!m_variables)
236         return;
237 
238     m_variables->Compute_inc_Mb_v(m_variables->Get_fb(), m_variables->Get_qb());
239 }
240 
VariablesQbIncrementPosition(double dt_step)241 void ChLinkSpringCB::VariablesQbIncrementPosition(double dt_step) {
242     //// RADU: correct?
243     // do nothing here
244 }
245 
246 // -----------------------------------------------------------------------------
247 
ArchiveOUT(ChArchiveOut & marchive)248 void ChLinkSpringCB::ArchiveOUT(ChArchiveOut& marchive) {
249     // version number
250     marchive.VersionWrite<ChLinkSpringCB>();
251 
252     // serialize parent class
253     ChLinkMarkers::ArchiveOUT(marchive);
254 
255     // serialize all member data:
256     marchive << CHNVP(m_rest_length);
257 }
258 
ArchiveIN(ChArchiveIn & marchive)259 void ChLinkSpringCB::ArchiveIN(ChArchiveIn& marchive) {
260     // version number
261     /*int version =*/ marchive.VersionRead<ChLinkSpringCB>();
262 
263     // deserialize parent class
264     ChLinkMarkers::ArchiveIN(marchive);
265 
266     // deserialize all member data:
267     marchive >> CHNVP(m_rest_length);
268 }
269 
270 }  // end namespace chrono
271