【问题标题】:Pass 1D array to 3D array将 1D 数组传递到 3D 数组
【发布时间】:2015-11-18 11:35:07
【问题描述】:

我在 Fortran 中使用了一个 API,它提供了一个写入数据的例程。假设它的名字是api_write_data。此例程需要一个数组作为参数,其维度可以是 1、2 或 3。

我想编写一个子例程,作为这个 API 例程的包装器。但因此我有必要编写一个可以处理 1D、2D 或 3D 数组的例程,并且可以正确地将它们传递给 API 例程。我怎样才能做到这一点?我可以这样做吗?

我的方法是这样的,但它不起作用:

subroutine write_data(array)
implicit none
integer, dimension(:,:,:), intent(in):: array

call api_write_data(array)

end subroutine write_data

但是,当我使用例如一维数组调用此例程时,我得到了已知错误:

Error: Rank mismatch in argument 'array' at (1) (rank-3 and rank-1)

有没有办法在 Fortran 中做这种事情?对我来说,有必要将 Array 作为 1D、2D 或 3D 数组传递给 write_data 例程。但是,我可以将数组作为一维数组传递给api_write_data

你知道我该怎么做吗?

【问题讨论】:

    标签: arrays multidimensional-array fortran subroutine


    【解决方案1】:

    reshape 函数的替代方法可能是有一个指向多维数组的一维指针:

    p(1:size(c)) => c(:,:,:)
    

    您可以将指针作为一维数组传递而无需进行复制。事实上,它应该和传递数组本身一样快。 当然,你需要某种方式告诉子程序数组的形状:

    module test_mod
    contains
      subroutine print_arr( arr, dimX, dimY, dimZ )
        integer,intent(in)  :: arr(:)
        integer,intent(in)  :: dimX, dimY, dimZ
    
        if ( dimZ == 0 ) then
          if ( dimY == 0 ) then
            ! 1D
            print *, "1D array provided"
            print *, "a(4) =", arr(4)
          else
            ! 2D
            print *, "2D array provided"
            print *, "a(1,2) =", arr((2-1)*dimX+1)
          endif
        else
          ! 3D
          print *, "3D array provided"
          print *, "a(1,2,1) =", arr( ((1-1)*dimY + (2-1))*dimX+1)
        endif
      end subroutine
    end module
    
    program test
    use test_mod
      integer :: i
      integer, target   :: a(8)
      integer, target   :: b(4,2) 
      integer, target   :: c(2,2,2)
      integer, pointer  :: p(:)
    
      a = [ (i,i=1,8) ]
      b = reshape( a, [4,2] )
      c = reshape( a, [2,2,2] )
    
      p(1:size(a)) => a(:)
      call print_arr( p, 8, 0, 0 )
    
      p(1:size(b)) => b(:,:)
      call print_arr( p, 4, 2, 0 )
    
      p(1:size(c)) => c(:,:,:)
      call print_arr( p, 2, 2, 2 )
    end program
    

    反之亦然……您可以将 1D 数组映射到 3D 指针:

    integer, pointer  :: p2(:,:,:)
    !...
    p2(1:4,1:2,1:1) => a
    

    【讨论】:

    • 不限制fortran 90,会不会有另一种可能?也许有新的语言特性,也可以通过 ifort 和 gfort 编译为 .f90 文件
    【解决方案2】:

    您可以使用 Fortran 接口来定义多个版本的例程:

    interface write_data
      module procedure write_data_1d
      module procedure write_data_2d
      module procedure write_data_3d
    end interface write_data
    

    然后这些程序可以处理不同类型的输入。然后在这些过程中,您可以使用 RESHAPE 函数将输入转换为方便的形状,以便所有三个都可以调用一个公共子例程来实现您所做的任何事情的逻辑。

    【讨论】:

    • reshape 确实提供了复制的可能性。
    • 这是一种选择,但这会导致很多代码。因为我有这个例程的 6 个不同版本,所以我总共有 18 个例程。
    • @francescalus 你这是什么意思?
    • @francescalus 意味着函数 RESHAPE 可能会复制原始数据,这可能会影响性能。这可能会也可能不会发生。如果您将数据存储在一维数组中的方式与存储多维数据的方式相同,那么足够好的编译器可能会看到并生成优化的代码。
    • @Skyy2010 是的,我的意思是前面的评论。也就是说,reshape 返回一个结果,并且只有当编译器可以绝对确定该结果和原始结果在联合生命周期内没有被修改时,才能进行任何非复制优化。许多人甚至不会费心去确定这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 2020-04-22
    • 2013-09-10
    • 2020-06-23
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多