12 #ifndef CD_LoadBalanceImplem_H
13 #define CD_LoadBalanceImplem_H
21 #include <LoadBalance.H>
22 #include <BoxLayout.H>
27 #include <CD_NamespaceHeader.H>
33 CH_TIME(
"LoadBalancing::makeBalance");
37 LoadBalancing::makeBalance<T>(a_ranks, rankLoads, a_loads, a_boxes);
44 const Vector<T>& a_boxLoads,
45 const Vector<Box>& a_boxes)
47 CH_TIME(
"LoadBalancing::makeBalance");
50 Vector<Real> boxLoads;
51 for (
int i = 0; i < a_boxLoads.size(); i++) {
52 boxLoads.push_back(1.0 * a_boxLoads[i]);
57 const int numBoxes = a_boxes.size();
58 const int numRanks = numProc();
59 const int numSubsets =
std::min(numBoxes, numRanks);
61 a_ranks.resize(numBoxes);
67 for (
int ibox = 0; ibox < numBoxes; ibox++) {
68 totalLoad += boxLoads[ibox];
71 Real staticTargetLoad = totalLoad / numSubsets;
77 using Span = std::pair<int, int>;
78 using Subset = std::pair<Span, Real>;
80 std::vector<Subset> subsets(numSubsets);
82 int firstSubsetBox = 0;
84 Real remainingLoad = totalLoad;
86 for (
int curSubset = 0; curSubset < numSubsets; curSubset++) {
89 Real subsetLoad = boxLoads[firstSubsetBox];
91 int lastSubsetBox = firstSubsetBox;
93 const int subsetsLeft = numSubsets - (curSubset + 1);
94 const int boxesLeft = numBoxes - (firstSubsetBox + 1);
96 if (boxesLeft > subsetsLeft) {
97 for (
int ibox = firstSubsetBox + 1; ibox < numBoxes; ibox++) {
100 if (numBoxes - lastSubsetBox - 1 <= subsetsLeft) {
108 const Real load1 = subsetLoad;
109 const Real load2 = subsetLoad + boxLoads[ibox];
112 bool addBoxToSubset =
false;
114 if (boxLoads[ibox] <= std::numeric_limits<Real>::epsilon()) {
115 addBoxToSubset =
true;
117 else if (load1 > staticTargetLoad) {
118 addBoxToSubset =
false;
120 else if (load2 <= staticTargetLoad) {
121 addBoxToSubset =
true;
123 else if (load1 <= staticTargetLoad && load2 > staticTargetLoad) {
126 const Real loadErrWithoutBox = std::abs(load1 - staticTargetLoad);
127 const Real loadErrWithBox = std::abs(load2 - staticTargetLoad);
129 if (loadErrWithBox <= loadErrWithoutBox) {
130 addBoxToSubset =
true;
135 if (addBoxToSubset) {
136 subsetLoad = subsetLoad + boxLoads[ibox];
137 lastSubsetBox = ibox;
142 lastSubsetBox = ibox - 1;
150 subsets[curSubset] = std::make_pair(std::make_pair(firstSubsetBox, lastSubsetBox), subsetLoad);
153 remainingLoad = remainingLoad - subsetLoad;
154 staticTargetLoad = remainingLoad / subsetsLeft;
157 firstSubsetBox = lastSubsetBox + 1;
161 std::sort(subsets.begin(), subsets.end(), [](
const Subset& A,
const Subset& B) ->
bool {
162 return A.second > B.second;
166 const std::vector<std::pair<int, Real>> sortedRankLoads = a_rankLoads.
getSortedLoads();
169 for (
int i = 0; i < subsets.size(); i++) {
170 const int startIndex = subsets[i].first.first;
171 const int endIndex = subsets[i].first.second;
172 const Real subsetLoad = subsets[i].second;
173 const int rank = sortedRankLoads[i].first;
176 for (
int ibox = startIndex; ibox <= endIndex; ibox++) {
177 a_ranks[ibox] = rank;
190 std::vector<std::pair<Box, T>>
193 CH_TIME(
"LoadBalancing::packPairs");
195 std::vector<std::pair<Box, T>> vec;
196 for (
int i = 0; i < a_boxes.size(); i++) {
197 vec.emplace_back(a_boxes[i], a_loads[i]);
207 CH_TIME(
"LoadBalancing::unpackPairs");
213 for (
const auto& v : a_pairs) {
214 a_boxes.push_back(v.first);
215 a_loads.push_back(v.second);
219 template <
typename T>
223 CH_TIME(
"LoadBalancing::sort");
225 for (
int lvl = 0; lvl < a_boxes.size(); lvl++) {
230 template <
typename T>
234 CH_TIME(
"LoadBalancing::sort");
237 case BoxSorting::None: {
240 case BoxSorting::Std: {
245 case BoxSorting::Shuffle: {
250 case BoxSorting::Morton: {
256 MayDay::Abort(
"LoadBalancing::sort_boxes - unknown algorithm requested");
267 CH_TIME(
"LoadBalancing::standardSort");
269 std::vector<std::pair<Box, T>> vec =
packPairs(a_boxes, a_loads);
272 std::sort(std::begin(vec), std::end(vec), [](
const std::pair<Box, T>& v1,
const std::pair<Box, T>& v2) {
273 return v1.first < v2.first;
283 CH_TIME(
"LoadBalancing::shuffleSort");
288 int seed = std::chrono::system_clock::now().time_since_epoch().count();
290 MPI_Bcast(&seed, 1, MPI_INT, 0, Chombo_MPI::comm);
294 std::default_random_engine e(seed);
295 std::shuffle(vec.begin(), vec.end(), e);
306 CH_TIME(
"LoadBalancing::mortonSort");
311 std::vector<Box>& b = a_boxes.stdVector();
312 int bits =
maxBits(b.begin(), b.end());
315 std::sort(std::begin(vec), std::end(vec), [bits](
const std::pair<Box, T>& v1,
const std::pair<Box, T>& v2) ->
bool {
327 const Box& lbox = a_lhs.first;
328 const Box& rbox = a_rhs.first;
330 const IntVect l = lbox.smallEnd();
331 const IntVect r = rbox.smallEnd();
333 for (
int i = a_maxBits; i > 0; i--) {
336 const int N = (1 << i);
338 for (
int dir = CH_SPACEDIM - 1; dir >= 0; dir--) {
339 if ((l[dir] / N) < (r[dir] / N)) {
342 else if ((l[dir] / N) > (r[dir] / N)) {
351 #include <CD_NamespaceFooter.H>
BoxSorting
Enum for sorting boxes.
Definition: CD_BoxSorting.H:21
Declaration of a static class for various load balancing operations.
static int maxBits(std::vector< Box >::iterator a_first, std::vector< Box >::iterator a_last)
Utility function for Morton sorting which needs the maximum bits.
Definition: CD_LoadBalancing.cpp:279
static void makeBalance(Vector< int > &a_ranks, const Vector< T > &a_loads, const Vector< Box > &a_boxes)
Load balancing, assigning ranks to boxes.
Definition: CD_LoadBalancingImplem.H:31
static void sort(Vector< Vector< Box >> &a_boxes, Vector< Vector< T >> &a_loads, const BoxSorting a_whichSorting)
Sorts boxes and loads over a hierarchy according to some sorting criterion.
Definition: CD_LoadBalancingImplem.H:221
static void standardSort(Vector< Box > &a_boxes, Vector< T > &a_loads)
Standard box sorting, calls C++ std::sort.
Definition: CD_LoadBalancingImplem.H:265
static void mortonSort(Vector< Box > &a_boxes, Vector< T > &a_loads)
Sort boxes using Morton code.
Definition: CD_LoadBalancingImplem.H:304
static bool mortonComparator(const int a_maxBits, const std::pair< Box, T > &a_lhs, const std::pair< Box, T > &a_rhs)
Morton comparator.
Definition: CD_LoadBalancingImplem.H:325
static std::vector< std::pair< Box, T > > packPairs(const Vector< Box > &a_boxes, const Vector< T > &a_loads)
Utility function which packs boxes and loads into a vector of pairs.
Definition: CD_LoadBalancingImplem.H:191
static void unpackPairs(Vector< Box > &a_boxes, Vector< T > &a_loads, const std::vector< std::pair< Box, T >> &a_pairs)
Splits vector pair into separate boxes and loads.
Definition: CD_LoadBalancingImplem.H:205
static void shuffleSort(Vector< Box > &a_boxes, Vector< T > &a_loads)
Randomly shuffles boxes and loads.
Definition: CD_LoadBalancingImplem.H:281
Class for holding computational loads.
Definition: CD_Loads.H:30
virtual void incrementLoad(const int a_rank, const Real a_increment) noexcept
Increment load on rank.
Definition: CD_Loads.cpp:168
virtual std::vector< std::pair< int, Real > > getSortedLoads() const noexcept
Get sorted loads.
Definition: CD_Loads.cpp:183
Real min(const Real &a_input) noexcept
Get the minimum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:58