Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29393 Discussions

Array sections and allocatable arrays

OP1
New Contributor III
933 Views

I have two questions:

1. I want to write a subroutine MY_SUB(A,B,C,D) where A,B,C,D can each be either allocatable arrays or sections of allocatable arrays. Writing an explicit interface becomes a combinatorial problem, since the dummy arguments can be allocatable arrays or array sections. How do I get around this?

2. Assuming that a section of an allocatable array is passed to MY_OTHER_SUB. Is there any way to check the allocation status of the parent array? It is possible to pass an array section of an unallocated array to a subroutine, which triggers an access violation when attempting to access the array elements.

My goal is to write a robust subroutine which takes indiscriminatelyallocatable arrays or sections of allocatable arrays; and check the validity (allocation, shape and size) of these inputs.

Thanks in advance,

Olivier

0 Kudos
5 Replies
Steven_L_Intel1
Employee
933 Views
First of all, you won't be able to write a routine which declares the argument as allocatable and allow passing sections to it. Such an argument takes a whole array or nothing. You cannot test the allocation status of an array slice that is passed to you unless it is a whole array and the argument is ALLOCATABLE or POINTER. Also, you can't resolve a generic based on whether the argument is ALLOCATBLE or not.

So what CAN you do? In "normal" code you could look at the value of LOC(arg) and see if it is "reasonable". It may not be zero if an array slice is passed. But if it's larger than oh, say, 4K, it's probably (but not definitely) ok. Then you can ask for the SHAPE of the array or use LBOUND and UBOUND, carefully, dimension by dimension.

If you wanted to be implementation-dependent, you could have an interface that declares the argument as assumed-shape but really fetches it as an address-sized integer array which will be the descriptor, and then peek at the descriptor fields to make sure they are "reasonable". There's a bit that tells you the allocation status is defined, and that will help.
0 Kudos
OP1
New Contributor III
933 Views
Thanks Steve - hmm, it doesn't seem so trivial to implement. Ideally, I'd like to write a subroutine SUPER_SUB(A) which can take A as one of these options:
- A is a full allocatable array (in this case, check for allocation status, size etc.)
- A is an array section (check that the array section is valid)
- A is an explicit array (check the array size).
I will try to implement your suggestion regarding examining the array descriptor - but it seems complicated, and maybe I could just forego all this and stick to a simple solution.


But then I guess another of my concerns is the efficient implementation of the calculations. Consider the example:

PROGRAM MY_PROG
IMPLICIT NONE
REAL(8),ALLOCATABLE :: R(:,:)
ALLOCATE(R(10000,100))
...
CALL SUB(R(:,20),SIZE(R,1))
END PROGRAM MY_PROG

SUBROUTINE SUB(V,N)
IMPLICIT NONE
REAL(8) V(N)
...
END SUBROUTINE SUB

In this case my actual argument is a section of anallocatable array, and my dummy argument is an explicit array. The help file stipulates that this is not an efficient way of passing arrays. Is this true here, since in this very example my array section is contiguous? Will an array temporary be created no matter what the contiguousness (?) of the array section is?

Olivier
0 Kudos
jimdempseyatthecove
Honored Contributor III
933 Views

Make all calls to MY_SUB pass pointer to array or pointer to array slice.
Then initialize all (innitially uninitialized) array pointer that will be passed to MY_SUB to NULL()
Next, whenever you are required to construct a proper pointer into one of the pointers passed to MY_SUB you can test the source array to the construct pointer for use in MY_SUB to see if it is allocated. If if so, construct proper pointer, if not, NULL out pointer.

Now all calls to MY_SUB will have either a valid and associated pointer or .NOT. associated pointer.

Jim Dempsey
0 Kudos
jimdempseyatthecove
Honored Contributor III
933 Views

[cpp]program my_prog
implicit none
real(8),allocateble,target :: R(:,:)
real(8),pointer :: pR(:,:) => NULL()

...

  pR => R
  call check(pR)
...
  nullify(pR)
  call check(pR)
...
  pR => R(3:6,4:15)
  call check(pR)

! Note, above could error out at runtime
! use function to return pointer to rank 2 array

  pR => ptrRank2(R, L1, H1, L2, H2) ! asserts valid arguments
  if(.not. associated(pR)) goto YouHandleIt
  ...
  call check(pR)

[/cpp]
Jim Dempsey
0 Kudos
Steven_L_Intel1
Employee
933 Views
If the routine has an explicit interface visible and accepts the array as assumed-shape (:), a copy is NEVER made. The only time a copy is made is if the compiler believes that the routine is expecting just the address of a contiguous array and you pass a non-contiguous section or POINTER.
0 Kudos
Reply