Variables being deleted in Fortran Arrays? - arrays

I have a following code, with an abstract type, inherited type and a short program, where I'm creating an object and storing it in an array.
module m
implicit none
type :: container
class(a), allocatable :: item
end type container
type, abstract :: a
integer, public :: num
end type a
type, extends(a) :: b
integer, public :: num2
end type b
end module m
program mwe
use m
implicit none
class(a), allocatable :: o1
class(container), allocatable :: arr(:)
o1 = b(1, 2)
allocate(arr(2))
arr(1) = container(o1)
select type(t => o1)
type is(b)
write(*,*) t%num, t%num2
end select
select type(t => arr(1)%item)
type is(b)
write(*,*) t%num, t%num2
end select
end program mwe
The problem is, that the output looks like this:
1 2
1 0
As can be seen, the same variable stored in the array has the second variable nullified. Why is that happening? Is it because the array is of type a, which only contains the first variable?
I'm compiling the code with ifort version 18.0.3.

I believe
arr(1) = container(o1)
is invalid Fortran 2008. This is an intrinsic assignment statement, but section 7.2.1.2 of the standard says that
In an intrinsic assignment statement, (1) if the variable is polymorphic it shall be allocatable and not a coarray.
As far as I can see, arr(1) is polymorphic but not allocatable, so a standards-compliant compiler should issue an error and abort compilation.
If my reasoning is correct, the fact that Intel Fortran compiler compiles this code is a compiler bug and should be reported to Intel.

As with ripero's answer one could say that any output from the program is valid. However, we can make a simple modification to the code to make it correct Fortran.1 This answer is concerned with this modified version.
I would call this unexpected output and seek the help of the compiler vendor.
Using a structure constructor with polymorphic allocatable components is one of those new areas in Fortran. Compilers may take a while to catch up or do it correctly.
I have tested your code with Intel Fortran 18.0.2 and see the same output.
For your question
Is it because the array is of type a, which only contains the first variable?
No: in the select type part with the output t is a non-polymorphic entity of type b.
You may work around this problem by avoiding using the structure constructor:
arr(1)%item = o1
I also see that Intel compilers before 18.0.2 do something different still.
1 With the declaration
class(container), allocatable :: arr(:)
arr is polymorphic and allocatable. As ripero notes, this means that arr(1), the element of arr is polymorphic. However, as an array element, arr(1) is not itself polymorphic and so may not be on the left-hand side of an intrinsic assignment statement. We can change the code in two ways: provide defined assignment, or make arr not polymorphic. In the code of the question there seems no reason to have the container polymorphic, so I'll consider
type(container), allocatable :: arr(:)
Further, as discussed in comments on the question, if you wish to work with gfortran 8, or earlier, to see what happens, you should also modify the code in the question so that the definition of the derived type container comes after the definition of the derived type a.

Related

Declaration of dummy argument explicit shape arrays in Fortran

