core
Shared MPI block decomposition + asynchronous ghost-layer exchange (header-only C++20)
Loading...
Searching...
No Matches
particle_rebalance.hpp
Go to the documentation of this file.
1// core — particle-count load re-balancing for the Lagrangian path.
2//
3// The Eulerian/AMR side rebalances by re-decomposing on a per-cell *work* weight and migrating the
4// owned data (see peclet::core::amr::DistributedOctree::rebalance). This is the Lagrangian
5// counterpart: when particles drift (e.g. a dense DEM packing densifies and skews the per-block
6// count), the equal-cell ORB no longer balances the load. rebalanceByParticleCount() bins the
7// particles onto the decomposition grid, re-decomposes with the *weighted* ORB so every block
8// carries a near-equal particle count, and migrates particles to their new owners with the existing
9// ParticleMigrator.
10//
11// It is a pure redistribution: the global particle set is unchanged (count conserved, positions and
12// payloads preserved); only ownership moves. The BlockDecomposer is re-initialised in place, so a
13// ParticleMigrator (or GridHaloTopology) holding a pointer to it transparently sees the new
14// partition. MPI-optional: a single rank keeps every particle and the decomposition is unchanged.
15#ifndef PECLET_CORE_HALO_PARTICLE_REBALANCE_HPP
16#define PECLET_CORE_HALO_PARTICLE_REBALANCE_HPP
17
18#include <vector>
19
24
25namespace peclet::core::halo {
26
27namespace detail {
28template <class T>
29struct NonDeduced {
30 using type = T;
31};
32} // namespace detail
33
39template <int Dim>
41 std::vector<typename detail::NonDeduced<Vec<Dim>>::type>& pos,
42 std::vector<char>& payload, std::size_t stride,
44 std::vector<double>* weightOut = nullptr) {
45 // 1. Particle count per global decomposition cell, agreed across ranks.
46 const IVec<Dim>& gsize = dec.globalSize();
47 std::size_t ncells = 1;
48 for (int d = 0; d < Dim; ++d)
49 ncells *= static_cast<std::size_t>(gsize[d]);
50 std::vector<double> localCount(ncells, 0.0), weight(ncells, 0.0);
51 for (const Vec<Dim>& x : pos)
52 localCount[static_cast<std::size_t>(dec.linearGlobal(mig.cellOf(x)))] += 1.0;
53 MPI_Allreduce(localCount.data(), weight.data(), static_cast<int>(ncells), MPI_DOUBLE, MPI_SUM,
54 comm);
55
56 // 2. Weighted re-decomposition over the same grid (in place: mig still points at dec).
57 int sz = 1;
58 MPI_Comm_size(comm, &sz);
59 dec.init(static_cast<std::size_t>(sz), gsize, weight);
60 if (weightOut)
61 *weightOut = std::move(weight);
62
63 // 3. Migrate particles to their new owners. ParticleMigrator already reassigns by ownerOf, which
64 // now reflects the re-weighted partition.
65 return mig.migrate(pos, payload, stride);
66}
67
68} // namespace peclet::core::halo
69
70#endif // PECLET_CORE_HALO_PARTICLE_REBALANCE_HPP
int MPI_Comm_size(MPI_Comm, int *s)
Definition mpi_stub.hpp:69
int MPI_Allreduce(const void *sbuf, void *rbuf, int count, MPI_Datatype dt, MPI_Op, MPI_Comm)
Definition mpi_stub.hpp:80
int MPI_Comm
Definition mpi_stub.hpp:16
#define MPI_COMM_WORLD
Definition mpi_stub.hpp:26
#define MPI_SUM
Definition mpi_stub.hpp:42
#define MPI_DOUBLE
Definition mpi_stub.hpp:40
std::size_t rebalanceByParticleCount(decomp::BlockDecomposer< Dim > &dec, ParticleMigrator< Dim > &mig, std::vector< typename detail::NonDeduced< Vec< Dim > >::type > &pos, std::vector< char > &payload, std::size_t stride, MPI_Comm comm=MPI_COMM_WORLD, std::vector< double > *weightOut=nullptr)
Re-decompose dec so each block holds a near-equal particle count, then migrate the particles (positio...
Kokkos::View< T *, MemSpace > View
1D device array.
Definition view.hpp:26