How to use a function inside a subroutine in Fortran? - fortran

Could anyone please tell me why this simple program give me a segmentation fault?
I'm using gfortran, and I need to use a function inside a subroutine.
program tst
implicit none
real z,x,y
x=10.
y=2.
call s(10.,10.,z)
print*,z
end program
real function c(x,y)
implicit none
real x, y
c = x*y
return
end
subroutine s(x,y,z)
implicit none
real x, y
real z
real c
z = c(x,y)
end

Better to put your procedures into a module so that their interfaces will be known to each other and any procedure or program useing the module:
module MyStuff
contains
function c(x,y)
implicit none
real :: c
real :: x, y
c = x*y
return
end
subroutine s(x,y,z)
implicit none
real :: x, y, z
z = c(x,y)
end
end module MyStuff
program tst
use MyStuff
implicit none
real z,x,y
x=10.
y=2.
call s(10.,10.,z)
print*,z
end program
It works, giving answer 100.

Related

How to use allocatable arrays in Fortran subroutines?

Let me just preface this by saying that I am very new to Fortran but familiar with Python. My research project however requires me to use some pre-written Fortran code, which at this moment wont compile on my pc. I am trying to understand why.
The actual code I am trying to compile is very long and probably not very illuminating, but I think I have managed to come up with a minimal example of where I think the issue is. Let's say I have a very simple module and subroutine as follows,
module arraycheck
implicit none
real*8, allocatable, dimension(:) :: x
contains
subroutine fillx
real*8, allocatable, dimension(:) :: x
allocate(x(5))
x(1) = 1
x(2) = 2
x(3) = 3
x(4) = 4
x(5) = 5
print*, x
end subroutine fillx
end module arraycheck
which I expect to simply create an array x, which when the subroutine fillx is called fills the array with the integers 1 to 5. My actual source contains something conceptually similar to this. Now I also have a main program as follows,
program main
use arraycheck
print*, x
call fillx
print*,x
end
My idea here would be that on the first print statement the variable x is still unallocated, so print returns nothing, and then on the second print statement x has been filled, so it should return the filled array.
However on both print statements nothing is returned. Now in my original source code something similar happens, which causes runtime to throw an error that an unallocated array was passed somewhere as an actual argument, which should have been allocated. It seems like the exact same thing happens as in my small example here.
So my question is, is the behaviour that I observe in my example here expected? And if it is, how can I alter the code to make it work in the way that I would want it to? If I know this I might better understand why the actual source doesn't work.
Just in case it is relevant, I am using gfortran on ubuntu.
Thanks!
You have too different xs. They do not have anything in common. One a module array and one array local to the subroutine. When you allocate the local array in the subroutine, it does not do anything to the other array in the module.
Also, you cannot print array that is not allocated. That is not standard conforming (undefined behaviour). Anything can happen. You should definitely enable all compiler checks when diagnosing problems. The compiler should complain about your code with those checks.
Remove the local array declaration and avoid referencing unallocated variables. Module procedures have access to module variables through host association.
module arraycheck
implicit none
real*8, allocatable, dimension(:) :: x
contains
subroutine fillx
allocate(x(5))
x(1) = 1
x(2) = 2
x(3) = 3
x(4) = 4
x(5) = 5
print*, x
end subroutine fillx
end module arraycheck
program main
use arraycheck
call fillx
print*,x
end
Also, real*8 is not standard Fortran, it is a non-standard extension. Fortran 90 and later uses the kind system instead.
Here are some other things which might be helpful - shown in UPPERCASE.
module arraycheck
USE ISO_C_BINDING, ONLY : C_Int32_t, C_DOUBLE
implicit none
PRIVATE
real(KIND=C_DOUBLE), allocatable, dimension(:), PUBLIC :: x
PUBLIC Creation_X, Destruction_X, FillX
contains
subroutine Creation_X(n)
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
INTEGER(KIND=C_Int32_t), INTENT(IN) :: n
allocate(x(n))
RETURN
end subroutine Creation_X
subroutine Destruction_X
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
IF(ALLOCATED(X)) DEALLOCATE(X)
RETURN
end subroutine Destruction_X
subroutine fillx
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
INTEGER(KIND=C_Int32_t) :: N
DO I= 1, SIZE(x)
x(I) = I
ENDDO
RETURN
end subroutine fillx
end module arraycheck
program main
use arraycheck
CALL Creation_X(5)
call fillx
print*,x
CALL Destruction_X
end

How to make a generic procedure pointer in Fortran?

