Fortran: Choosing the rank of an allocatable array - arrays

I am trying to write a program where I want the allocatable array A to be of either rank 1, 2, or 3, depending on my input at run-time. I want to do this since the subsequent operations on A are similar, and I have defined in a module an interface work with module procedures that when acted on A, gives the desired result.
What I am doing currently is this:
program main
implicit none
integer :: rank,n=10
real*8, allocatable :: A1(:)
real*8, allocatable :: A2(:,:)
read (*,*) rank
if (rank.eq.1) then
allocate (A1(n))
else if (rank.eq.2) then
allocate (A2(n,n))
end if
! operate on the array
if (rank.eq.1) then
call work(A1)
else if (rank.eq.2) then
call work(A2)
end if
end program
Things would be much easier if somehow I could choose the rank of A, as then the if statements are not needed. Maybe this is not possible, but all help are appreciated.

The next Fortran standard (2015) has the select rank construct similar to select case. My example uses the select case construct on the rank intrinsic of an assumed-rank dummy variable.
module my_type
use, intrinsic :: iso_fortran_env, &
ip => INT32, &
wp => REAL64
implicit none
private
public :: MyType
type MyType
real (wp) :: rank0
real (wp), allocatable :: rank1(:)
real (wp), allocatable :: rank2(:,:)
real (wp), allocatable :: rank3(:,:,:)
contains
procedure :: create => create_my_type
procedure :: destroy => destroy_my_type
end type MyType
contains
subroutine create_my_type(this, array)
! calling arguments
class (MyType), intent (in out) :: this
real (wp), intent (in) :: array(..) !! Assumed-rank dummy variable
! local variables
integer (ip), allocatable :: r(:)
select case(rank(array))
case (0)
return
case (1)
r = shape(array)
allocate( this%rank1(r(1)) )
case (2)
r = shape(array)
allocate( this%rank2(r(1), r(2)) )
case (3)
r = shape(array)
allocate( this%rank3(r(1), r(2), r(3)) )
case default
error stop 'array must have rank 0,1,2, or 3'
end select
! Release memory
if (allocated(r)) deallocate( r )
end subroutine create_my_type
subroutine destroy_my_type(this)
! calling arguments
class (MyType), intent (in out) :: this
if (allocated(this%rank1)) deallocate( this%rank1 )
if (allocated(this%rank2)) deallocate( this%rank2 )
if (allocated(this%rank3)) deallocate( this%rank3 )
end subroutine destroy_my_type
end module my_type
program main
use, intrinsic :: iso_fortran_env, only: &
ip => INT32, &
wp => REAL64
use my_type, only: &
MyType
implicit none
type (MyType) :: foo
real (wp) :: a0, a1(42), a2(42,42), a3(42,42,42)
print *, rank(a0)
print *, rank(a1)
print *, rank(a2)
print *, rank(a3)
! Allocate array of rank 3
call foo%create(a3)
print *, rank(foo%rank3)
print *, shape(foo%rank3)
print *, size(foo%rank3)
! Release memory
call foo%destroy()
end program main

Declare the array to be rank three. If a lower rank array is required, allocate the relevant trailing dimensions to be of size one.
real, allocatable :: array(:,:,:)
...
select case (desired_rank)
case (1) ; allocate(array(n,1,1))
case (2) ; allocate(array(n,n,1))
case (3) ; allocate(array(n,n,n))
case default ; error stop 'bad desired rank'
end select
You can then use an array section to get a contiguous slice of array that is consistent with your desired rank. Alternatively, write the relevant procedures that operate on array to take a rank three argument, and make them aware of the meaning of a size one extent for the higher dimensions.

Related

Can I pass a variable to a derived type such that each instance of my derived type could have arrays of different lengths?

