Pointer to subarray defined by a map - arrays

I want to define a pointer to a subarray. For a simple range this is easily done by pointer => array(i:j), but I can't figure out how to do this for a map like k=[k1,k2,k3]. If I would define another array I could use a loop like array2=[(array1(k(j)),j=1,size(k,1))]. But it isn't possible to assign a pointer in a similar way (pointer => [(array1(k(j)),j=1,size(k,1))]) since the r.h.s. of the expression seems to define another variabel which then not even has the target attribute. For simple tasks, a trick around this, is to first assign a pointer to the total array an to use the map on the readout. But in my case this doesn't seem to be possible.
I will attach to examples: The first one shows what I described above. The second one is a more complicated example, where the trick doesn't work anymore. And in addition a two dimensional map is required.
Minimal example:
program test
integer, parameter :: n=10,n_k=3
real,target :: a(1:n)
real :: b(1:n_k)
integer :: k(1:n_k)
integer :: j
real,pointer :: p(:)
! fill array a and define map k:
a=[(real(j),j=1,n)]
k=[((j+1)*2,j=1,n_k)]
! can be used to print the arrays:
!write(*,*) a
!write(*,*) k
! can be used to write only the part of a defined by k:
!write(*,*) (a(k(j)),j=1,n_k)
! this an similar things didn't work:
!p(1:n_k) => [(a(k(j)),j=1,n_k)]
! works, but not generally:
p => a
write(*,*) (p(k(j)),j=1,n_k)
! works, only for arrays:
b=(/(a(k(j)),j=1,n_k)/)
write(*,*) b
end program
More complicated (but also kind of minimal) example which shows (hopefully) the problem I really have. For an easy understanding some explanation leads through it. There are plenty of write commands to print the arrays. I appreciate for the amount of code, but I really don't see how to make a shorter and understandable working example:
module mod1
type base
real :: a
end type
type,extends(base) :: type1
end type
type,extends(base) :: type2
type(type1),allocatable :: b(:)
end type
type(type2),allocatable,target :: c(:)
contains
subroutine printer(z)
class(*),pointer,dimension(:) :: z
integer :: j,a_z,n_z
character(len=40) :: f,ff='(F10.2,1x))',form_z
! define format for printing:
a_z=lbound(z,1)
n_z=ubound(z,1)
write(f,'(I0)') (n_z-a_z+1)
form_z="("//trim(adjustl(f))//ff
! writing:
select type(z)
class is (base)
write(*,form_z) (z(j)%a,j=a_z,n_z)
end select
end subroutine
end module
program test
use mod1
integer,parameter :: n_b=8,n_c=6,n_js=3,n_ls=2
integer :: js(1:n_js),ls(1:n_ls)
integer :: j,l
class(*),pointer :: p(:)
character(len=40) :: f,ff='(F10.2,1x))',form_c,form_b
! define format for printing:
write(f,'(I0)') n_b
form_b="("//trim(adjustl(f))//ff
write(f,'(I0)') n_c
form_c="("//trim(adjustl(f))//ff
! creating and filling the arrays:
allocate(c(n_c))
c%a=[(2d0*real(j),j=1,n_c)]
do j=1,n_c
allocate(c(j)%b(n_b))
c(j)%b%a=[(real(l)*1d1**(j-1),l=1,n_b)]
end do
! write arrays to compare later:
write(*,form_c) c%a
write(*,*)
write(*,form_b) (c(j)%b%a,j=1,n_c)
write(*,*)
! denfining two maps (size and entries will be input in the final program):
js=[1,4,6]
ls=[2,7]
! using the maps to print only the desired entries:
write(*,*) (c(js(j))%a,j=1,n_js)
write(*,*)
write(*,*) ((c(js(j))%b(ls(l))%a,j=1,n_js),l=1,n_ls)
write(*,*)
! !!! here I want to use the maps as well, but so far I only know how to use ranges:
p => c(1:4)
call printer(p)
write(*,*)
p => c(2)%b(3:6)
call printer(p)
write(*,*)
end program
Edit:
Just for the record, I solved the problem now by using arrays of derived types including pointers and slightly changing the calling subroutines.