I am a low level Fortran programmer. I am trying to make subroutines as generic as possible and I wonder if I can send an information of which subroutine another subroutine should acces from a given information in the main program. For instance, if I have:
program main
use test
implicit none
real(8) X
end program main
And:
module test
contains
subroutine A (X)
real(8) X
X = 2*X
end subroutine A
subroutine B (X)
real(8) X
X = 3*X
end subroutine B
end module test
I would like to, given the subroutine name 'A' or 'B' in the main program, transfer this to a third subroutine C inside the module test, which in turn would make some calculations and use the transferred name to choose between A and B in its calculations.
I know if I build the calculations of that subroutine C inside the main program, I can use a procedure pointer to access either A or B subroutines. However, I need to have the subroutine C. So I guess I will have a subroutine C with built in procedure pointer and it will take the name given in the main program as an argument. But I do not know how to do that. Neither if it is possible. If it is not, is there any other way? I do not know, maybe the subroutine C reading a txt file associating the read name to the procedure pointer. But, how?
Thank you, in advance!
I think that what you want is this: you first define subroutines A and B
module ab_m
implicit none
contains
subroutine A(X)
real, intent(inout) :: X
X = 2 * X
end subroutine A
subroutine B(X)
real, intent(inout) :: X
X = 3 * X
end subroutine B
end module ab_m
Then subroutine C uses a dummy procedure, specified by an interface,
module c_m
implicit none
contains
subroutine C(sub,y)
interface
subroutine sub(p)
implicit none
real, intent(inout) :: p
end subroutine sub
end interface
real, intent(inout) :: y
y = y + 1
call sub(y)
end subroutine C
end module c_m
and the main program chooses what procedure to use in C:
program p
use ab_m
use c_m
implicit none
real :: z(2)
z = 1.0
call C(B, z(1))
call C(A, z(2))
write(*,*) z ! writes 6.0, 4.0 [ (1+1)*3, (1+1)*2) ]
end program p

Calling a subroutine within another subroutine [duplicate]

This question already has answers here:
Wrong result when using a global variable in Fortran
(2 answers)
Closed 5 years ago.
I am having some issues calling subroutines. First of all, am I allowed to call a subroutine within an IF statement?
IF (...) THEN
...
ELSE
CALL sub1(...)
END IF
Second question. Sub1 calls sub2 within it self. Then sub2 has an input from the main program, lets say x.
MODULE mod1
...
CONTAINS
SUBROUTINE sub1(w)
IMPLICIT NONE
INTENT(OUT) :: w
REAL :: x, z
CALL sub2(x, z)
w = z + 1
END SUBROUTINE sub1
SUBROUTINE sub2(x, z)
IMPLICIT NONE
INTENT(IN) :: x
INTENT(OUT) :: z
z = x + 1
END SUBROUTINE sub2
END MODULE mod1
PROGRAM prog
USE mod1
IMPLICIT NONE
IF (...) THEN
...
ELSE
x = y
CALL sub1(w)
x = w + y
END IF
END PROGRAM prog
NOTE: The addition between variable isn't the exact mathematical operation taking place
Basically every variable depends on each other, but the x = y is the initial condition which I think is the only way this could work. It seems that the sub2 isn't picking up on the initial x = y, which then gives its value to sub1, when called from sub1. So maybe I don't understand how the variables are being passed around. The errors I am getting is not with compiling but a run time error which leads me to the line where I call sub2 within sub1. Any help is much appreciated.
Please use implicit none at the beginning of all your programs and modules (only USE statements go before it), and then declare all variables explicitly.
While it's perfectly fine to call your subroutines the way you did, you have to take into consideration the scope of the variables.
In your example, sub1 does not have access to the main program's x and y as they're local to the main program.

I cannot work out the error in the script

I am very new to programming and I cannot debug my program. Whenever I run it it gives the same error:
return type mismatch of function f at (1)
My code is:
real function F(x)
implicit none
real:: x
F=exp(-x)-x
end function
program easycod
implicit none
real::xl,xu,xr,fu,test,xrold,fl,fr
integer ::i
do i=1,50
xr=xrold
xr=(xl+xu)/2.0
fr =F(xr)
fl =F(xl)
test=fl*fr
IF (test>0.0) then
xl=xr
fr=fl
else if (test<0.0) then
xu=xr
end if
if (test==0.0) exit
print*,xr
end do
end program
There are a few things wrong with your code.
First, you are getting a compiler error because you haven't declared your function F in your program:
program easycode
implicit none
real :: xl, xu, xr, fu, test, xrold, fl, fr
real :: F ! <----------------- Add this line
integer :: i
Then you are assigning xr twice, which makes the first one unnecessary. Finally, xold, xl and xr are not initialized and can therefore be given any value the compiler would like.

Pass real part of a complex array to a subroutines in fortran

Is it possible to pass real part of a complex array to a subroutine in Fortran without storing the real part in another array and pass that? e.g. instead of
Z = complex array;
X = real(Z)
call foo(X)
Do the following
Z = complex array
call foo(real(Z))
This gives me a compiler error! I am using an intel compiler ifort.
Sure, it works:
module testmod
implicit none
integer, parameter :: dp = kind(1.0d0)
contains
subroutine realsub(array)
real(dp), intent(in) :: array(:)
print *, array
end subroutine realsub
end module testmod
program testprog
use testmod
implicit none
complex(dp) :: array(3)
array(:) = [ (1.0_dp, 1.0_dp), (3.0_dp, 2.0_dp), (-1.0_dp, 3.0_dp) ]
call realsub(real(array))
end program testprog