【问题标题】:How to assign pointers to a complex 3d array in Fortran如何在 Fortran 中为复杂的 3d 数组分配指针
【发布时间】:2019-02-22 15:21:14
【问题描述】:

我想知道如何分配两个指针,一个指向复数 3d 数组的实部,另一个指向 Fortran 中同一数组的虚部。

假设我已经定义了一个 3d 数组:

复杂*16, 维度(:,:,:), 可分配, 目标:: vftmp

我想分配一个指向 vftmp(2,1,1) 实部的指针和一个指向 vftmp(2,1,1) 虚部的指针。有人可以帮我做一个sn-p吗?谢谢。

【问题讨论】:

  • 假设你的意思是指针赋值,你不能。 vftmp 的真正部分当然是real(vftmp,16)。例如,您不能使用re => real(vftmp,16)。顺便说一句,16 是一个非标准的种类类型参数。

标签: fortran


【解决方案1】:

我希望下面的事情是可能的

real, pointer :: re
complex, target :: z
re => z % re
! or
real, pointer :: re(:,:,:)
complex, target :: z(2,3,4)
re => z(:,:,:) % re

但它似乎不是(或者可能使用非常新的编译器......?)所以下面的解决方法:


1) 如果目标是获取复杂数组的单个元素的 Re 和 Im 部分的(标量)指针,我想我们可以使用 c_f_pointer 这样

module testmod
contains
    subroutine getreim_ptr( z, re, im )
        use iso_c_binding
        implicit none
        complex, target, intent(in) :: z
        real, pointer :: re, im, buf(:)

        call c_f_pointer( c_loc( z ), buf, [ 2 ] )

        re => buf( 1 )
        im => buf( 2 )
    end subroutine
end module

program main
    use testmod
    implicit none
    complex :: z( 2, 3 )
    real, pointer :: re, im

    !! Test array.
    z = 0.0
    z( 1, 1 ) = ( 1.0, -1.0 )

    !! Get pointers for the Re/Im parts of z(1,1).
    call getreim_ptr( z( 1, 1 ), re, im )

    print *, "z(1,:) = ", z(1,:)
    print *, "z(2,:) = ", z(2,:)
    print *, "re = ", re
    print *, "im = ", im
end

结果(gfortran-8.2):

 z(1,:) =   (1.00000000,-1.00000000)  (0.00000000,0.00000000)  (0.00000000,0.00000000)
 z(2,:) =   (0.00000000,0.00000000)   (0.00000000,0.00000000)  (0.00000000,0.00000000)
 re =    1.00000000    
 im =   -1.00000000 

2) 如果目标是获取整个复杂数组的数组指针,我想我们可以使用秩重映射指针分配(指向具有恒定间隙的非连续内存)。例如,在 2D 情况下(为简单起见),

re( 1:n1, 1:n2 ) => buf( 1::2 )
im( 1:n1, 1:n2 ) => buf( 2::2 )

其中reim 是二维数组指针,buf 是一个真正的一维数组指针,它指向一个可分配的二维复数数组(通过c_f_pointer)。一个最小的示例可能如下所示:

module testmod
contains
    subroutine getreim_ptr2d( zarr, re, im )
        use iso_c_binding
        implicit none
        complex, allocatable, target, intent(in) :: zarr(:,:)
        real, pointer :: re(:,:), im(:,:), buf(:)
        integer :: n1, n2

        n1 = size( zarr, 1 )
        n2 = size( zarr, 2 )
        call c_f_pointer( c_loc( zarr ), buf, [ size(zarr) * 2 ] )

        re( 1:n1, 1:n2 ) => buf( 1::2 )
        im( 1:n1, 1:n2 ) => buf( 2::2 )
    end subroutine
end module

program main
    use testmod
    implicit none
    complex, allocatable :: zarr(:,:)
    real, pointer :: re(:,:), im(:,:)
    integer i

    !! Prepare a test array (zarr).
    allocate( zarr( 2, 3 ) )
    zarr(1,:) = [( complex( 100 + i, -100 -i ), i=1,3 )]
    zarr(2,:) = [( complex( 200 + i, -200 -i ), i=1,3 )]
    print *, "shape( zarr ) = ", shape( zarr )
    print *, "zarr(1,:) = ", zarr(1,:)
    print *, "zarr(2,:) = ", zarr(2,:)

    call getreim_ptr2d( zarr, re, im )

    print *
    print *, "shape( re ) = ", shape( re )
    print *, "re(1,:) = ", re(1,:)
    print *, "re(2,:) = ", re(2,:)
    print *
    print *, "shape( im ) = ", shape( im )
    print *, "im(1,:) = ", im(1,:)
    print *, "im(2,:) = ", im(2,:)
end program

结果(gfortran 8.2):

 shape( zarr ) =            2           3
 zarr(1,:) =  (101.000000,-101.000000)  (102.000000,-102.000000)  (103.000000,-103.000000)
 zarr(2,:) =  (201.000000,-201.000000)  (202.000000,-202.000000)  (203.000000,-203.000000)

 shape( re ) =            2           3
 re(1,:) =    101.000000    102.000000    103.000000    
 re(2,:) =    201.000000    202.000000    203.000000    

 shape( im ) =            2           3
 im(1,:) =   -101.000000   -102.000000   -103.000000    
 im(2,:) =   -201.000000   -202.000000   -203.000000  

以下是我们可以在网上找到的一些资料:

Fortran 2003 的新特性(N1597):3.7“指针赋值”

"...允许重新映射秩一数组的元素:

p(1:m,1:2*m) => a(1:2*m*m)

映射是数组元素顺序,目标数组必须足够大。边界可以是任何标量整数表达式。 rank-one 数组的限制是因为指针数组不需要占用连续的存储空间:

a => b(1:10:2)

但在排名一的情况下,所有间隙的长度都相同。”

Fortran 2003 扩展:5.4.3 等级重新映射指针分配(this page)

"...此功能允许多维指针指向一维对象。例如:

REAL,POINTER :: diagonal(:),matrix(:,:),base(:)
...
ALLOCATE(base(n*n))
matrix(1:n,1:n) => base
diagonal => base(::n+1)
!
! DIAGONAL now points to the diagonal elements of MATRIX.
!

请注意,在进行排名重映射时,必须为所有维度明确指定下限和上限的值,没有默认值。"

【讨论】:

  • 我不理解代码中的符号 buf(1::2) 和 buf(2::2)。冒号后面的值2,是步幅吗?你能解释一下吗?谢谢。
  • 同写buf( 1 : 2*n1*n2 : 2 ) 和buf( 2 : 2*n1*n2 : 2 )。我们可以在符号 a:b:inc 中省略 a、b、inc 中的任何一个,然后它们被自动假定为下限(对于 a)、上限(对于 b)和 1(对于 inc)。 (例如,如果 A 被声明为 A(6),则 A(1::2) (= A(1:6:2)) 表示 A(1)、A(3)、A(5),并且A( 2::2 ) (= A( 2:6:2 )) 表示 A(2), A(4), A(6)。)
  • 只是后期添加... 上述方法为 non-contiguous 内存创建了一个数组指针,我认为不应将其传递给期望数组的子例程连续内存(例如具有显式形状或假定大小的虚拟参数的遗留库例程)。所以请小心……
猜你喜欢
  • 2021-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-09
  • 1970-01-01
  • 2021-07-06
  • 2019-07-17
  • 1970-01-01
相关资源
最近更新 更多