抱歉,我刚刚开始学习OpenMP,所以我有点困惑。 我正在分析我的分子动力学模拟,在一部分代码中我试图找到水分子(或离子)和蛋白质之间的最近距离。这是非常耗时的部分,因为我有大约500000个原子和大约25000个帧。单CPU需要1周(对于一组计算而言不仅是距离)。
我通过OpenMP将这部分代码更改为并行,但它确实很快但有一点bug;与单CPU代码相比,90%的结果(距离)是正确的,10%是错误的。 这是我的代码中计算最近距离的部分:
...
for (i=0; i< number of frames(25000) )
...
// XP,YP,ZP protein coordinates; malloc allocation in the code
// XI,YI,ZI Sodium molecule coordinates; malloc allocation
// LX,LY,LZ the dimension of simulation box, malloc allocation
// dimI defined as a temporary closest distance, filled with very large constant,
// malloc allocation
// NSOD number of Sodium molecules
// rhos keeping the closest distance for each Sodium for each frame.
…
...int l=0,kk=0;
#pragma omp parallel for shared(XI,YI,ZI,XP,YP,ZP,LX,LY,LZ,qq,dimI,distI,rhos,xmin,ymin,zmin,i) private(kk,l)
for (l=0; l < NSOD; l++){
// this part relocates every thing inside a box with dimension LX*LY*LZ. xmin, ymin and zmin are the boundaries of the box.
if (XI[l]!=0.0 || YI[l]!=0.0 || ZI[l]!=0.0){
if (XI[l] < xmin) XI[l] += ceil((xmin - XI[l])/LX[i-1]) * LX[i-1];
if (XI[l] > xmax) XI[l] -= ceil((XI[l] - xmax)/LX[i-1]) * LX[i-1];
if (YI[l] < ymin) YI[l] += ceil((ymin - YI[l])/LY[i-1]) * LY[i-1];
if (YI[l] > ymax) YI[l] -= ceil((YI[l] - ymax)/LY[i-1]) * LY[i-1];
if (ZI[l] < zmin) ZI[l] += ceil((zmin - ZI[l])/LZ[i-1]) * LZ[i-1];
if (ZI[l] > zmax) ZI[l] -= ceil((ZI[l] - zmax)/LZ[i-1]) * LZ[i-1];
}
for (kk=0; kk<NP; kk++){
if ( ( XP[kk]!=0. || YP[kk]!=0. || ZP[kk]!=0. ) ){
distI[l] = sqrt((XI[l]-XP[kk])*(XI[l]-XP[kk]) + (YI[l]-YP[kk])*(YI[l]-YP[kk]) + (ZI[l]-ZP[kk])*(ZI[l]-ZP[kk]) );
if (distI[l] < dimI[l] ) {
dimI[l] = distI[l];
}
}
}
distI[l] = dimI[l];
rhos[qq][l] = dimI[l];
} #pragma omp barrier ...
请您告诉我并行化后我的代码有什么问题?为什么只有在某些情况下它会给出错误答案而不是所有情况?我非常感谢您的意见和建议。我在linux上使用gcc。 非常感谢,
干杯, Arash的
答案 0 :(得分:2)
处理浮点数时,
可能不是一个好主意if (XI[l]!=0.0 || YI[l]!=0.0 || ZI[l]!=0.0){
相反,你应该与epsilon(一些非常小的数字)进行比较
if (fabs(XI[l]) > epsilon || ...
否则,这可能会导致问题。
答案 1 :(得分:1)
除了安德斯的回答。
除了使用实数进行数学计算之外,由于舍入误差,浮点运算不是关联的。 OpenMp改变了循环评估的顺序,因此结果通常会略有不同。您必须进行灵敏度分析,以确定您对结果的期望精度,并确定您使用(或不使用)OpenMP计算的内容是否在可容忍的范围内。
Numerics是一门艺术。
答案 2 :(得分:0)
我的问题已经偶然解决了,虽然我讨厌这种盲目解决问题;因此我找不到任何解释。
正如我所提到的,我应该找到蛋白质 - 水,蛋白质 - 钠和蛋白质 - 氯化物之间的最近距离。为了完成这项工作,我需要一个临时浮点变量来比较新距离与前一个距离,如果它更小,则替换最小距离。我认为,因为我将在不同的线程上运行它,所以在我的代码中为这个比较定义一维浮点数组更安全。我定义了一维浮点数组dimI[l]
,并在初始化期间用一个非常大的浮点数填充它。
我在我的代码中尝试了openmp命令中的共享和私有变量的组合,最后我用普通的float替换了这个1D数组,并将其定义为私有变量;令人惊讶的是它解决了这个问题,现在它完美无缺。
为什么1D数组不能作为临时变量?似乎定义一维阵列更安全;无论线程数如何,如下kk=0..NSOD
是私有的,而所有其他都是共享变量
Thread 0 T1 T2
l=0 ..10 l=11..20 l=21..30
kk1=0..NSOD kk2=0..NSOD kk3=0..NSOD
XI[l],XP[kk1] XI[l] ,XP[kk2] XI[l],XP[kk3]
distI[l] distI[l] distI[l]
dimI[l] dimI[l] dimI[l]
上述方法有什么问题?
干杯, Arash的