1#include "CoSemiImplicitHyperelasticitySolver.h"
2#include "Matrix/MatrixFunc.h"
3#include "ParticleSystem/Module/Kernel.h"
4#include "curand_kernel.h"
5#include "Algorithm/CudaRand.h"
9 IMPLEMENT_TCLASS(CoSemiImplicitHyperelasticitySolver, TDataType);
11 __constant__ EnergyModels<Real> ENERGY_FUNC;
13 template<typename Real>
14 __device__ Real constantWeight(Real r, Real h)
20 template<typename TDataType>
21 CoSemiImplicitHyperelasticitySolver<TDataType>::CoSemiImplicitHyperelasticitySolver()
22 : LinearElasticitySolver<TDataType>()
24 this->varIterationNumber()->setValue(30);
26 mContactRule = std::make_shared<ContactRule<TDataType>>();
28 this->inTriangularMesh()->connect(mContactRule->inTriangularMesh());
29 this->inOldPosition()->connect(mContactRule->inOldPosition());
30 this->inVelocity()->connect(mContactRule->inVelocity());
31 this->inTimeStep()->connect(mContactRule->inTimeStep());
32 this->inUnit()->connect(mContactRule->inUnit());
35 template<typename TDataType>
36 void CoSemiImplicitHyperelasticitySolver<TDataType>::initializeVolume()
38 int numOfParticles = this->inY()->getData().size();
39 uint pDims = cudaGridSize(numOfParticles, BLOCK_SIZE);
40 std::cout << "dev: " << numOfParticles << " particles\n";
41 HM_InitVolume << <pDims, BLOCK_SIZE >> > (m_volume, m_objectVolume, m_objectVolumeSet, m_particleVolume, m_particleVolumeSet);
44 template<typename TDataType>
45 CoSemiImplicitHyperelasticitySolver<TDataType>::~CoSemiImplicitHyperelasticitySolver()
47 this->mWeights.clear();
48 this->mDisplacement.clear();
51 this->mPosBuf.clear();
52 this->mPosBuf_March.clear();
55 template <typename Real, typename Coord, typename Matrix>
56 __global__ void HM_ComputeEnergy(
61 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
62 if (pId >= energy.size()) return;
64 Coord eigen_i = eigens[pId];
67 energy[pId] = ENERGY_FUNC.stvkModel.getEnergy(eigen_i[0], eigen_i[1], eigen_i[2]);
69 else if (type == NeoHooekean) {
70 energy[pId] = ENERGY_FUNC.neohookeanModel.getEnergy(eigen_i[0], eigen_i[1], eigen_i[2]);
72 else if (type == Linear) {
73 energy[pId] = ENERGY_FUNC.linearModel.getEnergy(eigen_i[0], eigen_i[1], eigen_i[2]);
75 else if (type == Xuetal) {
76 energy[pId] = ENERGY_FUNC.xuModel.getEnergy(eigen_i[0], eigen_i[1], eigen_i[2]);
81 template<typename TDataType>
82 void CoSemiImplicitHyperelasticitySolver<TDataType>::solveElasticity()
84 cudaMemcpyToSymbol(ENERGY_FUNC, this->inEnergyModels()->constDataPtr().get(), sizeof(EnergyModels<Real>));
86 enforceHyperelasticity();
89 template <typename Coord>
90 __global__ void HM_ComputeGradient(
95 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
96 if (pId >= y_next.size()) return;
98 grad[pId] = y_next[pId] - y_pre[pId];
101 template <typename Real, typename Coord>
102 __global__ void HM_ComputeCurrentPosition(
104 DArray<Coord> y_current,
105 DArray<Coord> y_next,
108 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
109 if (pId >= y_next.size()) return;
111 y_next[pId] = y_current[pId] + alpha[pId] * grad[pId];
114 template <typename Real, typename Coord>
115 __global__ void HM_ComputeCurrentPosition(
117 DArray<Coord> y_current,
118 DArray<Coord> y_next,
121 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
122 if (pId >= y_next.size()) return;
124 y_next[pId] = y_current[pId] + alpha * grad[pId];
127 template <typename Real, typename Coord, typename Matrix, typename Bond>
128 __global__ void HM_Compute1DEnergy(
130 DArray<Coord> energyGradient,
132 DArray<Coord> pos_current,
135 DArray<bool> validOfK,
136 DArray<Coord> eigenValues,
137 DArrayList<Bond> bonds,
140 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
141 if (pId >= energy.size()) return;
143 Coord pos_current_i = pos_current[pId];
145 Real totalEnergy = 0.0f;
146 Coord totalEnergyGradient = Coord(0);
147 Real V_i = volume[pId];
149 int size_i = bonds[pId].size();
152 Coord eigen_value_i = eigenValues[pId];
153 bool valid_i = validOfK[pId];
157 for (int ne = 0; ne < size_i; ne++)
159 Bond bond_ij = bonds[pId][ne];
161 Coord pos_current_j = pos_current[j];
163 Real r = (x_j - x_i).norm();
165 Real V_j = volume[j];
169 Real norm_ij = (pos_current_j - pos_current_i).norm();
170 Real lambda_ij = norm_ij / r;
173 Coord deltaEnergyGradient;
174 Coord dir_ij = norm_ij < EPSILON ? Coord(0) : (pos_current_i - pos_current_j) / (r);
177 deltaEnergy = V_j * ENERGY_FUNC.stvkModel.getEnergy(lambda_ij, lambda_ij, lambda_ij);
178 deltaEnergyGradient = V_j * (ENERGY_FUNC.stvkModel.getStressTensorPositive(lambda_ij, lambda_ij, lambda_ij) - ENERGY_FUNC.stvkModel.getStressTensorNegative(lambda_ij, lambda_ij, lambda_ij)) * dir_ij;
180 else if (type == NeoHooekean) {
181 deltaEnergy = V_j * ENERGY_FUNC.neohookeanModel.getEnergy(lambda_ij, lambda_ij, lambda_ij);
182 deltaEnergyGradient = V_j * (ENERGY_FUNC.neohookeanModel.getStressTensorPositive(lambda_ij, lambda_ij, lambda_ij) - ENERGY_FUNC.neohookeanModel.getStressTensorNegative(lambda_ij, lambda_ij, lambda_ij)) * dir_ij;
184 else if (type == Linear) {
185 deltaEnergy = V_j * ENERGY_FUNC.linearModel.getEnergy(lambda_ij, lambda_ij, lambda_ij);
186 deltaEnergyGradient = V_j * (ENERGY_FUNC.linearModel.getStressTensorPositive(lambda_ij, lambda_ij, lambda_ij) - ENERGY_FUNC.linearModel.getStressTensorNegative(lambda_ij, lambda_ij, lambda_ij)) * dir_ij;
188 else if (type == Xuetal) {
189 deltaEnergy = V_j * ENERGY_FUNC.xuModel.getEnergy(lambda_ij, lambda_ij, lambda_ij);
190 deltaEnergyGradient = V_j * (ENERGY_FUNC.xuModel.getStressTensorPositive(lambda_ij, lambda_ij, lambda_ij) - ENERGY_FUNC.xuModel.getStressTensorNegative(lambda_ij, lambda_ij, lambda_ij)) * dir_ij;
193 totalEnergy += deltaEnergy;
194 totalEnergyGradient += deltaEnergyGradient;
198 energy[pId] = totalEnergy * V_i;
199 energyGradient[pId] = totalEnergyGradient * V_i;
202 template <typename Coord>
203 __global__ void HM_Chebyshev_Acceleration(DArray<Coord> next_X, DArray<Coord> X, DArray<Coord> prev_X, float omega)
205 int pId = blockDim.x * blockIdx.x + threadIdx.x;
206 if (pId >= prev_X.size()) return;
208 next_X[pId] = (next_X[pId] - X[pId]) * 0.666 + X[pId];
210 next_X[pId] = omega * (next_X[pId] - prev_X[pId]) + prev_X[pId];
213 template <typename Real, typename Coord, typename Matrix, typename Bond>
214 __global__ void HM_ComputeStepLength(
215 DArray<Real> stepLength,
216 DArray<Coord> gradient,
217 DArray<Coord> energyGradient,
221 DArrayList<Bond> bonds)
223 int pId = blockDim.x * blockIdx.x + threadIdx.x;
224 if (pId >= stepLength.size()) return;
226 Real mass_i = volume[pId] * 1000.0;
227 Real energy_i = energy[pId];
229 Real deltaE_i = abs(energyGradient[pId].dot(gradient[pId]));
231 Real alpha = deltaE_i < EPSILON || deltaE_i < energy_i ? Real(1) : energy_i / deltaE_i;
233 alpha /= Real(1 + bonds[pId].size());
235 stepLength[pId] = alpha;
238 template <typename Coord>
239 __global__ void HM_FixCoM(
240 DArray<Coord> positions,
241 DArray<Attribute> atts,
244 int pId = blockDim.x * blockIdx.x + threadIdx.x;
245 if (pId >= positions.size()) return;
246 if ((positions[pId] - CoM).norm() < 0.05)
247 atts[pId].setFixed();
250 template <typename Coord, typename Bond>
251 __global__ void K_UpdateRestShape(
252 DArrayList<Bond> shape,
256 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
257 if (pId >= pos.size()) return;
261 List<Bond>& rest_shape_i = shape[pId];
262 List<int>& list_id_i = nbr[pId];
263 int nbSize = list_id_i.size();
264 for (int ne = 0; ne < nbSize; ne++)
266 int j = list_id_i[ne];
271 rest_shape_i.insert(np);
274 Bond np_0 = rest_shape_i[0];
275 rest_shape_i[0] = np;
276 rest_shape_i[ne] = np_0;
281 template <typename Coord>
282 __global__ void test_HM_UpdatePosition(
283 DArray<Coord> position, //position target
284 DArray<Coord> y_next, //position reference
285 DArray<Attribute> att)
287 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
288 if (pId >= position.size()) return;
290 if (!att[pId].isFixed()) {
291 position[pId] = y_next[pId];
295 template <typename Coord>
296 __global__ void test_HM_UpdatePosition(
297 DArray<Coord> position,
298 DArray<Coord> velocity,
299 DArray<Coord> y_next,
300 DArray<Coord> position_old,
301 DArray<Attribute> att,
304 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
305 if (pId >= position.size()) return;
307 if (!att[pId].isFixed()) {
308 position[pId] = y_next[pId];
310 velocity[pId] += (position[pId] - position_old[pId]) / dt;
314 template <typename Real, typename Coord, typename Matrix, typename Bond>
315 __global__ void HM_ComputeF(
317 DArray<Coord> eigens,
319 DArray<bool> validOfK,
325 DArrayList<Bond> bonds,
327 Real const strainLimit,
328 DArray<Coord> restNorm,
331 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
332 if (pId >= Y.size()) return;
335 int size_i = bonds[pId].size();
336 Real total_weight = Real(0);
345 printf("Position in HM_ComputeF %d: %f %f %f \n", pId, Y[pId][0], Y[pId][1], Y[pId][2]);
348 //printf("%d %d \n", pId, size_i);
350 Real maxDist = Real(0);
351 for (int ne = 0; ne < size_i; ne++)
353 Bond bond_ij = bonds[pId][ne];
356 Real r = (x_i - y_j).norm();
358 maxDist = max(maxDist, r);
360 maxDist = maxDist < EPSILON ? Real(1) : maxDist;
363 printf("Max distance %d: %f \n", pId, maxDist);
366 for (int ne = 0; ne < size_i; ne++)
368 Bond bond_ij = bonds[pId][ne];
371 Real r = (x_i - x_j).norm();
375 Real weight = Real(1);
377 Coord p = (Y[j] - Y[pId]) / maxDist;
378 Coord q = (x_j - x_i) / maxDist;
381 matL_i(0, 0) += p[0] * q[0] * weight; matL_i(0, 1) += p[0] * q[1] * weight; matL_i(0, 2) += p[0] * q[2] * weight;
382 matL_i(1, 0) += p[1] * q[0] * weight; matL_i(1, 1) += p[1] * q[1] * weight; matL_i(1, 2) += p[1] * q[2] * weight;
383 matL_i(2, 0) += p[2] * q[0] * weight; matL_i(2, 1) += p[2] * q[1] * weight; matL_i(2, 2) += p[2] * q[2] * weight;
385 matK_i(0, 0) += q[0] * q[0] * weight; matK_i(0, 1) += q[0] * q[1] * weight; matK_i(0, 2) += q[0] * q[2] * weight;
386 matK_i(1, 0) += q[1] * q[0] * weight; matK_i(1, 1) += q[1] * q[1] * weight; matK_i(1, 2) += q[1] * q[2] * weight;
387 matK_i(2, 0) += q[2] * q[0] * weight; matK_i(2, 1) += q[2] * q[1] * weight; matK_i(2, 2) += q[2] * q[2] * weight;
389 total_weight += weight;
395 printf("%d Neighbor %d: %f %f %f \n", pId, j, Y[j][0], Y[j][1], Y[j][2]);
403 Coord nr = restNorm[pId];
404 matK_i(0, 0) += t*nr[0] * nr[0]; matK_i(0, 1) += t*nr[0] * nr[1]; matK_i(0, 2) += t*nr[0] * nr[2];
405 matK_i(1, 0) += t*nr[1] * nr[0]; matK_i(1, 1) += t*nr[1] * nr[1]; matK_i(1, 2) += t*nr[1] * nr[2];
406 matK_i(2, 0) += t*nr[2] * nr[0]; matK_i(2, 1) += t*nr[2] * nr[1]; matK_i(2, 2) += t*nr[2] * nr[2];
410 matL_i(0, 0) += t*n[0] * nr[0]; matL_i(0, 1) += t*n[0] * nr[1]; matL_i(0, 2) += t*n[0] * nr[2];
411 matL_i(1, 0) += t*n[1] * nr[0]; matL_i(1, 1) += t*n[1] * nr[1]; matL_i(1, 2) += t*n[1] * nr[2];
412 matL_i(2, 0) += t*n[2] * nr[0]; matL_i(2, 1) += t*n[2] * nr[1]; matL_i(2, 2) += t*n[2] * nr[2];
414 total_weight += 2 * t;
415 if (total_weight > EPSILON)
417 matL_i *= (1.0f / total_weight);
418 matK_i *= (1.0f / total_weight);
423 polarDecomposition(matK_i, R, U, D, V);
428 Matrix mat_out = matK_i;
429 printf("matK_i: \n %f %f %f \n %f %f %f \n %f %f %f \n\n",
430 mat_out(0, 0), mat_out(0, 1), mat_out(0, 2),
431 mat_out(1, 0), mat_out(1, 1), mat_out(1, 2),
432 mat_out(2, 0), mat_out(2, 1), mat_out(2, 2));
435 printf("matL_i: \n %f %f %f \n %f %f %f \n %f %f %f \n\n",
436 mat_out(0, 0), mat_out(0, 1), mat_out(0, 2),
437 mat_out(1, 0), mat_out(1, 1), mat_out(1, 2),
438 mat_out(2, 0), mat_out(2, 1), mat_out(2, 2));
440 mat_out = U * D * V.transpose();
441 printf("matK polar: \n %f %f %f \n %f %f %f \n %f %f %f \n\n",
442 mat_out(0, 0), mat_out(0, 1), mat_out(0, 2),
443 mat_out(1, 0), mat_out(1, 1), mat_out(1, 2),
444 mat_out(2, 0), mat_out(2, 1), mat_out(2, 2));
446 printf("Horizon: %f; Det: %f \n", horizon, matK_i.determinant());
450 Real maxK = maximum(abs(D(0, 0)), maximum(abs(D(1, 1)),abs(D(2,2))));
451 Real minK = minimum(abs(D(0, 0)), minimum(abs(D(1, 1)),abs(D(2,2))));
454 bool valid_K = (minK < EPSILON || maxK / minK > Real(1/(strainLimit * strainLimit))) ? false : true;
455 validOfK[pId] = valid_K;
460 invK[pId] = matK_i.inverse();
461 F_i = matL_i * matK_i.inverse();
466 Real threshold = 0.0001f * horizon;
467 D(0, 0) = D(0, 0) > threshold ? 1.0 / D(0, 0) : 1.0;
468 D(1, 1) = D(1, 1) > threshold ? 1.0 / D(1, 1) : 1.0;
469 D(2, 2) = D(2, 2) > threshold ? 1.0 / D(2, 2) : 1.0;
470 invK[pId] = V * D * U.transpose();
471 F_i = matL_i * invK[pId];
474 polarDecomposition(F_i, R, U, D, V);
479 Matrix mat_out = F_i;
480 printf("matF_i: \n %f %f %f \n %f %f %f \n %f %f %f \n\n",
481 mat_out(0, 0), mat_out(0, 1), mat_out(0, 2),
482 mat_out(1, 0), mat_out(1, 1), mat_out(1, 2),
483 mat_out(2, 0), mat_out(2, 1), mat_out(2, 2));
486 printf("matD: \n %f %f %f \n %f %f %f \n %f %f %f \n\n",
487 mat_out(0, 0), mat_out(0, 1), mat_out(0, 2),
488 mat_out(1, 0), mat_out(1, 1), mat_out(1, 2),
489 mat_out(2, 0), mat_out(2, 1), mat_out(2, 2));
491 printf("Horizon: %f; Det: %f \n", horizon, F_i.determinant());
494 if (F_i.determinant() < maxDist * EPSILON)
502 Coord n0 = Coord(1, 0, 0);
503 Coord n1 = Coord(0, 1, 0);
504 Coord n2 = Coord(0, 0, 1);
507 Coord n0_rot = R * n0;
508 Coord n1_rot = R * n1;
509 Coord n2_rot = R * n2;
511 Real un0 = n0_rot.dot(n);
512 Real un1 = n1_rot.dot(n);
513 Real un2 = n2_rot.dot(n);
514 printf("U * N: %f,%f,%f\n",un0,un1,un2);
518 Real l0 = n0_rot.dot(F_i * n0);
519 Real l1 = n1_rot.dot(F_i * n1);
520 Real l2 = n2_rot.dot(F_i * n2);
530 const Real slimit = min(t, strainLimit);
531 l0 = clamp(l0, slimit, 1/slimit);
532 l1 = clamp(l1, slimit, 1/slimit);
533 l2 = clamp(l2, slimit, 1/slimit);
536 printf("l0 got low clamp, %f\n",l0);
537 else if(l0 == 1/slimit)
538 printf("l0 got high clamp, %f\n",l0);
540 printf("l1 got low clamp, %f\n",l1);
541 else if (l1 == 1 / slimit)
542 printf("l1 got high clamp, %f\n",l1);
544 printf("l2 got low clamp, %f\n",l2);
545 else if (l2 == 1 / slimit)
546 printf("l2 got high clamp, %f\n",l2);
553 eigens[pId] = Coord(D(0,0), D(1,1), D(2,2));
554 F[pId] = U * D * V.transpose();
559 template <typename Real, typename Coord, typename Matrix, typename Bond>
560 __global__ void HM_JacobiStepNonsymmetric(
561 DArray<Coord> source,
569 DArray<bool> validOfK,
572 DArrayList<Bond> bonds,
577 bool NeighborSearchingAdjacent)
579 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
580 if (pId >= y_pre.size()) return;
583 int size_i = bonds[pId].size();
585 Real maxDist = Real(0);
586 for (int ne = 0; ne < size_i; ne++)
588 Bond bond_ij = bonds[pId][ne];
591 Real r = (x_i - x_j).norm();
593 maxDist = max(maxDist, r);
595 maxDist = maxDist < EPSILON ? Real(1) : maxDist;
597 Real kappa = 16 / (15 * M_PI * maxDist * maxDist * maxDist * maxDist * maxDist);
599 Real lambda_i1 = eigen[pId][0];
600 Real lambda_i2 = eigen[pId][1];
601 Real lambda_i3 = eigen[pId][2];
603 Matrix U_i = matU[pId];
604 Matrix V_i = matV[pId];
607 Real vol = volume[pId];
609 S1_i = ENERGY_FUNC.stvkModel.getStressTensorPositive(lambda_i1, lambda_i2, lambda_i3);
610 S2_i = ENERGY_FUNC.stvkModel.getStressTensorNegative(lambda_i1, lambda_i2, lambda_i3);
612 else if (type == NeoHooekean) {
613 S1_i = ENERGY_FUNC.neohookeanModel.getStressTensorPositive(lambda_i1, lambda_i2, lambda_i3);
614 S2_i = ENERGY_FUNC.neohookeanModel.getStressTensorNegative(lambda_i1, lambda_i2, lambda_i3);
616 else if (type == Linear) {
617 S1_i = ENERGY_FUNC.linearModel.getStressTensorPositive(lambda_i1, lambda_i2, lambda_i3);
618 S2_i = ENERGY_FUNC.linearModel.getStressTensorNegative(lambda_i1, lambda_i2, lambda_i3);
620 else if (type == Xuetal) {
621 S1_i = ENERGY_FUNC.xuModel.getStressTensorPositive(lambda_i1, lambda_i2, lambda_i3);
622 S2_i = ENERGY_FUNC.xuModel.getStressTensorNegative(lambda_i1, lambda_i2, lambda_i3);
624 else if (type == Fiber)
626 S1_i = ENERGY_FUNC.fiberModel.getStressTensorPositive(lambda_i1, lambda_i2, lambda_i3, V_i);
627 S2_i = ENERGY_FUNC.fiberModel.getStressTensorNegative(lambda_i1, lambda_i2, lambda_i3, V_i);
628 ENERGY_FUNC.fiberModel.getInfo(lambda_i1, lambda_i2, lambda_i3, V_i);
631 Matrix PK1_i = U_i * S1_i * U_i.transpose();
632 Matrix PK2_i = U_i * S2_i * V_i.transpose();
634 Real Vol_i = volume[pId];
638 Coord y_pre_i = y_pre[pId];
640 bool K_valid = validOfK[pId];
645 for (int ne = 0; ne < size_i; ne++)
647 Bond bond_ij = bonds[pId][ne];
649 Coord y_pre_j = y_pre[j];
651 Real r = (x_j - x_i).norm();
657 Real Vol_j = volume[j];
659 Coord y_ij = y_pre_i - y_pre_j;
662 Real lambda = y_ij.norm() / r;
664 const Real scale = Vol_i * Vol_j * kappa;
665 const Real sw_ij = dt * dt * scale * weight_ij;
667 bool K_valid_ij = K_valid & validOfK[j];
672 S1_ij = ENERGY_FUNC.stvkModel.getStressTensorPositive(lambda, lambda, lambda);
673 S2_ij = ENERGY_FUNC.stvkModel.getStressTensorNegative(lambda, lambda, lambda);
675 else if (type == NeoHooekean) {
676 S1_ij = ENERGY_FUNC.neohookeanModel.getStressTensorPositive(lambda, lambda, lambda);
677 S2_ij = ENERGY_FUNC.neohookeanModel.getStressTensorNegative(lambda, lambda, lambda);
679 else if (type == Linear) {
680 S1_ij = ENERGY_FUNC.linearModel.getStressTensorPositive(lambda, lambda, lambda);
681 S2_ij = ENERGY_FUNC.linearModel.getStressTensorNegative(lambda, lambda, lambda);
683 else if (type == Xuetal) {
684 S1_ij = ENERGY_FUNC.xuModel.getStressTensorPositive(lambda, lambda, lambda);
685 S2_ij = ENERGY_FUNC.xuModel.getStressTensorNegative(lambda, lambda, lambda);
687 else if (type == Fiber) {
688 S1_ij = ENERGY_FUNC.fiberModel.getStressTensorPositive(lambda, lambda,lambda, V_i);
689 S2_ij = ENERGY_FUNC.fiberModel.getStressTensorNegative(lambda, lambda,lambda, V_i);
692 Matrix PK1_ij = K_valid_ij ? PK1_i : S1_ij;
693 Matrix PK2_ij = K_valid_ij ? PK2_i : S2_ij;
695 if (NeighborSearchingAdjacent)
697 Real standardVol = 0.0025f * 0.005f;
699 PK1_ij *= (x_i - x_j).normSquared() / standardVol;
700 PK2_ij *= (x_i - x_j).normSquared() / standardVol;
703 Coord dir_ij = lambda > EPSILON ? y_ij.normalize() : Coord(1, 0, 0);
705 Coord x_ij = K_valid_ij ? x_i - x_j : dir_ij * (x_i - x_j).norm();
707 Matrix F_i_1 = F_i.inverse();
708 Matrix F_i_T = F_i_1.transpose();
710 Matrix F_TF_1 = k_bend * F_i_T * F_i_1;
712 Coord ds_ij = sw_ij * (PK1_ij + F_TF_1) * y_pre_j + sw_ij * (PK2_ij + k_bend * F_i_1) * x_ij;
713 Coord ds_ji = sw_ij * (PK1_ij + F_TF_1) * y_pre_i - sw_ij * (PK2_ij + k_bend * F_i_1) * x_ij;
715 Matrix mat_ij = sw_ij * (PK1_ij + F_TF_1);
723 atomicAdd(&source[j][0], ds_ji[0]);
724 atomicAdd(&source[j][1], ds_ji[1]);
725 atomicAdd(&source[j][2], ds_ji[2]);
727 atomicAdd(&A[j](0, 0), mat_ij(0, 0));
728 atomicAdd(&A[j](0, 1), mat_ij(0, 1));
729 atomicAdd(&A[j](0, 2), mat_ij(0, 2));
730 atomicAdd(&A[j](1, 0), mat_ij(1, 0));
731 atomicAdd(&A[j](1, 1), mat_ij(1, 1));
732 atomicAdd(&A[j](1, 2), mat_ij(1, 2));
733 atomicAdd(&A[j](2, 0), mat_ij(2, 0));
734 atomicAdd(&A[j](2, 1), mat_ij(2, 1));
735 atomicAdd(&A[j](2, 2), mat_ij(2, 2));
739 atomicAdd(&source[pId][0], source_i[0]);
740 atomicAdd(&source[pId][1], source_i[1]);
741 atomicAdd(&source[pId][2], source_i[2]);
743 atomicAdd(&A[pId](0, 0), mat_i(0, 0));
744 atomicAdd(&A[pId](0, 1), mat_i(0, 1));
745 atomicAdd(&A[pId](0, 2), mat_i(0, 2));
746 atomicAdd(&A[pId](1, 0), mat_i(1, 0));
747 atomicAdd(&A[pId](1, 1), mat_i(1, 1));
748 atomicAdd(&A[pId](1, 2), mat_i(1, 2));
749 atomicAdd(&A[pId](2, 0), mat_i(2, 0));
750 atomicAdd(&A[pId](2, 1), mat_i(2, 1));
751 atomicAdd(&A[pId](2, 2), mat_i(2, 2));
756 template <typename Matrix>
757 __global__ void HM_InitRotation(
762 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
763 if (pId >= U.size()) return;
765 U[pId] = Matrix::identityMatrix();
766 V[pId] = Matrix::identityMatrix();
767 R[pId] = Matrix::identityMatrix();
772 template<typename Matrix, typename Coord, typename Real>
773 __global__ void HM_ComputeNextPosition(
774 DArray<Coord> y_next,
775 DArray<Coord> y_inter,
777 DArray<Coord> source,
781 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
782 if (pId >= y_next.size()) return;
784 Real mass_i = volume[pId] * 1000.0;
785 Matrix mat_i = A[pId] + mass_i * Matrix::identityMatrix();
786 Coord src_i = source[pId] + mass_i * y_inter[pId];
787 y_next[pId] = mat_i.inverse() * src_i;
791 template <typename Real>
792 __global__ void HM_InitVolume(
795 bool objectVolumeSet,
797 bool particleVolumeSet
800 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
801 if (pId >= volume.size()) return;
803 if (objectVolumeSet && volume.size() != 0) volume[pId] = Real(objectVolume / volume.size());
804 else if (particleVolumeSet) volume[pId] = particleVolume;
805 else volume[pId] = 0.001;
809 template <typename Coord, typename Real>
810 __global__ void HM_ComputeGradient(
814 DArray<Coord> y_next)
816 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
817 if (pId >= y_next.size()) return;
819 grad[pId] = y_next[pId] - y_pre[pId];
820 grad_m[pId] = sqrt(grad[pId].dot(grad[pId]));
824 template<typename TDataType>
825 void CoSemiImplicitHyperelasticitySolver<TDataType>::resizeAllFields()
828 uint num = this->inY()->getData().size();
830 if (m_F.size() == num)
837 m_validOfK.resize(num);
838 m_validOfF.resize(num);
840 m_eigenValues.resize(num);
844 m_volume.resize(num);
846 m_energy.resize(num);
848 m_gradient.resize(num);
849 mEnergyGradient.resize(num);
853 y_current.resize(num);
856 m_source.resize(num);
858 m_gradientMagnitude.resize(num);
859 this->mPosBuf.resize(num);
861 m_fraction.resize(num);
863 m_bFixed.resize(num);
864 m_fixedPos.resize(num);
865 mPosBuf_March.resize(num);
869 cuExecute(m_matU.size(),
875 m_reduce = Reduction<Real>::Create(num);
877 auto triSet = TypeInfo::cast<TriangleSet<TDataType>>(this->inTriangularMesh()->getDataPtr());
878 triSet->getPoints().assign(this->inY()->getData());
879 triSet->updateAngleWeightedVertexNormal(this->inNorm()->getData());
882 template<typename TDataType>
883 void CoSemiImplicitHyperelasticitySolver<TDataType>::enforceHyperelasticity()
887 int numOfParticles = this->inY()->getData().size();
888 uint pDims = cudaGridSize(numOfParticles, BLOCK_SIZE);
890 std::cout << "enforceElasticity Particles: " << numOfParticles << std::endl;
892 this->mWeights.reset();
894 Log::sendMessage(Log::User, "\n \n \n \n=================== solver start!!!===================");
898 /*====================================== Jacobi method ======================================*/
899 // initialize y_now, y_next_iter
900 y_current.assign(this->inY()->getData());
901 this->mPosBuf.assign(this->inY()->getData());
904 // do Jacobi method Loop
905 bool convergeFlag = false; // converge or not
909 Real max_grad_mag = Real(1000.0);
912 while (iterCount < this->varIterationNumber()->getData() && max_grad_mag >= this->grad_res_eps) {
917 HM_ComputeF << <pDims, BLOCK_SIZE >> > (
925 this->inX()->getData(),
927 this->inBonds()->getData(),
928 this->inHorizon()->getData(),
930 this->inRestNorm()->getData(),
931 this->inNorm()->getData());
934 HM_JacobiStepNonsymmetric << <pDims, BLOCK_SIZE >> > (
937 this->inX()->getData(),
946 this->inBonds()->getData(),
947 this->inHorizon()->getData(),
949 this->inTimeStep()->getData(),
950 this->inEnergyType()->getData(),
951 this->varNeighborSearchingAdjacent()->getData());
954 cuExecute(y_current.size(),
955 HM_ComputeNextPosition,
963 cuExecute(m_gradient.size(),
971 Reduction<Real> reduce;
972 max_grad_mag = reduce.maximum(m_gradientMagnitude.begin(), m_gradientMagnitude.size());
974 if (this->m_alphaCompute) {
975 cuExecute(m_energy.size(),
979 this->inX()->getData(),
985 this->inBonds()->getData(),
986 this->inEnergyType()->getData());
988 cuExecute(m_alpha.size(),
989 HM_ComputeStepLength,
996 this->inBonds()->getData());
998 cuExecute(m_gradient.size(),
999 HM_ComputeCurrentPosition,
1007 cuExecute(m_gradient.size(),
1008 HM_ComputeCurrentPosition,
1017 y_current.assign(y_next);
1020 // do Jacobi method Loop
1021 mContactRule->inNewPosition()->assign(y_next);
1022 mContactRule->initCCDBroadPhase();
1024 mContactRule->inNewPosition()->assign(this->mPosBuf);
1025 convergeFlag = false; // converge or not
1030 mPosBuf_March.assign(this->mPosBuf);
1033 auto& cntPos = mContactRule->inNewPosition()->getData();
1034 while (iterCount < this->varIterationNumber()->getData() && max_grad_mag >= this->grad_res_eps) {
1037 y_current.assign(cntPos);
1039 HM_ComputeF << <pDims, BLOCK_SIZE >> > (
1047 this->inX()->getData(),
1049 this->inBonds()->getData(),
1050 this->inHorizon()->getData(),
1052 this->inRestNorm()->getData(),
1053 this->inNorm()->getData());
1056 HM_JacobiStepNonsymmetric << <pDims, BLOCK_SIZE >> > (
1059 this->inX()->getData(),
1068 this->inBonds()->getData(),
1069 this->inHorizon()->getData(),
1071 this->inTimeStep()->getData(),
1072 this->inEnergyType()->getData(),
1073 this->varNeighborSearchingAdjacent()->getData());
1076 cuExecute(cntPos.size(),
1077 HM_ComputeNextPosition,
1085 cuExecute(m_gradient.size(),
1088 m_gradientMagnitude,
1092 Reduction<Real> reduce;
1093 max_grad_mag = reduce.maximum(m_gradientMagnitude.begin(), m_gradientMagnitude.size());
1095 if (this->m_alphaCompute) {
1096 cuExecute(m_energy.size(),
1100 this->inX()->getData(),
1106 this->inBonds()->getData(),
1107 this->inEnergyType()->getData());
1109 cuExecute(m_alpha.size(),
1110 HM_ComputeStepLength,
1117 this->inBonds()->getData());
1119 cuExecute(m_gradient.size(),
1120 HM_ComputeCurrentPosition,
1129 cuExecute(m_gradient.size(),
1130 HM_ComputeCurrentPosition,
1136 if (this->selfContact) {
1138 mContactRule->update();
1141 mContactRule->constrain();
1148 /*========================= end of alg, marching time step==============================*/
1149 printf("========= Enforcement elastic run %d iteration =======\n", iterCount);
1152 cuExecute(this->inY()->getDataPtr()->size(),
1153 test_HM_UpdatePosition,
1154 this->inY()->getData(),
1155 this->inVelocity()->getData(),
1158 this->inAttribute()->getData(),
1159 this->inTimeStep()->getData());
1162 Log::sendMessage(Log::User, "\n==================== solver end!!!====================\n");
1165 DEFINE_CLASS(CoSemiImplicitHyperelasticitySolver);