Search code examples
fortrangfortranfortran90dynamic-arraysfortran95

Passing an allocated array from a SUBTROUTINE to the main program in Fortran


There are several threads with similar titles of mine, but I do not believe they are the same. One was very similar fortran pass allocated array to main procedure, but the answer required Fortran 2008. I am after a Fortran 90/95 solution.

Another very good, and quite similar thread is Dynamic array allocation in fortran90. However in this method while they allocate in the subroutine, they don't ever appear to deallocate, which seems odd. My method looks on the surface at least to be the same, yet when I print the array in the main program, only blank spaces are printed. When I print in the subroutine itself, the array prints to screen the correct values, and the correct number of values.

In the following a MAIN program calls a subroutine. This subroutine reads data into an allocatable array, and passes the array back to the main program. I do this by using small subroutines each designed to look for specific terms in the input file. All of these subroutines are in one module file. So there are three files: Main.f90, input_read.f90 and filename.inp.

It seems then that I do not know how to pass an array that is allocatable in program Main.f90 as well as in the called subroutine where it is actually allocated, sized, and then deallocated before being passed to program Main. This perhaps sounds confusing, so here is the code for all three programs. I apologize for the poor formatting when I pasted it. I tried to separate all the rows.

main.f90:

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

Next is the module with a subroutine (I removed all but the necessary one for space), input_read.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  

And finally the input file: 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

And again, I can't figure out how to pass the allocated epsilstar array to the main program. I have tried passing an unallocated array to the subroutine from the main.f90, allocating it inside, passing it back, and deallocating it in the main.f90, but that did not work. I have tried it as the code currently is... the code works (i.e. is bug free) but it does not pass epsilstar from the subroutine where it correctly finds it and creates an array.


Solution

  • It turns out that the mistake I made was in deallocating the array in the subroutine before passing it to the main program. By NOT deallocating, the array was sent back fine. Also, I do not deallocate in the main program either.