parallel_bin_sorter.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 std::vector<KeyType>& d) : 00041 data(d) 00042 { 00043 // Assume (& libmesh_assert) we are working with a sorted range 00044 00045 // Ah... is_sorted is an STL extension! 00046 //libmesh_assert (std::is_sorted (data.begin(), data.end())); 00047 00048 // Home-grown is_sorted 00049 libmesh_assert (Parallel::Utils::is_sorted (data)); 00050 } 00051 00052 00053 00054 template <typename KeyType, typename IdxType> 00055 void BinSorter<KeyType,IdxType>::binsort (const IdxType nbins, 00056 KeyType max, 00057 KeyType min) 00058 { 00059 libmesh_assert_less (min, max); 00060 00061 // Build a histogram in parallel from our data. 00062 // Use this to create quasi-uniform bins. 00063 Parallel::Histogram<KeyType,IdxType> phist (data); 00064 phist.make_histogram (nbins*50, max, min); 00065 phist.build_histogram (); 00066 00067 const std::vector<IdxType>& histogram = 00068 phist.get_histogram(); 00069 00070 00071 // Now we will locate the bin boundaries so 00072 // that each bin is roughly equal size 00073 { 00074 // Find the total size of the data set 00075 IdxType local_data_size = libmesh_cast_int<IdxType>(data.size()); 00076 IdxType global_data_size = libmesh_cast_int<IdxType>(local_data_size); 00077 00078 CommWorld.sum(global_data_size); 00079 00080 std::vector<IdxType> target_bin_size (nbins, global_data_size / nbins); 00081 00082 // Equally distribute the remainder 00083 for (IdxType i=0; i<(global_data_size % nbins); i++) 00084 ++target_bin_size[i]; 00085 00086 // Set the iterators corresponding to the bin boundaries 00087 { 00088 std::vector<double> bin_bounds (nbins+1); 00089 bin_iters.resize (nbins+1, data.begin()); 00090 00091 // Set the minimum bin boundary iterator 00092 bin_iters[0] = data.begin(); 00093 bin_bounds[0] = Parallel::Utils::to_double(min); 00094 00095 // The current location in the histogram 00096 IdxType current_histogram_bin = 0; 00097 00098 // How much above (+) or below (-) we are from the 00099 // target size for the last bin. 00100 // Note that when delta is (-) we will 00101 // accept a slightly larger size for the next bin, 00102 // the goal being to keep the whole mess average 00103 int delta = 0; 00104 00105 // Set the internal bin boundary iterators 00106 for (IdxType b=0; b<nbins; ++b) 00107 { 00108 // The size of bin b. We want this to 00109 // be ~= target_bin_size[b] 00110 int current_bin_size = 0; 00111 00112 // Step through the histogram until we have the 00113 // desired bin size 00114 while ((current_bin_size + histogram[current_histogram_bin] + delta) <= target_bin_size[b]) 00115 { 00116 // Don't index out of the histogram! 00117 if ((current_histogram_bin+1) == phist.n_bins()) 00118 break; 00119 00120 current_bin_size += histogram[current_histogram_bin++]; 00121 } 00122 00123 delta += current_bin_size - target_bin_size[b]; 00124 00125 // Set the upper bound of the bin 00126 bin_bounds[b+1] = phist.upper_bound (current_histogram_bin); 00127 bin_iters[b+1] = std::lower_bound(bin_iters[b], data.end(), 00128 Parallel::Utils::to_key_type<KeyType>(bin_bounds[b+1])); 00129 } 00130 00131 // Just be sure the last boundaries point to the right place 00132 bin_iters[nbins] = data.end(); 00133 bin_bounds[nbins] = Parallel::Utils::to_double(max); 00134 } 00135 } 00136 } 00137 00138 } 00139 00140 00141 // Explicitly instantiate for int, double 00142 template class Parallel::BinSorter<int, unsigned int>; 00143 template class Parallel::BinSorter<double, unsigned int>; 00144 #ifdef LIBMESH_HAVE_LIBHILBERT 00145 template class Parallel::BinSorter<Hilbert::HilbertIndices, unsigned int>; 00146 #endif 00147 00148 } // namespace libMesh 00149
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: