I am trying to understand some old FORTRAN code and have reached a point that puzzles me.
In the main program, a 1-D work array has been defined.
i.e. -

REAL WORKA(30)

Later on, portions of this work array are passed into a few sub-routines:
e.g. -

CALL SNAME1 (10, WORKA(1), WORKA(11), WORKA(21))

Subroutine SNAME1, itself, might be defined as follows:

SUBROUTINE SNAME1 (N, VEC1, VEC2, VEC3)

DIMENSION VEC1(10), VEC2(10), VEC3(10)

So far, so good. I think I know what is going on.
Instead of creating three arrays, a single large array has been created, and portions passed in to act like separate arrays.
By carefully managing the array index, VEC1 is WORKA elements 1 through 10, VEC2 is WORKA elements 11 through 20, and VEC3 is WORKA elements 21 through 30.
All are 1-D arrays.

However, I am now looking at a few sub-routines where the work array is being passed in like a 1-D array, but inside the sub-routine, it looks like a 3-D array.
e.g. -

MDIM = 10
. . .
CALL SNAME5 (MDIM, WORKA(1), WORKA(11), WORKA)
 . . .

Inside SNAME5, the last three parameters are defined like the following:

SUBROUTINE SNAME5 (MDIM, VEC1, VEC2, VEC3)

DIMENSION VEC1(MDIM, 2, N), VEC2(2, MDIM, N), VEC3(MDIM, N, 2)

Now it looks like portions of the work array are being accessed like a 3-D array. (Or am I mistaken?)

I am trying to unravel this code. How does FORTRAN access a 1-D array via 3-D array notation?
Would VEC1(I, J, K) be the equivalent of WORKA(IMDIM + J2 + K)?

(Dang! Why did they have to write code like this?!?!)

Recommended Answers

All 5 Replies

My understanding of this is slightly different to yours, but probably still not right.

"Instead of creating three arrays, a single large array has been created, and portions passed in to act like separate arrays."

Not exactly. This may seem like not picking, because the effect is as you describe, but the mechanism is different. Portions of the array are not passed in to the sub routine. Only single elements of the array are passed in. Work through one of the parameters as an example.

CALL SNAME1 (10, WORKA(1), ...

Here the first element of the WORKA array is passed to the sub routine as the second parameter. The data passed in to the sub routine is just that one element, not a portion of the array.

DIMENSION VEC1(10), ...

Here we treat VEC1 as an array with 10 elements. Element 1 is the value received as the VEC1 arguement and the other 9 elements are lined up in memory after VEC1. That memory is occupied by WORKA(2) to WORKA(10) so you are correct to say "VEC1 is WORKA elements 1 through 10", but only element 1 was passed in as a parameter; elements 2 to 9 are just a way of addressing the memory occupied by WORKA. A bit like passing a pointer to the first element of an array in C will allow a sub routine to address the following elements.

If I am correct in this, then the code:

CALL SNAME5 (MDIM, WORKA(1), ...

works the same way. Only WORKA(1) is passed as the second parameter, rather than a larger portion of the WORKA array. The SNAME5 sub routine then sets up a different way of addressing the memory starting at WORKA(1):

DIMENSION VEC1(MDIM, 2, N), ...

This says the memory after VEC1 will be used as a 3D array (but the data will still be the data contained in WORKA). At this point I am confused, and maybe this shows an error in my thinking, because it seems to me that VEC1 has MDIM2N elements, which is more than WORKA if N>1, so what are the additional elements? Even if N is always 1 when dealing with WORKA, VEC3 would overflow the WORKA data. Perhaps I need to see more of the code.

To add to the confusion, Fortran arrays are a bit odd in the way they lay out the memory. I think it is called column-major form or some such term. It means the left-most index changes the most rapidly rather than he right-most index. This seems weird (to me at least) when we are used to the right-most item changing the most rapidly (for instance if you think of digits incrementing as you count). What this means in you example is, if we take N=3 for illustration:

VEC1(1, 1, 1) = WORKA( 1)
VEC1(2, 1, 1) = WORKA( 2)
VEC1(3, 1, 1) = WORKA( 3)
...
VEC1(10, 1, 1) = WORKA(10)

VEC1(1, 2, 1) = WORKA(11)
VEC1(2, 2, 1) = WORKA(12)
VEC1(3, 2, 1) = WORKA(13)
...
VEC1(10, 2, 1) = WORKA(20)

VEC1(1, 1, 2) = WORKA(21)
VEC1(2, 1, 2) = WORKA(22)
VEC1(3, 1, 2) = WORKA(23)
...
VEC1(10, 1, 2) = WORKA(30)

VEC1(1, 2, 2) = WORKA(31)
VEC1(2, 2, 2) = WORKA(32)
VEC1(3, 2, 2) = WORKA(33)
...
VEC1(10, 2, 2) = WORKA(40)

VEC1(1, 1, 3) = WORKA(41)
VEC1(2, 1, 3) = WORKA(42)
VEC1(3, 1, 3) = WORKA(43)
...
VEC1(10, 1, 3) = WORKA(50)

VEC1(1, 2, 3) = WORKA(51)
VEC1(2, 2, 3) = WORKA(52)
VEC1(3, 2, 3) = WORKA(53)
...
VEC1(10, 2, 3) = WORKA(60)

Of course this makes no sense because there are only 30 elements in WORKA.

Sorry if I have just added more confusuon.

I don't know the machanics either. You could look through the ISO standard (drafts are released freely if you look around).

But there are only so many possiblities it could be. Why not make an identity array with 10 elements (0-9), and see what happens when you index it as a 2D array. Then try for a 3D array.

What happens when you try it? (no fortran compiler on hand)

it seems the programmer understand how Fortran pass parameter between subroutine.
Actually all parameters are passed as one contiguous block. the calling routine or main put the parameter as one dimensional array so it will occupy contigous memory space, and the subroutine takes the parameter and put it in its corresponding array member.
In my opinion it is not a good practice because
- it will confused the later programmer
- not all programming language use this feature, since COBOL for example use dope vector technique
- it is dangerous because if is not used carefully for example the size of the array or data type is not the same it will corrupt the memory

hope this help
ahmad

it seems the programmer understand how Fortran pass parameter between subroutine.
Actually all parameters are passed as one contiguous block. the calling routine or main put the parameter as one dimensional array so it will occupy contigous memory space, and the subroutine takes the parameter and put it in its corresponding array member.
In my opinion it is not a good practice because
- it will confused the later programmer
- not all programming language use this feature, since COBOL for example use dope vector technique
- it is dangerous because if is not used carefully for example the size of the array or data type is not the same it will corrupt the memory

hope this help
ahmad

In this case, FORTRAN formats arrays in column-major order. That is, columns are adjacent in memory instead of the rows (C is row-major order). So, the developer is taking advantage of that knowledge in the way he/she is passing parameters. As you can see, this is really bad practice because it confuses the hell out of folks looking at the code.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.