I'm porting some code from Intel Fortran to gfortran and I can not figure out how to port Intel's INT_PTR_KIND() function.
program main
integer (INT_PTR_KIND()) v1
integer v2
print*, "sizeof v1:", sizeof(v1)
print*, "sizeof v2:", sizeof(v2)
print*, "sizeof INT_PTR_KIND:", INT_PTR_KIND()
end program main
gives me with Intel compiler following:
sizeof v1: 8
sizeof v2: 4
sizeof INT_PTR_KIND: 8
Please, how can I achieve following results in gfortran? I have tried with kind(1), sizeof,...everything gives me 4.
The correct integer kind from the iso_c_binding module for this is c_intptr_t
i.e. the most direct equivalent of your code is:
use, intrinsic :: iso_c_binding
integer(c_intptr_t) :: v1
integer(8) can mean anything or nothing at all for some compilers.
The integer(c_intptr_t) is directly interoperable with intptr_t from C (size_t vs. uintptr_t).
You need to look at the interoperability stuff, use iso_c_binding, in there, there is a special type for C pointers that is possibly what you are looking for.
program test
use iso_c_binding
implicit none
type(c_ptr) :: adr
integer(8) :: int8
integer :: int_default
print*, sizeof(adr)
print*, sizeof(int8)
print*, sizeof(int_default)
end program test
follow this link for more.
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 need to pass a vector of pointers from c++ to a Fortran dll and I do not know if this is possible.
I tried searching but I could not really find and answer to my question.
The idea is the following:
Fortran side
!DEC$ATTRIBUTES DLLEXPORT :: TO_FORTRAN
integer function TO_FORTRAN (test4) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
REAL, intent(in) :: test4(3)
REAL, pointer :: test5
call C_F_POINTER(C_LOC(test4),test5)
TO_FORTRAN = 0
END
c++ code
std::vector<float> test1(3);
std::vector<float> test2(3);
std::vector<float> test3(3);
std::vector<float*> test4(3);
test4[0] = test1.data();
test4[1] = test2.data();
test4[2] = test3.data();
TO_FORTRAN(test4);
If it is really an array of pointers, you need to treat it like an array of pointers at the Fortran side as well. You also have keep in mind they are pointers to arrays, not just scale real numbers (although they may be represented the same way in C).
!DEC$ATTRIBUTES DLLEXPORT :: TO_FORTRAN
integer function TO_FORTRAN (test4) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
type(c_ptr), intent(in) :: test4(3)
REAL, pointer :: test1(:), test2(:), test3(:)
call C_F_POINTER(test4(1),test1, [3])
call C_F_POINTER(test4(2),test2, [3])
call C_F_POINTER(test4(3),test3, [3])
TO_FORTRAN = 0
END FUNCTION
and
TO_FORTRAN(test4.data());
I'm learning the basics of Fortran. I created a simple subroutine initializing a matrix:
program test
integer, parameter :: n = 1024
real :: a(n, n)
call init(a)
write (*, *) a(1, 1)
end program
subroutine init(a)
real :: a(n, n)
a(:, :) = 3.0
end subroutine
Then the output is 0.0 instead of expected 3.0. Apart from that, valgrind says that:
==7006== Conditional jump or move depends on uninitialised value(s)
==7006== at 0x400754: init_ (in /home/marcin/proj/mimuw/fortran/test)
==7006== by 0x4007A4: MAIN__ (in /home/marcin/proj/mimuw/fortran/test)
==7006== by 0x40083B: main (in /home/marcin/proj/mimuw/fortran/test)
Why? The n parameter is correctly recognized by the compiler and should be a global one.
I compiled the program with gfortran 6.3.1
n is not a global variable, it is a local variable of the main program.
The subroutine is a completely independent compilation unit from the main program and they do not share any information.
A subroutine can "see" other variables of the parent module, if it is a module procedure, or variables of a parent (host) procedure or program if it is an internal procedure.
Be sure to read about the structure of Fortran programs and use modules as much as possible. Prefer modules over internal procedures. You will see how to put the subroutine into a module or how to make it internal to the main program in the link.
I did not mention common blocks, just don't use them, they are obsolete. And rember to use implicit none in every compilation unit.
Assuming that you want it everywhere, then one uses a COMMON block in the f77 era, and a MODULE now.
I CAPITALISED most of the changes. And if there is no error gives a few ways to consider understanding N in the SUBROUTINE, and an ELEMENTAL FUNCTION would likely be worthwhile to try here too.
MODULE MyMODULE
integer, parameter :: n = 1024
END MODULE MyMODULE
!%%%%%%%%%%
program test
USE MyModule
IMPLICIT NONE
! done up in ˆmoduleˆ...! integer, parameter :: n = 1024
REAL, DIMENSION(n,n) :: A
CALL Alternative_Init(A, 3.3)
WRITE (*,*) a(1, 1)
CALL Alternative2_Init(A, n, 1.23)
WRITE (*,*) a(1, 1)
call init(a)
write (*, *) a(1, 1)
END PROGRAM TEST
!%%%%%%%%%%
subroutine init(a)
USE MyModule
IMPLICIT NONE
real :: a(n, n)
a(:, :) = 3.0
RETURN
END SUBROUTINE init
!%%%%%%%%%%
SUBROUTINE Alternative_Init(a, Val4A)
USE MyModule
IMPLICIT NONE
REAL, DIMENSION(:,:) , INTENT(INOUT) :: a
REAL , INTENT(IN ) :: Val4A
a(:, :) = Val4A
! or just... A = Val4A ! which does them all too.
RETURN
END SUBROUTINE Alternative_Init
!%%%%%%%%%%
SUBROUTINE Alternative2_Init(a, n, Val4A)
!!!! USE MyModule
IMPLICIT NONE
INTEGER , INTENT(IN ) :: n
REAL, DIMENSION(n,n) , INTENT( OUT) :: a
REAL , INTENT(IN ) :: Val4A
A = Val4A
RETURN
END SUBROUTINE Alternative2_Init
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.
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.