71 std::vector<Particle *> local_particles;
72 std::vector<PosMom> local_posmom;
73 std::vector<PosMom> all_posmom;
74 std::vector<boost::mpi::request> reqs;
76 local_particles.reserve(particles.
size());
77 local_posmom.reserve(particles.
size());
79 for (
auto &p : particles) {
80 if (p.dipm() != 0.0) {
81 local_particles.emplace_back(&p);
82 local_posmom.emplace_back(
87 auto const local_size =
static_cast<int>(local_posmom.size());
88 std::vector<int> all_sizes;
89 boost::mpi::all_gather(comm, local_size, all_sizes);
92 std::accumulate(all_sizes.begin(), all_sizes.begin() + comm.rank(), 0);
93 auto const total_size =
94 std::accumulate(all_sizes.begin() + comm.rank(), all_sizes.end(), offset);
96 if (comm.size() > 1) {
97 all_posmom.resize(total_size);
99 all_posmom.data(), all_sizes.data());
101 std::swap(all_posmom, local_posmom);
104 return std::make_tuple(std::move(local_particles), std::move(all_posmom),
105 std::move(reqs), offset);
159 auto const &box_geo = *system.box_geo;
160 auto const &box_l = box_geo.length();
161 auto const particles = system.cell_structure->local_particles();
162 auto [local_particles, all_posmom, reqs, offset_signed] =
167 auto const with_replicas = (ncut.norm2() > 0);
170 auto const offset =
static_cast<std::size_t
>(offset_signed);
171 auto const n_local = local_particles.size();
172 auto const n_total = all_posmom.size();
179 auto const *pm = all_posmom.data();
181 using memory_space = Kokkos::HostSpace;
182 using execution_space = Kokkos::DefaultHostExecutionSpace;
184 Kokkos::View<double *[3], Kokkos::LayoutRight, Kokkos::HostSpace>;
186 Kokkos::Experimental::ScatterView<
double *[3], Kokkos::LayoutRight,
188 ForceView local_force(
"dds_force", n_local);
189 ForceView local_torque(
"dds_torque", n_local);
190 ScatterForce scatter_force(local_force);
191 ScatterForce scatter_torque(local_torque);
194 auto *local_particles_ptr = local_particles.data();
195 auto const *shifts_ptr = shifts.data();
196 auto const n_shifts = shifts.size();
202 Kokkos::RangePolicy<execution_space, Kokkos::Schedule<Kokkos::Dynamic>>
203 policy_local(std::size_t{0}, n_local);
204 policy_local.set_chunk_size(64);
205 Kokkos::parallel_for(
206 "dds_local_pairs", policy_local, [=](std::size_t
const i) {
207 auto const gi = offset + i;
208 auto const &pos_i = pm[gi].pos;
209 auto const &m_i = pm[gi].m;
213 for (std::size_t s = 1; s < n_shifts; ++s)
216 auto force_access = scatter_force.access();
217 auto torque_access = scatter_torque.access();
220 for (
auto j = gi + 1; j < offset + n_local; ++j) {
221 auto const &pos_j = pm[j].pos;
222 auto const &m_j = pm[j].m;
223 auto const d0 = with_replicas ? (pos_i - pos_j)
224 : box_geo.get_mi_vector(pos_i, pos_j);
225 auto const jl = j - offset;
226 for (std::size_t s = 0; s < n_shifts; ++s) {
227 auto const rn = d0 + shifts_ptr[s];
230 fi.torque += pf.torque;
234 for (
int c = 0; c < 3; ++c) {
235 force_access(jl, c) -= pf.f[c];
236 torque_access(jl, c) += torque_j[c];
241 local_particles_ptr[i]->force() += prefactor_local * fi.f;
242 local_particles_ptr[i]->torque() += prefactor_local * fi.torque;
247 boost::mpi::wait_all(reqs.begin(), reqs.end());
251 Kokkos::RangePolicy<execution_space> policy_remote(std::size_t{0}, n_local);
252 Kokkos::parallel_for(
253 "dds_remote_pairs", policy_remote, [=](std::size_t
const i) {
254 auto const gi = offset + i;
255 auto const &pos_i = pm[gi].pos;
256 auto const &m_i = pm[gi].m;
262 std::size_t
const ranges[2][2] = {{std::size_t{0}, offset},
263 {offset + n_local, n_total}};
264 for (
auto const &range : ranges) {
265 auto const range_begin = range[0];
266 auto const range_end = range[1];
267 for (
auto j = range_begin; j < range_end; ++j) {
268 auto const &pos_j = pm[j].pos;
269 auto const &m_j = pm[j].m;
270 auto const d0 = with_replicas ? (pos_i - pos_j)
271 : box_geo.get_mi_vector(pos_i, pos_j);
272 for (std::size_t s = 0; s < n_shifts; ++s) {
273 auto const rn = d0 + shifts_ptr[s];
276 fi.torque += pf.torque;
280 local_particles_ptr[i]->force() += prefactor_local * fi.f;
281 local_particles_ptr[i]->torque() += prefactor_local * fi.torque;
286 Kokkos::Experimental::contribute(local_force, scatter_force);
287 Kokkos::Experimental::contribute(local_torque, scatter_torque);
288 Kokkos::RangePolicy<execution_space> policy_reduce(std::size_t{0}, n_local);
289 Kokkos::parallel_for(
290 "dds_reduction", policy_reduce, [=](std::size_t
const i) {
291 local_particles_ptr[i]->force() +=
295 local_particles_ptr[i]->torque() +=
306 if (system.has_npt_enabled()) {
312#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
327 auto const &box_geo = *system.box_geo;
328 auto const &box_l = box_geo.length();
329 auto const particles = system.cell_structure->local_particles();
330 auto [local_particles, all_posmom, reqs, offset_signed] =
335 auto const with_replicas = (ncut.norm2() > 0);
338 auto const offset =
static_cast<std::size_t
>(offset_signed);
339 auto const n_local = local_particles.size();
340 auto const n_total = all_posmom.size();
345 auto const *pm = all_posmom.data();
347 using execution_space = Kokkos::DefaultHostExecutionSpace;
350 auto const *shifts_ptr = shifts.data();
351 auto const n_shifts = shifts.size();
358 Kokkos::RangePolicy<execution_space, Kokkos::Schedule<Kokkos::Dynamic>>
359 policy_local(std::size_t{0}, n_local);
360 policy_local.set_chunk_size(64);
361 Kokkos::parallel_reduce(
362 "dds_energy_local", policy_local,
363 [=](std::size_t
const i,
double &u_local) {
364 auto const gi = offset + i;
365 auto const &pos_i = pm[gi].pos;
366 auto const &m_i = pm[gi].m;
369 for (std::size_t s = 1; s < n_shifts; ++s)
373 for (
auto j = gi + 1; j < offset + n_local; ++j) {
374 auto const &pos_j = pm[j].pos;
375 auto const &m_j = pm[j].m;
376 auto const d0 = with_replicas ? (pos_i - pos_j)
377 : box_geo.get_mi_vector(pos_i, pos_j);
378 for (std::size_t s = 0; s < n_shifts; ++s)
387 boost::mpi::wait_all(reqs.begin(), reqs.end());
392 Kokkos::RangePolicy<execution_space> policy_remote(std::size_t{0}, n_local);
393 Kokkos::parallel_reduce(
394 "dds_energy_remote", policy_remote,
395 [=](std::size_t
const i,
double &u_local) {
396 auto const gi = offset + i;
397 auto const &pos_i = pm[gi].pos;
398 auto const &m_i = pm[gi].m;
400 for (
auto j = offset + n_local; j < n_total; ++j) {
401 auto const &pos_j = pm[j].pos;
402 auto const &m_j = pm[j].m;
403 auto const d0 = with_replicas ? (pos_i - pos_j)
404 : box_geo.get_mi_vector(pos_i, pos_j);
405 for (std::size_t s = 0; s < n_shifts; ++s)
425 "DipolarDirectSum on GPU.";
430 auto const &box_geo = *system.box_geo;
431 auto const &box_l = box_geo.length();
432 auto const particles = system.cell_structure->local_particles();
433 auto [local_particles, all_posmom, reqs, offset_signed] =
438 auto const with_replicas = (ncut.norm2() > 0);
441 auto const offset =
static_cast<std::size_t
>(offset_signed);
442 auto const n_local = local_particles.size();
443 auto const n_total = all_posmom.size();
448 auto const *pm = all_posmom.data();
450 using execution_space = Kokkos::DefaultHostExecutionSpace;
453 auto const *shifts_ptr = shifts.data();
454 auto const n_shifts = shifts.size();
464 Kokkos::RangePolicy<execution_space, Kokkos::Schedule<Kokkos::Dynamic>>
465 policy_local(std::size_t{0}, n_local);
466 policy_local.set_chunk_size(64);
470 auto reducerA = Reduction::make_kokkos_reducer<Utils::Vector9d>(
473 auto const gi = offset + i;
474 auto const &pos_i = pm[gi].pos;
475 auto const &m_i = pm[gi].m;
478 for (std::size_t s = 1; s < n_shifts; ++s) {
479 auto const rn = shifts_ptr[s];
485 for (
auto j = gi + 1; j < offset + n_local; ++j) {
486 auto const &pos_j = pm[j].pos;
487 auto const &m_j = pm[j].m;
488 auto const d0 = with_replicas ? (pos_i - pos_j)
489 : box_geo.get_mi_vector(pos_i, pos_j);
490 for (std::size_t s = 0; s < n_shifts; ++s) {
491 auto const rn = d0 + shifts_ptr[s];
498 Kokkos::parallel_reduce(
"dds_pressure_local", policy_local, reducerA, pA);
503 boost::mpi::wait_all(reqs.begin(), reqs.end());
508 Kokkos::RangePolicy<execution_space> policy_remote(std::size_t{0}, n_local);
509 auto reducerB = Reduction::make_kokkos_reducer<Utils::Vector9d>(
512 auto const gi = offset + i;
513 auto const &pos_i = pm[gi].pos;
514 auto const &m_i = pm[gi].m;
515 for (
auto j = offset + n_local; j < n_total; ++j) {
516 auto const &pos_j = pm[j].pos;
517 auto const &m_j = pm[j].m;
518 auto const d0 = with_replicas ? (pos_i - pos_j)
519 : box_geo.get_mi_vector(pos_i, pos_j);
520 for (std::size_t s = 0; s < n_shifts; ++s) {
521 auto const rn = d0 + shifts_ptr[s];
528 Kokkos::parallel_reduce(
"dds_pressure_remote", policy_local, reducerB, pB);
546 auto const &box_geo = *system.box_geo;
547 auto const &box_l = box_geo.length();
548 auto const particles = system.cell_structure->local_particles();
550 auto [local_particles, all_posmom, reqs, offset_signed] =
554 auto const with_replicas = (ncut.norm2() > 0);
557 auto const offset =
static_cast<std::size_t
>(offset_signed);
558 auto const n_local = local_particles.size();
559 auto const n_total = all_posmom.size();
566 boost::mpi::wait_all(reqs.begin(), reqs.end());
570 auto const *pm = all_posmom.data();
572 using execution_space = Kokkos::DefaultHostExecutionSpace;
575 auto *local_particles_ptr = local_particles.data();
576 auto const *shifts_ptr = shifts.data();
577 auto const n_shifts = shifts.size();
579 Kokkos::RangePolicy<execution_space> policy(std::size_t{0}, n_local);
580 Kokkos::parallel_for(
"dds_dipole_field", policy, [=](std::size_t
const i) {
581 auto const gi = offset + i;
582 auto const &pos_i = pm[gi].pos;
583 auto const &m_i = pm[gi].m;
587 for (std::size_t s = 1; s < n_shifts; ++s)
592 std::size_t
const ranges[2][2] = {{std::size_t{0}, gi}, {gi + 1, n_total}};
593 for (
auto const &range : ranges) {
594 auto const range_begin = range[0];
595 auto const range_end = range[1];
596 for (
auto j = range_begin; j < range_end; ++j) {
597 auto const &pos_j = pm[j].pos;
598 auto const &m_j = pm[j].m;
599 auto const d0 = with_replicas ? (pos_i - pos_j)
600 : box_geo.get_mi_vector(pos_i, pos_j);
601 for (std::size_t s = 0; s < n_shifts; ++s)
605 local_particles_ptr[i]->dip_fld() = prefactor_local * u;
base_type::size_type size() const