Fortran compiling error Two main programs - fortran

I've been trying to write this program for fortran where the pressure of a gas is calculated using the Van der Waals equation and everytime I've scrapped the entire code and started over because everything I do comes back with an error, even when I try using answers from other questions. I'm new to fortran and I know my syntax is probably all over, if someone could just please tell me where I'm going wrong it would be greatly appreciated.
!Named program EquationOfState
program EquationOfState
implicit none
real :: pressure
write(*,*) 'pressure of Ideal Gas = '
write(*,*) 'pressure calculated with Van der Waals equation = '
end program EquationOfState
!Prompt user to input values for density == d, and temperature == t
write(*,*) "Enter density of gas"
read(*,*) d
write(*,*) "Enter temperature conditions"
read(*,*) t
write(*,*) "The pressure of the gas is", pressure
function pressure(d, t)
real(kind=4) :: pressure_IdealGas
real, intent(in) :: d, t
real, parameter :: R = 286.9_4
pressure = d * R * t
end function pressure
with this error
program EquationOfState
1
HWL_4.f90:14.36:
write(*,*) "Enter density of gas"
2
Error: Two main PROGRAMs at (1) and (2)

Your lines:
!Prompt user to input values for density == d, and temperature == t
write(*,*) "Enter density of gas"
read(*,*) d
write(*,*) "Enter temperature conditions"
read(*,*) t
write(*,*) "The pressure of the gas is", pressure
are outside of any program or function. You should at least move the end program statement behind these lines.
After you will do that you will realize there is no way to call your function from the main program as the variable pressure shadows the external function pressure(). You will have to rename one of them.
Also, your function is ill-formed, it is named pressure, but you declare something called pressure_IdealGas inside.
So you probably wanted:
function pressure_IdealGas(d, t)
implicit none
real :: pressure_IdealGas
real, intent(in) :: d, t
real, parameter :: R = 286.9_4
pressure_IdealGas = d * R * t
end function pressure_IdealGas
and in the main program you wanted to call this function:
pressure = pressure_IdealGas(d, t)
write(*,*) "The pressure of the gas is", pressure
Notice the implicit none in the function. It is important to use it there, because the function is external and the implicit none in the program does not affect it.
The previous should make it work, but it is better not to use external functions and external subroutines. In very simple program, you can make the function internal by placing it between the keyword contains and end program but in serious programs you want to place it into a module:
module gas_functions
implicit none
contains
function pressure_IdealGas(d, t)
real :: pressure_IdealGas
real, intent(in) :: d, t
real, parameter :: R = 286.9_4
pressure_IdealGas = d * R * t
end function pressure_IdealGas
end module
program EquationOfState
use gas functions
implicit none
...
Note that one implicit none per program is enough.
Read Correct use of modules, subroutines and functions in fortran for more.
Finally, there is no reason for the real(kind=4) in the function declaration. For compatibility, if you use just real everywhere, stick with it. The hardcoded number 4 is not a good idea for other reasons, see Fortran 90 kind parameter

Related

When passing function name as argument, the function does not take array as input [duplicate]

This question already has answers here:
How to pass array to a procedure which is passed as an argument to another procedure using Fortran
(2 answers)
Closed 1 year ago.
I'm writing a subroutine that can take function names are argument.
In my example, it is call call_test(ga), where ga is a function ga(x).
My old practice works fine if x is a scalar.
The problem is the program failed if x is an array.
The minimal sample that can reproduce the problem is the code below:
module fun
implicit none
private
public :: ga, call_test
contains
subroutine call_test(fn)
double precision,external::fn
double precision::f
double precision,dimension(0:2)::x0
x0 = 0.111d0
print*,'Input x0=',x0
print*,'sze x0:',size(x0)
f = fn(x0)
print*,'fn(x0)=',f
end subroutine call_test
function ga(x) result(f)
double precision,dimension(0:) :: x
double precision::f
print*,'size x inside ga:',size(x)
print*,'x in ga is:=',x
f = sum(x)
end function ga
end module
program main
use fun
call call_test(ga)
end program main
Using latest ifort, my execution result is:
Input x0= 0.111000000000000 0.111000000000000 0.111000000000000
sze x0: 3
size x inside ga: 140732712329264
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
a.out 000000010C6EC584 Unknown Unknown Unknown
libsystem_platfor 00007FFF20610D7D Unknown Unknown Unknown
a.out 000000010C6C62B2 _MAIN__ 32 main.f90
a.out 000000010C6C5FEE Unknown Unknown Unknown
Using gfortran the result is
Input x0= 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 0
x in ga is:=
fn(x0)= 0.0000000000000000
My question is why is this, and how to make it work. A functional code solution based on my code is highly appreciated.
#IanBush is right in his comment. You need an explicit interface as the function argument takes an assumed-shape dummy argument. Since you have some other deprecated features in your code, here is a modern reimplementation of it in the hope of improving Fortran community coding practice,
module fun
use iso_fortran_env, only: RK => real64
implicit none
private
public :: ga, call_test
abstract interface
function fn_proc(x) result(f)
import RK
real(RK), intent(in) :: x(0:)
real(RK) :: f
end function fn_proc
end interface
contains
subroutine call_test(fn)
implicit none
procedure(fn_proc) :: fn
real(RK) :: f
real(RK) :: x0(0:2)
x0 = 0.111_RK
write(*,"(*(g0,:,' '))") 'Input x0 =',x0
write(*,"(*(g0,:,' '))") 'sze x0:',size(x0)
f = fn(x0)
write(*,"(*(g0,:,' '))") 'fn(x0) =', f
end subroutine call_test
function ga(x) result(f)
real(RK), intent(in) :: x(0:)
real(RK) :: f
write(*,"(*(g0,:,' '))") 'size x inside ga:',size(x)
write(*,"(*(g0,:,' '))") 'x in ga is:',x
f = sum(x)
end function ga
end module
program main
use fun
call call_test(ga)
end program main
Note the use of the abstract interface. The import statement merely imports the symbol RK for usage within the abstract. Without it, you will have to use iso_fortran_env to declare RK as real64. Do not use double precision, it is deprecated and does not necessarily mean 64bit real number. Also, note the conversion of 0.111d0 to 0.111_RK. Also, I strongly recommend not using single-letter variable names. They are ugly, error-prone, and non-informative. Modern Fortran allows variable names up to 63 characters long. There is no harm in having long but descriptive variable names. Here is the code output,
$main
Input x0 = 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 3
x in ga is: 0.11100000000000000 0.11100000000000000 0.11100000000000000
fn(x0) = 0.33300000000000002

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

