1#include "LinearElasticitySolver.h"
3#include "Matrix/MatrixFunc.h"
5#include "ParticleSystem/Module/Kernel.h"
9 IMPLEMENT_TCLASS(LinearElasticitySolver, TDataType)
11 template<typename Real>
12 __device__ Real D_Weight(Real r, Real h)
14 CorrectedKernel<Real> kernSmooth;
15 return kernSmooth.WeightRR(r, 2*h);
16// h = h < EPSILON ? Real(1) : h;
21 template <typename Real, typename Coord, typename Matrix, typename Bond>
22 __global__ void EM_PrecomputeShape(
25 DArrayList<Bond> bonds)
27 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
28 if (pId >= invK.size()) return;
30 List<Bond>& bonds_i = bonds[pId];
32 Coord rest_i = X[pId];
34 int size_i = bonds_i.size();
35 Real maxDist = Real(0);
36 for (int ne = 0; ne < size_i; ne++)
38 maxDist = max(maxDist, bonds_i[ne].xi.norm());
40 maxDist = maxDist < EPSILON ? Real(1) : maxDist;
41 Real smoothingLength = maxDist;
43 Real total_weight = 0.0f;
44 Matrix mat_i = Matrix(0);
45 for (int ne = 0; ne < size_i; ne++)
47 Bond bond_ij = bonds_i[ne];
51 Real r = (rest_i - rest_j).norm();
55 Real weight = D_Weight(r, smoothingLength);
56 Coord q = (rest_j - rest_i) / smoothingLength*sqrt(weight);
58 mat_i(0, 0) += q[0] * q[0]; mat_i(0, 1) += q[0] * q[1]; mat_i(0, 2) += q[0] * q[2];
59 mat_i(1, 0) += q[1] * q[0]; mat_i(1, 1) += q[1] * q[1]; mat_i(1, 2) += q[1] * q[2];
60 mat_i(2, 0) += q[2] * q[0]; mat_i(2, 1) += q[2] * q[1]; mat_i(2, 2) += q[2] * q[2];
62 total_weight += weight;
66 if (total_weight > EPSILON)
68 mat_i *= (1.0f / total_weight);
71 Matrix R(0), U(0), D(0), V(0);
73 polarDecomposition(mat_i, R, U, D, V);
75 if (mat_i.determinant() < EPSILON*smoothingLength)
77 Real threshold = 0.0001f*smoothingLength;
78 D(0, 0) = D(0, 0) > threshold ? 1.0 / D(0, 0) : 1.0;
79 D(1, 1) = D(1, 1) > threshold ? 1.0 / D(1, 1) : 1.0;
80 D(2, 2) = D(2, 2) > threshold ? 1.0 / D(2, 2) : 1.0;
82 mat_i = V * D*U.transpose();
85 mat_i = mat_i.inverse();
90 template <typename Real, typename Coord, typename Matrix, typename Bond>
91 __global__ void EM_EnforceElasticity(
92 DArray<Coord> delta_position,
94 DArray<Real> bulkCoefs,
98 DArrayList<Bond> bonds,
102 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
103 if (pId >= Y.size()) return;
105 List<Bond>& bonds_i = bonds[pId];
106 Coord rest_i = X[pId];
109 Coord cur_pos_i = Y[pId];
110 Coord accPos = Coord(0);
112 Real bulk_i = bulkCoefs[pId];
114 Real maxDist = Real(0);
115 int size_i = bonds_i.size();
116 for (int ne = 0; ne < size_i; ne++)
118 maxDist = max(maxDist, bonds_i[ne].xi.norm());
120 maxDist = maxDist < EPSILON ? Real(1) : maxDist;
121 Real horizon = maxDist;
124 Real total_weight = 0.0f;
125 Matrix deform_i = Matrix(0.0f);
126 for (int ne = 0; ne < size_i; ne++)
128 Bond bond_ij = bonds_i[ne];
132 Real r = (rest_j - rest_i).norm();
136 Real weight = D_Weight(r, horizon);
138 Coord p = (Y[j] - Y[pId]) / horizon;
139 Coord q = (rest_j - rest_i) / horizon*weight;
141 deform_i(0, 0) += p[0] * q[0]; deform_i(0, 1) += p[0] * q[1]; deform_i(0, 2) += p[0] * q[2];
142 deform_i(1, 0) += p[1] * q[0]; deform_i(1, 1) += p[1] * q[1]; deform_i(1, 2) += p[1] * q[2];
143 deform_i(2, 0) += p[2] * q[0]; deform_i(2, 1) += p[2] * q[1]; deform_i(2, 2) += p[2] * q[2];
144 total_weight += weight;
149 if (total_weight > EPSILON)
151 deform_i *= (1.0f / total_weight);
152 deform_i = deform_i * invK[pId];
159 //Check whether the reference shape is inverted, if yes, simply set K^{-1} to be an identity matrix
160 //Note other solutions are possible.
161 if ((deform_i.determinant()) < -0.001f)
163 deform_i = Matrix::identityMatrix();
169// Matrix mat_i = invK[pId];
170// printf("Mat %d: \n %f %f %f \n %f %f %f \n %f %f %f \n",
172// mat_i(0, 0), mat_i(0, 1), mat_i(0, 2),
173// mat_i(1, 0), mat_i(1, 1), mat_i(1, 2),
174// mat_i(2, 0), mat_i(2, 1), mat_i(2, 2));
177 for (int ne = 0; ne < size_i; ne++)
179 Bond bond_ij = bonds_i[ne];
184 Coord cur_pos_j = Y[j];
185 Real r = (rest_j - rest_i).norm();
187 if (r > 0.01f*horizon)
189 Real weight = D_Weight(r, horizon);
191 Coord rest_dir_ij = deform_i*(rest_i - rest_j);
192 Coord cur_dir_ij = cur_pos_i - cur_pos_j;
194 cur_dir_ij = cur_dir_ij.norm() > EPSILON ? cur_dir_ij.normalize() : Coord(0);
195 rest_dir_ij = rest_dir_ij.norm() > EPSILON ? rest_dir_ij.normalize() : Coord(0, 0, 0);
197 Real mu_ij = mu*bulk_i* D_Weight(r, horizon);
198 Coord mu_pos_ij = Y[j] + r*rest_dir_ij;
199 Coord mu_pos_ji = Y[pId] - r*rest_dir_ij;
201 Real lambda_ij = lambda*bulk_i*D_Weight(r, horizon);
202 Coord lambda_pos_ij = Y[j] + r*cur_dir_ij;
203 Coord lambda_pos_ji = Y[pId] - r*cur_dir_ij;
205 Coord delta_pos_ij = mu_ij*mu_pos_ij + lambda_ij*lambda_pos_ij;
206 Real delta_weight_ij = mu_ij + lambda_ij;
208 Coord delta_pos_ji = mu_ij*mu_pos_ji + lambda_ij*lambda_pos_ji;
210 accA += delta_weight_ij;
211 accPos += delta_pos_ij;
214 atomicAdd(&weights[j], delta_weight_ij);
215 atomicAdd(&delta_position[j][0], delta_pos_ji[0]);
216 atomicAdd(&delta_position[j][1], delta_pos_ji[1]);
217 atomicAdd(&delta_position[j][2], delta_pos_ji[2]);
221 atomicAdd(&weights[pId], accA);
222 atomicAdd(&delta_position[pId][0], accPos[0]);
223 atomicAdd(&delta_position[pId][1], accPos[1]);
224 atomicAdd(&delta_position[pId][2], accPos[2]);
227 template <typename Real, typename Coord>
228 __global__ void K_UpdatePosition(
229 DArray<Coord> position,
230 DArray<Coord> old_position,
231 DArray<Coord> delta_position,
232 DArray<Real> delta_weights)
234 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
235 if (pId >= position.size()) return;
237 position[pId] = (old_position[pId] + delta_position[pId]) / (1.0+delta_weights[pId]);
240 template <typename Real, typename Coord>
241 __global__ void K_UpdateVelocity(
242 DArray<Coord> velArr,
243 DArray<Coord> prePos,
244 DArray<Coord> curPos,
247 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
248 if (pId >= velArr.size()) return;
250 velArr[pId] += (curPos[pId] - prePos[pId]) / dt;
253 template<typename TDataType>
254 LinearElasticitySolver<TDataType>::LinearElasticitySolver()
257 this->inHorizon()->setValue(0.0125);
261 template<typename TDataType>
262 LinearElasticitySolver<TDataType>::~LinearElasticitySolver()
265 mDisplacement.clear();
271 template<typename TDataType>
272 void LinearElasticitySolver<TDataType>::enforceElasticity()
274 int num = this->inY()->size();
275 uint pDims = cudaGridSize(num, BLOCK_SIZE);
277 mDisplacement.reset();
280 EM_EnforceElasticity << <pDims, BLOCK_SIZE >> > (
285 this->inX()->getData(),
286 this->inY()->getData(),
287 this->inBonds()->getData(),
288 this->varMu()->getData(),
289 this->varLambda()->getData());
292 K_UpdatePosition << <pDims, BLOCK_SIZE >> > (
293 this->inY()->getData(),
300 template<typename Real>
301 __global__ void EM_InitBulkStiffness(DArray<Real> stiffness)
303 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
304 if (pId >= stiffness.size()) return;
306 stiffness[pId] = Real(1);
309 template<typename TDataType>
310 void LinearElasticitySolver<TDataType>::computeMaterialStiffness()
312 int num = this->inY()->size();
314 uint pDims = cudaGridSize(num, BLOCK_SIZE);
315 EM_InitBulkStiffness << <pDims, BLOCK_SIZE >> > (mBulkStiffness);
319 template<typename TDataType>
320 void LinearElasticitySolver<TDataType>::computeInverseK()
322 auto& restShapes = this->inBonds()->getData();
323 uint pDims = cudaGridSize(restShapes.size(), BLOCK_SIZE);
325 EM_PrecomputeShape <Real, Coord, Matrix, Bond> << <pDims, BLOCK_SIZE >> > (
327 this->inX()->getData(),
332 template<typename TDataType>
333 void LinearElasticitySolver<TDataType>::solveElasticity()
336 mPosBuf.assign(this->inY()->getData());
338 this->computeInverseK();
341 uint maxIterNum = this->varIterationNumber()->getData();
342 while (itor < maxIterNum) {
343 this->enforceElasticity();
347 this->updateVelocity();
350 template<typename TDataType>
351 void LinearElasticitySolver<TDataType>::updateVelocity()
353 int num = this->inY()->size();
354 uint pDims = cudaGridSize(num, BLOCK_SIZE);
356 Real dt = this->inTimeStep()->getData();
358 K_UpdateVelocity << <pDims, BLOCK_SIZE >> > (
359 this->inVelocity()->getData(),
361 this->inY()->getData(),
367 template<typename TDataType>
368 void LinearElasticitySolver<TDataType>::constrain()
370 this->solveElasticity();
374 template <typename Coord, typename Bond>
375 __global__ void K_UpdateRestShape(
376 DArrayList<Bond> shape,
380 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
381 if (pId >= pos.size()) return;
385 List<Bond>& rest_shape_i = shape[pId];
386 List<int>& list_id_i = nbr[pId];
387 int nbSize = list_id_i.size();
388 for (int ne = 0; ne < nbSize; ne++)
390 int j = list_id_i[ne];
395 rest_shape_i.insert(np);
398 Bond np_0 = rest_shape_i[0];
399 rest_shape_i[0] = np;
400 rest_shape_i[ne] = np_0;
405 template<typename TDataType>
406 void LinearElasticitySolver<TDataType>::preprocess()
408 int num = this->inY()->size();
410 if (num == mInvK.size())
414 mWeights.resize(num);
415 mDisplacement.resize(num);
420 mBulkStiffness.resize(num);
422 this->computeMaterialStiffness();
425 DEFINE_CLASS(LinearElasticitySolver);