I thought that the specification of an explicit shape dummy argument array in a subroutine can involve any integer variables, including other dummy variables (usual cases), module variables, and local variables of the present subroutine. But it turns out that local variables (which are not dummy variables) can not be used in the specification.
An example is as follows:
module mp
implicit none
contains
subroutine p(b)
integer :: m=4, n=4 !not integer,parameter :: m=4, n=4
integer :: b(m,n)
end subroutine p
end module mp
gfortran will raise Error: Variable 'm' cannot appear in the expression at (1)
For this example, I can use integer,parameter :: m=4, n=4 to avoid this, but I do not understand why the original case does not work, considering the fact that the bounds/extents of explicit shape arrays do not need to be known at compile time. A modified version of the above example works:
module mp
implicit none
integer :: m=4, n=4
contains
subroutine p(b)
integer :: b(m,n)
end subroutine p
end module mp
Considering the slight difference between the two examples, I expect both of them work, but in fact the former does not. Could someone explain the reason?
Update: I found out that this is a very subtle issue because it depends on whether the subroutine is contained in a module or is standalone, it also depends on the version of gfortran. I have posted examples in the answer region.
Formally, there are requirements on what the bounds in such an explicit shape array are. These don't simply map to "don't have to be known at compile time".
For an array explicit shape, the array bounds must be specification expressions. Often, such bounds must be constant expressions, but this is not the case for dummy arguments. This partly gives rise to the (erroneous) thought that they needn't be known at compile time.
However, the constraints for a specification expression must still be met. These can be found in Fortran 2018 10.1.11. In particular, a local variable (even a saved one) may not appear in a specification expression.
For the examples of the question, using named constants such as with
integer, parameter :: m=4, n=4
is allowed in a specification expression. Indeed, the specification expressions m and n are even constant expressions in this case.
If we had
function p(b,m,n)
integer m, n, b(m,n)
end function
then we have valid specification expressions for the array bounds, even though m and n are not constants.
The right workaround is to put the procedure body in a BLOCK construct:
module mp3
contains
subroutine p(b)
implicit none
integer :: m=4, n=4
BLOCK
integer :: b(m,n)
END BLOCK
end subroutine p
end module mp3
The fact that it works in gfortran-8 as a standalone subroutine should be reported on bugzilla. You've got a nice minimal example there.
EDIT: I hadn't noticed that b was a dummy argument. I was thinking more in terms of something like
module mp3
contains
subroutine p(x)
implicit none
real x
integer :: m=4, n=4
BLOCK
integer :: b(m,n)
END BLOCK
end subroutine p
end module mp3
But as the example stands the BLOCK approach just can't work. Also gfortran 8.1.0 rejects the form with the standalone subroutine:
subroutine p(x)
implicit none
real x
integer :: m=4, n=4
integer :: b(m,n)
end subroutine p
Error: Variable 'm' cannot appear in the expression at (1)
(As it should)
Finally, I found out that this is a very subtle issue because it depends on the version of gfortran and also depends on whether the subroutine is contained in a module or is standalone.
Neither gfortran-4.8 or gfortran-8 can compile successfully the following code:
module mp3
contains
subroutine p(b)
implicit none
integer :: m=4, n=4
integer :: b(m,n)
end subroutine p
end module mp3
But if we consider a standalone subroutine as follows:
subroutine p(b)
implicit none
integer :: m=4, n=4
integer :: b(m,n)
end subroutine p
Then gfortran-4.8 still reject this form, but gfortran-8 accepts this, which may be just a bug in gfortran-8 because further testing (by user5713492) indicates that gfortran-8.1.0 also rejects this form.
In summary, local variables of a subroutine are not allowed in the specification expression of dummy argument arrays.
Using local non-constant variables in specification expressions is not very often needed. So it is not a terrible idea to forbid this usage.

Pass a real array if a complex array is expected

I have a Fortran subroutine that expects a complex array like
subroutine foo(cnumbers, n)
integer :: n
complex :: cnumbers(n)
...
end subroutine foo
and later I want to call it like
real :: rnumbers(40)
...
call foo(rnumbers, 20)
However, I get the compiler error:
error #6633: The type of the actual argument differs from the type of the dummy argument.
Of course, this is comprehensible since a real array is not a complex array. But there must be a way to make it work.
Because if the subroutine foo and the call of foo are in different modules and are written down in different Fortran files, then the compiler does not complain, and everything works fine.
Does someone know how to make it work? How to pass a real array if a complex array is expected?
You can either use transfer(rnumbers, ...) to convert the type (a temporary array is likely to be created) or use equivalence to avoid it
real :: rnumbers(40)
complex :: cnumbers(20)
equivalence (rnumbers, cnumbers)
set the value of rnumbers
call foo(cnumbers, 20)
If you need allocatable arrays the equivalence will not work.
You can also use an external subroutine and lie the compiler about the interface and just pass the real array instead of the complex one. It is not standard conforming, but it is sometimes used. See also Gfortran complex actual to real dummy argument

