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();
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)
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 {
292
293 for (auto k = j + 1; k < p1_end; ++k)
294 {
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)
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
void Potential2dMutual(const particle2d &p1, const particle2d &p2, double &potential1, double &potential2)