27#ifdef ESPRESSO_CALIPER
37#include <boost/mpi/collectives.hpp>
38#include <boost/mpi/nonblocking.hpp>
83std::span<ParticleList *const>
as_span(std::vector<ParticleList *>
const &v) {
84 return {v.data(), v.size()};
88std::vector<ParticleList *>
region_cells(std::vector<SendRegion>
const &send) {
89 std::vector<ParticleList *> cells;
90 cells.reserve(send.size());
91 for (
auto const &r : send)
92 cells.emplace_back(r.cell);
119#if defined(ESPRESSO_ADDITIONAL_CHECKS) and not defined(NDEBUG)
124 for (
auto const &r :
regions) {
126 "pack_regions: per-region shifts differ within one NeighborComm "
127 "-- packer must be generalized for per-region shift support");
168 auto const &comm = plan.
comm;
170 int const my_rank = comm.rank();
194 auto const cell_span = std::span<ParticleList *const>{&cell, 1};
200 boost::mpi::broadcast(comm,
safe_data(buf),
201 static_cast<int>(buf.
size()),
root);
202 boost::mpi::broadcast(comm, buf.
bonds(),
root);
206 boost::mpi::broadcast(comm,
safe_data(buf),
207 static_cast<int>(buf.
size()),
root);
208 boost::mpi::broadcast(comm, buf.
bonds(),
root);
217 int const count =
static_cast<int>(buf.
size() /
sizeof(
double));
222 boost::mpi::reduce(comm,
raw, count,
recv_raw, std::plus<double>{},
226 boost::mpi::reduce(comm,
raw, count, std::plus<double>{},
root);
239 st.data_parts = data_parts;
246#ifdef ESPRESSO_ADDITIONAL_CHECKS
266 "halo_exchange first use"));
276#ifdef ESPRESSO_ROTATION
283#ifdef ESPRESSO_BOND_CONSTRAINT
286#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
290 "Combine::Add only valid for reducible parts (FORCE, FORCE|TORQUE, "
294 auto const &comm = plan.
comm;
310 int const tag = main_tag(data_parts);
316 for (std::size_t i = 0; i < n; ++i) {
329#ifdef ESPRESSO_CALIPER
333 for (std::size_t i = 0; i < n; ++i) {
336 pack_regions(bufs.
send[i],
nc.send, box, data_parts);
343#ifdef ESPRESSO_CALIPER
353#ifdef ESPRESSO_CALIPER
357 for (std::size_t i = 0; i < n; ++i) {
362 static_cast<int>(bufs.
recv[i].size())));
364 for (std::size_t i = 0; i < n; ++i) {
367 static_cast<int>(bufs.
send[i].size())));
375 for (std::size_t i = 0; i < n; ++i) {
378 comm.irecv(
nc.peer, TAG_BONDS, bufs.
recv[i].bonds()));
380 for (std::size_t i = 0; i < n; ++i) {
383 comm.isend(
nc.peer, TAG_BONDS, bufs.
send[i].bonds()));
386#ifdef ESPRESSO_CALIPER
413 for (
auto const &
lc : plan.
local) {
430 auto pool = std::make_unique<ExchangeBuffers>();
433 st.owned = std::move(
pool);
441 auto &bufs = *
st.bufs;
446 if (
st.plan->collective)
447 run_collective(*
st.plan, *
st.box,
st.data_parts,
st.op);
449 auto const n =
st.plan->neighbors.size();
463#ifdef ESPRESSO_CALIPER
467 boost::mpi::wait_all(bufs.requests.begin(), bufs.requests.end());
468#ifdef ESPRESSO_CALIPER
474 for (std::size_t i = 0; i < n; ++i) {
475 auto dst = as_span(bufs.recv_cells[i]);
478#ifdef ESPRESSO_CALIPER
492#ifdef ESPRESSO_CALIPER
496 for (std::size_t i = 0; i < n; ++i) {
497 bufs.requests[i].wait();
498#ifdef ESPRESSO_CALIPER
504 auto dst = as_span(bufs.recv_cells[i]);
508#ifdef ESPRESSO_BOND_CONSTRAINT
513#ifdef ESPRESSO_DIPOLE_FIELD_TRACKING
518#ifdef ESPRESSO_CALIPER
528 boost::mpi::wait_all(bufs.requests.begin() +
static_cast<std::ptrdiff_t
>(n),
529 bufs.requests.begin() +
530 static_cast<std::ptrdiff_t
>(2 * n));
531#ifdef ESPRESSO_CALIPER
553#ifdef ESPRESSO_CALIPER
559 for (std::size_t i = 0; i < n; ++i)
560 bufs.slot_to_neighbor[i] = i;
566 auto first = bufs.requests.begin();
568 bufs.requests.begin() +
static_cast<std::ptrdiff_t
>(
active_end);
572#ifdef ESPRESSO_CALIPER
580 static_cast<std::size_t
>(
done_it - bufs.requests.begin());
592 std::iter_swap(
done_it, bufs.requests.begin() +
594 std::swap(bufs.slot_to_neighbor[
done_slot],
597#ifdef ESPRESSO_CALIPER
605#ifdef ESPRESSO_CALIPER
617 boost::mpi::wait_all(bufs.requests.begin() +
static_cast<std::ptrdiff_t
>(n),
618 bufs.requests.begin() +
619 static_cast<std::ptrdiff_t
>(2 * n));
620#ifdef ESPRESSO_CALIPER
Asynchronous, split-phase ghost-communication engine.
Zero-overhead Caliper guards for the inactive (no CALI_CONFIG) case.
bool espresso_cali_active() noexcept
Return true if Caliper is configured for this process.
Class that stores marshalled data for ghost communications.
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.
DEVICE_QUALIFIER constexpr bool empty() const noexcept
DEVICE_QUALIFIER constexpr reference front()
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
Ghost particles and particle exchange.
@ GHOSTTRANS_RATTLE
transfer ParticleRattle
@ GHOSTTRANS_DIPFLD
transfer dipole field tracking data
@ GHOSTTRANS_PARTNUM
resize the receiver particle arrays to the size of the senders
@ GHOSTTRANS_POSITION
transfer ParticlePosition
@ GHOSTTRANS_FORCE
transfer ParticleForce
@ GHOSTTRANS_TORQUE
transfer torque (reduced with force; runtime-conditional)
int main_tag(unsigned data_parts)
std::span< ParticleList *const > as_span(std::vector< ParticleList * > const &v)
View a list of cell pointers as a span for the packing routines.
void run_collective(HaloPlan const &plan, BoxGeometry const &box, unsigned data_parts, ExchangeOp op)
Collective (broadcast/reduce-sum) section.
void pack_regions(CommBuf &buf, std::vector< SendRegion > const ®ions, BoxGeometry const &box, unsigned data_parts)
Pack all send regions of one NeighborComm into a single buffer.
GhostTag
MPI tags for ghost communications.
std::vector< ParticleList * > region_cells(std::vector< SendRegion > const &send)
Extract the plain cell pointers from a list of send regions.
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 halo_exchange_finish(GhostExchange &st)
Complete a halo exchange: run same-rank copies (overlapping the in-flight messages),...
bool report_violations(std::vector< std::string > const &violations, char const *context)
Print violations to stderr and return whether the list was empty.
void halo_exchange(HaloPlan const &plan, BoxGeometry const &box, unsigned data_parts, ExchangeOp op, ExchangeBuffers &bufs)
Blocking wrapper using a caller-owned buffer pool (no per-call alloc after warm-up).
GhostExchange halo_exchange_start(HaloPlan const &plan, BoxGeometry const &box, unsigned data_parts, ExchangeOp op, ExchangeBuffers &bufs)
Begin a halo exchange using a caller-owned buffer pool.
void add_rattle(CommBuf &buf, std::span< ParticleList *const > cells)
Add rattle corrections from a communication buffer to particles.
std::vector< std::string > validate_halo_plan_symmetry(HaloPlan const &plan)
Cross-rank symmetry check for a HaloPlan.
Reusable particle packing/unpacking for ghost communications.
Persistent per-neighbor buffer pool for halo exchanges.
std::vector< CommBuf > send
Per-neighbor packed send buffers (index-aligned with plan->neighbors).
std::vector< std::size_t > slot_to_neighbor
Scratch index map for the Overwrite (wait_any) path in halo_exchange_finish: maps active request slot...
std::vector< CommBuf > recv
Per-neighbor recv buffers (index-aligned with plan->neighbors).
std::vector< std::vector< ParticleList * > > send_cells
Scratch cell-pointer arrays for the packing routines.
std::vector< std::vector< ParticleList * > > recv_cells
std::vector< boost::mpi::request > requests
Outstanding non-blocking send/recv requests (cleared before each use).
Opaque handle for one in-flight halo exchange.
bool symmetry_validated
Lazily-set flag for the once-per-plan symmetry check.
std::optional< CollectiveSection > collective
boost::mpi::communicator comm
std::vector< NeighborComm > neighbors
std::vector< LocalComm > local