1#include "SemiAnalyticalParticleShifting.h"
3#include "SemiAnalyticalSummationDensity.h"
5#include "IntersectionArea.h"
9 IMPLEMENT_TCLASS(SemiAnalyticalParticleShifting, TDataType)
11 template<typename TDataType>
12 SemiAnalyticalParticleShifting<TDataType>::SemiAnalyticalParticleShifting()
13 : ParticleApproximation<TDataType>()
15 this->varInertia()->setValue(Real(0.1));
16 this->varBulk()->setValue(Real(0.5));
18 mCalculateDensity = std::make_shared<SemiAnalyticalSummationDensity<TDataType>>();
19 this->inSamplingDistance()->connect(mCalculateDensity->inSamplingDistance());
20 this->inSmoothingLength()->connect(mCalculateDensity->inSmoothingLength());
21 this->inPosition()->connect(mCalculateDensity->inPosition());
22 this->inNeighborIds()->connect(mCalculateDensity->inNeighborIds());
23 this->inNeighborTriIds()->connect(mCalculateDensity->inNeighborTriIds());
24 this->inTriangleSet()->connect(mCalculateDensity->inTriangleSet());
25 this->varRestDensity()->connect(mCalculateDensity->varRestDensity());
28 template<typename TDataType>
29 SemiAnalyticalParticleShifting<TDataType>::~SemiAnalyticalParticleShifting()
36 __device__ inline Real KernSpikyGradient(const Real r, const Real h)
39 if (q > 1.0f) return 0.0;
41 const Real d = 1.0 - q;
42 const Real hh = h * h;
43 return -45.0f / ((Real)M_PI * hh*h) *d*d;
47 template<typename Real>
48 __device__ inline Real KernSpiky(const Real r, const Real h)
51 if (q > 1.0f) return 0.0;
53 const Real d = 1.0 - q;
54 const Real hh = h * h;
55 return -15.0f / ((Real)M_PI * hh*h) *d*d*d;
59 template<typename Real>
60 __device__ inline Real kernWeight1(const Real r, const Real h)
63 if (q > 1.0f) return 0.0f;
65 const Real d = 1.0f - q;
66 const Real hh = h * h;
67 return (1.0 - q * q*q*q)*h*h;
72 template<typename Real>
73 __device__ inline Real kernWRR1(const Real r, const Real h)
75 Real w = kernWeight1(r, h);
79 return w / (0.25f*h*h);
84 template <typename Real, typename Coord>
85 __global__ void SAPS_ComputeBoundaryGradient(
86 DArray<Coord> adhesion,
89 DArray<Coord> position,
90 DArrayList<int> neighbors,
91 DArrayList<int> neighborTri,
92 DArray<Triangle> m_triangle_index,
93 DArray<Coord> positionTri,
96 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
97 if (pId >= position.size()) return;
99 Coord pos_i = position[pId];
100 Coord Tri_direction(0);
103 List<int>& nbrIds_i = neighbors[pId];
104 int nbSize = nbrIds_i.size();
106 List<int>& nbrTriIds_i = neighborTri[pId];
107 int nbSizeTri = nbrTriIds_i.size();
110 for (int ne = 0; ne < nbSizeTri; ne++)
112 int j = nbrTriIds_i[ne];
114 Triangle3D t3d(positionTri[m_triangle_index[j][0]], positionTri[m_triangle_index[j][1]], positionTri[m_triangle_index[j][2]]);
115 Plane3D PL(positionTri[m_triangle_index[j][0]], t3d.normal());//plane of Tri
118 Point3D nearest_pt = p3d.project(PL);
119 Real r = (nearest_pt.origin - pos_i).norm();//distance between Fluid point and plane
120 float d = p3d.distance(PL);
122 Real AreaSum = calculateIntersectionArea(p3d, t3d, smoothingLength);
123 Real MinDistance = abs(p3d.distance(t3d));
124 Coord Min_Pt = (p3d.project(t3d)).origin - pos_i;
127 Tri_direction += t3d.normal()*KernSpiky(MinDistance, smoothingLength);
129 Coord boundNorm = t3d.normal();
131 if (Min_Pt.norm() > 0)
132 if (ne < nbSizeTri - 1)
137 jn = nbrTriIds_i[ne + 1];
139 Triangle3D t3d_n(positionTri[m_triangle_index[jn][0]], positionTri[m_triangle_index[jn][1]], positionTri[m_triangle_index[jn][2]]);
140 if ((t3d.normal().cross(t3d_n.normal())).norm() > EPSILON)// not at the same plane
145 Real minDis = abs(p3d.distance(t3d_n));
146 Coord minPt = (p3d.project(t3d_n)).origin - pos_i;
148 AreaSum += calculateIntersectionArea(p3d, t3d_n, smoothingLength);
150 if (abs(p3d.distance(t3d_n)) < MinDistance)
152 MinDistance = minDis;
155 Tri_direction += t3d_n.normal() * KernSpiky(MinDistance, smoothingLength);
160 } while (ne < nbSizeTri - 1);
163 Min_Pt /= Min_Pt.norm();
167 if (smoothingLength - d > EPSILON&& smoothingLength* smoothingLength - d * d > EPSILON&& d > EPSILON)
169 Coord n_PL = -t3d.normal();
170 n_PL = n_PL / n_PL.norm();
172 AreaB = M_PI * (smoothingLength * smoothingLength - d * d);//A0
175 Real weightS = ep*KernSpiky(r, smoothingLength);
176 Real weightS_hat = ep* r*r*r* KernSpikyGradient(r, smoothingLength);
179 Real EP_ij = - weightS * AreaSum;
180 Real totalWeight = weightS_hat
181 * 2.0 * (M_PI) * (1 - d / smoothingLength)//Omega_0
182 * AreaSum * n_PL.dot(Min_Pt)//£¨n_s¡¤d_n£©*As
185 numerator += EP_ij * boundNorm;
186 totalW[pId] += totalWeight;//denominator
191 if (Tri_direction.norm() > EPSILON) {
192 Tri_direction /= Tri_direction.norm();
194 else Tri_direction = Coord(0);
196 dir[pId] = Tri_direction;
197 adhesion[pId] = numerator;
200 template <typename Real, typename Coord>
201 __global__ void PR_ComputeGradient(
202 DArray<Coord> grads,//delta Pos
203 DArray<Coord> Adhesion,
204 DArray<Real> totalW,//total weight from boundary mesh
205 DArray<Real> rhoArr,//rDensity
206 DArray<Coord> curPos,
207 DArray<Coord> originPos,
208 DArrayList<int> neighbors,
216 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
217 if (pId >= curPos.size()) return;
221 Real a3 = surfaceTension;
225 Real w2 = 0.005f*(rhoArr[pId] - 1000.0f) / (1000.0f)*a2;
233 Coord pos_i = curPos[pId];
235 Coord grad1_i = originPos[pId] - pos_i;
238 Real total_weight2 = 0.0f;
240 Real total_weight3 = 0.0f;
242 List<int>& list_i = neighbors[pId];
243 int nbSize = list_i.size();
245 for (int ne = 0; ne < nbSize; ne++)
248 Coord pos_j = curPos[j];
249 Real r = (pos_i - pos_j).norm();
253 Real weight2 = -mass * KernSpikyGradient(r, h);
254 total_weight2 += weight2;
255 Coord g2_ij = weight2 * (pos_i - pos_j) * (1.0f / r);
258 Real weight3 = kernWRR1(r, h);
259 total_weight3 += weight3;
260 Coord g3_ij = weight3 * (pos_i - pos_j)* (1.0f / r);
264 //printf("totalW: %f\n", total_weight4);
265 total_weight2 = total_weight2 < EPSILON ? 1.0f : total_weight2;
266 total_weight3 = total_weight3 < EPSILON ? 1.0f : total_weight3;
268 grad2 /= total_weight2;
269 grad3 /= total_weight3;
273 for (int ne = 0; ne < nbSize; ne++)
276 Coord pos_j = curPos[j];
277 Real r = (pos_i - pos_j).norm();
281 Real weight2 = -mass * KernSpikyGradient(r, h);
282 Coord g2_ij = (weight2 / total_weight2) * (pos_i - pos_j) * (1.0f / r);
283 atomicAdd(&grads[j][0], -w2 * g2_ij[0]);
284 atomicAdd(&grads[j][1], -w2 * g2_ij[1]);
285 atomicAdd(&grads[j][2], -w2 * g2_ij[2]);
291 if (grad3.norm() > EPSILON)
293 Real temp = grad3.norm();
294 nGrad3 = grad3 / temp;
297 Real energy = grad3.dot(grad3);
301 Real total_weight4(0);
303 if (totalW.size() > 0)
304 total_weight4 = totalW[pId];
306 if (Adhesion[pId].norm() > 0 && Adhesion.size() > 0) {
307 grad4 = Adhesion[pId];
310 total_weight4 = total_weight4 < EPSILON ? 1.0f : total_weight4;
311 grad4 /= total_weight4;
314 if (grad4.norm() > 0) {
315 nGrad4 = grad4 / grad4.norm();
318 Real energy_solid = grad4.dot(grad4);
319 Coord shift4 = w4 * energy_solid*nGrad4;
321 Real max_ax = abs(shift4[0]);
322 if (abs(shift4[1]) > max_ax) max_ax = abs(shift4[1]);
323 if (abs(shift4[2]) > max_ax) max_ax = abs(shift4[2]);
325 Real threash = 0.00005;
326 if (max_ax > threash)
327 for (int i = 0; i < 3; ++i)
330 shift4[i] *= threash;
333 atomicAdd(&grads[pId][0], w1*grad1_i[0] + w2 * grad2[0] - w3 * energy*nGrad3[0] - shift4[0]);
334 atomicAdd(&grads[pId][1], w1*grad1_i[1] + w2 * grad2[1] - w3 * energy*nGrad3[1] - shift4[1]);
335 atomicAdd(&grads[pId][2], w1*grad1_i[2] + w2 * grad2[2] - w3 * energy*nGrad3[2] - shift4[2]);
338 template <typename Coord>
339 __global__ void SAPS_UpdatePosition(
341 DArray<Coord> curPos)
343 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
344 if (pId >= curPos.size()) return;
346 curPos[pId] += grads[pId];
349 template <typename Real, typename Coord>
350 __global__ void SAPS_UpdateVelocity(
351 DArray<Coord> velArr,
352 DArray<Coord> curArr,
353 DArray<Coord> originArr,
354 DArray<Coord> TriDir,//normal of boundary
357 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
358 if (pId >= velArr.size()) return;
360 Plane3D PL(curArr[pId], TriDir[pId]);
361 Point3D origP(originArr[pId]);
362 Point3D projectedP = origP.project(PL);
363 Coord boundary_vec = projectedP.origin - curArr[pId];
364 if (boundary_vec.norm() > 0)
365 boundary_vec /= boundary_vec.norm();
367 Real fr = 0.97f;//0.96f
369 boundary_vec[0] = 1.0f - abs(boundary_vec[0]);
370 boundary_vec[1] = 1.0f - abs(boundary_vec[1]);
371 boundary_vec[2] = 1.0f - abs(boundary_vec[2]);
373 velArr[pId] += (curArr[pId] - originArr[pId]) / dt;
375 //*********boundary friction part
376 if (boundary_vec.norm() > 0) {
377 if (abs(boundary_vec[0]) > fr)
378 velArr[pId][0] *= boundary_vec[0];
380 velArr[pId][0] *= fr;
381 if (abs(boundary_vec[1]) > fr)
382 velArr[pId][1] *= boundary_vec[1];
384 velArr[pId][1] *= fr;
385 if (abs(boundary_vec[2]) > fr)
386 velArr[pId][2] *= boundary_vec[2];
388 velArr[pId][2] *= fr;
392 template<typename TDataType>
393 void SemiAnalyticalParticleShifting<TDataType>::compute()
395 Real dt = this->inTimeStep()->getData();
397 int num = this->inPosition()->size();
399 mDeltaPos.resize(num);
401 mAdhesionEP.resize(num);
403 mBoundaryDir.resize(num);
404 mBoundaryDis.resize(num);
407 mBoundaryDir.reset();
408 mBoundaryDis.reset();
410 Real d = mCalculateDensity->inSamplingDistance()->getValue();
411 Real rho_0 = mCalculateDensity->varRestDensity()->getValue();
412 Real mass = d * d*d*rho_0;
414 auto ts = this->inTriangleSet()->constDataPtr();
415 auto& triVertex = ts->getPoints();
416 auto& triIndex = ts->getTriangles();
418 mCalculateDensity->update();
420 mPosBuf.assign(inPosition()->getData());
423 uint maxIter = this->varInterationNumber()->getData();
424 while (iter++ < maxIter)
428 mCalculateDensity->update();
430 if (this->inNeighborTriIds()->getData().size() > 0) {
432 SAPS_ComputeBoundaryGradient,
436 this->inPosition()->getData(),
437 this->inNeighborIds()->getData(),
438 this->inNeighborTriIds()->getData(),
441 this->inSmoothingLength()->getData());
449 mCalculateDensity->outDensity()->getData(),
450 this->inPosition()->getData(),
452 this->inNeighborIds()->getData(),
454 this->inSmoothingLength()->getData(),
455 this->varInertia()->getData(),
456 this->varBulk()->getData(),
457 this->varSurfaceTension()->getData(),
458 this->varAdhesionIntensity()->getData());
463 this->inPosition()->getData());
468 this->inVelocity()->getData(),
469 this->inPosition()->getData(),
475 DEFINE_CLASS(SemiAnalyticalParticleShifting);