Dynamic array rank - fortran

I have a few array variables in a module that are dynamic, and later allocated in one of two subroutines outside of the module. However, in one subroutine I want the array to be 1D, in the other subroutine I want it to be 2D.
In principle I would want something like this in the module, but I don't believe this is possible in the declaration area?:
if (option1) then
real (kind=8), allocatable :: arr1(:)
else
real (kind=8), allocatable :: arr1(:,:)
endif
Is there a way in the allocatable declarations to have the dimension be dynamic?
Edit1: The reason I'm doing this is I'm adding a new subroutine to an existing codebase, but I want to be backwards compatible. arr1 is only used by the two separate subroutines, the main program doesn't use it at all. Here is some more complete code showing the idea:
program myprog
use inputs
call read_inputs
if (option1) then
call do1
else
call do2
endif
contains
subroutine read_inputs
use inputs
use mymod
!!!read from file .logical. option1, integers N1, N2
!allocate arrays
if (option1) then
else
endif
end subroutine read_inputs
subroutine do1
use inputs
use mymod
allocate(arr1(N1))
!do stuff with arr1
end subroutine do1
subroutine do2
use inputs
use mymod
allocate(arr1(N1,N2))
!do stuff with arr1
end subroutine do2
end program
module inputs
logical :: option1
integer :: N1, N2
end module inputs
module mymod
use inputs
!!!!can I do something here to make the rank of arr1 dynamic? I don't think the following will work
if (option1)
real (kind=8), allocatable :: arr1(:)
else
real (kind=8), allocatable :: arr1(:,:)
endif
end module mymod
I may just have two separate variable in mymod, arr1 and arr1_new. I was just hoping to avoid that.

I think the 'olden' ways to do something like this is to pass the first element instead of the whole array and the size of the array separately:
program dyn_array
implicit none
integer :: a(2, 3)
integer :: i
call set1d(a(1,1), size(a))
do i = 1, 3
write(*, '(2I4)') a(:,i)
end do
contains
subroutine set1d(array, s)
implicit none
integer, intent(in) :: s
integer, intent(out) :: array(s)
integer :: i
do i = 1, s
array(i) = 3 * i
end do
end subroutine set1d
end program dyn_array

