1#include <cuda_runtime.h>
2#include "DualParticleIsphModule.h"
5#include "ParticleSystem/Module/SummationDensity.h"
6#include "Collision/Attribute.h"
7#include "ParticleSystem/Module/Kernel.h"
8#include "Algorithm/Function2Pt.h"
9#include "Algorithm/CudaRand.h"
14 IMPLEMENT_TCLASS(DualParticleIsphModule, TDataType)
16 template<typename TDataType>
17 DualParticleIsphModule<TDataType>::DualParticleIsphModule()
19 , m_airPressure(Real(0))
23 this->inParticleAttribute()->tagOptional(true);
24 this->inBoundaryNorm()->tagOptional(true);
26 this->varSamplingDistance()->setValue(Real(0.005));
27 this->varRestDensity()->setValue(Real(1000));
28 this->varSmoothingLength()->setValue(Real( 0.0125));
29 this->varPpeSmoothingLength()->setValue(Real( 0.0125));
31 m_summation = std::make_shared<SummationDensity<TDataType>>();
32 this->varRestDensity()->connect(m_summation->varRestDensity());
33 this->varSmoothingLength()->connect(m_summation->inSmoothingLength());
34 this->varSamplingDistance()->connect(m_summation->inSamplingDistance());
35 this->inRPosition()->connect(m_summation->inPosition());
36 this->inNeighborIds()->connect(m_summation->inNeighborIds());
38 m_vr_summation = std::make_shared<SummationDensity<TDataType>>();
39 this->varRestDensity()->connect(m_vr_summation->varRestDensity());
40 this->varSmoothingLength()->connect(m_vr_summation->inSmoothingLength());
41 this->varSamplingDistance()->connect(m_vr_summation->inSamplingDistance());
42 this->inVPosition()->connect(m_vr_summation->inPosition());
43 this->inRPosition()->connect(m_vr_summation->inOther());
44 this->inVRNeighborIds()->connect(m_vr_summation->inNeighborIds());
46 m_vv_summation = std::make_shared<SummationDensity<TDataType>>();
47 this->varRestDensity()->connect(m_vv_summation->varRestDensity());
48 this->varSmoothingLength()->connect(m_vv_summation->inSmoothingLength());
49 this->varSamplingDistance()->connect(m_vv_summation->inSamplingDistance());
50 this->inVPosition()->connect(m_vv_summation->inPosition());
51 this->inVVNeighborIds()->connect(m_vv_summation->inNeighborIds());
55 template<typename TDataType>
56 DualParticleIsphModule<TDataType>::~DualParticleIsphModule()
61 m_virtualAirFlag.clear();
62 m_virtualAirWeight.clear();
64 m_solidVirtualPaticleFlag.clear();
65 m_virtualVelocity.clear();
72 m_GpNearSolid.clear();
89 template <typename Vec4, typename Matrix4x4>
90 __device__ inline Vec4 MatrixDotVector(const Matrix4x4 M, const Vec4 V)
93 V[0] * M(0, 0) + V[1] * M(0, 1) + V[2] * M(0, 2) + V[3] * M(0, 3),
94 V[0] * M(1, 0) + V[1] * M(1, 1) + V[2] * M(1, 2) + V[3] * M(1, 3),
95 V[0] * M(2, 0) + V[1] * M(2, 1) + V[2] * M(2, 2) + V[3] * M(2, 3),
96 V[0] * M(3, 0) + V[1] * M(3, 1) + V[2] * M(3, 2) + V[3] * M(3, 3)
101 * Name : UpdateVelocity;
102 * Function : Update velocities with the pressure gradient field;
103 * Formular : vi = vi + dt * Gp / rho;
105 template <typename Real, typename Coord>
106 __global__ void DualParticle_UpdateVelocity(
107 DArray<Coord> gradientPress,
108 DArray<Coord> velocity,
109 DArray<Real> density,
114 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
115 if (pId >= velocity.size()) return;
117 Coord temp = dt * gradientPress[pId] / density[pId];
118 velocity[pId] = velocity[pId] - temp;
122 template<typename TDataType>
123 bool DualParticleIsphModule<TDataType>::virtualArraysResize()
125 int num = this->inRPosition()->size();
126 int num_v = this->inVPosition()->size();
128 if (m_pressure.size() != num_v)
129 m_pressure.resize(num_v);
131 if (m_Ax.size() != num_v)
133 if (m_Aii.size() != num_v)
135 if (m_r.size() != num_v)
137 if (m_p.size() != num_v)
139 if (m_virtualAirFlag.size() != num_v)
140 m_virtualAirFlag.resize(num_v);
141 if (m_source.size() != num_v)
142 m_source.resize(num_v);
143 if (m_virtualVelocity.size() != num_v)
144 m_virtualVelocity.resize(num_v);
145 if (m_solidVirtualPaticleFlag.size() != num_v)
146 m_solidVirtualPaticleFlag.resize(num_v);
147 if (this->outVirtualBool()->isEmpty())
148 this->outVirtualBool()->allocate();
149 if (this->outVirtualWeight()->isEmpty())
150 this->outVirtualWeight()->allocate();
151 if (this->outVirtualBool()->size() != num_v)
152 this->outVirtualBool()->resize(num_v);
153 if (this->outVirtualWeight()->size() != num_v)
154 this->outVirtualWeight()->resize(num_v);
159 m_reduce = Reduction<float>::Create(num_v);
163 m_reduce = Reduction<float>::Create(num_v);
169 m_arithmetic = Arithmetic<float>::Create(num_v);
173 m_arithmetic = Arithmetic<float>::Create(num_v);
178 template<typename TDataType>
179 bool DualParticleIsphModule<TDataType>::realArraysResize()
181 int num = this->inRPosition()->size();
183 if (m_Gp.size() != num)
186 if (m_GpNearSolid.size() != num)
187 m_GpNearSolid.resize(num);
189 //if (m_arithmetic_r)
191 // delete m_arithmetic_r;
192 // m_arithmetic_r = Arithmetic<float>::Create(num);
196 // m_arithmetic_r = Arithmetic<float>::Create(num);
204 * Name : DualParticle_SolidVirtualParticleDetect
205 * Function : A virtual particle is Neumann boundary particle or not?
207 template <typename Real, typename Coord>
208 __global__ void DualParticle_VirtualSolidParticleDetection(
209 DArray<bool> solidVirtual,
210 DArray<Real> fluidFraction,
211 DArray<Coord> virtualPosition,
212 DArray<Coord> realPosition,
213 DArray<Attribute> attribute,
214 DArray<Real> density,
215 DArrayList<int> vr_neighbors,
216 DArray<bool> virtualAir,
217 CubicKernel<Real> kernel,
223 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
224 if (pId >= solidVirtual.size()) return;
226 solidVirtual[pId] = false;
228 List<int> & list_i_vr = vr_neighbors[pId];
229 int nbSize = list_i_vr.size();
232 for (int ne = 0; ne < nbSize; ne++)
234 int j = list_i_vr[ne];
235 Real r_ij = (virtualPosition[pId] - realPosition[j]).norm();
236 if (!attribute[j].isFluid())
238 c += kernel.Weight(r_ij, h) * mass / density[j];
240 w += kernel.Weight(r_ij, h) * mass / density[j];
243 if (w < EPSILON) w = EPSILON;
244 fluidFraction[pId] = c / w;
248 if (fluidFraction[pId] > threshold)
250 solidVirtual[pId] = true;
254 solidVirtual[pId] = false;
263 template <typename Real, typename Coord>
264 __global__ void DualParticle_SolidBoundaryDivergenceCompsate(
266 DArray<bool> solidVirtual,
267 DArray<bool> airVirtual,
268 DArray<Coord> virtualVelocity,
269 DArray<Coord> realVelocity,
270 DArray<Coord> virtualPosition,
271 DArray<Coord> realPosition,
272 DArray<Attribute> attribute,
274 DArray<Real> density,
275 DArrayList<int> vr_neighbors,
276 CubicKernel<Real> kernel,
283 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
284 if (pId >= virtualPosition.size()) return;
285 if (solidVirtual[pId] == true) return;
286 if (airVirtual[pId] == true) return;
288 List<int> & list_i_vr = vr_neighbors[pId];
289 int nbSize_vr = list_i_vr.size();
292 for (int ne = 0; ne < nbSize_vr; ne++)
294 int j = list_i_vr[ne];
295 if (!attribute[j].isFluid())
298 Real r_ij = (virtualPosition[pId] - realPosition[j]).norm();
301 if (r_ij > EPSILON && !attribute[j].isFluid())
304 Coord dVel = virtualVelocity[pId] - realVelocity[j];
305 Real magNVel = dVel.dot(norm[j]);
306 Coord nVel = magNVel * norm[j];
307 Coord tVel = dVel - nVel;
310 Gwij = kernel.Gradient(r_ij, h) * (virtualPosition[pId] - realPosition[j]) / r_ij;
313 if (magNVel < -EPSILON)
315 value += 2 * (nVel + 0.01*tVel).dot(Gwij) * mass / density[pId];
319 value += 2 * (0.1 * nVel + 0.01*tVel).dot(Gwij) * mass / density[pId];
328 source[pId] -= -value * restDensity / dt;
333 * @briedf Use CSPH method to calculate the virtual particle velocity;
334 * Virtual-air particle velocity should be zero;
338 template <typename Real, typename Coord>
339 __global__ void DualParticle_SmoothVirtualVelocity(
340 DArray<Coord> virtualVelocity,
341 DArray<Coord> velocity,
342 DArray<Coord> virtualPosition,
343 DArray<Coord> realPosition,
344 DArrayList<int> vr_neighbors,
345 DArray<bool> virtualAir,
346 DArray<bool> virtualSolid,
347 DArray<Real> density,
348 CubicKernel<Real> kernel,
353 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
354 if (pId >= virtualPosition.size()) return;
355 if (virtualSolid[pId] == true) return;
356 if (virtualAir[pId] == true)
358 virtualVelocity[pId] = Coord(0.0f);
362 List<int> & list_i_vr = vr_neighbors[pId];
363 int nbSize_vr = list_i_vr.size();
366 for (int ne = 0; ne < nbSize_vr; ne++)
368 int j = list_i_vr[ne];
369 Real r_ij = (virtualPosition[pId] - realPosition[j]).norm();
370 Real wij = kernel.Weight(r_ij ,h);
372 total_vw += velocity[j] * wij;
375 if (total_w > EPSILON)
377 if (nbSize_vr == 0) printf("1-ERROR: pId %d \r\n", pId);
378 virtualVelocity[pId] = total_vw / total_w;
382 if (nbSize_vr != 0) printf("0-ERROR: pId %d \r\n", pId);
383 virtualVelocity[pId] = Coord(0.0f);
388 template <typename Real, typename Coord>
389 __global__ void DualParticle_SourceTerm(
391 DArray<Coord> virtualVelocity,
392 DArray<Coord> velocity,
393 DArray<Coord> virtualPosition,
394 DArray<Coord> realPosition,
395 DArray<Real> density,
396 DArray<Real> vdensity,
397 DArrayList<int> vr_neighbors,
398 DArray<Attribute> attribute,
399 DArray<bool> virtualAir,
400 DArray<bool> virtualSolid,
401 DArray<Coord> boundaryNorm,
402 CubicKernel<Real> kernel,
409 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
410 if (pId >= source.size()) return;
411 if (virtualSolid[pId] == true)
417 if (virtualAir[pId] == true)
423 List<int> & list_i_vr = vr_neighbors[pId];
424 int nbSize_vr = list_i_vr.size();
427 for (int ne = 0; ne < nbSize_vr; ne++)
429 int j = list_i_vr[ne];
430 Real r_ij = (virtualPosition[pId] - realPosition[j]).norm();
432 if(r_ij > EPSILON & attribute[j].isFluid())
434 Gwij = kernel.Gradient(r_ij, h) * (virtualPosition[pId] - realPosition[j]) / r_ij;
436 value += (velocity[j] - virtualVelocity[pId]).dot(Gwij) * mass / vdensity[pId];
438 source[pId] = -value * restDensity / dt;
443 * Name: VirtualAirParticleDetection
444 * Return: Virtual-air particle flag
445 * Function: rho_v(virtual particles'real density) < threashold ? true: false
447 template <typename Real>
448 __global__ void DualParticle_VirtualAirParticleDetection
450 DArray<bool> m_virtualAirFlag,
451 DArrayList<int> vr_neighbors,
456 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
457 if (pId >= m_virtualAirFlag.size()) return;
459 List<int> & list_i_vr = vr_neighbors[pId];
460 int nbSize_vr = list_i_vr.size();
463 if ((rho_v[pId] > threshold) && (nbSize_vr > 0))
465 m_virtualAirFlag[pId] = false;
470 m_virtualAirFlag[pId] = true;
477 template <typename Real, typename Coord>
478 __global__ void DualParticle_LaplacianPressure
482 DArray<Real> pressure,
484 DArray<bool> virtualAir,
485 DArray<bool> virtualSolid,
486 DArrayList<int> vv_neighbors,
488 CubicKernel<Real> kernel,
493 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
494 if (pId >= Ax.size()) return;
495 if (virtualSolid[pId] == true)
501 if (virtualAir[pId] == true)
504 pressure[pId] = 0.0f;
507 List<int> & list_i = vv_neighbors[pId];
508 int nbSize_i = list_i.size();
511 for (int ne = 0; ne < nbSize_i; ne++)
515 Real rij = (v_pos[pId] - v_pos[j]).norm();
519 if (rij > EPSILON && virtualAir[j] == false && virtualSolid[j] == false)
520 //if (rij > EPSILON && virtualAir[j] == false)
522 Real dwij = kernel.Gradient(rij, h) / rij;
523 temp += 8 * mass * dwij / pow((rho_vv[pId] + rho_vv[j]), 2) * pressure[j];
527 Ax[pId] = Aii[pId] * pressure[pId] + temp;
533 template <typename Real, typename Coord>
534 __global__ void DualParticle_AiiInLaplacian
538 DArray<bool> virtualAir,
539 DArray<bool> virtualSolid,
540 DArrayList<int > vv_neighbors,
542 CubicKernel<Real> kernel,
547 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
548 if (pId >= Aii.size()) return;
549 if (virtualSolid[pId] == true) return;
550 if (virtualAir[pId] == true) {
554 List<int> & list_i = vv_neighbors[pId];
555 int nbSize_i = list_i.size();
559 for (int ne = 0; ne < nbSize_i; ne++)
563 Real rij = (v_pos[pId] - v_pos[j]).norm();
565 //if (rij > EPSILON && virtualAir[j] == false && virtualSolid[j] == false)
566 if (rij > EPSILON && virtualAir[j] == false)
568 Real dwij = kernel.Gradient(rij, h) / rij;
569 temp += 8 * mass * dwij / pow((rho_vv[pId] + rho_vv[j]), 2);
577 * @brief: Using SPH aproach to calculate Gradient pressures of fluid particles.
579 template <typename Real, typename Coord>
580 __global__ void DualParticle_GradientPressure
582 DArray<Coord> gradient,
583 DArray<Real> pressure,
584 DArray<Coord> velocity,
587 DArray<Attribute> attribute,
588 DArray<bool> virtualAir,
589 DArray<bool> virtualSolid,
590 DArrayList<int> vr_neighbors,
591 DArrayList<int> rv_neighbors,
594 CubicKernel<Real> kernel,
601 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
603 if (pId >= gradient.size()) return;
604 if (!attribute[pId].isFluid()) return;
607 List<int> & list_i_rv = rv_neighbors[pId];
608 int nbSize_i = list_i_rv.size();
610 for (int ne = 0; ne < nbSize_i; ne++)
612 int j = list_i_rv[ne];
613 Real r_ij = (r_pos[pId] - v_pos[j]).norm();
614 if ((r_ij > EPSILON) && (virtualAir[j] != true) && (virtualSolid[j] != true))
616 value += (mass / rho_0) * pressure[j] * (r_pos[pId] - v_pos[j]) * kernel.Gradient(r_ij, h) / r_ij;
619 value = value * dt / rho_0;
620 gradient[pId] = value;
621 //Coord v = velocity[pId];
622 velocity[pId] -= gradient[pId] ;
628 * Gradient correction Martrix
629 * @Paper: Fang et al 2009.
630 * @Paper: Improved SPH methods for simulating free surface flows of viscous fluids
631 * @Paper: Applied Numerical Mathematics 59 (2009) 251¨C271
634 template <typename Real, typename Coord>
635 __global__ void DualParticle_ImprovedGradient(
636 DArray<Coord> improvedGradient,
637 DArrayList<int> rv_neighbors,
641 DArray<bool> virtualAir,
642 DArray<bool> virtualSolid,
643 CubicKernel<Real> kernel,
649 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
650 if (pId >= improvedGradient.size()) return;
652 Real V = mass / rho_0;
654 List<int> & list_i_rr = rv_neighbors[pId];
655 int nbSize_i = list_i_rr.size();
656 for (int ne = 0; ne < nbSize_i; ne++)
658 int j = list_i_rr[ne];
659 Coord xij = rpos[pId] - vpos[j];
660 Real rij = xij.norm();
661 Coord nij = xij / rij;
662 Real weight = kernel.Weight(rij, h);
663 Real dweight = kernel.Gradient(rij, h);
665 C[0][1] += xij[0] * weight;
666 C[0][2] += xij[1] * weight;
667 C[0][3] += xij[2] * weight;
669 C[1][0] += nij[0] * dweight;
670 C[1][1] += xij[0] * nij[0] * dweight;
671 C[1][2] += xij[1] * nij[0] * dweight;
672 C[1][3] += xij[2] * nij[0] * dweight;
674 C[2][0] += nij[1] * dweight;
675 C[2][1] += xij[0] * nij[1] * dweight;
676 C[2][2] += xij[1] * nij[1] * dweight;
677 C[2][3] += xij[2] * nij[1] * dweight;
679 C[3][0] += nij[2] * dweight;
680 C[3][1] += xij[0] * nij[2] * dweight;
681 C[3][2] += xij[1] * nij[2] * dweight;
682 C[3][3] += xij[2] * nij[2] * dweight;
690 printf("GLM:INVERSE:");
691 for (int ci = 0; ci < 4; ci++)
693 for (int cj = 0; cj < 4; cj++)
695 printf("%f, ", C[ci][cj]);
705 * @brief: Modify gradient pressures if the fluid particle near solids.
706 * @Paper: Bridson. Fluid simulation for computer graphics, Second Edition. (Section 5.1, The Discrete Pressure Gradient)
709 template <typename Real, typename Coord>
710 __global__ void DualParticle_GradientNearSolid
712 DArray<Coord> gradidentComp,
713 DArray<Coord> velocity,
716 DArray<Attribute> attribute,
718 DArray<bool> virtualAir,
719 DArray<bool> virtualSolid,
720 DArrayList<int> rr_neighbors,
723 CubicKernel<Real> kernel,
730 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
731 if (pId >= gradidentComp.size()) return;
733 gradidentComp[pId] = Coord(0.0f);
735 List<int> & list_i_rr = rr_neighbors[pId];
736 int nbSize_i = list_i_rr.size();
737 Coord & vel_i = velocity[pId];
739 for (int ne = 0; ne < nbSize_i; ne++)
741 int j = list_i_rr[ne];
742 Real r_ij = (r_pos[pId] - r_pos[j]).norm();
743 Real weight = kernel.Weight(r_ij, h);
744 if (!attribute[j].isFluid())
747 Coord nij = (r_pos[pId] - r_pos[j]);
748 if(nij.norm() > EPSILON)
750 nij = nij.normalize();
754 nij = Coord(1.0f, 0.0f, 0.0f);
757 Coord normal_j = norm[j];
758 Coord dVel = vel_i - velocity[j];
759 Real magNVel = dVel.dot(normal_j);
760 Coord nVel = magNVel * normal_j;
761 Coord tVel = dVel - nVel;
762 if (magNVel < -EPSILON)
764 dvij += nij.dot(nVel + 0.01 * dVel) * weight * nij;
768 dvij += nij.dot(0.1 * nVel + 0.01 * dVel) * weight * nij;
774 gradidentComp[pId] = 2 * dt * dvij / rho_0;
775 velocity[pId] -= gradidentComp[pId];
779 * @brief: Semi-analytical Dirichlet boundary.
780 * @Paper: Nair and Tomar, Computers & Fluids, 2014, 10(102): 304-314, An improved free surface modeling for incompressible SPH.
782 template <typename Real>
783 __global__ void DualParticle_CorrectAii
790 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
791 if (pId >= Aii.size()) return;
792 max_Aii = max_Aii * c;
793 Real temp = Aii[pId];
802 * @brief: Modified density drifting error (Liu, et al. Tog 2024, Equation 13.)
803 * @Paper: Abbas Khayyer and Hitoshi Gotoh. J. Comput. Phys. 230, 8 (2011). Enhancement of stability and accuracy of the moving particle semi-implicit method
805 template <typename Real>
806 __global__ void DualParticle_DensityCompensate
810 DArray<bool> virtualAir,
811 DArray<bool> virtualSolid,
817 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
818 if (pId >= source.size()) return;
819 if (virtualSolid[pId] == true)
824 if (virtualAir[pId] == true)
829 if (rho[pId] > rho_0)
831 source[pId] += 1000000.0f * (rho[pId] - rho_0) / rho_0;
837 * @brief: Neumann Boundary in Matrix of pressrue Poisson eqtution.
838 * @Paper: Bridson. Fluid simulation for computer graphics, Second Edition. (Section 5.3, The Pressure Equations.)
840 template <typename Real, typename Coord>
841 __global__ void DualParticle_AiiNeumannCorrect
844 DArray<bool> virtualAir,
845 DArray<bool> virtualSolid,
846 DArrayList<int > vv_neighbors,
849 CubicKernel<Real> kernel,
855 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
856 if (pId >= Aii.size()) return;
857 if (virtualSolid[pId] == true) return;
858 if (virtualAir[pId] == true) return;
860 List<int> & list_i = vv_neighbors[pId];
861 int nbSize_i = list_i.size();
864 int solidCounter = 0;
866 for (int ne = 0; ne < nbSize_i; ne++)
870 Real rij = (v_pos[pId] - v_pos[j]).norm();
872 //if (rij > EPSILON && virtualAir[j] == false && virtualSolid[j] == true)
873 if (rij > EPSILON && virtualSolid[j] == true)
875 Real dwij = kernel.Gradient(rij, h) / rij;
876 temp += 8 * mass * dwij / pow((rho_vv[pId] + rho_vv[j]), 2);
881 Real value = Aii[pId] + temp;
885 template <typename Coord>
886 __global__ void DualParticle_SolidVelocityReset
888 DArray<Coord> velocity,
889 DArray<Attribute> attribute
892 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
893 if (pId >= velocity.size()) return;
895 if (!attribute[pId].isFluid())
897 velocity[pId] = Coord(0.0f);
904 template <typename Real>
905 __global__ void DualParticle_VolumeTest
908 DArray<Real> density,
912 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
913 if (pId >= volume.size()) return;
915 volume[pId] = mass / density[pId];
919 template <typename Real>
920 __global__ void DualParticle_VirtualVolumeTest
923 DArray<Real> density,
928 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
929 if (pId >= volume.size()) return;
930 if (air[pId] == false)
931 volume[pId] = mass / density[pId];
938 * @brief: Using euleric finite divegence aproach to calculate Gradient pressures
940 template <typename Real, typename Coord>
941 __global__ void DualParticle_VirtualGradientPressureFD(
944 DArrayList<int> vv_neighbors,
945 DArray<Real> pressure,
946 DArray<bool> virtualAir,
947 DArray<bool> virtualSolid,
951 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
952 if (pId >= vpos.size()) return;
954 List<int> & list_i = vv_neighbors[pId];
955 int nbSize_i = list_i.size();
958 for (int ne = 0; ne < nbSize_i; ne++)
961 Real rij = (vpos[pId] - vpos[j]).norm();
962 if ((rij < dx)&&(rij > EPSILON))
965 gp += (pressure[pId] - pressure[j]) * (vpos[pId] - vpos[j]) / rij;
973 template <typename Real, typename Coord>
974 __global__ void DualParticle_VirtualGradientPressureMeshless(
977 DArrayList<int> vv_neighbors,
978 DArray<Real> pressure,
979 DArray<bool> virtualAir,
980 DArray<bool> virtualSolid,
981 CubicKernel<Real> kernel,
987 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
988 if (pId >= vpos.size()) return;
990 if (virtualAir[pId] == true)
992 vGp[pId] = Coord(0.0f);
996 List<int> & list_i = vv_neighbors[pId];
997 int nbSize_i = list_i.size();
1000 for (int ne = 0; ne < nbSize_i; ne++)
1003 Real rij = (vpos[pId] - vpos[j]).norm();
1006 dwij = kernel.Gradient(rij, h);
1007 value += mass * (pressure[j] - pressure[pId]) * dwij * (vpos[pId] - vpos[j]) / (rij * rho_0);
1008 //value += mass * (pressure[j]) * dwij * (vpos[pId] - vpos[j]) / (rij * rho_0);
1018 * @brief: Using moving least square aproach to calculate Gradient pressures
1020 template <typename Real, typename Coord, typename Vector4, typename Matrix4x4>
1021 __global__ void DualParticle_MlsGradientPressure(
1023 DArray<Coord> velocity,
1027 DArrayList<int> rv_neighbors,
1028 DArray<Real> pressure,
1029 CubicKernel<Real> kernel,
1035 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
1036 if (pId >= velocity.size()) return;
1039 List<int> & list_i = rv_neighbors[pId];
1040 int nbSize_i = list_i.size();
1042 Vector4 P(0.0f); /* Basis Function: P((xi - xj)/h) */
1043 Vector4 P0(0.0f); /* Basis Function: P(0) */
1044 Matrix4x4 M(0.0f); /* Momentum Matrix of MLS*/
1045 Real dx_Ji(0.0f); /* (xi - xj)/h*/
1046 Real dy_Ji(0.0f); /* (yi - yj)/h*/
1047 Real dz_Ji(0.0f); /* (zi - zj)/h*/
1048 Real wij(0.0f); /*Weight*/
1053 for (int ne = 0; ne < nbSize_i; ne++)
1056 rij = (rpos[pId] - vpos[j]).norm();
1057 wij = kernel.Weight(rij, h);
1059 dx_Ji = (vpos[j] - rpos[pId])[0] / h;
1060 dy_Ji = (vpos[j] - rpos[pId])[1] / h;
1061 dz_Ji = (vpos[j] - rpos[pId])[2] / h;
1063 M(0, 0) += wij; M(0, 1) += wij * dx_Ji; M(0, 2) += wij * dy_Ji; M(0, 3) += wij * dz_Ji;
1064 M(1, 0) += wij * dx_Ji; M(1, 1) += wij * dx_Ji * dx_Ji; M(1, 2) += wij * dx_Ji * dy_Ji; M(1, 3) += wij * dx_Ji * dz_Ji;
1065 M(2, 0) += wij * dy_Ji; M(2, 1) += wij * dx_Ji * dy_Ji; M(2, 2) += wij * dy_Ji * dy_Ji; M(2, 3) += wij * dy_Ji * dz_Ji;
1066 M(3, 0) += wij * dz_Ji; M(3, 1) += wij * dx_Ji * dz_Ji; M(3, 2) += wij * dy_Ji * dz_Ji; M(3, 3) += wij * dz_Ji * dz_Ji;
1069 Matrix4x4 M_inv = M.inverse();
1073 for (int ne = 0; ne < nbSize_i; ne++)
1076 rij = (rpos[pId] - vpos[j]).norm();
1077 wij = kernel.Weight(rij, h);
1079 dx_Ji = (vpos[j] - rpos[pId])[0] / h;
1080 dy_Ji = (vpos[j] - rpos[pId])[1] / h;
1081 dz_Ji = (vpos[j] - rpos[pId])[2] / h;
1093 tgp += P0.dot(MatrixDotVector(M_inv, P)) * wij * vGp[j];
1097 rGp[pId] = dt * tgp / rho_0;
1099 velocity[pId] -= rGp[pId];
1104 __global__ void DualParticle_AttributeInit
1106 DArray<Attribute> atts
1109 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
1110 if (pId >= atts.size()) return;
1112 atts[pId].setFluid();
1113 atts[pId].setDynamic();
1116 template<typename TDataType>
1117 void DualParticleIsphModule<TDataType>::constrain()
1119 int num = this->inRPosition()->size();
1120 int num_v = this->inVPosition()->size();
1122 cudaDeviceSynchronize();
1124 if (m_Gp.size() != num)
1128 if (m_Ax.size() != num_v)
1130 virtualArraysResize();
1133 auto & m_virtualSolidFlag = this->outVirtualBool()->getData();
1134 Real dt = this->inTimeStep()->getData();
1135 Real h1 = this->varSmoothingLength()->getData();
1136 Real h2 = this->varPpeSmoothingLength()->getData();
1139 if (this->inParticleAttribute()->isEmpty()
1140 || this->inParticleAttribute()->size() != num
1141 || this->inBoundaryNorm()->size() != num
1144 this->inParticleAttribute()->allocate();
1145 this->inParticleAttribute()->resize(num);
1146 cuExecute(num, DualParticle_AttributeInit, this->inParticleAttribute()->getData());
1147 this->inBoundaryNorm()->resize(num);
1148 this->inBoundaryNorm()->reset();
1152 m_summation->update();
1153 m_vv_summation->update();
1154 m_vr_summation->update();
1156 m_particleMass = m_summation->getParticleMass();
1157 m_v_particleMass = m_vv_summation->getParticleMass();
1159 Real restDensity= this->varRestDensity()->getValue();
1161 Real MaxVirtualDensity =
1163 m_vr_summation->outDensity()->getData().begin(),
1164 m_vr_summation->outDensity()->getData().size()
1167 cuExecute(num_v, DualParticle_VirtualAirParticleDetection,
1169 this->inVRNeighborIds()->getData(),
1170 m_vr_summation->outDensity()->getData(),
1171 MaxVirtualDensity * 0.1f
1174 cuExecute(num_v, DualParticle_VirtualSolidParticleDetection,
1176 this->outVirtualWeight()->getData(),
1177 this->inVPosition()->getData(),
1178 this->inRPosition()->getData(),
1179 this->inParticleAttribute()->getData(),
1180 m_summation->outDensity()->getData(),
1181 this->inVRNeighborIds()->getData(),
1189 cuExecute(num_v, DualParticle_SmoothVirtualVelocity,
1191 this->inVelocity()->getData(),
1192 this->inVPosition()->getData(),
1193 this->inRPosition()->getData(),
1194 this->inVRNeighborIds()->getData(),
1197 m_summation->outDensity()->getData(),
1205 cuExecute(num, DualParticle_SolidVelocityReset,
1206 this->inVelocity()->getData(),
1207 this->inParticleAttribute()->getData()
1210 cuExecute(num_v, DualParticle_SourceTerm,
1213 this->inVelocity()->getData(),
1214 this->inVPosition()->getData(),
1215 this->inRPosition()->getData(),
1216 m_summation->outDensity()->getData(),
1217 m_vr_summation->outDensity()->getData(),
1218 this->inVRNeighborIds()->getData(),
1219 this->inParticleAttribute()->getData(),
1222 this->inBoundaryNorm()->getData(),
1230 cuExecute(num_v, DualParticle_SolidBoundaryDivergenceCompsate,
1235 this->inVelocity()->getData(),
1236 this->inVPosition()->getData(),
1237 this->inRPosition()->getData(),
1238 this->inParticleAttribute()->getData(),
1239 this->inBoundaryNorm()->getData(),
1240 m_vr_summation->outDensity()->getData(),
1241 this->inVRNeighborIds()->getData(),
1249 cuExecute(num_v, DualParticle_DensityCompensate,
1251 m_vr_summation->outDensity()->getData(),
1262 if (m_pressure.size() != virtualNumber_old)
1267 virtualNumber_old = m_pressure.size();
1269 cuExecute(num_v, DualParticle_AiiInLaplacian,
1271 this->inVPosition()->getData(),
1274 this->inVVNeighborIds()->getData(),
1275 m_vv_summation->outDensity()->getData(),
1281 if ((frag_number <= 3) || abs(max_Aii) < EPSILON)
1283 //if(m_reduce->maximum(m_Aii.begin(), m_Aii.size()) > 0)
1284 max_Aii = m_reduce->maximum(m_Aii.begin(), m_Aii.size());
1287 cuExecute(num_v, DualParticle_CorrectAii,
1293 cuExecute(num_v, DualParticle_AiiNeumannCorrect,
1297 this->inVVNeighborIds()->getData(),
1298 m_vv_summation->outDensity()->getData(),
1299 this->inVPosition()->getData(),
1306 cuExecute(num_v, DualParticle_LaplacianPressure,
1310 this->inVPosition()->getData(),
1313 this->inVVNeighborIds()->getData(),
1314 m_vv_summation->outDensity()->getData(),
1320 Function2Pt::subtract(m_r, m_source, m_Ax);
1323 Real rr = m_arithmetic->Dot(m_r, m_r);
1324 Real err = m_r.size() > 0 ? sqrt(rr / m_r.size()) : 0.0f;
1326 if (abs(max_err) < EPSILON) max_err = EPSILON;
1327 unsigned int iter = 0;
1328 Real threshold = this->varResidualThreshold()->getValue();
1329 while ((iter < 500) && (err / max_err > threshold) && (err > threshold))
1335 cuExecute(num_v, DualParticle_LaplacianPressure,
1339 this->inVPosition()->getData(),
1342 this->inVVNeighborIds()->getData(),
1343 m_vv_summation->outDensity()->getData(),
1349 float alpha = rr / m_arithmetic->Dot(m_p, m_Ax);
1350 Function2Pt::saxpy(m_pressure, m_p, m_pressure, alpha);
1351 Function2Pt::saxpy(m_r, m_Ax, m_r, -alpha);
1355 rr = m_arithmetic->Dot(m_r, m_r);
1357 Real beta = rr / rr_old;
1358 Function2Pt::saxpy(m_p, m_p, m_r, beta);
1359 err = sqrt(rr / m_r.size());
1360 //std::cout<<"*DUAL-ISPH:: iter:"<< iter <<": Err-" << err << std::endl;
1362 std::cout << "*DUAL-ISPH::Solver::Iteration:" << iter << "||RelativeError:" << err/ max_err * 100 <<"%" << std::endl;
1364 m_GpNearSolid.reset();
1366 cuExecute(num, DualParticle_GradientPressure,
1369 this->inVelocity()->getData(),
1370 this->inVPosition()->getData(),
1371 this->inRPosition()->getData(),
1372 this->inParticleAttribute()->getData(),
1375 this->inVRNeighborIds()->getData(),
1376 this->inRVNeighborIds()->getData(),
1377 m_summation->outDensity()->getData(),
1378 m_vr_summation->outDensity()->getData(),
1386 cuExecute(num, DualParticle_GradientNearSolid,
1388 this->inVelocity()->getData(),
1389 this->inVPosition()->getData(),
1390 this->inRPosition()->getData(),
1391 this->inParticleAttribute()->getData(),
1392 this->inBoundaryNorm()->getData(),
1395 this->inNeighborIds()->getData(),
1396 m_summation->outDensity()->getData(),
1397 m_vr_summation->outDensity()->getData(),
1406 * Gradient Pressure On Virtual Points (Finite Difference)
1408 //DualParticle_VirtualGradientPressureFD << <pDims_r, BLOCK_SIZE >> > (
1410 // this->inVPosition()->getData(), //DArray<Coord> vpos,
1411 // this->inVVNeighborIds()->getData(), //DArrayList<int> vv_neighbors,
1412 // m_pressure, //DArray<Real> pressure,
1413 // m_virtualAirFlag, //DArray<bool> virtualAir,
1414 // m_virtualSolidFlag, //DArray<bool> virtualSolid,
1420 * Improved method for Gradient Pressure On Virtual Points
1422 //DualParticle_ImprovedGradient << <pDims_r, BLOCK_SIZE >> > (
1423 // m_improvedGradient,
1424 // this->inRVNeighborIds()->getData(),
1425 // this->inVPosition()->getData(),
1426 // this->inRPosition()->getData(),
1427 // m_vv_summation->outDensity()->getData(),
1428 // m_virtualAirFlag,
1429 // m_virtualSolidFlag,
1431 // m_v_particleMass,
1438 * Gradient Pressure On Virtual Points (SPH)
1440 //DualParticle_VirtualGradientPressureMeshless << <pDims_v, BLOCK_SIZE >> > (
1442 // this->inVPosition()->getData(), //DArray<Coord> vpos,
1443 // this->inVVNeighborIds()->getData(), //DArrayList<int> vv_neighbors,
1444 // //pseudoPressure,
1445 // m_pressure, ////DArray<Real> pressure,
1446 // m_virtualAirFlag, //DArray<bool> virtualAir,
1447 // m_virtualSolidFlag, //DArray<bool> virtualSolid,
1449 // m_v_particleMass,
1456 * Moving least square approgh for Gradient Pressure On Virtual Points (SPH)
1458 //DualParticle_MlsGradientPressure <Real, Coord, Vector<Real, 4>, SquareMatrix<Real , 4>> << <pDims_r, BLOCK_SIZE >> > (
1459 // m_rGp, //DArray<Coord> rGp,
1460 // this->inVelocity()->getData(),
1461 // m_vGp, //DArray<Coord> vGp,
1462 // this->inVPosition()->getData(), //DArray<Coord> vpos,
1463 // this->inRPosition()->getData(), //DArray<Coord> rpos,
1464 // this->inRVNeighborIds()->getData(), //DArrayList<int> rv_neighbors,
1465 // m_pressure, //DArray<Real> pressure,
1476 template<typename TDataType>
1477 bool DualParticleIsphModule<TDataType>::initializeImpl()
1481 int num = this->inRPosition()->size();
1482 int num_v = this->inVPosition()->size();
1484 m_reduce = Reduction<float>::Create(num_v);
1485 m_arithmetic = Arithmetic<float>::Create(num_v);
1486 // m_arithmetic_r = Arithmetic<float>::Create(num);
1491 DEFINE_CLASS(DualParticleIsphModule);