libMesh
parallel_bin_sorter.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 // C++ includes
20 #include <algorithm> // is_sorted, lower_bound
21 
22 // Local includes
23 #include "libmesh/libmesh_common.h"
24 #include "libmesh/parallel.h"
25 #include "libmesh/parallel_bin_sorter.h"
26 #include "libmesh/parallel_hilbert.h"
27 #include "libmesh/parallel_histogram.h"
28 #include "libmesh/parallel_conversion_utils.h"
29 
30 namespace libMesh
31 {
32 
33 
34 
35 namespace Parallel {
36 
37 template <typename KeyType, typename IdxType>
39  const std::vector<KeyType> & d) :
40  ParallelObject(comm_in),
41  data(d)
42 {
43  libmesh_assert (std::is_sorted (data.begin(), data.end()));
44 }
45 
46 
47 
48 template <typename KeyType, typename IdxType>
49 void BinSorter<KeyType,IdxType>::binsort (const IdxType nbins,
50  KeyType max,
51  KeyType min)
52 {
53  libmesh_assert_less (min, max);
54 
55  // Build a histogram in parallel from our data.
56  // Use this to create quasi-uniform bins.
57  Parallel::Histogram<KeyType,IdxType> phist (this->comm(), data);
58  phist.make_histogram (nbins*50, max, min);
59  phist.build_histogram ();
60 
61  const std::vector<IdxType> & histogram =
62  phist.get_histogram();
63 
64 
65  // Now we will locate the bin boundaries so
66  // that each bin is roughly equal size
67  {
68  // Find the total size of the data set
69  IdxType local_data_size = cast_int<IdxType>(data.size());
70  IdxType global_data_size = cast_int<IdxType>(local_data_size);
71 
72  this->comm().sum(global_data_size);
73 
74  std::vector<IdxType> target_bin_size (nbins, global_data_size / nbins);
75 
76  // Equally distribute the remainder
77  for (IdxType i=0; i<(global_data_size % nbins); i++)
78  ++target_bin_size[i];
79 
80  // Set the iterators corresponding to the bin boundaries
81  {
82  std::vector<double> bin_bounds (nbins+1);
83  bin_iters.resize (nbins+1, data.begin());
84 
85  // Set the minimum bin boundary iterator
86  bin_iters[0] = data.begin();
87  bin_bounds[0] = Parallel::Utils::to_double(min);
88 
89  // The current location in the histogram
90  IdxType current_histogram_bin = 0;
91 
92  // How much above (+) or below (-) we are from the
93  // target size for the last bin.
94  // Note that when delta is (-) we will
95  // accept a slightly larger size for the next bin,
96  // the goal being to keep the whole mess average
97  int delta = 0;
98 
99  // Set the internal bin boundary iterators
100  for (IdxType b=0; b<nbins; ++b)
101  {
102  // The size of bin b. We want this to
103  // be ~= target_bin_size[b]
104  int current_bin_size = 0;
105 
106  // Step through the histogram until we have the
107  // desired bin size
108  while ((current_bin_size +
109  cast_int<int>(histogram[current_histogram_bin]) +
110  delta) <= cast_int<int>(target_bin_size[b]))
111  {
112  // Don't index out of the histogram!
113  if ((current_histogram_bin+1) == phist.n_bins())
114  break;
115 
116  current_bin_size += histogram[current_histogram_bin++];
117  }
118 
119  delta += current_bin_size - static_cast<int>(target_bin_size[b]);
120 
121  // Set the upper bound of the bin
122  bin_bounds[b+1] = phist.upper_bound (current_histogram_bin);
123  bin_iters[b+1] =
124  std::lower_bound(bin_iters[b], data.end(),
126  }
127 
128  // Just be sure the last boundary points to the right place
129  bin_iters[nbins] = data.end();
130  // This gets destructed here anyway
131  // bin_bounds[nbins] = Parallel::Utils::to_double(max);
132  }
133  }
134 }
135 
136 }
137 
138 
139 // Explicitly instantiate for int, double
140 template class LIBMESH_EXPORT Parallel::BinSorter<int, unsigned int>;
141 template class LIBMESH_EXPORT Parallel::BinSorter<double, unsigned int>;
142 #ifdef LIBMESH_HAVE_LIBHILBERT
144 #endif
145 
146 } // namespace libMesh
BinSorter(const Parallel::Communicator &comm, const std::vector< KeyType > &d)
const std::vector< KeyType > & data
IdxType n_bins() const
The number of bins in the histogram.
The libMesh namespace provides an interface to certain functionality in the library.
void build_histogram()
Build the histogram across all processors and store the result in the input vector hist...
double upper_bound(const IdxType bin) const
bool is_sorted(const std::vector< KeyType > &v)
void make_histogram(const IdxType nbins, KeyType max, KeyType min)
The actual function which sorts the data into nbins.
Perform a parallel sort using a bin-sort method.
libmesh_assert(ctx)
An object whose state is distributed along a set of processors.
static KeyType to_key_type(const double f)
Defines a histogram to be used in parallel in conjunction with a BinSorter.
double to_double(const KeyType &k)
A utility function which converts whatever KeyType is to a double for the histogram bounds...
void binsort(const IdxType nbins, KeyType max, KeyType min)
The actual function which sorts the data into nbins.
const std::vector< IdxType > & get_histogram() const