VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
fmm::FastMultipole Class Reference

#include <multipole.h>

Collaboration diagram for fmm::FastMultipole:

Public Member Functions

 FastMultipole (const std::vector< particle2d > &particles, double eps=1.e-8, int N=FMM_AUTO, int tree_depth=FMM_AUTO)
 
 FastMultipole (std::vector< particle2d > &&particles, double eps=1.e-8, int N=FMM_AUTO, int tree_depth=FMM_AUTO)
 
 FastMultipole (const std::vector< particle2d > &source_particles, const std::vector< particle2d > &target_particles, double eps=1.e-8, int N=FMM_AUTO, int tree_depth=FMM_AUTO)
 

Public Attributes

std::vector< std::complex< double > > forces
 
std::vector< double > potentials
 

Private Member Functions

void Solve (std::vector< particle2d > &&particles, double eps=1.e-8, int N=FMM_AUTO, int tree_depth=FMM_AUTO)
 
void Multipole (std::complex< double > *a, const std::pair< size_t, size_t > &particle_range, const std::complex< double > &z0)
 
void M2M (const std::complex< double > *a, const std::complex< double > &z0, std::complex< double > *b, std::vector< std::complex< double > > &work)
 
void M2L (const std::complex< double > *a, const std::complex< double > &z0, std::complex< double > *b, std::vector< std::complex< double > > &work)
 
void L2L (const std::complex< double > *a, const std::complex< double > &z0, std::complex< double > *b)
 
void Upward ()
 
void Downward ()
 
void ComputePotentials ()
 
void ComputeForces ()
 

Private Attributes

std::shared_ptr< MortonTree2dtree
 
std::vector< std::vector< std::complex< double > > > outer_expansions
 
std::vector< std::vector< std::complex< double > > > inner_expansions
 
size_t tree_depth
 
int N
 
size_t num_particles
 
size_t targets_num
 
tbb::enumerable_thread_specific< std::vector< std::complex< double > > > local_work
 

Detailed Description

Definition at line 10 of file multipole.h.

Constructor & Destructor Documentation

◆ FastMultipole() [1/3]

fmm::FastMultipole::FastMultipole ( const std::vector< particle2d > &  particles,
double  eps = 1.e-8,
int  N = FMM_AUTO,
int  tree_depth = FMM_AUTO 
)

Definition at line 454 of file multipole.cpp.

455{
456 auto particles_copy = particles;
457 targets_num = particles.size();
458 Solve(std::move(particles_copy), eps, N_, tree_depth_);
459}
void Solve(std::vector< particle2d > &&particles, double eps=1.e-8, int N=FMM_AUTO, int tree_depth=FMM_AUTO)

◆ FastMultipole() [2/3]

fmm::FastMultipole::FastMultipole ( std::vector< particle2d > &&  particles,
double  eps = 1.e-8,
int  N = FMM_AUTO,
int  tree_depth = FMM_AUTO 
)

Definition at line 461 of file multipole.cpp.

462{
463 targets_num = particles.size();
464 Solve(std::move(particles), eps, N_, tree_depth_);
465}

◆ FastMultipole() [3/3]

fmm::FastMultipole::FastMultipole ( const std::vector< particle2d > &  source_particles,
const std::vector< particle2d > &  target_particles,
double  eps = 1.e-8,
int  N = FMM_AUTO,
int  tree_depth = FMM_AUTO 
)

Definition at line 467 of file multipole.cpp.

468{
469 std::vector<particle2d> particles(source_particles.size() + target_particles.size());
470 memcpy(particles.data(), target_particles.data(), target_particles.size() * sizeof(particle2d));
471 memcpy(particles.data() + target_particles.size(), source_particles.data(), source_particles.size() * sizeof(particle2d));
472 targets_num = target_particles.size();
473 Solve(std::move(particles), eps, N_, tree_depth_);
474}
particle< point2d, double > particle2d
Definition utils.h:155

Member Function Documentation

◆ ComputeForces()

