PeriDyno 1.0.0
Loading...
Searching...
No Matches
GranularMedia.cu
Go to the documentation of this file.
1#include "GranularMedia.h"
2
3#include "Mapping/HeightFieldToTriangleSet.h"
4#include "GLSurfaceVisualModule.h"
5
6namespace dyno
7{
8#define EPSILON 0.000001
9
10 template<typename TDataType>
11 GranularMedia<TDataType>::GranularMedia()
12 : Node()
13 {
14 this->setDt(0.033f);
15
16 auto heights = std::make_shared<HeightField<TDataType>>();
17 this->stateHeightField()->setDataPtr(heights);
18
19 auto mapper = std::make_shared<HeightFieldToTriangleSet<DataType3f>>();
20 this->stateHeightField()->connect(mapper->inHeightField());
21 this->graphicsPipeline()->pushModule(mapper);
22
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);
28 }
29
30 template<typename TDataType>
31 GranularMedia<TDataType>::~GranularMedia()
32 {
33 }
34
35 template<typename Real, typename Coord4D>
36 __device__ Coord4D d_flux_x(Coord4D gpl, Coord4D gpr, Real GRAVITY)
37 {
38 Real h = maximum(0.5f * (gpl.x + gpr.x), 0.0f);
39 Real b = 0.5f * (gpl.w + gpr.w);
40
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))));
44
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))));
48
49 if (hl < EPSILON && hr < EPSILON)
50 {
51
52 return Coord4D(0.0f);
53 }
54
55 Real a_plus;
56 Real a_minus;
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));
59
60 Coord4D delta_U = gpr - gpl;
61 if (gpl.x > EPSILON && gpr.x > EPSILON)
62 {
63 delta_U.x += delta_U.w;
64 }
65
66 delta_U.w = 0.0f;
67
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);
70
71 Coord4D re = (a_plus * Fl - a_minus * Fr) / (a_plus - a_minus) + a_plus * a_minus / (a_plus - a_minus) * delta_U;
72
73 if (ul == 0 && ur == 0)//abs(ul) <EPSILON && abs(ur) <EPSILON
74 {
75 re.x = 0;
76 re.y = 0;
77 re.z = 0;
78 }
79 return re;
80 }
81
82 template<typename Real, typename Coord4D>
83 __device__ Coord4D d_flux_y(Coord4D gpl, Coord4D gpr, Real GRAVITY)
84 {
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)));
88
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)));
92
93 if (hl < EPSILON && hr < EPSILON)
94 {
95 return Coord4D(0.0f);
96 }
97
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));
100
101 Real b = 0.5f * (gpl.w + gpr.w);
102
103 Coord4D delta_U = gpr - gpl;
104 if (gpl.x > EPSILON && gpr.x > EPSILON)
105 {
106 delta_U.x += delta_U.w;
107 }
108 delta_U.w = 0.0f;
109
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);
112
113 Coord4D re = (a_plus * Fl - a_minus * Fr) / (a_plus - a_minus) + a_plus * a_minus / (a_plus - a_minus) * delta_U;
114
115 if (vl == 0 && vr == 0)
116 {
117 re.x = 0;
118 re.y = 0;
119 re.z = 0;
120 }
121 return re;
122 }
123
124 //Section 4.1
125 template<typename Coord4D>
126 __global__ void GM_Advection(
127 DArray2D<Coord4D> grid_next,
128 DArray2D<Coord4D> grid,
129 Real GRAVITY,
130 Real timestep)
131 {
132 int x = threadIdx.x + blockIdx.x * blockDim.x;
133 int y = threadIdx.y + blockIdx.y * blockDim.y;
134
135 uint width = grid.nx();
136 uint height = grid.ny();
137
138 if (x < width - 2 && y < height - 2)
139 {
140 int gridx = x + 1;
141 int gridy = y + 1;
142
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);
148
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;
155
156 if (u_center.x < EPSILON)
157 {
158 u_center.x = 0.0f;
159 u_center.y = 0.0f;
160 u_center.z = 0.0f;
161 }
162
163 Real totalH = u_center.x + center.w;
164 if (u_center.x <= EPSILON)
165 {
166 u_center.y = 0;
167 u_center.z = 0;
168 }
169 if ((east.w >= totalH) || (west.w >= totalH))
170 {
171 u_center.y = 0;
172 //u_center.z = 0;
173 }
174 if ((north.w >= totalH) || (south.w >= totalH))
175 {
176 //u_center.y = 0;
177 u_center.z = 0;
178 }
179
180 if (x == 0 || x == width - 1)
181 {
182 u_center.y = 0;
183 //u_center.z = 0;
184 }
185 if (y == 0 || y == height - 1)
186 {
187 //u_center.y = 0;
188 u_center.z = 0;
189 }
190 u_center.w = center.w;
191
192 grid_next(gridx, gridy) = u_center;
193 }
194 }
195
196
197 template<typename Coord4D>
198 __global__ void GM_SetBoundaryCondition(DArray2D<Coord4D> grid)
199 {
200 int x = threadIdx.x + blockIdx.x * blockDim.x;
201 int y = threadIdx.y + blockIdx.y * blockDim.y;
202
203 uint width = grid.nx();
204 uint height = grid.ny();
205
206 if (x >= width || y >= height) return;
207
208 if (x == 0) grid(0, y) = grid(1, y);
209
210 if (x == width - 1) grid(width - 1, y) = grid(width - 2, y);
211
212 if (y == 0) grid(x, 0) = grid(x, 1);
213
214 if (y == height - 1) grid(x, height - 1) = grid(x, height - 2);
215 }
216
217 //Section 4.2
218 template<typename Real, typename Coord4D>
219 __global__ void GM_UpdateVelocity(
220 DArray2D<Coord4D> grid_next,
221 DArray2D<Coord4D> grid,
222 Real timestep,
223 Real depth,
224 Real dragging,
225 Real GRAVITY,
226 Real h,
227 Real mu)
228 {
229 int x = threadIdx.x + blockIdx.x * blockDim.x;
230 int y = threadIdx.y + blockIdx.y * blockDim.y;
231
232 const Real grid_spacing2 = 2 * h;
233
234 uint width = grid.nx();
235 uint height = grid.ny();
236
237 if (x < width - 2 && y < height - 2)
238 {
239 int gridx = x + 1;
240 int gridy = y + 1;
241
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);
247
248 Real h = center.x;
249 Real hu_new = center.y;
250 Real hv_new = center.z;
251
252 Real hu_old = hu_new;
253 Real hv_old = hv_new;
254
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;
260
261
262 Real h_d = depth;
263
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);
268
269 Real sliding_cos = 1 / sqrtf(1 + gradient * gradient);
270 Real sliding_sin = abs(gradient) / sqrtf(1 + gradient * gradient);
271
272 Real sliding_length = sqrtf(sliding_dir.x * sliding_dir.x + sliding_dir.y * sliding_dir.y);
273
274 Real g = GRAVITY;
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;
277
278 Vector<Real, 2> vel_dir;
279
280 Real vel_norm = sqrtf(hu_tmp * hu_tmp + hv_tmp * hv_tmp);
281 if (vel_norm < EPSILON)
282 {
283 vel_dir.x = 0.0f;
284 vel_dir.y = 0.0f;
285 }
286 else
287 {
288 vel_dir.x = hu_tmp / vel_norm;
289 vel_dir.y = hv_tmp / vel_norm;
290 }
291
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;
294
295 if (hu_new * hu_tmp + hv_new * hv_tmp < EPSILON && sliding_sin - mu * sliding_cos < 0)
296 {
297 hu_new = 0.0f;
298 hv_new = 0.0f;
299 }
300
301
302 Coord4D u_center;
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)
308 {
309 //u_center.x = 0;
310 u_center.y = 0;
311 u_center.z = 0;
312 }
313 if ((east.w >= totalH) || (west.w >= totalH))
314 {
315 u_center.y = 0;
316 //u_center.z = 0;
317 }
318 if ((north.w >= totalH) || (south.w >= totalH))
319 {
320 //u_center.y = 0;
321 u_center.z = 0;
322 }
323
324 if (x == 0 || x == width - 1)
325 {
326 u_center.y = 0;
327 //u_center.z = 0;
328 }
329 if (y == 0 || y == height - 1)
330 {
331 //u_center.y = 0;
332 u_center.z = 0;
333 }
334 u_center.w = center.w;
335
336 grid_next(gridx, gridy) = u_center;
337 }
338 }
339
340 template<typename Coord3D, typename Coord4D>
341 __global__ void UpdateHeightField(
342 DArray2D<Coord3D> heightfield,
343 DArray2D<Coord4D> grid)
344 {
345 int i = threadIdx.x + blockIdx.x * blockDim.x;
346 int j = threadIdx.y + blockIdx.y * blockDim.y;
347
348 int width = grid.nx();
349 int height = grid.ny();
350
351 if (i < width - 2 && j < height - 2)
352 {
353 int gx = i + 1;
354 int gy = j + 1;
355
356 Coord4D gxy = grid(gx, gy);
357
358 heightfield(i, j) = Coord3D(0, gxy.x, 0);
359 }
360 }
361 template<typename Coord3D, typename Coord4D>
362 __global__ void GM_SetGrid(
363 DArray2D<Coord3D> heightfield,
364 DArray2D<Coord4D> grid,
365 Real depthOffset)
366 {
367 int i = threadIdx.x + blockIdx.x * blockDim.x;
368 int j = threadIdx.y + blockIdx.y * blockDim.y;
369
370 int width = heightfield.nx();
371 int height = heightfield.ny();
372 if (i == 0)
373 {
374 grid(i, j) = Coord4D(heightfield(0, j == 0 ? j:j-1).y + depthOffset, 0.0f, 0.0f, 0.0f);
375 }
376 else if (j == 0)
377 {
378 grid(i, j) = Coord4D(heightfield(i == 0 ? i : i - 1, 0).y + depthOffset, 0.0f, 0.0f, 0.0f);
379 }
380 else
381 {
382 if (i < width + 1 && j < height + 1)
383 {
384 grid(i, j) = Coord4D(heightfield(i - 1, j - 1).y + depthOffset, 0.0f, 0.0f, 0.0f);
385 }
386 else
387 {
388 if(i == width + 1)
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);
392 }
393 }
394 }
395
396 template<typename TDataType>
397 void GranularMedia<TDataType>::resetStates()
398 {
399 uint w = this->varWidth()->getValue();
400 uint h = this->varHeight()->getValue();
401
402 uint exW = w + 2;
403 uint exH = h + 2;
404
405 auto s = this->varSpacing()->getValue();
406 auto o = this->varOrigin()->getValue();
407
408 auto d = this->varDepth()->getValue();
409
410 this->stateGrid()->resize(exW, exH);
411 this->stateGridNext()->resize(exW, exH);
412
413 auto topo = this->stateHeightField()->getDataPtr();
414
415 CArray2D<Coord4D> initializer(exW, exH);
416
417 for (uint i = 0; i < exW; i++)
418 {
419 for (uint j = 0; j < exH; j++)
420 {
421 initializer(i, j) = Coord4D(d, 0, 0, 0);
422 }
423 }
424
425 this->stateGrid()->assign(initializer);
426 this->stateGridNext()->assign(initializer);
427
428 topo->setExtents(w, h);
429 topo->setGridSpacing(s);
430 topo->setOrigin(o);
431 topo->update();
432
433 auto hf = this->stateHeightField()->getDataPtr();
434
435 auto& disp = hf->getDisplacement();
436
437 auto& grid = this->stateGrid()->getData();
438
439 cuExecute2D(make_uint2(grid.nx(), grid.ny()),
440 UpdateHeightField,
441 disp,
442 grid);
443
444 initializer.clear();
445
446 Node::resetStates();
447 }
448
449 template<typename TDataType>
450 void GranularMedia<TDataType>::updateStates()
451 {
452 auto& grid = this->stateGrid()->getData();
453 auto& grid_next = this->stateGridNext()->getData();
454
455 uint2 dim = make_uint2(grid.nx(), grid.ny());
456
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();
461
462 Real h = this->varSpacing()->getValue();
463
464 Real G = abs(this->varGravity()->getValue());
465
466 cuExecute2D(dim,
467 GM_Advection,
468 grid_next,
469 grid,
470 G,
471 dt);
472
473 cuExecute2D(dim,
474 GM_SetBoundaryCondition,
475 grid_next);
476
477 cuExecute2D(
478 dim,
479 GM_UpdateVelocity,
480 grid,
481 grid_next,
482 dt,
483 d_hat,
484 dragging,
485 G,
486 h,
487 mu);
488
489 auto hf = this->stateHeightField()->getDataPtr();
490
491 auto& disp = hf->getDisplacement();
492
493 cuExecute2D(dim,
494 UpdateHeightField,
495 disp,
496 grid_next);
497 }
498
499 DEFINE_CLASS(GranularMedia);
500}
501