FORTRAN 95: OPTIONAL statement does not work (using FTN95 and Plato) - fortran

I am having a problem with the OPTIONAL statement in functions and subroutines with Fortran 95. Currently I am using Silverfrost's Plato and their FTN95 compiler (in "Release Win32" mode). After trying to implement the OPTIONAL statement in a more complex program I am writing, I created a very simple program to test it. Here is the code:
program TEST
implicit none
integer :: a=1, b=2
call Z(a,b)
call Z(a)
call Z(b)
end program TEST
subroutine Z(x,y)
implicit none
integer :: x
integer, optional :: y
if (present(y)) then
write(*,*) x, y
else
write(*,*) x
endif
end subroutine Z
I expected the following result displayed on the screen:
1 2
1
2
Well, the code compiles, although I get a warning (673) that "SUBROUTINE Z has been called with too few arguments". After executing it, I get on my screen:
1 2
and then an "Access violation" error message. Can somebody understand what is wrong here?
Thanks a lot!
Gilberto

Try putting the subroutine in a module, like so:
module testoptional
contains
subroutine Z(x,y)
implicit none
integer :: x
integer, optional :: y
if (present(y)) then
write(*,*) x, y
else
write(*,*) x
endif
end subroutine Z
end module testoptional
program TEST
use testoptional
implicit none
integer :: a=1, b=2
call Z(a,b)
call Z(a)
call Z(b)
end program TEST
Compiling and running then gives the expected result using gfortran and ifort.
The problem is in how the main program knows (or guesses) the interface to Z(x,y). In the code you provide, although the main program and the subroutine are in the same file, there's nothing explicitly telling the main program the interface - the calling sequence, including argument counts, types, etc - of Z. The first call is to Z(a,b), so it infers there's a subroutine out there somewhere that takes two parameters; then it tries calling it with one parameter, which fails.
Putting the subroutine in a module, then using the module (you could also use contains for a contained subroutine, or explicitly/manually providing the main program the interface using an interface block) then gives the main program the information it needs about the calling sequence - e.g., that there's an optional argument - and things work correctly.

Procedures with optional arguments must have explicit interfaces, so try giving one to Z. (E.g. just use the subroutine from a short module.)
I don't have this specific compiler on hand, but I've gotten an error when using the Cray compiler for cases like this.

Related

Code get compiled when include 'mpif.h' but failed when switch to use mpi

I am trying to switch to use mpi for some old fortran codes I have. I got some strange errors when compiling the code.
Error: There is no specific subroutine for the generic 'mpi_type_indexed' at (1)
when I try to switch to 'use mpi' in the code. If I use 'include 'mpif.h'' then the program got compiled and is able to run correctly.
I have written a compact example to verify the program. Both the code and my example are compiled under gcc/8.1.0 and openmpi/3.1.2.
program bt
use mpi
implicit none
!include 'mpif.h'
contains
subroutine read_me()
implicit none
integer :: my_n, my_disp, my_type
integer :: ierr
my_n = 2
my_disp = 4
call MPI_Type_indexed(1, my_n, my_disp, MPI_INTEGER, my_type, ierr)
end subroutine
end program
compile it with no flag: mpif90 bt.F90
With use mpi committed and include 'mpif.h' uncommitted, everything works fine.
With use mpi uncommitted and include 'mpif.h' committed, I got error says
bt.F90:23:67:
call MPI_Type_indexed(1, my_n, my_disp, MPI_INTEGER, my_type, ierr)
1
Error: There is no specific subroutine for the generic 'mpi_type_indexed' at (1)
As indicated in the comments the "problem" that has occurred is that because you have used the module rather than the include file an interface is now in scope, and the compiler can now detect that you are trying to call MPI_Type_indexed with incorrect arguments, as the 2nd and 3rd arguments should be arrays - take a look at https://www.mpi-forum.org/docs/mpi-3.1/mpi31-report/node79.htm#Node79 to see what the interface should be.
Looking at your example it looks as though the original author was assuming that a scalar and a 1 element array are the same thing - this is not the case as the former is rank 0 and the later rank 1. I say this as the first argument specifies how big the arrays should be, and in your case this has the value 1. Thus the 2nd and 3rd arguments should be single element arrays, rather than the scalars you have. The simplest solution, as these arguments are Intent( In ), is to put them in square brackets acting as an array constructor
call MPI_Type_indexed(1, [ my_n ], [ my_disp ], MPI_INTEGER, my_type, ierr)

Fortran Type mismatch in argument n at 1 passed REAL(8) to integer (4)

I'm having a problem with a fortran 77 project (Yes i know it's archaic, but my prof requres us to program in fixed form fortran)
So I'm having a problem with a subroutine, which should read an N dimension Vector, which should be a column. the code for this looks like: (its still an early draft for my homework, just trying to figure out how to call a subroutine the rest of the code will be done if i can compile this problem)
Program gauss
implicit double precision (A-H,O-Z)
!he directly asked for implicit typing
call Vread(V(N))
end program
Subroutine Vread(V,N)
Implicit double precision (A-H,O-Z)
dimension V(N)
read(*,*) (V(I),I=1,N)
return
end
So my problem is: If I try to compile it with gfortran gauss.exe -o gauss.f the compiler returns with error:
Type mismatch argument 'n' at(1); passed REAL(8) to Integer(4)
In your main program you write
call Vread(V(N)) ! this passes a rank-1 vector with N elements
but your subroutine is declared
Subroutine Vread(V,N) ! this requires 2 arguments
Change the call to
call Vread(V,N)
and let your professor know that the 21st Century arrived a while age. Note too that it is possible to write 21C Fortran in fixed-form. It doesn't make much sense, but might enable you to toe the line while developing in a more modern version of the language.
!he directly asked for implicit typing
I trust that you are in a jurisdiction where you do not pay directly for your education. If you are paying fees then demand more, you're being cheated.

Does fortran function pass by const reference?

I'm learning how to use functions in fortran and I came across several cases which made me believe that fortran function pass the argument by const reference. When I say "pass by const reference", I'm saying it in C++ sense. I searched online and didn't find related documents. The code which makes me believe fortran functions pass arguments by const reference is as follows.
program try
implicit none
real sq
real a,b
write(*,*) sq(2)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
sq=x**2
return
end
The output for this is
0.0000000E+00
4.000000
This result supports the idea that fortran functions pass arguments by reference, since sq(2) doesn't work. After this code, I put a new line x=x+1 inside the definition of sq. The code looks like
program try
implicit none
real sq
real a,b
write(*,*) sq(2)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
x=x+1
sq=x**2
return
end
This code does compile, but when I run it, it gives the following error
forrtl: severe (180): SIGBUS, bus error occurred
Image PC Routine Line Source
a.out 00000001000014DB Unknown Unknown Unknown
a.out 000000010000144C Unknown Unknown Unknown
Stack trace terminated abnormally.
I guess I got this error because I can't modify the argument inside the function definition, which makes me believe that the argument is passed by const reference. The compiler I'm using is ifort 12.0.0. I'm running it on Mac OS X 10.6.8. Can anyone tell me whether my guess is true?
Update: According to the comment of #Jean, after modifying sq(2) to sq(2.0). The first example will work, the second one still gives the same error. The modified version of the first example is
program try
implicit none
real sq
real a,b
write(*,*) sq(2.0)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
sq=x**2
return
end
The output is
4.000000
4.000000
I don't know why this simple modification will work. Hopefully someone can clarify for me.
As pointed out in the comments, you should use explicit interfaces. Then the compiler is able to check argument types. There are different possibilities to do that. For larger programs use modules, for smaller ones, you can include your procedure in the main program by using the contains keyword.
Here is a slightly modified version of your code:
program try
implicit none
real a,b
write(*,*) sq(2.0)
a=2
write(*,*) sq(a)
contains
real function sq(x)
real, value :: x
x=x+1
sq=x**2
return
end
end program
What's new?
the function is included in the main program with the contains keyword. When doing so, you don't have to declare sq like you did before in your third line. Also, the compiler can now check the argument type. Try to write 2 instead of 2.0 and see what happens.
You are right about the references. In Fortran arguments are passed by reference. If your argument is not a variable but just a number, then you can not change it within the procedure because it is constant. If you want variables to be passed by value, use the value keyword.

