1#include "SurfaceParticleTracking.h"
3#include "GLPointVisualModule.h"
5#include "Algorithm/CudaRand.h"
9 IMPLEMENT_TCLASS(SurfaceParticleTracking, TDataType)
11 template<typename TDataType>
12 SurfaceParticleTracking<TDataType>::SurfaceParticleTracking()
15 auto ps = std::make_shared<PointSet<TDataType>>();
16 this->statePointSet()->setDataPtr(ps);
18 auto render = std::make_shared<GLPointVisualModule>();
19 render->varPointSize()->setValue(0.25);
20 render->varBaseColor()->setValue(Color(1, 1, 0.1));
21 this->statePointSet()->connect(render->inPointSet());
22 this->graphicsPipeline()->pushModule(render);
25 template<typename TDataType>
26 SurfaceParticleTracking<TDataType>::~SurfaceParticleTracking()
31 mPositionBuffer.clear();
37 template<typename TDataType>
38 bool SurfaceParticleTracking<TDataType>::validateInputs()
40 return this->importGranularMedia()->getDerivedNode() != nullptr;
43 template<typename TDataType>
44 void SurfaceParticleTracking<TDataType>::resetStates()
46 auto granular = this->importGranularMedia()->getDerivedNode();
48 Real ps = this->varSpacing()->getValue();
50 auto w = granular->varWidth()->getValue();
51 auto h = granular->varHeight()->getValue();
53 mNx = floor((w - 0.5f * ps) / ps) + 1;
54 mNy = floor((h - 0.5f * ps) / ps) + 1;
55 mNz = this->varLayer()->getValue() == 0 ? 1 : this->varLayer()->getValue();
57 mPosition.resize(mNx, mNy, mNz);
59 mMask.resize(mNx, mNy, mNz);
62 mPositionBuffer.resize(mNx, mNy, mNz);
63 mMaskBuffer.resize(mNx, mNy, mNz);
64 mMutex.resize(mNx, mNy, mNz);
72 template<typename Real>
73 __global__ void SPT_GenerateParticles(
74 DArray3D<Vector<Real, 3>> position,
75 DArray3D<bool> bExist,
80 int i = blockDim.x * blockIdx.x + threadIdx.x;
81 int j = blockIdx.y * blockDim.y + threadIdx.y;
82 int k = blockIdx.z * blockDim.z + threadIdx.z;
84 int nx = position.nx();
85 int ny = position.ny();
86 int nz = position.nz();
97 if (!(i % 2 == ci && j % 2 == cj && k % 2 == ck))
100 RandNumber gen(position.index(i, j, k));
106 position(i, j, k) = Vec3f(x, y, z);
107 bExist(i, j, k) = true;
110 template<typename TDataType>
111 void SurfaceParticleTracking<TDataType>::generate()
115 for (int ci = 0; ci < 2; ci++)
117 for (int cj = 0; cj < 2; cj++)
119 cuExecute3D(make_uint3(mNx, mNy, mNz),
120 SPT_GenerateParticles,
131 for (int ci = 0; ci < 2; ci++)
133 for (int ck = 0; ck < 2; ck++)
135 for (int cj = 0; cj < 2; cj++)
137 cuExecute3D(make_uint3(mNx, mNy, mNz),
138 SPT_GenerateParticles,
150 template<typename Real>
151 __device__ Vector<Real, 2> d_transfer_velocity(Vector<Real, 4> vel)
153 Real u = vel.x < EPSILON ? 0.0f : vel.y / vel.x;
154 Real v = vel.x < EPSILON ? 0.0f : vel.z / vel.x;
155 return Vector<Real, 2>(u, v);
159 template<typename Real, typename Coord3D, typename Coord4D>
160 __global__ void SPT_AdvectParticles(
161 DArray3D<Coord3D> p_pos,
162 DArray2D<Coord4D> g_vel,
167 uint i = blockDim.x * blockIdx.x + threadIdx.x;
168 uint j = blockIdx.y * blockDim.y + threadIdx.y;
169 uint k = blockIdx.z * blockDim.z + threadIdx.z;
171 int p_nx = p_pos.nx();
172 int p_ny = p_pos.ny();
173 int p_nz = p_pos.nz();
175 if (i >= p_nx) return;
176 if (j >= p_ny) return;
177 if (k >= p_nz) return;
179 int g_nx = g_vel.nx();
180 int g_ny = g_vel.ny();
182 Real w00, w10, w01, w11;
183 int g_ix, g_iy, g_iz;
185 Coord3D p_ijk = p_pos(i, j, k);
187 Real g_fx = (i + p_ijk.x) * p_spacing / g_spacing;
188 Real g_fy = (j + p_ijk.y) * p_spacing / g_spacing;
190 if (g_fx < 0.0f) g_fx = 0.0f;
191 if (g_fx > g_nx - 1) g_fx = g_nx - 1.0f;
192 if (g_fy < 0.0f) g_fy = 0.0f;
193 if (g_fy > g_ny - 1) g_fy = g_ny - 1.0f;
195 g_ix = floor(g_fx); g_iy = floor(g_fy);
196 g_fx -= g_ix; g_fy -= g_iy;
198 if (g_ix == g_nx - 1) { g_ix = g_nx - 2; g_fx = 1.0f; }
199 if (g_iy == g_ny - 1) { g_iy = g_ny - 2; g_fy = 1.0f; }
201 w00 = (1.0f - g_fx) * (1.0f - g_fy);
202 w10 = g_fx * (1.0f - g_fy);
203 w01 = (1.0f - g_fx) * g_fy;
209 Vector<Real, 2> vel_ijk = w00 * d_transfer_velocity(g_vel(g_ix, g_iy)) + w10 * d_transfer_velocity(g_vel(g_ix + 1, g_iy)) + w01 * d_transfer_velocity(g_vel(g_ix, g_iy + 1)) + w11 * d_transfer_velocity(g_vel(g_ix + 1, g_iy + 1));
211 p_ijk.x += vel_ijk.x * dt / p_spacing;
212 p_ijk.y += vel_ijk.y * dt / p_spacing;
214 p_pos(i, j, k) = p_ijk;
217 template<typename TDataType>
218 void SurfaceParticleTracking<TDataType>::advect()
220 auto granular = this->importGranularMedia()->getDerivedNode();
222 Real ps = this->varSpacing()->getValue();
223 Real gs = granular->varSpacing()->getValue();
225 Real dt = this->stateTimeStep()->getValue();
227 auto& computeGrid = granular->stateGrid()->getData();
229 cuExecute3D(make_uint3(mNx, mNy, mNz),
238 template<typename Coord3D>
239 __global__ void SPT_DepositPigments(
240 DArray3D<Coord3D> position,
241 DArray3D<Coord3D> positionBuffer,
243 DArray3D<bool> maskBuffer,
244 DArray3D<uint> mutex)
246 uint i = blockIdx.x * blockDim.x + threadIdx.x;
247 uint j = blockIdx.y * blockDim.y + threadIdx.y;
248 uint k = blockIdx.z * blockDim.z + threadIdx.z;
250 int nx = position.nx();
251 int ny = position.ny();
252 int nz = position.nz();
258 if (!maskBuffer(i, j, k)) return;
263 int id = positionBuffer.index(i, j, k);
264 Coord3D pos = positionBuffer[id];
266 ix = floor(i + pos.x);
267 iy = floor(j + pos.y);
268 iz = floor(k + pos.z);
274 Coord3D p = Coord3D(fx, fy, fz);
276 if (ix < 0) { return; }
277 if (ix >= nx) { return; }
278 if (iy < 0) { return; }
279 if (iy >= ny) { return; }
280 if (iz < 0) { return; }
281 if (iz >= nz) { return; }
283 int id_new = position.index(ix, iy, iz);
285 while (atomicCAS(&(mutex[id_new]), 0, 1) == 0) break;
286 position[id_new] = p;
288 atomicExch(&(mutex[id_new]), 0);
291 template<typename TDataType>
292 void SurfaceParticleTracking<TDataType>::deposit()
294 mPositionBuffer.assign(mPosition);
295 mMaskBuffer.assign(mMask);
300 cuExecute3D(make_uint3(mNx, mNy, mNz),
309 template<typename TDataType>
310 void SurfaceParticleTracking<TDataType>::updateStates()
320 template<typename Real, typename Coord3D, typename Coord4D>
321 __global__ void SPT_UpdatePointSet(
322 DArray<Coord3D> points,
323 DArray2D<Coord4D> grid,
324 DArray3D<Coord3D> point3d,
329 uint i = blockIdx.x * blockDim.x + threadIdx.x;
330 uint j = blockIdx.y * blockDim.y + threadIdx.y;
332 uint width = point3d.nx();
333 uint height = point3d.ny();
335 if (i >= point3d.nx() || j >= point3d.ny()) return;
337 for (uint k = 0; k < point3d.nz(); k++)
339 Coord3D pos = point3d(i, j, k);
340 Real grid_fx = (i + pos.x) * s;
341 Real grid_fy = (j + pos.y) * s;
343 if (grid_fx < 0.0f) grid_fx = 0.0f;
344 if (grid_fx > width - 1) grid_fx = width - 1.0f;
345 if (grid_fy < 0.0f) grid_fy = 0.0f;
346 if (grid_fy > height - 1) grid_fy = height - 1.0f;
348 int gridx = floor(grid_fx); int gridy = floor(grid_fy);
349 Real fx = grid_fx - gridx; Real fy = grid_fy - gridy;
351 if (gridx == width - 1) { gridx = width - 2; fx = 1.0f; }
352 if (gridy == height - 1) { gridy = height - 2; fy = 1.0f; }
354 Real w00 = (1.0f - fx) * (1.0f - fy);
355 Real w10 = fx * (1.0f - fy);
356 Real w01 = (1.0f - fx) * fy;
359 Coord4D gp00 = grid(gridx + 1, gridy + 1);
360 Coord4D gp10 = grid(gridx + 2, gridy + 1);
361 Coord4D gp01 = grid(gridx + 1, gridy + 2);
362 Coord4D gp11 = grid(gridx + 2, gridy + 2);
364 Coord4D gp = w00 * gp00 + w10 * gp10 + w01 * gp01 + w11 * gp11;
366 uint id = point3d.index(i, j, k);
367 points[id] = origin + Coord3D((pos.x + i) * s * grid_spacing, gp.x + gp.w - k * s * grid_spacing, (pos.z + j) * s * grid_spacing);
371 template<typename TDataType>
372 void SurfaceParticleTracking<TDataType>::updatePointSet()
374 auto pointSet = this->statePointSet()->getDataPtr();
376 float ps = this->varSpacing()->getValue();
378 auto granular = this->importGranularMedia()->getDerivedNode();
380 auto& computeGrid = granular->stateGrid()->getData();
382 auto& points = pointSet->getPoints();
384 auto heights = granular->stateHeightField()->getDataPtr();
385 auto origin = heights->getOrigin();
386 auto gridSpacing = heights->getGridSpacing();
388 uint num = mPosition.size();
392 cuExecute2D(make_uint2(mPosition.nx(), mPosition.ny()),
402 DEFINE_CLASS(SurfaceParticleTracking);