Netcdf 和 Fortran 结构

发布于 2024-11-27 13:02:42 字数 403 浏览 2 评论 0原文

我有这个 Fortran 结构。

 type custom 
    real :: a,b
    real,dimension(20) ::c,d
    real,dimension(20,50) :: e
 end type custom

然后我有另一个像这样的结构

type custom2
  type(custom):: data
end type custom2

,现在我创建一个对象类型(custom2)::pntr

是否可以将自定义结构中的所有数据直接写入 netcdf 格式,并使用所有组件的名称(即 a、b、c ,d,e) 相同。当然这是使用pntr(object)。 HDF5 中的任何解决方案也受到欢迎。提前致谢

I have this fortran structure.

 type custom 
    real :: a,b
    real,dimension(20) ::c,d
    real,dimension(20,50) :: e
 end type custom

Then I have another structure like this

type custom2
  type(custom):: data
end type custom2

now i make an object type(custom2)::pntr

is it possible to write all the data in the structure custom in to netcdf format directly with all the names of the components (i.e. a,b,c,d,e) to be the same. Of course this is using pntr(object). Any solution of this in HDF5 is also welcome. Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

瑾兮 2024-12-04 13:02:42

原则上,是的,这对于 NetCDF4 是可能的;您正在寻找 用户手册的定义数据类型部分。

然而,对它的支持很差,可能会导致问题(即使在 F90 中,您最终也可能不得不使用 f77 接口)。这是我真正的第一次尝试,我无法编译它,因为 F90 绑定不允许 nf90_put_var 调用。还要注意,神奇之处在于计算偏移量,这在 Fortran 中并不简单(但如果您也使用 MPI,则可以使用 MPI_Get_Address 进行操作...)。 loc() 是一个常见但非标准的函数,它允许您执行此操作,如果您信任指针数学,您也可以使用 iso_c_bindings 和 c_loc() 。

PROGRAM netcdf_userdeftypes
    USE netcdf
    implicit none

    type custom
       real :: a,b
       real,dimension(20) ::c,d
       real,dimension(20,50) :: e
    end type custom

    integer :: stat
    integer :: i
    integer, parameter :: ncvars=5
    type(custom) :: cvars(ncvars)
    integer :: ctype_id, cvar_id, file_id, dim_id
    integer :: aoff, boff, coff, doff, eoff

    stat = nf90_create(path="test.nc4", cmode=ior(NF90_CLOBBER,NF90_NETCDF4), ncid=file_id)
    stat = nf90_def_dim(file_id, 'Num Custom Vars', ncvars, dim_id)

    stat = nf90_def_compound(ctype_id, (2+2*20+1*(20*50))*4, 'custom type', ctype_id)

    call calcoffsets(aoff, boff, coff, doff, eoff)
    stat = nf90_insert_compound(file_id, ctype_id, 'a', aoff, NF90_REAL)
    stat = nf90_insert_compound(file_id, ctype_id, 'b', boff, NF90_REAL)
    stat = nf90_insert_array_compound(file_id, ctype_id, 'c', coff, NF90_REAL, 1, 20)
    stat = nf90_insert_array_compound(file_id, ctype_id, 'd', doff, NF90_REAL, 1, 20)
    stat = nf90_insert_array_compound(file_id, ctype_id, 'e', eoff, NF90_REAL, 2, 20*50)

    stat = nf90_def_var(file_id, 'custom variable', ctype_id, [dim_id], cvar_id)
    stat = nf90_enddef(file_id)

    do i=1,ncvars
        cvars(i)%a = ncvars*10+1
        cvars(i)%b = ncvars*10+2
        cvars(i)%c = ncvars*10+3
        cvars(i)%d = ncvars*10+4
        cvars(i)%e = ncvars*10+5
    enddo

    stat = nf90_put_var(file_id, cvar_id, cvars)

    stat = nf90_close(file_id)

