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
13 // =============================================================================
14
15 #include "chrono/fea/ChBeamSectionCosserat.h"
16 #include "chrono/core/ChMatrixMBD.h"
17 #include <math.h>
18
19 namespace chrono {
20 namespace fea {
21
22 // -----------------------------------------------------------------------------
23
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_e,const ChVector<> & strain_k)24 void ChElasticityCosserat::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
25 const ChVector<>& strain_e,
26 const ChVector<>& strain_k) {
27 double epsi = 1e-6;
28 double invepsi = 1.0 / epsi;
29 ChVector<> astress_n;
30 ChVector<> astress_m;
31 ChVector<> bstress_n;
32 ChVector<> bstress_m;
33 ChVector<> strain_e_inc = strain_e;
34 ChVector<> strain_k_inc = strain_k;
35 this->ComputeStress(astress_n, astress_m, strain_e, strain_k);
36 for (int i = 0; i < 3; ++i) {
37 strain_e_inc[i] += epsi;
38 this->ComputeStress(bstress_n, bstress_m, strain_e_inc, strain_k_inc);
39 K.block(0, i, 3, 1) = (bstress_n - astress_n).eigen() * invepsi;
40 K.block(3, i, 3, 1) = (bstress_m - astress_m).eigen() * invepsi;
41 strain_e_inc[i] -= epsi;
42 }
43 for (int i = 0; i < 3; ++i) {
44 strain_k_inc[i] += epsi;
45 this->ComputeStress(bstress_n, bstress_m, strain_e_inc, strain_k_inc);
46 K.block(0, i + 3, 3, 3) = (bstress_n - astress_n).eigen() * invepsi;
47 K.block(3, i + 3, 3, 3) = (bstress_m - astress_m).eigen() * invepsi;
48 strain_k_inc[i] -= epsi;
49 }
50 }
51
52 // -----------------------------------------------------------------------------
53
ChElasticityCosseratSimple()54 ChElasticityCosseratSimple::ChElasticityCosseratSimple()
55 : E(0.01e9) // default E stiffness (almost rubber)
56 {
57 SetGwithPoissonRatio(0.3); // default G (low poisson ratio)
58 SetAsRectangularSection(0.01, 0.01); // defaults Area, Ixx, Iyy, Ks_y, Ks_z, J
59 }
60
SetAsRectangularSection(double width_y,double width_z)61 void ChElasticityCosseratSimple::SetAsRectangularSection(double width_y, double width_z) {
62 this->A = width_y * width_z;
63 this->Izz = (1.0 / 12.0) * width_z * pow(width_y, 3);
64 this->Iyy = (1.0 / 12.0) * width_y * pow(width_z, 3);
65
66 // use Roark's formulas for torsion of rectangular sect:
67 double t = ChMin(width_y, width_z);
68 double b = ChMax(width_y, width_z);
69 this->J = b * pow(t, 3) * ((1.0 / 3.0) - 0.210 * (t / b) * (1.0 - (1.0 / 12.0) * pow((t / b), 4)));
70
71 // set Ks using Timoshenko-Gere formula for solid rect.shapes
72 double poisson = this->E / (2.0 * this->G) - 1.0;
73 this->Ks_y = 10.0 * (1.0 + poisson) / (12.0 + 11.0 * poisson);
74 this->Ks_z = this->Ks_y;
75 }
76
SetAsCircularSection(double diameter)77 void ChElasticityCosseratSimple::SetAsCircularSection(double diameter) {
78 this->A = CH_C_PI * pow((0.5 * diameter), 2);
79 this->Izz = (CH_C_PI / 4.0) * pow((0.5 * diameter), 4);
80 this->Iyy = Izz;
81
82 // exact expression for circular beam J = Ixx ,
83 // where for polar theorem Ixx = Izz+Iyy
84 this->J = Izz + Iyy;
85
86 // set Ks using Timoshenko-Gere formula for solid circular shape
87 double poisson = this->E / (2.0 * this->G) - 1.0;
88 this->Ks_y = 6.0 * (1.0 + poisson) / (7.0 + 6.0 * poisson);
89 this->Ks_z = this->Ks_y;
90 }
91
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_n,const ChVector<> & strain_m)92 void ChElasticityCosseratSimple::ComputeStress(ChVector<>& stress_n,
93 ChVector<>& stress_m,
94 const ChVector<>& strain_n,
95 const ChVector<>& strain_m) {
96 stress_n.x() = E * A * strain_n.x();
97 stress_n.y() = Ks_y * G * A * strain_n.y();
98 stress_n.z() = Ks_z * G * A * strain_n.z();
99 stress_m.x() = G * J * strain_m.x();
100 stress_m.y() = E * Iyy * strain_m.y();
101 stress_m.z() = E * Izz * strain_m.z();
102 }
103
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_n,const ChVector<> & strain_m)104 void ChElasticityCosseratSimple::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
105 const ChVector<>& strain_n,
106 const ChVector<>& strain_m) {
107 K.setZero(6, 6);
108 K(0, 0) = E * A;
109 K(1, 1) = Ks_y * G * A;
110 K(2, 2) = Ks_z * G * A;
111 K(3, 3) = G * J;
112 K(4, 4) = E * Iyy;
113 K(5, 5) = E * Izz;
114 }
115
116 // -----------------------------------------------------------------------------
117
ChElasticityCosseratGeneric()118 ChElasticityCosseratGeneric::ChElasticityCosseratGeneric() {
119 mE.setIdentity(); // default E stiffness: diagonal 1.
120 }
121
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_n,const ChVector<> & strain_m)122 void ChElasticityCosseratGeneric::ComputeStress(ChVector<>& stress_n,
123 ChVector<>& stress_m,
124 const ChVector<>& strain_n,
125 const ChVector<>& strain_m) {
126 ChVectorN<double, 6> mstrain;
127 ChVectorN<double, 6> mstress;
128 mstrain.segment(0, 3) = strain_n.eigen();
129 mstrain.segment(3, 3) = strain_m.eigen();
130 mstress = this->mE * mstrain;
131 stress_n = mstress.segment(0, 3);
132 stress_m = mstress.segment(3, 3);
133 }
134
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_n,const ChVector<> & strain_m)135 void ChElasticityCosseratGeneric::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
136 const ChVector<>& strain_n,
137 const ChVector<>& strain_m) {
138 K = this->mE;
139 }
140
141 // -----------------------------------------------------------------------------
142
ChElasticityCosseratAdvanced()143 ChElasticityCosseratAdvanced::ChElasticityCosseratAdvanced() : alpha(0), Cy(0), Cz(0), beta(0), Sy(0), Sz(0) {}
144
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_n,const ChVector<> & strain_m)145 void ChElasticityCosseratAdvanced::ComputeStress(ChVector<>& stress_n,
146 ChVector<>& stress_m,
147 const ChVector<>& strain_n,
148 const ChVector<>& strain_m) {
149 double cos_alpha = cos(alpha);
150 double sin_alpha = sin(alpha);
151 double a11 = E * A;
152 double a22 = E * (Iyy * pow(cos_alpha, 2.) + Izz * pow(sin_alpha, 2.) + Cz * Cz * A);
153 double a33 = E * (Izz * pow(cos_alpha, 2.) + Iyy * pow(sin_alpha, 2.) + Cy * Cy * A);
154 double a12 = Cz * E * A;
155 double a13 = -Cy * E * A;
156 double a23 = (E * Iyy - E * Izz) * cos_alpha * sin_alpha - E * Cy * Cz * A;
157 stress_n.x() = a11 * strain_n.x() + a12 * strain_m.y() + a13 * strain_m.z();
158 stress_m.y() = a12 * strain_n.x() + a22 * strain_m.y() + a23 * strain_m.z();
159 stress_m.z() = a13 * strain_n.x() + a23 * strain_m.y() + a33 * strain_m.z();
160 double cos_beta = cos(beta);
161 double sin_beta = sin(beta);
162 double KsyGA = Ks_y * G * A;
163 double KszGA = Ks_z * G * A;
164 double s11 = KsyGA * pow(cos_beta, 2.) + KszGA * pow(sin_beta, 2.);
165 double s22 = KsyGA * pow(sin_beta, 2.) + KszGA * pow(cos_beta, 2.); // ..+s_loc_12*sin(beta)*cos(beta);
166 double s33 = G * J + Sz * Sz * KsyGA + Sy * Sy * KszGA;
167 double s12 = (KszGA - KsyGA) * sin_beta * cos_beta;
168 double s13 = Sy * KszGA * sin_beta - Sz * KsyGA * cos_beta;
169 double s23 = Sy * KszGA * cos_beta + Sz * KsyGA * sin_beta;
170 stress_n.y() = s11 * strain_n.y() + s12 * strain_n.z() + s13 * strain_m.x();
171 stress_n.z() = s12 * strain_n.y() + s22 * strain_n.z() + s23 * strain_m.x();
172 stress_m.x() = s13 * strain_n.y() + s23 * strain_n.z() + s33 * strain_m.x();
173 }
174
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_n,const ChVector<> & strain_m)175 void ChElasticityCosseratAdvanced::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
176 const ChVector<>& strain_n,
177 const ChVector<>& strain_m) {
178 K.setZero(6, 6);
179 double cos_alpha = cos(alpha);
180 double sin_alpha = sin(alpha);
181 double a11 = E * A;
182 double a22 = E * (Iyy * pow(cos_alpha, 2.) + Izz * pow(sin_alpha, 2.) + Cz * Cz * A);
183 double a33 = E * (Izz * pow(cos_alpha, 2.) + Iyy * pow(sin_alpha, 2.) + Cy * Cy * A);
184 double a12 = Cz * E * A;
185 double a13 = -Cy * E * A;
186 double a23 = (E * Iyy - E * Izz) * cos_alpha * sin_alpha - E * Cy * Cz * A;
187 double cos_beta = cos(beta);
188 double sin_beta = sin(beta);
189 double KsyGA = Ks_y * G * A;
190 double KszGA = Ks_z * G * A;
191 double s11 = KsyGA * pow(cos_beta, 2.) + KszGA * pow(sin_beta, 2.);
192 double s22 = KsyGA * pow(sin_beta, 2.) + KszGA * pow(cos_beta, 2.); // ..+s_loc_12*sin(beta)*cos(beta);
193 double s33 = G * J + Sz * Sz * KsyGA + Sy * Sy * KszGA;
194 double s12 = (KszGA - KsyGA) * sin_beta * cos_beta;
195 double s13 = Sy * KszGA * sin_beta - Sz * KsyGA * cos_beta;
196 double s23 = Sy * KszGA * cos_beta + Sz * KsyGA * sin_beta;
197
198 K(0, 0) = a11;
199 K(0, 4) = a12;
200 K(0, 5) = a13;
201 K(1, 1) = s11;
202 K(1, 2) = s12;
203 K(1, 3) = s13;
204 K(2, 1) = s12;
205 K(2, 2) = s22;
206 K(2, 3) = s23;
207 K(3, 1) = s13;
208 K(3, 2) = s23;
209 K(3, 3) = s33;
210 K(4, 0) = a12;
211 K(4, 4) = a22;
212 K(4, 5) = a23;
213 K(5, 0) = a13;
214 K(5, 4) = a23;
215 K(5, 5) = a33;
216 }
217
218 // -----------------------------------------------------------------------------
219
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_n,const ChVector<> & strain_m)220 void ChElasticityCosseratAdvancedGeneric::ComputeStress(ChVector<>& stress_n,
221 ChVector<>& stress_m,
222 const ChVector<>& strain_n,
223 const ChVector<>& strain_m) {
224 double cos_alpha = cos(alpha);
225 double sin_alpha = sin(alpha);
226 double a11 = this->Ax;
227 double a22 = this->Byy * pow(cos_alpha, 2.) + this->Bzz * pow(sin_alpha, 2.) + Cz * Cz * this->Ax;
228 double a33 = this->Bzz * pow(cos_alpha, 2.) + this->Byy * pow(sin_alpha, 2.) + Cy * Cy * this->Ax;
229 double a12 = Cz * this->Ax;
230 double a13 = -Cy * this->Ax;
231 double a23 = (this->Byy - this->Bzz) * cos_alpha * sin_alpha - Cy * Cz * this->Ax;
232 stress_n.x() = a11 * strain_n.x() + a12 * strain_m.y() + a13 * strain_m.z();
233 stress_m.y() = a12 * strain_n.x() + a22 * strain_m.y() + a23 * strain_m.z();
234 stress_m.z() = a13 * strain_n.x() + a23 * strain_m.y() + a33 * strain_m.z();
235 double cos_beta = cos(beta);
236 double sin_beta = sin(beta);
237 double KsyGA = this->Hyy;
238 double KszGA = this->Hzz;
239 double s11 = KsyGA * pow(cos_beta, 2.) + KszGA * pow(sin_beta, 2.);
240 double s22 = KsyGA * pow(sin_beta, 2.) + KszGA * pow(cos_beta, 2.); // ..+s_loc_12*sin(beta)*cos(beta);
241 double s33 = this->Txx + Sz * Sz * KsyGA + Sy * Sy * KszGA;
242 double s12 = (KszGA - KsyGA) * sin_beta * cos_beta;
243 double s13 = Sy * KszGA * sin_beta - Sz * KsyGA * cos_beta;
244 double s23 = Sy * KszGA * cos_beta + Sz * KsyGA * sin_beta;
245 stress_n.y() = s11 * strain_n.y() + s12 * strain_n.z() + s13 * strain_m.x();
246 stress_n.z() = s12 * strain_n.y() + s22 * strain_n.z() + s23 * strain_m.x();
247 stress_m.x() = s13 * strain_n.y() + s23 * strain_n.z() + s33 * strain_m.x();
248 }
249
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_n,const ChVector<> & strain_m)250 void ChElasticityCosseratAdvancedGeneric::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
251 const ChVector<>& strain_n,
252 const ChVector<>& strain_m) {
253 K.setZero(6, 6);
254 double cos_alpha = cos(alpha);
255 double sin_alpha = sin(alpha);
256 double a11 = this->Ax;
257 double a22 = this->Byy * pow(cos_alpha, 2.) + this->Bzz * pow(sin_alpha, 2.) + Cz * Cz * this->Ax;
258 double a33 = this->Bzz * pow(cos_alpha, 2.) + this->Byy * pow(sin_alpha, 2.) + Cy * Cy * this->Ax;
259 double a12 = Cz * this->Ax;
260 double a13 = -Cy * this->Ax;
261 double a23 = (this->Byy - this->Bzz) * cos_alpha * sin_alpha - Cy * Cz * this->Ax;
262 double cos_beta = cos(beta);
263 double sin_beta = sin(beta);
264 double KsyGA = this->Hyy;
265 double KszGA = this->Hzz;
266 double s11 = KsyGA * pow(cos_beta, 2.) + KszGA * pow(sin_beta, 2.);
267 double s22 = KsyGA * pow(sin_beta, 2.) + KszGA * pow(cos_beta, 2.); // ..+s_loc_12*sin(beta)*cos(beta);
268 double s33 = this->Txx + Sz * Sz * KsyGA + Sy * Sy * KszGA;
269 double s12 = (KszGA - KsyGA) * sin_beta * cos_beta;
270 double s13 = Sy * KszGA * sin_beta - Sz * KsyGA * cos_beta;
271 double s23 = Sy * KszGA * cos_beta + Sz * KsyGA * sin_beta;
272
273 K(0, 0) = a11;
274 K(0, 4) = a12;
275 K(0, 5) = a13;
276 K(1, 1) = s11;
277 K(1, 2) = s12;
278 K(1, 3) = s13;
279 K(2, 1) = s12;
280 K(2, 2) = s22;
281 K(2, 3) = s23;
282 K(3, 1) = s13;
283 K(3, 2) = s23;
284 K(3, 3) = s33;
285 K(4, 0) = a12;
286 K(4, 4) = a22;
287 K(4, 5) = a23;
288 K(5, 0) = a13;
289 K(5, 4) = a23;
290 K(5, 5) = a33;
291 }
292
293 // -----------------------------------------------------------------------------
294
ComputeTransformMatrix()295 void ChElasticityCosseratAdvancedGenericFPM::ComputeTransformMatrix() {
296 // Initialization of the transformation matrix
297 this->T.setIdentity();
298
299 // In case the section is rotated:
300 ChMatrix33<> RotsectA;
301 RotsectA.Set_A_Rxyz(ChVector<>(this->alpha, 0, 0));
302
303 // In case the shear axis is rotated:
304 ChMatrix33<> RotShearA;
305 RotShearA.Set_A_Rxyz(ChVector<>(this->beta, 0, 0));
306
307 ChMatrixNM<double, 6, 6> RotA;
308 RotA.setZero();
309 RotA.row(0) << RotsectA(0, 0), 0, 0, 0, RotsectA(0, 1), RotsectA(0, 2);
310 RotA.row(1) << 0, RotShearA(0, 0), RotShearA(0, 1), RotShearA(0, 2), 0, 0;
311 RotA.row(2) << 0, RotShearA(1, 0), RotShearA(1, 1), RotShearA(1, 2), 0, 0;
312 RotA.row(3) << 0, RotShearA(2, 0), RotShearA(2, 1), RotShearA(2, 2), 0, 0;
313 RotA.row(4) << RotsectA(1, 0), 0, 0, 0, RotsectA(1, 1), RotsectA(1, 2);
314 RotA.row(5) << RotsectA(2, 0), 0, 0, 0, RotsectA(2, 1), RotsectA(2, 2);
315
316 // In case the Elastic reference is offset to the centerline:
317 ChMatrixNM<double, 6, 6> Tc;
318 Tc.setIdentity();
319 Tc(0, 4) = Cz;
320 Tc(0, 5) = -Cy;
321 Tc(1, 3) = -Cz;
322 Tc(2, 3) = Cy;
323
324 // In case the Shear center is offset to the centerline:
325 ChMatrixNM<double, 6, 6> Ts;
326 Ts.setIdentity();
327 Ts(1, 3) = -Sz;
328 Ts(2, 3) = Sy;
329
330 this->T = RotA * Ts * Tc;
331 }
332
UpdateEMatrix()333 void ChElasticityCosseratAdvancedGenericFPM::UpdateEMatrix() {
334 if (!updated) { // do it only once
335 // compute T
336 ComputeTransformMatrix();
337 // update Klaw after setting section rotation and EC/SC offset
338 this->Klaw = this->T.transpose() * this->Klaw * this->T;
339 updated = true;
340 }
341 }
342
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_n,const ChVector<> & strain_m)343 void ChElasticityCosseratAdvancedGenericFPM::ComputeStress(ChVector<>& stress_n,
344 ChVector<>& stress_m,
345 const ChVector<>& strain_n,
346 const ChVector<>& strain_m) {
347 ChVectorN<double, 6> mstrain;
348 ChVectorN<double, 6> mstress;
349 mstrain.segment(0, 3) = strain_n.eigen();
350 mstrain.segment(3, 3) = strain_m.eigen();
351 mstress = this->Klaw * mstrain;
352 stress_n = mstress.segment(0, 3);
353 stress_m = mstress.segment(3, 3);
354 }
355
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_n,const ChVector<> & strain_m)356 void ChElasticityCosseratAdvancedGenericFPM::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
357 const ChVector<>& strain_n,
358 const ChVector<>& strain_m) {
359 K = this->Klaw;
360 }
361
362 // -----------------------------------------------------------------------------
363
SetAsRectangularSection(double width_y,double width_z)364 void ChElasticityCosseratMesh::SetAsRectangularSection(double width_y, double width_z) {
365 this->vertexes.clear();
366 this->vertexes.push_back(ChVector2<>(width_y * 0.5, width_z * 0.5));
367 this->vertexes.push_back(ChVector2<>(width_y * 0.5, -width_z * 0.5));
368 this->vertexes.push_back(ChVector2<>(-width_y * 0.5, -width_z * 0.5));
369 this->vertexes.push_back(ChVector2<>(-width_y * 0.5, width_z * 0.5));
370
371 this->triangles.clear();
372 this->triangles.push_back(ChVector<int>(0, 1, 2));
373 this->triangles.push_back(ChVector<int>(0, 2, 3));
374
375 // set Ks using Timoshenko-Gere formula for solid rect.shapes
376 /*
377 double poisson = this->E / (2.0 * this->G) - 1.0;
378 this->Ks_y = 10.0 * (1.0 + poisson) / (12.0 + 11.0 * poisson);
379 this->Ks_z = this->Ks_y;
380 */
381 }
382
SetAsCircularSection(double diameter)383 void ChElasticityCosseratMesh::SetAsCircularSection(double diameter) {
384 this->vertexes.clear();
385 this->triangles.clear();
386
387 double rad = diameter * 0.5;
388 this->vertexes.push_back(ChVector2<>(0, 0));
389 this->vertexes.push_back(ChVector2<>(rad, 0));
390 int ntri = 12;
391 for (int i = 0; i < ntri; ++i) {
392 double alpha = (i + 1) * (CH_C_2PI / (double)ntri);
393 this->vertexes.push_back(ChVector2<>(rad * cos(alpha), rad * sin(alpha)));
394 this->triangles.push_back(ChVector<int>(0, i + 1, i + 2));
395 }
396
397 // set Ks using Timoshenko-Gere formula for solid circular shape
398 /*
399 double poisson = this->E / (2.0 * this->G) - 1.0;
400 this->Ks_y = 6.0 * (1.0 + poisson) / (7.0 + 6.0 * poisson);
401 this->Ks_z = this->Ks_y;
402 */
403 }
404
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_n,const ChVector<> & strain_m)405 void ChElasticityCosseratMesh::ComputeStress(ChVector<>& stress_n,
406 ChVector<>& stress_m,
407 const ChVector<>& strain_n,
408 const ChVector<>& strain_m) {
409 int nv = (int)this->vertexes.size();
410 int nt = (int)this->triangles.size();
411
412 // temp per-vertex data for point strains:
413 std::vector<double> epsilon_xx(nv);
414 std::vector<double> gamma_xy(nv);
415 std::vector<double> gamma_xz(nv);
416
417 // temp per-vertex data for point stresses:
418 std::vector<double> sigma_xx(nv);
419 std::vector<double> sigma_xy(nv);
420 std::vector<double> sigma_xz(nv);
421
422 double warp_dy = 0; // to do
423 double warp_dz = 0; // to do
424
425 for (int i = 0; i < nv; ++i) {
426 std::shared_ptr<ChSectionMaterial> mmat;
427 if (materials.size() == 1)
428 mmat = materials[0];
429 else
430 mmat = materials[i];
431
432 double vy = vertexes[i][0];
433 double vz = vertexes[i][1];
434 epsilon_xx[i] = strain_n.x() + strain_m.y() * vz - strain_m.z() * vy;
435 gamma_xy[i] = strain_n.y() + strain_m.x() * (warp_dy - vz);
436 gamma_xz[i] = strain_n.z() + strain_m.x() * (warp_dz + vy);
437 // simple linear elastic model:
438 sigma_xx[i] = mmat->E * epsilon_xx[i];
439 sigma_xy[i] = mmat->G * gamma_xy[i];
440 sigma_xz[i] = mmat->G * gamma_xz[i];
441 }
442
443 // integrate on triangles, assuming linear interpolation of vertex values
444 stress_n = VNULL;
445 stress_m = VNULL;
446 for (int t = 0; t < nt; ++t) {
447 size_t iv1 = triangles[t].x();
448 size_t iv2 = triangles[t].y();
449 size_t iv3 = triangles[t].z();
450 double y1 = this->vertexes[iv1][0];
451 double z1 = this->vertexes[iv1][1];
452 double y2 = this->vertexes[iv2][0];
453 double z2 = this->vertexes[iv2][1];
454 double y3 = this->vertexes[iv3][0];
455 double z3 = this->vertexes[iv3][1];
456
457 double A = fabs(0.5 * ((y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2))));
458
459 double s1 = sigma_xx[iv1];
460 double s2 = sigma_xx[iv2];
461 double s3 = sigma_xx[iv3];
462 double sxz1 = sigma_xz[iv1];
463 double sxz2 = sigma_xz[iv2];
464 double sxz3 = sigma_xz[iv3];
465 double sxy1 = sigma_xy[iv1];
466 double sxy2 = sigma_xy[iv2];
467 double sxy3 = sigma_xy[iv3];
468
469 stress_n.x() += (1. / 3.) * A * (s1 + s2 + s3);
470 stress_n.y() += (1. / 3.) * A * (sxy1 + sxy2 + sxy3);
471 stress_n.z() += (1. / 3.) * A * (sxz1 + sxz2 + sxz3);
472
473 stress_m.x() +=
474 2. * A *
475 ((sxz1 * y1) / 12. + (sxz1 * y2) / 24. + (sxz2 * y1) / 24. + (sxz1 * y3) / 24. + (sxz2 * y2) / 12. +
476 (sxz3 * y1) / 24. + (sxz2 * y3) / 24. + (sxz3 * y2) / 24. + (sxz3 * y3) / 12. - (sxy1 * z1) / 12. -
477 (sxy1 * z2) / 24. - (sxy2 * z1) / 24. - (sxy1 * z3) / 24. - (sxy2 * z2) / 12. - (sxy3 * z1) / 24. -
478 (sxy2 * z3) / 24. - (sxy3 * z2) / 24. - (sxy3 * z3) / 12.);
479 stress_m.y() += 2. * A *
480 ((s1 * z1) / 12. + (s1 * z2) / 24. + (s2 * z1) / 24. + (s1 * z3) / 24. + (s2 * z2) / 12. +
481 (s3 * z1) / 24. + (s2 * z3) / 24. + (s3 * z2) / 24. + (s3 * z3) / 12.);
482 stress_m.z() -= 2. * A *
483 ((s1 * y1) / 12. + (s1 * y2) / 24. + (s2 * y1) / 24. + (s1 * y3) / 24. + (s2 * y2) / 12. +
484 (s3 * y1) / 24. + (s2 * y3) / 24. + (s3 * y2) / 24. + (s3 * y3) / 12.);
485 }
486 }
487
488 // -----------------------------------------------------------------------------
489
ChPlasticityCosserat()490 ChPlasticityCosserat::ChPlasticityCosserat() : section(nullptr), nr_yeld_tolerance(1e-7), nr_yeld_maxiters(5) {}
491
ComputeStiffnessMatrixElastoplastic(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_n,const ChVector<> & strain_m,const ChBeamMaterialInternalData & data)492 void ChPlasticityCosserat::ComputeStiffnessMatrixElastoplastic(ChMatrixNM<double, 6, 6>& K,
493 const ChVector<>& strain_n,
494 const ChVector<>& strain_m,
495 const ChBeamMaterialInternalData& data) {
496 ChVector<> astress_n;
497 ChVector<> astress_m;
498 ChVector<> me_strain_n_new; // needed only as placeholder
499 ChVector<> me_strain_m_new; // needed only as placeholder
500
501 std::vector<std::unique_ptr<ChBeamMaterialInternalData>> a_plastic_data;
502 this->CreatePlasticityData(1, a_plastic_data);
503 std::vector<std::unique_ptr<ChBeamMaterialInternalData>> b_plastic_data;
504 this->CreatePlasticityData(1, b_plastic_data);
505
506 bool in_plastic = ComputeStressWithReturnMapping(astress_n, astress_m, me_strain_n_new, me_strain_m_new,
507 *a_plastic_data[0], strain_n, strain_m, data);
508
509 if (!in_plastic) {
510 // if no return mapping is needed at this strain state, just use elastic matrix:
511 return this->section->GetElasticity()->ComputeStiffnessMatrix(K, strain_n, strain_m);
512 } else {
513 // if return mapping is needed at this strain state, compute the elastoplastic stiffness by brute force BDF
514 double epsi = 1e-6;
515 double invepsi = 1.0 / epsi;
516 ChVector<> bstress_n;
517 ChVector<> bstress_m;
518 ChVector<> strain_n_inc = strain_n;
519 ChVector<> strain_m_inc = strain_m;
520 for (int i = 0; i < 3; ++i) {
521 strain_n_inc[i] += epsi;
522 this->ComputeStressWithReturnMapping(bstress_n, bstress_m, me_strain_n_new, me_strain_m_new,
523 *b_plastic_data[0], strain_n_inc, strain_m_inc, data);
524 K.block(0, i, 3, 1) = (bstress_n - astress_n).eigen() * invepsi;
525 K.block(3, i, 3, 1) = (bstress_m - astress_m).eigen() * invepsi;
526 strain_n_inc[i] -= epsi;
527 }
528 for (int i = 0; i < 3; ++i) {
529 strain_m_inc[i] += epsi;
530 this->ComputeStressWithReturnMapping(bstress_n, bstress_m, me_strain_n_new, me_strain_m_new,
531 *b_plastic_data[0], strain_n_inc, strain_m_inc, data);
532 K.block(0, i + 3, 3, 1) = (bstress_n - astress_n).eigen() * invepsi;
533 K.block(3, i + 3, 3, 1) = (bstress_m - astress_m).eigen() * invepsi;
534 strain_m_inc[i] -= epsi;
535 }
536 }
537 }
538
CreatePlasticityData(int numpoints,std::vector<std::unique_ptr<ChBeamMaterialInternalData>> & plastic_data)539 void ChPlasticityCosserat::CreatePlasticityData(
540 int numpoints,
541 std::vector<std::unique_ptr<ChBeamMaterialInternalData>>& plastic_data) {
542 plastic_data.resize(numpoints);
543 for (int i = 0; i < numpoints; ++i) {
544 plastic_data[i] = std::unique_ptr<ChBeamMaterialInternalData>(new ChBeamMaterialInternalData());
545 }
546 }
547
548 // -----------------------------------------------------------------------------
549
ChPlasticityCosseratLumped()550 ChPlasticityCosseratLumped::ChPlasticityCosseratLumped() {
551 // Default: linear isotropic constant hardening
552 n_yeld_x = chrono_types::make_shared<ChFunction_Const>(1000);
553 n_beta_x = chrono_types::make_shared<ChFunction_Const>(0);
554 n_yeld_y = chrono_types::make_shared<ChFunction_Const>(1000);
555 n_beta_y = chrono_types::make_shared<ChFunction_Const>(0);
556 n_yeld_z = chrono_types::make_shared<ChFunction_Const>(1000);
557 n_beta_z = chrono_types::make_shared<ChFunction_Const>(0);
558 n_yeld_Mx = chrono_types::make_shared<ChFunction_Const>(1000);
559 n_beta_Mx = chrono_types::make_shared<ChFunction_Const>(0);
560 n_yeld_My = chrono_types::make_shared<ChFunction_Const>(1000);
561 n_beta_My = chrono_types::make_shared<ChFunction_Const>(0);
562 n_yeld_Mz = chrono_types::make_shared<ChFunction_Const>(1000);
563 n_beta_Mz = chrono_types::make_shared<ChFunction_Const>(0);
564 }
565
ComputeStressWithReturnMapping(ChVector<> & stress_n,ChVector<> & stress_m,ChVector<> & e_strain_e_new,ChVector<> & e_strain_k_new,ChBeamMaterialInternalData & data_new,const ChVector<> & tot_strain_e,const ChVector<> & tot_strain_k,const ChBeamMaterialInternalData & data)566 bool ChPlasticityCosseratLumped::ComputeStressWithReturnMapping(ChVector<>& stress_n,
567 ChVector<>& stress_m,
568 ChVector<>& e_strain_e_new,
569 ChVector<>& e_strain_k_new,
570 ChBeamMaterialInternalData& data_new,
571 const ChVector<>& tot_strain_e,
572 const ChVector<>& tot_strain_k,
573 const ChBeamMaterialInternalData& data) {
574 auto mydata = dynamic_cast<const ChInternalDataLumpedCosserat*>(&data);
575 auto mydata_new = dynamic_cast<ChInternalDataLumpedCosserat*>(&data_new);
576
577 if (!mydata)
578 throw ChException("ComputeStressWithReturnMapping cannot cast data to ChInternalDataLumpedCosserat*.");
579
580 // Implement return mapping for a simple 1D plasticity model.
581
582 // Compute the elastic trial stress:
583 e_strain_e_new = tot_strain_e - mydata->p_strain_e;
584 e_strain_k_new = tot_strain_k - mydata->p_strain_k;
585 // double p_strain_acc = mydata->p_strain_acc;
586 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
587
588 // axial direction
589 {
590 double strain_yeld_x = this->n_yeld_x->Get_y(mydata->p_strain_acc_e.x()); //<<<< sigma_y(p_strain_acc)
591 double eta_x = stress_n.x() - this->n_beta_x->Get_y(mydata->p_strain_e.x()); //<<<< beta(p_strain_e)
592 double Fyeld_x = fabs(eta_x) - strain_yeld_x; //<<<< Phi(sigma,p_strain_acc)
593
594 if (Fyeld_x > 0) {
595 double Dgamma = 0;
596 double Dgamma_old = 0;
597 mydata_new->p_strain_acc_e.x() = mydata->p_strain_acc_e.x();
598 mydata_new->p_strain_e.x() = mydata->p_strain_e.x();
599 int iters = 0;
600 while ((Fyeld_x > this->nr_yeld_tolerance) && (iters < this->nr_yeld_maxiters)) {
601 double E_x = stress_n.x() / e_strain_e_new.x(); // instead of costly evaluation of Km, =dstress/dstrain
602 double H = this->n_beta_x->Get_y_dx(mydata->p_strain_e.x()) +
603 this->n_yeld_x->Get_y_dx(mydata->p_strain_acc_e.x()); //<<<< H = dyeld/dplasticflow
604 Dgamma -= Fyeld_x / (-E_x - H);
605 double dDgamma = Dgamma - Dgamma_old;
606 Dgamma_old = Dgamma;
607 mydata_new->p_strain_acc_e.x() += dDgamma;
608 e_strain_e_new.x() -= dDgamma * chrono::ChSignum(stress_n.x());
609 mydata_new->p_strain_e.x() += dDgamma * chrono::ChSignum(stress_n.x());
610 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
611 // compute yeld
612 strain_yeld_x = this->n_yeld_x->Get_y(mydata_new->p_strain_acc_e.x()); //<<<< sigma_y(p_strain_acc)
613 eta_x = stress_n.x() - this->n_beta_x->Get_y(mydata_new->p_strain_e.x()); //<<<< beta(p_strain_acc)
614 Fyeld_x = fabs(eta_x) - strain_yeld_x; //<<<< Phi(sigma,p_strain_acc)
615
616 ++iters;
617 }
618 }
619 }
620
621 // shear direction
622 {
623 double strain_yeld_y = this->n_yeld_y->Get_y(mydata->p_strain_acc_e.y());
624 double eta_y = stress_n.y() - this->n_beta_y->Get_y(mydata->p_strain_e.y());
625 double Fyeld_y = fabs(eta_y) - strain_yeld_y; //<<<< Phi(sigma,p_strain_acc)
626
627 if (Fyeld_y < 0) {
628 double Dgamma = 0;
629 double Dgamma_old = 0;
630 mydata_new->p_strain_acc_e.y() = mydata->p_strain_acc_e.y();
631 mydata_new->p_strain_e.y() = mydata->p_strain_e.y();
632 int iters = 0;
633 while ((Fyeld_y > this->nr_yeld_tolerance) && (iters < this->nr_yeld_maxiters)) {
634 double E_y = stress_n.y() / e_strain_e_new.y(); // instead of costly evaluation of Km, =dstress/dstrain
635 double H = this->n_beta_y->Get_y_dx(mydata->p_strain_e.y()) +
636 this->n_yeld_y->Get_y_dx(mydata->p_strain_acc_e.y()); //<<<< H = dyeld/dplasticflow
637 Dgamma -= Fyeld_y / (-E_y - H);
638 double dDgamma = Dgamma - Dgamma_old;
639 Dgamma_old = Dgamma;
640 mydata_new->p_strain_acc_e.y() += dDgamma;
641 e_strain_e_new.y() -= dDgamma * chrono::ChSignum(stress_n.y());
642 mydata_new->p_strain_e.y() += dDgamma * chrono::ChSignum(stress_n.y());
643 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
644 // compute yeld
645 strain_yeld_y = this->n_yeld_y->Get_y(mydata_new->p_strain_acc_e.y()); //<<<< sigma_y(p_strain_acc)
646 eta_y = stress_n.y() - this->n_beta_y->Get_y(mydata_new->p_strain_e.y()); //<<<< beta(p_strain_acc)
647 Fyeld_y = fabs(eta_y) - strain_yeld_y; //<<<< Phi(sigma,p_strain_acc)
648
649 ++iters;
650 }
651 }
652 }
653
654 // shear direction
655 {
656 double strain_yeld_z = this->n_yeld_z->Get_y(mydata->p_strain_acc_e.z());
657 double eta_z = stress_n.z() - this->n_beta_z->Get_y(mydata->p_strain_e.z());
658 double Fyeld_z = fabs(eta_z) - strain_yeld_z; //<<<< Phi(sigma,p_strain_acc)
659
660 if (Fyeld_z > 0) {
661 double Dgamma = 0;
662 double Dgamma_old = 0;
663 mydata_new->p_strain_acc_e.z() = mydata->p_strain_acc_e.z();
664 mydata_new->p_strain_e.z() = mydata->p_strain_e.z();
665 int iters = 0;
666 while ((Fyeld_z > this->nr_yeld_tolerance) && (iters < this->nr_yeld_maxiters)) {
667 double E_z = stress_n.z() / e_strain_e_new.z(); // instead of costly evaluation of Km, =dstress/dstrain
668 double H = this->n_beta_z->Get_y_dx(mydata->p_strain_e.z()) +
669 this->n_yeld_z->Get_y_dx(mydata->p_strain_acc_e.z()); //<<<< H = dyeld/dplasticflow
670 Dgamma -= Fyeld_z / (-E_z - H);
671 double dDgamma = Dgamma - Dgamma_old;
672 Dgamma_old = Dgamma;
673 mydata_new->p_strain_acc_e.z() += dDgamma;
674 e_strain_e_new.z() -= dDgamma * chrono::ChSignum(stress_n.z());
675 mydata_new->p_strain_e.z() += dDgamma * chrono::ChSignum(stress_n.z());
676 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
677 // compute yeld
678 strain_yeld_z = this->n_yeld_z->Get_y(mydata_new->p_strain_acc_e.z()); //<<<< sigma_y(p_strain_acc)
679 eta_z = stress_n.z() - this->n_beta_z->Get_y(mydata_new->p_strain_e.z()); //<<<< beta(p_strain_acc)
680 Fyeld_z = fabs(eta_z) - strain_yeld_z; //<<<< Phi(sigma,p_strain_acc)
681
682 ++iters;
683 }
684 }
685 }
686
687 // torsion direction
688 {
689 double strain_yeld_Mx = this->n_yeld_Mx->Get_y(mydata->p_strain_acc_k.x());
690 double eta_Mx = stress_m.x() - this->n_beta_Mx->Get_y(mydata->p_strain_k.x());
691 double Fyeld_Mx = fabs(eta_Mx) - strain_yeld_Mx;
692
693 if (Fyeld_Mx > 0) {
694 double Dgamma = 0;
695 double Dgamma_old = 0;
696 mydata_new->p_strain_acc_k.x() = mydata->p_strain_acc_k.x();
697 mydata_new->p_strain_k.x() = mydata->p_strain_k.x();
698 int iters = 0;
699 while ((Fyeld_Mx > this->nr_yeld_tolerance) && (iters < this->nr_yeld_maxiters)) {
700 double E_Mx = stress_m.x() / e_strain_k_new.x(); // instead of costly evaluation of Km,
701 // =dstress/dstrain
702 double H = this->n_beta_Mx->Get_y_dx(mydata->p_strain_k.x()) +
703 this->n_yeld_Mx->Get_y_dx(mydata->p_strain_acc_k.x()); //<<<< H = dyeld/dplasticflow
704 Dgamma -= Fyeld_Mx / (-E_Mx - H);
705 double dDgamma = Dgamma - Dgamma_old;
706 Dgamma_old = Dgamma;
707 mydata_new->p_strain_acc_k.x() += dDgamma;
708 e_strain_k_new.x() -= dDgamma * chrono::ChSignum(stress_m.x());
709 mydata_new->p_strain_k.x() += dDgamma * chrono::ChSignum(stress_m.x());
710 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
711 // compute yeld
712 strain_yeld_Mx = this->n_yeld_Mx->Get_y(mydata_new->p_strain_acc_k.x()); //<<<< sigma_y(p_strain_acc)
713 eta_Mx = stress_m.x() - this->n_beta_Mx->Get_y(mydata_new->p_strain_k.x()); //<<<< beta(p_strain_acc)
714 Fyeld_Mx = fabs(eta_Mx) - strain_yeld_Mx; //<<<< Phi(sigma,p_strain_acc)
715
716 ++iters;
717 }
718 }
719 }
720
721 // bending y direction
722 {
723 double strain_yeld_My = this->n_yeld_My->Get_y(mydata->p_strain_acc_k.y());
724 double eta_My = stress_m.y() - this->n_beta_My->Get_y(mydata->p_strain_k.y());
725 double Fyeld_My = fabs(eta_My) - strain_yeld_My;
726
727 if (Fyeld_My > 0) {
728 double Dgamma = 0;
729 double Dgamma_old = 0;
730 mydata_new->p_strain_acc_k.y() = mydata->p_strain_acc_k.y();
731 mydata_new->p_strain_k.y() = mydata->p_strain_k.y();
732 int iters = 0;
733 while ((Fyeld_My > this->nr_yeld_tolerance) && (iters < this->nr_yeld_maxiters)) {
734 double E_My = stress_m.y() / e_strain_k_new.y(); // instead of costly evaluation of Km,
735 // =dstress/dstrain
736 double H = this->n_beta_My->Get_y_dx(mydata->p_strain_k.y()) +
737 this->n_yeld_My->Get_y_dx(mydata->p_strain_acc_k.y()); //<<<< H = dyeld/dplasticflow
738 Dgamma -= Fyeld_My / (-E_My - H);
739 double dDgamma = Dgamma - Dgamma_old;
740 Dgamma_old = Dgamma;
741 mydata_new->p_strain_acc_k.y() += dDgamma;
742 e_strain_k_new.y() -= dDgamma * chrono::ChSignum(stress_m.y());
743 mydata_new->p_strain_k.y() += dDgamma * chrono::ChSignum(stress_m.y());
744 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
745 // compute yeld
746 strain_yeld_My = this->n_yeld_My->Get_y(mydata_new->p_strain_acc_k.y()); //<<<< sigma_y(p_strain_acc)
747 eta_My = stress_m.y() - this->n_beta_My->Get_y(mydata_new->p_strain_k.y()); //<<<< beta(p_strain_acc)
748 Fyeld_My = fabs(eta_My) - strain_yeld_My; //<<<< Phi(sigma,p_strain_acc)
749
750 ++iters;
751 }
752 }
753 }
754
755 // bending z direction
756 {
757 double strain_yeld_Mz = this->n_yeld_Mz->Get_y(mydata->p_strain_acc_k.z());
758 double eta_Mz = stress_m.z() - this->n_beta_Mz->Get_y(mydata->p_strain_k.z());
759 double Fyeld_Mz = fabs(eta_Mz) - strain_yeld_Mz;
760
761 if (Fyeld_Mz > 0) {
762 double Dgamma = 0;
763 double Dgamma_old = 0;
764 mydata_new->p_strain_acc_k.z() = mydata->p_strain_acc_k.z();
765 mydata_new->p_strain_k.z() = mydata->p_strain_k.z();
766 int iters = 0;
767 while ((Fyeld_Mz > this->nr_yeld_tolerance) && (iters < this->nr_yeld_maxiters)) {
768 double E_Mz = stress_m.z() / e_strain_k_new.z(); // instead of costly evaluation of Km,
769 // =dstress/dstrain
770 double H = this->n_beta_Mz->Get_y_dx(mydata->p_strain_k.z()) +
771 this->n_yeld_Mz->Get_y_dx(mydata->p_strain_acc_k.z()); //<<<< H = dyeld/dplasticflow
772 Dgamma -= Fyeld_Mz / (-E_Mz - H);
773 double dDgamma = Dgamma - Dgamma_old;
774 Dgamma_old = Dgamma;
775 mydata_new->p_strain_acc_k.z() += dDgamma;
776 e_strain_k_new.z() -= dDgamma * chrono::ChSignum(stress_m.z());
777 mydata_new->p_strain_k.z() += dDgamma * chrono::ChSignum(stress_m.z());
778 this->section->GetElasticity()->ComputeStress(stress_n, stress_m, e_strain_e_new, e_strain_k_new);
779 // compute yeld
780 strain_yeld_Mz = this->n_yeld_Mz->Get_y(mydata_new->p_strain_acc_k.z()); //<<<< sigma_y(p_strain_acc)
781 eta_Mz = stress_m.z() - this->n_beta_Mz->Get_y(mydata_new->p_strain_k.z()); //<<<< beta(p_strain_acc)
782 Fyeld_Mz = fabs(eta_Mz) - strain_yeld_Mz; //<<<< Phi(sigma,p_strain_acc)
783
784 ++iters;
785 }
786 }
787 }
788 // te scalar plastic accumulator in this case is the sum of the single accumulators of the various degreees of
789 // freedom of the beam:
790 mydata_new->p_strain_acc = mydata_new->p_strain_acc_e.x() + mydata_new->p_strain_acc_e.y() +
791 mydata_new->p_strain_acc_e.z() + mydata_new->p_strain_acc_k.x() +
792 mydata_new->p_strain_acc_k.y() + mydata_new->p_strain_acc_k.z();
793
794 return true;
795 };
796
CreatePlasticityData(int numpoints,std::vector<std::unique_ptr<ChBeamMaterialInternalData>> & plastic_data)797 void ChPlasticityCosseratLumped::CreatePlasticityData(
798 int numpoints,
799 std::vector<std::unique_ptr<ChBeamMaterialInternalData>>& plastic_data) {
800 plastic_data.resize(numpoints);
801 for (int i = 0; i < numpoints; ++i) {
802 plastic_data[i] = std::unique_ptr<ChBeamMaterialInternalData>(new ChInternalDataLumpedCosserat());
803 }
804 }
805
806 // -----------------------------------------------------------------------------
807
ComputeDampingMatrix(ChMatrixNM<double,6,6> & R,const ChVector<> & dstrain_e,const ChVector<> & dstrain_k)808 void ChDampingCosserat::ComputeDampingMatrix(ChMatrixNM<double, 6, 6>& R,
809 const ChVector<>& dstrain_e,
810 const ChVector<>& dstrain_k) {
811 double epsi = 1e-6;
812 double invepsi = 1.0 / epsi;
813 ChVector<> astress_n;
814 ChVector<> astress_m;
815 ChVector<> bstress_n;
816 ChVector<> bstress_m;
817 ChVector<> strain_e_inc = dstrain_e;
818 ChVector<> strain_k_inc = dstrain_k;
819 this->ComputeStress(astress_n, astress_m, dstrain_e, dstrain_k);
820 for (int i = 0; i < 3; ++i) {
821 strain_e_inc[i] += epsi;
822 this->ComputeStress(bstress_n, bstress_m, strain_e_inc, strain_k_inc);
823 R.block(0, i, 3, 1) = (bstress_n - astress_n).eigen() * invepsi;
824 R.block(3, i, 3, 1) = (bstress_m - astress_m).eigen() * invepsi;
825 }
826 for (int i = 0; i < 3; ++i) {
827 strain_k_inc[i] += epsi;
828 this->ComputeStress(bstress_n, bstress_m, strain_e_inc, strain_k_inc);
829 R.block(0, i + 3, 3, 1) = (bstress_n - astress_n).eigen() * invepsi;
830 R.block(3, i + 3, 3, 1) = (bstress_m - astress_m).eigen() * invepsi;
831 strain_k_inc[i] -= epsi;
832 }
833 }
834
835 // -----------------------------------------------------------------------------
836
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & dstrain_e,const ChVector<> & dstrain_k)837 void ChDampingCosseratLinear::ComputeStress(ChVector<>& stress_n,
838 ChVector<>& stress_m,
839 const ChVector<>& dstrain_e,
840 const ChVector<>& dstrain_k) {
841 stress_n.x() = dstrain_e.x() * R_e.x();
842 stress_n.y() = dstrain_e.y() * R_e.y();
843 stress_n.z() = dstrain_e.z() * R_e.z();
844 stress_m.x() = dstrain_k.x() * R_k.x();
845 stress_m.y() = dstrain_k.y() * R_k.y();
846 stress_m.z() = dstrain_k.z() * R_k.z();
847 }
848
ComputeDampingMatrix(ChMatrixNM<double,6,6> & R,const ChVector<> & dstrain_e,const ChVector<> & dstrain_k)849 void ChDampingCosseratLinear::ComputeDampingMatrix(ChMatrixNM<double, 6, 6>& R,
850 const ChVector<>& dstrain_e,
851 const ChVector<>& dstrain_k) {
852 R.setZero();
853 R(0, 0) = R_e.x();
854 R(1, 1) = R_e.y();
855 R(2, 2) = R_e.z();
856 R(3, 3) = R_k.x();
857 R(4, 4) = R_k.y();
858 R(5, 5) = R_k.z();
859 }
860
861 // -----------------------------------------------------------------------------
862
863 // -----------------------------------------------------------------------------
864
ChDampingCosseratRayleigh(std::shared_ptr<ChElasticityCosserat> melasticity,const double & mbeta)865 ChDampingCosseratRayleigh::ChDampingCosseratRayleigh(std::shared_ptr<ChElasticityCosserat> melasticity,
866 const double& mbeta) {
867 this->beta = mbeta;
868 this->section_elasticity = melasticity;
869 this->updated = false;
870 }
871
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & dstrain_e,const ChVector<> & dstrain_k)872 void ChDampingCosseratRayleigh::ComputeStress(ChVector<>& stress_n,
873 ChVector<>& stress_m,
874 const ChVector<>& dstrain_e,
875 const ChVector<>& dstrain_k) {
876 if (!this->updated) {
877 this->UpdateStiffnessModel();
878 this->updated = true;
879 }
880 ChVectorN<double, 6> mdstrain;
881 ChVectorN<double, 6> mstress;
882 mdstrain.segment(0, 3) = dstrain_e.eigen();
883 mdstrain.segment(3, 3) = dstrain_k.eigen();
884 mstress = this->beta * this->E_const * mdstrain;
885 stress_n = mstress.segment(0, 3);
886 stress_m = mstress.segment(3, 3);
887 }
888
ComputeDampingMatrix(ChMatrixNM<double,6,6> & R,const ChVector<> & dstrain_e,const ChVector<> & dstrain_k)889 void ChDampingCosseratRayleigh::ComputeDampingMatrix(ChMatrixNM<double, 6, 6>& R,
890 const ChVector<>& dstrain_e,
891 const ChVector<>& dstrain_k) {
892 R = this->beta * this->E_const;
893 }
894
UpdateStiffnessModel()895 void ChDampingCosseratRayleigh::UpdateStiffnessModel() {
896 // Precompute and store the stiffness matrix into E_const, assuming
897 // initial zero stress and zero strain, and use it as constant E from now on
898 // (for many stiffness models, this is constant anyway)
899 this->section_elasticity->ComputeStiffnessMatrix(this->E_const, VNULL, VNULL);
900 }
901
902 //-----------------------------------------------------------------------------
903
ComputeInertiaDampingMatrix(ChMatrixNM<double,6,6> & Ri,const ChVector<> & mW)904 void ChInertiaCosserat::ComputeInertiaDampingMatrix(
905 ChMatrixNM<double, 6, 6>& Ri, ///< 6x6 sectional inertial-damping (gyroscopic damping) matrix values here
906 const ChVector<>& mW ///< current angular velocity of section, in material frame
907 ) {
908 double Delta = 1e-8; // magic number, todo: parametrize or #define
909 Ri.setZero();
910
911 if (compute_inertia_damping_matrix == false)
912 return;
913
914 // Fi=Fia+Fiv, where Fia depends on acceleration only, so restrict to Fiv quadratic terms for numerical
915 // differentiation. Also we assume first three columns of Ri are null because Fiv does not depend on linear
916 // velocity. Quadratic terms (gyro, centrifugal) at current state:
917 ChVectorN<double, 6> Fi0;
918 ChVector<> mF, mT;
919 this->ComputeQuadraticTerms(mF, mT, mW);
920 Fi0.segment(0, 3) = mF.eigen();
921 Fi0.segment(3, 3) = mT.eigen();
922 // dw_x
923 ChVectorN<double, 6> Fi_dw;
924 this->ComputeQuadraticTerms(mF, mT, mW + ChVector<>(Delta, 0, 0));
925 Fi_dw.segment(0, 3) = mF.eigen();
926 Fi_dw.segment(3, 3) = mT.eigen();
927 Ri.block(0, 3, 6, 1) = (Fi_dw - Fi0) * (1.0 / Delta);
928 // dw_y
929 this->ComputeQuadraticTerms(mF, mT, mW + ChVector<>(0, Delta, 0));
930 Fi_dw.segment(0, 3) = mF.eigen();
931 Fi_dw.segment(3, 3) = mT.eigen();
932 Ri.block(0, 4, 6, 1) = (Fi_dw - Fi0) * (1.0 / Delta);
933 // dw_z
934 this->ComputeQuadraticTerms(mF, mT, mW + ChVector<>(0, 0, Delta));
935 Fi_dw.segment(0, 3) = mF.eigen();
936 Fi_dw.segment(3, 3) = mT.eigen();
937 Ri.block(0, 5, 6, 1) = (Fi_dw - Fi0) * (1.0 / Delta);
938 }
939
ComputeInertiaStiffnessMatrix(ChMatrixNM<double,6,6> & Ki,const ChVector<> & mWvel,const ChVector<> & mWacc,const ChVector<> & mXacc)940 void ChInertiaCosserat::ComputeInertiaStiffnessMatrix(
941 ChMatrixNM<double, 6, 6>& Ki, ///< 6x6 sectional inertial-stiffness matrix values here
942 const ChVector<>& mWvel, ///< current angular velocity of section, in material frame
943 const ChVector<>& mWacc, ///< current angular acceleration of section, in material frame
944 const ChVector<>& mXacc ///< current acceleration of section, in material frame (not absolute!)
945 ) {
946 double Delta = 1e-8; // magic number, todo: parametrize or #define
947 Ki.setZero();
948
949 if (compute_inertia_stiffness_matrix == false)
950 return;
951
952 // We assume first three columns of Ki are null because Fi does not depend on displacement.
953 // We compute Ki by numerical differentiation.
954
955 ChVector<> mF, mT;
956 this->ComputeInertialForce(mF, mT, mWvel, mWacc, mXacc);
957 ChVectorN<double, 6> Fi0;
958 Fi0.segment(0, 3) = mF.eigen();
959 Fi0.segment(3, 3) = mT.eigen();
960
961 ChVectorN<double, 6> Fi_dr;
962 ChVectorN<double, 6> drFi;
963
964 // dr_x
965 ChStarMatrix33<> rot_lx(ChVector<>(Delta, 0, 0));
966 rot_lx.diagonal().setOnes();
967 this->ComputeInertialForce(
968 mF, mT,
969 mWvel, // or rot_lx.transpose()*mWvel, if abs. ang.vel is constant during rot.increments
970 mWacc, // or rot_lx.transpose()*mWacc, if abs. ang.vel is constant during rot.increments
971 rot_lx.transpose() * mXacc);
972 Fi_dr.segment(0, 3) = mF.eigen();
973 Fi_dr.segment(3, 3) = mT.eigen();
974 drFi.segment(0, 3) = rot_lx * Fi0.segment(0, 3);
975 drFi.segment(3, 3) = Fi0.segment(3, 3);
976 Ki.block(0, 3, 6, 1) = (Fi_dr - Fi0) * (1.0 / Delta) + (drFi - Fi0) * (1.0 / Delta);
977
978 // dr_y
979 ChStarMatrix33<> rot_ly(ChVector<>(0, Delta, 0));
980 rot_ly.diagonal().setOnes();
981 this->ComputeInertialForce(mF, mT, mWvel, mWacc, rot_ly.transpose() * mXacc);
982 Fi_dr.segment(0, 3) = mF.eigen();
983 Fi_dr.segment(3, 3) = mT.eigen();
984 drFi.segment(0, 3) = rot_ly * Fi0.segment(0, 3);
985 drFi.segment(3, 3) = Fi0.segment(3, 3);
986 Ki.block(0, 4, 6, 1) = (Fi_dr - Fi0) * (1.0 / Delta) + (drFi - Fi0) * (1.0 / Delta);
987
988 // dr_z
989 ChStarMatrix33<> rot_lz(ChVector<>(0, 0, Delta));
990 rot_lz.diagonal().setOnes();
991 this->ComputeInertialForce(mF, mT, mWvel, mWacc, rot_lz.transpose() * mXacc);
992 Fi_dr.segment(0, 3) = mF.eigen();
993 Fi_dr.segment(3, 3) = mT.eigen();
994 drFi.segment(0, 3) = rot_lz * Fi0.segment(0, 3);
995 drFi.segment(3, 3) = Fi0.segment(3, 3);
996 Ki.block(0, 5, 6, 1) = (Fi_dr - Fi0) * (1.0 / Delta) + (drFi - Fi0) * (1.0 / Delta);
997 }
998
ComputeInertialForce(ChVector<> & mFi,ChVector<> & mTi,const ChVector<> & mWvel,const ChVector<> & mWacc,const ChVector<> & mXacc)999 void ChInertiaCosserat::ComputeInertialForce(
1000 ChVector<>& mFi, ///< total inertial force returned here
1001 ChVector<>& mTi, ///< total inertial torque returned here
1002 const ChVector<>& mWvel, ///< current angular velocity of section, in material frame
1003 const ChVector<>& mWacc, ///< current angular acceleration of section, in material frame
1004 const ChVector<>& mXacc ///< current acceleration of section, in material frame (not absolute!)
1005 ) {
1006 // Default implementation as Fi = [Mi]*{xacc,wacc}+{mF_quadratic,mT_quadratic}
1007 // but if possible implement it in children classes with ad-hoc faster formulas.
1008 ChMatrixNM<double, 6, 6> Mi;
1009 this->ComputeInertiaMatrix(Mi);
1010 ChVectorN<double, 6> xpp;
1011 xpp.segment(0, 3) = mXacc.eigen();
1012 xpp.segment(3, 3) = mWacc.eigen();
1013 ChVectorN<double, 6> Fipp = Mi * xpp; // [Mi]*{xacc,wacc}
1014 ChVector<> mF_quadratic;
1015 ChVector<> mT_quadratic;
1016 this->ComputeQuadraticTerms(mF_quadratic, mT_quadratic, mWvel); // {mF_quadratic,mT_quadratic}
1017 mFi = ChVector<>(Fipp.segment(0, 3)) + mF_quadratic;
1018 mTi = ChVector<>(Fipp.segment(3, 3)) + mT_quadratic;
1019 }
1020
1021 //-----------------------------------------------------------------------------
1022
ComputeInertiaMatrix(ChMatrixNM<double,6,6> & M)1023 void ChInertiaCosseratSimple::ComputeInertiaMatrix(ChMatrixNM<double, 6, 6>& M) {
1024 M.setZero();
1025 M(0, 0) = this->GetMassPerUnitLength();
1026 M(1, 1) = this->GetMassPerUnitLength();
1027 M(2, 2) = this->GetMassPerUnitLength();
1028 M(3, 3) = this->GetInertiaJxxPerUnitLength();
1029 M(4, 4) = this->GetInertiaJyyPerUnitLength();
1030 M(5, 5) = this->GetInertiaJzzPerUnitLength();
1031 }
1032
ComputeInertiaDampingMatrix(ChMatrixNM<double,6,6> & Ri,const ChVector<> & mW)1033 void ChInertiaCosseratSimple::ComputeInertiaDampingMatrix(
1034 ChMatrixNM<double, 6, 6>& Ri, ///< 6x6 sectional inertial-damping (gyroscopic damping) matrix values here
1035 const ChVector<>& mW ///< current angular velocity of section, in material frame
1036 ) {
1037 Ri.setZero();
1038 if (compute_inertia_damping_matrix == false)
1039 return;
1040 if (this->compute_Ri_Ki_by_num_diff)
1041 return ChInertiaCosserat::ComputeInertiaDampingMatrix(Ri, mW);
1042
1043 ChStarMatrix33<> wtilde(mW); // [w~]
1044 ChMatrix33<> mI(ChVector<>(this->GetInertiaJxxPerUnitLength(), this->GetInertiaJyyPerUnitLength(),
1045 this->GetInertiaJzzPerUnitLength())); // [I] here just a diagonal inertia
1046 Ri.block<3, 3>(3, 3) = wtilde * mI - ChStarMatrix33<>(mI * mW); // Ri = [0, 0; 0, [w~][I] - [([I]*w)~] ]
1047 }
1048
ComputeInertiaStiffnessMatrix(ChMatrixNM<double,6,6> & Ki,const ChVector<> & mWvel,const ChVector<> & mWacc,const ChVector<> & mXacc)1049 void ChInertiaCosseratSimple::ComputeInertiaStiffnessMatrix(
1050 ChMatrixNM<double, 6, 6>& Ki, ///< 6x6 sectional inertial-stiffness matrix values here
1051 const ChVector<>& mWvel, ///< current angular velocity of section, in material frame
1052 const ChVector<>& mWacc, ///< current angular acceleration of section, in material frame
1053 const ChVector<>& mXacc ///< current acceleration of section, in material frame
1054 ) {
1055 Ki.setZero();
1056 if (compute_inertia_stiffness_matrix == false)
1057 return;
1058 if (this->compute_Ri_Ki_by_num_diff)
1059 return ChInertiaCosserat::ComputeInertiaStiffnessMatrix(Ki, mWvel, mWacc, mXacc);
1060 // null [Ki^] (but only for the case where angular speeds and accelerations are assumed to corotate with local
1061 // frames.
1062 }
1063
ComputeQuadraticTerms(ChVector<> & mF,ChVector<> & mT,const ChVector<> & mW)1064 void ChInertiaCosseratSimple::ComputeQuadraticTerms(
1065 ChVector<>& mF, ///< centrifugal term (if any) returned here
1066 ChVector<>& mT, ///< gyroscopic term returned here
1067 const ChVector<>& mW ///< current angular velocity of section, in material frame
1068 ) {
1069 mF = VNULL;
1070 mT = Vcross(mW, ChVector<>(this->GetInertiaJxxPerUnitLength() * mW.x(), this->GetInertiaJyyPerUnitLength() * mW.y(),
1071 this->GetInertiaJzzPerUnitLength() * mW.z()));
1072 }
1073
SetAsRectangularSection(double width_y,double width_z,double density)1074 void ChInertiaCosseratSimple::SetAsRectangularSection(double width_y, double width_z, double density) {
1075 this->A = width_y * width_z;
1076 this->Izz = (1.0 / 12.0) * width_z * pow(width_y, 3);
1077 this->Iyy = (1.0 / 12.0) * width_y * pow(width_z, 3);
1078 this->rho = density;
1079 }
1080
SetAsCircularSection(double diameter,double density)1081 void ChInertiaCosseratSimple::SetAsCircularSection(double diameter, double density) {
1082 this->A = CH_C_PI * pow((0.5 * diameter), 2);
1083 this->Izz = (CH_C_PI / 4.0) * pow((0.5 * diameter), 4);
1084 this->Iyy = Izz;
1085 this->rho = density;
1086 }
1087
1088 // -----------------------------------------------------------------------------
1089
ComputeInertiaMatrix(ChMatrixNM<double,6,6> & M)1090 void ChInertiaCosseratAdvanced::ComputeInertiaMatrix(ChMatrixNM<double, 6, 6>& M) {
1091 M.setZero();
1092 M(0, 0) = this->mu;
1093 M(1, 1) = this->mu;
1094 M(2, 2) = this->mu;
1095
1096 M(3, 1) = -this->mu * this->cm_z;
1097 M(3, 2) = this->mu * this->cm_y;
1098 M(4, 0) = this->mu * this->cm_z;
1099 M(5, 0) = -this->mu * this->cm_y;
1100
1101 M(1, 3) = -this->mu * this->cm_z;
1102 M(2, 3) = this->mu * this->cm_y;
1103 M(0, 4) = this->mu * this->cm_z;
1104 M(0, 5) = -this->mu * this->cm_y;
1105
1106 M(3, 3) = this->Jyy + this->Jzz;
1107 M(4, 4) = this->Jyy;
1108 M(5, 5) = this->Jzz;
1109 M(4, 5) = -this->Jyz;
1110 M(5, 4) = -this->Jyz;
1111 }
1112
ComputeInertiaDampingMatrix(ChMatrixNM<double,6,6> & Ri,const ChVector<> & mW)1113 void ChInertiaCosseratAdvanced::ComputeInertiaDampingMatrix(
1114 ChMatrixNM<double, 6, 6>& Ri, ///< 6x6 sectional inertial-damping (gyroscopic damping) matrix values here
1115 const ChVector<>& mW ///< current angular velocity of section, in material frame
1116 ) {
1117 Ri.setZero();
1118 if (compute_inertia_damping_matrix == false)
1119 return;
1120 if (this->compute_Ri_Ki_by_num_diff)
1121 return ChInertiaCosserat::ComputeInertiaDampingMatrix(Ri, mW);
1122
1123 ChStarMatrix33<> wtilde(mW); // [w~]
1124 ChVector<> mC(0, this->cm_y, this->cm_z);
1125 ChStarMatrix33<> ctilde(mC); // [c~]
1126 ChMatrix33<> mI;
1127 mI << this->Jyy + this->Jzz, 0, 0, 0, this->Jyy, -this->Jyz, 0, -this->Jyz, this->Jzz;
1128 // Ri = [0, m*[w~][c~]' + m*[([w~]*c)~]' ; 0 , [w~][I] - [([I]*w)~] ]
1129 Ri.block<3, 3>(0, 3) = this->mu * (wtilde * ctilde.transpose() + (ChStarMatrix33<>(wtilde * mC)).transpose());
1130 Ri.block<3, 3>(3, 3) = wtilde * mI - ChStarMatrix33<>(mI * mW);
1131 }
1132
ComputeInertiaStiffnessMatrix(ChMatrixNM<double,6,6> & Ki,const ChVector<> & mWvel,const ChVector<> & mWacc,const ChVector<> & mXacc)1133 void ChInertiaCosseratAdvanced::ComputeInertiaStiffnessMatrix(
1134 ChMatrixNM<double, 6, 6>& Ki, ///< 6x6 sectional inertial-stiffness matrix values here
1135 const ChVector<>& mWvel, ///< current angular velocity of section, in material frame
1136 const ChVector<>& mWacc, ///< current angular acceleration of section, in material frame
1137 const ChVector<>& mXacc ///< current acceleration of section, in material frame
1138 ) {
1139 Ki.setZero();
1140 if (compute_inertia_stiffness_matrix == false)
1141 return;
1142 if (this->compute_Ri_Ki_by_num_diff)
1143 return ChInertiaCosserat::ComputeInertiaStiffnessMatrix(Ki, mWvel, mWacc, mXacc);
1144
1145 ChStarMatrix33<> wtilde(mWvel); // [w~]
1146 ChStarMatrix33<> atilde(mWacc); // [a~]
1147 ChVector<> mC(0, this->cm_y, this->cm_z);
1148 ChStarMatrix33<> ctilde(mC); // [c~]
1149 ChMatrix33<> mI;
1150 mI << this->Jyy + this->Jzz, 0, 0, 0, this->Jyy, -this->Jyz, 0, -this->Jyz, this->Jzz;
1151 // case A: where absolute ang.vel and ang.acc are constant if the frame rotates (as in Bauchau)
1152 // and the local ang.vel and ang.acc will counterrotate:
1153 // for mixed absolute (translation) and local (rotation) bases one has:
1154 // Ki_al = [0, 0; m*([a~]+[w~][w~])[c~]', m*[c~][xpp~] + [I][a~] + [w~]([I][w~] - [([I]*w)~]) +[([w~][I]*w)~] ]
1155 /*
1156 Ki.block<3, 3>(0, 3) = this->mu * (atilde + wtilde* wtilde) * ctilde.transpose();
1157 Ki.block<3, 3>(3, 3) = this->mu * ctilde * ChStarMatrix33<>(mXacc)
1158 + (mI * atilde )
1159 + wtilde * (mI * wtilde - ChStarMatrix33<>(mI * mWvel))
1160 + ChStarMatrix33<>(wtilde*(mI*mWvel));
1161 */
1162 // case B: where local ang.vel and ang.acc are constant if the frame rotates (as in Chrono)
1163 // and the absolute ang.vel and ang.acc will rotate:
1164 // for mixed absolute (translation) and local (rotation) bases one has:
1165 // Ki_al = [0, 0; -m*[([a~]c)~] -m*[([w~][w~]c)~] , m*[c~][xpp~] ]
1166 Ki.block<3, 3>(0, 3) =
1167 -this->mu * ChStarMatrix33<>(atilde * mC) - this->mu * ChStarMatrix33<>(wtilde * (wtilde * mC));
1168 Ki.block<3, 3>(3, 3) = this->mu * ctilde * ChStarMatrix33<>(mXacc);
1169 }
1170
ComputeQuadraticTerms(ChVector<> & mF,ChVector<> & mT,const ChVector<> & mW)1171 void ChInertiaCosseratAdvanced::ComputeQuadraticTerms(
1172 ChVector<>& mF, ///< centrifugal term (if any) returned here
1173 ChVector<>& mT, ///< gyroscopic term returned here
1174 const ChVector<>& mW ///< current angular velocity of section, in material frame
1175 ) {
1176 // F_centrifugal = density_per_unit_length w X w X c
1177 mF = this->mu * Vcross(mW, Vcross(mW, ChVector<>(0, cm_y, cm_z)));
1178
1179 // unroll the product [J] * w in the expression w X [J] * w as 4 values of [J] are zero anyway
1180 mT = Vcross(mW, ChVector<>(this->GetInertiaJxxPerUnitLength() * mW.x(), this->Jyy * mW.y() - this->Jyz * mW.z(),
1181 this->Jzz * mW.z() - this->Jyz * mW.y()));
1182 }
1183
SetMainInertiasInMassReference(double Jmyy,double Jmzz,double phi)1184 void ChInertiaCosseratAdvanced::SetMainInertiasInMassReference(double Jmyy, double Jmzz, double phi) {
1185 double cc = pow(cos(-phi), 2);
1186 double ss = pow(sin(-phi), 2);
1187 double cs = cos(-phi) * sin(-phi);
1188 // generic 2x2 tensor rotation
1189 double Tyy_rot = cc * Jmyy + ss * Jmzz; // + 2 * Jmyz * cs;
1190 double Tzz_rot = ss * Jmyy + cc * Jmzz; // - 2 * Jmyz * cs;
1191 double Tyz_rot = (Jmzz - Jmyy) * cs; // +Jmyz * (cc - ss);
1192 // add inertia transport
1193 this->Jyy = Tyy_rot + this->mu * this->cm_z * this->cm_z;
1194 this->Jzz = Tzz_rot + this->mu * this->cm_y * this->cm_y;
1195 this->Jyz = -(Tyz_rot - this->mu * this->cm_z * this->cm_y); // note minus, per definition of Jyz
1196 }
1197
GetMainInertiasInMassReference(double & Jmyy,double & Jmzz,double & phi)1198 void ChInertiaCosseratAdvanced::GetMainInertiasInMassReference(double& Jmyy, double& Jmzz, double& phi) {
1199 // remove inertia transport
1200 double Tyy_rot = this->Jyy - this->mu * this->cm_z * this->cm_z;
1201 double Tzz_rot = this->Jzz - this->mu * this->cm_y * this->cm_y;
1202 double Tyz_rot = -this->Jyz + this->mu * this->cm_z * this->cm_y;
1203 // tensor de-rotation up to principal axes
1204 double argum = pow((Tyy_rot - Tzz_rot) * 0.5, 2) + pow(Tyz_rot, 2);
1205 if (argum <= 0) {
1206 phi = 0;
1207 Jmyy = 0.5 * (Tzz_rot + Tyy_rot);
1208 Jmzz = 0.5 * (Tzz_rot + Tyy_rot);
1209 return;
1210 }
1211 double discr = sqrt(pow((Tyy_rot - Tzz_rot) * 0.5, 2) + pow(Tyz_rot, 2));
1212 phi = -0.5 * atan2(Tyz_rot / discr, (Tzz_rot - Tyy_rot) / (2. * discr));
1213 Jmyy = 0.5 * (Tzz_rot + Tyy_rot) - discr;
1214 Jmzz = 0.5 * (Tzz_rot + Tyy_rot) + discr;
1215 }
1216
SetInertiasPerUnitLength(double Jyy_moment,double Jzz_moment,double Jyz_moment)1217 void ChInertiaCosseratAdvanced::SetInertiasPerUnitLength(double Jyy_moment, double Jzz_moment, double Jyz_moment) {
1218 this->Jyy = Jyy_moment;
1219 this->Jzz = Jzz_moment;
1220 this->Jyz = Jyz_moment;
1221 }
1222
1223 // -----------------------------------------------------------------------------
1224
ChBeamSectionCosserat(std::shared_ptr<ChInertiaCosserat> minertia,std::shared_ptr<ChElasticityCosserat> melasticity,std::shared_ptr<ChPlasticityCosserat> mplasticity,std::shared_ptr<ChDampingCosserat> mdamping)1225 ChBeamSectionCosserat::ChBeamSectionCosserat(std::shared_ptr<ChInertiaCosserat> minertia,
1226 std::shared_ptr<ChElasticityCosserat> melasticity,
1227 std::shared_ptr<ChPlasticityCosserat> mplasticity,
1228 std::shared_ptr<ChDampingCosserat> mdamping) {
1229 this->SetInertia(minertia);
1230
1231 this->SetElasticity(melasticity);
1232
1233 if (mplasticity)
1234 this->SetPlasticity(mplasticity);
1235
1236 if (mdamping)
1237 this->SetDamping(mdamping);
1238 }
1239
ComputeStress(ChVector<> & stress_n,ChVector<> & stress_m,const ChVector<> & strain_e,const ChVector<> & strain_k,ChBeamMaterialInternalData * mdata_new,const ChBeamMaterialInternalData * mdata)1240 void ChBeamSectionCosserat::ComputeStress(ChVector<>& stress_n,
1241 ChVector<>& stress_m,
1242 const ChVector<>& strain_e,
1243 const ChVector<>& strain_k,
1244 ChBeamMaterialInternalData* mdata_new,
1245 const ChBeamMaterialInternalData* mdata) {
1246 if (!plasticity || !mdata || !mdata_new)
1247 this->elasticity->ComputeStress(stress_n, stress_m, strain_e, strain_k);
1248 else {
1249 ChVector<> e_strain_e; // probably not needed as computable later as e_strain_e = strain_e - data.p_strain_e
1250 ChVector<> e_strain_k; // probably not needed " "
1251 this->plasticity->ComputeStressWithReturnMapping(stress_n, stress_m, e_strain_e, e_strain_k, *mdata_new,
1252 strain_e, strain_k, *mdata);
1253 }
1254 }
1255
ComputeStiffnessMatrix(ChMatrixNM<double,6,6> & K,const ChVector<> & strain_e,const ChVector<> & strain_k,const ChBeamMaterialInternalData * mdata)1256 void ChBeamSectionCosserat::ComputeStiffnessMatrix(ChMatrixNM<double, 6, 6>& K,
1257 const ChVector<>& strain_e,
1258 const ChVector<>& strain_k,
1259 const ChBeamMaterialInternalData* mdata) {
1260 if (!plasticity || !mdata)
1261 this->elasticity->ComputeStiffnessMatrix(K, strain_e, strain_k);
1262 else {
1263 this->plasticity->ComputeStiffnessMatrixElastoplastic(K, strain_e, strain_k, *mdata);
1264 }
1265 }
1266
SetElasticity(std::shared_ptr<ChElasticityCosserat> melasticity)1267 void ChBeamSectionCosserat::SetElasticity(std::shared_ptr<ChElasticityCosserat> melasticity) {
1268 elasticity = melasticity;
1269 elasticity->section = this;
1270 }
1271
SetPlasticity(std::shared_ptr<ChPlasticityCosserat> mplasticity)1272 void ChBeamSectionCosserat::SetPlasticity(std::shared_ptr<ChPlasticityCosserat> mplasticity) {
1273 plasticity = mplasticity;
1274 plasticity->section = this;
1275 }
1276
SetDamping(std::shared_ptr<ChDampingCosserat> mdamping)1277 void ChBeamSectionCosserat::SetDamping(std::shared_ptr<ChDampingCosserat> mdamping) {
1278 damping = mdamping;
1279 damping->section = this;
1280 }
1281
SetInertia(std::shared_ptr<ChInertiaCosserat> minertia)1282 void ChBeamSectionCosserat::SetInertia(std::shared_ptr<ChInertiaCosserat> minertia) {
1283 inertia = minertia;
1284 inertia->section = this;
1285 }
1286
1287 // -----------------------------------------------------------------------------
1288
ChBeamSectionCosseratEasyRectangular(double width_y,double width_z,double E,double G,double density)1289 ChBeamSectionCosseratEasyRectangular::ChBeamSectionCosseratEasyRectangular(
1290 double width_y, // width of section in y direction
1291 double width_z, // width of section in z direction
1292 double E, // Young modulus
1293 double G, // shear modulus
1294 double density // volumetric density (ex. in SI units: [kg/m])
1295 ) {
1296 auto melasticity = chrono_types::make_shared<ChElasticityCosseratSimple>();
1297 melasticity->SetYoungModulus(E);
1298 melasticity->SetGshearModulus(G);
1299 melasticity->SetAsRectangularSection(width_y, width_z);
1300 this->SetElasticity(melasticity);
1301
1302 auto minertia = chrono_types::make_shared<ChInertiaCosseratSimple>();
1303 minertia->SetAsRectangularSection(width_y, width_z, density);
1304 this->SetInertia(minertia);
1305
1306 auto mdrawshape = chrono_types::make_shared<ChBeamSectionShapeRectangular>(width_y, width_z);
1307 this->SetDrawShape(mdrawshape);
1308 }
1309
ChBeamSectionCosseratEasyCircular(double diameter,double E,double G,double density)1310 ChBeamSectionCosseratEasyCircular::ChBeamSectionCosseratEasyCircular(
1311 double diameter, // diameter
1312 double E, // Young modulus
1313 double G, // shear modulus
1314 double density // volumetric density (ex. in SI units: [kg/m])
1315 ) {
1316 auto melasticity = chrono_types::make_shared<ChElasticityCosseratSimple>();
1317 melasticity->SetYoungModulus(E);
1318 melasticity->SetGshearModulus(G);
1319 melasticity->SetAsCircularSection(diameter);
1320 this->SetElasticity(melasticity);
1321
1322 auto minertia = chrono_types::make_shared<ChInertiaCosseratSimple>();
1323 minertia->SetAsCircularSection(diameter, density);
1324 this->SetInertia(minertia);
1325
1326 auto mdrawshape = chrono_types::make_shared<ChBeamSectionShapeCircular>(diameter / 2, 10);
1327 this->SetDrawShape(mdrawshape);
1328 }
1329
1330 // ------------------------------------------------------------------------------
1331
1332 } // end namespace fea
1333 } // end namespace chrono
1334