ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
particle_packing.hpp
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
22#pragma once
23
24/**
25 * @file
26 * Reusable particle packing/unpacking for ghost communications.
27 */
28
29#include <config/config.hpp>
30
31#include "BoxGeometry.hpp"
32#include "ParticleList.hpp"
33
34#include <utils/Vector.hpp>
35
36#include <cstddef>
37#include <memory>
38#include <span>
39#include <vector>
40
41namespace GhostComm {
42
43namespace detail {
44/**
45 * @brief Allocator wrapper that skips value-initialization on grow.
46 *
47 * `std::vector<T, DefaultInitAllocator<T>>::resize(n)` extends storage
48 * without zero-filling when n > size(), leaving new bytes in an
49 * indeterminate state. Use only when all grown bytes are overwritten
50 * before being read (e.g. by pack_cells / MPI irecv).
51 *
52 * All other allocator operations (allocate, deallocate, copy/move) are
53 * forwarded to `std::allocator<T>`.
54 */
55template <class T> struct DefaultInitAllocator : std::allocator<T> {
56 using value_type = T;
57 // Inherit all constructors from std::allocator<T>.
58 using std::allocator<T>::allocator;
59
60 template <class U> struct rebind {
61 using other = DefaultInitAllocator<U>;
62 };
63
64 /**
65 * @brief Called by vector::resize for each newly appended element.
66 * Plain `new (p) T` uses default-initialization: trivial types like
67 * `char` are left uninitialized rather than zero-filled.
68 */
69 void construct(T *p) noexcept { ::new (static_cast<void *>(p)) T; }
70
71 /** Forward non-default construction unchanged. */
72 template <class... Args> void construct(T *p, Args &&...args) {
73 ::new (static_cast<void *>(p)) T(std::forward<Args>(args)...);
74 }
75};
76} // namespace detail
77
78/**
79 * @brief Class that stores marshalled data for ghost communications.
80 * To store and retrieve data, use the adapter classes below.
81 *
82 * Invariant: every byte in the non-bond buffer is written by the caller
83 * (pack_cells / MPI irecv) before it is read (unpack_cells / add_forces).
84 * The buffer therefore uses a default-init allocator so that resize()-on-grow
85 * does not zero-fill bytes that will be immediately overwritten, eliminating
86 * the `__memset_avx2` overhead visible in perf profiles at large particle
87 * counts. The bond buffer is kept as a plain std::vector<char> because it is
88 * serialized via boost.mpi (which requires exact byte semantics) and is on the
89 * cold resort-only path.
90 */
91class CommBuf {
92 using ByteVec = std::vector<char, detail::DefaultInitAllocator<char>>;
93
94public:
95 /** Returns a pointer to the non-bond storage. */
96 char *data() { return buf.data(); }
97 const char *data() const { return buf.data(); }
98
99 /** Returns the number of elements in the non-bond storage. */
100 std::size_t size() const { return buf.size(); }
101
102 /**
103 * @brief Resizes the underlying storage s.t. the object is capable of holding
104 * @p new_size chars. Bytes added by growth are left uninitialized;
105 * the caller must write them (pack_cells / MPI irecv) before reading.
106 */
107 void resize(std::size_t new_size) { buf.resize(new_size); }
108
109 /** Returns a reference to the bond storage. */
110 auto &bonds() { return bondbuf; }
111 const auto &bonds() const { return bondbuf; }
112
113 auto make_span() { return std::span(buf.data(), buf.size()); }
114
115private:
116 ByteVec buf; ///< Buffer for everything but bonds (default-init grow)
117 std::vector<char>
118 bondbuf; ///< Buffer for bond lists (boost.mpi-serialized, cold path)
119};
120
121/**
122 * @brief Calculate the per-particle transmit size for the given data parts.
123 */
124std::size_t calc_transmit_size(BoxGeometry const &box_geo, unsigned data_parts);
125
126/**
127 * @brief Calculate the total transmit size for a list of cells and data parts.
128 *
129 * When GHOSTTRANS_PARTNUM is set, returns sizeof(unsigned int) per cell.
130 * Otherwise returns the total number of particles times the per-particle size.
131 */
132std::size_t calc_transmit_size(std::span<ParticleList *const> cells,
133 BoxGeometry const &box_geo, unsigned data_parts);
134
135/**
136 * @brief Pack particle data from cells into a communication buffer.
137 *
138 * Handles GHOSTTRANS_PARTNUM (writes cell sizes) and GHOSTTRANS_BONDS
139 * (separate bond buffer) special cases.
140 *
141 * @param buf Buffer to pack into (resized as needed).
142 * @param cells Source particle lists.
143 * @param shift Ghost shift applied to particle positions on save.
144 * @param box_geo Box geometry for fold_position.
145 * @param data_parts Bitmask of GHOSTTRANS_* flags.
146 */
147void pack_cells(CommBuf &buf, std::span<ParticleList *const> cells,
148 Utils::Vector3d const &shift, BoxGeometry const &box_geo,
149 unsigned data_parts);
150
151/**
152 * @brief Unpack particle data from a communication buffer into cells.
153 *
154 * Handles GHOSTTRANS_PARTNUM (resizes ghost cells) and GHOSTTRANS_BONDS
155 * (separate bond buffer) special cases.
156 *
157 * @param buf Buffer to unpack from.
158 * @param cells Destination particle lists.
159 * @param box_geo Box geometry (unused here, kept for API symmetry).
160 * @param data_parts Bitmask of GHOSTTRANS_* flags.
161 */
162void unpack_cells(CommBuf &buf, std::span<ParticleList *const> cells,
163 BoxGeometry const &box_geo, unsigned data_parts);
164
165/**
166 * @brief Add forces (and optionally torques) from a communication buffer
167 * to particles in cells.
168 *
169 * @param buf Buffer produced by a force-reduce exchange.
170 * @param cells Destination (owned) particle lists.
171 * @param data_parts Bitmask of GHOSTTRANS_* flags; must include
172 * GHOSTTRANS_FORCE, may include GHOSTTRANS_TORQUE.
173 */
174void add_forces(CommBuf &buf, std::span<ParticleList *const> cells,
175 unsigned data_parts);
176
177#ifdef ESPRESSO_BOND_CONSTRAINT
178/**
179 * @brief Add rattle corrections from a communication buffer to particles.
180 */
181void add_rattle(CommBuf &buf, std::span<ParticleList *const> cells);
182#endif
183
184#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
185/**
186 * @brief Add dipole fields from a communication buffer to particles.
187 */
188void add_dip_fld(CommBuf &buf, std::span<ParticleList *const> cells);
189#endif
190
191/**
192 * @brief Copy particle data from src to dst applying a ghost shift.
193 *
194 * For GHOSTTRANS_PARTNUM, resizes dst to match src.
195 * Otherwise serializes each particle from src and deserializes into dst,
196 * applying the shift and folding the position. Bond data is copied directly.
197 *
198 * @param src Source particle list.
199 * @param dst Destination particle list.
200 * @param shift Ghost shift to apply.
201 * @param box_geo Box geometry for fold_position.
202 * @param data_parts Bitmask of GHOSTTRANS_* flags.
203 */
205 Utils::Vector3d const &shift, BoxGeometry const &box_geo,
206 unsigned data_parts);
207
208} // namespace GhostComm
Vector implementation and trait types for boost qvm interoperability.
Class that stores marshalled data for ghost communications.
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.
const auto & bonds() const
auto & bonds()
Returns a reference to the bond storage.
const char * data() const
void resize(std::size_t new_size)
Resizes the underlying storage s.t.
void unpack_cells(CommBuf &buf, std::span< ParticleList *const > cells, BoxGeometry const &box_geo, unsigned data_parts)
Unpack particle data from a communication buffer into cells.
void pack_cells(CommBuf &buf, std::span< ParticleList *const > cells, Utils::Vector3d const &shift, BoxGeometry const &box_geo, unsigned data_parts)
Pack particle data from cells into a communication buffer.
void local_cell_copy(ParticleList &src, ParticleList &dst, Utils::Vector3d const &shift, BoxGeometry const &box_geo, unsigned data_parts)
Copy particle data from src to dst applying a ghost shift.
std::size_t calc_transmit_size(BoxGeometry const &box_geo, unsigned data_parts)
Calculate the per-particle transmit size for the given data parts.
void add_forces(CommBuf &buf, std::span< ParticleList *const > cells, unsigned data_parts)
Add forces (and optionally torques) from a communication buffer to particles in cells.
void add_dip_fld(CommBuf &buf, std::span< ParticleList *const > cells)
Add dipole fields from a communication buffer to particles.
void add_rattle(CommBuf &buf, std::span< ParticleList *const > cells)
Add rattle corrections from a communication buffer to particles.