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