Pointer to derived type that contains allocatable array - pointers

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.

Related

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

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.

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

Is Abstract dummy interfaces a recommended programming habit in Fortran?

In my code I have different subroutines that need to be executed on a certain order depending on what inputs the user specify. For example, we could have
do TIMELOOP = 1, n
if(userinput_1) then
call routine_1(..)
call routine_2 (..)
etc etc
elseif (userinput_2) then
call routine_3(....)
call routine_1(....)
endif
enddo
A solution I have been using to avoid all these ifs is by using a an array of pointers to procedures
type ptr_proc
procedure(A_INT), pointer :: proc
end type
type(ptr_proc), allocatable :: ptr(:)
The issue is that Fortran requires the pointer proc to always point to procedures with same interface defined as the A_INT. There is no way I can do this as routine_1, routine_2 etc are very different.
I overcome this by defining the following magical interface
abstract interface
subroutine A_INT
end subroutine
end interface
In other words, it has an empty interface. The routines with empty interfaces are basically wrappers for routine_1, routine_2 etc.
So as an example, a wrapper for routine_1 could be:
subroutine WRAP_ROUT_1
use MOD_FOR_ROUT_1
call ROUTINE_1( ...) ! - I insert the (inputs, outputs) here which I have from the use statement
end subroutine
Then, during my initialisation I point all my pointers to the corresponding wrapper procedures.
if(userinput_1) then
ptr(1)% proc => WRAP_ROUT_1
ptr(2)% proc => WRAP_ROUT_2
etc etc.
elseif ...
endif
Then my timeloop looks like
do TIMELOOP = 1, n
do i = 1 , size(ptr)
call ptr(i)% PROC
enddo
enddo
It works, however, I fear whether this could lead to potential problems/danger. My question really boils down to the consequenes of using such a programming practice in Fortran.

Intentional type mismatch in Fortran

