Netcdf и фортрановые структуры - PullRequest
3 голосов
/ 03 августа 2011

У меня есть эта структура 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 (объект).Любое решение этого в HDF5 также приветствуется.Заранее спасибо

1 Ответ

2 голосов
/ 10 августа 2011

В принципе, да, это возможно с NetCDF4;Вы ищете раздел Определяемые пользователем типы данных руководства.

Однако его поддержка достаточно слабая, что может вызвать проблемы (и вам может понадобитьсяинтерфейс f77 даже в F90).Вот моя действительно хакерская первая попытка, которую я не могу скомпилировать, потому что привязки F90 не допускают вызова nf90_put_var.Также обратите внимание, что магия заключается в расчете смещений, что нетривиально в Фортране (но выполнимо с помощью MPI_Get_Address, если вы также используете MPI ...).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
...