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: Andrea Favali, Alessandro Tasora, Radu Serban
13 // =============================================================================
14
15 #include "chrono/fea/ChElementTetraCorot_4.h"
16
17 namespace chrono {
18 namespace fea {
19
ChElementTetraCorot_4()20 ChElementTetraCorot_4::ChElementTetraCorot_4() : Volume(0) {
21 nodes.resize(4);
22 this->MatrB.setZero(6, 12);
23 this->StiffnessMatrix.setZero(12, 12);
24 }
25
~ChElementTetraCorot_4()26 ChElementTetraCorot_4::~ChElementTetraCorot_4() {}
27
SetNodes(std::shared_ptr<ChNodeFEAxyz> nodeA,std::shared_ptr<ChNodeFEAxyz> nodeB,std::shared_ptr<ChNodeFEAxyz> nodeC,std::shared_ptr<ChNodeFEAxyz> nodeD)28 void ChElementTetraCorot_4::SetNodes(std::shared_ptr<ChNodeFEAxyz> nodeA,
29 std::shared_ptr<ChNodeFEAxyz> nodeB,
30 std::shared_ptr<ChNodeFEAxyz> nodeC,
31 std::shared_ptr<ChNodeFEAxyz> nodeD) {
32 nodes[0] = nodeA;
33 nodes[1] = nodeB;
34 nodes[2] = nodeC;
35 nodes[3] = nodeD;
36 std::vector<ChVariables*> mvars;
37 mvars.push_back(&nodes[0]->Variables());
38 mvars.push_back(&nodes[1]->Variables());
39 mvars.push_back(&nodes[2]->Variables());
40 mvars.push_back(&nodes[3]->Variables());
41 Kmatr.SetVariables(mvars);
42 }
43
Update()44 void ChElementTetraCorot_4::Update() {
45 // parent class update:
46 ChElementGeneric::Update();
47 // always keep updated the rotation matrix A:
48 this->UpdateRotation();
49 }
50
ShapeFunctions(ShapeVector & N,double r,double s,double t)51 void ChElementTetraCorot_4::ShapeFunctions(ShapeVector& N, double r, double s, double t) {
52 N(0) = 1.0 - r - s - t;
53 N(1) = r;
54 N(2) = s;
55 N(3) = t;
56 }
57
GetStateBlock(ChVectorDynamic<> & mD)58 void ChElementTetraCorot_4::GetStateBlock(ChVectorDynamic<>& mD) {
59 mD.setZero(this->GetNdofs());
60 mD.segment(0, 3) = (A.transpose() * nodes[0]->pos - nodes[0]->GetX0()).eigen();
61 mD.segment(3, 3) = (A.transpose() * nodes[1]->pos - nodes[1]->GetX0()).eigen();
62 mD.segment(6, 3) = (A.transpose() * nodes[2]->pos - nodes[2]->GetX0()).eigen();
63 mD.segment(9, 3) = (A.transpose() * nodes[3]->pos - nodes[3]->GetX0()).eigen();
64 }
65
ComputeVolume()66 double ChElementTetraCorot_4::ComputeVolume() {
67 ChVector<> B1, C1, D1;
68 B1.Sub(nodes[1]->pos, nodes[0]->pos);
69 C1.Sub(nodes[2]->pos, nodes[0]->pos);
70 D1.Sub(nodes[3]->pos, nodes[0]->pos);
71 ChMatrixDynamic<> M(3, 3);
72 M.col(0) = B1.eigen();
73 M.col(1) = C1.eigen();
74 M.col(2) = D1.eigen();
75 M.transposeInPlace();
76 Volume = std::abs(M.determinant() / 6);
77 return Volume;
78 }
79
ComputeStiffnessMatrix()80 void ChElementTetraCorot_4::ComputeStiffnessMatrix() {
81 // M = [ X0_0 X0_1 X0_2 X0_3 ] ^-1
82 // [ 1 1 1 1 ]
83 ChMatrixNM<double, 4, 4> tmp;
84 tmp.block(0, 0, 3, 1) = nodes[0]->GetX0().eigen();
85 tmp.block(0, 1, 3, 1) = nodes[1]->GetX0().eigen();
86 tmp.block(0, 2, 3, 1) = nodes[2]->GetX0().eigen();
87 tmp.block(0, 3, 3, 1) = nodes[3]->GetX0().eigen();
88 tmp.row(3).setConstant(1.0);
89 mM = tmp.inverse();
90
91 ////MatrB.Reset(6, 12);
92 MatrB(0) = mM(0);
93 MatrB(3) = mM(4);
94 MatrB(6) = mM(8);
95 MatrB(9) = mM(12);
96 MatrB(13) = mM(1);
97 MatrB(16) = mM(5);
98 MatrB(19) = mM(9);
99 MatrB(22) = mM(13);
100 MatrB(26) = mM(2);
101 MatrB(29) = mM(6);
102 MatrB(32) = mM(10);
103 MatrB(35) = mM(14);
104 MatrB(36) = mM(1);
105 MatrB(37) = mM(0);
106 MatrB(39) = mM(5);
107 MatrB(40) = mM(4);
108 MatrB(42) = mM(9);
109 MatrB(43) = mM(8);
110 MatrB(45) = mM(13);
111 MatrB(46) = mM(12);
112 MatrB(49) = mM(2);
113 MatrB(50) = mM(1);
114 MatrB(52) = mM(6);
115 MatrB(53) = mM(5);
116 MatrB(55) = mM(10);
117 MatrB(56) = mM(9);
118 MatrB(58) = mM(14);
119 MatrB(59) = mM(13);
120 MatrB(60) = mM(2);
121 MatrB(62) = mM(0);
122 MatrB(63) = mM(6);
123 MatrB(65) = mM(4);
124 MatrB(66) = mM(10);
125 MatrB(68) = mM(8);
126 MatrB(69) = mM(14);
127 MatrB(71) = mM(12);
128
129 StiffnessMatrix = Volume * MatrB.transpose() * Material->Get_StressStrainMatrix() * MatrB;
130
131 // ***TEST*** SYMMETRIZE TO AVOID ROUNDOFF ASYMMETRY
132 for (int row = 0; row < StiffnessMatrix.rows() - 1; ++row)
133 for (int col = row + 1; col < StiffnessMatrix.cols(); ++col)
134 StiffnessMatrix(row, col) = StiffnessMatrix(col, row);
135
136 double max_err = 0;
137 int err_r = -1;
138 int err_c = -1;
139 for (int row = 0; row < StiffnessMatrix.rows(); ++row)
140 for (int col = 0; col < StiffnessMatrix.cols(); ++col) {
141 double diff = fabs(StiffnessMatrix(row, col) - StiffnessMatrix(col, row));
142 if (diff > max_err) {
143 max_err = diff;
144 err_r = row;
145 err_c = col;
146 }
147 }
148 if (max_err > 1e-10)
149 GetLog() << "NONSYMMETRIC local stiffness matrix! err " << max_err << " at " << err_r << "," << err_c << "\n";
150 }
151
SetupInitial(ChSystem * system)152 void ChElementTetraCorot_4::SetupInitial(ChSystem* system) {
153 ComputeVolume();
154 ComputeStiffnessMatrix();
155 }
156
UpdateRotation()157 void ChElementTetraCorot_4::UpdateRotation() {
158 // P = [ p_0 p_1 p_2 p_3 ]
159 // [ 1 1 1 1 ]
160 ChMatrixNM<double, 4, 4> P;
161 P.block(0, 0, 3, 1) = nodes[0]->pos.eigen();
162 P.block(0, 1, 3, 1) = nodes[1]->pos.eigen();
163 P.block(0, 2, 3, 1) = nodes[2]->pos.eigen();
164 P.block(0, 3, 3, 1) = nodes[3]->pos.eigen();
165 P.row(3).setConstant(1.0);
166
167 ChMatrix33<double> F;
168 // F=P*mM (only upper-left 3x3 block!)
169 double sum;
170 for (int colres = 0; colres < 3; ++colres)
171 for (int row = 0; row < 3; ++row) {
172 sum = 0;
173 for (int col = 0; col < 4; ++col)
174 sum += (P(row, col)) * (mM(col, colres));
175 F(row, colres) = sum;
176 }
177 ChMatrix33<> S;
178 double det = ChPolarDecomposition<>::Compute(F, this->A, S, 1E-6);
179 if (det < 0)
180 this->A *= -1.0;
181
182 // GetLog() << "FEM rotation: \n" << A << "\n" ;
183 }
184
ComputeKRMmatricesGlobal(ChMatrixRef H,double Kfactor,double Rfactor,double Mfactor)185 void ChElementTetraCorot_4::ComputeKRMmatricesGlobal(ChMatrixRef H, double Kfactor, double Rfactor, double Mfactor) {
186 assert((H.rows() == 12) && (H.cols() == 12));
187
188 // warp the local stiffness matrix K in order to obtain global
189 // tangent stiffness CKCt:
190 ChMatrixDynamic<> CK(12, 12);
191 ChMatrixDynamic<> CKCt(12, 12); // the global, corotated, K matrix
192 ChMatrixCorotation::ComputeCK(StiffnessMatrix, this->A, 4, CK);
193 ChMatrixCorotation::ComputeKCt(CK, this->A, 4, CKCt);
194
195 // ***TEST*** SYMMETRIZE TO AVOID ROUNDOFF ASYMMETRY
196 for (int row = 0; row < CKCt.rows() - 1; ++row)
197 for (int col = row + 1; col < CKCt.cols(); ++col)
198 CKCt(row, col) = CKCt(col, row);
199
200 //***DEBUG***
201 double max_err = 0;
202 int err_r = -1;
203 int err_c = -1;
204 for (int row = 0; row < StiffnessMatrix.rows(); ++row)
205 for (int col = 0; col < StiffnessMatrix.cols(); ++col) {
206 double diff = fabs(StiffnessMatrix(row, col) - StiffnessMatrix(col, row));
207 if (diff > max_err) {
208 max_err = diff;
209 err_r = row;
210 err_c = col;
211 }
212 }
213 if (max_err > 1e-10)
214 GetLog() << "NONSYMMETRIC local stiffness matrix! err " << max_err << " at " << err_r << "," << err_c << "\n";
215 max_err = 0;
216 err_r = -1;
217 err_c = -1;
218 double maxval = 0;
219 for (int row = 0; row < CKCt.rows(); ++row)
220 for (int col = 0; col < CKCt.cols(); ++col) {
221 double diff = fabs(CKCt(row, col) - CKCt(col, row));
222 if (diff > max_err) {
223 max_err = diff;
224 err_r = row;
225 err_c = col;
226 }
227 if (CKCt(row, col) > maxval)
228 maxval = CKCt(row, col);
229 }
230 if (max_err > 1e-10)
231 GetLog() << "NONSYMMETRIC corotated matrix! err " << max_err << " at " << err_r << "," << err_c
232 << ", maxval=" << maxval << "\n";
233
234 // For K stiffness matrix and R damping matrix:
235 double mkfactor = Kfactor + Rfactor * this->GetMaterial()->Get_RayleighDampingK();
236 H = mkfactor * CKCt;
237
238 // For M mass matrix:
239 if (Mfactor) {
240 double lumped_node_mass = (this->GetVolume() * this->Material->Get_density()) / 4.0;
241 for (int id = 0; id < 12; id++) {
242 double amfactor = Mfactor + Rfactor * this->GetMaterial()->Get_RayleighDampingM();
243 H(id, id) += amfactor * lumped_node_mass;
244 }
245 }
246 //***TO DO*** better per-node lumping, or 12x12 consistent mass matrix.
247 }
248
ComputeInternalForces(ChVectorDynamic<> & Fi)249 void ChElementTetraCorot_4::ComputeInternalForces(ChVectorDynamic<>& Fi) {
250 assert(Fi.size() == 12);
251
252 // set up vector of nodal displacements (in local element system) u_l = R*p - p0
253 ChVectorDynamic<> displ(12);
254 this->GetStateBlock(displ); // nodal displacements, local
255
256 // [local Internal Forces] = [Klocal] * displ + [Rlocal] * displ_dt
257 ChVectorDynamic<> FiK_local = StiffnessMatrix * displ;
258
259 displ.segment(0, 3) = (A.transpose() * nodes[0]->pos_dt).eigen(); // nodal speeds, local
260 displ.segment(3, 3) = (A.transpose() * nodes[1]->pos_dt).eigen();
261 displ.segment(6, 3) = (A.transpose() * nodes[2]->pos_dt).eigen();
262 displ.segment(9, 3) = (A.transpose() * nodes[3]->pos_dt).eigen();
263 ChMatrixDynamic<> FiR_local = Material->Get_RayleighDampingK() * StiffnessMatrix * displ;
264
265 double lumped_node_mass = (this->GetVolume() * this->Material->Get_density()) / 4.0;
266 displ *= lumped_node_mass * this->Material->Get_RayleighDampingM();
267 FiR_local += displ;
268
269 //***TO DO*** better per-node lumping, or 12x12 consistent mass matrix.
270
271 FiK_local += FiR_local;
272 FiK_local *= -1.0;
273
274 // Fi = C * Fi_local with C block-diagonal rotations A
275 ChMatrixCorotation::ComputeCK(FiK_local, this->A, 4, Fi);
276 }
277
GetStrain()278 ChStrainTensor<> ChElementTetraCorot_4::GetStrain() {
279 // set up vector of nodal displacements (in local element system) u_l = R*p - p0
280 ChVectorDynamic<> displ(12);
281 this->GetStateBlock(displ); // nodal displacements, local
282
283 ChStrainTensor<> mstrain = MatrB * displ;
284 return mstrain;
285 }
286
GetStress()287 ChStressTensor<> ChElementTetraCorot_4::GetStress() {
288 ChStressTensor<> mstress = this->Material->Get_StressStrainMatrix() * this->GetStrain();
289 return mstress;
290 }
291
ComputeNodalMass()292 void ChElementTetraCorot_4::ComputeNodalMass() {
293 nodes[0]->m_TotalMass += this->GetVolume() * this->Material->Get_density() / 4.0;
294 nodes[1]->m_TotalMass += this->GetVolume() * this->Material->Get_density() / 4.0;
295 nodes[2]->m_TotalMass += this->GetVolume() * this->Material->Get_density() / 4.0;
296 nodes[3]->m_TotalMass += this->GetVolume() * this->Material->Get_density() / 4.0;
297 }
298
LoadableGetStateBlock_x(int block_offset,ChState & mD)299 void ChElementTetraCorot_4::LoadableGetStateBlock_x(int block_offset, ChState& mD) {
300 mD.segment(block_offset + 0, 3) = nodes[0]->GetPos().eigen();
301 mD.segment(block_offset + 3, 3) = nodes[1]->GetPos().eigen();
302 mD.segment(block_offset + 6, 3) = nodes[2]->GetPos().eigen();
303 mD.segment(block_offset + 9, 3) = nodes[3]->GetPos().eigen();
304 }
305
LoadableGetStateBlock_w(int block_offset,ChStateDelta & mD)306 void ChElementTetraCorot_4::LoadableGetStateBlock_w(int block_offset, ChStateDelta& mD) {
307 mD.segment(block_offset + 0, 3) = nodes[0]->GetPos_dt().eigen();
308 mD.segment(block_offset + 3, 3) = nodes[1]->GetPos_dt().eigen();
309 mD.segment(block_offset + 6, 3) = nodes[2]->GetPos_dt().eigen();
310 mD.segment(block_offset + 9, 3) = nodes[3]->GetPos_dt().eigen();
311 }
312
LoadableStateIncrement(const unsigned int off_x,ChState & x_new,const ChState & x,const unsigned int off_v,const ChStateDelta & Dv)313 void ChElementTetraCorot_4::LoadableStateIncrement(const unsigned int off_x,
314 ChState& x_new,
315 const ChState& x,
316 const unsigned int off_v,
317 const ChStateDelta& Dv) {
318 for (int i = 0; i < 4; ++i) {
319 nodes[i]->NodeIntStateIncrement(off_x + i * 3, x_new, x, off_v + i * 3, Dv);
320 }
321 }
322
LoadableGetVariables(std::vector<ChVariables * > & mvars)323 void ChElementTetraCorot_4::LoadableGetVariables(std::vector<ChVariables*>& mvars) {
324 for (int i = 0; i < nodes.size(); ++i)
325 mvars.push_back(&this->nodes[i]->Variables());
326 }
327
ComputeNF(const double U,const double V,const double W,ChVectorDynamic<> & Qi,double & detJ,const ChVectorDynamic<> & F,ChVectorDynamic<> * state_x,ChVectorDynamic<> * state_w)328 void ChElementTetraCorot_4::ComputeNF(const double U,
329 const double V,
330 const double W,
331 ChVectorDynamic<>& Qi,
332 double& detJ,
333 const ChVectorDynamic<>& F,
334 ChVectorDynamic<>* state_x,
335 ChVectorDynamic<>* state_w) {
336 // evaluate shape functions (in compressed vector), btw. not dependent on state
337 // note: U,V,W in 0..1 range, thanks to IsTetrahedronIntegrationNeeded() {return true;}
338 ShapeVector N;
339 this->ShapeFunctions(N, U, V, W);
340
341 detJ = 6 * this->GetVolume();
342
343 Qi(0) = N(0) * F(0);
344 Qi(1) = N(0) * F(1);
345 Qi(2) = N(0) * F(2);
346 Qi(3) = N(1) * F(0);
347 Qi(4) = N(1) * F(1);
348 Qi(5) = N(1) * F(2);
349 Qi(6) = N(2) * F(0);
350 Qi(7) = N(2) * F(1);
351 Qi(8) = N(2) * F(2);
352 Qi(9) = N(3) * F(0);
353 Qi(10) = N(3) * F(1);
354 Qi(11) = N(3) * F(2);
355 }
356
357 // -----------------------------------------------------------------------------
358
ChElementTetraCorot_4_P()359 ChElementTetraCorot_4_P::ChElementTetraCorot_4_P() : Volume(0) {
360 nodes.resize(4);
361 this->MatrB.setZero(3, 4);
362 this->StiffnessMatrix.setZero(4, 4);
363 }
364
SetNodes(std::shared_ptr<ChNodeFEAxyzP> nodeA,std::shared_ptr<ChNodeFEAxyzP> nodeB,std::shared_ptr<ChNodeFEAxyzP> nodeC,std::shared_ptr<ChNodeFEAxyzP> nodeD)365 void ChElementTetraCorot_4_P::SetNodes(std::shared_ptr<ChNodeFEAxyzP> nodeA,
366 std::shared_ptr<ChNodeFEAxyzP> nodeB,
367 std::shared_ptr<ChNodeFEAxyzP> nodeC,
368 std::shared_ptr<ChNodeFEAxyzP> nodeD) {
369 nodes[0] = nodeA;
370 nodes[1] = nodeB;
371 nodes[2] = nodeC;
372 nodes[3] = nodeD;
373 std::vector<ChVariables*> mvars;
374 mvars.push_back(&nodes[0]->Variables());
375 mvars.push_back(&nodes[1]->Variables());
376 mvars.push_back(&nodes[2]->Variables());
377 mvars.push_back(&nodes[3]->Variables());
378 Kmatr.SetVariables(mvars);
379 }
380
Update()381 void ChElementTetraCorot_4_P::Update() {
382 // parent class update:
383 ChElementGeneric::Update();
384 // always keep updated the rotation matrix A:
385 this->UpdateRotation();
386 }
387
ShapeFunctions(ShapeVector & N,double z0,double z1,double z2)388 void ChElementTetraCorot_4_P::ShapeFunctions(ShapeVector& N, double z0, double z1, double z2) {
389 N(0) = z0;
390 N(1) = z1;
391 N(2) = z2;
392 N(3) = 1.0 - z0 - z1 - z2;
393 }
394
GetStateBlock(ChVectorDynamic<> & mD)395 void ChElementTetraCorot_4_P::GetStateBlock(ChVectorDynamic<>& mD) {
396 mD.setZero(this->GetNdofs());
397 mD(0) = nodes[0]->GetP();
398 mD(1) = nodes[1]->GetP();
399 mD(2) = nodes[2]->GetP();
400 mD(3) = nodes[3]->GetP();
401 }
402
ComputeVolume()403 double ChElementTetraCorot_4_P::ComputeVolume() {
404 ChVector<> B1, C1, D1;
405 B1.Sub(nodes[1]->GetPos(), nodes[0]->GetPos());
406 C1.Sub(nodes[2]->GetPos(), nodes[0]->GetPos());
407 D1.Sub(nodes[3]->GetPos(), nodes[0]->GetPos());
408 ChMatrixDynamic<> M(3, 3);
409 M.col(0) = B1.eigen();
410 M.col(1) = C1.eigen();
411 M.col(2) = D1.eigen();
412 M.transposeInPlace();
413 Volume = std::abs(M.determinant() / 6);
414 return Volume;
415 }
416
ComputeStiffnessMatrix()417 void ChElementTetraCorot_4_P::ComputeStiffnessMatrix() {
418 // M = [ X0_0 X0_1 X0_2 X0_3 ] ^-1
419 // [ 1 1 1 1 ]
420 ChMatrixNM<double, 4, 4> tmp;
421 tmp.block(0, 0, 3, 1) = nodes[0]->GetPos().eigen();
422 tmp.block(0, 1, 3, 1) = nodes[1]->GetPos().eigen();
423 tmp.block(0, 2, 3, 1) = nodes[2]->GetPos().eigen();
424 tmp.block(0, 3, 3, 1) = nodes[3]->GetPos().eigen();
425 tmp.row(3).setConstant(1.0);
426 mM = tmp.inverse();
427
428 ////MatrB.Reset(3, 4);
429 MatrB(0, 0) = mM(0);
430 MatrB(0, 1) = mM(4);
431 MatrB(0, 2) = mM(8);
432 MatrB(0, 3) = mM(12);
433 MatrB(1, 0) = mM(1);
434 MatrB(1, 1) = mM(5);
435 MatrB(1, 2) = mM(9);
436 MatrB(1, 3) = mM(13);
437 MatrB(2, 0) = mM(2);
438 MatrB(2, 1) = mM(6);
439 MatrB(2, 2) = mM(10);
440 MatrB(2, 3) = mM(14);
441
442 StiffnessMatrix = Volume * MatrB.transpose() * Material->Get_ConstitutiveMatrix() * MatrB;
443 }
444
SetupInitial(ChSystem * system)445 void ChElementTetraCorot_4_P::SetupInitial(ChSystem* system) {
446 ComputeVolume();
447 ComputeStiffnessMatrix();
448 }
449
UpdateRotation()450 void ChElementTetraCorot_4_P::UpdateRotation() {
451 // P = [ p_0 p_1 p_2 p_3 ]
452 // [ 1 1 1 1 ]
453 ChMatrixNM<double, 4, 4> P;
454 P.block(0, 0, 3, 1) = nodes[0]->GetPos().eigen();
455 P.block(0, 1, 3, 1) = nodes[1]->GetPos().eigen();
456 P.block(0, 2, 3, 1) = nodes[2]->GetPos().eigen();
457 P.block(0, 3, 3, 1) = nodes[3]->GetPos().eigen();
458 P.row(3).setConstant(1.0);
459
460 ChMatrix33<double> F;
461 // F=P*mM (only upper-left 3x3 block!)
462 double sum;
463 for (int colres = 0; colres < 3; ++colres)
464 for (int row = 0; row < 3; ++row) {
465 sum = 0;
466 for (int col = 0; col < 4; ++col)
467 sum += (P(row, col)) * (mM(col, colres));
468 F(row, colres) = sum;
469 }
470 ChMatrix33<> S;
471 double det = ChPolarDecomposition<>::Compute(F, this->A, S, 1E-6);
472 if (det < 0)
473 this->A *= -1.0;
474 }
475
ComputeKRMmatricesGlobal(ChMatrixRef H,double Kfactor,double Rfactor,double Mfactor)476 void ChElementTetraCorot_4_P::ComputeKRMmatricesGlobal(ChMatrixRef H, double Kfactor, double Rfactor, double Mfactor) {
477 assert((H.rows() == 4) && (H.cols() == 4));
478
479 // For K matrix (jacobian d/dT of c dT/dt + div [C] grad T = f )
480 H = Kfactor * StiffnessMatrix;
481
482 // For R matrix: (jacobian d/d\dot(T) of c dT/dt + div [C] grad T = f )
483 if (Rfactor)
484 if (this->GetMaterial()->Get_DtMultiplier()) {
485 // lumped approx. integration of c
486 double lumped_node_c = (this->GetVolume() * this->GetMaterial()->Get_DtMultiplier()) / 4.0;
487 for (int id = 0; id < 4; id++) {
488 H(id, id) += Rfactor * lumped_node_c;
489 }
490 }
491 //***TO DO*** better per-node lumping, or 4x4 consistent c integration as per mass matrices.
492
493 // For M mass matrix: NONE in Poisson equation c dT/dt + div [C] grad T = f
494 }
495
ComputeInternalForces(ChVectorDynamic<> & Fi)496 void ChElementTetraCorot_4_P::ComputeInternalForces(ChVectorDynamic<>& Fi) {
497 assert(Fi.size() == 4);
498
499 // set up vector of nodal fields
500 ChVectorDynamic<> displ(4);
501 this->GetStateBlock(displ);
502
503 // [local Internal Forces] = [Klocal] * P
504 ChVectorDynamic<> FiK_local = StiffnessMatrix * displ;
505
506 //***TO DO*** derivative terms? + [Rlocal] * P_dt ???? ***NO because Poisson rho dP/dt + div [C] grad P = 0
507
508 FiK_local *= -1.0;
509
510 // ChMatrixCorotation::ComputeCK(FiK_local, this->A, 4, Fi); ***corotation NOT NEEDED
511
512 Fi = FiK_local;
513 }
514
GetPgradient()515 ChVectorN<double, 3> ChElementTetraCorot_4_P::GetPgradient() {
516 // set up vector of nodal displacements (in local element system) u_l = R*p - p0
517 ChVectorDynamic<> displ(4);
518 this->GetStateBlock(displ);
519
520 return MatrB * displ;
521 }
522
LoadableGetStateBlock_x(int block_offset,ChState & mD)523 void ChElementTetraCorot_4_P::LoadableGetStateBlock_x(int block_offset, ChState& mD) {
524 mD(block_offset) = this->nodes[0]->GetP();
525 mD(block_offset + 1) = this->nodes[1]->GetP();
526 mD(block_offset + 2) = this->nodes[2]->GetP();
527 mD(block_offset + 3) = this->nodes[3]->GetP();
528 }
529
LoadableGetStateBlock_w(int block_offset,ChStateDelta & mD)530 void ChElementTetraCorot_4_P::LoadableGetStateBlock_w(int block_offset, ChStateDelta& mD) {
531 mD(block_offset) = this->nodes[0]->GetP_dt();
532 mD(block_offset + 1) = this->nodes[1]->GetP_dt();
533 mD(block_offset + 2) = this->nodes[2]->GetP_dt();
534 mD(block_offset + 3) = this->nodes[3]->GetP_dt();
535 }
536
LoadableStateIncrement(const unsigned int off_x,ChState & x_new,const ChState & x,const unsigned int off_v,const ChStateDelta & Dv)537 void ChElementTetraCorot_4_P::LoadableStateIncrement(const unsigned int off_x,
538 ChState& x_new,
539 const ChState& x,
540 const unsigned int off_v,
541 const ChStateDelta& Dv) {
542 for (int i = 0; i < 4; ++i) {
543 nodes[i]->NodeIntStateIncrement(off_x + i * 1, x_new, x, off_v + i * 1, Dv);
544 }
545 }
546
LoadableGetVariables(std::vector<ChVariables * > & mvars)547 void ChElementTetraCorot_4_P::LoadableGetVariables(std::vector<ChVariables*>& mvars) {
548 for (int i = 0; i < nodes.size(); ++i)
549 mvars.push_back(&this->nodes[i]->Variables());
550 }
551
ComputeNF(const double U,const double V,const double W,ChVectorDynamic<> & Qi,double & detJ,const ChVectorDynamic<> & F,ChVectorDynamic<> * state_x,ChVectorDynamic<> * state_w)552 void ChElementTetraCorot_4_P::ComputeNF(const double U,
553 const double V,
554 const double W,
555 ChVectorDynamic<>& Qi,
556 double& detJ,
557 const ChVectorDynamic<>& F,
558 ChVectorDynamic<>* state_x,
559 ChVectorDynamic<>* state_w) {
560 // evaluate shape functions (in compressed vector), btw. not dependant on state
561 ShapeVector N;
562 this->ShapeFunctions(N, U, V,
563 W); // note: U,V,W in 0..1 range, thanks to IsTetrahedronIntegrationNeeded() {return true;}
564
565 detJ = 6 * this->GetVolume();
566
567 Qi(0) = N(0) * F(0);
568 Qi(1) = N(1) * F(0);
569 Qi(2) = N(2) * F(0);
570 Qi(3) = N(3) * F(0);
571 }
572
573 } // end namespace fea
574 } // end namespace chrono
575