cauchy42
cauchy42

Reputation: 201

Conditional use of subroutines in Fortran

My scenario: I would like to have my Fortran (>=95) program choose one of two subroutines in a calculation, based on a parameter. As an example, let's have two subroutines, foo, which subtracts; and bar, which adds its two integer arguments. I furthermore have a subroutine callingsub which gets either foo or bar as an argument. Full program could look like

program choice

implicit none

integer :: a,b

a=3
b=4

call callingsub(a,b,foo)

contains

  subroutine foo(a,b,c)
    integer, intent(in) :: a,b
    integer, intent(out) :: c

    c=a-b
  end subroutine foo

  subroutine bar(a,b,c)
    integer, intent(in) :: a,b
    integer, intent(out) :: c

    c=a+b
  end subroutine bar

  subroutine callingsub(a,b,sub)
    integer, intent(in) :: a,b

    interface 
       subroutine sub(a,b,c)
         integer, intent(in) :: a,b
         integer, intent(out) :: c
       end subroutine sub
    end interface

    integer :: c

    call sub(a,b,c)
    write(*,*) 'Your answer is ',c
  end subroutine callingsub

end program choice

Now to switch between foo and bar I have to recompile, but I would rather have a choice at run time. I imagine having an integer flag, which, if 0 chooses foo and if 1 chooses bar. I could of course write a subroutine

subroutine baz(a,b,c,flag)
  integer, intent(in) :: a,b
  integer, intent(out) :: c
  integer, intent(in) :: flag

  if (flag==0) then
    c=a-b
  else if (flag==1) then
    c=a+b
  else
    write(0,*) 'illegal flag ', flag
    stop 1
  end if
end subroutine baz

which uses the flag to decide, however, the call to callingsub will be in a huge loop, and my feeling tells me, that it would be better to have the decision on foo or bar before the loop.

Is there any possibility to have a conditional to decide in the main program? I imagine something like

if (flag==0) then
  chosensub=foo
elseif (flag==1) then
  chosensub=bar
else
  !error and exit
end if

and then call callingsub(a,b,chosensub), which unfortunately does not work. I cannot put interfaces into a conditional either.

I appreciate any help on this, and hope I made myself clear enough!

PS I have access to Intel ifort 18.0.5 20180823, so I am not limited to F95.

Upvotes: 2

Views: 380

Answers (1)

cauchy42
cauchy42

Reputation: 201

OK, for future reference here is what I did, after following @M.S.B s answer here, so thanks @HighPerformanceMark and @IanBush for pointing (haha) in that direction:

program choice

implicit none

integer :: a,b,flag

interface
   subroutine chosensub(a,b,c)
     integer, intent(in) :: a,b
     integer, intent(out) :: c
   end subroutine chosensub
end interface

procedure(chosensub), pointer :: subptr=>null()

read(*,*) flag

if (flag==0) then
   subptr=>foo
else if (flag==1) then
   subptr=>bar
else
   write(0,*) 'error message'
   stop 1
end if

a=3
b=4

call callingsub(a,b,subptr)

contains

! as in OP

end program choice

Upvotes: 5

Related Questions