G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsVisitorMuscle.h
Go to the documentation of this file.
1 
17 #pragma once
18 
20 #include <gsElasticity/gsBasePde.h>
21 
23 #include <gsCore/gsFuncData.h>
24 
25 namespace gismo
26 {
27 
28 template <class T>
29 class gsVisitorMuscle
30 {
31 public:
32  gsVisitorMuscle(const gsPde<T> & pde_,
33  const gsPiecewiseFunction<T> & muscleTendon_,
34  const gsVector<T> & fiberDir_,
35  const gsMultiPatch<T> & displacement_,
36  const gsMultiPatch<T> & pressure_)
37  : pde_ptr(static_cast<const gsBasePde<T>*>(&pde_)),
38  muscleTendon(muscleTendon_),
39  fiberDir(fiberDir_),
40  displacement(displacement_),
41  pressure(pressure_){}
42 
43  void initialize(const gsBasisRefs<T> & basisRefs,
44  const index_t patchIndex,
45  const gsOptionList & options,
46  gsQuadRule<T> & rule)
47  {
48  // parametric dimension of the first displacement component
49  dim = basisRefs.front().dim();
50  // a quadrature rule is defined by the basis for the first velocity component.
51  // the same rule is used for the presure
52  rule = gsQuadrature::get(basisRefs.front(), options);
53  // saving necessary info
54  patch = patchIndex;
55  T YM_muscle = options.getReal("MuscleYoungsModulus");
56  T PR_muscle = options.getReal("MusclePoissonsRatio");
57  T YM_tendon = options.getReal("TendonYoungsModulus");
58  T PR_tendon = options.getReal("TendonPoissonsRatio");
59  lambda_inv_muscle = ( 1. + PR_muscle ) * ( 1. - 2. * PR_muscle ) / YM_muscle / PR_muscle ;
60  mu_muscle = YM_muscle / ( 2. * ( 1. + PR_muscle ) );
61  lambda_inv_tendon = ( 1. + PR_tendon) * ( 1. - 2. * PR_tendon) / YM_tendon / PR_tendon;
62  mu_tendon = YM_tendon / ( 2. * ( 1. + PR_tendon ) );
63  forceScaling = options.getReal("ForceScaling");
64  maxMuscleStress = options.getReal("MaxMuscleStress");
65  optFiberStretch = options.getReal("OptFiberStretch");
66  deltaW = options.getReal("DeltaW");
67  powerNu = options.getReal("PowerNu");
68  alpha = options.getReal("Alpha"); // activation parameter
69  I = gsMatrix<T>::Identity(dim,dim);
70  // resize containers for global indices
71  globalIndices.resize(dim+1);
72  blockNumbers.resize(dim+1);
73  }
74 
75  inline void evaluate(const gsBasisRefs<T> & basisRefs,
76  const gsGeometry<T> & geo,
77  const gsMatrix<T> & quNodes)
78  {
79  // store quadrature points of the element for geometry evaluation
80  md.points = quNodes;
81  // NEED_VALUE to get points in the physical domain for evaluation of the RHS
82  // NEED_MEASURE to get the Jacobian determinant values for integration
83  // NEED_GRAD_TRANSFORM to get the Jacobian matrix to transform gradient from the parametric to physical domain
85  // Compute image of the quadrature points plus gradient, jacobian and other necessary data
86  geo.computeMap(md);
87  // find local indices of the displacement and pressure basis functions active on the element
88  basisRefs.front().active_into(quNodes.col(0),localIndicesDisp);
89  N_D = localIndicesDisp.rows();
90  basisRefs.back().active_into(quNodes.col(0), localIndicesPres);
91  N_P = localIndicesPres.rows();
92  // Evaluate displacement basis functions and their derivatives on the element
93  basisRefs.front().evalAllDers_into(quNodes,1,basisValuesDisp);
94  // Evaluate pressure basis functions on the element
95  basisRefs.back().eval_into(quNodes,basisValuesPres);
96  // Evaluate right-hand side at the image of the quadrature points
97  pde_ptr->rhs()->eval_into(md.values[0],forceValues);
98  // store quadrature points of the element for displacement evaluation
99  mdDisplacement.points = quNodes;
100  // NEED_DERIV to compute deformation gradient
101  mdDisplacement.flags = NEED_DERIV;
102  // evaluate displacement gradient
103  displacement.patch(patch).computeMap(mdDisplacement);
104  // evaluate pressure; we use eval_into instead of another gsMapData object
105  // because it easier for simple value evaluation
106  pressure.patch(patch).eval_into(quNodes,pressureValues);
107  // evaluate muscle-tendon distribution
108  muscleTendon.piece(patch).eval_into(quNodes,muscleTendonValues);
109  }
110 
111  inline void assemble(gsDomainIterator<T> & element,
112  const gsVector<T> & quWeights)
113  {
114  // Initialize local matrix/rhs // A | B^T
115  localMat.setZero(dim*N_D + N_P, dim*N_D + N_P); // --|-- matrix structure
116  localRhs.setZero(dim*N_D + N_P,1); // B | C
117  // Loop over the quadrature nodes
118  for (index_t q = 0; q < quWeights.rows(); ++q)
119  {
120  // Compute material parameters
121  const T mu = muscleTendonValues.at(q) * mu_muscle + (1-muscleTendonValues.at(q))*mu_tendon;
122  const T lambda_inv = muscleTendonValues.at(q) * lambda_inv_muscle + (1-muscleTendonValues.at(q))*lambda_inv_tendon;
123  // Multiply quadrature weight by the geometry measure
124  const T weight = quWeights[q] * md.measure(q);
125  // Compute physical gradients of basis functions at q as a dim x numActiveFunction matrix
126  transformGradients(md,q,basisValuesDisp[1],physGradDisp);
127  // physical jacobian of displacemnt du/dx = du/dxi * dxi/dx
128  physDispJac = mdDisplacement.jacobian(q)*(md.jacobian(q).cramerInverse());
129  // deformation gradient F = I + du/dx
130  F = I + physDispJac;
131  // deformation jacobian J = det(F)
132  T J = F.determinant();
133  // Right Cauchy Green strain, C = F'*F
134  RCG = F.transpose() * F;
135  // logarithmic neo-Hooke
136  GISMO_ENSURE(J>0,"Invalid configuration: J < 0");
137  RCGinv = RCG.cramerInverse();
138  // Second Piola-Kirchhoff stress tensor, passive part
139  S = (pressureValues.at(q)-mu)*RCGinv + mu*I;
141  // fiber direction in the physical domain
142  fiberDirPhys = md.jacobian(q)*fiberDir;
143  fiberDirPhys /= fiberDirPhys.norm();
144  // dyadic product of the fiber direction
145  M = fiberDirPhys * fiberDirPhys.transpose();
146  // active stress scaled with the time activation parameter
147  T fiberStretch = sqrt((M*RCG).trace());
148  T ratioInExp = (fiberStretch/optFiberStretch-1)/deltaW;
149  T megaExp = exp(-1*pow(abs(ratioInExp),powerNu));
150  S += M * maxMuscleStress * alpha * muscleTendonValues.at(q)/ pow(fiberStretch,2) * megaExp;
152  // elasticity tensor
153  symmetricIdentityTensor<T>(C,RCGinv);
154  C *= mu-pressureValues.at(q);
156 
157  matrixTraceTensor<T>(Ctemp,M,M);
158  C += -1*Ctemp*alpha*maxMuscleStress*megaExp/pow(fiberStretch,3)* muscleTendonValues.at(q)*
159  (2 + powerNu*pow(ratioInExp,powerNu-1)/deltaW/optFiberStretch);
161  // Matrix A and reisdual: loop over displacement basis functions
162  for (index_t i = 0; i < N_D; i++)
163  {
164  setB<T>(B_i,F,physGradDisp.col(i));
165  materialTangentTemp = B_i.transpose() * C;
166  // Geometric tangent K_tg_geo = gradB_i^T * S * gradB_j;
167  geometricTangentTemp = S * physGradDisp.col(i);
168  // A-matrix
169  for (index_t j = 0; j < N_D; j++)
170  {
171  setB<T>(B_j,F,physGradDisp.col(j));
172  materialTangent = materialTangentTemp * B_j;
173  T geometricTangent = geometricTangentTemp.transpose() * physGradDisp.col(j);
174  // K_tg = K_tg_mat + I*K_tg_geo;
175  for (short_t d = 0; d < dim; ++d)
176  materialTangent(d,d) += geometricTangent;
177 
178  for (short_t di = 0; di < dim; ++di)
179  for (short_t dj = 0; dj < dim; ++dj)
180  localMat(di*N_D+i, dj*N_D+j) += weight * materialTangent(di,dj);
181  }
182 
183  // Second Piola-Kirchhoff stress tensor as vector
184  voigtStress<T>(Svec,S);
185  // rhs = -r = force - B*Svec,
186  localResidual = B_i.transpose() * Svec;
187  for (short_t d = 0; d < dim; d++)
188  localRhs(d*N_D+i) -= weight * localResidual(d);
189  }
190  // B-matrix
191  divV = F.cramerInverse().transpose() * physGradDisp;
192  for (short_t d = 0; d < dim; ++d)
193  {
194  block = weight*basisValuesPres.col(q)*divV.row(d);
195  localMat.block(dim*N_D,d*N_D,N_P,N_D) += block.block(0,0,N_P,N_D);
196  localMat.block(d*N_D,dim*N_D,N_D,N_P) += block.transpose().block(0,0,N_D,N_P);
197  }
198  // C-matrix
199  if (abs(lambda_inv) > 0)
200  localMat.block(dim*N_D,dim*N_D,N_P,N_P) -=
201  (weight*lambda_inv*basisValuesPres.col(q)*basisValuesPres.col(q).transpose()).block(0,0,N_P,N_P);
202  // rhs: constraint residual
203  localRhs.middleRows(dim*N_D,N_P) += weight*basisValuesPres.col(q)*(lambda_inv*pressureValues.at(q)-log(J));
204  // rhs: force
205  for (short_t d = 0; d < dim; ++d)
206  localRhs.middleRows(d*N_D,N_D).noalias() += weight * forceScaling * forceValues(d,q) * basisValuesDisp[0].col(q) ;
207  }
208  }
209 
210  inline void localToGlobal(const int patchIndex,
211  const std::vector<gsMatrix<T> > & eliminatedDofs,
212  gsSparseSystem<T> & system)
213  {
214  // computes global indices for displacement components
215  for (short_t d = 0; d < dim; ++d)
216  {
217  system.mapColIndices(localIndicesDisp,patchIndex,globalIndices[d],d);
218  blockNumbers.at(d) = d;
219  }
220  // computes global indices for pressure
221  system.mapColIndices(localIndicesPres, patchIndex, globalIndices[dim], dim);
222  blockNumbers.at(dim) = dim;
223  // push to global system
224  system.pushToRhs(localRhs,globalIndices,blockNumbers);
225  system.pushToMatrix(localMat,globalIndices,eliminatedDofs,blockNumbers,blockNumbers);
226  }
227 
228 protected:
229  // problem info
230  short_t dim;
231  const gsBasePde<T> * pde_ptr;
232  // distribution of the tendon and muscle tissue; given in the parametric domain
233  const gsPiecewiseFunction<T> & muscleTendon;
234  // orientation of muscle fibers in the parametric domain
235  const gsVector<T> & fiberDir;
236  index_t patch; // current patch
237  // Lame coefficients and force scaling factor
238  T lambda_inv_muscle, mu_muscle, lambda_inv_tendon, mu_tendon, forceScaling;
239  // Active response parameters
240  T maxMuscleStress, optFiberStretch, deltaW, powerNu, alpha;
241  // geometry mapping
242  gsMapData<T> md;
243  // local components of the global linear system
244  gsMatrix<T> localMat;
245  gsMatrix<T> localRhs;
246  // local indices (at the current patch) of basis functions active at the current element
247  gsMatrix<index_t> localIndicesDisp;
248  gsMatrix<index_t> localIndicesPres;
249  // number of displacement and pressure basis functions active at the current element
250  index_t N_D, N_P;
251  // values and derivatives of displacement basis functions at quadrature points at the current element
252  // values are stored as a N_D x numQuadPoints matrix; not sure about derivatives, must be smth like N_D*dim x numQuadPoints
253  std::vector<gsMatrix<T> > basisValuesDisp;
254  // values of pressure basis functions active at the current element;
255  // stores as a N_P x numQuadPoints matrix
256  gsMatrix<T> basisValuesPres;
257  // RHS values at quadrature points at the current element; stored as a dim x numQuadPoints matrix
258  gsMatrix<T> forceValues;
259  // current displacement field
260  const gsMultiPatch<T> & displacement;
261  // evaluation data of the current displacement field
262  gsMapData<T> mdDisplacement;
263  // current pressure field
264  const gsMultiPatch<T> & pressure;
265  // evaluation data of the current pressure field stored as a 1 x numQuadPoints matrix
266  gsMatrix<T> pressureValues;
267  // evaluation data of the muscle-tendon distribution stored as a 1 x numQuadPoints matrix
268  gsMatrix<T> muscleTendonValues;
269 
270  // all temporary matrices defined here for efficiency
271  gsMatrix<T> C, Ctemp, physGradDisp, physDispJac, F, RCG, E, S, RCGinv, B_i, materialTangentTemp, B_j, materialTangent, divV, block, I, M;
272  gsVector<T> geometricTangentTemp, Svec, localResidual, fiberDirPhys;
273  // containers for global indices
274  std::vector< gsMatrix<index_t> > globalIndices;
275  gsVector<index_t> blockNumbers;
276 };
277 
278 } // namespace gismo
Gradient of the object.
Definition: gsForwardDeclarations.h:73
#define short_t
Definition: gsConfig.h:35
#define index_t
Definition: gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition: gsDebug.h:102
static gsQuadRule< T > get(const gsBasis< T > &basis, const gsOptionList &options, short_t fixDir=-1)
Constructs a quadrature rule based on input options.
Definition: gsQuadrature.h:48
Creates a variety of quadrature rules.
IMHO, a useless class, but it is necessary to use the gsAssembler class. Contains proper information ...
The density of the measure pull back.
Definition: gsForwardDeclarations.h:76
Tensor operations for elasticity.
Value of the object.
Definition: gsForwardDeclarations.h:72
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4486
Gradient transformation matrix.
Definition: gsForwardDeclarations.h:77
This object is a cache for computed values from an evaluator.