在将数组传递给LSODA
库的ODEPACK
过程时,我遇到了一种相当特殊的行为。
场景:Intel Fortran编译器,最近的一个,OS Windows。我有一个使用Fortran 2003功能的项目,但是脏计算工作被传递给LSODA
,即Fortran 77。
LSODA
被声明为
SUBROUTINE DLSODA (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
1 ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, JT)
EXTERNAL F, JAC
INTEGER NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK, LIW, JT
DOUBLE PRECISION Y, T, TOUT, RTOL, ATOL, RWORK
DIMENSION NEQ(*), Y(*), RTOL(*), ATOL(*), RWORK(LRW), IWORK(LIW)
注意数组。打电话给我所做的一切:
CALL DLSODA(FDARCY, NEQ, SATCCUR, TCUR, TNEXT, ITOL, RTOL, ATOL, ITASK, &
ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JDUM, JT)
让我们关注SATCCUR
(Y
位置LSODA
)。宣布:
REAL(8), DIMENSION(:), ALLOCATABLE :: SATCCUR
以防万一,在调试器中,我检查了DOUBLE PRECISION
是REAL(8)
。在某些时候,SATCCUR
也被分配。问题是,带有此调用的LSODA
看到完全垃圾。指针Y
有时会指向我无法读取或写入的内容,从而导致程序崩溃。解决问题的唯一方法是将调用更改为:
CALL DLSODA(FDARCY, NEQ, SATCCUR(1), TCUR, TNEXT, ITOL, RTOL, ATOL, ITASK, &
ISTATE, IOPT, RWORK(1), LRW, IWORK(1), LIW, JDUM, JT)
请注意,我没有传递数组,但它的第一个元素--- Fortran的引用传递在这里有帮助,因为LSODA
将有效地获取第一个元素的地址。而且我必须在通话中使用所有数组。
如果我使用LSODA
文档提供的示例,一切都可以正常传递整个数组。我能发现的差异:
LSODA
示例中的数组是静态分配的,而我是动态分配。F
我将函数内部传递给子例程。它使我的生活更加轻松,因为它捕获了运行它所需的参数。我相信这是Fortran 2003的功能。但我无法看到这会如何产生问题,因为问题比F
调用早得多。所以,问题是为什么会发生这种情况?这是预期的行为吗?
PS。另外,对于LSODA
进行编译,我必须关闭函数接口检查,因为它在内部传递DOUBLE PRECISION
数组,其中INTEGER
数组是预期的 - 对作者的无耻黑客侧!
我设法追查错误。问题是我在DLSODA
的界面声明中已经放了
INTERFACE
SUBROUTINE DLSODA(F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK, &
ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, JT)
USE GENERAL
EXTERNAL :: F, JAC
INTEGER :: NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, LIW, JT, IWORK
REAL(DP) :: T, TOUT, RTOL, ATOL, RWORK
DIMENSION RWORK(LRW), IWORK(LIW)
REAL(DP), DIMENSION(:) :: Y
END SUBROUTINE DLSODA
END INTERFACE
请注意Y
的声明以及它与RWORK
的不同之处。显然,
REAL(8), DIMENSION(:) :: X
和
REAL(8) X
DIMENSION X(*)
我认为这只是一种风格问题。有人可以解释为什么会有区别吗?