Give the target attribute to a variable, just in case we need to point at them, in Fortran - pointers

I have a code that makes extensive use of a type, let say, for simplicity:
type, public :: my_type
real, allocatable, dimension(:) :: x
real, allocatable, dimension(:,:) :: coeffs
end type my_type
...
type(my_type) :: data
Later in the code, we need to write data%x and data%coeffs to a file.
Whether the user wants it or not, this file could be written in a standard unformatted binary file and recently we add the possibility to write the file in HDF5 format.
In this case, when creating the data sets for data%x or data%coeffs, I need to pass a pointer, pointing on them, as argument to some hdf5 subroutines. This pointer can be defined as follow:
f_ptr = c_loc( data%x(1) )
But to do that, I should have given the target attribute to x and coeffs in my_type definition.
My questions are then:
is it safe to give this target attribute, just in case, even if, in the end, the user does not want to use HDF5 format ?
Would it have an impact on performance ?
Would it be better to make, in the routine that writes the data, a local copy of data%x and data%coeffs to same shape arrays with the target attribute and then point at them and pass the pointer to hdf5 subroutines ?
If it helps, this code can be compiled either with gfortran or ifort.
Thanks in advance !

It is safe; maybe; there's no need to make a copy.
Typically you would pass data%x (and then data%coeffs) to a procedure that does the HDF5 dataset writing as a actual argument, say associated with a dummy array arg. If so, just give arg the TARGET attribute.
call write_array_to_hdf5_file(data%x, ...)
subroutine write_array_to_hdf5_file(arg, ...)
real, intent(in), target :: arg(:)
...
call h5d_write_f(..., c_loc(arg))
If the actual argument does not have the target attribute, then pointers associated with arg become undefined when the write_array_to_hdf5_file procedure finishes execution.

I think you have misunderstood how target works in Fortran. If I have not misunderstood you, you want to make data%x and data%coeffs targets, by giving the x and coeffs member variables the target attribute, as
type, public :: my_type
real, allocatable, dimension(:), target :: x
real, allocatable, dimension(:,:), target :: coeffs
end type my_type
type(my_type) :: data
but this is not valid syntax. To quote Intel:
The TARGET attribute can be specified in a type declaration statement or a TARGET statement
This means the target attribute can only be applied to instances of variables, not to their definitions.
And so to make data%x and data%coeffs targets, you should instead give data the target attribute, as
type, public :: my_type
real, allocatable, dimension(:) :: x
real, allocatable, dimension(:,:) :: coeffs
end type my_type
type(my_type), target :: data
This hopefully also answers your question on usage; you only need to give the target attribute to those instances of my_type which need it.

Related

Is using a default method pointer valid Fortran? (IFort compiler bug)

