Cell Linked List
概念
🌟cell linked list算法是一种高效的邻域搜索算法,广泛应用于分子动力学(Molecular Dynamics, MD)模拟中,用于计算原子之间的相互作用力。该算法通过将模拟区域划分成多个小的立方体单元(cells),并使用链表来组织每个单元中的原子数据,从而加速邻域搜索过程。
⭐️过程:通常在有限的截止距离𝑟𝑐内计算相互作用。一个原子只与该截止距离内的原子相互作用,这极大地减少了需要计算的相互作用数量。Cell Linked List通过将模拟盒子分割成更小的单元,并且仅考虑每个单元及其相邻单元内的相互作用。
Cell Linked List步骤
-
划分模拟区域:将整个模拟区域划分为一系列小的立方体单元(cells)。这些单元的边长通常选择为原子相互作用力的截断半径(cutoff radius) 𝑟𝑐 的值,这样可以确保每个单元只需要与其周围的单元进行相互作用计算。
-
链表构建:
-
定义数据结构:
// 数据结构定义 float4* coords; // 存储原子坐标的数组 int* cell_starts; // 存储每个单元链表起始索引的数组 int* cell_ends; // 存储每个单元链表结束索引的数组 int* cell_list; // 存储链表中每个原子索引的数组
-
构建细胞链表:每个线程处理一个原子,计算其所在的单元索引。使用原子操作更新单元结束索引,记录原子在细胞链表中的位置。
__global__ void build_cell_list(int n_atoms, float4* coords, int* cell_starts, int* cell_ends, int* cell_list, int3 n_cells, float3 box_size, float cell_size) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < n_atoms) { float4 coord = coords[i]; int3 cell_idx; cell_idx.x = floorf(coord.x / cell_size); cell_idx.y = floorf(coord.y / cell_size); cell_idx.z = floorf(coord.z / cell_size); cell_idx.x = (cell_idx.x + n_cells.x) % n_cells.x; cell_idx.y = (cell_idx.y + n_cells.y) % n_cells.y; cell_idx.z = (cell_idx.z + n_cells.z) % n_cells.z; int cell_idx_flat = cell_idx.x + cell_idx.y * n_cells.x + cell_idx.z * n_cells.x * n_cells.y; int cell_start = atomicAdd(&cell_ends[cell_idx_flat], 1); cell_list[cell_start] = i; } }
-
-
计算相互作用:每个线程处理一个原子,遍历其所在单元及相邻单元中的原子。如果两个原子之间的距离小于截止距离,则计算并更新它们之间的相互作用力。
__global__ void compute_interactions(int n_atoms, float4* coords, float4* forces, int* cell_starts, int* cell_ends, int* cell_list, int3 n_cells, float3 box_size, float cell_size, float cutoff_squared) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < n_atoms) { float4 coord_i = coords[i]; float4 force_i = make_float4(0.0f, 0.0f, 0.0f, 0.0f); int3 cell_idx; cell_idx.x = floorf(coord_i.x / cell_size); cell_idx.y = floorf(coord_i.y / cell_size); cell_idx.z = floorf(coord_i.z / cell_size); cell_idx.x = (cell_idx.x + n_cells.x) % n_cells.x; cell_idx.y = (cell_idx.y + n_cells.y) % n_cells.y; cell_idx.z = (cell_idx.z + n_cells.z) % n_cells.z; for (int dx = -1; dx <= 1; ++dx) { for (int dy = -1; dy <= 1; ++dy) { for (int dz = -1; dz <= 1; ++dz) { int3 neighbor_idx = make_int3( (cell_idx.x + dx + n_cells.x) % n_cells.x,