How to pass assumed size arrays from fortran90/95 to fortran77 and back?

I'm working on a project, where the results of a numerical simulation program are to be optimized to fit measured behavior. I wrote some freeform Fortran routines to extract specific data and perform some preliminary calculations, which work fine. For the optimization purpose, i plan to use a local search algorithm provided here: http://mat.uc.pt/~zhang/software.html#bobyqa
I pass some arguments like dimensions and parameter vectors into the Fortran 77 routine, and the problem is, that the transferred argument arrays don't reach the other side. Only the first element will show up in an array with dimension 1.
I found some helpful answers in How to use Fortran 77 subroutines in Fortran 90/95? and tried to contain all 77 code in a module but i still don't get it done.
An explicit interface helps to get all variables into level1 f77 subroutine, but when stuff is beeing passed to another (level2), where assumed size arrays are to be constructed, 1-dimensional arrays are generated if at all.
I compile the f77 code first using ifort -c -fixed (and tried -f77rtl), then f90 and link all together.
Why are the assumed size arrays not generated properly?? The test program from vendor works fine!
How can i pass all needed data through and back in a defined way, without using explicit interfaces? Or is there a way to define suitable interfaces?
Here some example code:
program main_f90
use types
implicit none
real(dp) :: array(N)
interface
subroutine sub77_level1(array)
implicit real*8 (a-h,o-z)
real*8, intent(inout) :: array
dimension array(:)
end subroutine
end interface
[...fill array...]
call sub77_level1(array)
end
subroutine sub77_level1(array)
implicit real*8 (a-h,o-z)
integer i1, i2, i3, i4
dimension array(:)
[...modify array...]
call sub77_level2(array(i1), array(i2), array(i3), i4)
return
end
subroutine sub77_level2(array_1, array_2, array_3, i4)
implicit real*8 (a-h,o-z)
dimension array_1(*) array_2(*) array_3( i4, * )
[...modify...]
call sub_f90( <some other arrays, intent(in / out)> )
return
end

Fortran and C Mixed Programming (Shared Memory)