void fmm::FastMultipole::ComputeForces ( )
private

Definition at line 345 of file multipole.cpp.

346{
347 tbb::enumerable_thread_specific<std::complex<double>> dz_local;
348 tbb::enumerable_thread_specific<std::complex<double>> force_local;
349 tbb::enumerable_thread_specific<std::vector<std::complex<double>>> buf_forces_local((std::vector<std::complex<double>>(num_particles)));
350
351 const auto& leaves = tree->levels.back();
352 const auto& leaves_inner = inner_expansions.back();
353 auto& particles = tree->particles;
354
355#ifdef FMM_MPI
356 auto [Begin, End] = LocalPart(0, tree->level_sizes.back());
357#else
358 size_t Begin = 0, End = tree->level_sizes.back();
359#endif
360
361 decltype(&TreeCell2d::source_range) range_ptr;
362 if (tree->targets_num == 0) // targets = sources
363 range_ptr = &TreeCell2d::source_range;
364 else
365 range_ptr = &TreeCell2d::target_range;
366 const auto& index_mapping = tree->positions_map;
367
368 tbb::parallel_for(Begin, End, [&](size_t i) {
369 auto& dz = dz_local.local();
370 auto& force = force_local.local();
371 const auto& cell = leaves[i];
372 const auto& inner = leaves_inner.data() + i * N;
373 auto& buf_forces = buf_forces_local.local();
374
375 const auto& [p1_begin, p1_end] = cell.*range_ptr;
376
377 for (auto j = p1_begin; j < p1_end; ++j)
378 {
379 auto& particle = particles[j];
380
381 if (range_ptr == &TreeCell2d::target_range && particle.q == 0)
382 {
383 force = 0.0;
384
385 const auto& [p2_begin, p2_end] = cell.source_range;
386 for (auto k = p2_begin; k < p2_end; ++k)
387 force += Force2d(particle, particles[k]);
388
389 for (const auto& idx : cell.closeneighbours)
390 {
391 const auto& neighbour_cell = leaves[idx];
392 const auto& [p2_begin, p2_end] = neighbour_cell.source_range;
393
394 for (auto k = p2_begin; k < p2_end; ++k)
395 force += Force2d(particle, particles[k]);
396 }
397 }
398 else
399 {
400 force = Force2d(particle, particle);
401
402 for (auto k = j + 1; k < p1_end; ++k)
403 {
404 Force2dMutual(particle, particles[k], force, buf_forces[k]);
405 }
406
407 for (const auto& idx : cell.closeneighbours)
408 {
409 const auto& neighbour_cell = leaves[idx];
410 const auto& [p2_begin, p2_end] = neighbour_cell.source_range;
411
412 for (auto k = p2_begin; k < p2_end; ++k)
413 Force2dMutual(particle, particles[k], force, buf_forces[k]);
414 }
415 }
416 buf_forces[j] += force;
417 }
418
419 for (auto j = p1_begin; j < p1_end; ++j)
420 {
421 auto& particle = particles[j];
422 force = 0.0;
423 dz = particle.center - cell.center;
424 complex<double> dzpow{ 1.0 };
425 for (int k = 1; k < N; ++k)
426 {
427 force += double(k) * inner[k] * dzpow;
428 dzpow *= dz;
429 }
430 buf_forces[j] += force;
431 }
432 });
433
434 auto& buf_forces = *buf_forces_local.begin();
435 for (auto it = buf_forces_local.begin() + 1; it < buf_forces_local.end(); it++)
436 {
437 const auto& x = *it;
438 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_particles),
439 [&](tbb::blocked_range<size_t> r) {
440 for (auto i = r.begin(); i < r.end(); ++i)
441 buf_forces[i] += x[i];
442 });
443 }
444
445#ifdef FMM_MPI
446 AllReduce(buf_forces.data(), buf_forces.size());
447#endif
448
449 tbb::parallel_for(size_t(0), targets_num, [&](size_t i){
450 forces[i] = buf_forces[index_mapping[i]];
451 });
452}
std::vector< std::complex< double > > forces
Definition multipole.h:17
std::shared_ptr< MortonTree2d > tree
Definition multipole.h:32
std::vector< std::vector< std::complex< double > > > inner_expansions
Definition multipole.h:34
void Force2dMutual(const particle2d &p1, const particle2d &p2, std::complex< double > &force1, std::complex< double > &force2)
Here is the call graph for this function:

