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

arrays with variable dimensions?

gregfi04
Beginner
492 Views
I have something similar to the following:

do a=0,5
phi(0,a,x,y,z) = ...
do b=1,a
phi(b,a,x,y,z) = ...
enddo
enddo

This results in the phi array being about 2x larger than it needs to be. Phi can grow quite large sometimes, and there are some sizable performance and memory savings to be achieved by "flattening" the first two indices:

phi_idx=0
do a=0,5
phi(phi_idx,x,y,z) = ...
phi_idx=phi_idx+1

do b=1,a
phi(phi_idx,x,y,z) = ...
phi_idx=phi_idx+1
enddo
enddo

However, doing this makes the code significantly harder to follow, and makes the data more difficult to retrieve. Is there any way to store this data in a contiguous block of memory, but still leave it accessible by the "a" and "b" indices? There are also loops over "X", "Y", and "Z" (not included for the sake of clarity), so creating a whole bunch of pointers seems like it would take up a ton of space and negate the memory savings.

Thanks,
Greg
0 Kudos
4 Replies
mecej4
Honored Contributor III
492 Views
There are several important points that remain obscure in what you wrote, so it is difficult to know if the following suggestion is off the point:

You can replace your flattened code by

[fortran]ip=0
do a=0,5
do b = 0,a
phi(ip,x,y,z) = ...
end do
ip=ip+a+1
end do
[/fortran]
provided that you know how the expression denoted by "..." depends on a and b .

I have not seen an effective Fortran implementation of triangular and trapezoidal arrays, such as those that can be implemented in C using the somewhat error-prone representation of a 2D array as an array of pointers to 1D arrays, with the pointers adjusted to point at illegal memory addresses to create the illusion of the same easy access to elements as in a rectangular 2D array.

0 Kudos
jimdempseyatthecove
Honored Contributor III
492 Views
Consider something along the line of:

type phi_t
real, allocatable :: xyz(:,:,:) ! x, y, z
end type phi_t

type(phi_t), allocatable :: phi(:,:) ! b, a

...
phi(b,a)%xyz(x,y,z)

Jim Dempsey
0 Kudos
gregfi04
Beginner
492 Views
Doesn't that still create an array that is b x a? The issue is that I really only need roughly (bxa)/2 elements. Perhaps something like:

type b_type
real,allocatable :: b(:)
end type

type a_type
type(b_type),allocatable :: a(:)
end type

type(a_type),dimension(:,:,:),allocatable :: phi

and then...

allocate(phi(X,Y,Z))
do iz=1,Z
do iy=1,Y
do ix=1,X
allocate(phi(ix,iy,iz)%a(0:ipn))
do na=0,ipn
allocate(phi(ix,iy,iz)%a(na)%b(-na:na)); phi(ii,ij,ik)%a(na)%b(:)=0.0
enddo
enddo
enddo
enddo

This would give me phi(x,y,z)%a(na)%b(nb), but I'm not sure about the ordering in memory. Would these be contiguous in memory, as implied in my original post, as would be the case with a standard array ordered as phi(b,a,x,y,z)?
0 Kudos
jimdempseyatthecove
Honored Contributor III
492 Views
[bash]In your original code you had

   phi(b,a,x,y,z)=...

And used within

 do a=0,5
   do b=1,a
     phi(b,a,x,y,z)=...
   enddo
 enddo

My recommendation was to start with:

  type phi_t
    real, allocatable :: xyz(:,:,:) ! x, y, z
  end type phi_t

  type(phi_t), allocatable :: phi(:,:) ! b, a

This would create a 2D array of array descriptors (allocatable arrays)
However, you would only allocate those in the lower diagonal.

Subsequent to this, you could eliminate the empty array descriptors by extending the sketch code to:

  type phi_t
    real, allocatable :: xyz(:,:,:) ! x, y, z
  end type phi_t

  type phi_b_t
    type(phi_t), allocatable :: b(:) ! a
  end type phi_b_t

  type(phi_b_t), allocatable :: phi(:)
  ...

  allocate(phi(0:5))
  do a=1,5 ! *** allocate starting at 1 (0't is empty)
    allocate(phi(a)%b(a))
    do b=1,a
      allocate(phi(a)%b(a)%xyz(nX,nY,nZ)
    enddo
  enddo
  ...

  do a=0,5
    do b=1,a
      phi(b)%b(a)%xyz(x,y,z)=...
    enddo
  enddo


Note, the xyz 3D array will be contiguous memory (with x index having adjacent cells)

Jim Dempsey[/bash]
0 Kudos
Reply