1 /*************************************************************************
2 * *
3 * Vega FEM Simulation Library Version 3.1 *
4 * *
5 * "StVK" library , Copyright (C) 2007 CMU, 2009 MIT, 2016 USC *
6 * All rights reserved. *
7 * *
8 * Code author: Jernej Barbic *
9 * http://www.jernejbarbic.com/code *
10 * *
11 * Research: Jernej Barbic, Fun Shing Sin, Daniel Schroeder, *
12 * Doug L. James, Jovan Popovic *
13 * *
14 * Funding: National Science Foundation, Link Foundation, *
15 * Singapore-MIT GAMBIT Game Lab, *
16 * Zumberge Research and Innovation Fund at USC *
17 * *
18 * This library is free software; you can redistribute it and/or *
19 * modify it under the terms of the BSD-style license that is *
20 * included with this library in the file LICENSE.txt *
21 * *
22 * This library is distributed in the hope that it will be useful, *
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file *
25 * LICENSE.TXT for more details. *
26 * *
27 *************************************************************************/
28
29 #include "StVKStiffnessMatrix.h"
30 #include "volumetricMeshENuMaterial.h"
31
StVKStiffnessMatrix(StVKInternalForces * stVKInternalForces)32 StVKStiffnessMatrix::StVKStiffnessMatrix(StVKInternalForces * stVKInternalForces)
33 {
34 precomputedIntegrals = stVKInternalForces->GetPrecomputedIntegrals();
35 volumetricMesh = stVKInternalForces->GetVolumetricMesh();
36 numElementVertices = volumetricMesh->getNumElementVertices();
37 int numElements = volumetricMesh->getNumElements();
38
39 lambdaLame = (double*) malloc (sizeof(double) * numElements);
40 muLame = (double*) malloc (sizeof(double) * numElements);
41
42 for(int el=0; el<numElements; el++)
43 {
44 VolumetricMesh::Material * material = volumetricMesh->getElementMaterial(el);
45 VolumetricMesh::ENuMaterial * eNuMaterial = downcastENuMaterial(material);
46 if (eNuMaterial == NULL)
47 {
48 printf("Error: StVKStiffnessMatrix: mesh does not consist of E, nu materials.\n");
49 throw 1;
50 }
51
52 lambdaLame[el] = eNuMaterial->getLambda();
53 muLame[el] = eNuMaterial->getMu();
54 }
55
56 // build stiffness matrix skeleton
57 SparseMatrix * stiffnessMatrixTopology;
58 GetStiffnessMatrixTopology(&stiffnessMatrixTopology);
59
60 // build acceleration indices
61 row_ = (int**) malloc (sizeof(int*) * numElements);
62 column_ = (int**) malloc (sizeof(int*) * numElements);
63
64 for (int el=0; el < numElements; el++)
65 {
66 row_[el] = (int*) malloc (sizeof(int) * numElementVertices);
67 column_[el] = (int*) malloc (sizeof(int) * numElementVertices * numElementVertices);
68
69 for(int ver=0; ver<numElementVertices; ver++)
70 row_[el][ver] = volumetricMesh->getVertexIndex(el, ver);
71
72 // seek for value row[j] in list associated with row[i]
73 for(int i=0; i<numElementVertices; i++)
74 for(int j=0; j<numElementVertices; j++)
75 column_[el][numElementVertices * i + j] =
76 stiffnessMatrixTopology->GetInverseIndex(3*row_[el][i],3*row_[el][j]) / 3;
77 }
78
79 delete(stiffnessMatrixTopology);
80
81 }
82
GetStiffnessMatrixTopology(SparseMatrix ** stiffnessMatrixTopology)83 void StVKStiffnessMatrix::GetStiffnessMatrixTopology(SparseMatrix ** stiffnessMatrixTopology)
84 {
85 int numVertices = volumetricMesh->getNumVertices();
86
87 int * vertices = (int*) malloc (sizeof(int) * numElementVertices);
88
89 // build skeleton of sparseMatrix
90 SparseMatrixOutline * emptyMatrix = new SparseMatrixOutline(3 * numVertices);
91 for (int el=0; el < volumetricMesh->getNumElements(); el++)
92 {
93 //if(el % 100 == 1)
94 //printf(".");
95
96 for(int ver=0; ver<numElementVertices; ver++)
97 vertices[ver] = volumetricMesh->getVertexIndex(el, ver);
98
99 for (int i=0; i<numElementVertices; i++)
100 for (int j=0; j<numElementVertices; j++)
101 {
102 for(int k=0; k<3; k++)
103 for(int l=0; l<3; l++)
104 {
105 // only add the entry if both vertices are free (non-fixed)
106 // the corresponding elt is in row 3*i+k, column 3*j+l
107 emptyMatrix->AddEntry( 3*vertices[i]+k, 3*vertices[j]+l, 0.0 );
108 }
109 }
110 }
111 //printf("\n");
112
113 *stiffnessMatrixTopology = new SparseMatrix(emptyMatrix);
114 delete(emptyMatrix);
115
116 free(vertices);
117 }
118
~StVKStiffnessMatrix()119 StVKStiffnessMatrix::~StVKStiffnessMatrix()
120 {
121 int numElements = volumetricMesh->getNumElements();
122
123 for(int i=0; i<numElements; i++)
124 free(row_[i]);
125 free(row_);
126
127 for(int i=0; i<numElements; i++)
128 free(column_[i]);
129 free(column_);
130
131 free(lambdaLame);
132 free(muLame);
133 }
134
135 // the master function
ComputeStiffnessMatrix(const double * vertexDisplacements,SparseMatrix * sparseMatrix)136 void StVKStiffnessMatrix::ComputeStiffnessMatrix(const double * vertexDisplacements, SparseMatrix * sparseMatrix)
137 {
138 //PerformanceCounter stiffnessCounter;
139 sparseMatrix->ResetToZero();
140
141 AddLinearTermsContribution(vertexDisplacements, sparseMatrix);
142 AddQuadraticTermsContribution(vertexDisplacements, sparseMatrix);
143 AddCubicTermsContribution(vertexDisplacements, sparseMatrix);
144
145 //stiffnessCounter.StopCounter();
146 //printf("Stiffness matrix: %G\n", stiffnessCounter.GetElapsedTime());
147 }
148
AddLinearTermsContribution(const double * vertexDisplacements,SparseMatrix * sparseMatrix,int elementLow,int elementHigh)149 void StVKStiffnessMatrix::AddLinearTermsContribution(const double * vertexDisplacements, SparseMatrix * sparseMatrix, int elementLow, int elementHigh)
150 {
151 if (elementLow < 0)
152 elementLow = 0;
153 if (elementHigh < 0)
154 elementHigh = volumetricMesh->getNumElements();
155
156 int * vertices = (int*) malloc (sizeof(int) * numElementVertices);
157
158 void * elIter;
159 precomputedIntegrals->AllocateElementIterator(&elIter);
160
161 for(int el=elementLow; el < elementHigh; el++)
162 {
163 precomputedIntegrals->PrepareElement(el, elIter);
164 for(int ver=0; ver<numElementVertices; ver++)
165 vertices[ver] = volumetricMesh->getVertexIndex(el, ver);
166
167 double lambda = lambdaLame[el];
168 double mu = muLame[el];
169
170 for (int c=0; c<numElementVertices; c++) // over all vertices of the voxel, computing row of vertex c
171 {
172 // linear terms
173 for (int a=0; a<numElementVertices; a++) // over all vertices
174 {
175 Mat3d matrix(1.0);
176 matrix *= mu * precomputedIntegrals->B(elIter,a,c);
177 matrix += lambda * precomputedIntegrals->A(elIter,c,a) +
178 mu * precomputedIntegrals->A(elIter,a,c);
179
180 AddMatrix3x3Block(c, a, el, matrix, sparseMatrix);
181 }
182 }
183 }
184
185 free(vertices);
186
187 precomputedIntegrals->ReleaseElementIterator(elIter);
188 }
189
190 #define ADD_MATRIX_BLOCK(where)\
191 for(k=0; k<3; k++)\
192 for(l=0; l<3; l++)\
193 {\
194 dataHandle[rowc+k][3*column[c8+(where)]+l] += matrix[3*k+l];\
195 }
196
AddQuadraticTermsContribution(const double * vertexDisplacements,SparseMatrix * sparseMatrix,int elementLow,int elementHigh)197 void StVKStiffnessMatrix::AddQuadraticTermsContribution(const double * vertexDisplacements, SparseMatrix * sparseMatrix, int elementLow, int elementHigh)
198 {
199 if (elementLow < 0)
200 elementLow = 0;
201 if (elementHigh < 0)
202 elementHigh = volumetricMesh->getNumElements();
203
204 int * vertices = (int*) malloc (sizeof(int) * numElementVertices);
205
206 void * elIter;
207 precomputedIntegrals->AllocateElementIterator(&elIter);
208
209 double ** dataHandle = sparseMatrix->GetDataHandle();
210
211 for(int el=elementLow; el < elementHigh; el++)
212 {
213 precomputedIntegrals->PrepareElement(el, elIter);
214 int * row = row_[el];
215 int * column = column_[el];
216
217 for(int ver=0; ver<numElementVertices; ver++)
218 vertices[ver] = volumetricMesh->getVertexIndex(el, ver);
219
220 double lambda = lambdaLame[el];
221 double mu = muLame[el];
222
223 for (int c=0; c<numElementVertices; c++) // over all vertices of the voxel, computing row of vertex c
224 {
225 int rowc = 3*row[c];
226 int c8 = numElementVertices*c;
227 // quadratic terms
228 for (int e=0; e<numElementVertices; e++) // compute contribution to block (c,e) of the stiffness matrix
229 {
230 double matrix[9];
231 memset(matrix, 0, sizeof(double) * 9);
232 for(int a=0; a<numElementVertices; a++)
233 {
234 double qa[3] = { vertexDisplacements[3*vertices[a]+0], vertexDisplacements[3*vertices[a]+1], vertexDisplacements[3*vertices[a]+2] };
235
236 Vec3d C0v = lambda * precomputedIntegrals->C(elIter,c,a,e) + mu * (precomputedIntegrals->C(elIter,e,a,c) + precomputedIntegrals->C(elIter,a,e,c));
237 double C0[3] = {C0v[0], C0v[1], C0v[2]};
238
239 // C0 tensor qa
240 matrix[0] += C0[0] * qa[0]; matrix[1] += C0[0] * qa[1]; matrix[2] += C0[0] * qa[2];
241 matrix[3] += C0[1] * qa[0]; matrix[4] += C0[1] * qa[1]; matrix[5] += C0[1] * qa[2];
242 matrix[6] += C0[2] * qa[0]; matrix[7] += C0[2] * qa[1]; matrix[8] += C0[2] * qa[2];
243
244 Vec3d C1v = lambda * precomputedIntegrals->C(elIter,e,a,c) + mu * (precomputedIntegrals->C(elIter,c,e,a) + precomputedIntegrals->C(elIter,a,e,c));
245 double C1[3] = {C1v[0], C1v[1], C1v[2]};
246
247 // qa tensor C1
248 matrix[0] += qa[0] * C1[0]; matrix[1] += qa[0] * C1[1]; matrix[2] += qa[0] * C1[2];
249 matrix[3] += qa[1] * C1[0]; matrix[4] += qa[1] * C1[1]; matrix[5] += qa[1] * C1[2];
250 matrix[6] += qa[2] * C1[0]; matrix[7] += qa[2] * C1[1]; matrix[8] += qa[2] * C1[2];
251
252 Vec3d C2v = lambda * precomputedIntegrals->C(elIter,a,e,c) + mu * (precomputedIntegrals->C(elIter,c,a,e) + precomputedIntegrals->C(elIter,e,a,c));
253 double C2[3] = {C2v[0], C2v[1], C2v[2]};
254
255 // qa dot C2
256 double dotp = qa[0]*C2[0] + qa[1]*C2[1] + qa[2]*C2[2];
257 matrix[0] += dotp;
258 matrix[4] += dotp;
259 matrix[8] += dotp;
260
261 }
262 int k,l;
263 ADD_MATRIX_BLOCK(e);
264 }
265 }
266 }
267
268 free(vertices);
269
270 precomputedIntegrals->ReleaseElementIterator(elIter);
271 }
272
AddCubicTermsContribution(const double * vertexDisplacements,SparseMatrix * sparseMatrix,int elementLow,int elementHigh)273 void StVKStiffnessMatrix::AddCubicTermsContribution(const double * vertexDisplacements, SparseMatrix * sparseMatrix, int elementLow, int elementHigh)
274 {
275 if (elementLow < 0)
276 elementLow = 0;
277 if (elementHigh < 0)
278 elementHigh = volumetricMesh->getNumElements();
279
280 int * vertices = (int*) malloc (sizeof(int) * numElementVertices);
281
282 void * elIter;
283 precomputedIntegrals->AllocateElementIterator(&elIter);
284
285 double ** dataHandle = sparseMatrix->GetDataHandle();
286
287 for(int el=elementLow; el < elementHigh; el++)
288 {
289 precomputedIntegrals->PrepareElement(el, elIter);
290 int * row = row_[el];
291 int * column = column_[el];
292
293 for(int ver=0; ver<numElementVertices; ver++)
294 vertices[ver] = volumetricMesh->getVertexIndex(el, ver);
295
296 double lambda = lambdaLame[el];
297 double mu = muLame[el];
298
299 for (int c=0; c<numElementVertices; c++) // over all vertices of the voxel, computing derivative on force on vertex c
300 {
301 int rowc = 3*row[c];
302 int c8 = numElementVertices*c;
303 // cubic terms
304 for (int e=0; e<numElementVertices; e++) // compute contribution to block (c,e) of the stiffness matrix
305 {
306 double matrix[9];
307 memset(matrix, 0, sizeof(double) * 9);
308 for(int a=0; a<numElementVertices; a++)
309 {
310 int va = vertices[a];
311 const double * qa = &(vertexDisplacements[3*va]);
312 for(int b=0; b<numElementVertices; b++)
313 {
314 int vb = vertices[b];
315
316 const double * qb = &(vertexDisplacements[3*vb]);
317
318 double D0 = lambda * precomputedIntegrals->D(elIter,a,c,b,e) +
319 mu * ( precomputedIntegrals->D(elIter,a,e,b,c) + precomputedIntegrals->D(elIter,a,b,c,e) );
320
321 matrix[0] += D0 * qa[0] * qb[0]; matrix[1] += D0 * qa[0] * qb[1]; matrix[2] += D0 * qa[0] * qb[2];
322 matrix[3] += D0 * qa[1] * qb[0]; matrix[4] += D0 * qa[1] * qb[1]; matrix[5] += D0 * qa[1] * qb[2];
323 matrix[6] += D0 * qa[2] * qb[0]; matrix[7] += D0 * qa[2] * qb[1]; matrix[8] += D0 * qa[2] * qb[2];
324
325 double D1 = 0.5 * lambda * precomputedIntegrals->D(elIter,a,b,c,e) +
326 mu * precomputedIntegrals->D(elIter,a,c,b,e);
327
328 double dotpD = D1 * (qa[0] * qb[0] + qa[1] * qb[1] + qa[2] * qb[2]);
329
330 matrix[0] += dotpD;
331 matrix[4] += dotpD;
332 matrix[8] += dotpD;
333 }
334 }
335 int k,l;
336 ADD_MATRIX_BLOCK(e);
337 }
338 }
339 }
340
341 free(vertices);
342
343 precomputedIntegrals->ReleaseElementIterator(elIter);
344 }
345
346