PeriDyno 1.0.0
Loading...
Searching...
No Matches
NeighborPointQuery.cu
Go to the documentation of this file.
1#include "NeighborPointQuery.h"
2
3#include "Topology/GridHash.h"
4#include "Topology/LinearBVH.h"
5#include "Topology/SparseOctree.h"
6
7#include "SceneGraph.h"
8
9namespace dyno
10{
11 __constant__ int offset_nq[27][3] = {
12 0, 0, 0,
13 0, 0, 1,
14 0, 1, 0,
15 1, 0, 0,
16 0, 0, -1,
17 0, -1, 0,
18 -1, 0, 0,
19 0, 1, 1,
20 0, 1, -1,
21 0, -1, 1,
22 0, -1, -1,
23 1, 0, 1,
24 1, 0, -1,
25 -1, 0, 1,
26 -1, 0, -1,
27 1, 1, 0,
28 1, -1, 0,
29 -1, 1, 0,
30 -1, -1, 0,
31 1, 1, 1,
32 1, 1, -1,
33 1, -1, 1,
34 -1, 1, 1,
35 1, -1, -1,
36 -1, 1, -1,
37 -1, -1, 1,
38 -1, -1, -1
39 };
40
41 IMPLEMENT_TCLASS(NeighborPointQuery, TDataType)
42
43 template<typename TDataType>
44 NeighborPointQuery<TDataType>::NeighborPointQuery()
45 : ComputeModule()
46 {
47 this->inOther()->tagOptional(true);
48
49 this->varSizeLimit()->setRange(0, 100);
50 }
51
52 template<typename TDataType>
53 NeighborPointQuery<TDataType>::~NeighborPointQuery()
54 {
55 }
56
57 template<typename TDataType>
58 void NeighborPointQuery<TDataType>::compute()
59 {
60 auto sType = this->varSpatial()->currentKey();
61
62 if (sType == Spatial::UNIFORM)
63 {
64 if (this->varSizeLimit()->getValue() <= 0) {
65 requestDynamicNeighborIds();
66 }
67 else {
68 requestFixedSizeNeighborIds();
69 }
70 }
71 else if (sType == Spatial::BVH)
72 {
73 requestNeighborIdsWithBVH();
74 }
75 else if (sType == Spatial::OCTREE)
76 {
77 requestNeighborIdsWithOctree();
78 }
79 }
80
81 template<typename Real, typename Coord, typename TDataType>
82 __global__ void K_CalNeighborSize(
83 DArray<uint> count,
84 DArray<Coord> position_new,
85 DArray<Coord> position,
86 GridHash<TDataType> hash,
87 Real h)
88 {
89 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
90 if (pId >= position_new.size()) return;
91
92 Coord pos_ijk = position_new[pId];
93 int3 gId3 = hash.getIndex3(pos_ijk);
94
95 int counter = 0;
96 for (int c = 0; c < 27; c++)
97 {
98 int cId = hash.getIndex(gId3.x + offset_nq[c][0], gId3.y + offset_nq[c][1], gId3.z + offset_nq[c][2]);
99 if (cId >= 0) {
100 int totalNum = hash.getCounter(cId);
101 for (int i = 0; i < totalNum; i++) {
102 int nbId = hash.getParticleId(cId, i);
103 Real d_ij = (pos_ijk - position[nbId]).norm();
104 if (d_ij < h)
105 {
106 counter++;
107 }
108 }
109 }
110 }
111
112 count[pId] = counter;
113 }
114
115
116 template<typename Real, typename Coord, typename TDataType>
117 __global__ void K_GetNeighborElements(
118 DArrayList<int> nbrIds,
119 DArray<Coord> position_new,
120 DArray<Coord> position,
121 GridHash<TDataType> hash,
122 Real h)
123 {
124 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
125 if (pId >= position_new.size()) return;
126
127 Coord pos_ijk = position_new[pId];
128 int3 gId3 = hash.getIndex3(pos_ijk);
129
130 List<int>& list_i = nbrIds[pId];
131
132 int j = 0;
133 for (int c = 0; c < 27; c++)
134 {
135 int cId = hash.getIndex(gId3.x + offset_nq[c][0], gId3.y + offset_nq[c][1], gId3.z + offset_nq[c][2]);
136 if (cId >= 0) {
137 int totalNum = hash.getCounter(cId);
138 for (int i = 0; i < totalNum; i++) {
139 int nbId = hash.getParticleId(cId, i);
140 Real d_ij = (pos_ijk - position[nbId]).norm();
141 if (d_ij < h)
142 {
143 list_i.insert(nbId);
144 j++;
145 }
146 }
147 }
148 }
149 }
150
151 template<typename TDataType>
152 void NeighborPointQuery<TDataType>::requestDynamicNeighborIds()
153 {
154 // Prepare inputs
155 auto& points = this->inPosition()->constData();
156 auto& other = this->inOther()->isEmpty() ? this->inPosition()->constData() : this->inOther()->constData();
157 auto h = this->inRadius()->getValue();
158
159 // Prepare outputs
160 if (this->outNeighborIds()->isEmpty())
161 this->outNeighborIds()->allocate();
162
163 auto& nbrIds = this->outNeighborIds()->getData();
164
165 // Construct hash grid
166 Reduction<Coord> reduce;
167 Coord hiBound = reduce.maximum(points.begin(), points.size());
168 Coord loBound = reduce.minimum(points.begin(), points.size());
169
170 // To avoid particles running out of the simulation domain
171 auto scn = this->getSceneGraph();
172 if (scn != NULL)
173 {
174 auto loLimit = scn->getLowerBound();
175 auto hiLimit = scn->getUpperBound();
176
177 hiBound = hiBound.minimum(hiLimit);
178 loBound = loBound.maximum(loLimit);
179 }
180
181 GridHash<TDataType> hashGrid;
182 hashGrid.setSpace(h, loBound - Coord(h), hiBound + Coord(h));
183 hashGrid.clear();
184 hashGrid.construct(points);
185
186 DArray<uint> counter(other.size());
187 cuExecute(other.size(),
188 K_CalNeighborSize,
189 counter,
190 other,
191 points,
192 hashGrid,
193 h);
194
195 nbrIds.resize(counter);
196
197 cuExecute(other.size(),
198 K_GetNeighborElements,
199 nbrIds,
200 other,
201 points,
202 hashGrid,
203 h);
204
205 counter.clear();
206 hashGrid.release();
207 }
208
209
210 template <typename T> __device__ void inline swap_on_device(T& a, T& b) {
211 T c(a); a = b; b = c;
212 }
213
214 template <typename T>
215 __device__ void heapify_up(int* keys, T* vals, int child)
216 {
217 int parent = (child - 1) / 2;
218 while (child > 0)
219 {
220 if (vals[child] > vals[parent])
221 {
222 swap_on_device(vals[child], vals[parent]);
223 swap_on_device(keys[child], keys[parent]);
224
225 child = parent;
226 parent = (child - 1) / 2;
227 }
228 else
229 {
230 break;
231 }
232 }
233 }
234
235 template <typename T>
236 __device__ void heapify_down(int* keys, T* vals, int node, int size) {
237 int j = node;
238 while (true) {
239 int left = 2 * j + 1;
240 int right = 2 * j + 2;
241 int largest = j;
242 if (left<size && vals[left]>vals[largest]) {
243 largest = left;
244 }
245 if (right<size && vals[right]>vals[largest]) {
246 largest = right;
247 }
248 if (largest == j) return;
249 swap_on_device(vals[j], vals[largest]);
250 swap_on_device(keys[j], keys[largest]);
251 j = largest;
252 }
253 }
254
255 template <typename T>
256 __device__ void heap_sort(int* keys, T* vals, int size) {
257 while (size) {
258 swap_on_device(vals[0], vals[size - 1]);
259 swap_on_device(keys[0], keys[size - 1]);
260 heapify_down(keys, vals, 0, --size);
261 }
262 }
263
264 template<typename Real, typename Coord, typename TDataType>
265 __global__ void K_ComputeNeighborFixed(
266 DArrayList<int> nbrIds,
267 DArray<Coord> position_new,
268 DArray<Coord> position,
269 GridHash<TDataType> hash,
270 Real h,
271 int sizeLimit,
272 DArray<int> heapIDs,
273 DArray<Real> heapDistance)
274 {
275 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
276 if (pId >= position_new.size()) return;
277
278 //TODO: used shared memory for speedup
279 int* ids(heapIDs.begin() + pId * sizeLimit);// = new int[nbrLimit];
280 Real* distance(heapDistance.begin() + pId * sizeLimit);// = new Real[nbrLimit];
281
282 for (int i = 0; i < sizeLimit; i++) {
283 ids[i] = INT_MAX;
284 distance[i] = REAL_MAX;
285 }
286
287 Coord pos_ijk = position_new[pId];
288 int3 gId3 = hash.getIndex3(pos_ijk);
289
290 int counter = 0;
291 for (int c = 0; c < 27; c++)
292 {
293 int cId = hash.getIndex(gId3.x + offset_nq[c][0], gId3.y + offset_nq[c][1], gId3.z + offset_nq[c][2]);
294 if (cId >= 0) {
295 int totalNum = hash.getCounter(cId);// min(hash.getCounter(cId), hash.npMax);
296 for (int i = 0; i < totalNum; i++) {
297 int nbId = hash.getParticleId(cId, i);
298 float d_ij = (pos_ijk - position[nbId]).norm();
299 if (d_ij < h)
300 {
301 if (counter < sizeLimit)
302 {
303 ids[counter] = nbId;
304 distance[counter] = d_ij;
305
306 heapify_up(ids, distance, counter);
307 counter++;
308 }
309 else
310 {
311 if (d_ij < distance[0])
312 {
313 ids[0] = nbId;
314 distance[0] = d_ij;
315
316 heapify_down(ids, distance, 0, counter);
317 }
318 }
319
320 }
321 }
322 }
323 }
324
325 List<int>& list_i = nbrIds[pId];
326
327 heap_sort(ids, distance, counter);
328 for (int bId = 0; bId < counter; bId++)
329 {
330 list_i.insert(ids[bId]);
331 }
332 }
333
334 template<typename TDataType>
335 void NeighborPointQuery<TDataType>::requestFixedSizeNeighborIds()
336 {
337 // Prepare inputs
338 auto& points = this->inPosition()->constData();
339 auto& other = this->inOther()->isEmpty() ? this->inPosition()->constData() : this->inOther()->constData();
340 auto h = this->inRadius()->getValue();
341
342 // Prepare outputs
343 if (this->outNeighborIds()->isEmpty())
344 this->outNeighborIds()->allocate();
345
346 auto& nbrIds = this->outNeighborIds()->getData();
347
348 uint numPt = this->inPosition()->getDataPtr()->size();
349 uint sizeLimit = this->varSizeLimit()->getValue();
350
351 nbrIds.resize(numPt, sizeLimit);
352
353 // Construct hash grid
354 Reduction<Coord> reduce;
355 Coord hiBound = reduce.maximum(points.begin(), points.size());
356 Coord loBound = reduce.minimum(points.begin(), points.size());
357
358 // To avoid particles running out of the simulation domain
359 auto scn = this->getSceneGraph();
360 if (scn != NULL)
361 {
362 auto loLimit = scn->getLowerBound();
363 auto hiLimit = scn->getUpperBound();
364
365 hiBound = hiBound.minimum(hiLimit);
366 loBound = loBound.maximum(loLimit);
367 }
368
369 GridHash<TDataType> hashGrid;
370 hashGrid.setSpace(h, loBound - Coord(h), hiBound + Coord(h));
371 hashGrid.clear();
372 hashGrid.construct(points);
373
374 DArray<int> ids(numPt * sizeLimit);
375 DArray<Real> distance(numPt * sizeLimit);
376 cuExecute(numPt,
377 K_ComputeNeighborFixed,
378 nbrIds,
379 other,
380 points,
381 hashGrid,
382 h,
383 sizeLimit,
384 ids,
385 distance);
386
387 ids.clear();
388 distance.clear();
389 //hashGrid.clear();
390 hashGrid.release();
391 }
392
393 template<typename Real, typename Coord>
394 __global__ void NPQ_SetupAABB(
395 DArray<AABB> boundingBox,
396 DArray<Coord> position,
397 Real radius)
398 {
399 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
400 if (pId >= position.size()) return;
401
402 AABB box;
403 Coord p = position[pId];
404 box.v0 = p - radius;
405 box.v1 = p + radius;
406
407 boundingBox[pId] = box;
408 }
409
410 template<typename Coord, typename TDataType>
411 __global__ void NPQ_RequestNeighborNumberBVH(
412 DArray<uint> counter,
413 DArray<Coord> position,
414 LinearBVH<TDataType> bvh)
415 {
416 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
417 if (tId >= position.size()) return;
418
419 Coord p = position[tId];
420
421 typename LinearBVH<TDataType>::AABB aabb;
422 aabb.v0 = p - EPSILON;
423 aabb.v1 = p + EPSILON;
424
425 counter[tId] = bvh.requestIntersectionNumber(aabb);
426 }
427
428 //TODO: sort ids according to their distance to the center
429 template<typename Coord, typename TDataType>
430 __global__ void NPQ_RequestNeighborIdsBVH(
431 DArrayList<int> idLists,
432 DArray<Coord> position,
433 LinearBVH<TDataType> bvh)
434 {
435 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
436 if (tId >= position.size()) return;
437
438 Coord p = position[tId];
439
440 typename LinearBVH<TDataType>::AABB aabb;
441 aabb.v0 = p - EPSILON;
442 aabb.v1 = p + EPSILON;
443
444 bvh.requestIntersectionIds(idLists[tId], aabb);
445 }
446
447 template<typename TDataType>
448 void NeighborPointQuery<TDataType>::requestNeighborIdsWithBVH()
449 {
450 // Prepare inputs
451 auto& points = this->inPosition()->constData();
452 auto& other = this->inOther()->isEmpty() ? this->inPosition()->constData() : this->inOther()->constData();
453 auto h = this->inRadius()->getValue();
454
455 uint numSrc = points.size();
456 uint numTar = other.size();
457
458 if (this->outNeighborIds()->isEmpty()) {
459 this->outNeighborIds()->allocate();
460 }
461
462 auto& neighborLists = this->outNeighborIds()->getData();
463
464 DArray<AABB> aabbs(numTar);
465
466 cuExecute(numTar,
467 NPQ_SetupAABB,
468 aabbs,
469 other,
470 h);
471
472 LinearBVH<TDataType> bvh;
473 bvh.construct(aabbs);
474
475 DArray<uint> counter(numSrc);
476
477 cuExecute(numSrc,
478 NPQ_RequestNeighborNumberBVH,
479 counter,
480 points,
481 bvh);
482
483 neighborLists.resize(counter);
484
485 cuExecute(numSrc,
486 NPQ_RequestNeighborIdsBVH,
487 neighborLists,
488 points,
489 bvh);
490
491 counter.clear();
492 aabbs.clear();
493
494 bvh.release();
495 }
496
497 template<typename Coord, typename TDataType>
498 __global__ void CDBP_RequestIntersectionNumber(
499 DArray<uint> count,
500 DArray<Coord> points,
501 Real radius,
502 SparseOctree<TDataType> octree)
503 {
504 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
505 if (tId >= count.size()) return;
506
507 Coord p = points[tId];
508
509 AABB aabb;
510 aabb.v0 = p - radius;
511 aabb.v1 = p + radius;
512
513 count[tId] = octree.requestIntersectionNumberFromBottom(aabb);
514 }
515
516 template<typename Coord, typename TDataType>
517 __global__ void CDBP_RequestIntersectionIds(
518 DArrayList<int> lists,
519 DArray<int> ids,
520 DArray<uint> count,
521 DArray<Coord> points,
522 Real radius,
523 SparseOctree<TDataType> octree)
524 {
525 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
526 if (tId >= count.size()) return;
527
528 Coord p = points[tId];
529 int total_num = count.size();
530
531 AABB aabb;
532 aabb.v0 = p - radius;
533 aabb.v1 = p + radius;
534
535 octree.reqeustIntersectionIdsFromBottom(ids.begin() + count[tId], aabb);
536
537 int n = tId == total_num - 1 ? ids.size() - count[total_num - 1] : count[tId + 1] - count[tId];
538
539 List<int>& list_i = lists[tId];
540
541 for (int t = 0; t < n; t++)
542 {
543 list_i.insert(ids[count[tId] + t]);
544 }
545 }
546
547 template<typename Real, typename Coord>
548 __global__ void CDBP_RequestNeighborSize(
549 DArray<uint> counter,
550 DArray<Coord> srcPoints,
551 DArray<Coord> tarPoints,
552 DArrayList<int> lists,
553 Real radius)
554 {
555 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
556 if (tId >= counter.size()) return;
557
558 Coord p_i = srcPoints[tId];
559
560 List<int>& list_i = lists[tId];
561 int nbSize = list_i.size();
562 int num = 0;
563 for (int ne = 0; ne < nbSize; ne++)
564 {
565 int j = list_i[ne];
566 Real r = (p_i - tarPoints[j]).norm();
567
568 if (r < radius)
569 num++;
570 }
571
572 counter[tId] = num;
573 }
574
575 //TODO: sort ids according to their distance to the center
576 template<typename Real, typename Coord>
577 __global__ void CDBP_RequestNeighborIds(
578 DArrayList<int> neighbors,
579 DArray<Coord> srcPoints,
580 DArray<Coord> tarPoints,
581 DArrayList<int> lists,
582 Real radius)
583 {
584 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
585 if (tId >= neighbors.size()) return;
586
587 Coord p_i = srcPoints[tId];
588
589 List<int>& list_i = lists[tId];
590 int nbSize = list_i.size();
591
592 List<int>& neList_i = neighbors[tId];
593 int num = 0;
594 for (int ne = 0; ne < nbSize; ne++)
595 {
596 int j = list_i[ne];
597 Real r = (p_i - tarPoints[j]).norm();
598
599 if (r < radius)
600 {
601 neList_i.insert(j);
602 }
603 }
604 }
605
606 template<typename TDataType>
607 void NeighborPointQuery<TDataType>::requestNeighborIdsWithOctree()
608 {
609 // Prepare inputs
610 auto& points = this->inPosition()->constData();
611 auto& other = this->inOther()->isEmpty() ? this->inPosition()->constData() : this->inOther()->constData();
612 auto h = this->inRadius()->getValue();
613
614 uint numSrc = points.size();
615 uint numTar = other.size();
616
617 if (this->outNeighborIds()->isEmpty()) {
618 this->outNeighborIds()->allocate();
619 }
620
621 auto& neighborLists = this->outNeighborIds()->getData();
622
623 Reduction<Coord> m_reduce_coord;
624 auto min_v0 = m_reduce_coord.minimum(other.begin(), other.size());
625 auto max_v1 = m_reduce_coord.maximum(other.begin(), other.size());
626
627 SparseOctree<TDataType> octree;
628 octree.setSpace(min_v0, h, maximum(max_v1[0] - min_v0[0], maximum(max_v1[1] - min_v0[1], max_v1[2] - min_v0[2])));
629 octree.construct(other, 0);
630
631 DArray<uint> counter(numSrc);
632
633 cuExecute(numSrc,
634 CDBP_RequestIntersectionNumber,
635 counter,
636 points,
637 h,
638 octree);
639
640 DArrayList<int> lists;
641 lists.resize(counter);
642
643 Reduction<uint> reduce;
644 uint total_num = reduce.accumulate(counter.begin(), counter.size());
645
646 Scan<uint> scan;
647 scan.exclusive(counter.begin(), counter.size());
648
649 DArray<int> ids(total_num);
650 cuExecute(numSrc,
651 CDBP_RequestIntersectionIds,
652 lists,
653 ids,
654 counter,
655 points,
656 h,
657 octree);
658
659 DArray<uint> neighbor_counter(numSrc);
660 cuExecute(numSrc,
661 CDBP_RequestNeighborSize,
662 neighbor_counter,
663 points,
664 other,
665 lists,
666 h);
667
668 neighborLists.resize(neighbor_counter);
669
670 cuExecute(numSrc,
671 CDBP_RequestNeighborIds,
672 neighborLists,
673 points,
674 other,
675 lists,
676 h);
677
678 counter.clear();
679 lists.clear();
680 ids.clear();
681 neighbor_counter.clear();
682 octree.release();
683 }
684
685 DEFINE_CLASS(NeighborPointQuery);
686}