Home > Net >  Can I pass arrays with undefined dimension to a Fortran subroutine as INTENT(INOUT)?
Can I pass arrays with undefined dimension to a Fortran subroutine as INTENT(INOUT)?

Time:10-31

I need to pass arrays of variables to a subroutine that should change their values according to an external file. The problem is that this should be as generic as possible so if the file has n values I should be able to pass n generic integers.

Here is an example of my code:

program dummy
    
    use checkpt
    implicit none

    integer :: i1=0, i2=0, k=1, n, cpt
    integer*8 :: lastTime

    call load_checkpoint(ints=[k,i1,i2])
    
    --some code happening--

end program dummy

And the subroutine called is the following:

subroutine load_checkpoint(ints)
        implicit none

        integer, intent(inout) :: ints(:)
        integer :: stat

        open(8989, file='temp.txt', status='old', action='READ', iostat=stat)
        if (stat .eq. 0) then
            read (8989,*,iostat=stat) ints
        end if
        close(8989)

    end subroutine load_checkpoint

What I get is Error: Non-variable expression in variable definition context (actual argument to INTENT = OUT/INOUT) at (1) and I can't understand why. I also tried with non initialized variables but I get the same error. Can anybody help me, please?

CodePudding user response:

If a dummy argument is intent(out) or intent(inout), then the actual argument shall not be an expression. Your actual argument [k,i1,i2] is an expression (that forms a rank one array from 3 scalar variables), this is why you get an error here.

If you want your variables k, i1 and i2 to be updated at the end you have to write more lines (and in the called subroutine you should attribute only intent(out) to ints, as you don't use at all the input values):

integer :: ints(3)
call load_checkpoint(ints=ints)
k  = ints(1)
i1 = ints(2)
i2 = ints(3)

CodePudding user response:

You can even return an allocatable array from a function.

Checking datafiles with arbitrary number of lines, arbitrary number of integers per line is a bit messy.

module checkpt
   implicit none

contains

   function load_checkpoint()
      integer, allocatable :: load_checkpoint(:)
      integer nvars, i
      integer stat
      character(len=1000) line

      open( 10, file="temp.txt", status="old", action="read", iostat=stat )
      if ( stat == 0 ) then
         ! First pass - count variables (arbitrary number per line, arbitrary number of lines)
         nvars = 0
         do
            read( 10, "( a )", iostat=stat ) line
            if ( stat /= 0 ) exit
            do i = 1, len_trim( line )
               if ( isdigit( line(i:i) ) .and. ( i == 1 .or. ( i > 1 .and. .not. isdigit( line(i-1:i-1) ) ) ) ) nvars = nvars   1
            end do
         end do

         ! Second pass - store variables
         allocate( load_checkpoint( nvars ) )
         rewind( 10 )
         read( 10, *, iostat=stat ) load_checkpoint
      else
         write( *, * ) "Unable to read file"
         stop
      end if

      close( 10 )
    end function load_checkpoint


    logical function isdigit( c )
       character, intent(in) :: c
       isdigit = c >= '0' .and. c <= '9'
    end function isdigit

end module checkpt

!========================================================================

program dummy
   use checkpt
   implicit none
   integer, allocatable :: intvars(:)

   intvars = load_checkpoint()
    
   write( *, "( *( i0, 1x ) )" ) intvars
end program dummy
  • Related