带有重量的推力直方图

时间:2015-07-22 14:43:27

标签: cuda gpu histogram thrust

我想计算网格上的粒子密度。因此,我有一个包含每个粒子的cellID的向量,以及一个给定mass的向量,它不必是统一的。

我从Thrust获取非稀疏示例来计算粒子的直方图。 然而,为了计算密度,我需要包括每个粒子的权重,而不是简单地将每个单元格的粒子数加起来,即我对所有rho[i] = sum W[j]感兴趣的所有j感兴趣cellID[j]=i(可能没有必要解释,因为每个人都知道)。

使用Thrust实现此功能并不适用于我。我也尝试使用CUDA内核和thrust_raw_pointer_cast,但我也没有成功。

修改

这是一个最小的工作示例,它应该通过CUDA 6.5下的nvcc file.cu进行编译并安装Thrust。

#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/copy.h>
#include <thrust/binary_search.h>
#include <thrust/adjacent_difference.h>


// Predicate
struct is_out_of_bounds {
    __host__ __device__ bool operator()(int i) {

        return (i < 0); // out of bounds elements have negative id;
    }
};



// cf.: https://code.google.com/p/thrust/source/browse/examples/histogram.cu, but modified
template<typename T1, typename T2>
void computeHistogram(const T1& input, T2& histogram) {
    typedef typename T1::value_type ValueType; // input value type
    typedef typename T2::value_type IndexType; // histogram index type

    // copy input data (could be skipped if input is allowed to be modified)
    thrust::device_vector<ValueType> data(input);

    // sort data to bring equal elements together
    thrust::sort(data.begin(), data.end());


    // there are elements that we don't want to count, those have ID -1;
    data.erase(thrust::remove_if(data.begin(), data.end(), is_out_of_bounds()),data.end());



    // number of histogram bins is equal to the maximum value plus one
    IndexType num_bins = histogram.size();

    // find the end of each bin of values
    thrust::counting_iterator<IndexType> search_begin(0);
    thrust::upper_bound(data.begin(), data.end(), search_begin,
            search_begin + num_bins, histogram.begin());

    // compute the histogram by taking differences of the cumulative histogram
    thrust::adjacent_difference(histogram.begin(), histogram.end(),
            histogram.begin());

}




int main(void) {



    thrust::device_vector<int> cellID(5);
    cellID[0] = -1; cellID[1] = 1; cellID[2] = 0; cellID[3] = 2; cellID[4]=1;
    thrust::device_vector<float> mass(5);
    mass[0] = .5; mass[1] = 1.0; mass[2] = 2.0; mass[3] = 3.0; mass[4] = 4.0;

    thrust::device_vector<int> histogram(3);
    thrust::device_vector<float> density(3);


    computeHistogram(cellID,histogram);

    std::cout<<"\nHistogram:\n";

    thrust::copy(histogram.begin(), histogram.end(),
                    std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    // this will print: " Histogram 1 2 1 " 
    // meaning one element with ID 0, two elements with ID 1 
    // and one element with ID 2

    /* here is what I am unable to implement:
     *
     *
     * computeDensity(cellID,mass,density);
     *
     * print(density):        2.0 5.0 3.0
     *
     *
     */
}

我希望文件末尾的评论也能说明计算密度的含义。如果有任何问题,请随时询问。谢谢!

理解我的问题似乎仍有问题,我很抱歉!因此我添加了一些图片。 考虑第一张照片。根据我的理解,直方图只是每个网格单元的粒子数。在这种情况下,直方图将是大小为36的数组,因为有36个单元格。此外,向量中将存在大量零条目,因为例如在左上角几乎没有单元格包含粒子。这就是我在代码中已有的内容。 enter image description here

现在考虑稍微复杂的情况。这里每个粒子具有不同的质量,由图中的不同大小表示。为了计算密度,我不能仅添加每个单元格的粒子数,但我必须为每个单元格添加所有粒子的质量。这是我无法实现的。 enter image description here

1 个答案:

答案 0 :(得分:4)

您在示例中描述的内容看起来不像直方图,而是分段缩减。

以下示例代码使用thrust::reduce_by_key来总结同一单元格中的粒子质量:

<强> density.cu

#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/reduce.h>
#include <thrust/copy.h>
#include <thrust/scatter.h>
#include <iostream>

#define PRINTER(name) print(#name, (name))
template <template <typename...> class V, typename T, typename ...Args>
void print(const char* name, const V<T,Args...> & v)
{
    std::cout << name << ":\t\t";
    thrust::copy(v.begin(), v.end(), std::ostream_iterator<T>(std::cout, "\t"));
    std::cout << std::endl << std::endl;
}

int main()
{

    const int particle_count = 5;
    const int cell_count  = 10;

    thrust::device_vector<int> cellID(particle_count);
    cellID[0] = -1; cellID[1] = 1; cellID[2] = 0; cellID[3] = 2; cellID[4]=1;
    thrust::device_vector<float> mass(particle_count);
    mass[0] = .5; mass[1] = 1.0; mass[2] = 2.0; mass[3] = 3.0; mass[4] = 4.0;

    std::cout << "input data" << std::endl;
    PRINTER(cellID);
    PRINTER(mass);

    thrust::sort_by_key(cellID. begin(), cellID.end(), mass.begin());

    std::cout << "after sort_by_key" << std::endl;
    PRINTER(cellID);
    PRINTER(mass);

    thrust::device_vector<int> reduced_cellID(particle_count);
    thrust::device_vector<float> density(particle_count);

    int new_size = thrust::reduce_by_key(cellID. begin(), cellID.end(),
                                         mass.begin(),
                                         reduced_cellID.begin(),
                                         density.begin()
                                        ).second - density.begin();                                        
    if (reduced_cellID[0] == -1)
    {
        density.erase(density.begin());
        reduced_cellID.erase(reduced_cellID.begin());
        new_size--;
    }
    density.resize(new_size);
    reduced_cellID.resize(new_size);

    std::cout << "after reduce_by_key" << std::endl;

    PRINTER(density);
    PRINTER(reduced_cellID);

    thrust::device_vector<float> final_density(cell_count);
    thrust::scatter(density.begin(), density.end(), reduced_cellID.begin(), final_density.begin());
    PRINTER(final_density);
}

使用

进行编译
nvcc -std=c++11 density.cu -o density

<强>输出

input data
cellID:     -1   1  0   2   1   

mass:       0.5  1  2   3   4   

after sort_by_key
cellID:     -1   0  1   1   2   

mass:       0.5  2  1   4   3   

after reduce_by_key
density:        2   5   3   

reduced_cellID: 0   1   2   

final_density:  2   5   3   0   0   0   0   0   0   0