Fortran: modules and array size [duplicate] - arrays

The following code, combining module procedures and external procedures:
module module_dummy
implicit none
contains
subroutine foo(a)
real, intent(inout) :: a(:)
call bar(a)
end subroutine foo
end module module_dummy
program main
use module_dummy
implicit none
integer, parameter :: nelems = 100000000
real, allocatable :: a(:)
allocate( a(nelems) )
a = 0.0
call foo(a)
print *, a(1:10)
deallocate(a)
end program main
subroutine bar(a)
implicit none
real, intent(inout) :: a(:)
a = 1.0
end subroutine bar
seems to fail either:
with a segmentation fault
printing a block of 0.000 instead of a block of 1.000
on any platform I have tried so far. The problem is related to the implicit interface declaration of bar, and in fact the issue can be solved adding in any way an explicit interface, e.g. using:
module module_dummy
implicit none
contains
subroutine foo(a)
interface
subroutine bar(x)
real, intent(inout) :: x(:)
end subroutine bar
end interface
real, intent(inout) :: a(:)
call bar(a)
end subroutine foo
end module module_dummy
or declaring bar inside a module to be used by module_dummy.
Anyhow I really don't understand what is the error in the first place. What I have found on the Fortran 90 standard (sec. 12.3.2.4) says that:
The type, type parameters, and shape of dummy arguments of a procedure
referenced from a scoping unit where the interface of the procedure is
implicit must be such that the actual arguments are consistent with
the characteristics of the dummy arguments.
In this case the rule seems to be respected, as a is always declared as
real, intent(inout) :: a(:)
So, what am I missing in the interpretation of the standard that makes the previous code wrong?

Dummy arguments that are assumed shape must have an explicit interface at their point of reference. F90 12.3.1.1 item 2c.
Practically, assumed shape arrays are passed by passing a descriptor - a little structure that describes the bounds and the location of storage of the array. Ye-olde F77 explicit shape and assumed size arrays are passed simply by passing the address of the first element. Without the explicit interface the compiler doesn't know that it needs to build and pass the descriptor - hence chaos and confusion results.

Related

Warning for explicit-shape array reshaping

Let all routines be inside modules.
If I pass the array real*8 aa(5,3) to a routine
subroutine sub(bb)
real*8, intent(in) :: bb(2,5)
...
end subroutine
with the statement call sub(aa) this will compile without a warning and the first 2 columns of aa will fill the bb array. The elements of the arrays aa and bb are aligned very differently.
If instead the routine is written
subroutine sub(bb)
real*8, intent(in) :: bb(:,:)
...
end subroutine
then bb would have the same shape and storage order as aa.
Q: The first behavior is quite dangerous if one forgets that there are explicit-size declarations in a routine. Can I make the compiler warn when explicit-shape arrays change shape/alignment?
I am not aware of a compiler option to warn about this as it is a perfectly legitimate practise using the storage association - we have several questions and answers about this concept. It can be quite useful.

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.

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 - allocatable array in subroutine

I'm trying to use an allocatable array in a subroutine but the compiler complains that
Error: Dummy argument 'locs' with INTENT(IN) in variable definition context (ALLOCATE object) at (1)
The only thing I could find was that I am supposed to use an explicit interface, which I am doing. Here the relevant code for the subroutine:
RECURSIVE SUBROUTINE together(locs, LL, RL)
INTEGER, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: locs
INTEGER, INTENT(IN) :: LL, RL
ALLOCATE(locs(LL,RL))
END SUBROUTINE together
The compiler's error message is one descriptive of the problem. With INTENT(IN) you are saying that the object will not change, but you then go on to attempt to ALLOCATE it.
Yes, an explicit interface will be required for the calling, but that isn't the problem.
The Fortran 2008 standard says in section 5.3.10 that
A nonpointer object with the INTENT (IN) attribute shall not appear in a variable denition context
Allocation is one such context: section 16.6.7, point (11).
The locs dummy argument is allocatable, and has the INTENT(IN) attribute - the intent attribute here indicating that the calling procedure is providing information to the subroutine.
A consequence of the INTENT(IN) attribute is that you cannot change the allocation status (or value) of locs. Your ALLOCATE statement is attempting to do just that.
Try allocating your array in your main program, then when locs is pushed to your subroutine, use INTENT(INOUT) to tell the compiler you also want to change the contents of your array.

Can a scalar C function be called from Fortran with array arguments?

I recently came across a situation where I wanted to call a C function from Fortran, because of a useful snippet of C code. For convenience in array operations, I wanted to be able to call this function with array arguments as well, but it only accepted scalar arguments.
In Fortran, one can of course simply declare a procedure to be elemental to achieve this, and one can declare an interface to a C procedure with bind(C). However, since C does not have the concept of elemental procedures, the Fortran (2008) standard rules out this combination:
C1246 An elemental procedure shall not have the BIND attribute.
So, can this functionality be achieved in Fortran?
After some searching, I found that this is both possible and quite straightforward, using Fortran 2003 and the iso_c_binding intrinsic module; I thought I should document this here. An interface with the bind attribute can still be pure, so it can be referenced within a Fortran procedure which is itself elemental.
The following is a short example with the C99 macro isnan, which returns a non-zero integer value if its argument is NaN. Of course, this can also be done for any user-defined C/C++ function that is free of side effects.
elemental function isnan(val)
use, intrinsic :: iso_c_binding
implicit none
real(c_double), intent(in) :: val
logical(c_bool) :: isnan
interface
pure function isnan_C(val) bind(C, name = 'isnan')
import
! Pass the parameter by value:
real(c_double), value, intent(in) :: val
integer(c_int) :: isnan_C
end function
end interface
isnan = isnan_C(val) /= 0_c_int
end function
Example output using an array with some NaN values:
program main
use, intrinsic :: iso_c_binding
implicit none
real(c_double) :: nan(2,2) = 0.
nan(:,2) = nan(1,1)/0.
write(*,'(4F6.2 / 4L6)') nan, isnan(nan) ! Output: 0.00 0.00 NaN NaN
! F F T T
end program

Resources