"Can you pass a 2D array into a subroutine that expects a 1D array and get the right size?"
You can use reshape, but if you code is relying on the compiler to help then a 2D into a 1D is dicey. You could use RESHAPE before and after... Or you can have 2 routines, which we can call set1d and set2d.
Then in the module you can have it choose what one you want to use. You could have integer(s), float(s), complex(s), byte.
You would CALL Array$Set(Array,s)
MODULE Stuff
PUBLIC :: Array$Set
PRIVATE
INTERFACE Array$Set
MODULE PROCEDURE Set1d_Float, Set1D_Double, set2D_Float, Set2D_Double
END INTERFACE Array$Set
CONTAINS
SUBROUTINE Set1D_Float(Array,S)...
!$DIR ATRIBUTES ASUUME_ALIGND:64 :: Array
REAL, DIMENSION(:,:), CONTIGUOUS, INTENT(INOUT) :: Array
REAL, DIMENSION(:,:), INTENT(IN ) :: S
REAL, DIMENSION(2) :: Shapez
...
Shapez = Shape(Array)
DO I = 1, Shapez(1)
DO J = 1, Shapez(2)
...
END SUBROUTINE Set1D_Float
END MODULE Stuff
For your example:
if (option1) then
real (kind=8), allocatable :: arr1(:)
else
real (kind=8), allocatable :: arr1(:,:)
endif
I would suggest this:
!DIR ATTRIBUTES ALIGN:64 :: Arr1
REAL, DIMENSION(:), ALLOCATABLE :: Arr1
...
if (option1) then
ALLOCATE(Arr1(<#>))
else
ALLOCATE(Arr1(<#>*<#2>))
RESHAPE(Arr1, SHAPE=/(#1,#2)) !Check the syntax
endif
CALL Array$Set(Arr1,s) !It'll find the right one...
!... at the bottom ...
IF(ALLOCATED(Arr1)) DEALLOCATE(Arr1)
END PROGRAM

Related

Why an allocated array gets unallocated when it is passed to a subroutine?

Passing an allocatable array via actual argument to a subroutine whose corresponding dummy argument is defined as an allocatable array:
module m
real, allocatable :: a(:,:)
end module m
module m2
contains
subroutine p(c)
implicit none
real, allocatable, intent(out):: c(:,:)
write(*,*) 'allocated?=', allocated(c)
end subroutine p
end module m2
program main
use m, only : a
use m2, only: p
implicit none
allocate(a(3,3))
write(*,*) 'allocated?=', allocated(a)
call p(a)
end program main
The output:
allocated?= T
allocated?= F
The first is as expected, but why the allocated status becomes false, as is indicated by the second output?
Allocatable dummy arguments that have intent(out) are automatically deallocated when the procedure is entered according to thevstandard. The intent also affects the allocation status, not just the values inside.
It actually makes a very good sense. If it is intent(out), any previous allocation status should not matter.

array operation in fortran

I am writing a code with a lot of 2D arrays and manipulation of them. I would like the code to be as concise as possible, for that I would like to use as many 'implicit' operation on array as possible but I don't really know how to write them for 2D arrays.
For axample:
DO J=1,N
DO I=1,M
A(I,J)=B(J)*A(I,J)
ENDDO
ENDDO
become easily:
DO J=1,N
A(:,J)=B(J)*A(:,J)
ENDDO
Is there a way to reduce also the loop J?
Thanks
For brevity and clarity, you could wrap these operations in a derived type. I wrote a minimal example which is not so concise because I need to initialise the objects, but once this initialisation is done, manipulating your arrays becomes very concise and elegant.
I stored in arrays_module.f90 a derived type arrays2d_T which can hold the array coefficients, plus useful information (number of rows and columns). This type contains procedures for initialisation, and the operation you are trying to perform.
module arrays_module
implicit none
integer, parameter :: dp = kind(0.d0) !double precision definition
type :: arrays2d_T
real(kind=dp), allocatable :: dat(:,:)
integer :: nRow, nCol
contains
procedure :: kindOfMultiply => array_kindOfMuliply_vec
procedure :: init => initialize_with_an_allocatable
end type
contains
subroutine initialize_with_an_allocatable(self, source_dat, nRow, nCol)
class(arrays2d_t), intent(inOut) :: self
real(kind=dp), allocatable, intent(in) :: source_dat(:,:)
integer, intent(in) :: nRow, nCol
allocate (self%dat(nRow, nCol), source=source_dat)
self%nRow = nRow
self%nCol = nCol
end subroutine
subroutine array_kindOfMuliply_vec(self, vec)
class(arrays2d_t), intent(inOut) :: self
real(kind=dp), allocatable, intent(in) :: vec(:)
integer :: iRow, jCol
do jCol = 1, self%nCol
do iRow = 1, self%nRow
self%dat(iRow, jCol) = vec(jCol)*self%dat(iRow, jCol)
end do
end do
end subroutine
end module arrays_module
Then, in main.f90, I check the behaviour of this multiplication on a simple example:
program main
use arrays_module
implicit none
type(arrays2d_T) :: A
real(kind=dp), allocatable :: B(:)
! auxilliary variables that are only useful for initialization
real(kind=dp), allocatable :: Aux_array(:,:)
integer :: M = 3
integer :: N = 2
! initialise the 2d array
allocate(Aux_array(M,N))
Aux_array(:,1) = [2._dp, -1.4_dp, 0.3_dp]
Aux_array(:,2) = [4._dp, -3.4_dp, 2.3_dp]
call A%init(aux_array, M, N)
! initialise vector
allocate (B(N))
B = [0.3_dp, -2._dp]
! compute the product
call A%kindOfMultiply(B)
print *, A%dat(:,1)
print *, A%dat(:,2)
end program main
Compilation can be as simple as gfortran -c arrays_module.f90 && gfortran -c main.f90 && gfortran -o main.out main.o arrays_module.o
Once this object-oriented machinery exists, call A%kindOfMultiply(B) is much clearer than a FORALL approach (and much less error prone).
No one has mentioned do concurrent construct here, which has the potential to automatically parallelize and speed up your code,
do concurrent(j=1:n); A(:,j)=B(j)*A(:,j); end do
A one-line solution can be achieved by using FORALL:
FORALL(J=1:N) A(:,J) = B(J)*A(:,J)
Note that FORALL is deprecated in the most recent versions of the standard, but as far as I know, that is the only way you can perform that operation as a single line of code.

Why does a subroutine with an array from a "use module" statement give faster performance than the same subroutine a locally sized array?

Related to this question, but I believe the issue is more clearly identified with this example.
I have some legacy code that looks like this:
subroutine ID_OG(N, DETERM)
use variables, only: ID
implicit real (A-H,O-Z)
implicit integer(I-N)
DETERM = 1.0
DO 1 I=1,N
1 ID(I)=0
DETERM = sum(ID)
end subroutine ID_OG
Replacing use variables, only: ID with real, dimension(N) :: ID or real, dimension(:), allocatable :: ID causes a noticeable performance loss. Why is this? Is this expected behavior? I am wondering if it has something to do with the program needing to repeatedly allocate memory for the local array ID, while the use statement allows the program to skip the memory allocation step.
In the legacy code ID is in module variables but it is only used within the subroutine ID_OG. It is not used anywhere else in the code - it is not an input or an output. To me, it seems like good programming practice for ID to be removed from module variables and defined locally in the subroutine. But perhaps that isn't the case.
Minimum working example (MWE):
compiling as gfortran -O3 test.f95 using gfortran 8.2.0
MODULE variables
implicit none
real, dimension(:), allocatable :: ID
END MODULE variables
program test
use variables
implicit none
integer :: N
integer :: loop_max = 1e6
integer :: ii ! loop index
real :: DETERM
real :: t1, t2
real :: t_ID_OG, t_ID_header, t_ID_no_ID, t_OG_no_ID, t_allocate
character(*), parameter :: format_header = '((A5, 1X), 20(A12,1X))'
character(*), parameter :: format_data = '((I5, 1X), 20(ES12.5, 1X))'
open(1, file = 'TimingSubroutines_ID.txt', status = 'unknown')
write(1,format_header) 'N', 't_Legacy', 't_header', 't_head_No_ID', 't_Leg_no_ID', &
& 't_allocate'
do N = 1, 100
allocate(ID(N))
call CPU_time(t1)
do ii = 1, loop_max
CALL ID_OG(N, DETERM)
end do
call CPU_time(t2)
t_ID_OG = t2 - t1
print*, N, DETERM
call CPU_time(t1)
do ii = 1, loop_max
CALL ID_header(N, DETERM)
end do
call CPU_time(t2)
t_ID_header = t2 - t1
print*, N, DETERM
call CPU_time(t1)
do ii = 1, loop_max
CALL ID_header_no_ID(N, DETERM)
end do
call CPU_time(t2)
t_ID_no_ID = t2 - t1
print*, N, DETERM
call CPU_time(t1)
do ii = 1, loop_max
CALL ID_OG_no_ID(N, DETERM)
end do
call CPU_time(t2)
t_OG_no_ID = t2 - t1
print*, N, DETERM
call CPU_time(t1)
do ii = 1, loop_max
CALL ID_OG_allocate(N, DETERM)
end do
call CPU_time(t2)
t_allocate = t2 - t1
print*, N, DETERM
deallocate(ID)
write(1,format_data) N, t_ID_OG, t_ID_header, t_ID_no_ID, t_OG_no_ID, t_allocate
end do
end program test
subroutine ID_OG(N, DETERM)
use variables, only: ID
implicit real (A-H,O-Z)
implicit integer(I-N)
DETERM = 1.0
DO 1 I=1,N
1 ID(I)=0
DETERM = sum(ID)
end subroutine ID_OG
subroutine ID_header(N, DETERM)
use variables, only: ID
implicit none
integer, intent(in) :: N
real, intent(out) :: DETERM
integer :: I
DETERM = 1.0
DO 1 I=1,N
1 ID(I)=0
DETERM = sum(ID)
end subroutine ID_header
subroutine ID_header_no_ID(N, DETERM)
implicit none
integer, intent(in) :: N
real, intent(out) :: DETERM
integer :: I
real, dimension(N) :: ID
DETERM = 1.0
DO 1 I=1,N
1 ID(I)=0
DETERM = sum(ID)
end subroutine ID_header_no_ID
subroutine ID_OG_no_ID(N, DETERM)
implicit real (A-H,O-Z)
implicit integer(I-N)
real, dimension(N) :: ID
DETERM = 1.0
DO 1 I=1,N
1 ID(I)=0
DETERM = sum(ID)
end subroutine ID_OG_no_ID
subroutine ID_OG_allocate(N, DETERM)
implicit real (A-H,O-Z)
implicit integer(I-N)
real, dimension(:), allocatable :: ID
allocate(ID(N))
DETERM = 1.0
DO 1 I=1,N
1 ID(I)=0
DETERM = sum(ID)
end subroutine ID_OG_allocate
Allocating the arrays takes time. The compiler is free to allocate the local arrays where-ever it wants, but it can typically be adjusted by compiler-specific flags. Use -fstack-arrays for gfortran to force local arrays to stack.
Allocating on the stack is just changing the stack pointer, it is virtually for free. Allocating on the heap, however, is more involved and requires some bookkeeping.
There are situations where local variables are in order and there are situations where global (module) variables are in order. One can also use local saved variables or variables that are components of some objects. One cannot say which one is better without seeing the complete design of the code in question.
FWIW, with -fstack-arrays I do not see much difference except when allocating explicitly using allocate():
Explicit allocate will always use the heap.
Without -fstack-arrays I do see some:
The graphs are quite noisy because my notebook is running many processes at the same time.
This is not to say that one should always use -fstack-arrays, I used to demonstrate the difference. The option is useful, but care must be taken to avoid a stack overflow error. -fmax-stack-var-size may help with that.
As your tests are pointing out, the additional overhead of all methods which do not use the module variable is due to the language's phylosophy to not bother the user with memory handling too much.
The compiler will decide where memory should be allocated, unless you start tinkering with compiler flags. You see allocation/freeing time as a drawback, but your analysis also shows:
stack vs. heap memory handling overhead quickly gets smaller and smaller: for N>=100, it is already <50%. a dimension(100) array is a ridiculously small memory chunk on a modern computer.
declaring a variable in a module just for speeding up storage is a Fortran 90 way of making it a global, and as such, it is a deprecated coding style.
I think the best strategy to make the code well-coded and fast is:
Is N going to be constant through the whole runtime? Then, it would be a good idea to encapsulate it into a class:
module myCalculation
implicit none
type, public: fancyMethod
integer :: N = 0
real, allocatable :: ID(:)
contains
procedure :: init
procedure :: compute
procedure :: is_init
end type fancyMethod
contains
elemental subroutine init(self,n)
class(fancyMethod), intent(inout) :: self
integer, intent(in) :: n
real, allocatable :: tmp(:)
self%N = n
allocate(tmp(N)); tmp(:) = 0
call move_alloc(from=tmp,to=self%ID)
end subroutine init
elemental logical function is_init(self)
class(fancyMethod), intent(in) :: self
is_init = allocated(self%ID) .and. size(self%ID)>0
end function is_init
real function compute(self,n,...) result(DETERM)
class(fancyMethod), intent(inout) :: self
integer, intent(in) :: n
....
if (.not.is_init(self)) call init(self,N)
DETERM = sum(self%ID(1:N))
end function compute
end module myCalculation
Is N going to be constant and small? Why not just use a PARAMETER to define its max size? if it is a parameter, the compiler will perhaps always put the automatic array on the stack:
real function computeWithMaxSize(N) result(DETERM)
integer, intent(in) :: N
integer, parameter :: MAX_SIZE = 1024
real :: ID(MAX_SIZE)
[...]
if (N>MAX_SIZE) stop ' N is too large! '
DETERM = sum(ID(1:N))
end function computeWithMaxSize
Is N going to be variable-sized and large? Then, the in-routine memory handling is fine, and its overhead is likely negligible, because the CPU time will be dominated by the calculation; use an allocatable version if you're not sure that the size can be so large to cause any stack issues:
real function computeWithAllocatable(N) result(DETERM)
integer, intent(in) :: N
real, allocatable :: ID(:)
allocate(ID(N))
[...]
DETERM = sum(ID(1:N))
end function computeWithAllocatable

changing array dimensions in fortran

There are basically two ways to pass arrays to a subroutine in Fortran 90/95:
PROGRAM ARRAY
INTEGER, ALLOCATABLE :: A(:,:)
INTEGER :: N
ALLOCATE(A(N,N))
CALL ARRAY_EXPLICIT(A,N)
! or
CALL ARRAY_ASSUMED(A)
END PROGRAM ARRAY
SUBROUTINE ARRAY_EXPLICIT(A,N)
INTEGER :: N
INTEGER :: A(N,N)
! bla bla
END SUBROUTINE ARRAY_EXPLICIT
SUBROUTINE ARRAY_ASSUMED(A)
INTEGER, ALLOCATABLE :: A(:,:)
N=SIZE(A,1)
! bla bla
END SUBROUTINE ARRAY_ASSUMED
where you need an explicit interface for the second, usually through the use of a module.
From FORTRAN77, I'm used to the first alternative, and I read this is also the most efficient if you pass the whole array.
The nice thing with the explicit shape is that I can also call a subroutine and treat the array as a vector instead of a matrix:
SUBROUTINE ARRAY_EXPLICIT(A,N)
INTEGER :: N
INTEGER :: A(N**2)
! bla bla
END SUBROUTINE ARRAY_EXPLICIT
I wondered if there is a nice way to do that kind of thing using the second, assumed shape interface, without copying it.
See the RESHAPE intrinsic, e.g.
http://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html
Alternatively, if you want to avoid the copy (in some cases an optimizing compiler might be able to do a reshape without copying, e.g. if the RHS array is not used afterwards, but I wouldn't count on it), as of Fortran 2003 you can assign pointers to targets of different rank, using bounds remapping. E.g. something like
program ptrtest
real, pointer :: a(:)
real, pointer :: b(:,:)
integer :: n = 10
allocate(a(n**2))
a = 42
b (1:n, 1:n) => a
end program ptrtest
I was looking to do the same thing and came across this discussion. None of the solutions suited my purposes, but I found that there is a way to reshape an array without copying the data using iso_c_binding if you are using the fortran 2003 standard which current fortran 90/95 compilers tend to support. I know the discussion is old, but I figured I would add what I came up with for the benefit of others with this question.
The key is to use the function C_LOC to convert an array to an array pointer, and then use C_F_POINTER to convert this back into a fortran array pointer with the desired shape. One challenge with using C_LOC is that C_LOC only works for array that have a directly specified shape. This is because arrays in fortran with an incomplete size specification (i.e., that use a : for some dimension) include an array descriptor along with the array data. C_LOC does not give you the memory location of the array data, but the location of the descriptor. So an allocatable array or a pointer array don't work with C_LOC (unless you want the location of the compiler specific array descriptor data structure). The solution is to create a subroutine or function that receives the array as an array of fixed size (the size really doesn't matter). This causes the array variable in the function (or subroutine) to point to the location of the array data rather than the location of the array descriptor. You then use C_LOC to get a pointer to the array data location and C_F_POINTER to convert this pointer back into an array with the desired shape. The desired shape must be passed into this function to be used with C_F_POINTER. Below is an example:
program arrayresize
implicit none
integer, allocatable :: array1(:)
integer, pointer :: array2(:,:)
! allocate and initialize array1
allocate(array1(6))
array1 = (/1,2,3,4,5,6/)
! This starts out initialized to 2
print *, 'array1(2) = ', array1(2)
! Point array2 to same data as array1. The shape of array2
! is passed in as an array of intergers because C_F_POINTER
! uses and array of intergers as a SIZE parameter.
array2 => getArray(array1, (/2,3/))
! Change the value at array2(2,1) (same as array1(2))
array2(2,1) = 5
! Show that data in array1(2) was modified by changing
! array2(2,1)
print *, 'array(2,1) = array1(2) = ', array1(2)
contains
function getArray(array, shape_) result(aptr)
use iso_c_binding, only: C_LOC, C_F_POINTER
! Pass in the array as an array of fixed size so that there
! is no array descriptor associated with it. This means we
! can get a pointer to the location of the data using C_LOC
integer, target :: array(1)
integer :: shape_(:)
integer, pointer :: aptr(:,:)
! Use C_LOC to get the start location of the array data, and
! use C_F_POINTER to turn this into a fortran pointer (aptr).
! Note that we need to specify the shape of the pointer using an
! integer array.
call C_F_POINTER(C_LOC(array), aptr, shape_)
end function
end program
#janneb has already answered re RESHAPE. RESHAPE is a function -- usually used in an assignment statement so there will be a copy operation. Perhaps it can be done without copying using pointers. Unless the array is huge, it is probably better to use RESHAPE.
I'm skeptical that the explicit shape array is more efficient than the assumed shape, in terms of runtime. My inclination is to use the features of the Fortran >=90 language and use assumed shape declarations ... that way you don't have to bother passing the dimensions.
EDIT:
I tested the sample program of #janneb with ifort 11, gfortran 4.5 and gfortran 4.6. Of these three, it only works in gfortran 4.6. Interestingly, to go the other direction and connect a 1-D array to an existing 2-D array requires another new feature of Fortran 2008, the "contiguous" attribute -- at least according to gfortran 4.6.0 20110318. Without this attribute in the declaration, there is a compile time error.
program test_ptrs
implicit none
integer :: i, j
real, dimension (:,:), pointer, contiguous :: array_twod
real, dimension (:), pointer :: array_oned
allocate ( array_twod (2,2) )
do i=1,2
do j=1,2
array_twod (i,j) = i*j
end do
end do
array_oned (1:4) => array_twod
write (*, *) array_oned
stop
end program test_ptrs
You can use assumed-size arrays, but it can mean multiple layers of wrapper
routines:
program test
implicit none
integer :: test_array(10,2)
test_array(:,1) = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/)
test_array(:,2) = (/11, 12, 13, 14, 15, 16, 17, 18, 19, 20/)
write(*,*) "Original array:"
call print_a(test_array)
write(*,*) "Reshaped array:"
call print_reshaped(test_array, size(test_array))
contains
subroutine print_reshaped(a, n)
integer, intent(in) :: a(*)
integer, intent(in) :: n
call print_two_dim(a, 2, n/2)
end subroutine
subroutine print_two_dim(a, n1, n2)
integer, intent(in) :: a(1:n1,1:*)
integer, intent(in) :: n1, n2
call print_a(a(1:n1,1:n2))
end subroutine
subroutine print_a(a)
integer, intent(in) :: a(:,:)
integer :: i
write(*,*) "shape:", shape(a)
do i = 1, size(a(1,:))
write(*,*) a(:,i)
end do
end subroutine
end program test
I am using ifort 14.0.3 and 2D to 1D conversion, I could use an allocatable array for 2D array and a pointer array for 1D:
integer,allocatable,target :: A(:,:)
integer,pointer :: AP(:)
allocate(A(3,N))
AP(1:3*N) => A
As #M.S.B mentioned, in case both A and AP have the pointer attribute, I had to use contiguous attribute for A to guarantee the consistency of the conversion.
Gfortran is a bit paranoid with interfaces. It not only wants to know the type, kind, rank and number of arguments, but also the shape, the target attribute and the intent (although I agree with the intent part). I encountered a similar problem.
With gfortran, there are three different dimension definition:
1. Fixed
2. Variable
3. Assumed-size
With ifort, categories 1 and 2 are considered the same, so you can do just define any dimension size as 0 in the interface and it works.
program test
implicit none
integer, dimension(:), allocatable :: ownlist
interface
subroutine blueprint(sz,arr)
integer, intent(in) :: sz
integer, dimension(0), intent(in) :: arr
! This zero means that the size does not matter,
! as long as it is a one-dimensional integer array.
end subroutine blueprint
end interface
procedure(blueprint), pointer :: ptr
allocate(ownlist(3))
ownlist = (/3,4,5/)
ptr => rout1
call ptr(3,ownlist)
deallocate(ownlist)
allocate(ownlist(0:10))
ownlist = (/3,4,5,6,7,8,9,0,1,2,3/)
ptr => rout2
call ptr(3,ownlist)
deallocate(ownlist)
contains
! This one has a dimension size as input.
subroutine rout1(sz,arr)
implicit none
integer, intent(in) :: sz
integer, dimension(sz), intent(in) :: arr
write(*,*) arr
write(*,*) arr(1)
end subroutine rout1
! This one has a fixed dimension size.
subroutine rout2(sz,arr)
implicit none
integer, intent(in) :: sz
integer, dimension(0:10), intent(in) :: arr
write(*,*) "Ignored integer: ",sz
write(*,*) arr
write(*,*) arr(1)
end subroutine rout2
end program test
Gfortran complains about the interface. Changing the 0 into 'sz' solves the problem four 'rout1', but not for 'rout2'.
However, you can fool gfortran around and say dimension(0:10+0*sz) instead of dimension(0:10) and gfortran compiles and gives the same
result as ifort.
This is a stupid trick and it relies on the existence of the integer 'sz' that may not be there. Another program:
program difficult_test
implicit none
integer, dimension(:), allocatable :: ownlist
interface
subroutine blueprint(arr)
integer, dimension(0), intent(in) :: arr
end subroutine blueprint
end interface
procedure(blueprint), pointer :: ptr
allocate(ownlist(3))
ownlist = (/3,4,5/)
ptr => rout1
call ptr(ownlist)
deallocate(ownlist)
allocate(ownlist(0:10))
ownlist = (/3,4,5,6,7,8,9,0,1,2,3/)
ptr => rout2
call ptr(ownlist)
deallocate(ownlist)
contains
subroutine rout1(arr)
implicit none
integer, dimension(3), intent(in) :: arr
write(*,*) arr
write(*,*) arr(1)
end subroutine rout1
subroutine rout2(arr)
implicit none
integer, dimension(0:10), intent(in) :: arr
write(*,*) arr
write(*,*) arr(1)
end subroutine rout2
end program difficult_test
This works under ifort for the same reasons as the previous example, but gfortran complains about the interface. I do not know how I can fix it.
The only thing I want to tell gfortran is 'I do not know the dimension size yet, but we will fix it.'. But this needs a spare integer arguemnt (or something else that we can turn into an integer) to fool gfortran around.

Store a "pointer to function" in Fortran?

In Fortran, you can pass a function/subroutine A as an argument to another function/subroutine B, but can you store A for later retrieval and use?
for example, this is allowed in C
int foo(float, char, char) { /*whatever*/};
int (*pointerToFunction)(float, char, char);
pointerToFunction = foo;
In Fortran you can pass a subroutine as an argument
subroutine foo
! whatever
end subroutine foo
subroutine bar(func)
call func
end subroutine bar
program x
call bar(foo)
end program
but how can you store the address of foo in a similar way to C ?
Starting from so-called "Fortran 2003" (ISO/IEC 1539-2004) procedure pointers is a part of the Fortran language. It's definitely of the major new features of Fortran language.
Usage example from Fortran Wiki.
Stefano, you mentioned strategy design pattern. In Fortran 2003 you can use pure OOP way to implement it (without procedure pointers). Offhand example:
strategies.f90
module strategies
implicit none
private
public :: strategies_transportation_strategy, &
strategies_by_taxi_strategy, &
strategies_by_bus_strategy
type, abstract :: strategies_transportation_strategy
contains
procedure(transportation_strategy_go), deferred :: go
end type strategies_transportation_strategy
type, extends(strategies_transportation_strategy) :: strategies_by_taxi_strategy
contains
procedure :: go => strategies_by_taxi_strategy_go
end type strategies_by_taxi_strategy
type, extends(strategies_transportation_strategy) :: strategies_by_bus_strategy
contains
procedure :: go => strategies_by_bus_strategy_go
end type strategies_by_bus_strategy
abstract interface
subroutine transportation_strategy_go(this)
import strategies_transportation_strategy
class(strategies_transportation_strategy), intent(in) :: this
end subroutine transportation_strategy_go
end interface
contains
subroutine strategies_by_taxi_strategy_go(this)
class(strategies_by_taxi_strategy), intent(in) :: this
print *, "We are using taxi."
end subroutine strategies_by_taxi_strategy_go
subroutine strategies_by_bus_strategy_go(this)
class(strategies_by_bus_strategy), intent(in) :: this
print *, "We are using public transport."
end subroutine strategies_by_bus_strategy_go
end module strategies
vehicles.f90
module vehicles
use strategies
implicit none
private
public :: vehicles_vehicle, &
vehicles_taxi, &
vehicles_bus
type, abstract :: vehicles_vehicle
private
class(strategies_transportation_strategy), allocatable :: transportation_strategy
contains
procedure :: set_transportation_strategy => vehicle_set_transportation_strategy
procedure :: go => vehicle_go
end type vehicles_vehicle
type, extends(vehicles_vehicle) :: vehicles_taxi
contains
procedure :: init => taxi_init
end type vehicles_taxi
type, extends(vehicles_vehicle) :: vehicles_bus
contains
procedure :: init => bus_init
end type vehicles_bus
contains
subroutine vehicle_go(this)
class(vehicles_vehicle), intent(in) :: this
call this%transportation_strategy%go()
end subroutine vehicle_go
subroutine vehicle_set_transportation_strategy(this, new_transportation_strategy)
class(vehicles_vehicle), intent(inout) :: this
class(strategies_transportation_strategy), intent(in) :: new_transportation_strategy
if (allocated(this%transportation_strategy)) then
deallocate (this%transportation_strategy)
end if
allocate (this%transportation_strategy, source=new_transportation_strategy)
end subroutine vehicle_set_transportation_strategy
subroutine taxi_init(this)
class(vehicles_taxi), intent(out) :: this
type(strategies_by_taxi_strategy) :: by_taxi_strategy
call this%set_transportation_strategy(by_taxi_strategy)
end subroutine taxi_init
subroutine bus_init(this)
class(vehicles_bus), intent(out) :: this
type(strategies_by_bus_strategy) :: by_bus_strategy
call this%set_transportation_strategy(by_bus_strategy)
end subroutine bus_init
end module vehicles
main.f90
program main
use vehicles
implicit none
type(vehicles_taxi) :: taxi
type(vehicles_bus) :: bus
call taxi%init()
call bus%init()
call taxi%go()
call bus%go()
end program main
At least works using gfortran 4.6 (20100925).
The following codes demonstrate how to use procedure pointers:
module my_mod
implicit none
contains
subroutine sub1()
write(*,*) 'the first suboutine is being used'
end subroutine sub1
subroutine sub2()
write(*,*) 'the second subroutine is being used'
end subroutine sub2
end module my_mod
program procTest
use my_mod
implicit none
integer :: n
procedure(sub1), pointer:: funPointer => NULL()
write(*,'(A)') "Please enter your option"
read(*,*) n
select case( n )
case( 1 )
funPointer => sub1
case( 2 )
funPointer => sub2
case DEFAULT
funPointer => sub1
end select
call funPointer()
end program procTest