if 语句来确定稳态

我下面的代码正确地解决了函数 u(x,t) 的一维热方程。我现在想找到稳态解,该解不再随时间变化,因此它应该满足 u(t+1)-u(t) = 0。找到稳态解的最有效方法是什么? 我在下面展示了三种不同的尝试,但我不确定它们是否真的在做我想做的。第一个和第三个语法正确,第二个方法由于 if 语句有语法错误。由于 if 结构的变化,每种方法都不同。

方法一:

program parabolic1
  integer, parameter :: n = 10, m = 20 
  real, parameter :: h = 0.1, k = 0.005 !step sizes
  real, dimension (0:n) :: u,v
  integer:: i,j
  real::pi,pi2
  
  u(0) = 0.0; v(0) = 0.0; u(n) = 0.0; v(n) =0.0
  pi = 4.0*atan(1.0)    
  pi2 = pi*pi 
  
  do i=1, n-1
     u(i) = sin( pi*real(i)*h)
  end do
  
  do j = 1,m 

    do i = 1, n-1
       v(i) = 0.5*(u(i-1)+u(i+1))
    end do 
    t = real(j)*k  !increment in time, now check for steady-state

    !steady-state check: this checks the solutions at every space point  which I don't think is correct.
    do i = 1,n-1
       if ( v(i) - u(i) .LT. 1.0e-7 ) then
       print*, 'steady-state condition reached'
       exit 
       end if
    end do

    do i = 1, n-1 !updating solution
       u(i) = v(i)       
    end do 

  end do 
end program parabolic1

方法二:

program parabolic1
  integer, parameter :: n = 10, m = 20 
  real, parameter :: h = 0.1, k = 0.005 !step sizes
  real, dimension (0:n) :: u,v
  integer:: i,j
  real::pi,pi2
  
  u(0) = 0.0; v(0) = 0.0; u(n) = 0.0; v(n) =0.0
  pi = 4.0*atan(1.0)    
  pi2 = pi*pi 
  
  do i=1, n-1
     u(i) = sin( pi*real(i)*h)
  end do
  
  do j = 1,m 

    do i = 1, n-1
       v(i) = 0.5*(u(i-1)+u(i+1))
    end do 
    t = real(j)*k  !increment in time, now check for steady-state

    !steady-state check: (This gives an error message since the if statement doesn't have a logical scalar expression, but I want to compare the full arrays v and u as shown.
       if ( v - u .LT. 1.0e-7 ) then
       print*, 'steady-state condition reached'
       exit 
       end if

    do i = 1, n-1 !updating solution
       u(i) = v(i)       
    end do 

  end do 
end program parabolic1

方法三:

program parabolic1
  integer, parameter :: n = 10, m = 20 
  real, parameter :: h = 0.1, k = 0.005 !step sizes
  real, dimension (0:n) :: u,v
  integer:: i,j
  real::pi,pi2
  
  u(0) = 0.0; v(0) = 0.0; u(n) = 0.0; v(n) =0.0
  pi = 4.0*atan(1.0)    
  pi2 = pi*pi 
  
  do i=1, n-1
     u(i) = sin( pi*real(i)*h)
  end do
  
  do j = 1,m 

    do i = 1, n-1
       v(i) = 0.5*(u(i-1)+u(i+1))
    end do 
    t = real(j)*k  !increment in time, now check for steady-state

    !steady-state check: Perhaps this is the correct expression I want to use
       if( norm2(v) - norm2(u) .LT. 1.0e-7 ) then
       print*, 'steady-state condition reached'
       exit 
       end if

    do i = 1, n-1 !updating solution
       u(i) = v(i)       
    end do 

  end do 
end program parabolic1

回答

无需讨论确定“接近度”的最佳或正确方法(不是真正的编程问题),我们可以专注于方法的 Fortran 部分正在做什么。

方法 1 和方法 2 是相似的想法(但在执行上有问题),而方法 3 不同(在另一种情况下有问题)。

另请注意,通常人们想要比较差异的大小abs(v-u)而不是(有符号的)差异v-u。随着迭代的非单调变化,这些是完全不同的。

方法 3 用于norm2(v) - norm2(u)测试数组uv是否相似。这不正确。考虑

norm2([1.,0.])-norm2([0.,1.])

而不是更正确的

norm2([1.,0.]-[0.,1.])

方法二

if ( v - u .LT. 1.0e-7 ) then

存在无效数组表达式的问题,但“所有点都接近吗?” 可以适当地写成

if ( ALL( v - u .LT. 1.0e-7 )) then

(您会在此处找到有关此类数组缩减的其他问题)。

方法 1 尝试类似但不正确的方法:

    do i = 1,n-1
if ( v(i) - u(i) .LT. 1.0e-7 ) then
print*, 'steady-state condition reached'
exit
end if
end do

这在一个大的方面是不正确的,在一个微妙的方面是不正确的。

首先,当条件第一次测试为真时退出循环,并显示一条消息说达到稳定状态。这是不正确的:您需要关闭所有值,而这是测试任何关闭值。

其次,当条件满足时,您exit. 但是你没有exit时间迭代循环,你退出了紧密度测试循环。(exit没有构造名称会留下最里面的 do 构造)。您将处于完全相同的情况,在此最内层构造之后立即再次运行,无论测试条件是否曾经满足或从未满足(如果满足,您也会收到消息)。您将需要在时间循环中使用构造名称。

我不会展示如何做到这一点(同样,这里还有其他问题),因为您还需要修复测试条件,此时您最好使用if(all(...(更正的方法 2)而无需额外的 do 构造.

对于方法 1 和 2,您将有类似的内容:

if (all(v-u .lt 1e-7)) then
print *, "Converged"
exit
end if

对于方法 3:

if (norm2(v-u) .lt. 1e-7) then
print *, "Converged"
exit
end if

以上是if 语句来确定稳态的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>