I am a newbie in Fortran programming. I know this error may due to wrong data type, but I do not know which correct data type I should choose for...
Here is my code:
program main
REAL :: tempo(3), temp
INTEGER :: num_sta, num_sou
num_sta = 0
num_sou = 0
OPEN(11,status="old",file="sou_location.txt")
OPEN(12,status="old",file="sta_location.txt")
OPEN(21,file="RESULTS.txt")
DO WHILE ( .NOT. eof(11) )
READ(11,*) tempo(:)
num_sou = num_sou + 1
END DO
REWIND(11)
DO WHILE ( .NOT. eof(12) )
READ(12,*) tempo(:)
num_sta = num_sta + 1
END DO
REWIND(12)
end program main
and here is the error message:
eew_loca_H_test.f90:11:18:
DO WHILE ( .NOT. eof(11) )
1
Error: Operand of .not. operator at (1) is REAL(4)
eew_loca_H_test.f90:17:18:
DO WHILE ( .NOT. eof(12) )
1
Error: Operand of .not. operator at (1) is REAL(4)
EOF is a nonstandard intrinsic function that is probably not supported by the compiler you are using. The compilers I know of that do support this have EOF returning type LOGICAL, which is what your program expects. Otherwise Fortran implicit typing makes this REAL, which is an error for a logical operator such as .NOT.. (Some compilers won't warn you about this unless you ask for standards checking.) #francescalus has the right answer - include an IOSTAT= specifier in the READ and use IS_IOSTAT_EOF(statvar) to test it. You'll want to initialize "statvar" (or whatever you call it) to 0 before the loop, and be sure to declare it as INTEGER.
Related
I'm modernizing some old Fortran code and I cannot get rid of an equivalence statement somewhere (long story short: it's mixed use is so convoluted it'd take too much work to convert everything).
I need the length of the EQUIVALENCEd arrays to depend on some input, like the following code:
program test_equivalence
implicit none
type :: t1
integer :: len = 10
end type t1
type(t1) :: o1
call eqv_int(o1%len)
call eqv(o1)
return
contains
subroutine eqv_int(len)
integer, intent(in) :: len
integer :: iwork(len*2)
real(8) :: rwork(len)
equivalence(iwork,rwork)
print *, 'LEN = ',len
print *, 'SIZE(IWORK) = ',size(iwork)
print *, 'SIZE(RWORK) = ',size(rwork)
end subroutine eqv_int
subroutine eqv(o1)
type(t1), intent(in) :: o1
integer :: iwork(o1%len*2)
real(8) :: rwork(o1%len)
equivalence(iwork,rwork)
print *, 'LEN = ',o1%len
print *, 'SIZE(IWORK) = ',size(iwork)
print *, 'SIZE(RWORK) = ',size(rwork)
end subroutine eqv
end program test_equivalence
This program will create 0-length arrays with gfortran 9.2.0. This is the output:
LEN = 10
SIZE(IWORK) = 0
SIZE(RWORK) = 0
LEN = 10
SIZE(IWORK) = 0
SIZE(RWORK) = 0
The same code will return Array 'rwork' at (1) with non-constant bounds cannot be an EQUIVALENCE object when compiled with gfortran 5.3.0, the warning disappears since gfortran 6.2.0, but the size of the arrays is always 0. So maybe compiler bug?
The source code is indeed not a valid Fortran program. To be specific, it violates the numbered constraint C8106 of Fortran 2018:
An equivalence-object shall not be a designator with a base object that is .. an automatic data object ..
Being a numbered constraint, the compiler must be capable of detecting this violation. If hasn't such a capability this is a deficiency in the compiler (a bug). Being "capable" doesn't mean doing so by default, so please look carefully to see whether there are options which do lead to this detection. Someone familiar with the internals of GCC can give further detail here.
As the source isn't a valid Fortran program, the compiler is allowed to consider the arrays of size zero if it has skipped the violation detection.
This is a follow up question from a thread I've started earlier here.
Basically, what I want to achieve is defining a deferred type which automatically assigns primitive types (real, integer, character and logical). You can see a working example when following the above link and it compiles with gcc version 7.3.0 and ifort version 18.0.0.
I have now extended the code in order to "use" the deferred data type without knowing what primitive type is assigned. This works by overriding basic operators. For the sake of simplicity I've only included the + operator in the following example. The example works and compiles with gfortran but does give me an error when compiling with ifort :
error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [PLUS_FUNC_CLASS]
c%i = a%i + b%i
Does anyone know what the problem is here? I've already googled the error but I could not find out what I'm doing wrong.
NOTE
in order to match the precision I used the following compile flags
ifort -r8 -i8 tst.f90
gfortran -fdefault-real-8 -fdefault-integer-8 -fdefault-double-8 tst.f90
Here's the sample code:
module DervType
implicit none
type, public :: mytype
real :: r
integer :: i
character(len=:), allocatable :: c
logical :: l
end type
interface assignment(=)
module procedure equal_func_class
end interface
interface operator(+)
module procedure plus_func_class
end interface
contains
subroutine equal_func_class(a,b)
type(mytype), intent(out):: a
class(*), intent(in) :: b
select type (b)
type is (mytype)
print *, "is mytype"
if ( .not. a%r == b%r ) a%r = b%r !! <-- ugly, but necessary not to end up in an endless loop when reassigning mytype (only testing and assigning real here)
type is (real)
print *, "is real"
a%r = b
type is (integer)
print *, "is int"
a%i = b
type is (character(len=*))
print *, "is char"
a%c = b
type is (logical)
print *, "is logical"
a%l = b
end select
return
end subroutine equal_func_class
recursive function plus_func_class(a,b) result(c)
class(*), intent(in) :: a
class(*), intent(in) :: b
type(mytype) :: c
select type (a)
type is (mytype)
print *, "left side is mytype"
!! -------------------------------
!! only testing one case here and only real operations are
!! taken care of!
!! -------------------------------
select type (b)
type is (mytype)
print *, "right side is mytype"
c%i = a%i + b%i !! <-- this is where ifort throws the error
c%r = a%r + b%r !! <-- this is where ifort throws the error
type is (real)
print *, "right side is real", a%r
c = a%r + b
end select
!! do similar logic when the operands changing sides
type is (real)
print *, "left side is real"
end select
!c = 1.
return
end function plus_func_class
end module DervType
program TestType
use DervType
implicit none
type(mytype) :: test, test2, res, res2
real, parameter :: tt = 2.
test = 1.
test = 1
test = "Hey Tapir"
test = .true.
test2 = 2.
test = test2
print *, "test = ", test%r
res = test + 1.0
res2 = test + tt
print *, "Calculation 1 (real) : ", res%r
print *, "Calculation 2 (real) : ", res2%r
end program TestType
When compiling with gfortran and running the program this gives the following output:
is real
is int
is char
is logical
is real
is mytype
test = 2.0000000000000000
left side is mytype
right side is real 2.0000000000000000
is real
is mytype
left side is mytype
right side is real 2.0000000000000000
is real
is mytype
Calculation 1 (real) : 3.0000000000000000
Calculation 2 (real) : 4.0000000000000000
Let's cut this example program down to something more manageable:
module DervType
implicit none
type mytype
integer i
end type mytype
interface operator(+)
module procedure plus_func_class
end interface
contains
recursive function plus_func_class(a,b) result(c)
class(*), intent(in) :: a
class(*), intent(in) :: b
type(mytype) :: c
c%i = 1+1
end function plus_func_class
end module DervType
ifort 18.0.3 for me complains about this:
error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [PLUS_FUNC_CLASS]
c%i = 1+1
-----------^
Familiar?
Well, it looks like because we have the arguments to plus_func_class as unlimited polymorphic ifort is deciding to take this function as a specific procedure for the generic operator(+) with the expression 1+1. (Remove the recursive prefix to see further.)
We don't want it to do that. Can we persuade it not to?
We want our true function to consider cases where either the left-hand side or the right-hand side are of class(mytype), as we don't care to reimplement intrinsic+intrinsic. I won't write out details, but you can implement the function twice: once with LHS class(mytype) and RHS class(*), and once with the LHS class(*) and the RHS class(mytype).
Even if one initially views this approach simply as a "compiler bug workaround", it's really worth implementing the defined operation without using unlimited polymorphic arguments for both sides of the addition operation
When you want to create a new type mytype2 you don't want to define the operation with the function plus_func_class. You'd need to though, because you'll have an ambiguous interface if you create a new specific function for generic operator(+).
Consider the following code that attempts to create a coarray derived type containing an array of variable-length allocatable character types.
program testCoarrayJaggedArray
implicit none
integer :: i
type :: CharVec_type
character(:), allocatable :: record
end type
type :: List_type
type(CharVec_type), allocatable :: Item(:)
end type
type(List_type) :: List[*]
if (this_image()==1) then
allocate( List%Item(num_images()) )
do i = 1, num_images()
allocate( character(63) :: List%Item(i)%record )
write(List%Item(i)%record,*) i
List%Item(i)%record = "King" // trim(adjustl(List%Item(i)%record))
end do
sync images(*)
else
sync images(1)
allocate( List%Item( size(List[1]%Item(:)) ) )
do i = 1, size(List%Item(:))
allocate( character( len(List[1]%Item(i)%record) ) :: List%Item(i)%record )
List%Item(i)%record = List[1]%Item(i)%record
write(*,*) this_image(), List%Item(i)%record
end do
end if
end program testCoarrayJaggedArray
Intel's ifort 2018 in debug mode, shared-memory coarray, complains about several aspects of this code. Here is the first one:
ifort /debug /Qcoarray=shared /standard-semantics /traceback /gen-interfaces /check /fpe:0 main.f90 -o run.exe
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.2.185 Build 20180210
Copyright (C) 1985-2018 Intel Corporation. All rights reserved.
main.f90(30): error #6457: This derived type name has not been declared. [CHARACTER]
allocate( character( len(List[1]%Item(i)%record) ) :: List%Item(i)%record )
------------------^
main.f90(30): error #8235: If type specification appears, the type and kind type parameters of each object being allocated must be the same as type and kind type parameters of the type specification. [RECORD]
allocate( character( len(List[1]%Item(i)%record) ) :: List%Item(i)%record )
---------------------------------------------------------------------------^
compilation aborted for main.f90 (code 1)
Is this code non-standard Fortran? In particular the line that allocates a character type using the length of the corresponding character on the first image:
allocate( character( len(List[1]%Item(i)%record) ) :: List%Item(i)%record )
Regardless of the conformance of the program, the first error message is gibberish: character is not a valid name for a derived type. At the least, this should be reported to Intel support as a quality of implementation issue.
Now, is the code conforming? Rather than answer that, I'll look at the following program:
integer :: i[*]
character(:), allocatable :: x
i=1
allocate(character(i[this_image()]) :: x)
end
When I compile with ifort 18.0.2
test.f90(5): error #6457: This derived type name has not been declared. [CHARACTER]
allocate(character(i[this_image()]) :: x)
---------^
test.f90(5): error #8235: If type specification appears, the type and kind type parameters of each object being allocated must be the same as type and kind type parameters of the type specification. [X]
allocate(character(i[this_image()]) :: x)
---------------------------------------^
compilation aborted for test.f90 (code 1)
Let's look at what should happen to this program.
We can probably all agree that the only contentious line is the allocation statement, and the only part of that which is tricky is (again) the length type parameter for the type specification. So, is i[this_image()] a valid type parameter here?
It's a scalar integer expression and it's defined. We just need to determine whether any other restriction applies which is violated. There is none in Fortran 2008.
The compiler should not reject this program.
As a workaround for the program of the question: create a non-coarray temporary copy of the length expression to use in the allocation statement.
Why am I getting Error: Unclassifiable statement?
I use Fortran 95 and use compile Fortran online : http://rextester.com/l/fortran_online_compiler
program main
implicit none
real::p = 0
p=3**5 * exp(-3)/call fact(5)
print*,p
end program main
function fact(n)
implicit none
integer :: n
integer :: i
integer :: fact
if (n < 0)then
fact = 1
else
do i = 2, n, 1
fact = fact * i
end do
end if
end function fact
error:
p=3**5 * exp(-3)/call fact(5)
1 Error: Unclassifiable statement at (1)
You cannot call a function using the call statement, that is only for subroutines. You just use the function name
p=3**5 * exp(-3.0)/fact(5)
The argument to exp must be real (like -3.0).
You either have to put the function into a module (better) or make it internal (between contains and end program), or at least declare its type
integer :: fact
in the program that is calling it.
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.