How to mimic EQUIVALENCE when using Fortran allocatable arrays
Asked Answered
E

1

6

I have 3 allocatable 1D arrays in a Fortran routine, VX(:), VY(:), VZ(:), all with the same size.

I need to aggregate them in a 2D array named VARXYZ and send it to a routine that modifies the 'matrix'. The code below works but forces to double the memory size.

      SUBROUTINE TEST(VX,VY,VZ)
      REAL(8), INTENT(INOUT), DIMENSION(:) :: VX,VY,VZ ! They've been allocated with size N in the main
      REAL(8), ALLOCATABLE, DIMENSION(:,:) :: VARXYZ   ! The 'matrix'

      ALLOCATE(VARXYZ(3,N))

      VARXYZ(1,:)=VX(:)
      VARXYZ(2,:)=VY(:)
      VARXYZ(3,:)=VZ(:)
      
      CALL CHANGE_MATRIX(VARXYZ)

      VX(:)=VARXYZ(1,:)
      VY(:)=VARXYZ(2,:)
      VZ(:)=VARXYZ(3,:)
      ...

To avoid the 'double allocation', my first bad reflex was to use an EQUIVALENCE between the 1D arrays and the 3 'columns' of the matrix, but it is not allowed apparently.

After some reading, I have seen people recommending using pointers and the TRANSFER intrinsic function, but I have no idea of how to use them here.

Could you please give an example of how to mimic this EQUIVALENCE mechanism I need?

Engraving answered 1/1, 2022 at 9:54 Comment(5)
You can't (reasonably) do this, so our best advice will involve looking at what alternative approaches there are to how change_matrix works. Can you explain what that subroutine does, and whether you can change it?Incise
If you can point to the resources recommending pointers we can possibly explain what differences exist which means they can't work here. And note that transfer is a copying mechanism so cannot be useful if the goal is to have no extra memory use.Incise
Thanks for your comment francescalus. I don't really have the hand on this routine: it implies many other parts of the code and cannot be modified. I cannot avoid sending a multiple array. my last hope was using this pointer and transfer stuff... Thanks anywayEngraving
Is there a reason you can't just use VARXYZ(1,:) in place of VX(:) in the main code? It's hard to pretend you have a 2D array when you actually have three 1D arrays, but easy to pretend you have three 1D arrays when you actually have a 2D array.Ballista
Depending on how your code is set up, you might even be able to minimise code changes using associate(VX => VARXYZ(1,:)).Ballista
I
1

It is not possible to do exactly what you want, but changes to structures higher up may be possible.

The three input arrays vx, vy and vz are simply contiguous, but there is no expectation that the three arrays together form a (simply) contiguous block of memory. In particular, this means that a storage association mechanism such as using EQUIVALANCE cannot work. (Allocatable objects and dummy arguments are also explicitly prohibited from appearing as equivalence objects, but the previous argument shows the futility of working around this.)

Pointers more widely cannot point to arbitrary blocks of memory.

Finally, transfer is a means of creating a new entity with a transferred physical representation: it's a copy.

You can perhaps work backwards, by ensuring your three arrays are themselves the columns of the larger three-dimensional arrays, but you cannot force this from the procedure test itself. Note, however, that you will need to change test in this case: the allocatable array dummy arguments must correspond to actual array dummy arguments which are allocatable: sections of a larger array never will be. (This example appears not to rely on the allocatable nature of the dummy arguments, however.)

Incise answered 1/1, 2022 at 10:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.