我正在开发一个Fortran代码(.f90),它将在某个时间间隔(dt1=0.001
)中计算某个矩阵,并且这些矩阵必须在某些时间步长(dt=0.1
)中进行积分。虽然我在FORTRAN 77中很有经验,但对Fortran 90来说是新手。我无法使矩阵的维度变得真实(我认为这是问题所在,我可能错了!)。以下是长程序的一部分。我正在尝试(从最近1个月)不同的方法,但没有成功,输出是NaN
。我在Ubuntu 16.04中使用gfortran
PROGRAM MODEL
IMPLICIT NONE
REAL::DT,DT1,DK2
INTEGER::I,J,IL,IM,E(100000),jm,DK1
REAL::XN2(1),XO2(1)
REAL,DIMENSION(100000)::AN,BN,AN1,BN1
REAL,DIMENSION(21)::XA,XB
REAL,DIMENSION(21,21)::WA,WB,WAB,WBA
REAL,DIMENSION(21)::SUMA,SUMAB,SUMB,SUMBA
XN2=1E-7
XO2=1E-8
OPEN(1,FILE='TEST1.dat')
OPEN(2,FILE='TEST2.dat')
OPEN(3,FILE='TEST3.dat')
OPEN(4,FILE='TEST4.dat')
DO I=1,21
read(1,*)(WA(I,J),J=1,21)
read(2,*)(WB(I,J),J=1,21)
read(3,*)(WAB(I,J),J=1,21)
read(4,*)(WBA(I,J),J=1,21)
!enddo
IM=1
IL=1
AN(IM)=0.0
BN(IM)=0.0
!AN1(IL)=0.0
!BN1(IL)=0.0
JM=1
E(:)=0.0
DT=0.1
DT1=0.01
DK1=1.0
DK2=1.0
DO WHILE(DK1<=10)
!DO I=1,21
DO WHILE(DK2<=100)
do j=1,21
CALL XAA(WA,WAB,SUMA,SUMAB,XN2,XO2,AN(IM),BN(IM),XA)
CALL XBB(WB,WBA,SUMB,SUMBA,XN2,XO2,AN(IM),BN(IM),XB)
enddo
AN(IM+1)=AN(IM)+XA(I)*DT1
BN(IM+1)=BN(IM)+Xb(I)*DT1
AN1(IL)=AN(IM+1)
BN1(IL)=BN(IM+1)
AN(IM)=AN1(IL)
BN(IM)=BN1(IL)
IM=IM+1
IL=IL+1
WRITE(1112,203)I,an(Im),bn(Im)
DK2=DK2+DT1
ENDDO
203 FORMAT(' ',i2,1000000E13.5)
E(JM)=DK1
AN(DK1)=AN(IM)
BN(DK1)=BN(IM)
WRITE(1111,203)I,AN(DK1),BN(DK1)
DK1=DK1+DT
JM=JM+1
ENDDO
ENDDO
END PROGRAM MODEL
!!SUBROUTINES XAA
SUBROUTINE XAA(WA,WAB,SUMA,SUMAB,XN2,XO2,AN,BN,XA)
INTEGER::I,J
REAL,DIMENSION(100000)::AN,BN
REAL,intent(out)::XA(21)
REAL::XN2(1),XO2(1)
REAL,DIMENSION(21,21)::WA,WAB
REAL,DIMENSION(21)::SUMA,SUMAB
SUMA(:)=0.0
SUMAB(:)=0.0
DO I=1,21
DO J=1,21
SUMA(I)=SUMA(I)+WA(I,J)*XN2(1)
SUMAB(I)=SUMAB(I)+WAB(I,J)*XO2(1)
ENDDO
XA(I)=1e-5+SUMA(I)*AN(1)+SUMAB(I)*BN(1)
ENDDO
RETURN
END SUBROUTINE XAA
!!SUBROUTINES XBB
SUBROUTINE XBB(WB,WBA,SUMB,SUMBA,XN2,XO2,AN,BN,XB)
INTEGER::I,J
REAL::XN2(1),XO2(1)
REAL,DIMENSION(100000)::AN,BN
REAL,intent(out)::XB(21)
REAL,DIMENSION(21,21)::WB,WBA
REAL,DIMENSION(21)::SUMB,SUMBA
SUMB(:)=0.0
SUMBA(:)=0.0
DO I=1,21
DO J=1,21
SUMB(I)=SUMB(I)+WB(I,J)*XN2(1)
SUMBA(I)=SUMBA(I)+WBA(I,J)*XO2(1)
ENDDO
XB(I)=1e-5+SUMB(I)*AN(1)+SUMBA(I)*BN(1)
ENDDO
RETURN
END SUBROUTINE XBB
答案 0 :(得分:0)
您必须设置/增加IM和IL(并在使用IL前为IL分配一个值)! 在do循环中,没有任何内容,但肯定必须存在。 清单末尾的写入中,数组索引也必须始终是IM或IL之类的整数,将时间转换为例如如果需要,通过NINT(T / DT)+1发送IM。 但是首先要使程序能够正常工作,请在循环内为IM和IL设置适当的值。
答案 1 :(得分:0)
在聊天中的先前注释以及对代码的更改:
对于这样一个均匀离散的问题,使用整数对数组索引进行所有操作都非常容易(最好),并通过将步数和时间离散间隔相乘来恢复时间的真实值。
在这种情况下,我认为最简单的方法是使用两个嵌套循环:在“长”积分时间步长上进行外部循环,而在“短”时间步长上进行积分的内部循环。在每个长时间步骤的开始处,您都复制了上一个长时间步骤中的向量值,并为内循环中的每个短时间步骤添加了需要添加的向量。
在您的情况下,可以在主程序和子例程中使用数组语法来避免这么多的行和列索引。
在开始使用它们的值之前,请务必在程序开始时读取所有输入矩阵的系数。
如果要积分实数值,则可能要添加或减去具有不同数量级的实数。为了准确地执行此操作,您应确保实际值具有足够高的精度,例如,使用通过Fortran 95 KIND
函数获得的SELECTED_REAL_KIND
。
为您的子例程提供显式接口,例如,将其内部化。然后,您可以将数组传递为隐式形状,从而简化声明。
如果可以为子程序的每个参数定义一个意图,请提供它们。如果编译器可以(通过显式接口)访问意图,则它可以进行更多的检查和更多的优化。
不再需要将工作空间传递给子例程的Fortran 77常规做法,对于小型工作空间,它不应以任何明显的方式影响性能。
优良作法是只定义一次参数,而不是用21
s填充代码。
结果代码为:
PROGRAM MODEL
IMPLICIT NONE
INTEGER, PARAMETER :: DP = SELECTED_REAL_KIND(15,300)
INTEGER, PARAMETER :: N = 21 ! Dimension of arrays.
INTEGER, PARAMETER :: Nlong = 1000 ! Number of integrated ("long")
! time steps.
INTEGER, PARAMETER :: Nshort = 100 ! Number of short time steps
! within each long time step.
REAL(kind=DP), PARAMETER :: DT1 = 0.001_DP ! Small time step
REAL(kind=DP), PARAMETER :: DT = Nshort * DT1 ! Long time step
! REAL(kind=DP), PARAMETER :: T = DT * Nlong ! Total time
REAL(kind=DP), DIMENSION(N,N)::WA,WB,WAB,WBA ! Input arrays.
REAL(kind=DP) :: XN2(1), XO2(1) ! Other coefficients.
REAL(kind=DP), DIMENSION(N,0:Nlong) :: AN, BN ! Output vectors.
REAL(kind=DP), DIMENSION(N) :: XA, XB ! Vectors used in integrations.
INTEGER :: I, J ! Indices for rows and columns of arrays.
INTEGER :: IM ! Index for long time steps.
INTEGER :: IL ! Index for short time steps.
REAL(kind=DP) :: time_now
! Set coefficient values.
XN2=1E-7_DP
XO2=1E-8_DP
! Open input files,
OPEN(1,FILE='TEST1.dat')
OPEN(2,FILE='TEST2.dat')
OPEN(3,FILE='TEST3.dat')
OPEN(4,FILE='TEST4.dat')
! read input arrays
DO I=1,N
read(1,*)(WA(I,J),J=1,N)
read(2,*)(WB(I,J),J=1,N)
read(3,*)(WAB(I,J),J=1,N)
read(4,*)(WBA(I,J),J=1,N)
END DO
! and close input files.
DO I = 1, 4
CLOSE(I)
END DO
! Initialize output vectors for time=0.
AN(:,0) = 0.0_DP
BN(:,0) = 0.0_DP
! Loop over long time steps.
DO IM = 1, Nlong
! Initialize vectors from final values at previous time step.
AN(:,IM) = BN(:,IM-1)
BN(:,IM) = BN(:,IM-1)
! Loop over short time steps.
DO IL = 1, Nshort
time_now = (IM-1) * DT + IL * DT1
CALL XAA(WA,WAB,XN2,XO2,AN(:,IM),BN(:,IM),XA)
CALL XBB(WB,WBA,XN2,XO2,AN(:,IM),BN(:,IM),XB)
! Update vectors.
AN(:,IM) = AN(:,IM) + XA * DT1
BN(:,IM) = BN(:,IM) + XB * DT1
! Print their values.
WRITE(1112,'(F12.5,2(1X,i7),42(1X,E13.5))') &
time_now, IM, IL, AN(:,IM), BN(:,IM)
END DO
! Print integrated values.
WRITE(1111,'(F12.5,1X,i7,42(1X,E13.5))') &
time_now, IM, AN(:,IM), BN(:,IM)
END DO
CONTAINS
!!SUBROUTINES XAA
SUBROUTINE XAA(WA,WAB,XN2,XO2,AN,BN,XA)
! Arguments
REAL(kind=DP), DIMENSION(:,:) :: WA,WAB
REAL(kind=DP), DIMENSION(:), INTENT(IN) :: AN,BN
REAL(kind=DP), INTENT(OUT) :: XA(:)
REAL(kind=DP), INTENT(IN) :: XN2(1),XO2(1)
! Local variables.
REAL(kind=DP), DIMENSION(size(XA)) :: SUMA,SUMAB
INTEGER::I
DO I=1,N
SUMA(I)=SUM(WA(I,:))*XN2(1)
SUMAB(I)=SUM(WAB(I,:))*XO2(1)
END DO
XA(:)=1e-5_DP+SUMA(:)*AN(:)+SUMAB(:)*BN(:)
END SUBROUTINE XAA
!!SUBROUTINES XBB
SUBROUTINE XBB(WB,WBA,XN2,XO2,AN,BN,XB)
! Arguments
REAL(kind=DP), DIMENSION(:,:), INTENT(IN) :: WB,WBA
REAL(kind=DP), INTENT(IN) ::XN2(1),XO2(1)
REAL(kind=DP), DIMENSION(:), INTENT(IN) ::AN,BN
REAL(kind=DP), INTENT(OUT) :: XB(:)
! Local variables.
INTEGER::I
REAL(kind=DP), DIMENSION(size(XB)) :: SUMB,SUMBA
DO I=1,N
SUMB(I)=SUM(WB(I,:))*XN2(1)
SUMBA(I)=SUM(WBA(I,:))*XO2(1)
ENDDO
XB(:)=1e-5_DP+SUMB(:)*AN(:)+SUMBA(:)*BN(:)
END SUBROUTINE XBB
END PROGRAM MODEL