What is the best way to organize 11 similar but varying size arrays in a program, without the allocatable property?
I'm imagining something like this:
TYPE MyType(i)
integer, intent(in) :: i
integer, dimension(i,i) :: A
integer, dimension(2*i,i) :: B
integer, dimension(i,2*i) :: C
end type MyType
Then in the main program I can declare something like this:
type(mytype), dimension(N) :: Array
Wherein the i'th element of 'Array' has access to three arrays A, B, and C and each of these three arrays have different sizes.
The problem I have currently is I am solving a QM problem and I have 11 different arrays that vary in size but all depend on the same parameter (as the size A, B and C all depend on i). The actually values of these arrays don't change either.
My program looks at different kinds of systems, each with their own A, B and C (just to keep the analogy going) and in each system A, B and C have a unique size.
If I knew I was looking at 6 different kinds of systems, I'd need 6 different copies of A, B and C.
Currently, A, B and C are not part of a derived type but instead are allocatable and recalculated at each iteration. This calculation takes upwards of a tenth of a second for the larger systems. But I average my results ~100,000 times which means this could offer some serious time savings. In addition, memory is not something I lack.
I tried calculating these arrays in another program and writing them to file and reading them when needed but unfortunately this was not faster than recalculating at the same time.
Note: Here is what my actual arrays look like:
integer, dimension(:,:), allocatable :: fock_states
integer, dimension(:,:), allocatable :: PES_down, PES_up
integer, dimension(:,:), allocatable :: IPES_down, IPES_up
integer, dimension(:,:), allocatable :: phase_PES_down, phase_PES_up
integer, dimension(:,:), allocatable :: phase_IPES_down, phase_IPES_up
integer, dimension(:,:), allocatable :: msize
integer, dimension(:,:), allocatable :: mblock
Each array is a different size for each system.
Edit:
So what I really need is N copies of the arrays in the list just above this edit. The arrays belonging to the i'th copy have size that scales with i (e.g. PES_down has dimension (i,4**i)). As I understand it, this means that I need N different declarations of variables with type 'MyType'. This would normally be ok but the issue is that N is defined at compile time but can change between runs.
N does have a defined maximum but it seems like a lot of wasted memory when I know I won't be using the arrays.
(Relate to this answer for a more detailed explanation).
As #roygvib said in his comment, yes, using parameterized derived types in this case is not only possible, it is a perfect match. This is one of the main problem-cases PDT aims to solve.
type :: MyType(i)
integer, len :: i
integer, dimension(i,i) :: A
integer, dimension(2*i,i) :: B
integer, dimension(i,2*i) :: C
! (...)
end type
Then, in the main program, you would declare your object like this (where i is the known length parameter for the current kind of system):
type(mytype(i)), dimension(N) :: Array
But first, check the availability of this feature in your compiler.
I guess it would be most straightforward to use a derived type containing A, B, and C with the size variable i and allocate them for each i using some initialization routine (here, MyType_init()).
module mytype_mod
implicit none
type MyType
integer :: i
integer, dimension(:,:), allocatable :: A, B, C
end type
contains
subroutine MyType_init( this, i )
type(MyType), intent(inout) :: this
integer, intent(in) :: i
allocate( this % A( i, i ), &
this % B( 2*i, i ), &
this % C( i, 2*i ) )
this % A = 0 !! initial values
this % B = 0
this % C = 0
end subroutine
end module
program main
use mytype_mod
implicit none
integer, parameter :: N = 2
type(MyType) :: array( N )
integer i
do i = 1, N
call MyType_init( array( i ), i )
array( i ) % A(:,:) = i * 10 !! dummy data for check
array( i ) % B(:,:) = i * 20
array( i ) % C(:,:) = i * 30
enddo
do i = 1, N
print *
print *, "i = ", i
print *, " A = ", array( i ) % A(:,:)
print *, " B = ", array( i ) % B(:,:)
print *, " C = ", array( i ) % C(:,:)
enddo
end program
Result (with gfortran 8.1):
i = 1
A = 10
B = 20 20
C = 30 30
i = 2
A = 20 20 20 20
B = 40 40 40 40 40 40 40 40
C = 60 60 60 60 60 60 60 60
The array(:) in the main program can be allocatable, such that
type(MyType), allocatable :: array(:)
N = 6
allocate( array( N ) )
which may be useful when N is read in from an input file. Further, we can create a type-bound procedure from MyType_init() by changing the lines with (*) below (to use an OO style).
module mytype_m
implicit none
type MyType
integer :: i
integer, dimension(:,:), allocatable :: A, B, C
contains
procedure :: init => MyType_init ! (*) a type-bound procedure
end type
contains
subroutine MyType_init( this, i )
class(MyType), intent(inout) :: this ! (*) use "class" instead of "type"
...
end subroutine
end module
program main
...
do i = 1, N
call array( i ) % init( i ) ! (*) use a type-bound procedure
...
enddo
...
end program

How to create array of arrays from all variables in a module

I have a number of variables declared in a module such as
module test
use othermod, only: n
integer, dimension(n) :: var0
real, dimension(n) :: var1
real, dimension(n) :: var2
.....
real, dimension(n) :: var1000
end module test
Then I have a subroutine that fills these variables with values.
At this point I would like to create an array of arrays with all the variables declared in module test so that I can easily copy or print all variables of a particular (n) at the same time, like dimension(n,allvariablesin module test). For example I would like to do something like array(3,:)=array(2,:).
Because this code is part of a very large program I cannot really modify too much, but rather I need to create an array of arrays from all the variables in this module without typing all the variables.
How can I easily integrate this change in the current code?
I urge you follow to #Vladimir F's advice and encapsulate your variables inside a derived data type. You can employ the associate construct to call old codes expecting var0, var1, .., etc. Lastly, we can overload the type's name to get a Java style constructor in the code below
module type_MyArray
implicit none
private
type, public :: MyArray
! type-components
real, dimension(:), allocatable :: var0, var1, var2
contains
! type-bound procedures
procedure :: create => create_my_array
procedure :: destroy => destroy_my_array
end type MyArray
interface MyArray
module procedure my_array_constructor
end interface MyArray
contains
pure function my_array_constructor(n) result (return_value)
! Dummy arguments
integer, intent (in) :: n
type (MyArray) :: return_value
call return_value%create(n)
end function my_array_constructor
pure subroutine create_my_array(self, n)
! Dummy arguments
class(MyArray), intent(in out) :: self
integer, intent(in) :: n
allocate( self%var0(n) )
allocate( self%var1(n) )
allocate( self%var2(n) )
end subroutine create_my_array
pure subroutine destroy_my_array(self)
! Dummy arguments
class(MyArray), intent(in out) :: self
if (allocated(self%var0)) deallocate( self%var0 )
if (allocated(self%var1)) deallocate( self%var1 )
if (allocated(self%var2)) deallocate( self%var2 )
end subroutine destroy_my_array
end module type_MyArray
program main
use type_MyArray, only: MyArray
use old_code, only: do_something
implicit none
type (MyArray) :: foo, bar
! Allocate memory
foo = MyArray(42)
bar = MyArray(4200)
associate( var0 => foo%var0, var1 => bar%var1 )
! Call old code using var0 and var1
call do_something(var0, var1)
end associate
! Release memory
call foo%destroy()
call bar%destroy()
end program main

Allocatable Array of Inherited Derived Types Issues in Fortran

