34#include "communication.hpp"
41#include "system/System.hpp"
48#ifdef ESPRESSO_CALIPER
49#include <caliper/cali.h>
52#include <boost/mpi/collectives/all_reduce.hpp>
54#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
55#include <Cabana_Core.hpp>
56#include <Cabana_NeighborList.hpp>
57#include <Kokkos_Core.hpp>
74#include <unordered_set>
80#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
83 m_kokkos_handle.reset();
87#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
89 m_local_force.reset();
90#ifdef ESPRESSO_ROTATION
91 m_local_torque.reset();
94 m_local_virial.reset();
96 m_id_to_index.reset();
98 m_verlet_list_cabana.reset();
99 m_rebuild_verlet_list_cabana =
true;
103 m_kokkos_handle = std::move(
handle);
124 (4. / 3.) * std::numbers::pi * Utils::int_pow<3>(
pair_cutoff);
137#ifdef ESPRESSO_CALIPER
148#ifdef ESPRESSO_COLLISION_DETECTION
149 if (
system.has_collision_detection_enabled()) {
156#ifdef ESPRESSO_ROTATION
163 Kokkos::deep_copy(m_aosoa->flags,
uint8_t{0});
168#ifdef ESPRESSO_ROTATION
172 m_id_to_index = std::make_unique<Kokkos::View<int *>>(
173 Kokkos::ViewAllocateWithoutInitializing(
"id_to_index"),
177 m_aosoa = std::make_unique<AoSoA_pack>();
179 Kokkos::deep_copy(m_aosoa->flags,
uint8_t{0});
181 m_verlet_list_cabana =
185 m_local_virial = std::make_unique<VirialType>(
"local_virial",
num_threads);
190#ifdef ESPRESSO_CALIPER
198#ifdef ESPRESSO_ROTATION
208#ifdef ESPRESSO_CALIPER
211 auto &unique_particles = m_unique_particles;
212 unique_particles.clear();
220 unique_particles[index] = &p;
237 unique_particles.emplace_back(&p);
241 m_cached_max_local_particle_id =
max_id;
242 m_num_local_particles_cached = unique_particles.size();
254 auto const id = p.id();
257 throw std::runtime_error(
"Particle id out of bounds.");
261 throw std::runtime_error(
"Invalid local particle index entry.");
271 throw std::runtime_error(
"local_particles part has corrupted id.");
277 throw std::runtime_error(
285 for (
auto const &p : cell->particles()) {
286 if (particle_to_cell(p) != cell) {
287 throw std::runtime_error(
"misplaced particle with id " +
288 std::to_string(p.id()));
296 for (
auto it = bl.begin();
it != bl.end();) {
306 auto &
parts = cell->particles();
308 if (
it->id() == id) {
321 auto const sort_cell = particle_to_cell(p);
323 return std::addressof(
324 append_indexed_particle(
sort_cell->particles(), std::move(p)));
331 auto const sort_cell = particle_to_cell(p);
340 return std::addressof(
341 append_indexed_particle(cell->particles(), std::move(p)));
345 auto it = std::ranges::find_if(std::ranges::views::reverse(m_particle_index),
346 [](
auto const *p) {
return p !=
nullptr; });
348 return (
it != m_particle_index.rend()) ? (*it)->id() : -1;
353 cell->particles().clear();
356 m_particle_index.clear();
362 using namespace Cells;
389#ifdef ESPRESSO_BOND_CONSTRAINT
413 std::vector<ParticleChange>
diff;
417 for (
auto d :
diff) {
418 std::visit(UpdateParticleIndexVisitor{
this}, d);
422 m_rebuild_verlet_list =
true;
423 m_rebuild_verlet_list_cabana =
true;
424 m_le_pos_offset_at_last_resort =
lebc.pos_offset;
426#ifdef ESPRESSO_ADDITIONAL_CHECKS
434 auto &local_geo = *
system.local_geo;
435 auto const &box_geo = *
system.box_geo;
436 set_particle_decomposition(
437 std::make_unique<AtomDecomposition>(
::comm_cart, box_geo));
439 local_geo.set_cell_structure_type(m_type);
440 system.on_cell_structure_change();
444 double range, std::optional<std::pair<int, int>> fully_connected_boundary) {
446 auto &local_geo = *
system.local_geo;
447 auto const &box_geo = *
system.box_geo;
448 set_particle_decomposition(std::make_unique<RegularDecomposition>(
451 local_geo.set_cell_structure_type(m_type);
452 system.on_cell_structure_change();
458 auto &local_geo = *
system.local_geo;
459 auto const &box_geo = *
system.box_geo;
460 set_particle_decomposition(std::make_unique<HybridDecomposition>(
462 [&
system]() {
return system.get_global_ghost_flags(); }, box_geo,
465 local_geo.set_cell_structure_type(m_type);
466 system.on_cell_structure_change();
471 m_verlet_skin = value;
472 m_verlet_skin_set =
true;
473 m_rebuild_verlet_list_cabana =
true;
479 auto const max_cut =
get_system().maximal_cutoff();
481 throw std::runtime_error(
482 "cannot automatically determine skin, please set it manually");
497 ::comm_cart, m_resort_particles, std::bit_or<unsigned>());
523#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
524void CellStructure::parallel_for_each_particle_impl(
526 if (cells.size() > 1) {
527 Kokkos::parallel_for(
528 "for_each_local_particle", cells.size(), [&](
auto cell_idx) {
529 for (auto &p : cells[cell_idx]->particles())
532 }
else if (cells.size() == 1) {
533 auto &
particles = cells.front()->particles();
534 Kokkos::parallel_for(
536 [&](
auto part_idx) { f(*(particles.begin() + part_idx)); });
547 if ((p.pos() - p.pos_at_last_verlet_update()).norm2() >
lim) {
@ 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.
std::function< void(Particle &)> ParticleUnaryOp
Vector implementation and trait types for boost qvm interoperability.
Atom decomposition cell system.
Describes a cell structure / cell system.
ParticleRange ghost_particles() const
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.
std::size_t count_local_particles() 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.
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_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 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.
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,...
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
void resort_particles(bool global_flag)
Resort particles.
void check_particle_index() const
Check that particle index is commensurate with particles.
void set_regular_decomposition(double range, std::optional< std::pair< int, int > > fully_connected_boundary)
Set the particle decomposition to RegularDecomposition.
void set_atom_decomposition()
Set the particle decomposition to AtomDecomposition.
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 reset_local_properties()
virtual std::span< Cell *const > local_cells() const =0
Get pointer to local cells.
base_type::size_type size() const
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.
Ghost particles and particle exchange.
@ GHOSTTRANS_MOMENTUM
transfer ParticleMomentum
@ GHOSTTRANS_RATTLE
transfer ParticleRattle
@ GHOSTTRANS_PARTNUM
resize the receiver particle arrays to the size of the senders
@ GHOSTTRANS_POSITION
transfer ParticlePosition
@ GHOSTTRANS_PROPRTS
transfer ParticleProperties
@ GHOSTTRANS_FORCE
transfer ParticleForce
@ DATA_PART_PROPERTIES
Particle::p.
@ DATA_PART_BONDS
Particle::bonds.
ParticleRange particles(std::span< Cell *const > cells)
std::function< void(ResultType &, ResultType const &)> ReductionOp
Join two partial reduction results.
std::function< void(ResultType &, Particle const &)> AddPartialResultKernel
Kernel that adds the result from a single particle to a reduction.
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
bool contains(Range &&rng, T const &value)
Check whether a range contains a value.
void enumerate_local_particles(CellStructure const &cs, Kernel &&kernel)
Run a kernel on all local particles with enumeration.
ResultType reduce_over_local_particles(CellStructure const &cs, Reduction::AddPartialResultKernel< ResultType > add_partial, Reduction::ReductionOp< ResultType > reduce_op)
performs a reduction over all particles
Struct holding all information for one particle.
Apply a ParticleChange to a particle index.
void operator()(RemovedParticle rp) const
void operator()(ModifiedList mp) const