I'd like to turn a legacy Fortran code into modern Fortran compliant code, so I can turn on compiler warnings, interface checking, etc. At this stage I don't want to change the functionality, just make it work as close as possible to what it was, and still keep compilers happy.
My current problem is that the code at many places passes arrays of the wrong types, e.g. a real array to a subroutine that has an integer dummy argument. This is not a bug per se in the code, since it is intentional and it works as intended (at least in common configurations). Now, how could I do the same and while keeping the code compliant? Consider the following example:
program cast
implicit none
double precision :: a(10)
call fill_dble(a,10)
call print_dble(a,10)
call fill_int(a,10)
!call fill_int(cast_to_int(a),10)
call print_dble(a,10)
call print_int(a(1),10)
!call print_int(cast_to_int(a),10)
call print_dble(a(6),5)
contains
function cast_to_int(a) result(b)
use iso_c_binding
implicit none
double precision, target :: a(*)
integer, pointer :: b(:)
call c_f_pointer(c_loc(a(1)), b, [1])
end function
end program
subroutine fill_dble(b,n)
implicit none
integer :: n, i
double precision :: b(n)
do i = 1, n
b(i) = i
end do
end subroutine
subroutine print_dble(b,n)
implicit none
integer :: n
double precision :: b(n)
write(6,'(10es12.4)') b
end subroutine
subroutine fill_int(b,n)
implicit none
integer :: n, b(n), i
do i = 1, n
b(i) = i
end do
end subroutine
subroutine print_int(b,n)
implicit none
integer :: n, b(n)
write(6,'(10i4)') b
end subroutine
When I compile it and run it (gfortran 4.8 or ifort 18), I get, as expected:
1.0000E+00 2.0000E+00 3.0000E+00 4.0000E+00 5.0000E+00 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
4.2440-314 8.4880-314 1.2732-313 1.6976-313 2.1220-313 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
1 2 3 4 5 6 7 8 9 10
6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
The first half of the real array is corrupted with integers (because integers are half the size), but when printed as integers the "right" values are there. But this is non-compliant code. When I try to fix it by activating the cast_to_int function (and disabling the calls without it) I get indeed something that compiles without warning, and with gfortran I get the same result. With ifort, however, I get:
1.0000E+00 2.0000E+00 3.0000E+00 4.0000E+00 5.0000E+00 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
1.0000E+00 2.0000E+00 3.0000E+00 4.0000E+00 5.0000E+00 6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
0******** 0 5 6 7 8 9 10
6.0000E+00 7.0000E+00 8.0000E+00 9.0000E+00 1.0000E+01
which I can't understand. Moreover, ifort with -O0 crashes (and it doesn't with the other version).
I know the code is still not quite correct, because the pointer returned by cast_to_int is still of size 1, but I believe that should be a different problem.
What am I doing wrong, or how can I get ifort do what I want?
EDIT: Following #VladimirF's reply, I add, after implicit none:
subroutine fill_int(b,n)
!dec$ attributes no_arg_check :: b
integer :: n, b(n)
end subroutine
subroutine print_int(b,n)
!dec$ attributes no_arg_check :: b
integer :: n, b(n)
end subroutine
end interface
but compiling with warnings on still gives me an error:
$ ifort cast2.f90 -warn all
cast2.f90(17): error #6633: The type of the actual argument differs from the type of the dummy argument. [A]
call fill_int(a,10)
--------------^
cast2.f90(20): error #6633: The type of the actual argument differs from the type of the dummy argument. [A]
call print_int(a(1),10)
---------------^
compilation aborted for cast2.f90 (code 1)
Intel Fortran supports the !dec$ attributes no_arg_check directive. It instructs the compiler "that type and shape matching rules related to explicit interfaces are to be ignored".
"It can be applied to an individual dummy argument name or to the routine name, in which case the option is applied to all dummy arguments in that interface."
It should be applied to a module procedure (or an interface block), so you should move your functions and subroutines into a module.
Many other compilers have similar directives.
What is wrong about your code? As a rule of thumb, do not ever use any Fortran functions that return pointers. They are pure evil. Fortran pointers are completely different from C pointers.
When you do call fill_int(cast_to_int(a),10) what happens is that the expression cast_to_int(a) is evaluated and the result is an array. Now depending on the optimizations the compiler may choose to pass the address of the original pointer, but it may also create a copy of the result integer array and pass a copy to the subroutine.
Also, your array a does not have the target attribute, so the address used inside cast_to_int(a) is only valid inside the function and is not valid after it returns.
You should make the b inside the main program and just pass b instead of a. It will work similar to equivalence. Looking at the values stored as a different type will be not standard-conforming anyway. This form of type punning is not allowed.
I found a possible general solution that seems to work. The code I have to deal with looks something like this:
subroutine some_subroutine(a,b,c,d,...)
real a(*),b(*),c(*),d(*)
! many more declarations, including common blocks
!...
call other_subroutine(a,b(idx),c,...)
!...
end subroutine some_subroutine
! this typically in another file:
subroutine other_subroutine(x,y,z,...)
real x(*)
integer y(*)
logical z(*)
! other declarations and common blocks
! unreadable code with calls to other procedures
! not clear which which arguments are input and output
end subroutine other_subroutine
I now modify it to be:
subroutine some_subroutine(a,b,c,d,...)
real a(*),b(*),c(*),d(*)
! many more declarations, including common blocks
call inner_sub(b,c)
contains
subroutine inner_sub(b,c)
use iso_c_binding
real, target :: b(*),c(*)
integer, pointer :: ib(:)
logical, pointer :: lc(:)
!...
call c_f_pointer(c_loc(b(idx)),ib,[1]) ! or use the actual length if I can figure it out
call c_f_pointer(c_loc(c(1)),lc,[1])
call other_subroutine(a,ib,lc,...)
nullify(ib,lc)
!...
end subroutine inner_sub
end subroutine some_subroutine
leaving other_subroutine untouched. If I use directly the target attribute on the outer routine, I have to add an explicit interface to anything calling it, so instead I wrap the inner code. By using contains I don't need to pass all variables, just those that will be "punned". The c_f_pointer call should be done right before the problematic call, since index variables (idx in the example) could be in common blocks and changed in other calls, for example.
Any pitfalls, apart from those already present in the original code?

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

Resources