Conditional use of subroutines in Fortran - 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.

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

Related

Return a real vector from a Fortran function [duplicate]

I have the following code:
Program function_as_an_array
implicit none
integer:: i
integer, parameter:: N=10
real*8:: x(N),y(N),f(N)
do i=1,N
x(i)=float(i)
end do
call func(f,N,x)
open(unit=20, file='test.dat')
do i=1,N
y(i)=f(i)
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
Subroutine func(f,N,x)
implicit none
integer i,N
real*8:: x(N),f(N)
do i=1,N
f(i)=x(i)**2
end do
end Subroutine func
I want to make the program indeed be meant for
"function as an arrray", i.e. I would like to replace the Subroutine func by a function f and get the same result (In the main program, I wish to keep a statement like y=f(x,N)). How can I do that?
There's no problem having a function return an array, as with this question and answer: the main issue is that you need the function to be in a module (or contained within the program) so that there's an automatic explicit interface: (Edit to add: or explicitly defining the interface as with Alexander Vogt's answer)
module functions
contains
function func(N,x)
implicit none
integer, intent(in) :: N
double precision, intent(in) :: x(N)
double precision, dimension(N) :: func
integer :: i
do i=1,N
func(i)=x(i)**2
end do
end function func
end module functions
Program function_as_an_array
use functions
implicit none
integer:: i
integer, parameter:: N=10
double precision:: x(N),y(N)
do i=1,N
x(i)=float(i)
end do
y = func(N,x)
open(unit=20, file='test.dat')
do i=1,N
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
But note that this sort of function - applying the same operation to every element in array - is somewhat more nicely done with a Fortran elemental function, defined to work simply on a scalar and Fortran will automatically map it over all elements of an array for you:
module functions
contains
elemental double precision function f(x)
implicit none
double precision, intent(in) :: x
f = x**2
end function f
end module functions
Program function_as_an_array
use functions
implicit none
integer:: i
integer, parameter:: N=10
double precision:: x(N),y(N)
do i=1,N
x(i)=float(i)
end do
y = f(x)
open(unit=20, file='test.dat')
do i=1,N
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
The nice thing about this is that it will now work on scalars, and arrays of any rank automatically. Wherever possible, it's good to have the compiler do your work for you.
This is working for me:
Program function_as_an_array
implicit none
integer:: i
integer, parameter:: N=10
real*8 :: x(N),y(N),f(N)
interface func
function func(x,N) result(f)
implicit none
integer N
real*8:: x(N),f(N)
end function
end interface
do i=1,N
x(i)=float(i)
end do
f = func(x,N)
open(unit=20, file='test.dat')
do i=1,N
y(i)=f(i)
write(20,*) x(i),y(i)
end do
close(20)
Stop
End Program function_as_an_array
function func(x,N) result(f)
implicit none
integer i, N
real*8:: x(N),f(N)
do i=1,N
f(i)=x(i)**2
end do
end function
You need to:
use result for an array-valued return variable [edit] or specify func as real*8:: func(N). See the comments for details.
use an explicit interface for external functions (or a module which has an implicit interface, see Jonathan Dursi's answer )
Then, you can directly assign the return value of the function to the array.

gfortran associates wrong type-bound procedure

When we compile (gfortran 5.3 or 7.2) and run the following code, line 9 of the main.f03 ends up in a subroutine that is never called. Can anyone explain why?
main.f03:
program main
use minimalisticcase
implicit none
type(DataStructure) :: data_structure
type(DataLogger) :: data_logger
call data_structure%init()
call data_logger%init(data_structure)
end program
minimalisticcase.f03:
module minimalisticcase
implicit none
type, public :: DataStructure
integer :: i
contains
procedure, pass :: init => init_data_structure
procedure, pass :: a => beginning_of_alphabet
end type
type, public :: DataLogger
type(DataStructure), pointer :: data_structure
contains
procedure, pass :: init => init_data_logger
procedure, pass :: do_something => do_something
end type
contains
subroutine init_data_structure(self)
implicit none
class(DataStructure), intent(inout) :: self
write(*,*) 'init_data_structure'
end subroutine
subroutine beginning_of_alphabet(self)
implicit none
class(DataStructure), intent(inout) :: self
write(*,*) 'beginning_of_alphabet'
end subroutine
subroutine init_data_logger(self, data_structure)
implicit none
class(DataLogger), intent(inout) :: self
class(DataStructure), target :: data_structure
write(*,*) 'init_data_logger'
self%data_structure => data_structure
call self%do_something()
end subroutine
subroutine do_something(self)
implicit none
class(DataLogger), intent(inout) :: self
write(*,*) 'do_something'
end subroutine
end module
On line 40 of 'minimalisticcase.f03' we call 'do_something' of the DataLogger. But instead the 'beginning_of_alphabet' subroutin of DataStructure is executed!
Apparently one can fix this by changing line 13 in 'minimalisticcase.f03' from type(DataStructure), pointer :: data_structure to class(DataStructure), pointer :: data_structure.
But why?
This is a bug in gfortran. I posted it on Bugzilla as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82312. The error is now fixed on the GCC trunk.
A temporary workaround is to encase the pointer assignment in a select type, thusly:
select type (data_structure)
type is (DataStructure)
self%data_structure => data_structure
end select

UDDTIO reading: pointer being freed was not allocated

I'm trying to put together a minimal example for performing user-defined derived type input output in Fortran using ifort compiler version 15. The code posted below is able to read and write accordingly, however after "read" is done executing and while control is being returned to the main program the following error occurs:
(61586,0x7fff7e4dd300) malloc: *** error for object 0x10fa7bac4: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
The UDDTIO routines are called in the program as:
module mod_test
implicit none
type, public :: class_test
integer :: foo
contains
procedure, private :: write_test
procedure, private :: read_test
generic :: write(formatted) => write_test
generic :: read(formatted) => read_test
end type class_test
contains
subroutine write_test(dtv, unit, iotype, v_list, iostat, iomsg)
!
implicit none
!
class(class_test), intent(in) :: dtv
integer , intent(in) :: unit
character(*), intent(in) :: iotype
integer , intent(in) :: v_list(:)
integer , intent(out) :: iostat
character(*), intent(inout) :: iomsg
!
iostat = 0
!
write(unit,'(a,/)') '<foo>'
write(unit,*) dtv%foo
write(unit,'(/)')
write(unit,'(a,/)') '</foo>'
!
end subroutine write_test
subroutine read_test(dtv, unit, iotype, v_list, iostat, iomsg)
!
implicit none
!
class(class_test), intent(inout) :: dtv
integer , intent(in) :: unit
character(*), intent(in) :: iotype
integer , intent(in) :: v_list(:)
integer , intent(out) :: iostat
character(*), intent(inout) :: iomsg
!
read(unit,'(/)')
read(unit,*) dtv%foo
read(unit,'(/)')
read(unit,'(/)')
write(*,*) 'z'
end subroutine read_test
end module mod_test
program main
use mod_test
implicit none
type(class_test) :: test
test%foo = 5
write(*,*) 'writing'
open(unit=1, file='write.out', status='replace', action='write')
write(unit=1,fmt=*) test
close(unit=1)
write(*,*) 'reading'
open(unit=1, file='write.out', status='old', action='read')
read(unit=1,fmt=*) test
close(unit=1)
write(*,*) 'end'
end program main
The problem seems to be with the line break statements '(/)'.
Adding iostat=-1 to the read routine seems "solve" the problem. But why?
UDDTIO procedures are required to define the iostat dummy argument, so that the compiler's runtime can test for error and take the appropriate action.
Note that UDDTIO is a relatively recently implemented feature for that compiler. You need to be using the latest possible compiler version.
If I define the iostat dummy argument appropriately in the read and write UDDTIO procedures, your code runs for me with the current 17.0 beta.
Further UDDTIO issues should be fixed in the initial release of 17.0, which can't be too far away.

error #6404: This name does not have a type, and must have an explicit type - using function in subroutine

I am using Fortran 90 and the Intel compiler.
I am very confused using a function in a subroutine. My code is (I deleted everything unimportant):
program test
INTEGER :: seed=5
REAL :: nor_ran_number1, nor_ran_number2
CALL Box_Muller_transform(seed,nor_ran_number1,nor_ran_number2)
end program test
double precision function grnd(SEED)
grnd=5
return
end
SUBROUTINE Box_Muller_transform (seed,nor_ran_number1,nor_ran_number2)
implicit none
INTEGER, INTENT(in) :: seed
REAL, INTENT(out) :: nor_ran_number1, nor_ran_number2
nor_ran_number1 = grnd(seed)
nor_ran_number2 = grnd(seed)
end SUBROUTINE Box_Muller_transform
The compiler returns:
error #6404: This name does not have a type, and must have an explicit
type. [GRND]
nor_ran_number1 = grnd(seed)
------------------^
I found this and understand that the function "grad" is not visible inside "Box_Muller_transform". However then I would expect the following code to produce the same error:
program test
INTEGER ::a=5, b
call sub(a,b)
write(*,*) b
end program
SUBROUTINE sub(a,b)
INTEGER, INTENT(in) ::a
INTEGER, INTENT(out) ::b
b = fun(a)
end subroutine sub
function fun(a)
INTEGER :: fun
INTEGER :: a
fun = a*a
end function fun
But this is working.
I would be very happy if someone could point out the difference and explain the simplest way to solve this problem.
Functions must have their return value defined. Since you are using implicit none in your first example, the type of the return value of grnd must be defined explicitly:
SUBROUTINE Box_Muller_transform (seed,nor_ran_number1,nor_ran_number2)
implicit none
INTEGER, INTENT(in) :: seed
REAL, INTENT(out) :: nor_ran_number1, nor_ran_number2
double precision :: grnd
nor_ran_number1 = grnd(seed)
nor_ran_number2 = grnd(seed)
end SUBROUTINE Box_Muller_transform
In the second example, you have not specified implicit none in sub, therefore fun is assumed to be of (implicit) type real. The compiler seems to silently cast this to integer.

Keyword OPTIONAL in TYPE in Fortran does not work

I try the following codes, and find the OPTIONAL keyword does not work. The compile is ok, but the runtime error will prompt.
I know usually the INTERFACE should be used in the module to provide enough information for the routines. I also try that, but failed to finish the compile no matter where I put the INTERFACE.
I have read some codes which use OPTIONAL in the TYPE declaration. https://www.pgroup.com/lit/articles/insider/v3n1a3.htm
Now I am using intel visual fortran, so is there any difference?
module testA_m
implicit none
type :: onion_c
contains
procedure :: testA
end type
contains
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
write(*,*) a,b
end subroutine
end module
program main
call testIt()
end program
subroutine testIt()
use testA_m
implicit none
type(onion_c) :: onion
real*8 :: c1
real*8 :: c2
c1 = 1.0d0
c2 = 2.0d0
call onion.testA(c1)
end subroutine
Well, you are trying to print b, which is not passed to the subroutine. Hence the access violation.
You should check for b first:
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
if ( present(b) ) then
write(*,*) a,b
else
write(*,*) a
endif
end subroutine
Maybe I need another variable for the real operation. Like the following.
I am still looking forward the better solution to use b directly.
subroutine testA(this, a,b)
implicit none
class(onion_c) :: this
real*8 :: a
real*8, optional :: b
real*8 :: bUsed
if ( present(b) ) then
bUsed = b
write(*,*) a,bUsed
else
bUsed = 2.00d0
write(*,*) a,bUsed
endif
end subroutine
Because Fortran does not support a program like
subroutine testA( this, a, b=10.0d0 )
I usually define a macro like the following in a common header file
#define _optval_(x,xopt,default) x = default; if (present(xopt)) x = xopt
and then use it at the top of a subroutine like
subroutine testA(this, a,b_)
class(onion_c) :: this
real*8 :: a
real*8, optional :: b_
real*8 b
_optval_( b, b_, 10.0d0 ) !! use only b from here on
Although this is not essentially different from writing several IF constructs, I feel it is a bit more convenient (at least for simple variables) because no need to worry about whether b is optional or not in the subsequent code. (But frankly, I hope Fortran2020 or so will support a syntax like the first example...)