我正在重写分子动力学时间序列的分析代码。由于必须分析大量的时间步长(每次模拟运行 150,000 个),因此我的代码尽可能快非常重要。
旧代码非常慢(实际上它需要的时间是我的代码的 300 到 500 倍),因为它是为分析几千个 PDB 文件而编写的,而不是一堆充满不同模拟(大约 60 个),每个模拟都有 150 000 个时间步长。我知道在这种情况下,C 或 Fortran 将是瑞士军刀,但我对 c 的经验是......
因此,我正在尝试为我的 python 代码尽可能多地使用 numpy/scipy 例程。因为我有一个使用 mkl 加速分发 anaconda 的许可证,所以这是一个非常重要的加速。
现在我面临一个问题,我希望我能以一种你理解我的意思的方式来解释它。
我有三个数组,每个数组的形状为 (n, 3, 20)。第一行是我的肽的所有残余物,通常在23到31左右。第二行是按 xyz 顺序排列的坐标,第三行是一些特定的时间步长。
现在我正在计算每个时间步的每个残差的扭转。 我的形状为 (n,3,1) 的数组情况的代码是:
def fast_torsion(d1, d2, d3):
tt = dot(d1, np.cross(d2, d3))
tb = dot(d1, d1) * dot(d2, d2)
torsion = np.zeros([len(d1), 1])
for i in xrange(len(d1)):
if tb[i] != 0:
torsion[i] = tt[i]/tb[i]
return torsion
现在我尝试对具有扩展的第三轴的数组使用相同的代码,但与使用 for 循环的原始慢代码相比,交叉乘积函数产生了错误的值。我用我的大数组尝试了这段代码,它比 for 循环解决方案快大约 10 到 20 倍,比旧代码快大约 200 倍。
我正在尝试的是 np.cross() 只计算第二个 (xyz) 轴上的交叉乘积,并在其他两个轴上迭代。在短第三轴的情况下,它工作正常,但对于大数组,它只能在第一个时间步长工作。我也尝试了轴设置,但我没有机会。
如果这是我问题的唯一解决方案,我也可以使用 Cython 或 numba。
附言对不起我的英语,我希望你能理解一切。
np.cross
具有axisa
、axisb
和axisc
关键字参数,用于选择输入和输出参数中要交叉乘法的向量的位置。我想你想使用:
np.cross(d2, d3, axisa=1, axisb=1, axisc=1)
如果不包括 axisc=1
,乘法的结果将在输出数组的末尾。
此外,还可以通过执行以下操作来避免显式循环torsion
数组:
torsion = np.zeros((len(d1), 1)
idx = (tb !=0)
torsion[idx] = tt[idx] / tb[idx]