◆ ComputePotentials()

void fmm::FastMultipole::ComputePotentials ( )
private

Definition at line 236 of file multipole.cpp.

237{
238 tbb::enumerable_thread_specific<std::complex<double>> dz_local;
239 tbb::enumerable_thread_specific<double> phi_local;
240 tbb::enumerable_thread_specific<std::vector<double>> buf_potentials_local((std::vector<double>(num_particles)));
241
242 const auto& leaves = tree->levels.back();
243 const auto& leaves_inner = inner_expansions.back();
244 auto& particles = tree->particles;
245
246#ifdef FMM_MPI
247 auto [Begin, End] = LocalPart(0, tree->level_sizes.back());
248#else
249 size_t Begin = 0, End = tree->level_sizes.back();
250#endif
251
252 decltype(&TreeCell2d::source_range) range_ptr;
253 if (tree->targets_num == 0) // targets = sources
254 range_ptr = &TreeCell2d::source_range;
255 else
256 range_ptr = &TreeCell2d::target_range;
257 const auto& index_mapping = tree->positions_map;
258
259 tbb::parallel_for(Begin, End, [&](size_t i) {
260 auto& dz = dz_local.local();
261 auto& phi = phi_local.local();
262 const auto& cell = leaves[i];
263 const auto& inner = leaves_inner.data() + i * N;
264 auto& buf_potentials = buf_potentials_local.local();
265
266 const auto& [p1_begin, p1_end] = cell.*range_ptr;
267
268 for (auto j = p1_begin; j < p1_end; ++j)
269 {
270 auto& particle = particles[j];
271
272 if (range_ptr == &TreeCell2d::target_range && particle.q == 0)
273 {
274 phi = 0.0;
275
276 const auto& [p2_begin, p2_end] = cell.source_range;
277 for (auto k = p2_begin; k < p2_end; ++k)
278 phi += Potential2d(particle, particles[k]);
279
280 for (const auto& idx : cell.closeneighbours)
281 {
282 const auto& neighbour_cell = leaves[idx];
283 const auto& [p2_begin, p2_end] = neighbour_cell.source_range;
284
285 for (auto k = p2_begin; k < p2_end; ++k)
286 phi += Potential2d(particle, particles[k]);
287 }
288 }
289 else
290 {
291 phi = Potential2d(particle, particle);
292
293 for (auto k = j + 1; k < p1_end; ++k)
294 {
295 Potential2dMutual(particle, particles[k], phi, buf_potentials[k]);
296 }
297
298 for (const auto& idx : cell.closeneighbours)
299 {
300 const auto& neighbour_cell = leaves[idx];
301 const auto& [p2_begin, p2_end] = neighbour_cell.source_range;
302
303 for (auto k = p2_begin; k < p2_end; ++k)
304 Potential2dMutual(particle, particles[k], phi, buf_potentials[k]);
305 }
306 }
307 buf_potentials[j] += phi;
308 }
309
310 for (auto j = p1_begin; j < p1_end; ++j)
311 {
312 auto& particle = particles[j];
313 phi = 0.0;
314 dz = particle.center - cell.center;
315 complex<double> dzpow{ 1.0 };
316 for (int k = 0; k < N; ++k)
317 {
318 phi += inner[k].real() * dzpow.real() - inner[k].imag() * dzpow.imag();
319 dzpow *= dz;
320 }
321 buf_potentials[j] += phi;
322 }
323 });
324
325 auto& buf_potentials = *buf_potentials_local.begin();
326 for (auto it = buf_potentials_local.begin() + 1; it < buf_potentials_local.end(); it++)
327 {
328 const auto& x = *it;
329 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_particles),
330 [&](tbb::blocked_range<size_t> r) {
331 for (auto i = r.begin(); i < r.end(); ++i)
332 buf_potentials[i] += x[i];
333 });
334 }
335
336#ifdef FMM_MPI
337 AllReduce(buf_potentials.data(), buf_potentials.size());
338#endif
339
340 tbb::parallel_for(size_t(0), targets_num, [&](size_t i){
341 potentials[i] = buf_potentials[index_mapping[i]];
342 });
343}
std::vector< double > potentials
Definition multipole.h:18
void Potential2dMutual(const particle2d &p1, const particle2d &p2, double &potential1, double &potential2)
Here is the call graph for this function:

