VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
fmm::MortonTree< dim, point, value > Class Template Reference

#include <morton_tree.h>

Collaboration diagram for fmm::MortonTree< dim, point, value >:

Public Types

using particle_t = particle< point, value >
 
using TreeCell_t = TreeCell< point, value >
 

Public Member Functions

 MortonTree (std::vector< particle_t > &&particles, size_t tree_depth)
 

Public Attributes

std::vector< std::vector< TreeCell_t > > levels
 
std::vector< size_t > level_sizes
 
size_t tree_depth
 
size_t targets_num = 0
 
std::vector< particle_tparticles
 
std::vector< size_t > positions_map
 

Private Member Functions

void FillNeighbours ()
 

Private Attributes

point shift
 
double scale
 

Detailed Description

template<int dim, typename point, typename value>
class fmm::MortonTree< dim, point, value >

Definition at line 25 of file morton_tree.h.

Member Typedef Documentation

◆ particle_t

template<int dim, typename point , typename value >
using fmm::MortonTree< dim, point, value >::particle_t = particle<point, value>

Definition at line 28 of file morton_tree.h.

◆ TreeCell_t

template<int dim, typename point , typename value >
using fmm::MortonTree< dim, point, value >::TreeCell_t = TreeCell<point, value>

Definition at line 29 of file morton_tree.h.

Constructor & Destructor Documentation

◆ MortonTree()

template<int dim, typename point , typename value >
fmm::MortonTree< dim, point, value >::MortonTree ( std::vector< particle_t > &&  particles,
size_t  tree_depth 
)

Definition at line 287 of file morton_tree.cpp.

