(1) (1/2) 处数组引用中的排名不匹配

Rank mismatch in array reference at (1) (1/2)

我是 Fortran 的新手,基本上只是在大学里玩。我的代码代表了一个更维的牛顿算法来解决残差问题。我将所有函数和子例程放在一个文件中,以排除因错误包含而出错的可能性。 我的问题是我在第 52 行收到以下错误:

J = DFuncDx(x)

错误:在 (1) (1/2) 处的数组引用中排名不匹配

我知道传递的参数的维度一定有问题,但我不知道问题出在哪里。在我的理解中,变量 x 被声明为 3 维数组,函数需要 3 维。

我使用 "gfortran -o nDNewtonMain nDNewtonMain.f90 -l lapack" 在 Linux 上编译。

此外,每当我调用函数 Funct 或 DFuncDx 时,我都会收到 "REAL array index at (1)" 警告。

program nDNewton

   IMPLICIT NONE

   integer, parameter               :: N = 3
   double precision, dimension(N)   :: x
   integer, parameter               :: NMAXIT = 10
   double precision, parameter      :: MAXERR = 1.d-8
   integer                          :: Nit, i
   double precision                 :: ERR


   do i=1,N
      x(i) = 0.d0
   end do

   Nit = 0; ERR = 1.d0

   call myNewton( x, Nit, NMAXIT, MAXERR, ERR, N)

   write(*,*) "Solution: x="
   do i=1,N
      write(*,*) x(i)
   end do
   write(*,*) "Found after ", Nit, " iterations. Error: ", ERR

end program nDNewton

subroutine myNewton(x, Nit, NMAXIT, MAXERR, ERR, N)

    IMPLICIT NONE

    integer, intent(in)                                 ::  N
    double precision, intent(inout), dimension(N)       ::  x
    integer, intent(in)                                 ::  NMAXIT
    integer, intent(inout)                              ::  Nit
    double precision, intent(in)                        ::  MAXERR
    double precision, intent(inout)                     ::  ERR
    double precision, dimension(N, N)                   ::  J
    integer, dimension(N)                               ::  ipiv
    integer                                             ::  info, i
    double precision, dimension(N)                      ::  F
    double precision, dimension(N)                      ::  Funct
    double precision, dimension(N, N)                   ::  DFuncDx

    Nit = 0
    F   = Funct(x)
    ERR = norm2(F)

    do while (Nit < NMAXIT .AND. ERR > abs(MAXERR))

        J = DFuncDx(x)
        call DGESV( 3, 1, J, 3, ipiv, -F, 3, info )
        x = x + F
        Nit = Nit + 1
        F   = Funct(x)
        ERR = norm2(F)
        do i=1, 3
            write(*,*) x(i)
        end do
        write(*,*) "Error: ", ERR,", Nit: ", Nit
    end do

end subroutine myNewton

function Funct(x)
    IMPLICIT NONE

    double precision, dimension(3), intent(in)      ::      x
    double precision, dimension(3, 3)               ::      ASys
    double precision, dimension(3)                  ::      a, e1
    double precision, dimension(3)                  ::      Funct
    double precision                                ::      exp_part

    ASys    = reshape(  (/ 1.d0,2.d0/3.d0,-2.d0,0.d0,7.d0,6.d0/7.d0,-1.d0/3.d0,0.d0,1.d0 /), (/ 3,3/)  )
    ASys    = transpose(ASys)
    a       = (/ 5.0, 3.0, 2.0 /)
    e1      = (/ 1.0, 0.0, 0.0 /)

    Funct = matmul(ASys, x) + a + exp_part(x(1), x(2), x(3)) * e1

end function

function DFuncDx(x)
    IMPLICIT NONE

    double precision, dimension(3), intent(in)      ::      x
    double precision, dimension(3, 3)               ::      DFDx
    double precision                                ::      val
    double precision, dimension(3, 3)               ::      DFuncDx
    double precision                                ::      exp_part

    val = exp_part(x(1), x(2), x(3))
    DFDx    = reshape( (/ 1.d0 + val, 2.d0/3.d0 + 7.d-1*val, -2.d0 + 5.d-1*val, &
                        0.d0, 7.d0, 6.d0/7.d0, -1.d0/3.d0, 0.d0, 1.d0 /), (/ 3,3/) )
    DFuncDx    = transpose(DFDx)