You cannot do this with pointer association (e.g. pointer1 => array1(vector_subscript). Section 7.2.2.2 of the Fortran 2008 standard that disallows this is:
R733 pointer-assignment-stmt is data-pointer-object [ (bounds-spec-list) ] => data-target
There are two other forms, but they do not match your use, nor would they change the outcome. Reading further:
R737 data-target is variable
C724 (R737) A variable shall have either the TARGET or POINTER attribute, and shall not be an array section with a vector subscript.
This is why you cannot perform the pointer association your are attempting. You can however work around this and with pointer allocation. See this code:
n_k = 3
k = [((j+1)*2,j=1,n_k)] ! a vector subscript
p => a(k) ! NOT OK. Violates C724
allocate(p(n_k)) ! Associate your pointer this way
p = a(k) ! This is OK.
write(*,*) p
Which yields (wrapped in your example program):
% ./ptrtest
4.00000000 6.00000000 8.00000000
This allocates p to be the proper size and then assigns from a with a vector subscript. This gets around the issue of directly associating p with a map of a. This snippet assumes the variables are declared and initialized per your example code. This shows that you can assign a vector subscript of an array to a pointer, but only one that is already associated, not during the association.
As noted in a comment to your Q, if you have a regular stride, you can make the pointer association directly. For your first test case, this would be equivalent and work:
p => a(4:2:8) ! Allocation to a strided array is allowed
If however, you have an irregular vector subscript then the method in this answer will be what you need to use to accomplish the pointer association.
Another workaround you can use is passing a pointer and the map to a procedure. Consider the following code:
program test
implicit none
integer, parameter :: nx = 10, nx_m = 3
integer,dimension(nx_m) :: x_map
integer :: i
real, dimension(nx),target :: a
real, dimension(:), pointer :: p
! initialize array
a = [(real(i*2),i=1,10)]
write (*,'(10(f5.1 x))') a
!define a map
x_map = [1, 9, 4]
! associate pointer
p => a
call print_map(p, x_map)
contains
subroutine print_map(apointer, map)
implicit none
real, dimension(:), pointer :: apointer
integer, dimension(:) :: map
write (*,*) apointer(map)
end subroutine print_map
end program test
In this case, p "knows" about a and the map of elements in a can be calculated in the caller. Rather than associating (=>) p as a map of a (which cannot be done), p is associated to a and the map passed along with it.
This code produces the output:
% ./ptrtest3
2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0
2.00000000 18.0000000 8.00000000

Related

Difference in Fortran pointer and Fortran allocatable in calling C_F_POINTER

The thing is, 'C_F_POINTER' compiles successfully(ifort version 19.0.5.281) with 'allocatable arrays' as its argument, and it works in the exactly same way with the case in which 'pointer' is used as its argument.
program test1
use mkl_spblas
use omp_lib
use iso_c_binding
implicit none
integer, parameter :: DIM_ = 4, DIM_2 = 6
integer :: stat, i
integer :: irn(DIM_2), jcn(DIM_2)
real*8 :: val(DIM_2)
integer(c_int) :: indexing
integer :: DIM_r, DIM_c
type(c_ptr) :: rows_start_c, rows_end_c, col_indx_c, values_c
(*1)!integer,allocatable :: rows_start_f(:), rows_end_f(:), col_indx_f(:)
!real*8 ,allocatable :: values_f(:)
(*2)integer ,pointer :: rows_start_f(:), rows_end_f(:), col_indx_f(:)
real*8 ,pointer :: values_f(:)
type(SPARSE_MATRIX_T) :: mat1, mat2
irn = (/ 2, 2, 3, 4, 0, 0 /)
jcn = (/ 1, 2, 3, 2, 0, 0 /)
val = (/ 5, 8, 3, 6, 0, 0 /)
call omp_set_num_threads(1)
stat = mkl_sparse_d_create_coo (A=mat1, indexing=SPARSE_INDEX_BASE_ONE, &
rows=DIM_, cols=DIM_, nnz=DIM_,&
row_indx=irn, col_indx=jcn, values=val )
if (stat /= 0) stop 'Error in mkl_sparse_d_create_coo'
stat = mkl_sparse_convert_csr (source=mat1,&
operation=SPARSE_OPERATION_NON_TRANSPOSE, &
dest = mat2 )
if (stat /= 0) stop 'Error in mkl_sparse_convert_csr'
stat = mkl_sparse_d_export_csr(mat2, indexing, DIM_r, DIM_c, &
rows_start_c, rows_end_c, col_indx_c, values_c)
(*3)call c_f_pointer(rows_start_c, rows_start_f, [DIM_r])
call c_f_pointer(rows_end_c , rows_end_f , [DIM_c])
call c_f_pointer(col_indx_c , col_indx_f , [rows_end_f(DIM_r)-1])
call c_f_pointer(values_c , values_f , [rows_end_f(DIM_r)-1])
stat = mkl_sparse_destroy (A=mat1)
if (stat /= 0) stop 'Error in mkl_sparse_destroy (mat1)'
stat = mkl_sparse_destroy (A=mat2)
if (stat /= 0) stop 'Error in mkl_sparse_destroy (mat2)'
call mkl_free_buffers
(*4)print *, 'rows_start'
print *, rows_start_f
print *, 'rows_end'
print *, rows_end_f
print *, 'col_indx'
print *, col_indx_f
print *, 'values'
print *, values_f
print *, 'indexing'
print *, indexing
print *, 'size(values_f,1)'
print *, size(values_f,1)
end program test1
In the test code above, I marked some points as (*1), (*2), and so on in the leftside of the code.
(*1) & (*2) : allocatable array version and pointer version of the code
(*3) : where I call 'C_F_POINTER'
(*4) : print statements to see the output
The results are 'exactly' the same in both (*1), and (*2) case, and all values are properly converted into desired CSR format.
rows_start
1 1 3 4
rows_end
1 3 4 5
col_indx
1 2 3 2
values
5.00000000000000 8.00000000000000 3.00000000000000
6.00000000000000
indexing
1
size(values_f,1)
4
I found a similar question in StackOverflow 2 years ago (difference between fortran pointers or allocatable arrays for c_f_pointer call).
This question is asking the exactly the same questions in my mind right now.
If I rearange questions in my words,
Difference between pointer and allocatable array?
In C, as far as I know, the arrays are stored in contiguous memory and can be represented by the pointer which points its 1st element. And in Fortran90, if I pass a array into a subroutine as 'assumed-size array', the code behaves like it never cares about how it's allocated, how it's size is like, and treates the array as 1D being stored in contiguous site.
In below code, the subroutine 'assign_A' just gets the 'tot_array(1,2)' as its starting point, and do its work on contiguous site and seems to do it even out of bound of 'tot_array'!! (tot_array is 2x2 matrix, and assign_A's do loop runs 5 times starting at tot_array(1,2)) I was 'feeling' the pointer and allocatable arrays are similar stuff in this sense. But apparently, as the answers in difference between fortran pointers or allocatable arrays for c_f_pointer call, they are different things. Why arrays acts like pointer when they are passed to subroutine as 'assumed-size' one?
program assumed_size_array_test
implicit none
external assign_A
real*8 :: tot_array(2,2)
integer:: i
! Initially 'tot_array' set to be 1.d0
tot_array = 1.d0
write(*,*) 'Before'
write(*,'(5f5.2)') tot_array
call assign_A(tot_array(1,2))
write(*,*) 'After'
write(*,'(5f5.2)') tot_array
end program
subroutine assign_A(A)
implicit none
real*8, intent(inout) :: A(*)
integer :: i
do i = 1,5
A(i) = 2.d0
enddo
end subroutine
Before
1.00 1.00 1.00 1.00
After
1.00 1.00 2.00 2.00
Is there any difference in using 'allocatable array' and 'pointer' in calling 'C_F_POINTER' in Fortran90?
I used ifort version 19.0.5.281, and this compiler seems to give me exactly the same results as far as I checked. If it's okay, I prefer to use allocatble arrays instead of pointers. Is there any difference in using 'allocatable array' and 'pointer' with 'C_F_POINTER', and is there anything that I should be aware of in doing so?
The answers in difference between fortran pointers or allocatable arrays for c_f_pointer call says that I SHOULD use pointers, not using allocatable arrays with C_F_POINTER, but it seems it's some ongoing issue that was not concluded exactly at that time. Is there any conclusion in why 'C_F_POINTER', which is designed for fortran pointer, works fine with allocatable arrays and is result is the same?
Thank you for reading this question.
Obviously, both Fortran POINTER variables and ALLOCATABLE variables have a lot of common in their internal impementation. Most of that is under the hood and should not be accessed directly. Both allocate some memory and probably use the same operating system's or C runtime library's allocator. For example, malloc().
In both there is some memory allocated or pointed to and described by a simple address (for scalars) or by an array descriptor (for an array).
Pointers and allocatable variables mainly differ in what you can do with them and what the compiler will do with them for you. You can think of allocatables as a sort of "smart pointers" quite similar to std::unique_ptr in C++. Recall what happens in C++ you have new and delete which in turn call malloc and free but you are not allowed to mix them. And you are certainly not allowed to manually modify the address stored in a C++ smart pointer either.
When you send an allocatable variable to a procedure that expects a pointer, anything can happen, it is an undefined behaviour. But, if the internal hidden structure has a similar layout, it may happen that you actually set the allocatable internals to point to some memory that was not allocated through allocatable. You may then think that everything is OK and you have a new feature. However, when the time for deallocation comes, and allocatables are often deallocated automatically, it can easilly fail in very unpredictable ways. It can crash in very strange places of the code, the results can be wrong and so on. Anything can happen.
For example, this extremely ugly program works for me too (in gfortran):
subroutine point(ptr, x)
pointer :: ptr
target :: x
ptr => x
end subroutine
interface
subroutine point(ptr, x)
allocatable :: ptr
target :: x
end subroutine
end interface
allocatable z
y = 1.0
call point(z, y)
print *, z
end
But you should never do stuff like this. It is really something very, very wrong. If you make z a local variable, so that it is deallocated, or if you try to deallocate it, it will crash. That is because the only information the compiler has is the address. Internally, the allocatable really looks the same as a pointer. It is just an address (for a scalar). The only difference is what you are allowed to do with it and what the compiler will do for you automatically.
This won't even crash, because the internal implementation similarities I mentioned. but it is no less wrong.
subroutine point(ptr, x)
pointer :: ptr
target :: x
ptr => x
end subroutine
interface
subroutine point(ptr, x)
allocatable :: ptr
target :: x
end subroutine
end interface
allocatable z
pointer y
allocate(y)
y = 1.0
call point(z, y)
print *, z
deallocate(z)
end
It just survives because both allocatable and pointer use the same internal allocator (malloc) in gfortran and they are both implemented as a simple address.

Fortran cast 2D Array to 1D array and pass it

I am working with Fortran 2008 with the Intel 17 Compiler.
I am getting a 3D (x,y,z) assumed shape array in a subroutine and want to pass xy slices as a 1D array to another function that multiplies it with a matrix:
SUBROUTINE xy_gyro_average_3d(this,infield,barfield)
class(xy_GyroAverager_t) :: this
REAL,DIMENSION(:,:,:), INTENT(IN),contiguous,TARGET :: infield
REAL,DIMENSION(:,:,:,:,:), INTENT(OUT),contiguous,TARGET :: barfield
INTEGER :: n,m,k,li0,lj0
type(Error_t) :: err
REAL,DIMENSION(:),POINTER :: inptr,outptr
li0=SIZE(infield,1)
lj0=SIZE(infield,2)
DO n=1,this%ln0
DO m=1,this%lm0
DO k=1,this%lk0
inptr(1:li0*lj0) => infield(:,:,k)
outptr(1:li0*lj0) => barfield(:,:,k,m,n)
CALL this%gyromatrix(k,m,n)%multiply_with(invec=inptr,&
& outvec=outptr,err=err)
if (err%err) call write_err(err)
END DO ! k
END DO ! m
END DO ! n
END SUBROUTINE xy_gyro_average_3d
The multiply_with routine looks (simplified) like this:
SUBROUTINE multiply_with(this,invec,outvec,err)
CLASS(Matrix_t) :: this
real, dimension(1:), intent(IN) :: invec
real, dimension(1:),intent(OUT) :: outvec
CLASS(Error_t),INTENT(OUT) :: err
CALL this%multiply_with__do(invec,outvec,err)
END SUBROUTINE multiply_with
I am getting a warning about the pointer allocation and then an error about the types of actual and dummy argument not matching:
src/GyroAverager.F90(294): warning #8589: Fortran 2008 specifies that if a bound remapping list is specified, data target must be of rank one. [INFIELD]
inptr(1:SIZE(infield(:,:,k))) => infield(:,:,k)
----------------------------------------------^
src/GyroAverager.F90(295): warning #8589: Fortran 2008 specifies that if a bound remapping list is specified, data target must be of rank one. [BARFIELD]
outptr(1:li0*lj0) => barfield(:,:,k,m,n)
----------------------------------^
src/GyroAverager.F90(297): error #6633: The type of the actual argument differs from the type of the dummy argument. [INPTR]
CALL this%gyromatrix(k,m,n)%multiply_with(invec=inptr,&
-------------------------------------------------------------^
src/GyroAverager.F90(298): error #6633: The type of the actual argument differs from the type of the dummy argument. [OUTPTR]
& outvec=outptr,err=err)
Now I think the warning should not be a problem as long as the arrays infield and barfield are marked as contiguous (is there any way to do this to get rid of the warning messages though?).
What exactly is the problem with the error message? The pointers inptr and outptr have the same dimension as the dummy arguments invec and outvec.
But I read that if you pass a pointer but do not receive it as a pointer the array it is pointing to is passed instead. So in the end is it still passed as a 2D array instead of a 1D or is the problem somewhere else?
It was working before when the header of the multiply_with routine looked like this:
SUBROUTINE multiply_with(this,invec,outvec,err)
CLASS(Matrix_t) :: this
class(*), dimension(1:),intent(IN) :: invec
class(*), dimension(1:),intent(OUT) :: outvec
CLASS(Error_t),INTENT(OUT) :: err
and then the routines called by multiply_with would get the type via a select type later. But I reduced the code as we are always working with real arrays.
What is the correct way to do this?

Fortran 95: Array function return. Out-of-bounds

I have a simple problem in a rather simple code, but I really dont get to find the error after some hours. Here a minimised version of the code, where the problem occurs:
SUBROUTINE Partial_KlassRKV(x,y,f,f_xMarge,f_yMarge)
USE DGL_Functions
IMPLICIT NONE
REAL :: x(:),y(:),f(:,:,:),f_xMarge(:,:),f_yMarge(:,:)
INTEGER :: i,j,k
REAL :: partial_fx(6,6)
DO k=1,size(f,3)
partial_fx=PartialCalc(x,y,f(:,:,k),f_xMarge,f_yMarge)
WRITE(*,*) 'Nach PartialCalc x'
STOP
END DO
...
MODULE DGL_Functions
CONTAINS
FUNCTION PartialCalc(x,y,f,f_xMarge,f_yMarge)
IMPLICIT NONE
REAL :: x(:),y(:),f(:,:),f_xMarge(:,:),f_yMarge(:,:)
REAL :: PartialCalc(6,6)
INTEGER :: i,j
DO i=1,size(PartialCalc,1)
DO j=1,size(PartialCalc,2)
PartialCalc(i,j)=i+j
END DO
END DO
WRITE(*,*) 'PartialCalc ',PartialCalc
END FUNCTION PartialCalc
It returns the last WRITE-statement in FUNCION PartialCalc but not the WRITE after
partial_fx=PartialCalc(x,y,f(:,:,k),f_xMarge,f_yMarge)
in the SUBROUTINE. At that line there is "Array subscript out of bounds". I dont understand this. Both arrays (partial_fx and PartialCalc) are declared with dim (6,6) and a value is assigned to each PartialCalc(i,j)...?
Greets intasys
PS:I am using Plato f95 with Checkmate 32.
Maybe try a different compiler. gfortran and ifort normally identify the array and even the index value that is the problem. Here is a example that I quickly wrote:
module mysubs
contains
subroutine subxy (x,y)
real, dimension (5) :: x, y
x = 4.0
y = 5.0
end subroutine subxy
end module mysubs
program test_bounds
use mysubs
real :: x(4), y(5)
call subxy (x, y)
write (*, *) x, y
end program test_bounds
gfortran, with the right compiler options, finds this at compile time, with useful specificity:
call subxy (x, y)
1
Warning: Actual argument contains too few elements for dummy argument 'x' (4/5) at (1)

How to declare an array variable and its size mid-routine in Fortran

I would like to create an array with a dimension based on the number of elements meeting a certain condition in another array. This would require that I initialize an array mid-routine, which Fortran won't let me do.
Is there a way around that?
Example routine:
subroutine example(some_array)
real some_array(50) ! passed array of known dimension
element_count = 0
do i=1,50
if (some_array.gt.0) then
element_count = element_count+1
endif
enddo
real new_array(element_count) ! new array with length based on conditional statement
endsubroutine example
Your question isn't about initializing an array, which involves setting its values.
However, there is a way to do what you want. You even have a choice, depending on how general it's to be.
I'm assuming that the element_count means to have a some_array(i) in that loop.
You can make new_array allocatable:
subroutine example(some_array)
real some_array(50)
real, allocatable :: new_array(:)
allocate(new_array(COUNT(some_array.gt.0)))
end subroutine
Or have it as an automatic object:
subroutine example(some_array)
real some_array(50)
real new_array(COUNT(some_array.gt.0))
end subroutine
This latter works only when your condition is "simple". Further, automatic objects cannot be used in the scope of modules or main programs. The allocatable case is much more general, such as when you want to use the full loop rather than the count intrinsic, or want the variable not as a procedure local variable.
In both of these cases you meet the requirement of having all the declarations before executable statements.
Since Fortran 2008 the block construct allows automatic objects even after executable statements and in the main program:
program example
implicit none
real some_array(50)
some_array = ...
block
real new_array(COUNT(some_array.gt.0))
end block
end program example
Try this
real, dimension(50) :: some_array
real, dimension(:), allocatable :: other_array
integer :: status
...
allocate(other_array(count(some_array>0)),stat=status)
at the end of this sequence of statements other_array will have the one element for each element of some_array greater than 0, there is no need to write a loop to count the non-zero elements of some_array.
Following #AlexanderVogt's advice, do check the status of the allocate statement.
You can use allocatable arrays for this task:
subroutine example(some_array)
real :: some_array(50)
real,allocatable :: new_array(:)
integer :: i, element_count, status
element_count = 0
do i=lbound(some_array,1),ubound(some_array,1)
if ( some_array(i) > 0 ) then
element_count = element_count + 1
endif
enddo
allocate( new_array(element_count), stat=status )
if ( status /= 0 ) stop 'cannot allocate memory'
! set values of new_array
end subroutine
You need to use an allocatable array (see this article for more on it). This would change your routine to
subroutine example(input_array,output_array)
real,intent(in) :: input_array(50) ! passed array of known dimension
real, intent(out), allocatable :: output_array(:)
integer :: element_count, i
element_count = 0
do i=1,50
if (some_array.gt.0) element_count = element_count+1
enddo
allocate(output_array(element_count))
end subroutine
Note that the intents may not be necessary, but are probably good practice. If you don't want to call a second array, it is possible to create a reallocate subroutine; though this would require the array to already be declared as allocatable.

keeping array limits in fortran during subroutine call

I have the following program
module test
contains
subroutine foo()
integer, allocatable :: a(:)
allocate(a(-5:5))
call bar(a)
print *, a
end subroutine
subroutine bar(a)
integer, intent(out) :: a(:)
a = 0
a(-4) = 3 ! here
a(2) = 3
end subroutine
end module
program x
use test
call foo()
end program
In the line marked with "here" I am doing something wrong. The fact is that when I receive the array a (in the caller allocated from -5 to +5), the callee uses conventional numbering (1 to n), meaning that assigning -4 I am doing an out of boundary assignment. How can I instruct the compiler that, within the bar routine, the numbering of the a array must be the same as in the caller ?
The type of dummy argument that you are are using in the subroutine, with the dimension specified with a colon, is called "assumed shape". This name is the clue -- Fortran passes only the shape and not the lower and upper bounds. The lower bound is assumed to be one unless you override it as shown in the answer by kemiisto. If the lower bound is not fixed, you can pass an argument to use as the lower bound.
Later addition: a code example if the lower dimension isn't known at compile time:
subroutine example (low, array)
integer, intent (in) :: low
real, dimension (low:), intent (out) :: array
There are two common options:
As kemisto wrote, you pass a second argument. This was common in F77-style code. You can not use the LBOUND trick! It has to be passed as an integer.
You declare the argument to be a pointer, which includes the entire array descriptor. Then the bounds of the array in the subroutine are the same as in the calling scope. Of course you may lose on optimization this way.
How can I instruct the compiler that, within the bar routine, the numbering of the a array must be the same as in the caller ?
Not sure but according to the standard you can specify the lower bound for an assumed-shape array.
subroutine bar(a)
integer, intent(out) :: a(-5:)

Resources