使用Fortran Do Loops正确使用openMP

时间:2014-02-05 17:19:24

标签: loops fortran openmp

我是编码Fortran的初学者,仍然在主要的学习过程中。 我在Fortran中为FE Simulation编写了一个程序。但表现仍然太慢。 因此,我首先实现了稀疏矩阵,这很好地加快了代码的速度。但它仍然不够快。 这就是为什么我认为使用openMP和并行化部分代码会非常有用。 但是当我尝试实现openMP的命令时,要么代码运行得比以前慢(我假设开销太大),要么它不再正确执行。

在即将到来的部分代码之前,有一个do循环用于时间步进。 变量nE非常高,可以说高达50K或更高。必须为每个时间步计算该循环。 它是我想要并行化的代码的一部分:

!$omp parallel
!$omp do private(v, b, N_loc, c, n, vertices, a1, a2, a3, b1, b2, b3, etc...)
   do v = 1, nE
    do b = 1, 4
      N_loc(1,b) = umesh_elt(v,b)  !Extracting node numbers
      c(1,b) = c_s(N_loc(1,b),1)   !Extracting values
      n(1,b) = n_s(N_loc(1,b),1)
      vertices(b,1) = umesh_co(N_loc(1,b),1) !Extracting coordinates
      vertices(b,2) = umesh_co(N_loc(1,b),2) !Extracting coordinates
     end do  



    a1 = 0.25*(-vertices(1,1)+vertices(2,1)+vertices(3,1)-vertices(4,1))
    a2 = 0.25*(-vertices(1,1)-vertices(2,1)+vertices(3,1)+vertices(4,1))
    a3 = 0.25*(+vertices(1,1)-vertices(2,1)+vertices(3,1)-vertices(4,1))
    b1 = 0.25*(-vertices(1,2)+vertices(2,2)+vertices(3,2)-vertices(4,2))
    b2 = 0.25*(-vertices(1,2)-vertices(2,2)+vertices(3,2)+vertices(4,2))
    b3 = 0.25*(+vertices(1,2)-vertices(2,2)+vertices(3,2)-vertices(4,2))


     do j = 1, nGauss
       J_c(1,1) = a1 + a3*QuadRuleX(j,2)
       J_c(1,2) = a2 + a3*QuadRuleX(j,1)
       J_c(2,1) = b1 + b3*QuadRuleX(j,2)
       J_c(2,2) = b2 + b3*QuadRuleX(j,1)

       J_det(j,1) = J_c(1,1)*J_c(2,2) - J_c(1,2)*J_c(2,1)
     end do

     do k = 1, 4
       y(k,1) = 0.0
       do z = 1, nGauss
          r = QuadRuleX(z,1)
          t = QuadRuleX(z,2)

          if (k == 1) then
             phi = 0.25*(r-1)*(t-1)
          else if (k == 2) then
             phi = -0.25*(r+1)*(t-1)
          else if (k == 3) then
             phi = 0.25*(r+1)*(t+1) 
          else if (k == 4) then
             phi = -0.25*(r-1)*(t+1)
          endif


          phi_1 = 0.25*(r-1)*(t-1)
          phi_2 = -0.25*(r+1)*(t-1)
          phi_3 = 0.25*(r+1)*(t+1)
          phi_4 = -0.25*(r-1)*(t+1)


          c_h = c(1,1)*phi_1+c(1,2)*phi_2+c(1,3)*phi_3+c(1,4)*phi_4 
          n_h = n(1,1)*phi_1+n(1,2)*phi_2+n(1,3)*phi_3+n(1,4)*phi_4
          y(k,1)=(phi*((((hi-1)*c_h+hi)/(2*(hi-1)*c_h+1))*n_h*    (2-n_h)-n_h))*J_det(z,1)*QuadRuleW(z,1)+y(k,1)
        end do
     end do

    S(z1,1) = y(1,1)+S(z1,1)
    S(z2,1) = y(2,1)+S(z2,1)
    S(z3,1) = y(3,1)+S(z3,1)
    S(z4,1) = y(4,1)+S(z4,1)

   end do

!$omp end do
!omp end parallel

在这段代码之后,有一个时间步骤结束循环和一些if子句来停止模拟,如果发生了特定的事情。

我用选项编译它     ifort -mkl -openmp NAME.f90 当试图用它来执行时     时间./a.out 代码无法正常运行,程序启动和停止没有任何错误。

我认为我基本上做错了,就像我没有正确理解如何正确设置那些使用openMP做的循环。有人有什么建议吗?

感谢任何帮助,非常感谢! ·阿尔

1 个答案:

答案 0 :(得分:0)

这对评论来说有点太长了,所以我会将其作为答案发布......

如果没有整个PRIVATE()陈述,很难说出什么是全局的,什么是本地的......

乍一看,只有S(,1) = y(,1)+S(,1)行似乎很重要。你能确保没有两个线程同时尝试访问同一个S(,1)吗?从我看到的z1 - z4设置之外的循环 - 所以我的猜测是它们对于所有线程都是相同的并且发生了race condition

如果它们是相同的,这就像reduction操作一样。作为一个快速修复(仅用于调试,除非你真的需要它,否则不要使用它)你可以将该代码阻塞到critical部分。