交替拆分运算符方法

时间:2012-12-02 22:44:45

标签: algorithm fortran90

以下内容来自一维水电代码(使用汉密尔顿方法,使用Strang分裂来演化变量p& q),这是我本周末为一些介绍性研究工作掀起的

    do
       if(num==1) then
          p2   = p(i) - (dt/2.)*q(i)/abs(q(i))   ! half step in P
          q(i) = q(i) + dt*p2                    ! full step in Q
          p(i) = p2 - (dt/2.)*q(i)/abs(q(i))     ! half step in P
          num=2
       elseif(num==2) then
          q2   = q(i) + (dt/2.)*p(i)             ! half step in Q
          p(i) = p(i) - dt*q2/abs(q2)            ! full step in P
          q(i) = q(i) + (dt/2.)*p(i)             ! half step in Q
          num=1
       endif
       t = t+dt
       if(t >= tend) exit
    enddo

是否有更有效的方法在两种算法之间交替(这是减少虚假数据所必需的),而不是我在这里?如果重要,p和q每个大约有100,000个单元(代码是并行化的)。

编辑:我添加了代码的do - 循环部分,而不仅仅是if-elseif部分。在endif之后还有一个写入文件部分,但我不认为这对于潜在的优化是必要的。

1 个答案:

答案 0 :(得分:2)

我会重写代码以完全删除if/then/else

integer :: num_steps, k
logical :: one_more

num_steps = tend/dt
one_more = (mod(num_steps,2) /= 0)

do k = 1,num_steps/2
   p2   = p(i) - (dt/2.)*q(i)/abs(q(i))   ! half step in P
   q(i) = q(i) + dt*p2                    ! full step in Q
   p(i) = p2 - (dt/2.)*q(i)/abs(q(i))     ! half step in P
   ! output
   q2   = q(i) + (dt/2.)*p(i)             ! half step in Q
   p(i) = p(i) - dt*q2/abs(q2)            ! full step in P
   q(i) = q(i) + (dt/2.)*p(i)             ! half step in Q
   ! output
enddo

if (one_more) then
   p2   = p(i) - (dt/2.)*q(i)/abs(q(i))   ! half step in P
   q(i) = q(i) + dt*p2                    ! full step in Q
   p(i) = p2 - (dt/2.)*q(i)/abs(q(i))     ! half step in P
   ! output
endif

如果您需要输出操作的当前时间,您仍然可以在循环中的每个步骤之后使用t = t+dt语句。