为什么我的空间哈希如此缓慢?

时间:2013-12-20 00:11:24

标签: c++ hash spatial-query particles

为什么我的空间哈希这么慢?我正在研究一种使用平滑粒子流体动力学来模拟滑坡运动的代码。在平滑的颗粒流体动力学中,每个颗粒影响在3“平滑长度”范围内的颗粒。我正在尝试实现空间散列函数,以便快速查找相邻粒子。

对于我的实现,我使用了stl中的“set”数据类型。在每个时间步骤,使用下面的函数将颗粒散列到它们的桶中。 “bucket”是集合的向量,每个网格单元有一个集合(空间域是有限的)。每个粒子由整数标识。

为了查找碰撞,使用下面标题为“getSurroundingParticles”的函数,该函数采用整数(对应于粒子)并返回一个包含粒子的3个支撑长度内的所有网格单元的集合。

问题在于,当粒子数为2000时,这种实现方式实际上非常慢,甚至比仅检查每个粒子对每个其他粒子要慢。我希望有人能在我的实现中发现一个明显的问题我是没看见。

//put each particle into its bucket(s)
void hashParticles()
{
    int grid_cell0;

    cellsWithParticles.clear();

    for(int i = 0; i<N; i++)
    {
        //determine the four grid cells that surround the particle, as well as the grid cell that the particle occupies
        //using the hash function int grid_cell = ( floor(x/cell size) ) + ( floor(y/cell size) )*width
        grid_cell0 = ( floor( (Xnew[i])/cell_spacing) ) + ( floor(Ynew[i]/cell_spacing) )*cell_width;

        //keep track of cells with particles, cellsWithParticles is an unordered set so duplicates will automatically be deleted
        cellsWithParticles.insert(grid_cell0);


        //since each of the hash buckets is an unordered set any duplicates will be deleted
        buckets[grid_cell0].insert(i); 

    }
}

set<int> getSurroundingParticles(int particleOfInterest)
{
     set<int> surroundingParticles;
     int numSurrounding;
     float divisor = (support_length/cell_spacing);
     numSurrounding = ceil( divisor );
     int grid_cell;

     for(int i = -numSurrounding; i <= numSurrounding; i++)
     {
         for(int j = -numSurrounding; j <= numSurrounding; j++)
         {
             grid_cell = (int)( floor( ((Xnew[particleOfInterest])+j*cell_spacing)/cell_spacing) ) + ( floor((Ynew[particleOfInterest]+i*cell_spacing)/cell_spacing) )*cell_width;
             surroundingParticles.insert(buckets[grid_cell].begin(),buckets[grid_cell].end());
         }
     }
    return surroundingParticles;
}

看起来调用getSurroundingParticles:

的代码
set<int> nearbyParticles;
//for each bucket with particles in it
for ( int i = 0; i < N; i++ )
 {
     nearbyParticles = getSurroundingParticles(i);
    //for each particle in the bucket

    for ( std::set<int>::iterator ipoint = nearbyParticles.begin(); ipoint != nearbyParticles.end(); ++ipoint )
    {
        //do stuff to check if the smaller subset of particles collide
    }
}

非常感谢!

1 个答案:

答案 0 :(得分:3)

由于反复创建和填充所有这些集合导致的大量stl堆分配,您的性能会被活跃。如果您对代码进行了分析(比如使用像Sleepy这样的快速简便的非仪器工具),我确信您会发现情况就是如此。您正在使用集合来避免将给定的粒子多次添加到桶中 - 我明白了。如果Duck的建议不能满足您的需求,我认为您可以通过使用预分配的数组或向量来显着提高性能,并通过向添加项目时设置的粒子添加“添加”标记来获得这些容器的唯一性。然后在添加之前检查该标志,并确保在下一个循环之前清除标志。 (如果粒子数是常数,你可以使用专用于存储标志的预分配数组,然后在帧结束时将memset设置为0来非常有效地完成此操作。)

这是基本的想法。如果你决定走这条路并被困在某个地方,我会帮你弄清楚细节。