$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 // C++ includes 00020 #include <algorithm> // std::lower_bound 00021 00022 // Local includes 00023 #include "libmesh/libmesh_common.h" 00024 #include "libmesh/parallel_bin_sorter.h" 00025 #include "libmesh/parallel_histogram.h" 00026 #ifdef LIBMESH_HAVE_LIBHILBERT 00027 # include "hilbert.h" 00028 #endif 00029 #include "libmesh/parallel.h" 00030 #include "libmesh/parallel_conversion_utils.h" 00031 00032 namespace libMesh 00033 { 00034 00035 00036 00037 namespace Parallel { 00038 00039 template <typename KeyType, typename IdxType> 00040 BinSorter<KeyType,IdxType>::BinSorter (const Parallel::Communicator &comm_in, 00041 const std::vector<KeyType>& d) : 00042 ParallelObject(comm_in), 00043 data(d) 00044 { 00045 // Assume (& libmesh_assert) we are working with a sorted range 00046 00047 // Ah... is_sorted is an STL extension! 00048 //libmesh_assert (std::is_sorted (data.begin(), data.end())); 00049 00050 // Home-grown is_sorted 00051 libmesh_assert (Parallel::Utils::is_sorted (data)); 00052 } 00053 00054 00055 00056 template <typename KeyType, typename IdxType> 00057 void BinSorter<KeyType,IdxType>::binsort (const IdxType nbins, 00058 KeyType max, 00059 KeyType min) 00060 { 00061 libmesh_assert_less (min, max); 00062 00063 // Build a histogram in parallel from our data. 00064 // Use this to create quasi-uniform bins. 00065 Parallel::Histogram<KeyType,IdxType> phist (this->comm(), data); 00066 phist.make_histogram (nbins*50, max, min); 00067 phist.build_histogram (); 00068 00069 const std::vector<IdxType>& histogram = 00070 phist.get_histogram(); 00071 00072 00073 // Now we will locate the bin boundaries so 00074 // that each bin is roughly equal size 00075 { 00076 // Find the total size of the data set 00077 IdxType local_data_size = cast_int<IdxType>(data.size()); 00078 IdxType global_data_size = cast_int<IdxType>(local_data_size); 00079 00080 this->comm().sum(global_data_size); 00081 00082 std::vector<IdxType> target_bin_size (nbins, global_data_size / nbins); 00083 00084 // Equally distribute the remainder 00085 for (IdxType i=0; i<(global_data_size % nbins); i++) 00086 ++target_bin_size[i]; 00087 00088 // Set the iterators corresponding to the bin boundaries 00089 { 00090 std::vector<double> bin_bounds (nbins+1); 00091 bin_iters.resize (nbins+1, data.begin()); 00092 00093 // Set the minimum bin boundary iterator 00094 bin_iters[0] = data.begin(); 00095 bin_bounds[0] = Parallel::Utils::to_double(min); 00096 00097 // The current location in the histogram 00098 IdxType current_histogram_bin = 0; 00099 00100 // How much above (+) or below (-) we are from the 00101 // target size for the last bin. 00102 // Note that when delta is (-) we will 00103 // accept a slightly larger size for the next bin, 00104 // the goal being to keep the whole mess average 00105 int delta = 0; 00106 00107 // Set the internal bin boundary iterators 00108 for (IdxType b=0; b<nbins; ++b) 00109 { 00110 // The size of bin b. We want this to 00111 // be ~= target_bin_size[b] 00112 int current_bin_size = 0; 00113 00114 // Step through the histogram until we have the 00115 // desired bin size 00116 while ((current_bin_size + histogram[current_histogram_bin] + delta) <= target_bin_size[b]) 00117 { 00118 // Don't index out of the histogram! 00119 if ((current_histogram_bin+1) == phist.n_bins()) 00120 break; 00121 00122 current_bin_size += histogram[current_histogram_bin++]; 00123 } 00124 00125 delta += current_bin_size - target_bin_size[b]; 00126 00127 // Set the upper bound of the bin 00128 bin_bounds[b+1] = phist.upper_bound (current_histogram_bin); 00129 bin_iters[b+1] = std::lower_bound(bin_iters[b], data.end(), 00130 Parallel::Utils::to_key_type<KeyType>(bin_bounds[b+1])); 00131 } 00132 00133 // Just be sure the last boundary points to the right place 00134 bin_iters[nbins] = data.end(); 00135 // This gets destructed here anyway 00136 // bin_bounds[nbins] = Parallel::Utils::to_double(max); 00137 } 00138 } 00139 } 00140 00141 } 00142 00143 00144 // Explicitly instantiate for int, double 00145 template class Parallel::BinSorter<int, unsigned int>; 00146 template class Parallel::BinSorter<double, unsigned int>; 00147 #ifdef LIBMESH_HAVE_LIBHILBERT 00148 template class Parallel::BinSorter<Hilbert::HilbertIndices, unsigned int>; 00149 #endif 00150 00151 } // namespace libMesh