CONTAINS
    ! there has to be a better way to do this
    ! loc() is common, and c_loc() could in principle
    ! be used...
    SUBROUTINE calcoffsets(aoff, boff, coff, doff, eoff)
        implicit none
        integer, intent(out) :: aoff, boff, coff, doff, eoff

        type(custom) :: test
        integer :: i,testlen
        type(custom), pointer :: tp
        real, allocatable, dimension(:) :: copy

        test % a = 1.
        test % b = 2.
        test % c = 0.
        test % c(1) = 3.
        test % d = 0.
        test % d(1) = 4.
        test % e = 0.
        test % e(1,1) = 5.

        testlen = inquire( iolength=test )
        allocate( copy( testlen ) )
        copy = transfer( test, copy )

        do i=1,testlen
            if (copy(i) == 1.) aoff = i-1
            if (copy(i) == 2.) boff = i-1
            if (copy(i) == 3.) coff = i-1
            if (copy(i) == 4.) doff = i-1
            if (copy(i) == 5.) eoff = i-1
        enddo

    END SUBROUTINE calcoffsets

END PROGRAM netcdf_userdeftypes

In principle, yes, this is possible with NetCDF4; you're looking for the User Defined Data Types section of the manual.

However, the support for it is poor enough that it may cause problems (and you may end up having to use the f77 interface even in F90). Here's my really hacky first attempt, which I can't get to compile because the F90 bindings don't allow the nf90_put_var call. Note too that the magic is all in calculating the offsets, which is non-trivial in Fortran (but is doaable using MPI_Get_Address if you're also using MPI...). loc() is a common but non-standard function which would allow you to do this, and you could also use iso_c_bindings and c_loc() if you trust the pointer math.

PROGRAM netcdf_userdeftypes
    USE netcdf
    implicit none

    type custom
       real :: a,b
       real,dimension(20) ::c,d
       real,dimension(20,50) :: e
    end type custom

    integer :: stat
    integer :: i
    integer, parameter :: ncvars=5
    type(custom) :: cvars(ncvars)
    integer :: ctype_id, cvar_id, file_id, dim_id
    integer :: aoff, boff, coff, doff, eoff

    stat = nf90_create(path="test.nc4", cmode=ior(NF90_CLOBBER,NF90_NETCDF4), ncid=file_id)
    stat = nf90_def_dim(file_id, 'Num Custom Vars', ncvars, dim_id)

    stat = nf90_def_compound(ctype_id, (2+2*20+1*(20*50))*4, 'custom type', ctype_id)

    call calcoffsets(aoff, boff, coff, doff, eoff)
    stat = nf90_insert_compound(file_id, ctype_id, 'a', aoff, NF90_REAL)
    stat = nf90_insert_compound(file_id, ctype_id, 'b', boff, NF90_REAL)
    stat = nf90_insert_array_compound(file_id, ctype_id, 'c', coff, NF90_REAL, 1, 20)
    stat = nf90_insert_array_compound(file_id, ctype_id, 'd', doff, NF90_REAL, 1, 20)
    stat = nf90_insert_array_compound(file_id, ctype_id, 'e', eoff, NF90_REAL, 2, 20*50)

    stat = nf90_def_var(file_id, 'custom variable', ctype_id, [dim_id], cvar_id)
    stat = nf90_enddef(file_id)

    do i=1,ncvars
        cvars(i)%a = ncvars*10+1
        cvars(i)%b = ncvars*10+2
        cvars(i)%c = ncvars*10+3
        cvars(i)%d = ncvars*10+4
        cvars(i)%e = ncvars*10+5
    enddo

    stat = nf90_put_var(file_id, cvar_id, cvars)

    stat = nf90_close(file_id)

CONTAINS
    ! there has to be a better way to do this
    ! loc() is common, and c_loc() could in principle
    ! be used...
    SUBROUTINE calcoffsets(aoff, boff, coff, doff, eoff)
        implicit none
        integer, intent(out) :: aoff, boff, coff, doff, eoff

        type(custom) :: test
        integer :: i,testlen
        type(custom), pointer :: tp
        real, allocatable, dimension(:) :: copy

        test % a = 1.
        test % b = 2.
        test % c = 0.
        test % c(1) = 3.
        test % d = 0.
        test % d(1) = 4.
        test % e = 0.
        test % e(1,1) = 5.

        testlen = inquire( iolength=test )
        allocate( copy( testlen ) )
        copy = transfer( test, copy )

        do i=1,testlen
            if (copy(i) == 1.) aoff = i-1
            if (copy(i) == 2.) boff = i-1
            if (copy(i) == 3.) coff = i-1
            if (copy(i) == 4.) doff = i-1
            if (copy(i) == 5.) eoff = i-1
        enddo

    END SUBROUTINE calcoffsets

END PROGRAM netcdf_userdeftypes
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文