◆ Downward()

void fmm::FastMultipole::Downward ( )
private

Definition at line 182 of file multipole.cpp.

183{
184#ifdef FMM_MPI
185 std::vector<int> sizes(NProc());
186 std::vector<int> displs(NProc());
187#endif
188
189 for (int i = 2; i < tree->tree_depth; ++i)
190 {
191 const auto& top_level = tree->levels[i - 1];
192 const auto& top_inner = inner_expansions[i - 1];
193 auto& bottom_level = tree->levels[i];
194 auto& bottom_inner = inner_expansions[i];
195 const auto& bottom_outer = outer_expansions[i];
196
197#ifdef FMM_MPI
198 auto [Begin, End] = LocalPart(0, tree->level_sizes[i]);
199#else
200 size_t Begin = 0, End = tree->level_sizes[i];
201#endif
202
203 tbb::parallel_for(Begin, End, [&](size_t j)
204 {
205 TreeCell2d& cell = bottom_level[j];
206 auto& work = local_work.local();
207 auto& parent_cell = top_level[cell.parent];
208 L2L(top_inner.data() + N * cell.parent, parent_cell.center - cell.center, bottom_inner.data() + N * j);
209
210 for (const auto& idx : cell.farneighbours)
211 {
212 const auto& far_neighbour = bottom_level[idx];
213 M2L(bottom_outer.data() + idx * N, far_neighbour.center - cell.center, bottom_inner.data() + N * j, work);
214 }
215 });
216
217#ifdef FMM_MPI
218 {
219 std::vector<std::complex<double>> buf(bottom_inner.size());
220 for (int j = 0; j < NProc(); ++j)
221 {
222 sizes[j] = N * LocalPart(0, tree->level_sizes[i], j);
223 }
224 for (int j = 1; j < NProc(); ++j)
225 {
226 displs[j] = displs[j - 1] + sizes[j - 1];
227 }
228 MPI_Allgatherv(bottom_inner.data() + displs[MyID()], sizes[MyID()], MPI_COMPLEX16,
229 buf.data(), sizes.data(), displs.data(), MPI_COMPLEX16, MPI_COMM_WORLD);
230 std::swap(buf, bottom_inner);
231 }
232#endif
233 }
234}
void L2L(const std::complex< double > *a, const std::complex< double > &z0, std::complex< double > *b)
Definition multipole.cpp:89
std::vector< std::vector< std::complex< double > > > outer_expansions
Definition multipole.h:33
void M2L(const std::complex< double > *a, const std::complex< double > &z0, std::complex< double > *b, std::vector< std::complex< double > > &work)
Definition multipole.cpp:69
tbb::enumerable_thread_specific< std::vector< std::complex< double > > > local_work
Definition multipole.h:41
TreeCell< point2d, double > TreeCell2d
Definition morton_tree.h:47
Here is the call graph for this function:

◆ L2L()

void fmm::FastMultipole::L2L ( const std::complex< double > *  a,
const std::complex< double > &  z0,
std::complex< double > *  b 
)
private

Definition at line 89 of file multipole.cpp.