I have an existing Fortran codebase I'm working with and it's quite large. I am no Fortran programmer so I know that I'm not doing everything correctly here.
I'm trying to create and initialize an array of 1.6 million integers. I cannot get this to initialize in Fortran (using ifort or gfort) as I either would have too many line continuations or too long of lines.
So naturally, I switched to C and wrote a function to just initialize an array and it compiles in seconds with no problem. Now I'm trying to link the two together properly. I created a small test case here to simplify things. Here are the three files I'm working with:
init.c
void c_init_()
{
static const int f_init_g[1600000] =
{
3263, 322, 3261, 60, 32249, 32244, 3229, 23408, 252407, 25326,
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806,
---------------------------------------------------------------------
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806
};
}
init_mod.f90
MODULE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
SAVE
TYPE :: INIT_TYPE
INTEGER (C_INT), DIMENSION(1600000) :: INIT
END TYPE INIT_TYPE
TYPE (C_PTR), BIND(C,NAME="f_init_g") :: INIT_CP
TYPE (INIT_TYPE), POINTER :: INIT_FP
END MODULE INIT_MOD
main.f90
PROGRAM INIT
USE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
TYPE (INIT_TYPE) :: INIT_T
CALL c_init()
CALL C_F_POINTER(INIT_CP,INIT_FP)
INIT_T = INIT_FP
END PROGRAM INIT
I compile this using the following commands:
icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o
I get a segmentation fault when running because INIT_CP points to nothing as far as I can tell. I know I'm not successfully getting INIT_CP to point at the array in my C function. So I'm trying to figure out how to do that.
I would like if someone has a suggestion on how to initialize this array natively in Fortran. My final option that I'll do is make a small initialization of this array in assembly and write a script to generate the assembly code to initialize this array myself (based off the assembly from the small initialization I can mimic the same thing for any size array). I'm not as excited to do that, but it may be the easiest and most reliable solution.
Most importantly I want other Fortran subroutines that use this array to see that it is static in shape and value so that appropriate inter procedural optimizations can be done.
Fortran-C Interoperable variables must have external linkage. As suggested by others in the comments, move the C declaration to file scope and lose the static specifier.
There is no need for an intermediate C_PTR - a Fortran array variable is directly interoperable with the appropriate C array.
Reducing the size of the array slightly:
/* C File scope */
const int f_init_g[3] = { 101, 102, 103 };
! Fortran
MODULE m
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT
IMPLICIT NONE
INTEGER(C_INT), BIND(C, NAME='f_init_g') :: f_init_g(3)
END MODULE m
PROGRAM p
USE m
IMPLICIT NONE
PRINT *, f_init_g(2)
END PROGRAM p
Note that the starting premise - that it is impossible to define or initialize such an array from within Fortran only - is false. The rules around constant expressions in Fortran permit reference to existing named constants, including named constants that are arrays. If you decide to persist with this madness, and assuming that the value of the initializer cannot be described by some sort of expression, consider:
INTEGER, PARAMETER :: first(10) &
= [ 3263, 322, 3261, 60, 32249, &
32244, 3229, 23408, 252407, 25326 ]
INTEGER, PARAMETER :: second(10) &
= [ 25805, 25723, 25562, 25787, 4549, &
32248, 32244, 32243, 253207, 21806]
...
INTEGER, PARAMETER :: f_init_g(1600000) = [ first, second, ... ]
You will probably need intermediate named constant arrays before the final array constructor.
In the immediate above, f_init_g is a named constant, which is very visible to the compiler, and more likely to result in the optimisations that you seek.
However, you may run into compiler complexity limits, that defeat this latter approach.
When f_init_g is a variable initialized by C, you are basically reliant on the inter-language and inter-procedural optimisation capabilities of your tool set - and if those capabilities even exist, I wouldn't expect much from them for this case. I expect that you aren't going to lose much performance wise, beyond the one-off time for IO, if you read the value of the array in from a file at runtime.

Use of unlimited polymorphic type for array operation in Fortran 03/08 (gfortran compiler)