287 : tree_depth(tree_depth_), particles(particles_)
288{
289 double T = omp_get_wtime();
290 //if (IAmRoot()) std::cout << "\n************ Start Building Tree ************" << std::endl;
291 const int dim2 = MyPow(2, dim);
292 double t = omp_get_wtime();
293 {
294 auto be = box_extent(particles);
295 shift = be.first; scale = be.second;
296
297 while (scale < FORCE_EPS * (1 << tree_depth))
298 {
299 --tree_depth;
300 }
301
302 if constexpr (dim == 2)
303 shift -= std::complex<double> {1.e-7, 1.e-7}; // min particles shouldnt have coordinates equal zero
304 else
305 shift -= Vector3d {1.e-7, 1.e-7, 1.e-7}; // min particles shouldnt have coordinates equal zero
306 scale += 1.e-6; // max particles shouldnt have coordinate equal 1
307 }
308 //if (IAmRoot()) std::cout << "compute extent time: " << omp_get_wtime() - t << std::endl;
309 //if (IAmRoot()) std::cout << "scale factors: shift = " << shift << ", extent = " << scale << std::endl;
310
311 size_t num_particles = particles.size();
312 // if (IAmRoot()) std::cout << "particles num = " << num_particles << std::endl;
313
314 levels.resize(tree_depth);
315 tbb::parallel_for(size_t(0), tree_depth, [&](size_t i) {
316 levels[i].resize(std::min(num_particles, (size_t)MyPow(size_t(dim2), (unsigned int)i)));
317 });
318 level_sizes.resize(tree_depth);
319 positions_map.resize(num_particles);
320
321 t = omp_get_wtime();
322 tbb::parallel_for_each(particles.begin(), particles.end(), [&](particle_t& x) {
323 x.morton_code = MortonCode<dim, point>(x.center, (int)(tree_depth - 1), shift, scale);
324 assert(x.morton_code < MyPow(dim2, tree_depth - 1));
325 });
326 //if (IAmRoot()) std::cout << "compute morton codes time: " << omp_get_wtime() - t << std::endl;
327
328 assert(MyPow(dim2, tree_depth) > std::max_element(particles.begin(), particles.end(), [&](const particle_t& x, const particle_t& y) {return x.morton_code < y.morton_code; })->morton_code);
329 t = omp_get_wtime();
330 {
331#ifdef deterministic_behaviour
332 tbb::parallel_sort(particles.begin(), particles.end(), [](const auto& x, const auto& y) {return x.morton_code < y.morton_code; });
333 //boost::sort::block_indirect_sort(particles.begin(), particles.end(), [](const auto& x, const auto& y) {return x.morton_code < y.morton_code; }, 1);
334#else
335 if (IAmRoot())
336 {
337 // counting sort, using known number of unique numbers
338 tbb::concurrent_vector<std::atomic_size_t> counts(MyPow(dim2, (unsigned int)(tree_depth - 1)) + 1);
339 tbb::parallel_for_each(particles.begin(), particles.end(), [&](const auto& x) {counts[1 + x.morton_code]++; });
340 for (int i = 1; i < counts.size(); ++i)
341 counts[i] += counts[i - 1];
342 assert(counts.back() == num_particles);
343
344 tbb::scalable_allocator<small_particle<dim, value>> temp;
345 constexpr size_t memsize = sizeof(small_particle<dim, value>);
346 auto ptr = temp.allocate(num_particles);
347
348 //t = omp_get_wtime();
349 tbb::parallel_for(size_t(0), num_particles, [&](size_t i) {
350 const auto& x = particles[i];
351 size_t pos = counts[x.morton_code]++;
352 assert(pos < num_particles);
353 positions_map[i] = pos;
354 memcpy(&ptr[pos], &x, memsize);
355 });
356
357 tbb::parallel_for(size_t(0), num_particles, [&](size_t i) {
358 memcpy(&particles[i], &ptr[i], memsize);
359 });
360
361 temp.deallocate(ptr, num_particles);
362
363 assert(std::is_sorted(particles.begin(), particles.end(), [](const auto& x, const auto& y) {return x.morton_code < y.morton_code; }));
364 }
365#ifdef FMM_MPI
366 MPI_Bcast(particles.data(), num_particles * sizeof(particle_t), MPI_BYTE, RootID(), MPI_COMM_WORLD);
367 MPI_Bcast(positions_map.data(), num_particles * sizeof(size_t), MPI_BYTE, RootID(), MPI_COMM_WORLD);
368#endif
369
370#endif
371 }
372 //if (IAmRoot()) std::cout << "sort time: " << omp_get_wtime() - t << std::endl;
373 t = omp_get_wtime();
374#ifdef deterministic_behaviour
375 tbb::parallel_for_each(particles.begin(), particles.end(), [&](auto& x) {x.morton_code >>= dim * (30 - tree_depth); });
376#endif
377 {
378 auto& top_level = levels.back();
379 auto ptr = std::unique_copy(exec_policy, particles.begin(), particles.end(), top_level.begin(), [&](const auto& x, const auto& y) {return (x.morton_code) == (y.morton_code); });
380 level_sizes.back() = ptr - top_level.begin();
381
382 int idx_bottom = 0, idx_top = 0;
383 for (int j = 0; j < num_particles; ++j)
384 {
385 if ((particles[j].morton_code) != (top_level[idx_top].morton_code))
386 {
387 auto& cell = top_level[idx_top];
388 cell.source_range = { idx_bottom, j };
389 cell.center = PointFromMortonCode(cell.morton_code, (int)(tree_depth - 1), shift, scale);
390 ++idx_top;
391 idx_bottom = j;
392 }
393 }
394 auto& cell = top_level[idx_top];
395 cell.source_range = { idx_bottom, num_particles };
396 cell.center = PointFromMortonCode(cell.morton_code, (int)(tree_depth - 1), shift, scale);
397
398 //if (IAmRoot()) std::cout << "level " << tree_depth - 1 << " size: " << level_sizes.back() << std::endl;
399 }
400
401 for (int i = (int)(tree_depth - 2); i >= 0; --i)
402 {
403 auto& top_level = levels[i];
404 auto& bottom_level = levels[i + 1];
405
406 auto ptr = std::unique_copy(exec_policy, bottom_level.begin(), bottom_level.begin() + level_sizes[i + 1], top_level.begin(), [&](const auto& x, const auto& y) {return (x.morton_code >> dim) == (y.morton_code >> dim); });
407 level_sizes[i] = ptr - top_level.begin();
408
409 //if (IAmRoot()) std::cout << "level " << i << " size: " << level_sizes[i] << std::endl;
410
411 int idx_bottom = 0, idx_top = 0;
412 for (int j = 0; j < level_sizes[i + 1]; ++j)
413 {
414 if ((bottom_level[j].morton_code >> dim) != (top_level[idx_top].morton_code >> dim))
415 {
416 auto& cell = top_level[idx_top];
417 cell.source_range = { idx_bottom, j };
418 cell.morton_code >>= dim;
419 cell.center = PointFromMortonCode(cell.morton_code, i, shift, scale);
420 ++idx_top;
421 idx_bottom = j;
422 }
423 bottom_level[j].parent = idx_top;
424 }
425 auto& cell = top_level[idx_top];
426 cell.source_range = { idx_bottom, level_sizes[i + 1] };
427 cell.morton_code >>= dim;
428 cell.center = PointFromMortonCode(cell.morton_code, i, shift, scale);
429 }
430 //if (IAmRoot()) std::cout << "create levels time: " << omp_get_wtime() - t << std::endl;
431
432 t = omp_get_wtime();
433 {
434 std::vector<size_t> inverse_positions_map(num_particles);
435 tbb::parallel_for(size_t(0), num_particles, [&](size_t i){
436 inverse_positions_map[positions_map[i]] = i;
437 });
438
439 value Zero;
440 if constexpr (std::is_same_v<value, double>)
441 Zero = 0;
442 if constexpr (std::is_same_v<value, Vector3d>)
443 Zero = { 0,0,0 };
444 auto& leaves = levels.back();
445 tbb::enumerable_thread_specific<size_t> local_num(0);
446 tbb::parallel_for(size_t(0), level_sizes.back(), [&](size_t k){
447 auto& leaf = leaves[k];
448 auto& [s_begin, s_end] = leaf.source_range;
449 auto& [t_begin, t_end] = leaf.target_range;
450 t_end = s_end;
451 t_begin = s_begin;
452 for (size_t i = s_begin; i < s_end; ++i)
453 {
454 if (particles[i].q != Zero)
455 {
456 std::swap(particles[t_begin], particles[i]);
457 std::swap(inverse_positions_map[t_begin++], inverse_positions_map[i]);
458 }
459 }
460 s_end = t_begin;
461 local_num.local() += t_end - t_begin;
462
463 });
464
465 tbb::parallel_for(size_t(0), num_particles, [&](size_t i){
466 positions_map[inverse_positions_map[i]] = i;
467 });
468
469 for (const auto& x : local_num)
470 targets_num += x;
471 //if (IAmRoot()) std::cout << "targets num: " << targets_num << std::endl;
472
473 }
474 //if (IAmRoot()) std::cout << "source/target partition time: " << omp_get_wtime() - t << std::endl;
475
476 t = omp_get_wtime();
478 //if (IAmRoot()) std::cout << "fill neighbours time: " << omp_get_wtime() - t << std::endl;
479
480 //������ ������ ������� ������������
481 /*
482 t = omp_get_wtime();
483 if (targets_num == 0)
484 {
485 auto& leaves = levels.back();
486 for (int i = 0; i < level_sizes.back(); ++i)
487 {
488 const auto& cell = leaves[i];
489 for (const auto& idx : cell.closeneighbours)
490 {
491 auto& neighbour_cell = leaves[idx];
492 auto ptr = std::find(neighbour_cell.closeneighbours.begin(), neighbour_cell.closeneighbours.end(), i);
493 neighbour_cell.closeneighbours.erase(ptr);
494 }
495 }
496 }
497 if (IAmRoot()) std::cout << "remove duplicate nbr indices time:" << omp_get_wtime() - t << std::endl;
498 */
499
500 //if (IAmRoot()) std::cout << "total build time: " << omp_get_wtime() - T << std::endl;
501 //if (IAmRoot()) std::cout << "************ End Building Tree ************\n\n";
502}
particle< point, value > particle_t
Definition morton_tree.h:28
std::vector< std::vector< TreeCell_t > > levels
Definition morton_tree.h:33
std::vector< particle_t > particles
Definition morton_tree.h:37
std::vector< size_t > level_sizes
Definition morton_tree.h:34
std::vector< size_t > positions_map
Definition morton_tree.h:38
#define exec_policy
std::pair< point, double > box_extent(const std::vector< particle< point, value > > &particles)
constexpr T MyPow(T base, unsigned int exp)
Definition simple_math.h:85
point PointFromMortonCode(size_t val, int depth, point shift, double scale)
bool IAmRoot()
Definition mpi_utils.h:101
constexpr double FORCE_EPS
Definition defs.h:28
Vector3< double > Vector3d
Definition utils.h:63
Here is the call graph for this function:

Member Function Documentation

◆ FillNeighbours()

template<int dim, typename point , typename value >
void fmm::MortonTree< dim, point, value >::FillNeighbours ( )
private

Definition at line 148 of file morton_tree.cpp.

149{
150 if (tree_depth > 1)
151 for (int i = 0; i < level_sizes[1]; ++i)
152 {
153 auto& cell = levels[1][i];
154 auto& [s, e] = levels[0][0].source_range;
155 std::vector<size_t> indexes(e - s);
156 std::iota(indexes.begin(), indexes.end(), s);
157 indexes.erase(indexes.begin() + i);
158 cell.closeneighbours = indexes;
159 }
160 for (int i = 2; i < tree_depth; ++i)
161 {
162 double dw = sqrt(dim + 1.e-5) * scale / (1 << i);
163 dw *= dw;
164 const auto& parent_level = levels[i - 1];
165 auto& current_level = levels[i];
166
167 tbb::parallel_for_each(current_level.begin(), current_level.begin() + level_sizes[i], [&](auto& cell)
168 {
169 if constexpr (dim == 2)
170 {
171 cell.closeneighbours.reserve(9);
172 cell.farneighbours.reserve(27);
173 }
174 else
175 {
176 cell.closeneighbours.reserve(27);
177 cell.farneighbours.reserve(189);
178 }
179
180 const auto& parent_cell = parent_level[cell.parent];
181 for (const auto& parent_neighbours : parent_cell.closeneighbours)
182 {
183 const auto& [s, e] = parent_level[parent_neighbours].source_range;
184 for (auto k = s; k < e; ++k)
185 {
186 if (norm(current_level[k].center - cell.center) < dw)
187 cell.closeneighbours.push_back(k);
188 else
189 cell.farneighbours.push_back(k);
190 }
191 }
192
193 const auto& [s, e] = parent_level[cell.parent].source_range;
194 for (auto k = s; k < e; ++k)
195 {
196 if (&cell != &(current_level[k]))
197 {
198 if (norm(current_level[k].center - cell.center) < dw)
199 cell.closeneighbours.push_back(k);
200 else
201 cell.farneighbours.push_back(k);
202 }
203 }
204 cell.farneighbours.shrink_to_fit();
205 cell.closeneighbours.shrink_to_fit();
206 });
207 }
208}
double norm(const Vector3< T > &vec)
Definition utils.h:119
Here is the call graph for this function:

Member Data Documentation

◆ level_sizes

template<int dim, typename point , typename value >
std::vector<size_t> fmm::MortonTree< dim, point, value >::level_sizes

Definition at line 34 of file morton_tree.h.

◆ levels

template<int dim, typename point , typename value >
std::vector<std::vector<TreeCell_t> > fmm::MortonTree< dim, point, value >::levels

Definition at line 33 of file morton_tree.h.

◆ particles

template<int dim, typename point , typename value >
std::vector<particle_t> fmm::MortonTree< dim, point, value >::particles

Definition at line 37 of file morton_tree.h.

◆ positions_map

template<int dim, typename point , typename value >
std::vector<size_t> fmm::MortonTree< dim, point, value >::positions_map

Definition at line 38 of file morton_tree.h.

◆ scale

template<int dim, typename point , typename value >
double fmm::MortonTree< dim, point, value >::scale
private

Definition at line 43 of file morton_tree.h.

◆ shift

template<int dim, typename point , typename value >
point fmm::MortonTree< dim, point, value >::shift
private

Definition at line 42 of file morton_tree.h.

◆ targets_num

template<int dim, typename point , typename value >
size_t fmm::MortonTree< dim, point, value >::targets_num = 0

Definition at line 36 of file morton_tree.h.

◆ tree_depth

template<int dim, typename point , typename value >
size_t fmm::MortonTree< dim, point, value >::tree_depth

Definition at line 35 of file morton_tree.h.


The documentation for this class was generated from the following files: