开发者

Netcdf and fortran structures

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


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