2017-04-21 11 views
1

비슷한 제목의 스레드가 여러 개 있지만 그 중 하나가 같지 않다고 생각합니다. 하나는 fortran pass allocated array to main procedure과 매우 비슷하지만 답변에는 Fortran 2008이 필요합니다. 저는 Fortran 90/95 솔루션을 따릅니다.SUBTROUTINE에서 할당 된 배열을 Fortran의 주 프로그램에 넘김

아주 좋은 또 다른 스레드는 Dynamic array allocation in fortran90입니다. 그러나이 방법에서는 서브 루틴에 할당하는 동안 할당이 해제 된 것처럼 보이지 않으므로 이상하게 보입니다. 내 방법은 적어도 동일하게 보이지만, 주 프로그램에서 배열을 인쇄 할 때 공백 만 인쇄됩니다. 서브 루틴 자체에서 인쇄 할 때 배열은 올바른 값과 올바른 수의 값을 화면에 인쇄합니다.

다음에서는 MAIN 프로그램이 서브 루틴을 호출합니다. 이 서브 루틴은 데이터를 할당 가능한 배열로 읽어 들여 배열을 다시 주 프로그램으로 전달합니다. 필자는 입력 파일에서 특정 용어를 찾도록 설계된 작은 서브 루틴을 사용하여이 작업을 수행합니다. 이러한 모든 서브 루틴은 하나의 모듈 파일에 있습니다. 따라서 세 개의 파일이 있습니다 : Main.f90, input_read.f90 및 filename.inp.

그러면 프로그램 Main.f90에서 할당 할 수있는 배열을 전달하는 방법과 실제로 할당되고 크기가 지정되고 할당되지 않은 다음 호출 된 서브 루틴을 프로그램 Main으로 전달하는 방법을 모르겠습니다. 이것은 아마도 혼란스럽게 들릴 것입니다. 그래서 여기에 세 가지 프로그램 모두에 대한 코드가 있습니다. 부적절한 서식을 붙일 때 사과드립니다. 모든 행을 분리하려고했습니다.

main.f90 :

module input_read 
contains 
!=============================================================== 
!===============================================================  
Subroutine Obtain_LJ_Epsilon(epsilstar,natoms) 
! Reads epsilon and sigma parameters for Lennard-Jones Force-Field and also 
! counts the number of types of atoms in the system 
!=============================================================== 
!=============================================================== 
INTEGER        :: error,line_number,natoms_eps,i 
CHARACTER(120)       :: string, next_line, next_next_line,dummy_char 
CHARACTER(8)       :: dummy_na,dummy_eps  
INTEGER,intent(out)     :: natoms 
LOGICAL        :: Proceed 
real, intent(out), allocatable  :: epsilstar(:) 

error = 0 
line_number = 0 
Proceed = .true. 

open(10,file='filename.inp',status='old') 

!============================================= 
!   Find key word LJ_Epsilon 
!============================================= 

DO 
    line_number = line_number + 1 

    Read(10,'(A120)',iostat=error) string 

    IF (error .NE. 0) THEN 
    print*, "Error, stopping read input due to an error reading line" 
    exit 
    END IF 

    IF (string(1:12) == '$ LJ_epsilon') THEN 

     line_number = line_number + 1 
     exit 

    ELSE IF (string(1:3) == 'END' .or. line_number > 2000) THEN 

     print*, "Hit end of file before reading '$ LJ_epsilon' " 
     Proceed = .false. 
     exit 

    ENDIF 
ENDDO 

!======================================================== 
! Key word found, now determine number of parameters 
! needing to be read 
!======================================================== 

    natoms_eps = -1 
dummy_eps = 'iii' 

do while ((dummy_eps(1:1) .ne. '$') .and. (dummy_eps(1:1) .ne. ' ')) 

     natoms_eps = natoms_eps + 1 
     read(10,*) dummy_eps 

