Set array's rank at runtime - multidimensional-array

I have written a program which reads a file containing multidimensional data (most commonly 3D, but 2D could occur as well). To heighten simplicity I would like to store the data in an array of the same rank (or something pretending to be one), i.e. using a three-dimensional array for 3D data, etc.; the trouble is that the program only learns about the dimensionality on reading the data file.
Currently I store all data in an array of rank one and calculate each element's index in that array from the element's coordinates (this was also suggested here). However, I have also read about pointer rank remapping, which seems very elegant and just what I have been looking for, as it would allow me to scrap my procedures for array index determination (which are probably far less efficient than what goes on behind the scenes). Now, however, it looks like I'm facing the same problem as with directly declaring a multidimensional array - how to do the declaration? Again, it requires information about the rank.
How could I use pointer rank remapping or some other, more suitable technique for setting an array's rank at runtime - in case this can be done at all. Or am I best off sticking to the rank one-array that I am currently using?

I once asked something similar, i.e. how to treat a two-dimensional array as one dimension, see here: changing array dimensions in fortran.
The answers were about the RESHAPE instrinsic of pointers, however there seems to be no way to use the same array name unless you use subroutine wrappers, but then you need callbacks to have the eventual subroutine with only one name, so the problems get larger.
program test
real, allocatable :: data(:)
allocate(data(n_data))
! read stuff, set is_2d and sizes
if (is_2d) then
call my_sub2(data, nX, nY)
else
call my_sub3(data, nX, nY, nZ)
end if
end program test
subroutine my_sub2(data, nX, nY)
real :: data(nx,nY)
! ...
end subroutine my_sub2
subroutine my_sub3(data, nX, nY, nZ)
real :: data(nx,nY,nZ)
! ...
end subroutine my_sub3
EDIT: as an alternative, set the third rank to 1:
program test
real, allocatable, target:: data(:)
real, pointer:: my_array(:,:,:)
logical is_2d
n_data = 100
allocate(data(n_data))
! read stuff, determine is_2d and n
if (is_2d) then
i=n
j=n
k=1
else
i=n
j=n
k=n
end if
my_array(1:i,1:j,1:k) => data
write(*,*) my_array
end program test
Then you handle the 2D case as a special 3D case with third dimension 1.
EDIT2: also, beware when passing non-contiguous arrays to subroutines with explicit-shape arrays: http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/optaps/fortran/optaps_prg_arrs_f.htm

If I understand correctly, you read in data in and 1-D array and want to assign it to 2D or 3D arrays, which you know only after reading the file. Why not declare both 2D and 3D arrays as allocatable arrays, and allocate only one of them base on your data shape? You could use the intrinsic function RESHAPE to do this conveniently.
REAL,DIMENSION(:,:), ALLOCATABLE :: arr2d
REAL,DIMENSION(:,:,:),ALLOCATABLE :: arr3d
...
! Read data into 1-D array, arr1d;
...
IF(L2d)THEN
ALLOCATE(arr2d(im,jm))
arr2d=RESHAPE(arr1d,(/im,jm/))
ELSEIF(L3d)THEN
ALLOCATE(arr3d(im,jm,km))
arr3d=RESHAPE(arr1d,(/im,jm,km/))
ENDIF

You could use the EQUIVALENCE statement like this:
Program ranks
integer a_1d(12)
integer a_2d(2, 6)
integer a_3d(2, 2, 3)
equivalence (a_1d, a_2d, a_3d)
! fill array 1d
a_1d = (/1,2,3,4,5,6,7,8,9,10,11,12/)
print *, a_1d
print *, a_2d(1,1:6)
print *, a_2d(2,1:6)
print *, a_3d(1,1,1:3)
print *, a_3d(2,1,1:3)
print *, a_3d(1,2,1:3)
print *, a_3d(2,2,1:3)
end program ranks

You can write a subroutine for different ranks of array and create an interface
Here in example I have shown that how to populate an array of different array using interface statement `
program main
use data
implicit none
real,dimension(:,:,:),allocatable::data
integer::nx,ny,nz
nx = 5
ny = 10
nz = 7
call populate(nx,ny,nz,data)
print *,data
end program main `
data module is here
module data
private
public::populate
interface populate
module procedure populate_1d
module procedure populate_2d
module procedure populate_3d
end interface
contains
subroutine populate_1d(x,data)
implicit none
integer,intent(in)::x
real,dimension(:),allocatable,intent(out):: data
allocate(data(x))
data=rand()
end subroutine populate_1d
subroutine populate_2d(x,y,data)
implicit none
integer,intent(in)::x,y
real,dimension(:,:),allocatable,intent(out):: data
allocate(data(x,y))
data=rand()
end subroutine populate_2d
subroutine populate_3d(x,y,z,data)
implicit none
integer,intent(in)::x,y,z
real,dimension(:,:,:),allocatable,intent(out):: data
allocate(data(x,y,z))
data=rand()
end subroutine populate_3d
end module data
There is an interface to populate 1d, 2d and 3d arrays. you can call populate interface instead of calling individual subroutines. It will automatically pick the relevant one.

Related

Fortran array automatically growing when adding a value

Is there any existing way to emulate growing array in Fortran? Like vector in C++. I was very surprised when I haven't found anything on this subject on the Internet.
As a motivation example, suppose I compute some recurrence relation and I want to store all the intermediate numbers I get. My stopping criterion is the difference between adjacent results so I cannot know beforehand how much memory I should allocate for this.
I am sure it has been shown somewhere on this site before, but I cannot find it.
First, in Fortran 2003, you can add one element by simple
a = [a, item]
as commented by francescalus. This is likely to reallocate the array very often and will be slow.
You can keep your array to be allocated to somewhat larger size then your number of elements n. When your number of elements n grows above the size of the array size(a) you can allocate a new array larger by some factor (here 2x) and copy the old elements there. There is no realloc() in Fortran, unfortunately.
module growing_array
implicit none
real, allocatable :: a(:)
integer :: n
contains
subroutine add_item(item)
real, allocatable :: tmp(:)
real, intent(in) :: item
if (n == size(a)) then
!this statement is F2003, it can be avoided, but I don't see why in 2016
call move_alloc(a, tmp)
allocate(a(n*2))
a(1:n) = tmp
end if
n = n + 1
a(n) = item
end subroutine
end module
I left out the initial allocation, it is simple enough.
It all can be put into a derived type with type-bound procedures, and use it as a data structure, but that is pure Fortran 2003 and you wanted 90. So I show Fortran 95, because Fortran 90 is flawed in many ways for allocatable arrays and is desperately obsolete and essentially dead.

store multi dimensional arrays to be operated on along all the dimensions

