【SPH】邻域搜索中的紧凑哈希(compact hash)算法讲解

引子:为什么会提出紧凑哈希?

常规的Grid-Based邻域搜索我们之前讲过:http://t.csdn.cn/Ytwuy

常规方法有一个缺陷:那就是占用内存过高。

想象一下:你要存储两个庞大的二维数组。

第一个数组记录了每个网格里都有哪些粒子。我们姑且称为网格内粒子列表。particleInCellList
第二个数组记录了每个粒子的邻域都有哪些粒子。我们姑且称为邻域列表。neighborList

这两个列表的占用内存都很多。

第一个列表,假设每个网格最多有100个粒子,那么就需要网格数量*100 个int类型字节的内存。
第二个列表,假设每个粒子最多有100个邻居,那么就需要粒子数量*100 个int类型字节的内存。

实际上,在3D模拟中粒子数量要比网格数量少得多。这是因为3D网格有类似“维度爆炸”的问题。假设2D网格为100*100,也就是横向100个网格,纵向100个网格,那么3D场景就变为了100*100*100个网格。这就意味着网格数量增大了100倍。这是非常大的数量级。

因此实际上内存的主要开销在于第一个列表。紧凑哈希表也是针对节约第一个列表的内存而发明的算法,它对邻域列表(第二个列表)的内存没有任何影响

算法原理讲解

该算法实际上非常简单。

怎么节约网格内存呢?那么就不要那么浪费网格就好了!也就是把用不到的网格不去占用内存

你可能会立马想到稀疏数据结构,但是紧凑哈希是比稀疏数据结构更为简单的算法。

我们先要理解SPH中的网格的本质:在SPH中的网格,实际上只是一个辅助工具。它是用来帮助粒子建立拓扑关系的。说人话,就是它是用来帮粒子定位自己在哪的。

什么叫拓扑?北航在中国北京市海淀区学院路37号。这就是拓扑。我不知道北航的经纬度,但是我能够通过这样的地址找到北航。我会去先找中国在哪,再找北京在哪,然后找海淀区在哪,学院路在哪,最后找到北航在哪。所谓的拓扑,就是你和别人的相对关系,或者说就是相对位置。你的绝对位置可以变,但是相对位置没变,那么拓扑就没变。所以,我们建立网格的作用,就是给粒子一个家。用一个个小格子,把粒子的空间位置描述出来。粒子所在的网格,就是它所在的街道,或者说,它的门牌号。

既然它所在的网格本身只是一个用来指示地址的门牌号,那么我们完全不用遵循几何中的真实位置。

我们假设某个网格的索引为

c = ( i , j , k ) \mathbf{c} = (i, j, k) c=(i,j,k)

有用的只是i,j,k这三个索引,而不是i, j , k这三个索引的几何意义。所以我们完全可以将i,j,k经过一个奇怪的运算,得到一个数。我们只需要尽量保证每套索引值得到的是不同的数。计算方法如下:
在这里插入图片描述

这就是所谓的哈希函数。哈希函数的意义就是算出一个与众不同的数字。其中p1, p2, p3都是很大的质数。 XOR代表异或, mod代表取余数。 m是你给定的哈希表的大小。

为什么会给定一个m呢?因为当你剥离掉ijk的几何意义,这个表的大小就随意确定了。你想给定多少,就给定多少。但是实际上,要是给得太小,会造成哈希冲突,也就是不同的ijk值得到了相同的哈希值。也就是可能本来相距很远的粒子,被强行放到一个网格里了。

这个算法最早是由Ihmsen等人提出来的,他建议m的取值为2倍的粒子数。

到这里你或许还会有一个疑问:

怎么根据哈希值还原回网格索引呢?

答案是:不需要还原。

你又会问:那我怎么确定网格之间的拓扑关系呢,或者说怎么知道这个网格的上下左右邻居都是谁?

答案是:计算的时候,你仍然采用原始的索引值,哈希表对原本的网格空间结构没有任何破坏,它只是用来优化存储的。

比如说:你现在的网格编号是a,b,c。你想知道它头顶的网格是谁。假设y坐标是朝上的,那么它的顶部的网格就是(a, b+1, c)。在你计算的时候,仍然使用(a, b+1, c)。 但是你并不一定需要开辟一块对应网格(a, b+1, c)的内存。 而是先计算(a, b+1, c)的哈希值,鬼知道这个哈希值是多少,然后你用这个哈希值作为编号存到哈希表的一个元素里。这个哈希表的大小是确定的,就是你给定的m。假如哈希表大小不够用了,它就会自动循环(这也是为什么哈希函数最后除以m取余数)。

算法的额外开销

所有的开销就是每个使用的网格要计算一次哈希函数。这就是节约了内存所造成的时间的额外开销。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值