90{
91 for (int i = 0; i < N; ++i)
92 b[i] = a[i];
93 for (int j = 0; j < N; ++j)
94 {
95 for (int k = N - j - 1; k < N - 1; ++k)
96 {
97 b[k] -= z0 * b[k + 1];
98 }
99 }
100}
Here is the caller graph for this function:

◆ M2L()

void fmm::FastMultipole::M2L ( const std::complex< double > *  a,
const std::complex< double > &  z0,
std::complex< double > *  b,
std::vector< std::complex< double > > &  work 
)
private

Definition at line 69 of file multipole.cpp.

70{
71 work[0] = a[0];
72 b[0] += a[0] * std::conj(log(-z0));
73 for (int i = 1; i < N; ++i)
74 {
75 work[i] = ni(i) * a[i] / MyPow(z0, i);
76 b[0] += work[i];
77 }
78 for (int i = 1; i < N; ++i)
79 {
80 complex<double> tmp{ 0.0 };
81 for (int j = 1; j < N; ++j)
82 {
83 tmp += work[j] * detail::binom(i + j - 1, j - 1);
84 }
85 b[i] += divComp(-a[0] / double(i) + tmp, MyPow(z0, i));
86 }
87}
constexpr BinomNewton_wrapper< 2 *_2d_MAX_MULTIPOLE_NUM > binom
Definition simple_math.h:52
constexpr T MyPow(T base, unsigned int exp)
Definition simple_math.h:85
constexpr double ni(int n)
Definition simple_math.h:99
std::complex< double > divComp(const std::complex< double > &a, const std::complex< double > &b)
Definition multipole.cpp:58
Here is the call graph for this function:
Here is the caller graph for this function:

◆ M2M()

void fmm::FastMultipole::M2M ( const std::complex< double > *  a,
const std::complex< double > &  z0,
std::complex< double > *  b,
std::vector< std::complex< double > > &  work 
)
private

Definition at line 41 of file multipole.cpp.

42{
43 work[0] = 1.0;
44 for (int i = 1; i < N; ++i)
45 work[i] = work[i - 1] * z0;
46
47 for (int j = 1; j < N; ++j)
48 {
49 for (int i = 1; i <= j; ++i)
50 {
51 b[j] += a[i] * work[j - i] * detail::binom(j - 1, i - 1);
52 }
53 b[j] -= a[0] * work[j] / double(j);
54 }
55 b[0] += a[0];
56}
Here is the caller graph for this function:

◆ Multipole()

void fmm::FastMultipole::Multipole ( std::complex< double > *  a,
const std::pair< size_t, size_t > &  particle_range,
const std::complex< double > &  z0 
)
private

Definition at line 25 of file multipole.cpp.

26{
27 auto p_begin = tree->particles.begin() + particle_range.first;
28 auto p_end = tree->particles.begin() + particle_range.second;
29 for (int i = 1; i < N; ++i)
30 {
31 auto temp = std::accumulate(p_begin, p_end, 0.0i, [&z0, i](const complex<double>& x, const particle2d& y)
32 {
33 return x + y.q * MyPow(y.center - z0, i);
34 });
35 a[i] = -temp / double(i);
36 }
37
38 a[0] = std::accumulate(p_begin, p_end, 0.0i, [](const complex<double>& x, const particle2d& y) { return x + y.q; });
39}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Solve()

void fmm::FastMultipole::Solve ( std::vector< particle2d > &&  particles,
double  eps = 1.e-8,
int  N = FMM_AUTO,
int  tree_depth = FMM_AUTO 
)
private

size_t(std::max(3.0, ))//7;// (size_t)std::max(3.0, 2 + log(double(num_particles) / 100.0) / log(4.0));

Definition at line 476 of file multipole.cpp.

477{
478 double T = omp_get_wtime();
479 //if (IAmRoot()) std::cout << "\n***************** Start FMM **************" << std::endl;
480 num_particles = particles.size();
481 if (N_ == FMM_AUTO)
482 N = std::min(fmm::detail::_2d_MAX_MULTIPOLE_NUM, int(-1.18 * log(1.65 * eps)));
483 else
485 //if (IAmRoot()) std::cout << "multipole num = " << N << std::endl;
486
487 size_t initial_depth;
488 if (tree_depth_ == FMM_AUTO)
489 initial_depth = std::max((size_t)4, size_t(log(double(num_particles)) / log(4.0) + 0.5)) - 1;
491 else
492 initial_depth = tree_depth_;
493 //if (IAmRoot()) std::cout << "tree depth = " << initial_depth << std::endl;
494
495 tree = std::make_shared<MortonTree2d>(std::move(particles), initial_depth);
496 tree_depth = tree->tree_depth;
497
498 //if (tree_depth < initial_depth)
499 // std::cout << "Warning: tree_depth was reduced from " << initial_depth << " to " << tree_depth << " to ensure H_CELL < EPS_FORCE" << std::endl;
500
501
502 double t = omp_get_wtime();
505 for (int i = 0; i < tree->tree_depth; ++i)
506 {
507 auto& outer = outer_expansions[i];
508 auto& inner = inner_expansions[i];
509 outer.resize(tree->level_sizes[i] * N);
510 inner.resize(tree->level_sizes[i] * N);
511 }
512 forces.resize(targets_num);
513 potentials.resize(targets_num);
514 //if (IAmRoot()) std::cout << "allocation time: " << omp_get_wtime() - t << std::endl;
515 local_work = tbb::enumerable_thread_specific<vector<complex<double>>>{ vector<complex<double>>(N) };
516
517 Upward();
518
519 t = omp_get_wtime();
520 Downward();
521 //if (IAmRoot()) std::cout << "m2l+l2l time: " << omp_get_wtime() - t << std::endl;
522
523 t = omp_get_wtime();
525 //if (IAmRoot()) std::cout << "leaf potential time: " << omp_get_wtime() - t << std::endl;
526
527 t = omp_get_wtime();
529 //if (IAmRoot()) std::cout << "leaf force time: " << omp_get_wtime() - t << std::endl;
530
531 //if (IAmRoot()) std::cout << "total fmm time: " << omp_get_wtime() - T << std::endl;
532 if (IAmRoot()) std::cout << "FMM time ConvVelo Wake: " << (omp_get_wtime() - T) * 1000.0 << std::endl;
533 //if (IAmRoot()) std::cout << "***************** End FMM **************\n" << std::endl;
534}
const int _2d_MAX_MULTIPOLE_NUM
Definition defs.h:43
const int FMM_AUTO
Definition defs.h:26
bool IAmRoot()
Definition mpi_utils.h:101
Here is the call graph for this function:

◆ Upward()

void fmm::FastMultipole::Upward ( )
private

Definition at line 102 of file multipole.cpp.

