动态数组排名

时间:2016-07-15 03:34:46

标签: fortran fortran90

我在模块中有一些动态的数组变量,后来在模块外部的两个子程序之一中分配。但是,在一个子程序中,我希望数组为1D,在另一个子程序中,我希望它是2D。

原则上我会在模块中想要这样的东西,但我不相信这在声明区域是可行的吗?:

if (option1) then
  real (kind=8), allocatable :: arr1(:)
else
  real (kind=8), allocatable :: arr1(:,:)
endif

在可分配的声明中是否有一种方法可以使维度具有动态性?

编辑1:我这样做的原因是我在现有代码库中添加了一个新的子程序,但我希望向后兼容。 arr1仅由两个独立的子程序使用,主程序根本不使用它。以下是一些更完整的代码,显示了这个想法:

program myprog
use inputs

call read_inputs

if (option1) then
    call do1
else
    call do2
endif

contains
    subroutine read_inputs
        use inputs
        use mymod
        !!!read from file .logical. option1, integers N1, N2

        !allocate arrays
        if (option1) then 

        else

        endif
    end subroutine read_inputs

    subroutine do1
        use inputs
        use mymod

        allocate(arr1(N1))

        !do stuff with arr1
    end subroutine do1

    subroutine do2
        use inputs
        use mymod

        allocate(arr1(N1,N2))

        !do stuff with arr1
    end subroutine do2

end program

module inputs
    logical :: option1
    integer :: N1, N2

end module inputs

module mymod
    use inputs
    !!!!can I do something here to make the rank of arr1 dynamic? I don't think the following will work
    if (option1)
        real (kind=8), allocatable :: arr1(:)
    else
        real (kind=8), allocatable :: arr1(:,:)
    endif
end module mymod

我可能在mymod中有两个单独的变量,arr1和arr1_new。我只是希望避免这种情况。

2 个答案:

答案 0 :(得分:1)

我认为' olden'做这样的事情的方法是分别传递第一个元素而不是整个数组和数组的大小:

program dyn_array
    implicit none
    integer :: a(2, 3)
    integer :: i
    call set1d(a(1,1), size(a))
    do i = 1, 3
        write(*, '(2I4)') a(:,i)
    end do
    contains
        subroutine set1d(array, s)
            implicit none
            integer, intent(in) :: s
            integer, intent(out) :: array(s)
            integer :: i
            do i = 1, s
                array(i) = 3 * i
            end do
        end subroutine set1d
end program dyn_array

答案 1 :(得分:0)

"你能否将2D数组传递给需要一维数组并获得正确尺寸的子程序?"

你可以使用reshape,但是如果你的代码依赖于编译器来帮助那么2D进入1D是很冒险的。你可以在之前和之后使用RESHAPE ......或者你可以有2个例程,我们可以调用set1d和set2d。 然后在模块中,您可以选择要使用的模块。你可以有整数(s),float(s),complex(s),byte。

你会CALL Array $ Set(Array,s)

MODULE Stuff
  PUBLIC :: Array$Set

  PRIVATE
    INTERFACE Array$Set
  MODULE PROCEDURE Set1d_Float, Set1D_Double, set2D_Float, Set2D_Double
END INTERFACE Array$Set

CONTAINS

SUBROUTINE  Set1D_Float(Array,S)...
!$DIR ATRIBUTES ASUUME_ALIGND:64                :: Array
REAL, DIMENSION(:,:), CONTIGUOUS, INTENT(INOUT) :: Array
REAL, DIMENSION(:,:),             INTENT(IN   ) :: S
REAL, DIMENSION(2)                              :: Shapez
...
Shapez = Shape(Array)
DO I =  1, Shapez(1)
  DO J = 1, Shapez(2)
...
END SUBROUTINE Set1D_Float

END MODULE Stuff

对于你的例子:     if(option1)然后       real(kind = 8),allocatable :: arr1(:)     其他       real(kind = 8),allocatable :: arr1(:,:)     ENDIF

我会建议:

!DIR ATTRIBUTES ALIGN:64        :: Arr1
REAL, DIMENSION(:), ALLOCATABLE :: Arr1
...


if (option1) then
  ALLOCATE(Arr1(<#>))
else
  ALLOCATE(Arr1(<#>*<#2>))
  RESHAPE(Arr1, SHAPE=/(#1,#2)) !Check the syntax
endif

CALL Array$Set(Arr1,s) !It'll find the right one...

!... at the bottom ...
IF(ALLOCATED(Arr1)) DEALLOCATE(Arr1)
END PROGRAM