151 for (
int i = 0; i < level_sizes[1]; ++i)
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;
160 for (
int i = 2; i < tree_depth; ++i)
162 double dw = sqrt(dim + 1.e-5) * scale / (1 << i);
164 const auto& parent_level = levels[i - 1];
165 auto& current_level = levels[i];
167 tbb::parallel_for_each(current_level.begin(), current_level.begin() + level_sizes[i], [&](
auto& cell)
169 if constexpr (dim == 2)
171 cell.closeneighbours.reserve(9);
172 cell.farneighbours.reserve(27);
176 cell.closeneighbours.reserve(27);
177 cell.farneighbours.reserve(189);
180 const auto& parent_cell = parent_level[cell.parent];
181 for (
const auto& parent_neighbours : parent_cell.closeneighbours)
183 const auto& [s, e] = parent_level[parent_neighbours].source_range;
184 for (
auto k = s; k < e; ++k)
186 if (
norm(current_level[k].center - cell.center) < dw)
187 cell.closeneighbours.push_back(k);
189 cell.farneighbours.push_back(k);
193 const auto& [s, e] = parent_level[cell.parent].source_range;
194 for (
auto k = s; k < e; ++k)
196 if (&cell != &(current_level[k]))
198 if (
norm(current_level[k].center - cell.center) < dw)
199 cell.closeneighbours.push_back(k);
201 cell.farneighbours.push_back(k);
204 cell.farneighbours.shrink_to_fit();
205 cell.closeneighbours.shrink_to_fit();
221 tbb::enumerable_thread_specific<double> xmin(particles[0].center.real()), xmax(particles[0].center.real()),
222 ymin(particles[0].center.imag()), ymax(particles[0].center.imag());
223 tbb::parallel_for(tbb::blocked_range<size_t>(0, particles.size()), [&](
const tbb::blocked_range<size_t>& r)
225 auto& Xmin = xmin.local();
226 auto& Xmax = xmax.local();
227 auto& Ymin = ymin.local();
228 auto& Ymax = ymax.local();
229 for (size_t i = r.begin(); i < r.end(); ++i)
231 double x = particles[i].center.real();
232 double y = particles[i].center.imag();
233 Xmin = std::min(Xmin, x);
234 Xmax = std::max(Xmax, x);
235 Ymin = std::min(Ymin, y);
236 Ymax = std::max(Ymax, y);
239 double Xmin = *std::min_element(xmin.begin(), xmin.end());
240 double Ymin = *std::min_element(ymin.begin(), ymin.end());
241 double Xmax = *std::max_element(xmax.begin(), xmax.end());
242 double Ymax = *std::max_element(ymax.begin(), ymax.end());
244 double dw = std::max(Xmax - Xmin, Ymax - Ymin);
245 return { {Xmin,Ymin}, dw };
251 tbb::enumerable_thread_specific<double> xmin(particles[0].center[0]), xmax(particles[0].center[0]),
252 ymin(particles[0].center[1]), ymax(particles[0].center[1]),
253 zmin(particles[0].center[2]), zmax(particles[0].center[2]);
254 tbb::parallel_for(tbb::blocked_range<size_t>(0, particles.size()), [&](
const tbb::blocked_range<size_t>& r)
256 auto& Xmin = xmin.local();
257 auto& Xmax = xmax.local();
258 auto& Ymin = ymin.local();
259 auto& Ymax = ymax.local();
260 auto& Zmin = zmin.local();
261 auto& Zmax = zmax.local();
262 for (size_t i = r.begin(); i < r.end(); ++i)
264 double x = particles[i].center[0];
265 double y = particles[i].center[1];
266 double z = particles[i].center[2];
267 Xmin = std::min(Xmin, x);
268 Xmax = std::max(Xmax, x);
269 Ymin = std::min(Ymin, y);
270 Ymax = std::max(Ymax, y);
271 Zmin = std::min(Zmin, z);
272 Zmax = std::max(Zmax, z);
275 double Xmin = *std::min_element(xmin.begin(), xmin.end());
276 double Ymin = *std::min_element(ymin.begin(), ymin.end());
277 double Zmin = *std::min_element(zmin.begin(), zmin.end());
278 double Xmax = *std::max_element(xmax.begin(), xmax.end());
279 double Ymax = *std::max_element(ymax.begin(), ymax.end());
280 double Zmax = *std::max_element(zmax.begin(), zmax.end());
282 double dw = std::max({Xmax - Xmin, Ymax - Ymin, Zmax - Zmin});
283 return { {Xmin, Ymin, Zmin}, dw };
289 double T = omp_get_wtime();
291 const int dim2 =
MyPow(2, dim);
292 double t = omp_get_wtime();
302 if constexpr (dim == 2)
303 shift -= std::complex<double> {1.e-7, 1.e-7};
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)));
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));
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; });
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);
344 tbb::scalable_allocator<small_particle<dim, value>> temp;
346 auto ptr = temp.allocate(num_particles);
349 tbb::parallel_for(
size_t(0), num_particles, [&](
size_t i) {
352 assert(pos < num_particles);
354 memcpy(&ptr[pos], &x, memsize);
357 tbb::parallel_for(
size_t(0), num_particles, [&](
size_t i) {
361 temp.deallocate(ptr, num_particles);
363 assert(std::is_sorted(
particles.begin(),
particles.end(), [](
const auto& x,
const auto& y) {return x.morton_code < y.morton_code; }));
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);
374#ifdef deterministic_behaviour
375 tbb::parallel_for_each(
particles.begin(),
particles.end(), [&](
auto& x) {x.morton_code >>= dim * (30 - tree_depth); });
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); });
382 int idx_bottom = 0, idx_top = 0;
383 for (
int j = 0; j < num_particles; ++j)
385 if ((
particles[j].morton_code) != (top_level[idx_top].morton_code))
387 auto& cell = top_level[idx_top];
388 cell.source_range = { idx_bottom, j };
394 auto& cell = top_level[idx_top];
395 cell.source_range = { idx_bottom, num_particles };
401 for (
int i = (
int)(
tree_depth - 2); i >= 0; --i)
403 auto& top_level =
levels[i];
404 auto& bottom_level =
levels[i + 1];
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); });
411 int idx_bottom = 0, idx_top = 0;
414 if ((bottom_level[j].morton_code >> dim) != (top_level[idx_top].morton_code >> dim))
416 auto& cell = top_level[idx_top];
417 cell.source_range = { idx_bottom, j };
418 cell.morton_code >>= dim;
423 bottom_level[j].parent = idx_top;
425 auto& cell = top_level[idx_top];
426 cell.source_range = { idx_bottom,
level_sizes[i + 1] };
427 cell.morton_code >>= dim;
434 std::vector<size_t> inverse_positions_map(num_particles);
435 tbb::parallel_for(
size_t(0), num_particles, [&](
size_t i){
440 if constexpr (std::is_same_v<value, double>)
442 if constexpr (std::is_same_v<value, Vector3d>)
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;
452 for (size_t i = s_begin; i < s_end; ++i)
454 if (particles[i].q != Zero)
456 std::swap(particles[t_begin], particles[i]);
457 std::swap(inverse_positions_map[t_begin++], inverse_positions_map[i]);
461 local_num.local() += t_end - t_begin;
465 tbb::parallel_for(
size_t(0), num_particles, [&](
size_t i){
469 for (
const auto& x : local_num)