The following
type t
real :: r(2)
end type t
class(t), allocatable :: array(:)
allocate(array(1))
array(1)%r(1) = 1
array(1)%r(2) = 2
print*,array(1)%r
end program
prints incorrectly
1.00000000 0.00000000
with gfortran-4.8.1. Regardless of the array size I can only correctly set the first element. All other assignments have no effect. No warning is given. Is this a compiler bug? With Intel compiler it prints correctly
1.000000 2.000000
EDIT
Sorry, the above, while possibly a compiler bug, is an oversimplification of my actual problem. In reality I have an allocatable array whose elements inherit from an abstract type.
module m
type, abstract :: base
real, allocatable :: r(:)
contains
procedure :: print
end type base
type, extends(base) :: t
end type t
contains
subroutine print(this, n)
class(base) :: this
integer n
print*,this%r(n)
end subroutine print
end module m
program test
use m
class(base), allocatable :: array(:)
type(t) :: f
allocate(array(1), mold=f)
allocate(array(1)%r(2))
array(1)%r(1) = 1.0
array(1)%r(2) = 2.0
call array(1)%print(1)
call array(1)%print(2)
end program test
Result is
1.00000000
0.00000000
with gfortran but should be
1.00000000
2.00000000
as it is with ifort. Using a base-bound set function, instead of directly defining 'r', yields the correct results.
Anything non-standard in the above code or just a compiler bug?
UPDATE
This issue seems to be resolved now. I don't when a fix was introduced, but with GFortran 10.2.0 I get the correct behavior.
Related
I have the following simple Fortran code
program test
type vec
integer :: x(3)
end type
type(vec) :: v(2)
call sub(v)
contains
subroutine sub (v)
class(vec), intent(in) :: v(:)
integer :: k, q(3)
q = [ (v(1)%x(k), k = 1, 3) ] ! <-- fails here
end subroutine
end program
which, when compiled by GNU Fortran 11 (but not other versions) with -fcheck=bounds, fails with the error
At line 19 of file test.f90
Fortran runtime error: Index '3' of dimension 1 of array 'v%_data%x' above upper bound of 2
It look as if the compiler simply interchanged the lengths of x and v and this can be confirmed by changing the numbers.
When the word class is replaced by type, the problem goes away.
I believe that the code is valid as it is. Or is it violating some Fortran language restriction that results in this surprising behaviour?
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 have a small code declaring a pointer to array of derived type which has a field that is an allocatable array of another derived type having a real variable as a field.
Using gnu fortran (8.2) I obtain different results for each location in the array or as a vector.
Using intel fortran (2019.4) compiler succeeded.
program test
implicit none
integer, parameter :: length = 2
real(8), dimension(length) :: a, b
integer :: i
type point
real(8) :: x
end type point
type stored
type(point), dimension(:), allocatable :: np
end type stored
type(stored), dimension(:), pointer :: std=>null()
allocate(std(1))
allocate(std(1)%np(length))
std(1)%np(1)%x = 0.3d0
std(1)%np(2)%x = 0.3555d0
do i = 1, length
write(*, "('std(1)%np(',i1,')%x = ',1e22.14)") i, std(1)%np(i)%x
end do
do i = 1, length
write(*, "('std(1)%np(1:',i1,') = ',2e22.14)") i, std(1)%np(1:i)%x
end do
a = std(1)%np(1:2)%x
b = [std(1)%np(1)%x, std(1)%np(2)%x]
if (norm2(a - b) .gt. 1d-3) then
write(*,*) 'failure'
else
write(*, *) 'success'
end if
end program test
the code terminates successfully, but using gfortran one obtains 'failure' on screen and inconsistent prints above and using Intel compiler one obtains 'success' on screen and consistent prints above.
It's not clear to me what your question is, unless it's the title. If so, no, pointers to derived types are fine. Your program correctly allocates std as an extent-1 array and then allocates std(1)%np(2). It then assigns to the x subcomponents of both np elements. Looks fine to me.
There are several things that could potentially cause "failure" - you should run the gfortran code in the debugger to see what is going wrong.
The problem presented in the code above was resolved in the following [link] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91077
Trying to learn Fortran for a project. In a very simple program I am getting invalid character error.
program foo
implicit none
integer :: n_samp
integer :: samp_len
integer :: x_len
integer :: y_len
n_samp=2
samp_len=2
y_len=11
x_len=2
real(8),dimension(n_samp,samp_len,y_len,x_len)=Yvec
end program foo
error generated by GFORTRAN
t.f90:11.12:
real(8), dimension(n_samp,samp_len,y_len,x_len)=Yvec
1
Error: Invalid character in name at (1)
What is the cause of this error?
The correct syntax is
real(8), dimension(n_samp,samp_len,y_len,x_len) :: Yvec
The :: is obligatory when specifying any attributes (as the dimension in your case).
As #AlexanderVoigt points out, all variable declaration must be placed in the declaration part of the code, i.e., at the beginning.
I do not recommend using real(8) because that is not well defined, the 8 can mean anything, it is an index to a table of kinds and different compilers can have something different at place 8 in that table. See Fortran 90 kind parameter
That's simple: You are not allowed to have declarations in the main body (that is after some instructions)! Instead, you should use parameters:
program foo
implicit none
integer,parameter :: n_samp=2
integer,parameter :: samp_len=2
integer,parameter :: x_len=11
integer,parameter :: y_len=2
real(8),dimension(n_samp,samp_len,y_len,x_len) :: Yvec ! Add. typo here
end program foo
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.