Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 使用数组组件设计派生类型_Arrays_Fortran_Structure_Dynamictype_Allocatable Array - Fatal编程技术网

Arrays 使用数组组件设计派生类型

Arrays 使用数组组件设计派生类型,arrays,fortran,structure,dynamictype,allocatable-array,Arrays,Fortran,Structure,Dynamictype,Allocatable Array,在设计派生类型时,我很难找到任何具体的信息。我认为讨论这个问题的最好方式是通过几个选项。我用派生类型的不同应用程序编写了一些代码段。我更喜欢对npart、index和refs使用动态数组。我省略了实际使用该结构的代码部分(因为是我自己编的,所以没有任何代码),但显示了一个示例,在一个例程中,我打算至少使用一次该结构中的所有值 选项A:在派生类型中使用静态数组。缺点是我必须在编译时猜测数组的大小 ! Known before compile time. nboxes = 5000 max_part

在设计派生类型时,我很难找到任何具体的信息。我认为讨论这个问题的最好方式是通过几个选项。我用派生类型的不同应用程序编写了一些代码段。我更喜欢对
npart
index
refs
使用动态数组。我省略了实际使用该结构的代码部分(因为是我自己编的,所以没有任何代码),但显示了一个示例,在一个例程中,我打算至少使用一次该结构中的所有值

选项A:在派生类型中使用静态数组。缺点是我必须在编译时猜测数组的大小

! Known before compile time.
nboxes = 5000
max_parts = 2000
packs = 10

Type Boxes
   Sequence
   Integer :: location, date
   Integer, Dimension(0:packs) :: nparts
   Integer, Dimension(max_parts,packs) :: index
   Real(Kind=8), Dimension(packs,packs) :: refs
End Type Boxes

type(boxes), dimension(:), allocatable :: assembly
allocate(assembly(nboxes))

! Perform some operations on assembly...
do i = 1,nboxes
   do j = 1,packs
      do k = j,packs
         example = assembly(i)%nparts(k) - assembly(i)%nparts(j)
         .
         .
         do m = 1,max_parts
            example = assembly(i)%index(m,j) + assembly(i)%refs(k,j) * assembly(i)%nparts(j)
            .
            .
         end do
      end do
   end do
end do
选项B:在派生类型中使用动态数组

! Defined during execution. Much better.
nboxes = 5000
max_parts = 2000
packs = 10

Type Boxes
   Sequence
   Integer :: location, date
   Integer, Dimension(:), Allocatable :: nparts
   Integer, Dimension(:,:), Allocatable :: index
   Real(Kind=8), Dimension(:,:), Allocatable :: refs
End Type Boxes

type(boxes), dimension(:), allocatable :: assembly
allocate(assembly(nboxes))
do i = 1,nboxes
   allocate(assembly(i)%nparts(0:packs))
   allocate(assembly(i)%index(max_parts,packs))
   allocate(assembly(i)%refs(packs,packs))
end do

! Perform some operations on assembly...
do i = 1,nboxes
   do j = 1,packs
      do k = j,packs
         example = assembly(i)%nparts(k) - assembly(i)%nparts(j)
         .
         .
         do m = 1,max_parts
            example = assembly(i)%index(m,j) + assembly(i)%refs(k,j) * assembly(i)%nparts(j)
            .
            .
         end do
      end do
   end do
end do
选项C:最小化派生类型中使用的动态数组的数量,并强制
程序集
成为数组。请注意,在这个版本中,我们有一堆未使用的内存。例如,
npart
index
需要内存
packs
-自
组装(packs,packs,nboxes)
以来的次数

选项D:选项C的另一种排列方式

问题:

  • 哪个版本是为所示的
    do
    循环示例设计派生类型的正确/预期方法?考虑到我想要动态阵列功能,哪个版本是最优化的
  • 可能与上述有关。如何分配和访问内存?使用
    序列
    是否值得?我认为分配的数组无论如何都不会按顺序出现。既然
    assembly
    的每个部分都比较小,那么选项C不是最好的吗
  • 我是否应该将这个派生类型拆分为多个派生类型,或者干脆放弃它,只使用变量?我将在多个例程上使用这个派生类型,并将它放在一个模块中
  • 您希望变化最快的索引成为最内部的循环。在多维数组中,变化最快的索引是第一个索引。因此,备选方案B接近这一目标。尽管您可能希望更改参照中标注的顺序

  • 由索引(i,j)访问的形状(m,n)的二维数组的内存布局通过以下顺序给出:
    k=i+m*(j-1)
    ,其中
    k
    表示内存中的一维索引。派生的数据类型将包含对已分配内存的引用,所包含可分配数据的实际内存可能分散在内存中,但每个可分配数组本身是连续的。因此,在选项B中,
    程序集
    将是一个连续数组,其中包含对可分配数组的引用。
    nPart
    index
    ref
    中的每一个本身都是连续的数组,但可以位于任意位置,在一个装配图元内或不同装配图元之间没有特定关系。使用
    序列
    在这里没有任何意义,它迫使编译器按照您声明的顺序将派生数据类型的元素放入内存,并禁止它根据自己认为合适的顺序重新排列数据类型组件,这可能会限制性能。我怀疑,在你的例子中,它会有很大的影响,但当它不需要时,你应该离开它

  • 不,在我看来,选项B看起来非常合理(除了
    序列


  • 您的编译器支持参数化派生类型吗?它支持,尽管我不熟悉这个概念和应用程序。所以我的头脑还不支持它。:)
    kind=8
    真的很难看,避免使用魔法常量!这并不意味着8个字节!至少不是在所有编译器中。1。哎呀,我的疏忽。我已经编辑了问题中的代码,因此这是正确的。2.选项A中的
    SEQUENCE
    是否有助于优化?我的印象是,在内存中相邻的信息将提高循环中的计算速度。如果使用一个派生类型,其中每个循环的内存都是连续的并且是可分配的,那会更好吗?例如,选项C上的一个变体,
    索引
    不再是派生类型中的数组。@Higgy关于
    序列
    ,您指的是哪些信息?从性能的角度来看,将其放入派生数据类型是一个坏主意。正如我所说,它强制编译器使用您强加的顺序。因此,它的优化选项较少。你想要数组,这就是Fortran的亮点,我相信选项B会给你最好的变体。性能方面的选项A可能会更好,但您说过希望使用动态内存分配。在我看来,C的变化比A和B更糟糕。很好。那对我来说就清楚了。是否有任何理由认为
    SEQUENCE
    是有益的?@Higgy From:“SEQUENCE语句用于:(a)允许这种类型的对象与存储关联,或(b)允许实际参数和伪参数具有相同的类型,而不使用或主机关联”。关于参数关联,请看一看:假设您使用的是ifort,那么REAL(KIND=8)就可以了,表示8字节,但是我在标记中没有看到intel fortran。我可能会在编译器开关中使用数组对齐,或者在ifort中使用数组对齐!DIR$ATTRIBUTES ALIGN:64::assembly。
    ! Defined during execution. Much better.
    nboxes = 5000
    max_parts = 2000
    packs = 10
    
    Type Boxes
       Sequence
       Integer :: location, date, nparts, index
       Real(Kind=8) :: refs
       Integer, Dimension(:), Allocatable :: index
    End Type Boxes
    
    type(boxes), dimension(:,:,:), allocatable :: assembly
    allocate(assembly(packs,packs,nboxes))
    do i = 1,nboxes
       do j = 1,packs
          do k = 1,packs
             allocate(assembly(k,j,i)%index(max_parts))
          end do
       end do
    end do
    
    ! Perform some operations on assembly...
    do i = 1,nboxes
       do j = 1,packs
          do k = j,packs
             example = assembly(k,j,i)%nparts - assembly(k,j,i)%nparts
             .
             do m = 1,max_parts
                example = assembly(k,j,i)%index(m) + assembly(k,j,i)%refs * assembly(k,j,i)%nparts
                .
                .
             end do
          end do
       end do
    end do