1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Alessandro Tasora, Radu Serban
13 // =============================================================================
14
15 #include <algorithm>
16 #include <fstream>
17 #include <functional>
18 #include <iostream>
19 #include <sstream>
20 #include <string>
21
22 #include "chrono/core/ChMath.h"
23 #include "chrono/physics/ChLoad.h"
24 #include "chrono/physics/ChObject.h"
25 #include "chrono/physics/ChSystem.h"
26
27 #include "chrono/fea/ChElementTetraCorot_4.h"
28 #include "chrono/fea/ChMesh.h"
29 #include "chrono/fea/ChNodeFEAxyz.h"
30 #include "chrono/fea/ChNodeFEAxyzrot.h"
31
32 namespace chrono {
33 namespace fea {
34
ChMesh(const ChMesh & other)35 ChMesh::ChMesh(const ChMesh& other) : ChIndexedNodes(other) {
36 vnodes = other.vnodes;
37 velements = other.velements;
38
39 n_dofs = other.n_dofs;
40 n_dofs_w = other.n_dofs_w;
41
42 vcontactsurfaces = other.vcontactsurfaces;
43 vmeshsurfaces = other.vmeshsurfaces;
44
45 automatic_gravity_load = other.automatic_gravity_load;
46 num_points_gravity = other.num_points_gravity;
47
48 ncalls_internal_forces = 0;
49 ncalls_KRMload = 0;
50 }
51
SetupInitial()52 void ChMesh::SetupInitial() {
53 n_dofs = 0;
54 n_dofs_w = 0;
55
56 for (unsigned int i = 0; i < vnodes.size(); i++) {
57 if (!vnodes[i]->GetFixed()) {
58 // - count the degrees of freedom
59 n_dofs += vnodes[i]->Get_ndof_x();
60 n_dofs_w += vnodes[i]->Get_ndof_w();
61 }
62 }
63
64 for (unsigned int i = 0; i < velements.size(); i++) {
65 // - precompute matrices, such as the [Kl] local stiffness of each element, if needed, etc.
66 velements[i]->SetupInitial(GetSystem());
67 }
68 }
69
Relax()70 void ChMesh::Relax() {
71 for (unsigned int i = 0; i < vnodes.size(); i++) {
72 // - "relaxes" the structure by setting all X0 = 0, and null speeds
73 vnodes[i]->Relax();
74 }
75 }
76
SetNoSpeedNoAcceleration()77 void ChMesh::SetNoSpeedNoAcceleration() {
78 for (unsigned int i = 0; i < vnodes.size(); i++) {
79 // - set null speeds, null accelerations
80 vnodes[i]->SetNoSpeedNoAcceleration();
81 }
82 }
83
AddNode(std::shared_ptr<ChNodeFEAbase> m_node)84 void ChMesh::AddNode(std::shared_ptr<ChNodeFEAbase> m_node) {
85 m_node->SetIndex(static_cast<unsigned int>(vnodes.size()) + 1);
86 vnodes.push_back(m_node);
87
88 // If the mesh is already added to a system, mark the system uninitialized and out-of-date
89 if (system) {
90 system->is_initialized = false;
91 system->is_updated = false;
92 }
93 }
94
AddElement(std::shared_ptr<ChElementBase> m_elem)95 void ChMesh::AddElement(std::shared_ptr<ChElementBase> m_elem) {
96 velements.push_back(m_elem);
97
98 // If the mesh is already added to a system, mark the system uninitialized and out-of-date
99 if (system) {
100 system->is_initialized = false;
101 system->is_updated = false;
102 }
103 }
104
ClearElements()105 void ChMesh::ClearElements() {
106 velements.clear();
107 vcontactsurfaces.clear();
108
109 // If the mesh is already added to a system, mark the system out-of-date
110 if (system) {
111 system->is_updated = false;
112 }
113 }
114
ClearNodes()115 void ChMesh::ClearNodes() {
116 velements.clear();
117 vnodes.clear();
118 vcontactsurfaces.clear();
119
120 // If the mesh is already added to a system, mark the system out-of-date
121 if (system) {
122 system->is_updated = false;
123 }
124 }
125
AddContactSurface(std::shared_ptr<ChContactSurface> m_surf)126 void ChMesh::AddContactSurface(std::shared_ptr<ChContactSurface> m_surf) {
127 m_surf->SetMesh(this);
128 vcontactsurfaces.push_back(m_surf);
129 }
130
ClearContactSurfaces()131 void ChMesh::ClearContactSurfaces() {
132 vcontactsurfaces.clear();
133 }
134
AddMeshSurface(std::shared_ptr<ChMeshSurface> m_surf)135 void ChMesh::AddMeshSurface(std::shared_ptr<ChMeshSurface> m_surf) {
136 m_surf->SetMesh(this);
137 vmeshsurfaces.push_back(m_surf);
138 }
139
140 /// This recomputes the number of DOFs, constraints, as well as state offsets of contained items
Setup()141 void ChMesh::Setup() {
142 n_dofs = 0;
143 n_dofs_w = 0;
144
145 for (unsigned int i = 0; i < vnodes.size(); i++) {
146 // Set node offsets in state vectors (based on the offsets of the containing mesh)
147 vnodes[i]->NodeSetOffset_x(GetOffset_x() + n_dofs);
148 vnodes[i]->NodeSetOffset_w(GetOffset_w() + n_dofs_w);
149 // Count the degrees of freedom (consider only nodes that are not fixed)
150 if (!vnodes[i]->GetFixed()) {
151 n_dofs += vnodes[i]->Get_ndof_x();
152 n_dofs_w += vnodes[i]->Get_ndof_w();
153 }
154 }
155 }
156
157 // Updates all time-dependant variables, if any...
158 // Ex: maybe the elasticity can increase in time, etc.
Update(double m_time,bool update_assets)159 void ChMesh::Update(double m_time, bool update_assets) {
160 // Parent class update
161 ChIndexedNodes::Update(m_time, update_assets);
162
163 for (unsigned int i = 0; i < velements.size(); i++) {
164 // - update auxiliary stuff, ex. update element's rotation matrices if corotational..
165 velements[i]->Update();
166 }
167 }
168
SyncCollisionModels()169 void ChMesh::SyncCollisionModels() {
170 for (unsigned int j = 0; j < vcontactsurfaces.size(); j++) {
171 vcontactsurfaces[j]->SurfaceSyncCollisionModels();
172 }
173 }
174
AddCollisionModelsToSystem()175 void ChMesh::AddCollisionModelsToSystem() {
176 assert(GetSystem());
177 SyncCollisionModels();
178 for (unsigned int j = 0; j < vcontactsurfaces.size(); j++) {
179 vcontactsurfaces[j]->SurfaceAddCollisionModelsToSystem(GetSystem());
180 }
181 }
182
RemoveCollisionModelsFromSystem()183 void ChMesh::RemoveCollisionModelsFromSystem() {
184 assert(GetSystem());
185 for (unsigned int j = 0; j < vcontactsurfaces.size(); j++) {
186 vcontactsurfaces[j]->SurfaceRemoveCollisionModelsFromSystem(GetSystem());
187 }
188 }
189
190 //// STATE BOOKKEEPING FUNCTIONS
191
IntStateGather(const unsigned int off_x,ChState & x,const unsigned int off_v,ChStateDelta & v,double & T)192 void ChMesh::IntStateGather(const unsigned int off_x,
193 ChState& x,
194 const unsigned int off_v,
195 ChStateDelta& v,
196 double& T) {
197 unsigned int local_off_x = 0;
198 unsigned int local_off_v = 0;
199 for (unsigned int j = 0; j < vnodes.size(); j++) {
200 if (!vnodes[j]->GetFixed()) {
201 vnodes[j]->NodeIntStateGather(off_x + local_off_x, x, off_v + local_off_v, v, T);
202 local_off_x += vnodes[j]->Get_ndof_x();
203 local_off_v += vnodes[j]->Get_ndof_w();
204 }
205 }
206
207 T = GetChTime();
208 }
209
IntStateScatter(const unsigned int off_x,const ChState & x,const unsigned int off_v,const ChStateDelta & v,const double T,bool full_update)210 void ChMesh::IntStateScatter(const unsigned int off_x,
211 const ChState& x,
212 const unsigned int off_v,
213 const ChStateDelta& v,
214 const double T,
215 bool full_update) {
216 unsigned int local_off_x = 0;
217 unsigned int local_off_v = 0;
218 for (unsigned int j = 0; j < vnodes.size(); j++) {
219 if (!vnodes[j]->GetFixed()) {
220 vnodes[j]->NodeIntStateScatter(off_x + local_off_x, x, off_v + local_off_v, v, T);
221 local_off_x += vnodes[j]->Get_ndof_x();
222 local_off_v += vnodes[j]->Get_ndof_w();
223 }
224 }
225
226 Update(T, full_update);
227 }
228
IntStateGatherAcceleration(const unsigned int off_a,ChStateDelta & a)229 void ChMesh::IntStateGatherAcceleration(const unsigned int off_a, ChStateDelta& a) {
230 unsigned int local_off_a = 0;
231 for (unsigned int j = 0; j < vnodes.size(); j++) {
232 if (!vnodes[j]->GetFixed()) {
233 vnodes[j]->NodeIntStateGatherAcceleration(off_a + local_off_a, a);
234 local_off_a += vnodes[j]->Get_ndof_w();
235 }
236 }
237 }
238
IntStateScatterAcceleration(const unsigned int off_a,const ChStateDelta & a)239 void ChMesh::IntStateScatterAcceleration(const unsigned int off_a, const ChStateDelta& a) {
240 unsigned int local_off_a = 0;
241 for (unsigned int j = 0; j < vnodes.size(); j++) {
242 if (!vnodes[j]->GetFixed()) {
243 vnodes[j]->NodeIntStateScatterAcceleration(off_a + local_off_a, a);
244 local_off_a += vnodes[j]->Get_ndof_w();
245 }
246 }
247 }
248
IntStateIncrement(const unsigned int off_x,ChState & x_new,const ChState & x,const unsigned int off_v,const ChStateDelta & Dv)249 void ChMesh::IntStateIncrement(const unsigned int off_x,
250 ChState& x_new,
251 const ChState& x,
252 const unsigned int off_v,
253 const ChStateDelta& Dv) {
254 unsigned int local_off_x = 0;
255 unsigned int local_off_v = 0;
256 for (unsigned int j = 0; j < vnodes.size(); j++) {
257 if (!vnodes[j]->GetFixed()) {
258 vnodes[j]->NodeIntStateIncrement(off_x + local_off_x, x_new, x, off_v + local_off_v, Dv);
259 local_off_x += vnodes[j]->Get_ndof_x();
260 local_off_v += vnodes[j]->Get_ndof_w();
261 }
262 }
263 for (unsigned int ie = 0; ie < velements.size(); ie++) {
264 velements[ie]->EleDoIntegration();
265 }
266 }
267
IntLoadResidual_F(const unsigned int off,ChVectorDynamic<> & R,const double c)268 void ChMesh::IntLoadResidual_F(const unsigned int off, ChVectorDynamic<>& R, const double c) {
269 // nodes applied forces
270 unsigned int local_off_v = 0;
271 for (unsigned int j = 0; j < vnodes.size(); j++) {
272 if (!vnodes[j]->GetFixed()) {
273 vnodes[j]->NodeIntLoadResidual_F(off + local_off_v, R, c);
274 local_off_v += vnodes[j]->Get_ndof_w();
275 }
276 }
277
278 int nthreads = GetSystem()->nthreads_chrono;
279
280 // elements internal forces
281 timer_internal_forces.start();
282 //***PARALLEL FOR***, must use omp atomic to avoid race condition in writing to R
283 #pragma omp parallel for schedule(dynamic, 4) num_threads(nthreads)
284 for (int ie = 0; ie < velements.size(); ie++) {
285 velements[ie]->EleIntLoadResidual_F(R, c);
286 }
287 timer_internal_forces.stop();
288 ncalls_internal_forces++;
289
290 // elements gravity forces
291 if (automatic_gravity_load) {
292 //***PARALLEL FOR***, must use omp atomic to avoid race condition in writing to R
293 #pragma omp parallel for schedule(dynamic, 4) num_threads(nthreads)
294 for (int ie = 0; ie < velements.size(); ie++) {
295 velements[ie]->EleIntLoadResidual_F_gravity(R, GetSystem()->Get_G_acc(), c);
296 }
297 }
298
299 // nodes gravity forces
300 local_off_v = 0;
301 if (automatic_gravity_load && this->system) {
302 //#pragma omp parallel for schedule(dynamic, 4) num_threads(nthreads)
303 //***PARALLEL FOR***, (no need here to use omp atomic to avoid race condition in writing to R)
304 for (int in = 0; in < vnodes.size(); in++) {
305 if (!vnodes[in]->GetFixed()) {
306 if (auto mnode = std::dynamic_pointer_cast<ChNodeFEAxyz>(vnodes[in])) {
307 ChVector<> fg = c * mnode->GetMass() * this->system->Get_G_acc();
308 R.segment(off + local_off_v, 3) += fg.eigen();
309 }
310 // odd stuf here... the ChNodeFEAxyzrot is not inherited from ChNodeFEAxyz so must trap it too:
311 if (auto mnode = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(vnodes[in])) {
312 ChVector<> fg = c * mnode->GetMass() * this->system->Get_G_acc();
313 R.segment(off + local_off_v, 3) += fg.eigen();
314 }
315 local_off_v += vnodes[in]->Get_ndof_w();
316 }
317 }
318 }
319 }
320
ComputeMassProperties(double & mass,ChVector<> & com,ChMatrix33<> & inertia)321 void ChMesh::ComputeMassProperties(double& mass, // ChMesh object mass
322 ChVector<>& com, // ChMesh center of gravity
323 ChMatrix33<>& inertia) // ChMesh inertia tensor
324 {
325 mass = 0;
326 com = ChVector<>(0);
327 inertia = ChMatrix33<>(1);
328
329 // Initialize all nodal total masses to zero
330 for (unsigned int j = 0; j < vnodes.size(); j++) {
331 vnodes[j]->m_TotalMass = 0.0;
332 }
333 // Loop over all elements and calculate contribution to nodal mass
334 for (unsigned int ie = 0; ie < velements.size(); ie++) {
335 velements[ie]->ComputeNodalMass();
336 }
337 // Loop over all the nodes of the mesh to obtain total object mass
338 for (unsigned int j = 0; j < vnodes.size(); j++) {
339 mass += vnodes[j]->m_TotalMass;
340 }
341 }
IntLoadResidual_Mv(const unsigned int off,ChVectorDynamic<> & R,const ChVectorDynamic<> & w,const double c)342 void ChMesh::IntLoadResidual_Mv(const unsigned int off, ///< offset in R residual
343 ChVectorDynamic<>& R, ///< result: the R residual, R += c*M*v
344 const ChVectorDynamic<>& w, ///< the w vector
345 const double c ///< a scaling factor
346 ) {
347 // nodal masses
348 unsigned int local_off_v = 0;
349 for (unsigned int j = 0; j < vnodes.size(); j++) {
350 if (!vnodes[j]->GetFixed()) {
351 vnodes[j]->NodeIntLoadResidual_Mv(off + local_off_v, R, w, c);
352 local_off_v += vnodes[j]->Get_ndof_w();
353 }
354 }
355
356 // internal masses
357 for (unsigned int ie = 0; ie < velements.size(); ie++) {
358 velements[ie]->EleIntLoadResidual_Mv(R, w, c);
359 }
360 }
361
IntToDescriptor(const unsigned int off_v,const ChStateDelta & v,const ChVectorDynamic<> & R,const unsigned int off_L,const ChVectorDynamic<> & L,const ChVectorDynamic<> & Qc)362 void ChMesh::IntToDescriptor(const unsigned int off_v,
363 const ChStateDelta& v,
364 const ChVectorDynamic<>& R,
365 const unsigned int off_L,
366 const ChVectorDynamic<>& L,
367 const ChVectorDynamic<>& Qc) {
368 unsigned int local_off_v = 0;
369 for (unsigned int j = 0; j < vnodes.size(); j++) {
370 if (!vnodes[j]->GetFixed()) {
371 vnodes[j]->NodeIntToDescriptor(off_v + local_off_v, v, R);
372 local_off_v += vnodes[j]->Get_ndof_w();
373 }
374 }
375 }
376
IntFromDescriptor(const unsigned int off_v,ChStateDelta & v,const unsigned int off_L,ChVectorDynamic<> & L)377 void ChMesh::IntFromDescriptor(const unsigned int off_v,
378 ChStateDelta& v,
379 const unsigned int off_L,
380 ChVectorDynamic<>& L) {
381 unsigned int local_off_v = 0;
382 for (unsigned int j = 0; j < vnodes.size(); j++) {
383 if (!vnodes[j]->GetFixed()) {
384 vnodes[j]->NodeIntFromDescriptor(off_v + local_off_v, v);
385 local_off_v += vnodes[j]->Get_ndof_w();
386 }
387 }
388 }
389
390 //// SOLVER FUNCTIONS
391
InjectKRMmatrices(ChSystemDescriptor & mdescriptor)392 void ChMesh::InjectKRMmatrices(ChSystemDescriptor& mdescriptor) {
393 for (unsigned int ie = 0; ie < velements.size(); ie++)
394 velements[ie]->InjectKRMmatrices(mdescriptor);
395 }
396
KRMmatricesLoad(double Kfactor,double Rfactor,double Mfactor)397 void ChMesh::KRMmatricesLoad(double Kfactor, double Rfactor, double Mfactor) {
398 int nthreads = GetSystem()->nthreads_chrono;
399
400 timer_KRMload.start();
401 #pragma omp parallel for num_threads(nthreads)
402 for (int ie = 0; ie < velements.size(); ie++)
403 velements[ie]->KRMmatricesLoad(Kfactor, Rfactor, Mfactor);
404 timer_KRMload.stop();
405 ncalls_KRMload++;
406 }
407
VariablesFbReset()408 void ChMesh::VariablesFbReset() {
409 for (unsigned int ie = 0; ie < vnodes.size(); ie++)
410 vnodes[ie]->VariablesFbReset();
411 }
412
VariablesFbLoadForces(double factor)413 void ChMesh::VariablesFbLoadForces(double factor) {
414 // applied nodal forces
415 for (unsigned int in = 0; in < vnodes.size(); in++)
416 vnodes[in]->VariablesFbLoadForces(factor);
417
418 // internal forces
419 for (unsigned int ie = 0; ie < velements.size(); ie++)
420 velements[ie]->VariablesFbLoadInternalForces(factor);
421 }
422
VariablesQbLoadSpeed()423 void ChMesh::VariablesQbLoadSpeed() {
424 for (unsigned int ie = 0; ie < vnodes.size(); ie++)
425 vnodes[ie]->VariablesQbLoadSpeed();
426 }
427
VariablesFbIncrementMq()428 void ChMesh::VariablesFbIncrementMq() {
429 // nodal masses
430 for (unsigned int ie = 0; ie < vnodes.size(); ie++)
431 vnodes[ie]->VariablesFbIncrementMq();
432
433 // internal masses
434 for (unsigned int ie = 0; ie < velements.size(); ie++)
435 velements[ie]->VariablesFbIncrementMq();
436 }
437
VariablesQbSetSpeed(double step)438 void ChMesh::VariablesQbSetSpeed(double step) {
439 for (unsigned int ie = 0; ie < vnodes.size(); ie++)
440 vnodes[ie]->VariablesQbSetSpeed(step);
441 }
442
VariablesQbIncrementPosition(double step)443 void ChMesh::VariablesQbIncrementPosition(double step) {
444 for (unsigned int ie = 0; ie < vnodes.size(); ie++)
445 vnodes[ie]->VariablesQbIncrementPosition(step);
446 }
447
InjectVariables(ChSystemDescriptor & mdescriptor)448 void ChMesh::InjectVariables(ChSystemDescriptor& mdescriptor) {
449 for (unsigned int ie = 0; ie < vnodes.size(); ie++)
450 vnodes[ie]->InjectVariables(mdescriptor);
451 }
452
453 } // end namespace fea
454 } // end namespace chrono
455