Complex vs real arrays for representing vectors

Arrays of physical vectors occur in many scientific computations. These can be represented in Fortran using one of the following:

Key: Ndim := dimension of the vector space, Nvec := number of vectors

  1. Array of a user defined vector type:
type(vector(Ndim)) :: v(Nvec)
  1. Array of a complex type:
complex :: v(Nvec)
  1. Multidimensional array:
real :: v(Ndim,Nvec)

#2 is obviously limited to 2D vectors. Dimension can be parameterized for #1. #1 and #2 allow writing elemental procedures over vectors and lead to more elegant code. I expect #1 to be, in principle, slower, and it anyway increases OOPs complexity, something I dislike.

#2 appears to be a nice compromise, if you have no plans for extending to 3D. I expected it to not have much performance penalty, compared to #3, after all it is still an array of a native type. But, results for similar computations using the two approaches seem to differ. Why so?

Normally, if you have a 2D array, then you would dimension it as a 2D array in the language. If you want to use standard math libraries on the data (say LAPACK), then you will almost certainly take this approach. If you have a jagged 2D array, or a sparse 2D array that you want to store compactly, then something like #1 is appropriate, except that each vector will be allocated separately with the appropriate length. That means that a parameterized data type probably isn’t appropriate, an allocatable array is probably best. You likely cannot use standard math libraries with this derived type, you will need to write your own or convert back and forth when necessary. I don’t know how the complex array fits in here; I think maybe it is a misunderstanding of what a complex number is.

Another use for #1 is when you have a 2D array where it is easy to confuse the meanings of the rows and columns. If you never treat the elements of the 2D array as a matrix, then you can do #1 without much, if any, loss of efficiency. Then when you reference the elements, you can name them appropriately, something like A%distance(i)%time(j) for example (with varying length allocations if appropriate). If you were to reference this simply as A(j,i), then it might be easy to make transpose mistakes. That extra verbosity protects you from that common mistake.