enddo !we now know the number of atoms in the system (# of parameters) 

close(10) 

Allocate(epsilstar(natoms_eps)) 
epsilstar = 0.0 
!============================================================ 
! Number of parameters found, now read their values 
!============================================================ 
if(Proceed) then 

    open(11,file='filename.inp',status='old') 

    do i = 1,line_number-1 
     read(11,*) ! note it is not recording anything for this do loop 
    enddo 

    do i = 1,natoms_eps 

     read(11,*) dummy_char 
     read(dummy_char,*) epsilstar(i) ! convert string read in to real, and store in epsilstar 

    enddo 

    close(11) 

    PRINT*, 'LJ_epsilon: ', epsilstar ! printing to make sure it worked 
endif 

deallocate(epsilstar) 
END Subroutine Obtain_LJ_Epsilon 

end module input_read 

마지막 입력 파일 :

Program main 

use input_read ! the module with the subroutines used for reading filename.inp 
implicit none 
REAL, Allocatable   :: epsilstar(:) 
INTEGER      :: natoms 

call Obtain_LJ_Epsilon(epsilstar, natoms) 

print*, 'LJ Epsilon  : ', epsilstar 

END Program main 

다음 서브 루틴 (I 공간에 필요한 하나를 제외한 모두를 제거) input_read.f90와 모듈 : filename.inp

# Run_Type 
NVT 

# Run_Name 
Test_Name 

# Pressure 
1.0 

# Temperature 
298.15 

# Number_Species 

# LJ_epsilon 
117.1 
117.1 
117.1 

# LJ_sigma 
3.251 
3.251 
3.251 

END 

그리고 또, 내가 전달하는 방법을 알아낼 수,984,614,321 할당 0 배열을 주 프로그램에 추가합니다. 할당되지 않은 배열을 main.f90에서 서브 루틴으로 전달하여 내부에 할당하고 다시 전달하고 main.f90에서 할당을 해제하려고 시도했지만 작동하지 않았습니다. 코드가 현재 작동 중입니다. 코드가 작동합니다 (즉, 버그가 없습니다). 제대로 찾았고 배열을 만드는 서브 루틴에서 epsilstar을 전달하지 않습니다.

+0

코드에서 사용하는 할당 가능 인수는 Fortran 2003 표준 기능입니다. – IanH

+0

알아두면 좋을 것 같습니다. 감사! Fortran 90/95에서 배열을 전달하는 방법에 대한 간단한 설명이 있습니까? 제가 정말로 싫어하는 한 가지 방법은 처음부터 끝까지 통과하고 내가 가진 것의 크기를 얻는 서브 루틴을 가지는 것입니다. 그러면 할당 할 필요가 없습니다. 이것이 Fortran 90/95 방법일까요? –

답변

0

내가 만든 실수는 메인 프로그램에 전달하기 전에 서브 루틴에서 배열의 할당을 해제하는 것이 었습니다. 배열을 해제하지 않으면 어레이가 정상적으로 전송되었습니다. 또한 주 프로그램에서 할당을 해제하지도 않습니다.

+0

받은 피드백이 거의 없음을 유의하십시오. 의견이나 답변이 없습니다. 귀하의 질문을보다 합리적인 것으로 만드십시오. 모든 코드를 포함 시켰지만 변경하지 말고 더 짧은 코드를 만들어 문제를 해결하십시오 ([mcve]). 필요한 부분을 중단 할 때까지 코드의 일부를 삭제하십시오. 그리고 가장 중요한 * 것 : 많은 텍스트를 포함하지 말고 바로 그 지점으로 가십시오. –

+0

게시 한 후 잠시 나마 해결했기 때문에 계속 보관해야하는지 궁금합니다. 그것은 불필요한 것처럼 보입니다. 아마도 그것은 다른 사람들에게 유용 할 것이지만 당신이 말했듯이, 그것은 부피가 크다. –