ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
CellStructure.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2026 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
28
29#include "BoxGeometry.hpp"
30#include "LocalBondState.hpp"
31#include "LocalBox.hpp"
32#include "Particle.hpp"
33#include "aosoa_pack.hpp"
35#include "communication.hpp"
36#include "ghosts.hpp"
38#include "kokkos_helpers.hpp"
42#include "system/System.hpp"
43
44#include <utils/Vector.hpp>
45#include <utils/contains.hpp>
47#include <utils/math/sqr.hpp>
48
49#ifdef ESPRESSO_CALIPER
50#include <caliper/cali.h>
51#endif
52
53#include <boost/mpi/collectives/all_reduce.hpp>
54
55#include <omp.h>
56
57#include <algorithm>
58#include <cassert>
59#include <cmath>
60#include <cstddef>
61#include <cstdint>
62#include <iterator>
63#include <memory>
64#include <numbers>
65#include <optional>
66#include <ranges>
67#include <set>
68#include <stdexcept>
69#include <string>
70#include <unordered_set>
71#include <utility>
72#include <variant>
73#include <vector>
74
77 // Kokkos handle can only be freed after all Cabana containers have been freed
78 m_kokkos_handle.reset();
79}
80
82 m_scatter_force.reset();
83 m_local_force.reset();
84#ifdef ESPRESSO_ROTATION
85 m_scatter_torque.reset();
86 m_local_torque.reset();
87#endif
88#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
89 m_scatter_dip_fld.reset();
90 m_local_dip_fld.reset();
91#endif
92#ifdef ESPRESSO_NPT
93 m_scatter_virial.reset();
94 m_local_virial.reset();
95#endif
96 m_id_to_index.reset();
97 m_aosoa.reset();
98 m_verlet_list_cabana.reset();
99 m_bond_state->clear();
100 m_rebuild_verlet_list_cabana = true;
101}
102void CellStructure::clear_bond_properties() { m_bond_state->reset(); }
103
104void CellStructure::set_kokkos_handle(std::shared_ptr<KokkosHandle> handle) {
105 m_kokkos_handle = std::move(handle);
106 m_bond_state = std::make_unique<LocalBondState>();
107}
108
110 std::size_t number_of_unique_particles,
111 double local_box_volume,
112 std::size_t num_local_particles) {
113 if (std::isinf(pair_cutoff)) {
115 }
116 if (pair_cutoff < 0.) {
117 pair_cutoff = 0.;
118 }
119 // Estimate number of neighbors based on local density and cutoff sphere:
120 // volume n_neighbors = rho * (4/3) * pi * r^3, where rho = n_particles /
121 // volume
122 auto const local_density =
124 ? static_cast<double>(num_local_particles) / local_box_volume
125 : 0.;
126 auto const cutoff_sphere_volume =
127 (4. / 3.) * std::numbers::pi * Utils::int_pow<3>(pair_cutoff);
128 // account for local fluctuations. Empirical.
129 auto const fluctuation_factor = 2.;
130 auto max_counts = static_cast<std::size_t>(
132 std::size_t constexpr threshold_num = 16;
135 }
136 return max_counts;
137}
138
140#ifdef ESPRESSO_CALIPER
142#endif
143 assert(m_kokkos_handle);
144 auto const num_part = get_unique_particles().size();
145 auto const &system = get_system();
146 auto const local_box_volume = system.local_geo->volume();
149#ifdef ESPRESSO_COLLISION_DETECTION
150 if (system.has_collision_detection_enabled()) {
151 // TODO: use other types of Verlet list data structures
152 max_counts = num_part * 2ul;
153 }
154#endif
155 if (m_local_force) { // local properties are reallocated
156 Kokkos::realloc(get_local_force(), num_part);
157 // underlying View extent changed -> scratch buffers must be rebuilt
158 m_scatter_force.emplace(
159 Kokkos::Experimental::create_scatter_view(get_local_force()));
160#ifdef ESPRESSO_ROTATION
161 Kokkos::realloc(get_local_torque(), num_part);
162 // underlying View extent changed -> scratch buffers must be rebuilt
163 m_scatter_torque.emplace(
164 Kokkos::Experimental::create_scatter_view(get_local_torque()));
165#endif
166#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
167 Kokkos::realloc(get_local_dip_fld(), num_part);
168 // underlying View extent changed -> scratch buffers must be rebuilt
169 m_scatter_dip_fld.emplace(
170 Kokkos::Experimental::create_scatter_view(get_local_dip_fld()));
171#endif
172 Kokkos::realloc(get_id_to_index(), get_cached_max_local_particle_id() + 1);
174 // Resize particle views using AoSoA_pack's resize method
175 m_aosoa->resize(num_part);
176 kokkos_deep_copy(execution_space{}, m_aosoa->flags, uint8_t{0});
177 m_verlet_list_cabana->reallocData(num_part, max_counts);
178 } else { // local properties are initialized
179 m_local_force = std::make_unique<ForceType>("local_force", num_part);
180 m_scatter_force.emplace(
181 Kokkos::Experimental::create_scatter_view(*m_local_force));
182#ifdef ESPRESSO_ROTATION
183 m_local_torque = std::make_unique<ForceType>("local_torque", num_part);
184 m_scatter_torque.emplace(
185 Kokkos::Experimental::create_scatter_view(*m_local_torque));
186#endif
187#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
188 m_local_dip_fld = std::make_unique<ForceType>("local_dip_fld", num_part);
189 m_scatter_dip_fld.emplace(
190 Kokkos::Experimental::create_scatter_view(*m_local_dip_fld));
191#endif
192 m_id_to_index = std::make_unique<Kokkos::View<int *, memory_space>>(
193 Kokkos::view_alloc(execution_space{}, Kokkos::WithoutInitializing,
194 "id_to_index"),
197 // Create AoSoA_pack and initialize with resize
198 m_aosoa = std::make_unique<AoSoA_pack>();
199 m_aosoa->resize(num_part);
200 kokkos_deep_copy(execution_space{}, m_aosoa->flags, uint8_t{0});
201
202 m_verlet_list_cabana =
203 std::make_unique<ListType>(0ul, num_part, max_counts);
204 }
205#ifdef ESPRESSO_NPT
206 m_local_virial = std::make_unique<VirialType>("local_virial");
207 m_scatter_virial.emplace(
208 Kokkos::Experimental::create_scatter_view(*m_local_virial));
209#endif
210}
211
213#ifdef ESPRESSO_CALIPER
215#endif
217 m_scatter_force->reset();
218#ifdef ESPRESSO_ROTATION
220 m_scatter_torque->reset();
221#endif
222#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
224 m_scatter_dip_fld->reset();
225#endif
226}
227
230 m_scatter_force->reset();
231#ifdef ESPRESSO_ROTATION
233 m_scatter_torque->reset();
234#endif
235#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
237 m_scatter_dip_fld->reset();
238#endif
239#ifdef ESPRESSO_NPT
241 m_scatter_virial->reset();
242#endif
244}
245
246void CellStructure::update_bond_storage(int &pair_count, int &angle_count,
247 int &dihedral_count,
248 Particle const &p) {
249 auto &pair_list = m_bond_state->pair_list;
250 auto &pair_ids = m_bond_state->pair_ids;
251 auto &angle_list = m_bond_state->angle_list;
252 auto &angle_ids = m_bond_state->angle_ids;
253 auto &dihedral_list = m_bond_state->dihedral_list;
254 auto &dihedral_ids = m_bond_state->dihedral_ids;
255 for (auto const bond : p.bonds()) {
256 auto const partner_ids = bond.partner_ids();
257 try {
258 auto const partners = resolve_bond_partners(partner_ids);
259 if (partners.size() == 1u) { // pair bonds
260 auto p_index = Kokkos::atomic_fetch_add(&pair_count, 1);
261 pair_list(p_index, 0) = p.id();
262 pair_list(p_index, 1) = partners[0]->id();
263 pair_ids(p_index) = bond.bond_id();
264 } else if (partners.size() == 2u) { // angle bond
265 auto a_index = Kokkos::atomic_fetch_add(&angle_count, 1);
266 angle_list(a_index, 0) = p.id();
267 angle_list(a_index, 1) = partners[0]->id();
268 angle_list(a_index, 2) = partners[1]->id();
269 angle_ids(a_index) = bond.bond_id();
270 } else if (partners.size() == 3u) { // dihedral bond
271 auto d_index = Kokkos::atomic_fetch_add(&dihedral_count, 1);
272 dihedral_list(d_index, 0) = p.id();
273 dihedral_list(d_index, 1) = partners[0]->id();
274 dihedral_list(d_index, 2) = partners[1]->id();
275 dihedral_list(d_index, 3) = partners[2]->id();
276 dihedral_ids(d_index) = bond.bond_id();
277 }
278 } catch (BondResolutionError const &) {
279 bond_resolution_error(partner_ids);
280 }
281 }
282}
283
285#ifdef ESPRESSO_CALIPER
287#endif
288 auto &unique_particles = m_unique_particles;
289 unique_particles.clear();
290 unique_particles.resize(count_local_particles());
291 std::unordered_set<int> registered_index{};
292 using execution_space = Kokkos::DefaultHostExecutionSpace;
293 int n_threads = execution_space().concurrency();
294 std::vector<int> max_ids(n_threads);
295
296 m_bond_state->reset_counts();
297 std::vector<int> pair_counts(n_threads, 0);
298 std::vector<int> angle_counts(n_threads, 0);
299 std::vector<int> dihedral_counts(n_threads, 0);
300
302 *this, [&unique_particles, &max_ids, &pair_counts, &angle_counts,
303 &dihedral_counts](std::size_t index, Particle &p) {
304 unique_particles[index] = &p;
305 auto const thread_num = omp_get_thread_num();
306 max_ids[thread_num] = std::max(p.id(), max_ids[thread_num]);
307 for (auto const bond : p.bonds()) {
308 if (not bond.partner_ids().empty()) {
309 auto const partner_ids = bond.partner_ids();
310 if (partner_ids.size() == 1u) {
312 } else if (partner_ids.size() == 2u) {
314 } else if (partner_ids.size() == 3u) {
316 }
317 }
318 }
319 });
320 Kokkos::fence();
321 int pair_count = std::reduce(std::begin(pair_counts), std::end(pair_counts));
322 int angle_count =
323 std::reduce(std::begin(angle_counts), std::end(angle_counts));
324 int dihedral_count =
325 std::reduce(std::begin(dihedral_counts), std::end(dihedral_counts));
326 set_local_bond_numbers(pair_count, angle_count, dihedral_count);
327 m_bond_state->allocate();
328
329 int max_id = *(std::max_element(max_ids.begin(), max_ids.end()));
330 for (auto &p : ghost_particles()) {
331 auto const *local_particle = get_local_particle(p.id());
332 if (not local_particle) {
333 continue;
334 }
335 if (not local_particle->is_ghost()) {
336 continue;
337 }
338 if (registered_index.contains(p.id())) {
339 continue;
340 }
341 registered_index.insert(p.id());
342 unique_particles.emplace_back(&p);
343 max_id = std::max(p.id(), max_id);
344 }
345 registered_index.clear();
346 m_cached_max_local_particle_id = max_id;
347 m_num_local_particles_cached = unique_particles.size();
348}
349
351 : m_decomposition{std::make_unique<AtomDecomposition>(box)} {}
352
354 auto const max_id = get_max_local_particle_id();
355
356 for (auto const &p : local_particles()) {
357 auto const id = p.id();
358
360 throw std::runtime_error("Particle id out of bounds.");
361 }
362
363 if (get_local_particle(id) != &p) {
364 throw std::runtime_error("Invalid local particle index entry.");
365 }
366 }
367
368 /* checks: local particle id */
369 std::size_t local_part_cnt = 0u;
370 for (int n = 0; n < get_max_local_particle_id() + 1; n++) {
371 if (get_local_particle(n) != nullptr) {
373 if (get_local_particle(n)->id() != n) {
374 throw std::runtime_error("local_particles part has corrupted id.");
375 }
376 }
377 }
378
379 if (local_part_cnt != local_particles().size()) {
380 throw std::runtime_error(
381 std::to_string(local_particles().size()) + " parts in cells but " +
382 std::to_string(local_part_cnt) + " parts in local_particles");
383 }
384}
385
387 for (auto cell : decomposition().local_cells()) {
388 for (auto const &p : cell->particles()) {
389 if (particle_to_cell(p) != cell) {
390 throw std::runtime_error("misplaced particle with id " +
391 std::to_string(p.id()));
392 }
393 }
394 }
395}
396
398 auto remove_all_bonds_to = [id](BondList &bl) {
399 for (auto it = bl.begin(); it != bl.end();) {
400 if (Utils::contains(it->partner_ids(), id)) {
401 it = bl.erase(it);
402 } else {
403 std::advance(it, 1);
404 }
405 }
406 };
407
408 for (auto cell : decomposition().local_cells()) {
409 auto &parts = cell->particles();
410 for (auto it = parts.begin(); it != parts.end();) {
411 if (it->id() == id) {
412 it = parts.erase(it);
413 update_particle_index(id, nullptr);
415 } else {
416 remove_all_bonds_to(it->bonds());
417 it++;
418 }
419 }
420 }
421}
422
424 auto const sort_cell = particle_to_cell(p);
425 if (sort_cell) {
426 return std::addressof(
427 append_indexed_particle(sort_cell->particles(), std::move(p)));
428 }
429
430 return {};
431}
432
434 auto const sort_cell = particle_to_cell(p);
435 /* There is always at least one cell, so if the particle
436 * does not belong to a cell on this node we can put it there. */
437 auto cell = sort_cell ? sort_cell : decomposition().local_cells()[0];
438
439 /* If the particle isn't local a global resort may be
440 * needed, otherwise a local resort if sufficient. */
442
443 return std::addressof(
444 append_indexed_particle(cell->particles(), std::move(p)));
445}
446
448 auto it = std::ranges::find_if(std::ranges::views::reverse(m_particle_index),
449 [](auto const *p) { return p != nullptr; });
450
451 return (it != m_particle_index.rend()) ? (*it)->id() : -1;
452}
453
455 return m_bond_state->pair_count;
456}
458 return m_bond_state->angle_count;
459}
461 return m_bond_state->dihedral_count;
462}
467#ifdef ESPRESSO_COLLISION_DETECTION
468void CellStructure::clear_new_bonds() { m_bond_state->clear_new_bonds(); }
470 std::vector<int> const &particle_ids) {
471 m_bond_state->add_new_bond(bond_id, particle_ids, get_id_to_index());
472}
473void CellStructure::rebuild_bond_list() { m_bond_state->rebuild(); }
474#endif // ESPRESSO_COLLISION_DETECTION
475
477 for (auto cell : decomposition().local_cells()) {
478 cell->particles().clear();
479 }
480
481 m_particle_index.clear();
483}
484
485/* Map the data parts flags from cells to those used internally
486 * by the ghost communication */
487unsigned map_data_parts(unsigned data_parts) {
488 using namespace Cells;
489
490 /* clang-format off */
491 return GHOSTTRANS_NONE
492 | ((data_parts & DATA_PART_PROPERTIES) ? GHOSTTRANS_PROPRTS : 0u)
493 | ((data_parts & DATA_PART_POSITION) ? GHOSTTRANS_POSITION : 0u)
494 | ((data_parts & DATA_PART_MOMENTUM) ? GHOSTTRANS_MOMENTUM : 0u)
495 | ((data_parts & DATA_PART_FORCE) ? GHOSTTRANS_FORCE : 0u)
497 | ((data_parts & DATA_PART_RATTLE) ? GHOSTTRANS_RATTLE : 0u)
498#endif
500 | ((data_parts & DATA_PART_DIPFLD) ? GHOSTTRANS_DIPFLD : 0u)
501#endif
502 | ((data_parts & DATA_PART_BONDS) ? GHOSTTRANS_BONDS : 0u);
503 /* clang-format on */
504}
505
507 ghost_communicator(decomposition().exchange_ghosts_comm(),
508 *get_system().box_geo, GHOSTTRANS_PARTNUM);
509}
511 ghost_communicator(decomposition().exchange_ghosts_comm(),
513}
515 ghost_communicator(decomposition().collect_ghost_force_comm(),
516 *get_system().box_geo, GHOSTTRANS_FORCE);
517}
518#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
520 ghost_communicator(decomposition().collect_ghost_force_comm(),
521 *get_system().box_geo, GHOSTTRANS_DIPFLD);
522}
523#endif
524#ifdef ESPRESSO_BOND_CONSTRAINT
529#endif
530
531namespace {
532/**
533 * @brief Apply a @ref ParticleChange to a particle index.
534 */
543} // namespace
544
546 invalidate_ghosts();
547
548 std::vector<ParticleChange> diff;
549
550 m_decomposition->resort(global_flag, diff);
551
552 for (auto d : diff) {
553 std::visit(UpdateParticleIndexVisitor{this}, d);
554 }
555
556 auto const &lebc = get_system().box_geo->lees_edwards_bc();
557 m_rebuild_verlet_list = true;
558 m_rebuild_verlet_list_cabana = true;
559 m_le_pos_offset_at_last_resort = lebc.pos_offset;
560
561#ifdef ESPRESSO_ADDITIONAL_CHECKS
564#endif
565}
566
568 auto &system = get_system();
569 auto &local_geo = *system.local_geo;
570 auto const &box_geo = *system.box_geo;
571 set_particle_decomposition(
572 std::make_unique<AtomDecomposition>(::comm_cart, box_geo));
574 local_geo.set_cell_structure_type(m_type);
575 system.on_cell_structure_change();
576}
577
579 double range, std::optional<std::pair<int, int>> fully_connected_boundary) {
580 auto &system = get_system();
581 auto &local_geo = *system.local_geo;
582 auto const &box_geo = *system.box_geo;
583 set_particle_decomposition(std::make_unique<RegularDecomposition>(
584 ::comm_cart, range, box_geo, local_geo, fully_connected_boundary));
586 local_geo.set_cell_structure_type(m_type);
587 system.on_cell_structure_change();
588}
589
591 std::set<int> n_square_types) {
592 auto &system = get_system();
593 auto &local_geo = *system.local_geo;
594 auto const &box_geo = *system.box_geo;
595 set_particle_decomposition(std::make_unique<HybridDecomposition>(
596 ::comm_cart, cutoff_regular, m_verlet_skin,
597 [&system]() { return system.get_global_ghost_flags(); }, box_geo,
598 local_geo, n_square_types));
600 local_geo.set_cell_structure_type(m_type);
601 system.on_cell_structure_change();
602}
603
605 assert(value >= 0.);
606 m_verlet_skin = value;
607 m_verlet_skin_set = true;
608 m_rebuild_verlet_list_cabana = true;
609 get_system().on_verlet_skin_change();
610}
611
614 auto const max_cut = get_system().maximal_cutoff();
615 if (max_cut <= 0.) {
616 throw std::runtime_error(
617 "cannot automatically determine skin, please set it manually");
618 }
619 /* maximal skin that can be used without resorting is the maximal
620 * range of the cell system minus what is needed for interactions. */
621 auto const max_range = std::ranges::min(max_cutoff());
622 auto const new_skin = std::min(0.4 * max_cut, max_range - max_cut);
624}
625
627 /* data parts that are only updated on resort */
628 auto constexpr resort_only_parts =
630
631 auto const global_resort = boost::mpi::all_reduce(
632 ::comm_cart, m_resort_particles, std::bit_or<unsigned>());
633
636
637 /* Resort cell system */
639 ghosts_count();
641
642 /* Add the ghost particles to the index if we don't already
643 * have them. */
644 for (auto &p : ghost_particles()) {
645 if (get_local_particle(p.id()) == nullptr) {
646 update_particle_index(p.id(), &p);
647 }
648 }
649
650 /* Particles are now sorted */
652 } else {
653 /* Communication step: ghost information */
655 }
656}
657
659 Utils::Vector3d const &additional_offset) const {
660 auto const lim = Utils::sqr(m_verlet_skin / 2.) - additional_offset.norm2();
661
662 auto add_partial = [lim](bool &result, Particle const &p) {
663 if ((p.pos() - p.pos_at_last_verlet_update()).norm2() > lim) {
664 result = true;
665 }
666 };
667
668 auto reduce_op = [](bool &acc, bool const &val) { acc |= val; };
669
671}
@ NSQUARE
Atom decomposition (N-square).
@ HYBRID
Hybrid decomposition.
@ REGULAR
Regular decomposition.
unsigned map_data_parts(unsigned data_parts)
Map the data parts flags from cells to those used internally by the ghost communication.
static auto estimate_max_counts(double pair_cutoff, std::size_t number_of_unique_particles, double local_box_volume, std::size_t num_local_particles)
unsigned map_data_parts(unsigned data_parts)
Map the data parts flags from cells to those used internally by the ghost communication.
Vector implementation and trait types for boost qvm interoperability.
void bond_resolution_error(std::span< const int > partner_ids)
Atom decomposition cell system.
Bond storage.
Definition BondList.hpp:84
Describes a cell structure / cell system.
ParticleRange ghost_particles() const
auto & get_local_force()
Particle * get_local_particle(int id)
Get a local particle by id.
void set_kokkos_handle(std::shared_ptr< KokkosHandle > handle)
void check_particle_sorting() const
Check that particles are in the correct cell.
auto & get_id_to_index()
std::size_t count_local_particles() const
virtual ~CellStructure()
int get_local_angle_bond_numbers() const
void clear_resort_particles()
Set the resort level to sorted.
auto is_verlet_skin_set() const
Whether the Verlet skin is set.
void clear_local_properties()
ParticleDecomposition const & decomposition() const
Get the underlying particle decomposition.
int get_local_pair_bond_numbers() const
void update_ghosts_and_resort_particle(unsigned data_parts)
Update ghost particles, with particle resort if needed.
Particle * add_local_particle(Particle &&p)
Add a particle.
void set_verlet_skin_heuristic()
Set the Verlet skin using a heuristic.
void set_verlet_skin(double value)
Set the Verlet skin.
void ghosts_update(unsigned data_parts)
Update ghost particles.
int get_local_dihedral_bond_numbers() const
int get_cached_max_local_particle_id() const
CellStructure(BoxGeometry const &box)
auto & get_local_torque()
auto & get_local_virial()
void update_particle_index(int id, Particle *p)
Update local particle index.
void set_local_bond_numbers(int p, int a, int d)
void ghosts_reduce_forces()
Add forces and torques from ghost particles to real particles.
auto const & get_unique_particles() const
void rebuild_local_properties(double pair_cutoff)
Utils::Vector3d max_range() const
Maximal pair range supported by current cell system.
void add_new_bond(int bond_id, std::vector< int > const &particle_ids)
bool check_resort_required(Utils::Vector3d const &additional_offset={}) const
Check whether a particle has moved further than half the skin since the last Verlet list update,...
auto resolve_bond_partners(std::span< const int > partner_ids)
Resolve ids to particles.
void ghosts_count()
Synchronize number of ghosts.
void set_resort_particles(Cells::Resort level)
Increase the local resort level at least to level.
void remove_particle(int id)
Remove a particle.
Particle * add_particle(Particle &&p)
Add a particle.
std::size_t get_num_local_particles_cached() const
Kokkos::DefaultHostExecutionSpace execution_space
void resort_particles(bool global_flag)
Resort particles.
void check_particle_index() const
Check that particle index is commensurate with particles.
void ghosts_reduce_dipole_field()
Add dipole fields from ghost particles to real particles.
void set_regular_decomposition(double range, std::optional< std::pair< int, int > > fully_connected_boundary)
Set the particle decomposition to RegularDecomposition.
void reset_local_force_and_torque()
void set_atom_decomposition()
Set the particle decomposition to AtomDecomposition.
auto & get_local_dip_fld()
void remove_all_particles()
Remove all particles from the cell system.
ParticleRange local_particles() const
void ghosts_reduce_rattle_correction()
Add rattle corrections from ghost particles to real particles.
void set_hybrid_decomposition(double cutoff_regular, std::set< int > n_square_types)
Set the particle decomposition to HybridDecomposition.
int get_max_local_particle_id() const
Get the maximal particle id on this node.
Utils::Vector3d max_cutoff() const
Maximal cutoff supported by current cell system.
void update_bond_storage(int &pair_count, int &angle_count, int &dihedral_count, Particle const &p)
Update bond storage(m_*_bond_list_kokkos and m_*_bond_id_kokkos).
void clear_bond_properties()
void reset_local_properties()
virtual std::span< Cell *const > local_cells() const =0
Get pointer to local cells.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
boost::mpi::communicator comm_cart
The communicator.
void ghost_communicator(GhostCommunicator const &gcr, BoxGeometry const &box_geo, unsigned int data_parts)
Do a ghost communication with the specified data parts.
Definition ghosts.cpp:469
Ghost particles and particle exchange.
@ GHOSTTRANS_MOMENTUM
transfer ParticleMomentum
Definition ghosts.hpp:132
@ GHOSTTRANS_RATTLE
transfer ParticleRattle
Definition ghosts.hpp:137
@ GHOSTTRANS_DIPFLD
transfer dipole field tracking data
Definition ghosts.hpp:145
@ GHOSTTRANS_PARTNUM
resize the receiver particle arrays to the size of the senders
Definition ghosts.hpp:140
@ GHOSTTRANS_POSITION
transfer ParticlePosition
Definition ghosts.hpp:130
@ GHOSTTRANS_PROPRTS
transfer ParticleProperties
Definition ghosts.hpp:128
@ GHOSTTRANS_FORCE
transfer ParticleForce
Definition ghosts.hpp:134
@ GHOSTTRANS_NONE
Definition ghosts.hpp:126
@ GHOSTTRANS_BONDS
transfer bonds data
Definition ghosts.hpp:142
ESPRESSO_ATTR_ALWAYS_INLINE void kokkos_deep_copy(auto const &exec_space, auto const &view, auto const &value)
Wrapper for Kokkos::deep_copy that skips fork/join when the number of threads is 1.
@ DATA_PART_PROPERTIES
Particle::p.
@ DATA_PART_BONDS
Particle::bonds.
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
bool contains(Range &&rng, T const &value)
Check whether a range contains a value.
Definition contains.hpp:36
STL namespace.
void enumerate_local_particles(CellStructure const &cs, Kernel &&kernel)
Run a kernel on all local particles with enumeration.
Exception indicating that a particle id could not be resolved.
Struct holding all information for one particle.
Definition Particle.hpp:436
constexpr auto const & bonds() const
Definition Particle.hpp:473
constexpr auto const & id() const
Definition Particle.hpp:455