G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsVisitorMuscle.h
Go to the documentation of this file.
1
17#pragma once
18
21
23#include <gsCore/gsFuncData.h>
24
25namespace gismo
26{
27
28template <class T>
29class gsVisitorMuscle
30{
31public:
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 GISMO_UNUSED(element);
115 // Initialize local matrix/rhs // A | B^T
116 localMat.setZero(dim*N_D + N_P, dim*N_D + N_P); // --|-- matrix structure
117 localRhs.setZero(dim*N_D + N_P,1); // B | C
118 // Loop over the quadrature nodes
119 for (index_t q = 0; q < quWeights.rows(); ++q)
120 {
121 // Compute material parameters
122 const T mu = muscleTendonValues.at(q) * mu_muscle + (1-muscleTendonValues.at(q))*mu_tendon;
123 const T lambda_inv = muscleTendonValues.at(q) * lambda_inv_muscle + (1-muscleTendonValues.at(q))*lambda_inv_tendon;
124 // Multiply quadrature weight by the geometry measure
125 const T weight = quWeights[q] * md.measure(q);
126 // Compute physical gradients of basis functions at q as a dim x numActiveFunction matrix
127 transformGradients(md,q,basisValuesDisp[1],physGradDisp);
128 // physical jacobian of displacemnt du/dx = du/dxi * dxi/dx
129 physDispJac = mdDisplacement.jacobian(q)*(md.jacobian(q).cramerInverse());
130 // deformation gradient F = I + du/dx
131 F = I + physDispJac;
132 // deformation jacobian J = det(F)
133 T J = F.determinant();
134 // Right Cauchy Green strain, C = F'*F
135 RCG = F.transpose() * F;
136 // logarithmic neo-Hooke
137 GISMO_ENSURE(J>0,"Invalid configuration: J < 0");
138 RCGinv = RCG.cramerInverse();
139 // Second Piola-Kirchhoff stress tensor, passive part
140 S = (pressureValues.at(q)-mu)*RCGinv + mu*I;
142 // fiber direction in the physical domain
143 fiberDirPhys = md.jacobian(q)*fiberDir;
144 fiberDirPhys /= fiberDirPhys.norm();
145 // dyadic product of the fiber direction
146 M = fiberDirPhys * fiberDirPhys.transpose();
147 // active stress scaled with the time activation parameter
148 T fiberStretch = sqrt((M*RCG).trace());
149 T ratioInExp = (fiberStretch/optFiberStretch-1)/deltaW;
150 T megaExp = exp(-1*pow(abs(ratioInExp),powerNu));
151 S += M * maxMuscleStress * alpha * muscleTendonValues.at(q)/ pow(fiberStretch,2) * megaExp;
153 // elasticity tensor
154 symmetricIdentityTensor<T>(C,RCGinv);
155 C *= mu-pressureValues.at(q);
157
158 matrixTraceTensor<T>(Ctemp,M,M);
159 C += -1*Ctemp*alpha*maxMuscleStress*megaExp/pow(fiberStretch,3)* muscleTendonValues.at(q)*
160 (2 + powerNu*pow(ratioInExp,powerNu-1)/deltaW/optFiberStretch);
162 // Matrix A and reisdual: loop over displacement basis functions
163 for (index_t i = 0; i < N_D; i++)
164 {
165 setB<T>(B_i,F,physGradDisp.col(i));
166 materialTangentTemp = B_i.transpose() * C;
167 // Geometric tangent K_tg_geo = gradB_i^T * S * gradB_j;
168 geometricTangentTemp = S * physGradDisp.col(i);
169 // A-matrix
170 for (index_t j = 0; j < N_D; j++)
171 {
172 setB<T>(B_j,F,physGradDisp.col(j));
173 materialTangent = materialTangentTemp * B_j;
174 T geometricTangent = geometricTangentTemp.transpose() * physGradDisp.col(j);
175 // K_tg = K_tg_mat + I*K_tg_geo;
176 for (short_t d = 0; d < dim; ++d)
177 materialTangent(d,d) += geometricTangent;
178
179 for (short_t di = 0; di < dim; ++di)
180 for (short_t dj = 0; dj < dim; ++dj)
181 localMat(di*N_D+i, dj*N_D+j) += weight * materialTangent(di,dj);
182 }
183
184 // Second Piola-Kirchhoff stress tensor as vector
185 voigtStress<T>(Svec,S);
186 // rhs = -r = force - B*Svec,
187 localResidual = B_i.transpose() * Svec;
188 for (short_t d = 0; d < dim; d++)
189 localRhs(d*N_D+i) -= weight * localResidual(d);
190 }
191 // B-matrix
192 divV = F.cramerInverse().transpose() * physGradDisp;
193 for (short_t d = 0; d < dim; ++d)
194 {
195 block = weight*basisValuesPres.col(q)*divV.row(d);
196 localMat.block(dim*N_D,d*N_D,N_P,N_D) += block.block(0,0,N_P,N_D);
197 localMat.block(d*N_D,dim*N_D,N_D,N_P) += block.transpose().block(0,0,N_D,N_P);
198 }
199 // C-matrix
200 if (abs(lambda_inv) > 0)
201 localMat.block(dim*N_D,dim*N_D,N_P,N_P) -=
202 (weight*lambda_inv*basisValuesPres.col(q)*basisValuesPres.col(q).transpose()).block(0,0,N_P,N_P);
203 // rhs: constraint residual
204 localRhs.middleRows(dim*N_D,N_P) += weight*basisValuesPres.col(q)*(lambda_inv*pressureValues.at(q)-log(J));
205 // rhs: force
206 for (short_t d = 0; d < dim; ++d)
207 localRhs.middleRows(d*N_D,N_D).noalias() += weight * forceScaling * forceValues(d,q) * basisValuesDisp[0].col(q) ;
208 }
209 }
210
211 inline void localToGlobal(const int patchIndex,
212 const std::vector<gsMatrix<T> > & eliminatedDofs,
213 gsSparseSystem<T> & system)
214 {
215 // computes global indices for displacement components
216 for (short_t d = 0; d < dim; ++d)
217 {
218 system.mapColIndices(localIndicesDisp,patchIndex,globalIndices[d],d);
219 blockNumbers.at(d) = d;
220 }
221 // computes global indices for pressure
222 system.mapColIndices(localIndicesPres, patchIndex, globalIndices[dim], dim);
223 blockNumbers.at(dim) = dim;
224 // push to global system
225 system.pushToRhs(localRhs,globalIndices,blockNumbers);
226 system.pushToMatrix(localMat,globalIndices,eliminatedDofs,blockNumbers,blockNumbers);
227 }
228
229protected:
230 // problem info
231 short_t dim;
232 const gsBasePde<T> * pde_ptr;
233 // distribution of the tendon and muscle tissue; given in the parametric domain
234 const gsPiecewiseFunction<T> & muscleTendon;
235 // orientation of muscle fibers in the parametric domain
236 const gsVector<T> & fiberDir;
237 index_t patch; // current patch
238 // Lame coefficients and force scaling factor
239 T lambda_inv_muscle, mu_muscle, lambda_inv_tendon, mu_tendon, forceScaling;
240 // Active response parameters
241 T maxMuscleStress, optFiberStretch, deltaW, powerNu, alpha;
242 // geometry mapping
243 gsMapData<T> md;
244 // local components of the global linear system
245 gsMatrix<T> localMat;
246 gsMatrix<T> localRhs;
247 // local indices (at the current patch) of basis functions active at the current element
248 gsMatrix<index_t> localIndicesDisp;
249 gsMatrix<index_t> localIndicesPres;
250 // number of displacement and pressure basis functions active at the current element
251 index_t N_D, N_P;
252 // values and derivatives of displacement basis functions at quadrature points at the current element
253 // values are stored as a N_D x numQuadPoints matrix; not sure about derivatives, must be smth like N_D*dim x numQuadPoints
254 std::vector<gsMatrix<T> > basisValuesDisp;
255 // values of pressure basis functions active at the current element;
256 // stores as a N_P x numQuadPoints matrix
257 gsMatrix<T> basisValuesPres;
258 // RHS values at quadrature points at the current element; stored as a dim x numQuadPoints matrix
259 gsMatrix<T> forceValues;
260 // current displacement field
261 const gsMultiPatch<T> & displacement;
262 // evaluation data of the current displacement field
263 gsMapData<T> mdDisplacement;
264 // current pressure field
265 const gsMultiPatch<T> & pressure;
266 // evaluation data of the current pressure field stored as a 1 x numQuadPoints matrix
267 gsMatrix<T> pressureValues;
268 // evaluation data of the muscle-tendon distribution stored as a 1 x numQuadPoints matrix
269 gsMatrix<T> muscleTendonValues;
270
271 // all temporary matrices defined here for efficiency
272 gsMatrix<T> C, Ctemp, physGradDisp, physDispJac, F, RCG, E, S, RCGinv, B_i, materialTangentTemp, B_j, materialTangent, divV, block, I, M;
273 gsVector<T> geometricTangentTemp, Svec, localResidual, fiberDirPhys;
274 // containers for global indices
275 std::vector< gsMatrix<index_t> > globalIndices;
276 gsVector<index_t> blockNumbers;
277};
278
279} // namespace gismo
IMHO, a useless class, but it is necessary to use the gsAssembler class. Contains proper information ...
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
This object is a cache for computed values from an evaluator.
Creates a variety of quadrature rules.
Tensor operations for elasticity.
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition gsExpressions.h:4486
The G+Smo namespace, containing all definitions for the library.
@ NEED_VALUE
Value of the object.
Definition gsForwardDeclarations.h:72
@ NEED_DERIV
Gradient of the object.
Definition gsForwardDeclarations.h:73
@ NEED_GRAD_TRANSFORM
Gradient transformation matrix.
Definition gsForwardDeclarations.h:77
@ NEED_MEASURE
The density of the measure pull back.
Definition gsForwardDeclarations.h:76
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:51