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.
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 have the following code which is producing a segmentation fault. It does complain that
forrtl: severe (408): fort: (7): Attempt to use pointer TT when it is not associated with a target
Now I am pretty sure what the reason is, namely, it is trying to access my copy assignment routine, while I am just trying to initialise the object.
By commenting out generic :: assignment(=) => copy it works fine!
I am compiling the code as follows : (IFORT version 19.0.3)
ifort -O0 -debug full -check all -traceback -g -C -CB -CU -CA -fpp filaname.f90
and running by ./a.out
module md
implicit none
type T_TEST
integer :: ii
contains
procedure, pass(this) :: COPY
generic :: assignment(=) => copy
end type
interface t_test
module procedure init
end interface t_test
type(t_test) , allocatable :: tt
contains
function init( size )
integer, intent(in) :: size
type(t_test) , allocatable :: init
allocate( init )
init% ii = size
end function
subroutine copy(this, old )
class(t_test), intent(out) ::this
type(t_test), intent(in) :: old
this% ii = old% ii
end subroutine
end module md
program t_Testprogram
use md
implicit none
tt = t_test( 100 )
end program t_Testprogram
The reason is that the overloaded assignment copy does not support allocatable left hand sides. So when the value of this is used in this% ii = old% ii , it actually does not exist and a null pointer is used. But I do agree the Intel's error message is confusing or even incorrect.
The automatic left hand side (re-)allocation only applies to intrisic assignments, not to user defined ones. In user-defined ones you must program yourself the exact behaviour. And you did not specify anything for not-allocated left hand sides.
This works for me:
type T_TEST
integer :: ii
end type
interface assignment(=)
procedure copy
end interface
subroutine copy(this, old )
class(t_test), allocatable, intent(out) ::this
type(t_test), intent(in) :: old
if (.not.allocated(this)) allocate(this)
this% ii = old% ii
end subroutine
Or you can just allocate the object first (that is what I would do here because gfortran seems to not like generic resolution based on the allocatable attribute - a F08 feature).
allocate(tt)
tt = t_test( 100 )
It seems that you are thinking that just because the constructor has its result variable "marked" allocatable, it will allocate the left hand side of the assignment for you. It is not so. The only thing it does it that it allocates its own result as a temporary variable. This result is then assigned in tt = t_test() and then deallocated automatically.
Remember, the result variable is not the same as the left hand side of the assignment. The result can be used in an expression of many different types, not just in an assignment. It can be passed to a subroutine, it can be used in an arithmetic expression, it can be printed...
Your constructor can be just
function init( size )
integer, intent(in) :: size
type(t_test) :: init
init% ii = size
end function
and the result will be exactly the same. There is no reason to make it allocatable, it just complicates it, but does not change the result in the slightest.
Maybe what you are trying to follow some C++ RAII principles, but remember, C++ is simply not Fortran.
I have a subroutine that doesn't behave as expected, and I cannot understand why.
SUBROUTINE CHECK_INPUT_2D(VNAME,X,MIN_VAL)
CHARACTER(LEN=*) :: VNAME
REAL(KIND=JPRB),INTENT(INOUT) :: X(:,:)
REAL(KIND=JPRB),INTENT(IN),OPTIONAL :: MIN_VAL
LOGICAL :: L_MIN
CHARACTER(LEN=128) :: PRO_NAME='CHECK_INPUT_2D'
L_MIN= .FALSE.
IF (PRESENT(MIN_VAL)) THEN
IF (ANY(X < MIN_VAL)) THEN
L_MIN = .TRUE.
WHERE (X < MIN_VAL)
X = MIN_VAL
END WHERE
END IF
END IF
IF(L_MIN) WRITE(*,*) 'WARNING:'//PRO_NAME//'MIN VAL:'//TRIM(VNAME)//,MINVAL(X),' SET: ',MIN_VAL
END SUBROUTINE CHECK_INPUT_2D
The subroutine is called with MIN_VAL set to 0.0 but this routine still generates a warning. Why is this when no values of X are less than 0.0? How do I solve this bug?
This subroutine is located in a module with the following header:
MODULE MOD_UTILS
USE KIND1 ,ONLY : JPIM ,JPRB
IMPLICIT NONE
INTERFACE CHECK_INPUT
MODULE PROCEDURE CHECK_INPUT_1D,CHECK_INPUT_2D,CHECK_INPUT_3D
END INTERFACE
CONTAINS
and the subroutine is called from another module with the following header:
MODULE MOD_SIM
#include "defs.h"
USE MOD_SIM_TYPES
USE MOD_SIMULATOR
USE KIND1 ,ONLY : JPIM, JPRB
IMPLICIT NONE
CONTAINS
In MOD_SIM is the calling subroutine that simply contains: CALL CHECK_INPUT_2D(VNAME,X,MIN_VAL)
Appreciate your help with this.
Use of OPTIONAL arguments requires that the calling procedure be aware of this. The only way to accomplish this in Fortran is through the use of an explicit interface.
You procedure is within a module MOD_UTILS so it has an explicit interface. Make sure the procedure that is calling this subroutine has use MOD_UTILS or is using a module uses that module.
The need for the explicit interface is required by the standard:
Fortran 2008: 12.4.2.2 p1.(1)(2)(a) ISO/IEC 1539-1:2010
Fortran 90: 12.3.1.1 (2)(a) ISO/IEC 1539:1991(E)
I was doing an svd decomposition of a square matrix A, with A=U S Vdag, and in the fortran code, the line reads
lwork = -1
call zgesvd( 'A', 'A', A%d, A%d, A%m, A%d, S, U%m, U%d, Vdag%m, Vdag%d,work, lwork, rwork, info )
lwork = int(work(1));deallocate(work); allocate(work(lwork))
call zgesvd( 'A', 'A', A%d, A%d, A%m, A%d, S, U%m, U%d, Vdag%m, Vdag%d,work, lwork, rwork, info )
When I compiled with gfortran, it went through with no error or warning. However when I run the program, it shows error with message:
" ** On entry to ZGESVD parameter number 11 had an illegal value "
I could not figure out what went wrong.
For reference, the definitions of the parameters:
type cmatrix
integer(4) d
complex(8), allocatable :: m(:,:)
end type
type (cmatrix) A,U,Vdag
allocate(A%m(dim,dim),U%m(dim,dim),Vdag%m(dim,dim))
A%d = dim; U%m = dim; Vdag%d = dim
real(8) S(dim)
Thanks in advance!
Xiaoyu
p.s. It should be mentioned that such a program runs smoothly when compiled with ifort, but gfortran gives an runtime error as shown above
--- Problem solved!
It seems that the issue lies in how ifortran and gfortran allocates memory. I defined in the code USV type which:
type USV
integer is_alloc
type (cmatrix) U,V
real(8), allocatable :: S(:)
end USV
When initializing by
type(USV) Test_usv(:)
allocate(Test_usv(3)),
the value of is_alloc is 0 using intel fortran compiler, while arbitrary number for gfortran. I need to use this value as a criterion for allocating U V matrices:
if (is_alloc.eq.0) then
allocate(U%m(dim,dim))
end if
The fundamental problem is not a difference between ifort and gfortran. Your approach to the initialization of the variables isn't valid Fortran. Unless you initialize a variable with a declaration, assignment statement, etc., its value is undefined. One way to fix this would be to add a default initialization to the type definition:
type USV
integer is_alloc = 0
type (cmatrix) U,V
real(8), allocatable :: S(:)
end USV
Another approach would be to not track the allocation status yourself and to rely upon the intrinsic function that Fortran provides for this purpose:
if (.NOT. allocated (U%m) ) allocate(U%m(dim,dim))
P.S. Best practice is not to rely upon specific numeric values for kinds. The kind values are arbitrary and are not necessarily the number of bytes of the type. Some compilers use the number of bytes, others don't. One method to specify the number of bytes and to have portable code is to use types provided by the ISO Fortran environment:
use, intrinsic :: ISO_FORTRAN_ENV
integer(int32) :: d
real(real64), allocatable :: S(:)
The types are named after the number of bits. A list of the available types is in the "Intrinsic Modules" chapter of the gfortran manual.