Fortran数组自动更改值

时间:2016-06-26 02:37:32

标签: arrays fortran intel-fortran

我正在关于WIND涡轮机模拟的关于ANSYS CFX的maser论文。要计算参数,我必须使用FORTRAN编写的代码。我面临一个非常奇怪的问题,需要你的帮助。完整的fortran代码很长,但我只会在导致问题的代码中发布子程序。

我正在使用一个子程序将刀片分成一个径向元素。使用两种类型的分割,然后将元素的径向位置存储在两个1-D阵列RI和RJ中。

稍后在代码中,我收到了一些错误,我追溯到这个子程序,它没有给我正确的RJ值。子程序给出正确的RI值。然后我使用计算correct values of RJ的相同循环显示RJ的结果。幸运的是,RJ的值是正确的。然后在同一个子程序中,紧接在该循环之后,我开始另一个循环再次显示RJ的值,不幸的是这次它们不正确incorrect values of RJ即使两个循环之间没有任何东西可以改变RJ的值。看似RJ的每个元素都被RI的下一个元素所取代。因此我开始知道这是错误的起源。我已经重新检查了程序,似乎没有错误,错误发生在子程序内的某个地方。我在没有ANSYS CFX的fortran上使用另一个程序来使用相同的子程序计算风力涡轮机性能,虽然两个程序中的两个子程序完全相同,但这个问题并没有出现在该程序中。我在这件事上需要帮助,因为我被困在这几天。我正在使用INTEL COMPOSER附带的Intel fortran编译器。

子实例如下

CALL INIT(M,PI,PREC,R,HUBRAD,RI,RJ)

SUBROUTINE INIT(M,PI,PREC,R,HUBRAD,RI,RJ)


  INTEGER:: M
  REAL:: PI,PREC,R,HUBRAD
  REAL:: RI(41),RJ(41)
  !,RRI,RRJ)

    CALL LLPOINTS (PI,PREC,R,HUBRAD,M,RI,RJ)


    return
    End Subroutine

    SUBROUTINE LLPOINTS (PI,PREC,R,HUBRAD,M,RI,RJ)

  !Input arguments: M,Pi, PREC, R, HUBRAD 
  !Output arguments : RI, RJ

  INTEGER:: M
  REAL::PREC,R,HUBRAD
  REAL:: RI(41),RJ(41)
  INTEGER :: J
  character*100 ::string1, string2, string3

  CALL MESAGE( 'WRITE', 'subroutine INIT START' )  

  CALL MESAGE( 'WRITE', "RI   RJ    DJ")

  DO J=1,M+1   


        IF (J.LT.M+1) THEN   
        RI(J)=0.5E+00*(1.E+00+HUBRAD/R)-0.5E+00*(1.E+00-HUBRAD/R)
       &*COS((J-0.5E+00)*PI/M)

        RJ(J)=0.5E+00*(1.E+00+HUBRAD/R)-0.5E+00*(1.E+00-HUBRAD/R)
       &*COS((J-1.E+00)*PI/M)


        IF (ABS(RI(J)).LT.(1/PREC)) THEN

              STOP 
        ENDIF

        ELSE
           RJ(J)=1.E+00

          END IF


          write (string1,*) RI(J)
          write (string2,*) RJ(J)


          CALL MESAGE( 'WRITE', string1//' '//string2) 

      END DO

      CALL MESAGE( 'WRITE','ri     rj')
      do j =1,m

          write (string1,*) RI(J)
          write (string2,*) RJ(J)
          CALL MESAGE( 'WRITE', string1//' '//string2 ) 

      end do
      CALL MESAGE( 'WRITE', 'subroutine LLINE OK' )  

  END SUBROUTINE

你会想知道为什么LLPOINTS是INSIDE INIT子程序而没有任何理由。实际上在原始程序中,子程序INIT有很多其他子程序。我只使用了LLPOINTS,因为我不需要它们而丢弃其余的

我已经检查过我的程序在任何子程序中没有隐含的,根据我的有限知识应该存在。当我向所有子例程添加隐式none时,发生了许多编译错误,似乎在这些错误中,我发现存在与许多变量的声明相关的问题。我已经解决了这些问题,现在当所有问题都得到解决时,我在编译时遇到了以下错误,这个错误在隐式无效之前就没有了。

错误:函数ACD_Dp中引用的未解析的外部符号LLINE。

我不知道如何处理这个错误

2 个答案:

答案 0 :(得分:1)

奇怪的行为可能源于一些(不正确的)实际参数而不是子例程本身。为了解释这一点,我们首先考虑INIT()LLPOINTS()的简化版本,如下所示:

subroutine INIT ( a, b )
    implicit none
    real :: a( 5 ), b( 5 )

    call LLPOINTS ( a, b )
end subroutine

subroutine LLPOINTS ( a, b )
    implicit none
    real :: a( 5 ), b( 5 )
    integer :: i

    print *, "output (1):"
    do i = 1, 5
        a( i ) = i                !! set some values to a(:) and b(:)
        b( i ) = i * 100
        print *, a( i ), b( i )   !! check the values
    enddo

    print *, "output (2):"
    do i = 1, 4
        print *, a( i ), b( i )   !! check the values again
    enddo
end subroutine

此程序将一些值设置为a(:)b(:),并将其值打印两次以进行双重检查(如在OP程序中)。现在我们考虑主要程序:

program main
    real :: a( 5 ), b( 5 )
    call INIT ( a, b )
end

给出预期结果(ifort test.f90与v14.0):

 output (1):
   1.000000       100.0000
   2.000000       200.0000
   3.000000       300.0000
   4.000000       400.0000
   5.000000       500.0000
 output (2):
   1.000000       100.0000
   2.000000       200.0000
   3.000000       300.0000
   4.000000       400.0000

接下来,让我们假设ab被错误地声明为标量变量

program main
    real :: a, b
    call INIT ( a, b )
end

或甚至没有声明(即默认implicit real(a-h,o-z)规则)

program main
    call INIT ( a, b )
end

然后我们获得

 output (1):
   1.000000       100.0000
   2.000000       200.0000
   3.000000       300.0000
   4.000000       400.0000
   5.000000       500.0000
 output (2):
   1.000000       2.000000
   2.000000       3.000000
   3.000000       4.000000
   4.000000       5.000000

其模式似乎与OP输出的模式非常相似(即,所有元素在输出(2)中移位1)。也就是说,这种奇怪行为的原因可能是我们传递标量并访问无效的内存区域(假设ab在内存中连续对齐,并且有一些尾随内存区域)。如果是这样,main()LLPOINTS()之间的内存映射可能如下所示:

a       b      NG     NG     NG     NG
---------------------------------------
a(1)    a(2)   a(3)   a(4)   a(5)
        b(1)   b(2)   b(3)   b(4)   b(5)

如果是这种情况,由于a(i+1) = b(i),我们在上面的输出(2)中获得了奇怪的结果。我们可以通过插入像

这样的行来确认这一点
if ( loc( a(2) ) == loc( b(1) ) ) stop "trapped (ifort)"
LLPOINTS()中的

。更重要的是,如果我们附上

ifort -check test.f90

选项,我们可以自动检测到这种情况(带有分段错误)。那你可以尝试这个选项来看看是否是这种情况......?

答案 1 :(得分:0)

是的,你是对的。我已经提出以下几行

If ( loc( RJ(1) ) == loc( RI(2) ) ) then
call mesage ('write','trapped (ifort)')

stop

End If

我收到错误,打印被困(ifort)。 但问题是,我没有在任何地方声明标量参数RI,RJ。我一直把它们称为向量RI(41)和RJ(41)

相关问题