end function


double precision function exp_part(x1, x2, x3)
    IMPLICIT NONE

    double precision, intent(in)                    ::      x1, x2, x3
    double precision, dimension(3)                  ::      b

    b       = (/ 1.0, 0.7, 0.5 /)
    exp_part = exp(b(1)*x1 + b(2)*x2 + b(3)*x3)

end function exp_part

多亏了 High Performance Mark,我才找到了解决方案。也许这会在将来帮助其他用户:


module A
    contains
        subroutine myNewton(x, Nit, NMAXIT, MAXERR, ERR, N)
            IMPLICIT NONE
            integer, intent(in)                                 ::  N
            double precision, intent(inout), dimension(N)       ::  x
            integer, intent(in)                                 ::  NMAXIT
            integer, intent(inout)                              ::  Nit
            double precision, intent(in)                        ::  MAXERR
            double precision, intent(inout)                     ::  ERR
            double precision, dimension(N, N)                   ::  J
            integer, dimension(N)                               ::  ipiv
            integer                                             ::  info, i
            double precision, dimension(N)                      ::  F, B

            Nit = 0
            F   = Funct(x)
            ERR = norm2(F)

            do while (Nit < NMAXIT .AND. ERR > abs(MAXERR))

                J = DFuncDx(x)
                B = -F
                call DGESV( 3, 1, J, 3, ipiv, B, 3, info )
                x = x + B
                Nit = Nit + 1
                F   = Funct(x)
                ERR = norm2(F)
                do i=1, 3
                    write(*,*) x(i)
                end do
                write(*,*) "Error: ", ERR,", Nit: ", Nit
            end do

        end subroutine myNewton

        function Funct(x)   result(res)
            IMPLICIT NONE
            double precision, dimension(3), intent(in)      ::      x
            double precision, dimension(3, 3)               ::      ASys
            double precision, dimension(3)                  ::      a, e1
            double precision, dimension(3)                  ::      res

            ASys    = reshape(  (/ 1.d0,2.d0/3.d0,-2.d0,0.d0,7.d0,6.d0/7.d0,-1.d0/3.d0,0.d0,1.d0 /), (/ 3,3/)  )
            ASys    = transpose(ASys)
            a       = (/ 5.0, 3.0, 2.0 /)
            e1      = (/ 1.0, 0.0, 0.0 /)

            res = matmul(ASys, x) + a + exp_part(x(1), x(2), x(3)) * e1

        end function

        function DFuncDx(x) result(res)
            IMPLICIT NONE
            double precision, dimension(3), intent(in)      ::      x
            double precision, dimension(3, 3)               ::      DFDx
            double precision                                ::      val
            double precision, dimension(3, 3)               ::      res

            val = exp_part(x(1), x(2), x(3))
            DFDx   = reshape( (/ 1.d0 + val, 2.d0/3.d0 + 7.d-1*val, -2.d0 + 5.d-1*val, &
                                0.d0, 7.d0, 6.d0/7.d0, -1.d0/3.d0, 0.d0, 1.d0 /), (/ 3,3/) )
                                !DFDx
            res    = transpose(DFDx)

        end function

        double precision function exp_part(x1, x2, x3)
            IMPLICIT NONE
            double precision, intent(in)                    ::      x1, x2, x3
            double precision, dimension(3)                  ::      b

            b       = (/ 1.0, 0.7, 0.5 /)
            exp_part = exp(b(1)*x1 + b(2)*x2 + b(3)*x3)

        end function exp_part
end module

program nDNewton
    use A
    IMPLICIT NONE
    integer, parameter               :: N = 3
    double precision, dimension(N)   :: x
    integer, parameter               :: NMAXIT = 10
    double precision, parameter      :: MAXERR = 1.d-8
    integer                          :: Nit, i
    double precision                 :: ERR


    do i=1,N
        x(i) = 0.d0
    end do

    Nit = 0; ERR = 1.d0

    call myNewton( x, Nit, NMAXIT, MAXERR, ERR, N)

    write(*,*) "Solution: x="
    do i=1,N
        write(*,*) x(i)
    end do
    write(*,*) "Found after ", Nit, " iterations. Error: ", ERR

    x = Funct(x)

    write(*,*) "Residium Test: r="
    do i=1,N
        write(*,*) x(i)
    end do


end program nDNewton