103{
104 double t1 = omp_get_wtime();
105
106 auto& leaves = tree->levels.back();
107 auto& leaves_outer = outer_expansions.back();
108#ifdef FMM_MPI
109 auto [Begin, End] = LocalPart(0, tree->level_sizes[tree->tree_depth - 1]);
110#else
111 size_t Begin = 0, End = tree->level_sizes[tree->tree_depth - 1];
112#endif
113 tbb::parallel_for(Begin, End, [&](size_t i) {
114 TreeCell2d& cell = leaves[i];
115 Multipole(leaves_outer.data() + N * i, cell.source_range, cell.center);
116 });
117#ifdef FMM_MPI
118 std::vector<std::complex<double>> buf(leaves_outer.size());
119 std::vector<int> sizes(NProc());
120 std::vector<int> displs(NProc());
121 for (int i = 0; i < NProc(); ++i)
122 {
123 sizes[i] = N * LocalPart(0, tree->level_sizes[tree->tree_depth - 1], i);
124 }multipole time:
125 for (int i = 1; i < NProc(); ++i)
126 {
127 displs[i] = displs[i - 1] + sizes[i - 1];
128 }
129 MPI_Allgatherv(leaves_outer.data() + displs[MyID()], sizes[MyID()], MPI_COMPLEX16,
130 buf.data(), sizes.data(), displs.data(), MPI_COMPLEX16, MPI_COMM_WORLD);
131 std::swap(buf, leaves_outer);
132#endif
133// if (IAmRoot()) std::cout << "multipole time: " << omp_get_wtime() - t1 << std::endl;
134
135 t1 = omp_get_wtime();
136
137 for (int i = (int)(tree->tree_depth - 2); i >= 0; --i)
138 {
139 auto& top_level = tree->levels[i];
140 auto& top_outer = outer_expansions[i];
141 const auto& bottom_level = tree->levels[i + 1];
142 const auto& bottom_outer = outer_expansions[i + 1];
143#ifdef FMM_MPI
144 auto [Begin, End] = LocalPart(0, tree->level_sizes[i]);
145#else
146 size_t Begin = 0, End = tree->level_sizes[i];
147#endif
148 tbb::parallel_for(Begin, End, [&](size_t j)
149 {
150 TreeCell2d& cell = top_level[j];
151 auto& work = local_work.local();
152 const auto& [begin, end] = cell.source_range;
153
154 for (auto k = begin; k < end; ++k)
155 {
156 const auto& children_cell = bottom_level[k];
157 M2M(bottom_outer.data() + k * N, children_cell.center - cell.center, top_outer.data() + j * N, work);
158 }
159 });
160
161#ifdef FMM_MPI
162 {
163 std::vector<std::complex<double>> buf(top_outer.size());
164 for (int j = 0; j < NProc(); ++j)
165 {
166 sizes[j] = N * LocalPart(0, tree->level_sizes[i], j);
167 }
168 for (int j = 1; j < NProc(); ++j)
169 {
170 displs[j] = displs[j - 1] + sizes[j - 1];
171 }
172 MPI_Allgatherv(top_outer.data() + displs[MyID()], sizes[MyID()], MPI_COMPLEX16,
173 buf.data(), sizes.data(), displs.data(), MPI_COMPLEX16, MPI_COMM_WORLD);
174 std::swap(buf, top_outer);
175 }
176#endif
177 }
178
179 //if (IAmRoot()) std::cout << "m2m time: " << omp_get_wtime() - t1 << std::endl;
180}
void M2M(const std::complex< double > *a, const std::complex< double > &z0, std::complex< double > *b, std::vector< std::complex< double > > &work)
Definition multipole.cpp:41
void Multipole(std::complex< double > *a, const std::pair< size_t, size_t > &particle_range, const std::complex< double > &z0)
Definition multipole.cpp:25
Here is the call graph for this function:

Member Data Documentation

◆ forces

std::vector<std::complex<double> > fmm::FastMultipole::forces

Definition at line 17 of file multipole.h.

◆ inner_expansions

std::vector<std::vector<std::complex<double> > > fmm::FastMultipole::inner_expansions
private

Definition at line 34 of file multipole.h.

◆ local_work

tbb::enumerable_thread_specific<std::vector<std::complex<double> > > fmm::FastMultipole::local_work
private

Definition at line 41 of file multipole.h.

◆ N

int fmm::FastMultipole::N
private

Definition at line 37 of file multipole.h.

◆ num_particles

size_t fmm::FastMultipole::num_particles
private

Definition at line 38 of file multipole.h.

◆ outer_expansions

std::vector<std::vector<std::complex<double> > > fmm::FastMultipole::outer_expansions
private

Definition at line 33 of file multipole.h.

◆ potentials

std::vector<double> fmm::FastMultipole::potentials

Definition at line 18 of file multipole.h.

◆ targets_num

size_t fmm::FastMultipole::targets_num
private

Definition at line 39 of file multipole.h.

◆ tree

std::shared_ptr<MortonTree2d> fmm::FastMultipole::tree
private

Definition at line 32 of file multipole.h.

◆ tree_depth

size_t fmm::FastMultipole::tree_depth
private

Definition at line 36 of file multipole.h.


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