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