Skip to content

Instantly share code, notes, and snippets.

@yangyushi
Created November 2, 2020 14:36
Show Gist options
  • Save yangyushi/1d031dea79f1be43d3cafc6079e3fe45 to your computer and use it in GitHub Desktop.
Save yangyushi/1d031dea79f1be43d3cafc6079e3fe45 to your computer and use it in GitHub Desktop.
Different ways to get pairwise distance in cubic box with PBC in Python
"""
Different functions to get pairwise distance in cubic box with PBC
Args:
positions: the positions of particles, shape (N, dim)
box (int or float): the size of the box
Return:
np.ndarray: the pair-wise distances, shape (N, N)
"""
import numpy as np
from scipy.spatial.distance import pdist, squareform
def get_pdist_pbc_v1(positions, box):
pos_in_pbc = positions % box
pair_distances = np.empty((N, N))
for i, p1 in enumerate(pos_in_pbc):
for j, p2 in enumerate(pos_in_pbc):
dist_nd_sq = 0
for d in range(dim):
dist_1d = abs(p2[d] - p1[d])
if dist_1d > (box / 2): # check if d_ij > box_size / 2
dist_1d = box - dist_1d
dist_nd_sq += dist_1d ** 2
pair_distances[i, j] = dist_nd_sq
return np.sqrt(pair_distances)
def get_pdist_pbc_v2(positions, box):
pos_in_pbc = positions % box
dist_nd_sq = np.zeros(N * (N - 1) // 2)
for d in range(dim):
pos_1d = pos_in_pbc[:, d][:, np.newaxis]
dist_1d = pdist(pos_1d)
dist_1d[dist_1d > box * 0.5] -= box
dist_nd_sq += dist_1d ** 2
dist_nd = squareform(np.sqrt(dist_nd_sq))
return dist_nd
def get_pdist_pbc_v3(positions, box):
pos_in_box = positions.T / box
pair_shift = pos_in_box[:, :, np.newaxis] - pos_in_box[:, np.newaxis, :]
pair_shift = pair_shift - np.rint(pair_shift)
return np.linalg.norm(pair_shift, axis=0) * box
if __name__ == "__main__":
from time import time
N, dim, box = 1000, 3, 2
positions = np.random.uniform(0, 1, (N, dim))
t0 = time()
pd1 = get_pdist_pbc_v1(positions, box)
print(f"{time() - t0:.4f} s spent by method 1")
t0 = time()
pd2 = get_pdist_pbc_v2(positions, box)
print(f"{time() - t0:.4f} s spent by method 2")
t0 = time()
pd3 = get_pdist_pbc_v3(positions, box)
print(f"{time() - t0:.4f} s spent by method 3")
eq12 = np.allclose(pd1, pd2)
eq13 = np.allclose(pd1, pd3)
print("Getting identical results?", eq12 and eq13)
@yangyushi
Copy link
Author

This is what I got

3.8901 s spent by method 1
0.0230 s spent by method 2
0.0747 s spent by method 3
Getting identical results? True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment