【问题标题】:Can I pass a variable to a derived type such that each instance of my derived type could have arrays of different lengths?我可以将变量传递给派生类型,以便派生类型的每个实例都可以具有不同长度的数组吗?
【发布时间】:2019-03-18 03:40:23
【问题描述】:

在一个程序中组织 11 个相似但大小不同的数组的最佳方法是什么,没有 allocatable 属性?

我在想象这样的事情:

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

然后在主程序中我可以这样声明:

type(mytype), dimension(N) :: Array

其中 'Array' 的第 i 个元素可以访问三个数组 A、B 和 C,并且这三个数组中的每一个都有不同的大小。

我目前遇到的问题是我正在解决一个 QM 问题,我有 11 个不同的数组,它们的大小各不相同,但都依赖于相同的参数(因为大小 A、B 和 C 都取决于 i)。这些数组的实际值也不会改变。

我的程序着眼于不同类型的系统,每个系统都有自己的 A、B 和 C(只是为了保持类比),并且在每个系统中 A、B 和 C 都有唯一的大小。

如果我知道我正在查看 6 种不同类型的系统,我需要 A、B 和 C 的 6 个不同副本。

目前,A、B 和 C 不是派生类型的一部分,而是在每次迭代时可分配和重新计算。对于较大的系统,此计算需要十分之一秒以上。但我的结果平均约为 100,000 次,这意味着这可以节省大量时间。另外,记忆力也不是我欠缺的。

我尝试在另一个程序中计算这些数组并将它们写入文件并在需要时读取它们,但不幸的是这并不比同时重新计算快。

注意:这是我的实际数组的样子:

  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      

每个系统的每个数组都有不同的大小。

编辑:

所以我真正需要的是该编辑上方列表中的 N 个数组副本。属于第 i 个副本的数组具有随 i 缩放的大小(例如 PES_down 具有维度 (i,4**i))。据我了解,这意味着我需要 N 个不同类型的“MyType”变量声明。这通常没问题,但问题是 N 是在编译时定义的,但可以在运行之间更改。

N 确实有一个已定义的最大值,但是当我知道我不会使用这些数组时,它似乎浪费了很多内存。

【问题讨论】:

  • 那么,您希望名为 Array 的数组变量具有维度 N,其中 N 来自用户输入?另外,这个数组的每个元素都是带有数组组件的派生类型,其中这些数组的维度与数组中的元素位置成正比?
  • 是的,我认为这是准确的。我目前正在按照您在评论中的建议进行操作。我没有做太多的测试,但我的经验是可分配的数组比那些没有的要慢。所以我希望通过在编译时定义它会更快。

标签: arrays fortran allocation derived-types


【解决方案1】:

我想使用包含ABC 的派生类型和大小变量i 并使用一些初始化例程为每个i 分配它们是最直接的(这里, 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

结果(使用 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

主程序中的array(:)是可分配的,这样

type(MyType), allocatable :: array(:)

N = 6
allocate( array( N ) )

当从输入文件读入N 时,这可能很有用。此外,我们可以通过更改下面带有(*) 的行(以使用OO 样式),从MyType_init() 创建一个类型绑定过程。

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

【讨论】:

  • 但我想知道是否可以为此目的使用参数化类型...?
【解决方案2】:

(更详细的解释请联系this answer)。

正如@roygvib 在他的评论中所说,是的,在这种情况下使用参数化派生类型不仅是可能的,而且是完美的匹配。这是 PDT 旨在解决的主要问题之一。

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

然后,在主程序中,您将像这样声明您的对象(其中i 是当前系统类型的已知长度参数):

type(mytype(i)), dimension(N) :: Array

但首先,请检查编译器中此功能的可用性。

【讨论】:

  • 您的意思是 OP 想要将具有不同类型参数的对象存储在同一个数组中吗?如果是,那是不可能的,因为数组元素必须具有相同的存储大小(形式上,相同的类型和种类)。
  • 我不确定,但我认为指针组件是模拟锯齿状数组的唯一方法
  • 这似乎完全符合我的要求。我现在意识到,除了我在原始帖子中描述的功能之外,我还需要功能。我将添加一个编辑以进一步澄清。
猜你喜欢
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 2011-11-05
  • 1970-01-01
相关资源
最近更新 更多