如何加速Madelung Constant的三维和?

时间:2016-09-29 18:30:03

标签: python performance numpy vectorization

对于我的计算物理课,我们必须计算NaCl的Madelung Constant。我执行此操作的代码使用三个嵌套for循环,因此运行速度非常慢。我想知道是否有办法使用数组或其他方法来提高计算速度。谢谢

from math import sqrt 
l= int(input("The lattice size is :"))
M = 0.0
for i in range(-L,L+1):
    for j in range(-L,L+1):
       for k in range(-L,L+1):
           if not (i==j==k==0):
              M += ((-1)**(i+j+k+1))/sqrt(i*i +j*j +k*k)

print("The Madelung constant for NaCl with lattice size",l,"is",M)

2 个答案:

答案 0 :(得分:2)

这是一种使用np.ogrid开放网格而不是创建实际网格的方法,基于this other post必须非常高效 -

# Create open meshes for efficiency purposes
I,J,K = np.ogrid[-L:L+1,-L:L+1,-L:L+1]

# Perform all computations using those open meshes in a vectorized manner
all_vals = ((-1)**(I+J+K+1))/np.sqrt(I**2 +J**2+ K**2)

# Corresponding to "not (i==j==k==0)", which would be satisfied by 
# just one combination and that will occur at location (L,L,L), 
# let's set it as zero as a means to sum later on without adding for that elem
all_vals[L,L,L] = 0
M_out = all_vals.sum()

答案 1 :(得分:1)

由于您在评论中指出您可以使用numpy,我建议您这样做。您可以为整数构建一个3d网格,并同时计算每个项,从而对计算进行矢量化。您只需要注意每个整数为0的单数情况,例如使用numpy.where

import numpy as np

ran = np.arange(-L,L+1)
i,j,k = np.meshgrid(ran,ran,ran)
M = np.where((i!=0) | (j!=0) | (k!=0),
             (-1)**(i+j+k+1)/np.sqrt(i**2+j**2+k**2),
             0).sum()

ran是一个numpy数组,其元素与range()中的元素相同(如果转换为python 3中的列表)。 meshgrid然后构造三个3d数组,它们一起跨越需要执行总和的3d空间。

请注意,对于大型域,此方法需要更高的内存。这是矢量化的一个因素:你可以节省CPU时间,但代价是增加内存需求。