There is a F77 code, slightly modified from me. The code calls a particular routine, but it seems that compilation does not stop (and I believe there is no problem with loops). This makes me wonder why this might happen.
Second i cannot really understand what the output of that routine will be. Can anyone help here?
this is the section of the code that calls the routine/function. By working a MWE,
integer, parameter:: nf=101, ns=7, nas=427, na=61, nxm=3
integer:: i,j,k,
allocate(xf(nf), xa(na))
allocate(absa(nxm,na-1), wgta(nxm,na-1),absf(nxm,nf-1), wgtf(nxm,nf-1))
do 150 i=1,na-1
call qgausl (nxp(i), xa(i), xa(i+1), absa(1,i), wgta(1,i))
150 continue
do 160 i=1,nf-1
call qgausl (nxp(i), xf(i), xf(i+1), absf(1,i), wgtf(1,i))
160 continue
And this is the routine
subroutine qgausl(n,x1,x2,x,w)
implicit none
integer:: n, m
real*8:: xl,x2, x1, xm, eps, z, p1,p2,p3, pp, z1
real*8:: x(n), w(n)
eps=1.0e-8
m=(n+1)/2
xm=0.5*(x2+x1)
xl=0.5*(x2-x1)
do 12 i=1,m
z = cos(3.141592654*(i-.25)/(n+.5))
1 continue
print*, z
p1 = 1.0
p2 = 0.0
do 11 j=1,n
p3 = p2
p2 = p1
p1 = ((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j
11 continue
pp = n*(z*p1-p2)/(z*z-1.0)
z1 = z
z = z1-p1/pp
if (dabs(z-z1).gt.eps) go to 1
x(i) = xm-xl*z
x(n+1-i) = xm+xl*z
w(i) = 2.0*xl/((1.0-z*z)*pp*pp)
w(n+1-i) = w(i)
12 continue
return
end subroutine
For your information and if I made a good job, i translated this into Matlab and seems that there is no problem with the loops in the routine.
A bit of an extended comment:
One thing I notice is you tagged this as fortran77 but in fact it will not compile if this is indeed an f77-type external subroutine (ie. not in a module/contains construct) because you use implicit none but fail to declare i in the subroutine.
( There are numerous other post-f77 syntax features in there as well. )
So...assuming this subroutine is internal (ie. lives within contains in the calling routine) the i here :
do 12 i=1,m
is the same i from the scope of the calling routine, ie. you are effectively using the same variable for two nested loops.
This is obviously an illegal thing to do, and I must say I'm disturbed to see that gfortran silently compiles such and runs off in an endless loop.. (!?!)
I'd suggest moving the subroutine to a module or simply making it external if you think this is the case. Then the compiler will flag your failure to declare i
example
both gfortran and ifort compile this without warnings:
implicit none
integer j
do j = 1,2
call x()
enddo
contains
subroutine x()
implicit none
do j=3,4
write(*,*)j
enddo
end subroutine
end
the gfortran version runs away endlessly printing 3,4,3,4. The intel version writes 3,4 just once (ie not what you might expect either)
declaring j in the subroutine fixes it of course..
Related
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
I try to introduce complex-valued array and variables in Fortran. For the following code
program
integer :: i , j !two dimensional real array
real(dp) :: m1(3,2)
complex(dp) :: a1(3,2),a2(3,2), c0, c1
!assigning some values to the array numbers
c0 = (1.0_dp, 0.0_dp)
c1 = (0.000000001_dp, 0.0_dp)
do i=1,3
do j = 1, 2
a1(i,j) = c0*i*j
end do
end do
do i=1,3
do j = 1, 2
a2(i,j) = c0*i*j + c1
end do
end do
do i=1,3
do j = 1, 2
if (dabs( dreal(a1(i,j)) - dreal(a2(i,j))) > 1.e-6 then
write (*,*), 'warning',i,j, a1(i,j), a2(i,j)
end if
end do
end do
write (*,*), a1(1,1), a2(1,1)
end program
ifort gives me
complex(dp) :: a1(3,2), a2(3,2)
-----------^
why complex(dp) requires compile-time constant and how to fix it? Thank you.
The kind parameter dp must be a constant, see Fortran - setting kind/precision of a variable at run time
However, you do not have the same problem as in the link, you did not try to define dp at all! First, you must use IMPLICIT NONE, it is absolutely necessary for safe programming and the biggest problem with your code. Then it will tell you that the type of dp is not declared.
You just define the kind constant in one of the usual ways, as a constant. The most simple is:
program main
!NECESSARY!
implicit none
integer, parameter :: dp = kind(1.d0)
Note that I named the program main, you have to name your program. Or just omit the program.
More about defining real kinds can be found at Fortran 90 kind parameter
Another note: Forget dabs() and dreal(). dabs() is an old remnant of Fortran 66 and dreal() is not standard Fortran at all. Just use abs and either dble() or better real( ,dp).
I am new to Fortran and I am trying on the common block. My code is simple
program main
implicit double precision (p)
real * 8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end program main
function power(x)
implicit none
real * 8 :: power
real * 8 :: x, y
common /yvalue/ y
power = x ** y
end function power
It works but if I comment out the second line, which implicitly declares variables starting with p to be double precision, the compiler complains the following
Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))
I do get the point that the return value power is by default a single precision variable, but why declaring power as double precision in the function is not enough? And why writing real * 8 power in main would not work either?
When a procedure (function or subroutine) that you are trying to invoke in your code lays outside the body of your program and also is not part of any module, it's named an external function (or subroutine).
Fortran is a statically-typed language, so the types of all variables and functions must be known at compile-time. So, if you want to reference an external function in your program, there must be a way for the program to know its return type. You have 3 (bad) options for this, and I'll list them, starting from the worst:
WORST: Rely on an implicit-typing rule that happens to match the return type of the external function with the type associated with its identifier in the caller (as you did in your sample).
Why you shouldn't do that? Because it is cancer. It makes the meaning of the code obscure, you can't know what this name reference to. It may even look just like an array variable in some circumstances, instead of a function. Also, the compiler doesn't check argument conformance in this case, so if you don't have specific compiler options turned on, the code will fail at runtime, or worse, will give wrong results. Moreover, implicit-typing is very very rarely useful these days, most of the time it's an ask for trouble. Always use implicit none!
As you noted, by the default rules of implicit-typing, any variable with a name starting with p will be default real type (in your compiler, it is real(4)). As you declared the function result as real*8, that your compiler interpret as real(8) (see final note), the error arises.
BAD: Declare the function's name and type in the caller's specification area.
You'd do that just like you'd declare a variable, like this:
program main
implicit none
real*8 :: x, y, power
By the way, the attribute external may be applied to external procedures like yours. More than giving some properties to the procedure (can be passed as an actual argument, disambiguation from intrinsic procedures), it would make the origin of the identifier clearer.
program main
implicit none
real*8 :: x, y, power
external :: power
Why you shouldn't do that? There is no argument checking by the compiler either. This severely limits your options for communicating to external functions: the arguments cannot be assumed-shape, assumed-rank, polymorphic, parameterized, coarray, or be declared on the callee side as allocatable, optional, pointer, target, asynchronous, volatile or value; the return type cannot be an array, or pointer, or allocatable; the function cannot be passed as argument, be elemental and, if pure, can't be used in such contexts. And the reason for all this is the lack of an explicit interface.
ACCEPTABLE: Specify an interface for your external function in the caller.
Like this:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
This way, the compiler is able to know all details of declaration and all the restrictions I mentioned won't apply. Total freedom and code clarity!
Why you shouldn't do that? Because there is a better way, that is using modules! Well, it's totally ok to do this in contexts were you can't go for modules, e.g. when working with already existent large old code. The downside is that, you have almost the same code in two different places, and they must always match.
Bonus: BETTER: Use modules.
program main
use :: aux_module
implicit none
real*8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
contains
function power(x)
real*8 :: power
real*8 :: x, y
common /yvalue/ y
power = x ** y
end
end
Why you should definitely do that? Because with modules, interfaces are automatically and implicitly available (less code duplication, no restrictions); modules can be recompiled separately and updated without breaking code. Also, you can declare shared variables in the scope of the module and avoid using common declarations. An even better version of your code would be:
program main
use aux_module
implicit none
real*8 :: x
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
real*8 :: y
contains
function power(x)
real*8 :: power
real*8 :: x
power = x ** y
end
end
There is even the option to include your functions directly into your program, after contains. This is recommended only if you don't plan to reuse this function in other program units. #IanBush's answer covers this case.
Final note: take a look on this answer to see why the syntax real*8 is non-standard and should be avoided.
As stated in the comments simply declaring the function in not only its own scope but also the scope that it is called will solve your problem. However I also want to discourage you from using common, implicit typing, and the completely non-standard real*8. As such here is a version of your program in a more modern dialect
ian#eris:~/work/stackoverflow$ cat power.f90
Program power_program
Implicit None
Integer, Parameter :: wp = Selected_real_kind( 14, 70 )
Real( wp ) :: x, y
x = 3.0_wp
y = 3.0_wp
! Return type and kind of the function power in scope
! due to the implicit interface
Write( *, '( 3( a, 1x, f0.6, 1x ) )' ) &
'x =', x, 'y = ', y, 'x**y = ', power( x, y )
Contains
Pure Function power( x, y ) Result( r )
Real( wp ) :: r
Real( wp ), Intent( In ) :: x
Real( wp ), Intent( In ) :: y
r = x ** y
End Function power
End Program power_program
ian#eris:~/work/stackoverflow$ gfortran -std=f2003 -Wall -Wextra -O power.f90
ian#eris:~/work/stackoverflow$ ./a.out
x = 3.000000 y = 3.000000 x**y = 27.000000
ian#eris:~/work/stackoverflow$
I'm getting a weird error when compiling my simulation code written in Fortran 90, I was hoping to get some help by any chance. I'm using ifort version 18.0.3.
Before telling the problem, here's what I have that are working properly:
Below module prng is a pseudo-random number generator(it's in fortran 77 but I have tested it just in case any compatibility concerns, it works fine!):
module prng
implicit none
contains
real*8 function genrand_real( ir )
implicit real*8 (a-h,o-z)
integer, intent(inout) :: ir
parameter(da=16807.d0,db=2147483647.d0,dc=2147483648.d0)
ir = abs(mod(da*ir,db)+0.5d0)
genrand_real = dfloat(ir)/dc
return
end function genrand_real
end module prng
I also created a module in order to declare the seed:
module seed
implicit none
type mod_seed
integer :: seedvalue
end type mod_seed
end module seed
In order to use seedvalue, type(mod_seed) :: seedval needs to be declared first, then genrand_real(seedval%seedvalue) returns a real value in (0,1).
So far above mentioned are all working fine! Below is what I'm trying to implement, basically I adopted a gaussian deviate function, function gauss_dev() result(harvest), from Numerical recipes in Fortran (page 280), see the source code below:
module moves
use prng
use seed
implicit none
contains
function gauss_dev() result(harvest)
implicit none
real(kind=8) :: harvest
real(kind=8) :: rsq,v1,v2
real(kind=8), save :: g
logical, save :: gauss_stored = .false.
if (gauss_stored) then
harvest = g
gauss_stored = .false.
else
do
v1 = genrand_real(seedval%seedvalue)
v2 = genrand_real(seedval%seedvalue)
v1 = 2.0*v1-1.0
v2 = 2.0*v2-1.0
rsq = v1**2 + v2**2
if (rsq > 0.0 .and. rsq < 1.0) exit
enddo
rsq = sqrt(-2.0*log(rsq)/rsq)
harvest = v1*rsq
g = v2*rsq
gauss_stored = .true.
endif
end function gauss_dev
! also other subroutines that calls gauss_dev()
end module moves
The seedval%seedvalue is initialised by
subroutine read_iseed(seedval,IN_ISEED)
use prng
use seed
type (mod_seed), intent(inout) :: seedval
character(len=80) :: IN_ISEED
integer :: i
call system('od -vAn -N4 -td4 < /dev/urandom > '//trim(IN_ISEED))
open(unit=7,file=trim(IN_ISEED),status='old')
read(7,*) i
close(7)
seedval%seedvalue = abs(i)
return
end
When I compile the code, I get an error message: error #6404: This name does not have a type, and must have an explicit type. [SEEDVAL], this is expected as the seedvalue must be declared before calling!
Since the seedvalue gets reassigned in prng, intuitively I'd use intent(inout) option. And here's my fix:
module moves
use prng
use seed
implicit none
contains
function gauss_dev() result(harvest)
implicit none
type (mod_seed), intent(inout) :: seedval
real(kind=8) :: harvest
real(kind=8) :: rsq,v1,v2
real(kind=8), save :: g
logical, save :: gauss_stored = .false.
if (gauss_stored) then
harvest = g
gauss_stored = .false.
else
do
v1 = genrand_real(seedval%seedvalue)
v2 = genrand_real(seedval%seedvalue)
v1 = 2.0*v1-1.0
v2 = 2.0*v2-1.0
rsq = v1**2 + v2**2
if (rsq > 0.0 .and. rsq < 1.0) exit
enddo
rsq = sqrt(-2.0*log(rsq)/rsq)
harvest = v1*rsq
g = v2*rsq
gauss_stored = .true.
endif
end function gauss_dev
! also other subroutines that calls gauss_dev()
end module moves
However when I compile the code, I get error message:
error #6451: A dummy argument name is required in this context. [SEEDVAL]
type (mod_seed), intent(inout) :: seedval
I'm not certain what caused the error. But as I was randomly trying with intent()options, I accidentally found out that without specifying intent(), the code gets compiled WITHOUT errors, which is weird because I thought without specifying intent(), fortran compiler takes inout as the default option? But as a result of NOT specifying intent(), the simulation gets stuck in the do-loop:
do
v1 = genrand_real(seedval%seedvalue)
v2 = genrand_real(seedval%seedvalue)
v1 = 2.0*v1-1.0
v2 = 2.0*v2-1.0
rsq = v1**2 + v2**2
if (rsq > 0.0 .and. rsq < 1.0) exit
enddo
because seedval%seedvalue returns 0, which causes rsq constantly failing if (rsq > 0.0 .and. rsq < 1.0) exit condition.
Before posting this thread, I read Fortran intent(inout) versus omitting intent, I see the potential compatibility issue out there, but that's introduced since Fortran 2003 according to the thread.
Coming to the end I bear two questions: 1. In fortran 90, is there a difference between specifying intent(inout) and not specifying at all?
2. In regard to the error message when specifying intent(inout), what's the cause of it?
Any hint would be appreciated!
In fortran 90, is there a difference between specifying intent(inout) and not specifying at all?
Yes: already in the Fortran 90 standard, a dummy argument with intent(inout) needed to be definable, and this was not a requirement for dummy arguments without an intent attribute, see section 5.1.2.3 of the Fortran 90 standard.
Before posting this thread, I read Fortran intent(inout) versus omitting intent, I see the potential compatibility issue out there, but that's introduced since Fortran 2003 according to the thread.
Please read that thread more carefully, while they do discuss the issue citing Fortran 2003 references, at no point they say anything about this being introduced in the 2003 version of the standard.
In regard to the error message when specifying intent(inout), what's the cause of it?
When you did not specify the intent of seedval and you didn't list seedval as a dummy argument of the function, the compiler thought that seedval was a local variable and was happy with it. The moment you defined an intent for seedval, without listing it as a dummy variable, the compiler was naturally unhappy (intent can only be provided for dummy arguments), so it raised the error.
with/without having intent(inout) specified, code returns different results, any clue?
Maybe I am missing it, but can you please clarify where you initialize seedval%seedvalue? If you are using an uninitialized variable, that would easily explain why different compilations produce different values.
If I follow your description of the issue correctly (please correct me otherwise), your code only ran when either (a) seedval was not listed as a dummy argument of function gauss_dev, and it didn't have an intent attribute; or (b) seedval was listed as a dummy argument of the function and it had intent(inout).
The code had a very different behaviour in (a) and (b) because in (b) the component seedval%seedvalue had been appropriately initialized by your read_iseed subroutine, while in (a) seedval was a variable local to gauss_dev, which was being used by genrand_real before being initialised. In this case, the compiler was probably initialising seedval%seedvalue to zero in gauss_dev, and your genrand_real function returns zeroes (for both ir and genrand_real) when variable ir is zero at input, hence the infinite loop you described.
Note that multiple runs of a binary compiled following (b) will most likely produce different numerical results, since the system call you make within read_iseed
od -vAn -N4 -td4 < /dev/urandom
will usually return different integer values for your seed.
Why am I in an infinite loop?
PROGRAM tayls
USE kertoma
USE tforexp
IMPLICIT NONE
INTEGER :: n= 5
INTEGER :: i
REAL :: x
WRITE(*,*) "f1(x)= (e**x-1)/x"
DO i=1,10
x= 0.01*i
WRITE(*,*)x, (taylexp(x,n)-1)/x
END DO
END PROGRAM tayls
with
MODULE tforexp
USE kertoma
IMPLICIT NONE
CONTAINS
FUNCTION taylexp(x,ord)
REAL :: taylexp, x, sum
INTEGER :: ord, i
sum= 1.0
DO i=1,ord
sum= sum+ x**i/fact(i)
END DO
taylexp= sum
END FUNCTION taylexp
END MODULE tforexp
and
MODULE kertoma
IMPLICIT NONE
CONTAINS
FUNCTION fact(n)
INTEGER :: fact,n,y=1
DO WHILE (n>1)
y= y*n
n= n-1
END DO
fact = y
END FUNCTION fact
END MODULE kertoma
The infinite loop starts right after the first print "f1(x)=...".
So I think it goes to infinite loop when calling the taylexp-function for the first time, but I don't understand why.
I think it has got something to do with fortran using public variables, but I'm clueless how to consistently avoid this.
First I tried to call the function without defining x, just using "0.01*i", and I thought maybe the problem was that this function used the same name for the dummy index, but it clearly it didn't solve the problem.
The problem is inside then function fact(n):
n= n-1
changes the argument and, therefore, the loop counter i in taylexp. In your code i never exceeds 2. I'm surprised the compiler didn't issue a warning (mine didn't either), because anything might happen in this case.
Better specify the intent of dummy arguments to avoid issues like this in the future:
FUNCTION fact(n)
integer,intent(in) :: n
INTEGER :: fact,nn,y
y=1 ! Avoid the implicit save and assign variables separately
nn=n
DO WHILE (nn>1)
y= y*nn
nn= nn-1
END DO
fact = y
END FUNCTION fact
With gfortran, it is possible to catch this error with
the -fcheck=all option:
$ gfortran -fcheck=all 1.f90
$ ./a.out
f1(x)= (e**x-1)/x
At line 22 of file 1.f90
Fortran runtime error: Loop variable has been modified