1#include "GranularMedia.h"
3#include "Mapping/HeightFieldToTriangleSet.h"
4#include "GLSurfaceVisualModule.h"
8#define EPSILON 0.000001
10 template<typename TDataType>
11 GranularMedia<TDataType>::GranularMedia()
16 auto heights = std::make_shared<HeightField<TDataType>>();
17 this->stateHeightField()->setDataPtr(heights);
19 auto mapper = std::make_shared<HeightFieldToTriangleSet<DataType3f>>();
20 this->stateHeightField()->connect(mapper->inHeightField());
21 this->graphicsPipeline()->pushModule(mapper);
23 auto sRender = std::make_shared<GLSurfaceVisualModule>();
24 sRender->setColor(Color::SandyBrown());
25 sRender->varUseVertexNormal()->setValue(true);
26 mapper->outTriangleSet()->connect(sRender->inTriangleSet());
27 this->graphicsPipeline()->pushModule(sRender);
30 template<typename TDataType>
31 GranularMedia<TDataType>::~GranularMedia()
35 template<typename Real, typename Coord4D>
36 __device__ Coord4D d_flux_x(Coord4D gpl, Coord4D gpr, Real GRAVITY)
38 Real h = maximum(0.5f * (gpl.x + gpr.x), 0.0f);
39 Real b = 0.5f * (gpl.w + gpr.w);
41 Real hl = maximum(gpl.x, 0.0f);
42 Real hl4 = hl * hl * hl * hl;
43 Real ul = sqrtf(2.0f) * hl * gpl.y / (sqrtf(hl4 + maximum(hl4, Real(EPSILON))));
45 Real hr = max(gpr.x, 0.0f);
46 Real hr4 = hr * hr * hr * hr;
47 Real ur = sqrtf(2.0f) * hr * gpr.y / (sqrtf(hr4 + maximum(hr4, Real(EPSILON))));
49 if (hl < EPSILON && hr < EPSILON)
57 a_plus = maximum(maximum(Real(ul + sqrtf(GRAVITY * (gpl.x/*+gpl.w*/))), Real(ur + sqrtf(GRAVITY * (gpr.x/*+gpr.w*/)))), Real(0));
58 a_minus = minimum(minimum(Real(ul - sqrtf(GRAVITY * (gpl.x/*+gpl.w*/))), Real(ur - sqrtf(GRAVITY * (gpr.x/*+gpr.w*/)))), Real(0));
60 Coord4D delta_U = gpr - gpl;
61 if (gpl.x > EPSILON && gpr.x > EPSILON)
63 delta_U.x += delta_U.w;
68 Coord4D Fl = Coord4D(gpl.y, gpl.y * ul, gpl.z * ul, 0.0f);
69 Coord4D Fr = Coord4D(gpr.y, gpr.y * ur, gpr.z * ur, 0.0f);
71 Coord4D re = (a_plus * Fl - a_minus * Fr) / (a_plus - a_minus) + a_plus * a_minus / (a_plus - a_minus) * delta_U;
73 if (ul == 0 && ur == 0)//abs(ul) <EPSILON && abs(ur) <EPSILON
82 template<typename Real, typename Coord4D>
83 __device__ Coord4D d_flux_y(Coord4D gpl, Coord4D gpr, Real GRAVITY)
85 Real hl = max(gpl.x, 0.0f);
86 Real hl4 = hl * hl * hl * hl;
87 Real vl = sqrtf(2.0f) * hl * gpl.z / (sqrtf(hl4 + max(hl4, EPSILON)));
89 Real hr = max(gpr.x, 0.0f);
90 Real hr4 = hr * hr * hr * hr;
91 Real vr = sqrtf(2.0f) * hr * gpr.z / (sqrtf(hr4 + max(hr4, EPSILON)));
93 if (hl < EPSILON && hr < EPSILON)
98 Real a_plus = maximum(maximum(Real(vl + sqrtf(GRAVITY * (gpl.x/* + gpl.w*/))), Real(vr + sqrtf(GRAVITY * (gpr.x/* + gpr.w*/)))), Real(0));
99 Real a_minus = minimum(minimum(Real(vl - sqrtf(GRAVITY * (gpl.x/* + gpl.w*/))), Real(vr - sqrtf(GRAVITY * (gpr.x/* + gpr.w*/)))), Real(0));
101 Real b = 0.5f * (gpl.w + gpr.w);
103 Coord4D delta_U = gpr - gpl;
104 if (gpl.x > EPSILON && gpr.x > EPSILON)
106 delta_U.x += delta_U.w;
110 Coord4D Fl = Coord4D(gpl.z, gpl.y * vl, gpl.z * vl, 0.0f);
111 Coord4D Fr = Coord4D(gpr.z, gpr.y * vr, gpr.z * vr, 0.0f);
113 Coord4D re = (a_plus * Fl - a_minus * Fr) / (a_plus - a_minus) + a_plus * a_minus / (a_plus - a_minus) * delta_U;
115 if (vl == 0 && vr == 0)
125 template<typename Coord4D>
126 __global__ void GM_Advection(
127 DArray2D<Coord4D> grid_next,
128 DArray2D<Coord4D> grid,
132 int x = threadIdx.x + blockIdx.x * blockDim.x;
133 int y = threadIdx.y + blockIdx.y * blockDim.y;
135 uint width = grid.nx();
136 uint height = grid.ny();
138 if (x < width - 2 && y < height - 2)
143 Coord4D center = grid(gridx, gridy);
144 Coord4D north = grid(gridx, gridy - 1);
145 Coord4D west = grid(gridx - 1, gridy);
146 Coord4D south = grid(gridx, gridy + 1);
147 Coord4D east = grid(gridx + 1, gridy);
149 Coord4D eastflux = d_flux_x(center, east, GRAVITY);
150 Coord4D westflux = d_flux_x(west, center, GRAVITY);
151 Coord4D southflux = d_flux_y(center, south, GRAVITY);
152 Coord4D northflux = d_flux_y(north, center, GRAVITY);
153 Coord4D flux = eastflux - westflux + southflux - northflux;
154 Coord4D u_center = center - timestep * flux;
156 if (u_center.x < EPSILON)
163 Real totalH = u_center.x + center.w;
164 if (u_center.x <= EPSILON)
169 if ((east.w >= totalH) || (west.w >= totalH))
174 if ((north.w >= totalH) || (south.w >= totalH))
180 if (x == 0 || x == width - 1)
185 if (y == 0 || y == height - 1)
190 u_center.w = center.w;
192 grid_next(gridx, gridy) = u_center;
197 template<typename Coord4D>
198 __global__ void GM_SetBoundaryCondition(DArray2D<Coord4D> grid)
200 int x = threadIdx.x + blockIdx.x * blockDim.x;
201 int y = threadIdx.y + blockIdx.y * blockDim.y;
203 uint width = grid.nx();
204 uint height = grid.ny();
206 if (x >= width || y >= height) return;
208 if (x == 0) grid(0, y) = grid(1, y);
210 if (x == width - 1) grid(width - 1, y) = grid(width - 2, y);
212 if (y == 0) grid(x, 0) = grid(x, 1);
214 if (y == height - 1) grid(x, height - 1) = grid(x, height - 2);
218 template<typename Real, typename Coord4D>
219 __global__ void GM_UpdateVelocity(
220 DArray2D<Coord4D> grid_next,
221 DArray2D<Coord4D> grid,
229 int x = threadIdx.x + blockIdx.x * blockDim.x;
230 int y = threadIdx.y + blockIdx.y * blockDim.y;
232 const Real grid_spacing2 = 2 * h;
234 uint width = grid.nx();
235 uint height = grid.ny();
237 if (x < width - 2 && y < height - 2)
242 Coord4D center = grid(gridx, gridy);
243 Coord4D north = grid(gridx, gridy - 1);
244 Coord4D west = grid(gridx - 1, gridy);
245 Coord4D south = grid(gridx, gridy + 1);
246 Coord4D east = grid(gridx + 1, gridy);
249 Real hu_new = center.y;
250 Real hv_new = center.z;
252 Real hu_old = hu_new;
253 Real hv_old = hv_new;
255 Real s = center.x + center.w;
256 Real sw = west.x + west.w;
257 Real se = east.x + east.w;
258 Real sn = north.x + north.w;
259 Real ss = south.x + south.w;
264 Vector<Real, 2> sliding_dir;
265 sliding_dir.x = (sw - se) / grid_spacing2;
266 sliding_dir.y = (sn - ss) / grid_spacing2;
267 Real gradient = sqrtf(sliding_dir.x * sliding_dir.x + sliding_dir.y * sliding_dir.y);
269 Real sliding_cos = 1 / sqrtf(1 + gradient * gradient);
270 Real sliding_sin = abs(gradient) / sqrtf(1 + gradient * gradient);
272 Real sliding_length = sqrtf(sliding_dir.x * sliding_dir.x + sliding_dir.y * sliding_dir.y);
275 Real hu_tmp = hu_old + timestep * g * maximum(minimum(h_d, center.x), Real(0)) * sliding_dir.x;
276 Real hv_tmp = hv_old + timestep * g * maximum(minimum(h_d, center.x), Real(0)) * sliding_dir.y;
278 Vector<Real, 2> vel_dir;
280 Real vel_norm = sqrtf(hu_tmp * hu_tmp + hv_tmp * hv_tmp);
281 if (vel_norm < EPSILON)
288 vel_dir.x = hu_tmp / vel_norm;
289 vel_dir.y = hv_tmp / vel_norm;
292 hu_new = hu_tmp - timestep * g * maximum(minimum(h_d, center.x), Real(0)) * vel_dir.x * mu;
293 hv_new = hv_tmp - timestep * g * maximum(minimum(h_d, center.x), Real(0)) * vel_dir.y * mu;
295 if (hu_new * hu_tmp + hv_new * hv_tmp < EPSILON && sliding_sin - mu * sliding_cos < 0)
303 u_center.x = center.x;
304 u_center.y = hu_new * dragging;
305 u_center.z = hv_new * dragging;
306 Real totalH = u_center.x + center.w;
307 if (u_center.x <= EPSILON)
313 if ((east.w >= totalH) || (west.w >= totalH))
318 if ((north.w >= totalH) || (south.w >= totalH))
324 if (x == 0 || x == width - 1)
329 if (y == 0 || y == height - 1)
334 u_center.w = center.w;
336 grid_next(gridx, gridy) = u_center;
340 template<typename Coord3D, typename Coord4D>
341 __global__ void UpdateHeightField(
342 DArray2D<Coord3D> heightfield,
343 DArray2D<Coord4D> grid)
345 int i = threadIdx.x + blockIdx.x * blockDim.x;
346 int j = threadIdx.y + blockIdx.y * blockDim.y;
348 int width = grid.nx();
349 int height = grid.ny();
351 if (i < width - 2 && j < height - 2)
356 Coord4D gxy = grid(gx, gy);
358 heightfield(i, j) = Coord3D(0, gxy.x, 0);
361 template<typename Coord3D, typename Coord4D>
362 __global__ void GM_SetGrid(
363 DArray2D<Coord3D> heightfield,
364 DArray2D<Coord4D> grid,
367 int i = threadIdx.x + blockIdx.x * blockDim.x;
368 int j = threadIdx.y + blockIdx.y * blockDim.y;
370 int width = heightfield.nx();
371 int height = heightfield.ny();
374 grid(i, j) = Coord4D(heightfield(0, j == 0 ? j:j-1).y + depthOffset, 0.0f, 0.0f, 0.0f);
378 grid(i, j) = Coord4D(heightfield(i == 0 ? i : i - 1, 0).y + depthOffset, 0.0f, 0.0f, 0.0f);
382 if (i < width + 1 && j < height + 1)
384 grid(i, j) = Coord4D(heightfield(i - 1, j - 1).y + depthOffset, 0.0f, 0.0f, 0.0f);
389 grid(i, j) = Coord4D(heightfield(i - 2, j == height + 1 ? j - 2 : j - 1).y + depthOffset, 0.0f, 0.0f, 0.0f);
390 else if(j == height + 1)
391 grid(i, j) = Coord4D(heightfield(i == width + 1 ? i - 2 :i - 1, j - 2).y + depthOffset, 0.0f, 0.0f, 0.0f);
396 template<typename TDataType>
397 void GranularMedia<TDataType>::resetStates()
399 uint w = this->varWidth()->getValue();
400 uint h = this->varHeight()->getValue();
405 auto s = this->varSpacing()->getValue();
406 auto o = this->varOrigin()->getValue();
408 auto d = this->varDepth()->getValue();
410 this->stateGrid()->resize(exW, exH);
411 this->stateGridNext()->resize(exW, exH);
413 auto topo = this->stateHeightField()->getDataPtr();
415 CArray2D<Coord4D> initializer(exW, exH);
417 for (uint i = 0; i < exW; i++)
419 for (uint j = 0; j < exH; j++)
421 initializer(i, j) = Coord4D(d, 0, 0, 0);
425 this->stateGrid()->assign(initializer);
426 this->stateGridNext()->assign(initializer);
428 topo->setExtents(w, h);
429 topo->setGridSpacing(s);
433 auto hf = this->stateHeightField()->getDataPtr();
435 auto& disp = hf->getDisplacement();
437 auto& grid = this->stateGrid()->getData();
439 cuExecute2D(make_uint2(grid.nx(), grid.ny()),
449 template<typename TDataType>
450 void GranularMedia<TDataType>::updateStates()
452 auto& grid = this->stateGrid()->getData();
453 auto& grid_next = this->stateGridNext()->getData();
455 uint2 dim = make_uint2(grid.nx(), grid.ny());
457 Real dt = this->stateTimeStep()->getValue();
458 Real d_hat = this->varDepthOfDiluteLayer()->getValue();
459 Real dragging = this->varCoefficientOfDragForce()->getValue();
460 Real mu = this->varCoefficientOfFriction()->getValue();
462 Real h = this->varSpacing()->getValue();
464 Real G = abs(this->varGravity()->getValue());
474 GM_SetBoundaryCondition,
489 auto hf = this->stateHeightField()->getDataPtr();
491 auto& disp = hf->getDisplacement();
499 DEFINE_CLASS(GranularMedia);