OS Ubuntu 14.04 on 64-bit notebook
I compile a function written in the Fortran code using f2py
then I call this function from Python.
And I get error message:
ValueError: failed to initialize intent(inout) array -- expected elsize=4 but got 8
It looks like my Fortran code is being compiled as a 32-bit in spite of 64-bit machine.
On 32-bit computer everything works fine.
What do I do wrong?
It looks like I have found solution.
First, reported error raises only when integer arrays are being passed to Fortran subroutine. Integer values and real arrays (I suppose, values too) pass correctly, when I use default Python int and float, while in Fortran I declare them as INTEGER*4 and REAL*8.
But in the case of integer arrays this did not work. Minor corrections needed, namely, integer arrays in Python should be declared as (or converted to) np.int32 type and declared as INTEGER*4 in Fortran subroutine.
Here are samples of array declaration/conversion that worked in my project.
Python:
import numpy as np
import Fortran_file
#.... some code
# variable "data" is integer 2-D array
data = data.astype(np.int32) # data.astype(int) gives error
data = np.asfortranarray(data)
array1 = np.zeros(5, dtype=np.int32, order='F') # dtype=int gives error
array2 = np.zeros(5, dtype=float, order='F')
ivalue = 2 # conversion to np.int32 is not needed
Fortran_file.Fortran_subroutine(data, ivalue, array1, array2)
Fortran:
SUBROUTINE Fortran_subroutine (matrix, value, array1, array2)
IMPLICIT NONE
INTEGER*4 :: matrix(:,:)
!f2py INTENT(INOUT) :: matrix(:,:)
INTEGER*4 :: value
!f2py INTENT(INOUT) :: value
INTEGER*4 :: array1(5)
!f2py INTENT(INOUT):: array1(5)
REAL*8 :: array2(5)
!f2py INTENT(INOUT) :: array2(5)
Again, this had sense on 64-bit OS. When I used 32-bit OS, everything worked without these tricks.
I have not experimented with other data types.
Related
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.
The Fortran intrinsic function transfer can be used to covert a derived type into a real or integer array. This is potentially very useful when working in legacy systems which relies on arrays of primitive types (integer, real etc.) for persistence.
The code below runs at least on ifort and gfortran and converts a simple derived type example to an integer array (updated with solution):
program main
implicit none
integer, parameter :: int_mem_size = storage_size(1)
type subtype
integer a
double precision b
end type subtype
type :: mytype
integer :: foo
double precision :: bar
type(subtype) :: some_type
end type
type(mytype) :: my_var
type(subtype) :: my_subtype
! Old version: integer :: x(30)
integer, allocatable :: x(:)
integer :: mem_size
!Allocate array with required size
mem_size = storage_size(my_var)
allocate(x(mem_size/int_mem_size))
my_subtype%a = 1
my_subtype%b = 2.7
my_var%foo = 42
my_var%bar = 3.14
my_var%some_type = my_subtype
write(*,*) "transfering..."
x = transfer(my_var, x)
write(*,*) "Integer transformation:", x
end program main
On my PC, this is the output (this result is at least platform dependent):
transfering...
Integer transformation: 42 0 1610612736 1074339512
999 0 -1610612736 1074108825
My problem is that I have "guessed" that a 30 element long integer array is large enough to store this data structure. Is there a way I can determine how large the array needs to be to store the whole data structure?
If you have a Fortran 2008 compliant compiler, or one that is compliant enough, you will find the intrinsic function storage_size which returns the number of bits used to store its argument. Failing that most compilers that I am familiar with implement a non-standard function to do this; the Intel Fortran compiler has a function called sizeof which returns the number of bytes required to store its argument.
I seem to have hit a wall while coding these past few days. from what i can gather, it is possible to make arrays of arrays in fortran ala Fortran array of variable size arrays
type par
.... !data
integer :: location
end type par
type locations
....! data
type (par), allocatable, dimension(:) :: pars
end type locations
type (par), allocatable, dimension(:) :: all_pars
type (locations), allocatable, dimension(:) :: all_loc
.... !read numpars, numlocs from file etc
allocate(all_pars(numpars))
allocate(all_locs(numlocs))
!initialize all_pars
do n = 1:numpars
....
all_pars(n)%location = some_location
enddo
!get particles in each location
do n = 1:numlocs
allocate(all_locs(n)%pars(count(all_pars(:)%location .ne. n)))
all_locs(n)%pars = pack(all_pars, (all_pars(:)%location .ne. n)) !ERROR: An assignment of different structure types is invalid.
enddo
the compiler does not complain with my equivalent lines of code for the stack overflow example above, but it indeed does have an issue when i attempt to use that array to store the result of a pack function call. i suspect that it may be the case that the allocate function is not behaving as expected, but since the code does not compile, i cannot debug it....
the squirrely idea for pack usage comes from http://flibs.sourceforge.net/fortran_aspects.html , about halfway down the page.
I am running on a linux system, with ifort 12.1.3.293
any help is much appreciated
This may be an extended comment rather than an answer ...
to get it to compile I modified your posted code to;
program main
implicit none
integer :: numpars, numlocs, n
type par
!data
integer :: location
end type par
type locations
! data
type (par), allocatable, dimension(:) :: pars
end type locations
type (par), allocatable, dimension(:) :: all_pars
type (locations), allocatable, dimension(:) :: all_locs
!read numpars, numlocs from file etc
numpars = 10
numlocs = 4
allocate(all_pars(numpars))
allocate(all_locs(numlocs))
!initialize all_pars
all_pars(1:numpars:4)%location = 1
all_pars(2:numpars:4)%location = 2
all_pars(3:numpars:4)%location = 3
all_pars(4:numpars:4)%location = 4
!get particles in each location
do n = 1,numlocs
! allocate(all_locs(n)%pars(count(all_pars(:)%location .ne. n)))
all_locs(n)%pars = pack(all_pars, (all_pars(:)%location .ne. n))
enddo
end program
and it compiles without a hitch on my Mac with Intel Fortran 13.something. Of course, since you've only posted a syntactically-slightly-incorrect part of your code I can't be sure that this tells you very much.
Since you don't show that your code uses implicit none your error might be down to the difference between all_loc and all_locs or some other similar issue.
Note, in passing, that with Fortran allocatable arrays you don't need to allocate all_locs(n)%pars prior to setting its value with the call to pack, the compiler will take care of that for you. This, though, is not the source of your error.