I'm attempting to create global-ish-ly available allocatable array of a set of derived types that share inheritance with a single object. Fortran does not seem to make this very easy. The below is what I have so far.
First the derived types and module with the allocatable array.
Module Environment
use Entity_M
type(Entity_C), dimenion(:), allocatable :: objects
End Module Environment
Module Entity_M
type Entity_T
integer :: id
real*8 :: time
real*8, dimension(3) :: currPos
type(TrajectoryDatum), dimension(:), allocatable :: trajTable
end type Entity_T
type Entity_C
class(Entity_T), pointer :: e
end type Entity_C
type, extends(Entity_T) :: Aircraft_T
real*8 :: altitude
end type Aircraft_T
type, extends(Entity_T) :: Missile_T
integer :: targetID
end type Missile_T
End Module Entity
Now the main program
Program Main
use Initialization
use Environment
use Entity_M
call simInit(3)
write(*,*) objects%trajTable !<---- this does not persist
call runSim()
End Program Main
The code with the issue
Module Initialization
use Entity_M
contains
subroutine simInit(numOfObjects)
integer, intent(in) :: numOfObjects
call objectsInit(numOfObjects)
call launchersInit()
end subroutine simInit
subroutine objectsInit(numOfObjects)
use Environment
integer, intent(in) :: numOfObjects
!local
type(Aircraft_T) :: aircraft
integer :: i
allocate(objects(numOfObjects)
do i = 1, numOfObjects
aircraft%trajTable = getTrajectoryData()
call allocatePointer(objects(i)%e, aircraft)
end do
end subroutine objectsInit
subroutine allocatePointer(c, t)
class(Entity), pointer, intent(out) :: c
type(Aircraft), target, intent(in) :: t
c => t
end subroutine allocatePointer
End Module Initialization
This above just example code written on a computer that doesn't have a compiler. I did my best and hopefully if there are typos they are few. I did my best to mirror the structure of the original code.
The problem is that the field "objects%trajTable" goes back to a undefined pointer after it leaves the "objectsInit" subroutine. The other values like time, id, and currPos are still correct. How can I correct this?
I am using Visual Studio 2012 and Intel Visual Fortran 2015.
Because the program has many overlapping names (like Aircraft and aircraft, which are regarded as the same in Fortran), I have attached "_t" to all the types (e.g., Aircraft to Aircraft_t etc) and "_m" to all the module names (e.g., Entity to Entity_m) to make the program work (at least formally).
More importantly, as #innoSPC commented above, type(Aircraft) :: aircraft is a local variable, so I think a pointer associated to it becomes undefined after exiting objectsInit(). The code works if
call allocatePointer( objects( i )% e, aircraft )
is replaced by
allocate( objects( i )% e, source=aircraft )
so that each objects( i )% e is given an independent memory having the type of Aircraft_t, with the contents of aircraft copied to it.
Edit Here is a minimum example that I used for test.
Module Entity_m
implicit none
type Entity_t !! base type
integer :: trajTable( 2 )
endtype
type, extends(Entity_t) :: Aircraft_t
real*8 :: altitude
endtype
type, extends(Entity_t) :: Missile_t !! dangerous...
integer :: targetID
endtype
type Entity_c !! container type
class(Entity_t), pointer :: e
endtype
type(Entity_c), allocatable :: objects(:)
contains
subroutine objectsInit( numObj )
integer :: numObj
!local
type(Aircraft_t) :: aircraft
type(Missile_t) :: missile
integer :: i
allocate( objects( numObj ) )
do i = 1, numObj
if ( mod( i, 2 ) == 1 ) then
aircraft% trajTable(:) = i
aircraft% altitude = 10.0d0 * i
allocate( objects( i )% e, source= aircraft )
else
missile% trajTable(:) = 10000 * i
missile% targetID = -100 * i
allocate( objects( i )% e, source= missile ) !! missile loaded !!
endif
enddo
endsubroutine
EndModule
Program Main
use Entity_m
call objectsInit( 3 )
do i = 1, 3
print *, objects( i )% e% trajTable(:) !! access members of base type
select type ( t => objects( i )% e ) !! access members of derived type
type is ( Aircraft_t ) ; print *, t% altitude
type is ( Missile_t ) ; print *, t% targetID
endselect
enddo
EndProgram

FORTRAN: Use character as changeable array name

I am trying to write a subroutine to access arrays in a certain manner.
One input argument of the subroutine is a character containing the name of the array whose access is desired. Here is a rather simplified code example of how I generally imagine this to work:
PROGAM prog
real, dimension(3,3) :: array1(3,3)
real, dimension(3,3) :: array2(3,3)
real value1
real value2
... fill 'array1' and 'array2'...
call sub(array1,2,2,value1)
call sub(array2,2,2,value2)
... do something with 'value1' and 'value2'...
END
SUBROUTINE sub(name,x,y,out)
character(len=*), intent(in) :: name
integer, intent(in) :: x
integer, intent(in) :: y
real, intent(out) :: out
out = name(x,y)
RETURN
END
What I want is the subroutine to access array1(2,2) as requested in the argument and return this value to value1. Then access array2(2,2) and return this value to value2. Above code snippet does not work - no wonder about that. How do I get name(x,y) replaced with array1(x,y) respectively array2(x,y)?
Thanks a lot and best regards!
It is not necessary to use the name of the array to get at its content, if the array is declared in caller. You then use normal argument association.
You could write your subroutine as
subroutine sub(a,x,y,out)
integer, intent(in) :: x, y
real, intent(out) :: out
real, dimension(:,:), intent(in) :: a
out = a(x,y)
end subroutine sub
Much simpler would be to do, in the main program
value1 = array1(2,2)
value2 = array2(2,2)
I would recommend a textbook on Fortran, or even a look at http://en.wikipedia.org/wiki/Fortran_95_language_features .
Edit:
You could also use a SELECT CASE statement, like this:
subroutine bar(c, i, j, out)
character(len=*), intent(in) :: c
integer, intent(in) :: i,j
real, intent(out) :: out
select case (trim(c))
case ("array1")
out = array1(i,j)
case ("array2")
out = array2(i,j)
case default
stop "Argument is bletchful"
end case
end subroutine bar
I am simply at a loss to understand what good this would do, as opposed to using the array directly.
Is this what you want?
select case (array_name)
case ("array_dog")
array_ptr => array_dog
case ("array_cat")
array_ptr => array_cat
end select
where array_name is a character variable, array_dog and array_cat are arrays declared in the module (needing target attribute), and array_ptr is another array with the pointer attribute.

Can a input argument of a Fortran subroutine be deallocated and allocated in the body of the subroutine?

UPDATE: My modified code looks like this:
program run_module_test
use module_test
implicit none
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
call update(xyzArray)
write(6,*)'xyzArray',xyzArray
end program run_module_test
module module_test
implicit none
TYPE :: newXYZ
real(4) :: x, u
real(4) :: y, v
real(4) :: z, w
real(4),dimension(3) :: uvw
END TYPE
integer(4) :: shape = 3
contains
subroutine update(xyzArray)
integer(4) :: i
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
allocate( xyzArray(shape) )
do i = 1, shape
xyzArray(i)%x = 0
xyzArray(i)%y = 0
xyzArray(i)%z = 0
xyzArray(i)%u = 0
xyzArray(i)%v = 0
xyzArray(i)%w = 0
xyzArray(i)%uvw = (/0,0,0/)
end do
return
end subroutine update
end module module_test
When they are compiled, they generate a similar error:
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
1
Error: ALLOCATABLE attribute conflicts with DUMMY attribute at (1)
When I eliminate the argument in update() subroutine, I receive a contradictory error:
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
1
Error: Symbol at (1) is not a DUMMY variable
Have I eliminated the sources of error pointed out in the helpful suggestions? Could this be a compiler related error (using mpi90)?
~~~First Edit~~~
I have a subroutine whose input argument is an array of user defined type XYZ. I wish to deallocate xyzArray and allocate/modify it to a different size in the body of the subroutine. I attempted the method suggested by changing array dimensions in fortran, but when I do the following:
subroutine update(xyzArray, ...)
...
TYPE (XYZ), allocatable :: xyzArray(:)
I receive an error message:
Error: ALLOCATABLE attribute conflicts with DUMMY attribute at (1)
When I try:
subroutine update(xyzArray, ...)
...
deallocate( xyzArray(myshape) )
allocate( xyzArray(newshape) )
I receive error messages:
Error: Expression in DEALLOCATE statement at (1) must be ALLOCATABLE or a POINTER
Error: Expression in ALLOCATE statement at (1) must be ALLOCATABLE or a POINTER
What do I need to do to change the size of the array in the subroutine?
To do this:
The dummy argument must be allocatable. Allocatable dummy arguments require a compiler that implements the relevant part of the Fortran 2003 standard (or a Fortran 95 compiler that implements the so called "allocatable" TR).
An explicit interface to the procedure is required (the procedure must be a module procedure, an internal procedure or have an interface block in the calling scope).
The dummy argument must not be intent(in). If you are not using the allocation status or other aspects of the value of the dummy argument at all in the subroutine then intent(out) may be appropriate (if allocated beforehand the dummy argument will be automatically deallocated when the procedure is called), otherwise intent(inout) or no intent.
(Your second block of example code has a syntax error with the deallocate statement - you should simply specify the xyzArray variable, leave off the (myshape) shape specification))
For example, in a module:
subroutine update(xyzArray)
type(xyz), allocatable, intent(inout) :: xyzArray(:)
...
if (allocated(xyzArray)) deallocate(xyzArray)
allocate(xyzArray(newshape))
...
If you are sure, you want to deallocate the array in your subroutine, you can declare the dummy argument being intent(out), so that it is deallocated automatically when the subroutine is entered:
module whatever
implicit none
type :: xyz
:
end type xyz
contains
subroutine update(xyzArray)
type(xyz), allocatable, intent(out) :: xyzArray(:)
:
allocate(xyzArray(someshape))
:
end subroutine update
end module whatever
As already noted by IanH, the process must have an explicit interface (e.g. being enclosed in a module) and in the caller program you must declare the actual argument allocatable:
program test
use whatever
implicit none
type(xyz), allocatable :: array(:)
:
call update(array)
:
end program test

Resources