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
精彩评论