我正在关于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。
我不知道如何处理这个错误
答案 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
接下来,让我们假设a
和b
被错误地声明为标量变量
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)。也就是说,这种奇怪行为的原因可能是我们传递标量并访问无效的内存区域(假设a
和b
在内存中连续对齐,并且有一些尾随内存区域)。如果是这样,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)