I just want to know for sure if this is valid Fortran or if I've misunderstood some usage. Is the following code valid?
Module MathFxns
implicit none
Type A_T
procedure(DoStuff_F), nopass, pointer :: method => add
contains
End Type A_T
Abstract Interface
Function DoStuff_F(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
End Function DoStuff_F
End Interface
contains
function add(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = a + b
end function add
End Module MathFxns
program Main
use MathFxns
implicit none
type(A_T) :: math
print *, math%method(2, 5)
end program Main
I just had to track down a compiler bug, that was being caused by something I think is valid Fortran. I'd submit to the compiler team, but I don't have a way to replicate as it's buried pretty far down in the stack and down multiple libraries before it caused a compiler bug and it doesn't happen in every program that uses it.
Edit: I didn't mention it before because it is complicated to explain, but since there was some curiosity, I'll try.
The production code does work in some executables, but recently I implemented it in another project which caused a compiler bug. I'll try to make a pseudo code example to illustrate, but first is a description. In the production code I have a type that has a default procedure pointer to a function (just like above). An instance of that type is a field of an abstract type. That abstract type is extended by another abstract type, then in a subsequent library that type is extended by another abstract type, which is then extended by a concrete type in another library. Finally an executable makes use of that concrete type. The module that has an instance of the concrete type throws a compiler error.
In the production code, it is an ODE Solver, with functionality wrapped into an entity type that gets extended a few times before being implemented.
It took me 6 hours, but after commenting and uncommenting line after line, the cause of the error was shown to be the default procedure pointer in the type. Whether that is the actual error or not, I can't know, but removing the default pointer (and pointing in the construction subroutine) made the project work again.
!this is in the first static library project
Module Library1
implicit none
Type A_T
!more stuff
procedure(DoStuff_F), nopass, pointer :: method => add
contains
!more procedures
End Type A_T
Type, abstract :: B1_A
type(A_T) :: a
!more stuff and procedures
End Type B1_A
Type, extends(B1_A), abstract :: B2_A
!more stuff and procedures
End Type B2_A
Abstract Interface
Function DoStuff_F(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
End Function DoStuff_F
End Interface
contains
function add(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = a + b
end function add
End Module Library1
! this is in the second static library project
Module Library2
use Library1
implicit none
Type, extends(B2_A), abstract :: B3_A
!more stuff and procedures
End Type B3_A
End Module Library2
! this is in the third static library project
Module Library3
use Library2
implicit none
Type, extends(B3_A) :: C_T
!more stuff and procedures
End Type C_T
End Module Library3
!this is in a fourth executable project
program Main
use Library3
implicit none
type(C_T) :: math
print *, math%a%method(2, 5)
end program Main

Initialization of a pointer to polymorphic object

Suppose I have a pointer to a polymorphic object:
TYPE, ABSTRACT:: ab
ENT TYPE
TYPE, EXTENDS(ab):: co
INTEGER:: i
ENT TYPE
Class(ab), POINTER:: foo
How do I initialize the object pointed by foo to be a co object, in the executable part of the code? I am thinking of something like
foo => co(1) ! WRONG
but this is wrong.
Pointers can only be initialized with a target with the save attribute or with null(). If you mean the initialization during compilation in the declaration part.
In the executable part of code you can certainly make the pointer to point to an object. But you need an actual object with the target attribute or you need to make an anonymous target using the allocate() statement.
co(1) is an expression or a value result of an expression. You cannot point to it, it does not have the pointer attribute. You could allocate an anonymous target with this value
allocate(foo, source=co(1))
Consider using allocatable instead of a pointer, they should be strongly preferred. If you could use allocatable, it is as simple as
foo = co(1)
thanks to the automatic (re)allocation in the assignment.

Pointer to derived type that contains allocatable array

Generally speaking I want to rename allocatable variables in a derived type that are passed through subroutine arguments. Writing everything with 'derived%type_xx' is not so pleasant. Besides, I don't want to spend extra memory on copying the values of the derived type to a new variable which costs new allocated memory. Furthermore, I know allocatable arrays are preferred than pointers for many reasons. I try to define pointers to the allocatable variable, but failed. I tried this because I want to simplify my code, both to be readable and not to be too long. I wonder if there's a way of achieving the goal? Thanks.
Here's the demonstration code:
Module module_type
IMPLICIT NONE
TYPE type_1
REAL,ALLOCATABLE :: longname_1(:), longname_2(:)
END TYPE
END MODULE
!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
USE MODULE module_type
IMPLICIT NONE
TYPE(type_1) :: input
input%longname_1 = input%longname_1 + input%longname_2 ! Use one line to show what I mean
END SUBROUTINE
And here's what failed:
Module module_type
IMPLICIT NONE
TYPE type_1
REAL,ALLOCATABLE :: longname_1(:), longname_2(:)
END TYPE
END MODULE
!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
USE MODULE module_type
IMPLICIT NONE
TYPE(type_1),TARGET :: input
REAL,POINTER :: a => input%longname_1 &
& b => input%longname_2
a = a + b ! much better for reading
END SUBROUTINE
It seems like a small issue, but I'd like to read my code without too much pain in the future. So what's the best option? Thanks a lot.
You can use the ASSOCIATE construct to associate a simple name with a more complex designator or expression.
You could also use the subobjects of the derived type as actual arguments to a procedure that carried out the operation.
You pointer approach failed because you had a rank mismatch - you were attempting to associate scalar pointers with array targets. You may also have had problems if an explicit interface to your procedure was not available in the calling scope. An explicit interface is required for procedures with dummy arguments with the TARGET attribute.
Use of pointers for this sort of simple name aliasing may reduce the ability of the compiler to optimize the code. Something like ASSOCIATE should be preferred.
Update: After #IanH made his comment, I have gone back to check: I was completely and utterly wrong on why your code failed. As he pointed out in his answer, the main issue is that pointer and target have to have the same rank, so you'd have to declare a and b as:
real, pointer :: a(:), b(:)
Secondly, before you can actually point these pointers to the targets, the targets have to be allocated. Here's an example that works:
program allocatable_target
implicit none
type :: my_type
integer, allocatable :: my_array(:)
end type my_type
type(my_type), target :: dummy
integer, pointer :: a(:)
allocate(dummy%my_array(10))
a => dummy%my_array
a = 10
print *, dummy%my_array
end program allocatable_target
If you have a Fortran 2003 compatible compiler, you can use associate -- which is specifically meant for this kind of issue. Here's an example:
program associate_example
implicit none
type :: my_type
integer, allocatable :: long_name_1(:), long_name_2(:)
end type my_type
type(my_type) :: input
integer :: i
allocate(input%long_name_1(100), input%long_name_2(100))
associate (a=>input%long_name_1, b=>input%long_name_2)
a = (/ (i, i = 1, 100, 1) /)
b = (/ (2*i+4, i = 1, 100, 1) /)
a = a + b
end associate
print *, input%long_name_1
end program associate_example
Inside the associate block, you can use a and b as a shortform for the declared longer named variables.
But other than that, I suggest you get an editor with proper code completion, then long variable names are not that much of an issue any more. At the moment I'm trying out Atom and am quite happy with it. But I have used vim with the proper expansions for a long time.

LOC() for user defined types gives different results depending on the context

I'm trying to debug some code in which members of a user defined object mysteriously change addresses, and while doing that I realized user defined objects do that as well. Here's a small example of querying object address from function that created it and then from its member function:
module foo_module
type foo_type
contains
procedure :: foo
end type foo_type
contains
subroutine foo(this)
class(foo_type) :: this
print *, 'Inside foo this is', loc(this)
end subroutine foo
end module foo_module
program trial
use foo_module
type(foo_type) :: object
print *, 'Object address', loc(object)
call object%foo()
end program trial
A sample output I get is:
Object address 4452052800
Inside foo this is 140734643354880
Why am I getting two different addresses for the same object? Am I doing something wrong? Or is there something with LOC that comes into play I don't understand?
I'm using ifort under osx.
LOC is an extension. Its behaviour is as specified by the compiler vendor.
What the behaviour intended by the vendor here isn't clear, but the difference that you are seeing is that in the main program you get the integer equivalent of the memory address of the non-polymorphic object (what you probably expect), while in the subroutine you get the integer equivalent of the memory address of the polymorphic descriptor for the object (maybe what you want, maybe not).
Using TRANSFER(C_LOC(xxx), 0_C_INTPTR_T) is a more portable way of getting the integer representation of the address of an object (where the C_* things are from the ISO_C_BINDING intrinsic module). C_LOC requires that its argument have the TARGET attribute and be non-polymorphic (use SELECT TYPE).
I'd recommend asking on the relevant Intel Forum if you want further clarification on the intended behaviour of the LOC extension.
I reported the bug to the developers our internal issue ID is DPD200253159. I found that the C_LOC function from ISO_C_BINDING works. For example:
subroutine foo(this)
use, intrinsic :: iso_c_binding
class(foo_type) :: this
print *, 'Inside foo this is', transfer(c_loc(this),0_C_INTPTR_T)
end subroutine foo

How to get the address of array pointer in Fortran?

I would like to get the address of an array pointer. The prototype codes are as following:
program main
implicit none
type foo
integer, allocatable :: i(:)
integer j
end type
type(foo) a
integer, pointer :: ai(:)
ai => a%i
print *, "The address of a is ", loc(a)
print *, "The address of a%i is", loc(ai) ! <--- I expect the same address as a.
end program main
My final target is to get the address of a with type(foo) through the address of array pointer ai, since i is the first part of type(foo).
Thanks in advance!
Li
Fortran doesn't guarantee that the first item of a user-defined the same address as that user-defined type. Maybe there is a header before the items. Maybe there is some padding. Maybe the compiler stores the items in a different order. Maybe different compilers do it differently. None of this is specified. So your expectation may not occur. There is little need in Fortran for addresses. What are you trying to do? If you are interfacing to C, the ISO_C_Binding provides C_LOC.
EDIT in response to the comment. If your goal is to simplifying the variable name by omitting the leading "a %", you can use a pointer to create an alternative variable that accesses the same storage. You don't have to try to get past the language with pointers. Example:
program main
implicit none
type foo
integer, pointer :: i(:)
integer j
end type
type(foo) a
integer, pointer :: ai(:)
allocate ( a%i (5) )
a%i = [ 2, 5, 1, 3, 9 ]
ai => a%i
write (*, '( "a%i=", 5(2X,I2) )' ) a%i
write (*, '( "ai=", 5(2X,I2) )' ) ai
end program main
Output is:
a%i= 2 5 1 3 9
ai= 2 5 1 3 9
You can't, not using standard Fortran anyway.
Note that your expectations are misplaced.
loc is an extension. What it does is processor specific, but typically it will give you an integer representation of the address of the data object that the argument represents. (The F2003 standard's C_LOC is roughly equivalent.). In this case, the data object is an allocatable array. In all processors that I am aware of the storage for that array is not in the storage for the object of derived type that hosts the allocatable component. The derived type object simply contains a descriptor that describes where the array is stored (and how big it is, etc), not storage for the array itself.

Resources