30#include "system/System.hpp"
38#include <boost/mpi/collectives/all_gather.hpp>
39#include <boost/mpi/collectives/all_reduce.hpp>
40#include <boost/mpi/collectives/gather.hpp>
41#include <boost/mpi/collectives/reduce.hpp>
42#include <boost/mpi/collectives/scatter.hpp>
43#include <boost/optional.hpp>
44#include <boost/range/algorithm/sort.hpp>
45#include <boost/range/numeric.hpp>
53#include <unordered_map>
54#include <unordered_set>
84 boost::mpi::broadcast(
::comm_cart, is_rebuild_needed, 0);
85 return is_rebuild_needed;
94 throw std::runtime_error(
"Types may not be negative");
98 nonbonded_ias.make_particle_type_exist(type);
100 std::vector<int> local_pids;
102 if (p.type() == type) {
103 local_pids.emplace_back(p.id());
107 std::vector<std::vector<int>> global_pids;
108 boost::mpi::all_gather(
::comm_cart, local_pids, global_pids);
110 for (
auto const &vec : global_pids) {
111 for (
auto const &p_id : vec) {
120 it->second.erase(p_id);
126 it->second.insert(p_id);
133 auto it = kv.second.find(p_id);
134 if (it != kv.second.end()) {
138 assert(p->type() == kv.first);
145 if (old_type != new_type) {
164 auto const found = p and not p->is_ghost();
165 assert(1 == boost::mpi::all_reduce(
::comm_cart,
static_cast<int>(found),
167 "Particle not found");
180 assert(p !=
nullptr);
194 ::comm_cart.recv(boost::mpi::any_source, boost::mpi::any_tag, result);
199 std::vector<int> ids;
202 std::vector<Particle> parts(ids.size());
203 std::transform(ids.begin(), ids.end(), parts.begin(), [](
int p_id) {
204 auto const p = get_cell_structure().get_local_particle(p_id);
205 assert(p != nullptr);
227 std::vector<Particle> parts(ids.size());
230 static std::vector<std::vector<int>> node_ids(
comm_cart.size());
231 for (
auto &per_node : node_ids) {
235 for (
auto const &p_id : ids) {
239 node_ids[p_node].push_back(p_id);
244 static std::vector<int> ignore;
245 boost::mpi::scatter(
comm_cart, node_ids, ignore, 0);
250 parts.begin(), [](
int p_id) {
251 auto const p = get_cell_structure().get_local_particle(p_id);
252 assert(p != nullptr);
256 static std::vector<int> node_sizes(
comm_cart.size());
258 node_ids.cbegin(), node_ids.cend(), node_sizes.begin(),
259 [](std::vector<int>
const &ids) { return static_cast<int>(ids.size()); });
262 parts.data(), node_sizes.data(), 0);
273 static std::vector<int> ids;
275 auto out_ids = std::back_inserter(ids);
277 std::copy_if(in_ids.
begin(), in_ids.
end(), out_ids, [](
int id) {
278 return (get_particle_node(id) != this_node) && particle_fetch_cache.has(id);
293 static std::vector<int> sendbuf;
296 auto const n_part =
static_cast<int>(local_particles.size());
297 boost::mpi::gather(
comm_cart, n_part, 0);
304 sendbuf.resize(n_part);
306 std::transform(local_particles.begin(), local_particles.end(),
307 sendbuf.begin(), [](
Particle const &p) { return p.id(); });
318 static std::vector<int> n_parts;
319 boost::mpi::gather(
comm_cart,
static_cast<int>(local_particles.size()),
322 static std::vector<int> pdata;
327 for (
int pnode = 0; pnode < n_nodes; pnode++) {
329 for (
auto const &p : local_particles) {
333 }
else if (n_parts[pnode] > 0) {
334 pdata.resize(n_parts[pnode]);
336 for (
int i = 0; i < n_parts[pnode]; i++) {
366 throw std::domain_error(
"Invalid particle id: " + std::to_string(p_id));
376 throw std::runtime_error(
"Particle node for id " + std::to_string(p_id) +
379 return needle->second;
384 throw std::domain_error(
"Invalid particle id: " + std::to_string(p_id));
399 throw std::runtime_error(
"Particle node for id " + std::to_string(p_id) +
402 return needle->second;
426 [](
int max,
const std::pair<int, int> &kv) {
427 return std::max(max, kv.first);
439 auto folded_pos =
pos;
441 box_geo.fold_position(folded_pos, image_box);
444 new_part.id() = p_id;
445 new_part.pos() = folded_pos;
446 new_part.image_box() = image_box;
460 auto const &box_geo = *system.box_geo;
461 auto p = system.cell_structure->get_local_particle(p_id);
465 auto folded_pos =
pos;
467 box_geo.fold_position(folded_pos, image_box);
468 p->pos() = folded_pos;
469 p->image_box() = image_box;
484 if (p !=
nullptr and not p->is_ghost()) {
491 ::comm_cart.recv(boost::mpi::any_source, 42, p_type);
527 auto const node_local = (has_created) ?
::comm_cart.rank() : 0;
528 boost::mpi::reduce(
::comm_cart, node_local,
node, std::plus<int>{}, 0);
532 assert(not has_created or
node == 0);
542 auto success =
false;
543 boost::mpi::reduce(
::comm_cart, has_moved, success, std::plus<bool>{}, 0);
545 throw std::runtime_error(
"Particle node for id " + std::to_string(p_id) +
553 throw std::runtime_error(
"The provided particle type " +
554 std::to_string(type) +
555 " is currently not tracked by the system.");
558 if (random_index_in_type_map + 1 > it->second.size())
559 throw std::runtime_error(
"The provided index exceeds the number of "
560 "particle types listed in the particle_type_map");
562 auto p_id = *std::next(it->second.begin(), random_index_in_type_map);
570 throw std::runtime_error(
"The provided particle type " +
571 std::to_string(type) +
572 " is currently not tracked by the system.");
575 return static_cast<int>(it->second.size());
#define REGISTER_CALLBACK(cb)
Register a static callback without return value.
Vector implementation and trait types for boost qvm interoperability.
__shared__ int pos[MAXDEPTH *THREADS5/WARPSIZE]
__shared__ int node[MAXDEPTH *THREADS5/WARPSIZE]
This file contains everything related to the global cell structure / cell system.
auto call_all(void(*fp)(Args...), ArgRef &&...args) const -> std::enable_if_t< std::is_void_v< decltype(fp(args...))> >
Call a callback on all nodes.
void on_particle_change()
Called every time a particle property changes.
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
std::shared_ptr< InteractionsNonBonded > nonbonded_ias
A stripped-down version of std::span from C++17.
DEVICE_QUALIFIER constexpr iterator end() const
DEVICE_QUALIFIER constexpr iterator begin() const
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
void mpi_call(void(*fp)(Args...), ArgRef &&...args)
Call a local function.
MpiCallbacks & mpiCallbacks()
Returns a reference to the global callback class instance.
void gatherv(const boost::mpi::communicator &comm, const T *in_values, int in_size, T *out_values, const int *sizes, const int *displs, int root)
auto keys(Map const &m) -> std::vector< typename Map::key_type >
Return the keys of a map type.
std::size_t const max_cache_size
Utils::Cache< int, Particle > particle_fetch_cache(max_cache_size)
Various procedures concerning interactions between particles.
std::vector< int > get_particle_ids_parallel()
static int max_seen_pid
Keep track of the largest particle id.
static void add_id_to_type_map(int p_id, int type)
void prefetch_particle_data(Utils::Span< const int > in_ids)
Fetch a range of particle into the fetch cache.
static bool maybe_move_particle(int p_id, Utils::Vector3d const &pos)
Move particle to a new position.
static void build_particle_node()
Rebuild the particle index.
void make_new_particle(int p_id, Utils::Vector3d const &pos)
Create a new particle and attach it to a cell.
const Particle & get_particle_data(int p_id)
Get particle data.
static std::unordered_map< int, int > particle_node
Mapping particle ids to MPI ranks.
int get_particle_node(int p_id)
Get the MPI rank which owns the a specific particle.
int number_of_particles_with_type(int type)
void set_particle_pos(int p_id, Utils::Vector3d const &pos)
Move particle to a new position.
void init_type_map(int type)
static void remove_id_from_map(int p_id, int type)
static void mpi_synchronize_max_seen_pid_local()
void remove_all_particles()
Remove all particles.
int get_random_p_id(int type, int random_index_in_type_map)
Find a particle of given type and return its id.
static int calculate_max_seen_id()
Calculate the largest particle id.
void remove_particle(int p_id)
Remove particle with a given identity.
static void mpi_get_particles_local()
static void mpi_who_has_head()
int get_maximal_particle_id()
Get maximal particle id.
int get_particle_node_parallel(int p_id)
std::vector< int > get_particle_ids()
Get all particle ids.
std::size_t fetch_cache_max_size()
Return the maximal number of particles that are kept in the fetch cache.
void invalidate_fetch_cache()
Invalidate the fetch cache for get_particle_data.
static auto rebuild_needed()
static auto & get_cell_structure()
static void build_particle_node_parallel()
Rebuild the particle index.
static bool maybe_insert_particle(int p_id, Utils::Vector3d const &pos)
Create a new particle and attach it to a cell.
void clear_particle_node()
Invalidate particle_node.
static bool type_list_enable
Enable particle type tracking in particle_type_map.
static void mpi_who_has_local()
void on_particle_type_change(int p_id, int old_type, int new_type)
static void mpi_send_particle_data_local(int p_id)
int get_n_part()
Get number of particles.
static void clear_particle_type_map()
static std::vector< Particle > mpi_get_particles(Utils::Span< const int > ids)
Get multiple particles at once.
static std::unordered_map< int, std::unordered_set< int > > particle_type_map
Mapping particle types to lists of particle ids.
bool particle_exists(int p_id)
Check if particle exists.
Particles creation and deletion.
Struct holding all information for one particle.