Search code examples
recursionfortranscopesubroutine

How to keep variables defined in a recursive Fortran subroutine from updating upon internal calls?


With the following code, when variable a and a1 are equal to 2, I would like the recursive subroutine to create 2 nested do loops of length 4 (maxdev=4).

I am attempting to control the level of nesting by the variable count (count1 in the subroutine). However, when the subroutine is called by itself, the value for count1 is not preserved within the first call. I would like the outer loop to retain a value for count1 of 1 and the second loop to have a value for count1 of 2, to reflect the level of nesting.

I am unsure how to specify the program so this is achieved. Instead, when the call that creates the inner loop returns to the outer loop, the value of count1 in the outer loop has been changed and reflects what it incremented to be in the inner loop.

program fragarrays
implicit none

integer::gridres,maxdev,a,count
integer, allocatable:: x(:)

open(unit=1,file='D:/output11.txt',status='unknown')

gridres=2

maxdev=gridres*gridres

do a = 1,2 
    count=0    
    allocate(x(a))
    call assigncell(a,maxdev,count,x)
    deallocate(x)
end do

contains

recursive subroutine assigncell(a1,maxdev1,count1,x1)
    integer:: a1,maxdev1,b
    integer::count1
    integer,dimension(a1):: x1

    count1=count1+1
    do b=1,maxdev1
        x1(count1)=b
        write (1,*)count1,x1(count1),b,a1
        if(count1.lt.a1)then
            call assigncell (a1,maxdev1,count1,x1)
        end if

    end do

end subroutine assigncell

end program fragarrays

Solution

  • Make count1 a local variable instead of an argument. Its changing because its implicitly an inout argument and the call is supposed to change it. As a local variable, it is unique to each invocation of the subroutine. For example:

    module MyMod
    contains
    recursive subroutine assigncell(a1,maxdev1,count1_arg,x1)
        integer, intent (in):: a1,maxdev1
        integer, intent (in)::count1_arg
        integer,dimension(a1):: x1
        integer :: count1, b
    
        count1 = count1_arg
        write (*, *) "entering subr. with", a1, count1
        count1=count1+1
        write (*, *) "changed to: a1, count1=", a1, count1
        do b=1,maxdev1
            x1(count1)=b
            write (1,*)count1,x1(count1),b,a1
            if(count1.lt.a1)then
                call assigncell (a1,maxdev1,count1,x1)
            end if
    
        end do
        write (*, *) "still at: a1, count1:", a1, count1
    
    end subroutine assigncell
    
    end module MyMod
    
    program fragarrays
    use MyMod
    implicit none
    
    integer::gridres,maxdev,a,count
    integer, allocatable:: x(:)
    
    open(unit=1,file='output11.txt',status='replace')
    
    gridres=2
    
    maxdev=gridres*gridres
    
    do a = 1,2
        count=0
        allocate(x(a))
        write (*, *) "calling with", a, count
        call assigncell(a,maxdev,count,x)
        deallocate(x)
    end do
    
    
    end program fragarrays
    

    P.S. An alternative method of making the count1 argument local to the subroutine: give that argument the VALUE attribute:

    ...
    recursive subroutine assigncell(a1,maxdev1,count1,x1)
        integer, intent (in):: a1,maxdev1
        integer, VALUE ::count1
        integer,dimension(a1):: x1
        integer :: b
    
        write (*, *) "entering subr. with", a1, count1
    ...