I'd like to realize useful array operations (add element, remove element, different realizations by allocatable/pointer/binary tree structures) by class(*) feature (unlimited polymorphism). I use gfortran 5.0 that should handle such a feature. I need it for not repeating identical code for each type I use.
This should look something like
function add_element(array,element)
class(*),intent(in)::array(:)
class(*),intent(in)::element
class(*)::add_element(size(array)+1)
add_element=[array,element]
end function
The problem is that when I try to use this function with some definite type, I have an error with returning result. I can not assign class(*) to some definite type variable without select type, and I surely don't want to have select type structures every time I use it. And inside a subroutine I should not know anything of types I want to use, because I will create many of them.
I tried some variants with move_alloc, source, tried to use subroutine with intent(out) argument etc. It didn't work. I think it should be defined in argument attributes, the same as size (with source keyword?) but didn't find an example or a definition of such structure in standard. Of course I will study this standard more (I'm not a professional programmer but physicist trying to make my programs testable, checkable and more comfortable to change) and will simply repeat this code now in waiting for better solution, but maybe anybody knows where to search it in the standard or some book? I think this is not only about arrays but use of class(*) at all as I think there should be methods that don't know of types...
Don't know if I should add examples of other not working forms of this subroutine or what it says about the error - or a question will be unfocused. It can be compiled, but in all cases assigning to definite type in call doesn't work. For argument intent(out) or (inout) it can not go from dummy argument to actual argument. Reallocation from source makes an object which has type (and a result of assigning in my example too), but the type is hidden... and I can't use the select type in subroutine because I don't know the type.
Also I don't know constructs that could check "the same type as" or something in this context...
This is not an easy problem You can use select type, but Fortran doesn't have anything like type is(type_of(x)). On the other hand, there are the SAME_TYPE_AS() and EXTENDS
TYPE_OF() intrinsics, but you cannot use them as type guards.
It is necessary to assure, that the dynamic types of both array and element are the same.
I think this is a deficiency in the standard.
But still, there is an error in your approach. You should make the function result allocatable, to be able to allocate it to correct dynamic type:
class(*), allocatable ::add_element(:)
You may think something along the lines of: (UNTESTED! compiles with gfortran-4.9 ifort14)
allocate(add_element(size(array)+1), mold=array)
But how to actually transfer the values I don't know and I am worried it might not be possible without resorting to some dirty tricks.
You cannot even use transfer and that is where I see real deficiency. Eventhough you can call transfer with polymorphic mold
transfer(element, add_element(1))
you have no way to assign it to the array element
add_element(1) = transfer(element, add_element(1))
My opinion is that Fortran lacks an option for the type guards that just ensures that two variables have the same dynamic type.
You may think something along the lines of: (UNTESTED! compiles with gfortran-4.9 ifort14)
function add_element(array,element)
use iso_c_binding
implicit none
class(*),intent(in)::array(:)
class(*),intent(in)::element
class(*), allocatable ::add_element(:)
type(c_ptr) :: tmp
interface
function memcpy(dest, src, n) bind(c)
use iso_c_binding
integer(c_intptr_t),value :: dest, src
integer(c_size_t) :: n
type(c_ptr) :: memcpy
end function
end interface
allocate(add_element(size(array)+1), mold=array)
tmp = memcpy(loc(add_element(size(array)+1)), &
loc(array), &
size(array, kind=c_size_t) * storage_size(array, c_size_t)/8_c_size_t )
tmp = memcpy(loc(add_element(size(array)+1)), &
loc(array(1)), &
storage_size(element, c_size_t)/8_c_size_t )
end function
CLASS(*) is a facility that basically allows runtime type safe but type agnostic storage. You are trying to use it as a compile time type parameterisation mechanism. It isn't terribly appropriate for that, and the language doesn't directly support an alternative means.
Traditionally type parameterisation is done by placing the common parts of the procedures to be parameterised in a separate file, and then including that file as appropriate, perhaps in a module that uses implicit typing to specify the type to be parameterised.
If you must use CLASS(*), you practically need to write and use a wrapper type. If all you are wrapping is basic array operations, then this will be far more trouble than it is worth.
In client code (versus your common procedures) to extract the thing that has been stored you generally need to use SELECT TYPE (you can use pointer assignment if the type of the data has BIND(C) or SEQUENCE, but this isn't type safe).
TYPE :: Wrapper
CLASS(*), ALLOCATABLE :: item
END TYPE Wrapper
FUNCTION add_element(array, element)
TYPE(Wrapper), INTENT(IN) :: array(:)
CLASS(*), INTENT(IN) :: element
TYPE(Wrapper), INTENT(OUT) :: add_element(SIZE(array)+1)
! If you want to enforce type consistency (at runtime)...
IF (SIZE(array) > 0) THEN
IF (.NOT. SAME_TYPE_AS(array(1)%item, element)) THEN
STOP 'Objects not of same type!'
END IF
END IF
add_element(:SIZE(array)) = array
add_element(SIZE(add_element))%item = element
END FUNCTION add_element
FUNCTION get(scalar)
TYPE(Wrapper), INTENT(IN) :: scalar
CLASS(*), ALLOCATABLE :: get
get = scalar%item
END FUNCTION get
...
TYPE(Wrapper), ALLOCATABLE :: array(:)
array = [ Wrapper :: ]
array = add_element(array, 'cat')
array = add_element(array, 'dog')
DO i = 1, SIZE(array)
SELECT TYPE (item => get(array(i)))
TYPE IS (CHARACTER(*))
PRINT "(A)", item
END SELECT
END DO

Resources