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>
57#define REQ_GHOST_SEND 100
67 char *
data() {
return buf.data(); }
68 const char *
data()
const {
return buf.data(); }
72 std::size_t
size()
const {
return buf.size(); }
78 void resize(std::size_t new_size) { buf.resize(new_size); }
82 auto &
bonds() {
return bondbuf; }
83 const auto &
bonds()
const {
return bondbuf; }
85 auto make_span() {
return std::span(buf.data(), buf.size()); }
88 std::vector<char> buf;
89 std::vector<char> bondbuf;
94 std::size_t m_size = 0;
97 auto size()
const {
return m_size; }
104 template <
class T>
auto &
operator&(T &t) {
return *
this << t; }
124template <
class Archive>
134#ifdef ROTATIONAL_INERTIA
147#ifdef LB_ELECTROHYDRODYNAMICS
150#ifdef VIRTUAL_SITES_RELATIVE
153#ifdef THERMOSTAT_PER_PARTICLE
159#ifdef EXTERNAL_FORCES
173 auto pos = p.
pos() + *ghost_shift;
185#ifdef BOND_CONSTRAINT
215#ifdef BOND_CONSTRAINT
230 unsigned data_parts) {
235 return sizeof_archive.
size();
240 unsigned int data_parts) {
242 return sizeof(
unsigned int) * ghost_comm.
part_lists.size();
244 auto const n_part = boost::accumulate(
246 [](std::size_t sum,
auto part_list) { return sum + part_list->size(); });
254 unsigned int data_parts) {
258 send_buffer.
bonds().clear();
263 namespace io = boost::iostreams;
264 io::stream<io::back_insert_device<std::vector<char>>> os{
265 io::back_inserter(send_buffer.
bonds())};
266 boost::archive::binary_oarchive bond_archiver{os};
269 for (
auto part_list : ghost_comm.
part_lists) {
271 assert(part_list->size() <= std::numeric_limits<unsigned int>::max());
272 auto np =
static_cast<unsigned int>(part_list->size());
275 for (
auto &p : *part_list) {
280 bond_archiver << p.bonds();
286 assert(archiver.bytes_written() == send_buffer.
size());
294 for (
auto &p : *cell) {
302 unsigned int data_parts) {
306 recv_buffer.
bonds().clear();
312 unsigned int data_parts) {
317 for (
auto part_list : ghost_comm.
part_lists) {
323 for (
auto part_list : ghost_comm.
part_lists) {
324 for (
auto &p : *part_list) {
330 namespace io = boost::iostreams;
331 io::stream<io::array_source> bond_stream(io::array_source{
332 recv_buffer.
bonds().data(), recv_buffer.
bonds().size()});
333 boost::archive::binary_iarchive bond_archiver(bond_stream);
335 for (
auto part_list : ghost_comm.
part_lists) {
336 for (
auto &p : *part_list) {
337 bond_archiver >> p.bonds();
343 assert(archiver.bytes_read() == recv_buffer.
size());
345 recv_buffer.
bonds().clear();
348#ifdef BOND_CONSTRAINT
354 for (
auto &part_list : ghost_comm.
part_lists) {
358 part.rattle_params() += pr;
368 for (
auto &part_list : ghost_comm.
part_lists) {
372 part.force_and_torque() += pf;
379 unsigned int data_parts) {
385 auto const offset = ghost_comm.
part_lists.size() / 2;
386 for (std::size_t pl = 0; pl < offset; pl++) {
388 auto *dst_list = ghost_comm.
part_lists[pl + offset];
393 auto &src_part = *src_list;
394 auto &dst_part = *dst_list;
395 assert(src_part.size() == dst_part.size());
397 for (std::size_t i = 0; i < src_part.size(); i++) {
400 auto &p1 = src_part.begin()[i];
401 auto &p2 = dst_part.begin()[i];
408 p2.bonds() = p1.bonds();
430 int const node = ghost_comm.
node;
438 int const node = ghost_comm.
node;
443 BoxGeometry const &box_geo,
unsigned int data_parts) {
447 static CommBuf send_buffer, recv_buffer;
463 int const node = ghost_comm.
node;
466 if (
is_send_op(comm_type, node, comm.rank())) {
473 assert(send_buffer.
size() ==
475 }
else if (prefetch) {
477 auto prefetch_ghost_comm = std::find_if(
480 return is_prefetchable(ghost_comm, this_node);
498 static_cast<int>(recv_buffer.
size()));
503 static_cast<int>(send_buffer.
size()));
507 if (node == comm.rank()) {
508 boost::mpi::broadcast(comm, send_buffer.
data(),
509 static_cast<int>(send_buffer.
size()), node);
510 boost::mpi::broadcast(comm, send_buffer.
bonds(), node);
512 boost::mpi::broadcast(comm, recv_buffer.
data(),
513 static_cast<int>(recv_buffer.
size()), node);
514 boost::mpi::broadcast(comm, recv_buffer.
bonds(), node);
518 if (node == comm.rank())
520 comm,
reinterpret_cast<double *
>(send_buffer.
data()),
521 static_cast<int>(send_buffer.
size() /
sizeof(
double)),
522 reinterpret_cast<double *
>(recv_buffer.
data()), std::plus<double>{},
526 comm,
reinterpret_cast<double *
>(send_buffer.
data()),
527 static_cast<int>(send_buffer.
size() /
sizeof(
double)),
528 std::plus<double>{}, node);
533 if (
is_recv_op(comm_type, node, comm.rank())) {
539#ifdef BOND_CONSTRAINT
546 }
else if (poststore) {
550 auto poststore_ghost_comm = std::find_if(
553 return is_poststorable(ghost_comm, this_node);
557 assert(recv_buffer.
size() ==
562#ifdef BOND_CONSTRAINT
565 *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