Syntax Error/Two main programs Fortran

I'm trying to compile this program for monte carlo importance sampling, but i'm running into a couple issues:
1 - Error: Syntax error in data declaration at (1), referring to the following line, where the (1) is placed right after and beneath the word "function".
real function f(x)
2 - Error: Two main PROGRAMS at (1) and (2), referring to these two lines
program importance1
and
t=0.0
.
The sample code follows. There are more lines of code in the program, but I don't think there are any problems so I've just posted this first segment.
program importance1
implicit none
real mean_value,t,ta,rr
real x,xtrials,s_square_old,s_square_new,std_dev,std_error,frac_stand_dev
integer k
real :: alpha=0.90
integer :: trials=50
xtrials=trials
real function f(x)
f=exp(x)
return
end
real function g(x)
g=(alpha/(exp(alpha)-1.))*exp(alpha*x)
return
end
t=0.0
s_square_old=0.0
Not sure where you got the idea to do that, but it looks like you are defining functions in the middle of your code, which is the wrong place. In Fortran, the functions go in a separate MODULE or at the end of the program under a CONTAINS block:
program importance1
implicit none
real :: mean_value,t,ta,rr
real :: x,xtrials,s_square_old,s_square_new,std_dev,std_error,frac_stand_dev
integer :: k
real :: alpha=0.90
integer :: trials=50
xtrials=trials
t=0.0
s_square_old=0.0
contains
real function f(x)
real :: x
f=exp(x)
end function
real function g(x)
real :: x
g=(alpha/(exp(alpha)-1.))*exp(alpha*x)
end function
end program

Why does this Fortran random number generator cause a segmentation fault?

I took the following function ran0 from the text Numerical Recipes. I wrote my own program random2 to call ran0.
Why does this code cause a segmentation fault? Thanks for your time.
FUNCTION ran0(idum)
INTEGER idum,IA,IM,IQ,IR,MASK
REAL ran0,AM
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,MASK=123459876)
INTEGER k
idum=ieor(idum,MASK)
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
ran0=AM*idum
idum=ieor(idum,MASK)
return
END FUNCTION
PROGRAM random2
IMPLICIT NONE
REAL :: ran0
PRINT *, ran0(6)
END PROGRAM
You pass the constant 6.0 to your function as the IDUM dummy argument. You then (attempt to) modify this argument with lines such as idum = ieor(...) etc. You are effectively trying to modify a constant.
The value of 6.0 has been fixed for some time now - long enough that most programmers expect to find it somewhere between 5.0 and 7.0. Please don't try and change it.
Extending the answer of IanH, if you partially rewrite this in more modern Fortran:
module my_subs
contains
FUNCTION ran0(idum)
INTEGER, intent(inout) :: idum
INTEGER IA,IM,IQ,IR,MASK
REAL ran0,AM
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,MASK=123459876)
INTEGER k
idum=ieor(idum,MASK)
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
ran0=AM*idum
idum=ieor(idum,MASK)
return
END FUNCTION
end module my_subs
PROGRAM random2
use my_subs
IMPLICIT NONE
!REAL :: ran0
PRINT *, ran0(6)
END PROGRAM
Identifying the argument as being both input and output with the intent(inout) attribute and placing the subroutine in a module and using that module to allow the compiler to check the consistency of the arguments, the compiler is likely to find this problem. For example, gfortran outputs:
PRINT *, ran0(6)
1
Error: Non-variable expression in variable definition context (actual argument to INTENT = OUT/INOUT) at (1)