Foreword
The Fortran program that I'm writing should deal with 1D, 2D and 3D problems depending on ndims, which can be 1, 2 or 3 and is read from an input file.
In these cases the quantity/ies of interest can be stored in arrays (one could be named phi)
of rank dims (ALLOCATABLE(:) or ALLOCATABLE(:,:) or ALLOCATABLE(:,:,:)),
or in arrays of rank 3 (ALLOCATABLE(:,:,:) with third dimension to be set equal to 1 in 2D or both second and third dimensions equal to 1 in 1D);
both cases are explained well in this answer. The first approach seems more elegant to me, but in the following I assume the second one, which is definitely simpler.
These quantities have to be operated on by several subroutines (e.g. mysub) along the ndims dimensions (along "pencils" should give a graphic idea), so I should call something like
SELECT CASE (ndims)
! 3D case
CASE (3)
DO j = ...
DO k = ...
CALL mysub(phi(:,j,k))
END DO
END DO
DO i = ...
DO k = ...
CALL mysub(phi(i,:,k))
END DO
END DO
DO i = ...
DO j = ...
CALL mysub(phi(i,j,:))
END DO
END DO
! 2D case
CASE (2)
DO j = ...
DO k = ...
CALL mysub(phi(:,j,1))
END DO
END DO
DO i = ...
DO k = ...
CALL mysub(phi(i,:,1))
END DO
END DO
! 1D case
CASE (1)
DO j = ...
DO k = ...
CALL mysub(phi(:,1,1))
END DO
END DO
END SELECT
Actual question
Can anyone suggest me (or help me to to devise!) a different way of store phi (maybe involving derived data types?) so that I can collapse the preceding code as follows?
DO id = 1, ndims
CALL mysub2(phi,id)
END DO
(Here mysub2 acts on mysub's place.)
So the question is how should I store phi, so that I can substitute the first code with the second one?
Maybe I could return to the foreword and decide to follow the point 1., in which case would be easier to write a generic interface. This would be, I think, just a way to "hide" exactly what the SELECT CASE would do. Which of the two (SELECT CASE/generic INTERFACE) would be more efficient?
Are these the only two ways to face this problem?
Perhaps I have misunderstood, but I think the answer to the specific question is to not make any changes to the storage or declaration of phi at all.
In the original code, three dimensional data (differentiating rank of the data from rank of the array used to store the data) is processed in slices along the first dimension, then the second, then the third. Two dimensional data is processed along the first, then the second, and one dimensional data is processed along the first only.
So with id going from 1 to the number of dimensions in the data, consider the following implementation of mysub2:
SUBROUTINE mysub2(phi, id)
TYPE(pink_elephant), INTENT(IN) :: phi(:,:,:)
INTEGER, INTENT(IN) :: id
INTEGER :: i, j, k
SELECT CASE (id)
CASE (1)
DO j = ...
DO k = ...
CALL mysub(phi(:,j,k))
END DO
END DO
CASE (2)
DO i = ...
DO k = ...
CALL mysub(phi(i,:,k))
END DO
END DO
CASE (3)
DO i = ...
DO j = ...
CALL mysub(phi(i,j,:))
END DO
END DO
END SELECT
END SUBROUTINE mysub2
~~
Generic interfaces can always be resolved at "compile time" - the specific procedure (not type bound) or binding (type bound) that will be invoked by a particular CALL statement or function reference can be determined just from looking at the declarations in the code.
If you have a situation where "runtime" information is going to affect the choice of procedure, then there has to be some other executable mechanism, other than or additional to the resolution of a generic, that comes into play - if statement, select case, dynamic dispatch, etc, etc, etc.
Asking whether generic resolution is more efficient than a executable decision is therefore not particularly meaningful - they are different things.
You probably want something like this:
program test
integer :: j,ndims
integer :: n ! rank of each dimension, could also be read from input an allocated separately
type arr
real(8) :: x(n) ! one array for each dimension
end type
type(arr),allocatable :: phi
read(*,*) ndims
allocate(phi(ndims))
do j=1,ndims
call mysub(phi(j)%x) ! acts on the array in dimension j
end do
contains
subroutine mysub(x)
...
end subroutine
end program

passing pointer arguments in fortran

I am wondering what is the proper way to write the following code?
PROGRAM foo
INTEGER :: x
REAL(KIND=8), TARGET, DIMENSION(0: 10) :: array
REAL(KIND=8), POINTER, DIMENSION(:) :: ptr
ptr => array
CALL bar(ptr)
END PROGRAM foo
SUBROUTINE bar (ptr)
REAL(KIND=8), POINTER, DIMENSION(:) :: ptr
INTEGER x
DO x =0, 10
ptr(x) = 2 // seg faults
ENDDO
END SUBROUTINE bar
It works if I declare ptr in bar as REAL(KIND=8), DIMENSION(0:10). But in general I might not know the size of the passed-in array, so is there a way to declare ptr to be a pointer to some array? I am compiling this with gfortran
If a procedure has a dummy argument that is a pointer, then an explicit interface is required in any calling scope.
(There are numerous things that require an explicit interface, a pointer dummy is but one.)
You can provide that explicit interface yourself by putting an interface block for your subroutine inside the main program. An alternative and far, far, far better option is to put the subroutine inside a module and then USE that module in the main program. A third alternative is to make the subroutine an internal procedure of the calling scope.
As of Fortran 2003, you should only use pointers if you intend to point the pointer at different things. If you are just using the pointer for something that really just behaves like a value, then you should use allocatables instead.
It depends what you mean with "proper" way. As IanH already pointed out, you need an explicit interface (best done via packing things in a module) and using allocatables instead of pointers, if possible.
I'd further add, that if you do not want to change the allocation status of your array within your subroutine, but only want to manipulate its elements, then use a simple assumed shape array within your subroutine. Below you find a working example for it. A few more things to note:
Do not use real(kind=8) as not all compilers use the number of bytes as kind for the real numbers. If you want double precision accuracy, ask for it explicitely as below.
If you just want to fill up an array with a constant value, do it the simple way: array(:) = 2.0_dp
And here the example:
module accuracy
implicit none
integer, parameter :: dp = kind(1.0d0)
end module accuracy
module barmodule
use accuracy
implicit none
contains
subroutine bar(array)
real(dp), intent(inout) :: array(:)
integer :: ii
do ii = 1, size(array)
array(ii) = ii
end do
end subroutine bar
end module barmodule
program foo
use accuracy
use barmodule
implicit none
real(dp), dimension(0:10) :: array
call bar(array)
end program foo

Fortran calls: advantage of passing by pointer vs passing by reference

It is my understanding that in Fortran arrays are passed by reference. So is there an advantage to passing a pointer to a large array (into a subroutine) as opposed to passing the array itself.
Could you also clarify this in the context of recursive functions. I have seen implementations where pointers are used "for efficiency", but if everything is passed by reference, then what's the benefit of pointers.
Here's an example. I have an array X (in reality lets say it's a very large array).
INTEGER :: X(:)
I can define a subrouitne that takes this array as follows:
SUBROUTINE FOO(X)
INTEGER, INTENT(IN) :: X(:)
INTEGER :: I
DO I = 1, 4
WRITE(*,*) X(I)
ENDDO
END SUBROUTINE FOO
When I call the subroutine above then the array X is not copied as fortran passes a reference to it. Now lets say I have a modified version of the subroutine:
SUBROUTINE FOO2(X)
INTEGER, POINTER, INTENT(IN) :: X(:)
INTEGER :: I
DO I = 1, 4
WRITE(*,*) X(I)
ENDDO
END SUBROUTINE FOO2
I can call FOO2 from a program as follows:
PROGRAM TEST
IMPLICIT NONE
INTEGER, TARGET :: X(5)
INTEGER, POINTER :: Y(:)
X = (/1,2,3,4,5/)
Y => X
CALL FOO2(Y)
END PROGRAM TEST
Then here's my question: is there a performance difference between the two versions of foo? Is there any useful scenario where the declaration of FOO2 might be preferable to FOO?
In this simple case there shouldn't be any real difference. Note the program is illegal, you don't have the explicit interface to FOO or FOO2, but I will assume you just ommited it for simplicity and they are in a module or internal.
Both arrays can be non-contiguous in principle, so no difference here. If that slows down the code, the contiguous attribute might help. Or assumed size or explicite size arrays too.
Your subroutine is too simple, so there is no danger of aliasing too. This is the common source of decreasing performance with pointers. There could be potential aliasing with some other argument or another variable you access by host or use association provided it has the target attribute.
The purpose of pointer arguments is actually to either allow disassociated (null()) arguments, or to allow changing of the association status in the subroutines. Your example doesn't use neither and therefore the pointer attribute is superfluous.
There is on last small difference. It is not specified in the standard what is actually passed to the subroutine at the machine code level for the pointer variables. If it is just an address (likely for scalars) it is the same as non-pointer, just the aliasing rules and the allowed usage are different. Otherwise some descriptor is passed, but any overhead should be negligible, the assumed shape arrays use a descriptor too.