Check values of local variables in subroutines from outside

How do you check values in Fortran like in Matlab? For example in the little program under, why does it show c=0 in main when it is c=36 in the subroutine testing? How do you make it so c=36 in the main program?
Can you call on the value c in some sort of way? I understand that in the main program the variable c is either undefined or has value 0, but is there a way to save the value of c in the subroutine so you can use it again in other subroutines, without calculating it again?
When the program is quite large it is handy to check values as you go.
program main
use test
implicit none
integer :: a,b,c
call testing(a,b)
write(*,*)'Test of c in main program',c
end program main
module test
implicit none
contains
subroutine testing(a,b)
integer :: a,b,c
a=2
b=3
c=(a*b)**a
write(*,*)'Value of c in subroutine',c
end subroutine testing
end module test
It is important to learn about scope in programming languages.
Every name (identifier) has only a limited range of validity.
If you declare some variable inside a subroutine
subroutine s
integer :: i
end subroutine
than the i is valid only in that subroutine.
If you declare a variable in a module
module m
integer :: i
contains
subroutines and functions
end module
then the i is valid inside all those subroutines and functions and also in all program units that use that module.
However, that does not mean that you should declare the variable in the module and just share it. That would be more or less a global variable. This is reserved only for certain cases, where that is necessary, but not for getting results out of your subprograms.
If your subroutine just computes something and you want to get the result of that computation you have two possibilities:
1. pass it as an additional argument, which will be defined by the subroutine
subroutine testing(a, b, c)
integer, intent(in) :: a, b
integer, intent(out) :: c
c = (a*b) ** a
end subroutine
you then call it as
call testing(2, 3, c)
print *, "result is:" c
2. Make it a function
function testing(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = (a*b) ** a
end function
and then you can use directly
c = testing(2, 3)
print *, "result is:", c
or just
print *, "result is:", testing(2, 3)
This is the desired behaviour. Basically the calling routine should know nothing about the subroutine except for how to call it and what to get back. This is called encapsulation.
You can make variables accessible to the calling routine by declaring it in the module itself, and not in the subroutine:
module test
implicit none
integer :: c
contains
subroutine testing(a, b)
implicit none
integer :: a, b
a = 2
b = 3
c = (a*b) ** a
write(*, *) "Value of c in the subroutine: ", c
end subroutine testing
end module test
program main
use test
implicit none
integer :: a, b
call testing(a, b)
write(*, *) "Test of c in the main program: ", c
end program main
Note that you must not declare c in the main program, as it will get the variable from the module.
You could also use a COMMON block, but modules are far superior.

Need to read a file and assign its content to a function

I am a novice to Fortran 90 and stack overflow, and I have a simple question (I think).
I have a file, named Eq1, containing the following Fortran mathematical expression:
x**2
The objective is to input this expression from the file, and use it in a function inside fortran. I have tried the following
REAL FUNCTION f(x)
IMPLICIT NONE
REAL (kind =8), INTENT(IN) :: x
open(1,file = 'Eq1',status='old')
read(1,*) f
close(1)
END FUNCTION f
and when I do
print *, f(0.1d+0)
inside the main program, I get the following error message:
Fortran runtime error: Bad real number in item 1 of list input
Thanks for the help!
Cheers
Fortran does not have a string evaluation functionality as some script languages, e.g. Python's eval().
You have to write your own string to expression parser, which is not a trivial task.
One simple workaround is to call Python's eval() with SYSTEM and use it's output:
REAL FUNCTION f(x)
IMPLICIT NONE
REAL (kind =8), INTENT(IN) :: x
CHARACTER(LEN=200) EXP
CHARACTER(LEN=400) CMD
open(1,file = 'Eq1',status='old')
read(1,*) exp
close(1)
WRITE(CMD, "(A,f14.7, A, A, A)") 'python -c "x=',x,';print ',trim(exp), '" > out.txt'
CALL system(CMD)
open(2,file = 'out.txt',status='old')
read(2,*) f
close(2)
END FUNCTION f
program calc
implicit none
real f
print *, f(0.1d+0)
print *, f(2.0d+0)
print *, f(3.0d+0)
print *, f(4.0d+0)
end program calc
Output:
9.9999998E-03
4.000000
9.000000
16.00000