35#include "system/System.hpp"
39#include <boost/archive/binary_iarchive.hpp>
40#include <boost/archive/binary_oarchive.hpp>
41#include <boost/iostreams/device/array.hpp>
42#include <boost/iostreams/device/back_inserter.hpp>
43#include <boost/iostreams/stream.hpp>
44#include <boost/mpi/collectives.hpp>
45#include <boost/range/numeric.hpp>
46#include <boost/serialization/vector.hpp>
58#define REQ_GHOST_SEND 100
68 char *
data() {
return buf.data(); }
69 const char *
data()
const {
return buf.data(); }
73 std::size_t
size()
const {
return buf.size(); }
79 void resize(std::size_t new_size) { buf.resize(new_size); }
83 auto &
bonds() {
return bondbuf; }
84 const auto &
bonds()
const {
return bondbuf; }
86 auto make_span() {
return std::span(buf.data(), buf.size()); }
89 std::vector<char> buf;
90 std::vector<char> bondbuf;
95 std::size_t m_size = 0;
98 auto size()
const {
return m_size; }
105 template <
class T>
auto &
operator&(T &t) {
return *
this << t; }
125template <
class Archive>
133#ifdef ESPRESSO_ROTATION
135#ifdef ESPRESSO_ROTATIONAL_INERTIA
142#ifdef ESPRESSO_ELECTROSTATICS
145#ifdef ESPRESSO_DIPOLES
148#ifdef ESPRESSO_LB_ELECTROHYDRODYNAMICS
151#ifdef ESPRESSO_VIRTUAL_SITES_RELATIVE
154#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
156#ifdef ESPRESSO_ROTATION
160#ifdef ESPRESSO_EXTERNAL_FORCES
163#ifdef ESPRESSO_ROTATION
167#ifdef ESPRESSO_ENGINE
174 auto pos = p.
pos() + *ghost_shift;
183#ifdef ESPRESSO_ROTATION
186#ifdef ESPRESSO_BOND_CONSTRAINT
192#ifdef ESPRESSO_ROTATION
205#ifdef ESPRESSO_ROTATION
216#ifdef ESPRESSO_BOND_CONSTRAINT
231 unsigned data_parts) {
236 return sizeof_archive.
size();
241 unsigned int data_parts) {
243 return sizeof(
unsigned int) * ghost_comm.
part_lists.size();
245 auto const n_part = boost::accumulate(
247 [](std::size_t sum,
auto part_list) { return sum + part_list->size(); });
255 unsigned int data_parts) {
259 send_buffer.
bonds().clear();
264 namespace io = boost::iostreams;
265 io::stream<io::back_insert_device<std::vector<char>>> os{
266 io::back_inserter(send_buffer.
bonds())};
267 boost::archive::binary_oarchive bond_archiver{os};
270 for (
auto part_list : ghost_comm.
part_lists) {
272 assert(part_list->size() <= std::numeric_limits<unsigned int>::max());
273 auto np =
static_cast<unsigned int>(part_list->size());
276 for (
auto &p : *part_list) {
281 bond_archiver << p.bonds();
287 assert(archiver.bytes_written() == send_buffer.
size());
295 for (
auto &p : *cell) {
303 unsigned int data_parts) {
307 recv_buffer.
bonds().clear();
313 unsigned int data_parts) {
318 for (
auto part_list : ghost_comm.
part_lists) {
324 for (
auto part_list : ghost_comm.
part_lists) {
325 for (
auto &p : *part_list) {
331 namespace io = boost::iostreams;
332 io::stream<io::array_source> bond_stream(io::array_source{
333 recv_buffer.
bonds().data(), recv_buffer.
bonds().size()});
334 boost::archive::binary_iarchive bond_archiver(bond_stream);
336 for (
auto part_list : ghost_comm.
part_lists) {
337 for (
auto &p : *part_list) {
338 bond_archiver >> p.bonds();
344 assert(archiver.bytes_read() == recv_buffer.
size());
346 recv_buffer.
bonds().clear();
349#ifdef ESPRESSO_BOND_CONSTRAINT
355 for (
auto &part_list : ghost_comm.
part_lists) {
359 part.rattle_params() += pr;
369 for (
auto &part_list : ghost_comm.
part_lists) {
373 part.force_and_torque() += pf;
380 unsigned int data_parts) {
386 auto const offset = ghost_comm.
part_lists.size() / 2;
387 for (std::size_t pl = 0; pl < offset; pl++) {
389 auto *dst_list = ghost_comm.
part_lists[pl + offset];
394 auto &src_part = *src_list;
395 auto &dst_part = *dst_list;
396 assert(src_part.size() == dst_part.size());
398 for (std::size_t i = 0; i < src_part.size(); i++) {
401 auto &p1 = src_part.begin()[i];
402 auto &p2 = dst_part.begin()[i];
409 p2.bonds() = p1.bonds();
431 int const node = ghost_comm.
node;
439 int const node = ghost_comm.
node;
444 BoxGeometry const &box_geo,
unsigned int data_parts) {
448 static CommBuf send_buffer, recv_buffer;
454 auto const &ghost_comm = *cit;
464 int const node = ghost_comm.node;
467 if (
is_send_op(comm_type, node, comm.rank())) {
474 assert(send_buffer.
size() ==
476 }
else if (prefetch) {
478 auto prefetch_ghost_comm =
480 [
this_node = comm.rank()](
auto const &other_ghost_comm) {
481 return is_prefetchable(other_ghost_comm, this_node);
499 static_cast<int>(recv_buffer.
size()));
504 static_cast<int>(send_buffer.
size()));
508 if (node == comm.rank()) {
509 boost::mpi::broadcast(comm, send_buffer.
data(),
510 static_cast<int>(send_buffer.
size()), node);
511 boost::mpi::broadcast(comm, send_buffer.
bonds(), node);
513 boost::mpi::broadcast(comm, recv_buffer.
data(),
514 static_cast<int>(recv_buffer.
size()), node);
515 boost::mpi::broadcast(comm, recv_buffer.
bonds(), node);
519 if (node == comm.rank())
521 comm,
reinterpret_cast<double *
>(send_buffer.
data()),
522 static_cast<int>(send_buffer.
size() /
sizeof(
double)),
523 reinterpret_cast<double *
>(recv_buffer.
data()), std::plus<double>{},
527 comm,
reinterpret_cast<double *
>(send_buffer.
data()),
528 static_cast<int>(send_buffer.
size() /
sizeof(
double)),
529 std::plus<double>{}, node);
534 if (
is_recv_op(comm_type, node, comm.rank())) {
540#ifdef ESPRESSO_BOND_CONSTRAINT
547 }
else if (poststore) {
551 auto poststore_ghost_comm = std::find_if(
553 [
this_node = comm.rank()](
auto const &other_ghost_comm) {
554 return is_poststorable(other_ghost_comm, this_node);
558 assert(recv_buffer.
size() ==
563#ifdef ESPRESSO_BOND_CONSTRAINT
566 *poststore_ghost_comm);
void fold_position(Utils::Vector3d &pos, Utils::Vector3i &image_box) const
Fold coordinates to primary simulation box in-place.
Class that stores marshalled data for ghost communications.
const auto & bonds() const
const char * data() const
char * data()
Returns a pointer to the non-bond storage.
std::size_t size() const
Returns the number of elements in the non-bond storage.
auto & bonds()
Returns a reference to the bond storage.
void resize(std::size_t new_size)
Resizes the underlying storage s.t.
Pseudo-archive to calculate the size of the serialization buffer.
void resize(std::size_t new_size)
Resize container.
Archive that deserializes from a buffer via memcpy.
Archive that serializes to a buffer via memcpy.
int this_node
The number of this node.
static void serialize_and_reduce(Archive &ar, Particle &p, unsigned int data_parts, ReductionPolicy policy, SerializationDirection direction, BoxGeometry const &box_geo, Utils::Vector3d const *ghost_shift)
Serialize particle data, possibly with reduction.
static void add_rattle_correction_from_recv_buffer(CommBuf &recv_buffer, const GhostCommunication &ghost_comm)
static void prepare_recv_buffer(CommBuf &recv_buffer, GhostCommunication const &ghost_comm, BoxGeometry const &box_geo, unsigned int data_parts)
#define REQ_GHOST_SEND
Tag for ghosts communications.
static void put_recv_buffer(CommBuf &recv_buffer, GhostCommunication const &ghost_comm, BoxGeometry const &box_geo, unsigned int data_parts)
static void prepare_send_buffer(CommBuf &send_buffer, GhostCommunication const &ghost_comm, BoxGeometry const &box_geo, unsigned int data_parts)
ReductionPolicy
Type of reduction to carry out during serialization.
@ UPDATE
Reduction for cell-to-cell particle update.
@ MOVE
Reduction for domain-to-domain particle communication.
static bool is_recv_op(int comm_type, int node, int this_node)
static void add_forces_from_recv_buffer(CommBuf &recv_buffer, const GhostCommunication &ghost_comm)
static void cell_cell_transfer(GhostCommunication const &ghost_comm, BoxGeometry const &box_geo, unsigned int data_parts)
static bool is_send_op(int comm_type, int node, int this_node)
static void prepare_ghost_cell(ParticleList *cell, std::size_t size)
static auto calc_transmit_size(BoxGeometry const &box_geo, unsigned data_parts)
static bool is_prefetchable(GhostCommunication const &ghost_comm, int this_node)
void ghost_communicator(GhostCommunicator const &gcr, BoxGeometry const &box_geo, unsigned int data_parts)
Do a ghost communication with the specified data parts.
static bool is_poststorable(GhostCommunication const &ghost_comm, int this_node)
SerializationDirection
Whether to save the state to or load the state from the archive.
Ghost particles and particle exchange.
#define GHOST_RECV
recv from a single node
#define GHOST_PSTSTORE
additional flag for poststoring
#define GHOST_JOBMASK
mask to the job area of the transfer type
#define GHOST_RDCE
reduce, the node entry gives the receiver
#define GHOST_LOCL
transfer data from cell to cell on this node
#define GHOST_BCST
broadcast, the node entry gives the sender
@ 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
#define GHOST_SEND
send to a single node
#define GHOST_PREFETCH
additional flag for prefetching
Utils::Vector3d shift
Position shift for ghost particles.
int node
Node to communicate with (to use with all MPI operations).
std::vector< ParticleList * > part_lists
Pointer array to particle lists to communicate.
int type
Communication type.
Properties for a ghost communication.
boost::mpi::communicator mpi_comm
Attached mpi communicator.
std::vector< GhostCommunication > communications
List of ghost communications.
Force information on a particle.
Struct holding all information for one particle.
auto const & swimming() const
auto const & propagation() const
auto const & rinertia() const
auto const & mass() const
auto const & quat() const
auto const & rotation() const
auto const & vs_relative() const
auto const & gamma() const
auto const & pos_last_time_step() const
auto const & gamma_rot() const
auto const & torque() const
auto const & fixed() const
auto const & ext_force() const
auto const & omega() const
auto const & image_box() const
auto const & type() const
auto const & ext_torque() const
auto const & dipm() const
auto const & mol_id() const
auto const & mu_E() const
auto const & force() const
auto const & rattle_correction() const