Assigning a routine name to a different routine in Fortran

I have a solver that iterates for a good amount of time (several hours) and I'm trying to remove several if statements from the main loop in order to save time.
What I'm essentially trying to do here is to create a routine, updateGhosts, which points to an assigned routine. This routine belongs to a derived data type which contains several other properties and routines. I want to use a routine, setGhosts, to set updateGhost to be either ghostOne or ghostTwo, which will be routines that properly update some conditions.
I can't seem to figure out a method that leads the code to compile, though I've tried several different things to no avail.
I have attempted to reduce the code sample down as far as possible for simplicity, but in reality types GridPoint and BlockType have many more parameters to deal with, so simple refactoring is not an option.
Here's the reduced code:
module BlockModule
implicit none
type GridPoint
real(kind=8) :: x, y, T
end type GridPoint
type BlockType
integer :: BC
type (GridPoint) :: Points(0:102,0:102)
contains
procedure :: setGhosts, updateGhosts
procedure :: ghostOne, ghostTwo
end type BlockType
contains
subroutine setGhosts(this)
class(BlockType), intent(inout) :: this
if (this%BC == -1) then
! We want to assign updateGhosts to ghostOne.
this%updateGhosts => this%ghostOne
else
! We want to assign updateGhosts to ghostTwo.
this%updateGhosts => this%ghostTwo
end if
end subroutine
! Routine that will be either ghostOne or ghostTwo.
subroutine updateGhosts(this)
class(BlockType), intent(inout) :: this
end subroutine
! Routine will do something.
subroutine ghostOne(this)
class(BlockType), intent(inout) :: this
end subroutine
! Routine will do something completely different, with same inputs.
subroutine ghostTwo(this)
class(BlockType), intent(inout) :: this
end subroutine
end module
How can I assign a routine name to point to a different routine in Fortran90/95/03? (The oldest version possible is ideal, but not necessary.) Sorry if similar questions have been asked before, I tried a search but I'm not quite sure what I need to look for.
Thanks for reading!
(Question was answered in a comment. See Question with no answers, but issue solved in the comments (or extended in chat) )
#SuperCow wrote:
Does this help? Procedure Pointer, Derived Type
The OP wrote:
Yes! This was the trick.

Resources