@@ -48,6 +48,20 @@ the determinant of the deformation gradient J and the right Cauchy Green deforma
4848template <class DataTypes >
4949class Ogden : public HyperelasticMaterial <DataTypes>
5050{
51+ private:
52+ // In SOFA Voigt order for 3D symmetric tensors is non-standard: xx, xy, yy, xz, yz, zz
53+ const std::array<sofa::Index, 3 *3 > toVoigt = {0 , 1 , 3 , 1 , 2 , 4 , 3 , 4 , 5 };
54+ inline sofa::Index vId (sofa::Index i, sofa::Index j) {return toVoigt[i * 3 + j];}
55+ const std::array<std::tuple<sofa::Index, sofa::Index>, 6 > fromVoigt =
56+ {
57+ std::make_tuple (0 ,0 ),
58+ std::make_tuple (0 ,1 ),
59+ std::make_tuple (1 ,1 ),
60+ std::make_tuple (0 ,2 ),
61+ std::make_tuple (1 ,2 ),
62+ std::make_tuple (2 ,2 )
63+ };
64+
5165public:
5266 static constexpr std::string_view Name = " Ogden" ;
5367
@@ -70,8 +84,8 @@ class Ogden: public HyperelasticMaterial<DataTypes>
7084
7185 // Solve eigen problem for C
7286 Eigen::Matrix<Real, 3 , 3 > CEigen;
73- CEigen ( 0 , 0 )=C[ 0 ]; CEigen ( 0 , 1 )=C[ 1 ]; CEigen ( 1 , 0 )=C[ 1 ]; CEigen ( 1 , 1 )=C[ 2 ];
74- CEigen ( 1 , 2 )=C[ 4 ]; CEigen ( 2 , 1 )=C[ 4 ]; CEigen ( 2 , 0 )=C[ 3 ]; CEigen (0 , 2 )=C[ 3 ]; CEigen ( 2 , 2 )=C[ 5 ];
87+ for (sofa::Index i = 0 ; i < 3 ; ++i)
88+ for (sofa::Index j = 0 ; j < 3 ; ++j) CEigen (i, j) = C[ vId (i, j) ];
7589
7690 // Disable temporarilly until fixed /*Eigen::SelfAdjointEigenSolver<EigenMatrix>*/
7791 Eigen::EigenSolver<Eigen::Matrix<Real, 3 , 3 > > EigenProblemSolver (CEigen, true );
@@ -103,9 +117,9 @@ class Ogden: public HyperelasticMaterial<DataTypes>
103117 const Real fj = pow (sinfo->J , -alpha1/3 .0_sreal);
104118
105119 // Solve eigen problem for C
106- Eigen::Matrix<Real,3 , 3 > CEigen;
107- CEigen ( 0 , 0 )=C[ 0 ]; CEigen ( 0 , 1 )=C[ 1 ]; CEigen ( 1 , 0 )=C[ 1 ]; CEigen ( 1 , 1 )=C[ 2 ]; CEigen ( 1 , 2 )=C[ 4 ]; CEigen ( 2 , 1 )=C[ 4 ];
108- CEigen ( 2 , 0 )=C[ 3 ]; CEigen (0 , 2 )=C[ 3 ]; CEigen ( 2 , 2 )=C[ 5 ];
120+ Eigen::Matrix<Real, 3 , 3 > CEigen;
121+ for (sofa::Index i = 0 ; i < 3 ; ++i)
122+ for (sofa::Index j = 0 ; j < 3 ; ++j) CEigen (i, j) = C[ vId (i, j) ];
109123
110124 // Disable temporarilly until fixed /*Eigen::SelfAdjointEigenSolver<EigenMatrix>*/
111125 Eigen::EigenSolver<Eigen::Matrix<Real, 3 , 3 > > EigenProblemSolver (CEigen, true );
@@ -140,7 +154,6 @@ class Ogden: public HyperelasticMaterial<DataTypes>
140154 SPKTensorGeneral = fj * mu1 / alpha1 * (CaBy2Minus1 + -1_sreal/3_sreal * trCaBy2 * invC) + k0*log (sinfo->J )*invC;
141155 }
142156
143-
144157 void applyElasticityTensor_old (StrainInformation<DataTypes> *sinfo, const MaterialParameters<DataTypes> ¶m,
145158 const MatrixSym& inputTensor, MatrixSym& outputTensor)
146159 {
@@ -272,139 +285,130 @@ class Ogden: public HyperelasticMaterial<DataTypes>
272285
273286 void ElasticityTensor (StrainInformation<DataTypes> *sinfo, const MaterialParameters<DataTypes> ¶m, Matrix6& outputTensor) override
274287 {
275- Real k0=param.parameterArray [0 ];
276- Real mu1=param.parameterArray [1 ];
277- Real alpha1=param.parameterArray [2 ];
278- MatrixSym C=sinfo->deformationTensor ;
279- Eigen::Matrix<Real,3 ,3 > CEigen;
280- CEigen (0 ,0 )=C[0 ]; CEigen (0 ,1 )=C[1 ]; CEigen (1 ,0 )=C[1 ]; CEigen (1 ,1 )=C[2 ]; CEigen (1 ,2 )=C[4 ]; CEigen (2 ,1 )=C[4 ];
281- CEigen (2 ,0 )=C[3 ]; CEigen (0 ,2 )=C[3 ]; CEigen (2 ,2 )=C[5 ];
288+ const MatrixSym& C = sinfo->deformationTensor ;
289+ const Real k0 = param.parameterArray [0 ];
290+ const Real mu1 = param.parameterArray [1 ];
291+ const Real alpha1 = param.parameterArray [2 ];
292+ const Real fj = pow (sinfo->J , -alpha1/3 .0_sreal);
282293
283- /* Eigen::SelfAdjointEigenSolver<EigenMatrix>*/ Eigen::EigenSolver<Eigen::Matrix<Real, 3 , 3 > > EigenProblemSolver (CEigen,true );
294+ // Solve eigen problem for C
295+ Eigen::Matrix<Real, 3 , 3 > CEigen;
296+ for (sofa::Index i = 0 ; i < 3 ; ++i)
297+ for (sofa::Index j = 0 ; j < 3 ; ++j) CEigen (i, j) = C[vId (i, j)];
298+
299+ // Disable temporarilly until fixed /*Eigen::SelfAdjointEigenSolver<EigenMatrix>*/
300+ Eigen::EigenSolver<Eigen::Matrix<Real, 3 , 3 > > EigenProblemSolver (CEigen, true );
284301 if (EigenProblemSolver.info () != Eigen::Success)
285302 {
286303 dmsg_warning (" Ogden" ) << " SelfAdjointEigenSolver iterations failed to converge" ;
287304 return ;
288305 }
289- EigenMatrix Evect= EigenProblemSolver.eigenvectors ().real ();
290- CoordEigen Evalue= EigenProblemSolver.eigenvalues ().real ();
306+ const EigenMatrix Evect = EigenProblemSolver.eigenvectors ().real ();
307+ const CoordEigen Evalue = EigenProblemSolver.eigenvalues ().real ();
291308
292- Real trCalpha=pow (Evalue[0 ],alpha1/(Real)2 )+pow (Evalue[1 ],alpha1/(Real)2 )+pow (Evalue[2 ],alpha1/(Real)2 );
293- Matrix3 Pinverse;
294- Pinverse (0 ,0 )=Evect (0 ,0 ); Pinverse (1 ,1 )=Evect (1 ,1 ); Pinverse (2 ,2 )=Evect (2 ,2 ); Pinverse (0 ,1 )=Evect (1 ,0 ); Pinverse (1 ,0 )=Evect (0 ,1 ); Pinverse (2 ,0 )=Evect (0 ,2 );
295- Pinverse (0 ,2 )=Evect (2 ,0 ); Pinverse (2 ,1 )=Evect (1 ,2 ); Pinverse (1 ,2 )=Evect (2 ,1 );
309+ // trace of C^(alpha1/2)
310+ const Real aBy2 = alpha1*0 .5_sreal;
311+ const Real trCaBy2 = pow (Evalue[0 ], aBy2) + pow (Evalue[1 ], aBy2) + pow (Evalue[2 ], aBy2);
296312
297- MatrixSym Dalpha_1 (
298- pow (Evalue[0 ], alpha1/2.0 - 1.0 ), 0 ,
299- pow (Evalue[1 ], alpha1/2.0 - 1.0 ), 0 , 0 ,
300- pow (Evalue[2 ], alpha1/2.0 - 1.0 )
301- );
302- MatrixSym Calpha_1;
303- Calpha_1.Mat2Sym (Pinverse.transposed ()*Dalpha_1.SymMatMultiply (Pinverse),Calpha_1);
304-
305- MatrixSym Dalpha_2 (
306- pow (Evalue[0 ], alpha1/2.0 - 2.0 ), 0 ,
307- pow (Evalue[1 ], alpha1/2.0 - 2.0 ), 0 , 0 ,
308- pow (Evalue[2 ], alpha1/2.0 - 2.0 )
309- );
310- MatrixSym Calpha_2;
311- Calpha_2.Mat2Sym (Pinverse.transposed () * Dalpha_2.SymMatMultiply (Pinverse), Calpha_2);
313+ // Transpose (also inverse) of the eigenvector matrix
314+ Matrix3 EigenBasis;
315+ for (auto m = 0 ; m < Evect.rows (); ++m)
316+ for (auto n = 0 ; n < Evect.cols (); ++n) EigenBasis (m, n) = Evect (m, n);
312317
313- MatrixSym inversematrix;
314- invertMatrix (inversematrix,sinfo->deformationTensor );
318+ // Construct C^(alpha1/2 - 1) from eigenbasis: V * D * V^T; D_i = lambda_i^(alpha1/2 - 1)
319+ const Real aBy2Minus1 = aBy2 - 1_sreal;
320+ MatrixSym D (pow (Evalue[0 ], aBy2Minus1), 0 , pow (Evalue[1 ], aBy2Minus1), 0 , 0 , pow (Evalue[2 ], aBy2Minus1));
321+ MatrixSym CaBy2Minus1;
322+ sofa::type::MatSym<3 >::Mat2Sym (EigenBasis*D.SymMatMultiply (EigenBasis.transposed ()), CaBy2Minus1);
315323
316- // build 4th-order tensor contribution in Voigt notation
324+ // Invert deformation tensor
325+ MatrixSym invC;
326+ invertMatrix (invC, C);
327+
328+ // Build the 4th-order tensor contribution in Voigt notation
317329 Matrix6 elasticityTensor;
318330
319- // diagonal entries
320- const Real coef = 0.5 * alpha1 - 1 .;
321- Real fj= (Real)(pow (sinfo->J ,(Real)(-alpha1/3.0 )));
322- for (int n = 0 ; n < 6 ; n++)
331+ const Real aBy2Minus2 = aBy2 - 2_sreal;
332+ for (sofa::Index m = 0 ; m < 6 ; m++)
323333 {
324- int i, j;
325- switch (n)
326- {
327- case 0 : i=0 ; j=0 ; break ;
328- case 1 : i=0 ; j=1 ; break ;
329- case 2 : i=1 ; j=1 ; break ;
330- case 3 : i=0 ; j=2 ; break ;
331- case 4 : i=1 ; j=2 ; break ;
332- case 5 : i=2 ; j=2 ; break ;
333- }
334- for (int m = 0 ; m < 6 ; m++)
334+ sofa::Index i, j;
335+ std::tie (i, j) = fromVoigt[m];
336+
337+ for (sofa::Index n = 0 ; n < 6 ; n++)
335338 {
336- int k, l;
337- switch (m)
338- {
339- case 0 : k=0 ; l=0 ; break ;
340- case 1 : k=0 ; l=1 ; break ;
341- case 2 : k=1 ; l=1 ; break ;
342- case 3 : k=0 ; l=2 ; break ;
343- case 4 : k=1 ; l=2 ; break ;
344- case 5 : k=2 ; l=2 ; break ;
345- }
346- // Simple Ogden summation
347- for (int ii = 0 ; ii < 3 ; ii++)
348- {
349- Real eigenTerm = pow (Evalue[ii], alpha1/2 . - 2 .);
350- elasticityTensor (n, m) += coef * eigenTerm
351- * Evect (i, ii) * Evect (j, ii) * Evect (k, ii) * Evect (l, ii);
339+ sofa::Index k, l;
340+ std::tie (k, l) = fromVoigt[n];
352341
353- const Real eigenTerm_ii = pow (Evalue[ii], alpha1/2 . - 1 .);
354- for (int jj = 0 ; jj < 3 ; jj++)
342+ // SPK derivative contribution from spectral part
343+ for (sofa::Index eI = 0 ; eI < 3 ; eI++)
344+ {
345+ // Distortion term from differenting of eigenvalues
346+ const Real evalPowI2 = pow (Evalue[eI], aBy2Minus2);
347+ elasticityTensor (m, n) += aBy2Minus1 * evalPowI2
348+ * Evect (i, eI) * Evect (j, eI) * Evect (k, eI) * Evect (l, eI);
349+
350+ // Rotational part from differenting of eigenvectors
351+ const Real evalPowI = pow (Evalue[eI], aBy2Minus1);
352+ for (sofa::Index eJ = 0 ; eJ < 3 ; eJ++)
355353 {
356- if (jj == ii ) continue ;
354+ if (eJ == eI ) continue ;
357355
358356 Real coefRot{0 };
359- if (std::fabs (Evalue[ii] - Evalue[jj]) < std::numeric_limits<Real>::epsilon ())
360- coefRot = (alpha1 / 2 . - 1 .) * pow (Evalue[ii], alpha1 / 2 . - 2 .);
357+
358+ if (std::fabs (Evalue[eI] - Evalue[eJ]) < std::numeric_limits<Real>::epsilon ())
359+ coefRot = aBy2Minus1 * evalPowI2;
361360 else
362361 {
363- const Real eigenTerm_jj = pow (Evalue[jj ], alpha1/ 2 . - 1 . );
364- coefRot = (eigenTerm_ii - eigenTerm_jj )/(Evalue[ii ] - Evalue[jj ]);
362+ const Real evalPowJ = pow (Evalue[eJ ], aBy2Minus1 );
363+ coefRot = (evalPowI - evalPowJ )/(Evalue[eI ] - Evalue[eJ ]);
365364 }
366- elasticityTensor (n, m) += coefRot * 0.5 *
365+
366+ elasticityTensor (m, n) += coefRot * 0 .5_sreal *
367367 (
368- Evect (i, ii ) * Evect (j, jj ) * Evect (k, jj ) * Evect (l, ii ) +
369- Evect (i, ii ) * Evect (j, jj ) * Evect (k, ii ) * Evect (l, jj )
368+ Evect (i, eI ) * Evect (j, eJ ) * Evect (k, eJ ) * Evect (l, eI ) +
369+ Evect (i, eI ) * Evect (j, eJ ) * Evect (k, eI ) * Evect (l, eJ )
370370 );
371371 }
372372 }
373- // F(J) term
374- elasticityTensor (n, m) -= alpha1/6 . * (inversematrix (i,j) * Calpha_1 (k,l)
375- - trCalpha / 3 . * inversematrix (i,j) * inversematrix (k,l));
376373
377- // T22 term 1
378- elasticityTensor (n, m) -= alpha1/6 . * Calpha_1 (i,j) * inversematrix (k,l);
374+ // SPK derivative contributions from isochoric part; product rule applies
375+ // Factor 1 - Directly differentiate F(J)
376+ elasticityTensor (m, n) -= alpha1/6_sreal * (invC (i,j) * CaBy2Minus1 (k,l)
377+ - trCaBy2 / 3_sreal * invC (i,j) * invC (k,l));
378+
379+ // Factor 2 - 1st term - trace(C^(alpha1/2)) contribution
380+ elasticityTensor (m, n) -= alpha1/6_sreal * CaBy2Minus1 (i,j) * invC (k,l);
379381
380- // T22 term 2
381- elasticityTensor (n, m ) += alpha1/3 . * trCalpha * 0.5 * (
382- inversematrix (i,k) * inversematrix (j,l)
383- + inversematrix (i,l) * inversematrix (j,k));
382+ // Factor 2 - 2nd term - C inverse contribution
383+ elasticityTensor (m, n ) += alpha1/3_sreal * trCaBy2 * 0 .5_sreal * (
384+ invC (i,k) * invC (j,l)
385+ + invC (i,l) * invC (j,k));
384386
385- elasticityTensor (n, m) += 0.5 * alpha1 / mu1 / fj *
387+ // SPK derivative contribution from the volumetric part
388+ elasticityTensor (m, n) += 0 .5_sreal * alpha1 / mu1 / fj *
386389 (
387- k0 * inversematrix (i,j) * inversematrix (k,l)
388- - k0*log (sinfo->J ) *(inversematrix (i,k) * inversematrix (j,l)
389- + inversematrix (i,l) * inversematrix (j,k))
390+ k0 * invC (i,j) * invC (k,l)
391+ - k0*log (sinfo->J ) *(invC (i,k) * invC (j,l)
392+ + invC (i,l) * invC (j,k))
390393 ) ;
391394 }
392395 }
393396
394- // multiply by scalar factor
395- outputTensor = 2.0 * fj * mu1 / alpha1 * elasticityTensor ;
396- for (int n = 0 ; n < 6 ; n++)
397+ outputTensor = 2_sreal * fj * mu1 / alpha1 * elasticityTensor ;
398+
399+ // Adjust for Voigt notation using 2x factor on the off-diagonal
400+ for (sofa::Index m = 0 ; m < 6 ; m++)
397401 {
398- outputTensor (n ,1 ) *= 2 . ;
399- outputTensor (n ,3 ) *= 2 . ;
400- outputTensor (n ,4 ) *= 2 . ;
402+ outputTensor (m ,1 ) *= 2_sreal ;
403+ outputTensor (m ,3 ) *= 2_sreal ;
404+ outputTensor (m ,4 ) *= 2_sreal ;
401405 }
402406 }
403407
404408 void applyElasticityTensor (StrainInformation<DataTypes> *sinfo, const MaterialParameters<DataTypes> ¶m,
405409 const MatrixSym& inputTensor, MatrixSym& outputTensor) override
406410 {
407- // For now, let's just multiply matrices using the ElasticityTensor explicitely
411+ // For now, let's just multiply matrices using the ElasticityTensor explicitly
408412 Matrix6 elasticityTensor;
409413 this ->ElasticityTensor (sinfo, param, elasticityTensor);
410414 auto temp = elasticityTensor * inputTensor;
0 commit comments