next_inactive up previous


File_HDF - Interface to HDF4 files

ARJO SEGERS, ROELAND VAN OSS, GIJS VAN SOEST, JOS VAN GEFFEN
KNMI


Date: 3 March 2009


Contents

Introduction

The routines facilitate reading/writing of integer or real arrays. The following type/kinds are possible:

integer(1)  
integer(2)  
integer(4) real(4)
integer(8) real(8)

Subroutines convert where possible between types and/or kinds:

Compile and link

The module includes the file "hdf.f90" from the HDF4 distribution. The include directory with this file should be specified in an argument of the 'configure' script:

     ./configure --includes=/usr/local/include

The library should be linked together with the default hdf libraries.

Usage

   use file_hdf

   HDF files
   ---------

     type(THdfFile)    ::  hdf

     call Init( hdf, '/data/test.hdf', 'read'|'create'|'write', status )

     call GetInfo( hdf, status [,num_datasets=] [,num_global_attrs=] )

     call Done( hdf, status )


   Scientific Data Sets
   --------------------

     type(TSds)        ::  sds


     !
     ! *** basic access
     !

     call Init( sds, status )

     !
     ! select sds in hdf file;
     !   index  : sets numbered 0,..,num_datasets-1
     !
     call Select( sds, hdf, index, status )

     !
     ! extract properties
     !
     call   GetInfo( sds, status [,name=] [,data_rank=] [,data_dims=] [,data_type=] [,num_attrs=]           )

     !
     ! check sds params:
     !   name  :  case independent
     !
     !   status : on input  : if non-zero, do not print error messages
     !            on output : <0 check failed, =0 check success, >0 error
     !
     call CheckInfo( sds, status [,name=] [,data_rank=] [,data_dims=] [,data_type=] [,num_attrs=] )

     call Done( sds, status )


     !
     ! *** init for reading
     !

     call Init( sds, hdf, 'name', status )

     call ReadData( sds, x(:,:,..), status [,start=(/0,0,../)] [,stride=(/1,1,../)] )

     call Done( sds, status )


     !
     ! *** init for creation
     !

     call Init( sds, hdf, 'name', shape(x), <typekey>, status [,knd=] [,bits=] )

     ! The last value of the shape array might be the
     ! hdf constant 'SD_UNLIMITED' to specify an unlimited dimension.
     !
     ! The <typekey> with optional knd or bits specify 
     ! how the data is storred:
     !
     !   'int8'     |  'integer(1)'  |  ('int'  |'integer'), (bits=8 |knd=1)
     !   'int16'    |  'integer(2)'  |  ('int'  |'integer'), (bits=16|knd=2)
     !   'int32'    |  'integer(4)'  |  ('int'  |'integer'), (bits=32|knd=4)
     !   'int64'    |  'integer(8)'  |  ('int'  |'integer'), (bits=64|knd=8)
     !   'float32'  |  'real(4)'     |  ('float'|'real'   ), (bits=32|knd=4)
     !   'float64'  |  'real(8)'     |  ('float'|'real'   ), (bits=64|knd=8)
     !
     !   'char'
     !

     call Compress( sds, 'none'   , status )
     call Compress( sds, 'rle'    , status )
     call Compress( sds, 'skphuff', status [,skip_size=1..] )
     call Compress( sds, 'deflate', status [,deflate_level=0..9] )

     call WriteData( sds, x, status [,start=(/0,0,../)] [,stride=(/1,1,../)] )

     call Done( sds, status )


     !
     ! *** init for creation with unlimited dimension
     !

     call Init( sds, hdf, 'name', (/2,3,..,SD_UNLIMITED/), &
                                          <typekey>, status [,knd=] [,bits=] )

     call WriteData( sds, x(:,:,..,1), status, start=(/0,0,..,0/) [,stride=(/1,1,../)] )
     call WriteData( sds, x(:,:,..,1), status, start=(/0,0,..,1/) [,stride=(/1,1,../)] )
                                                      :

     call Done( sds, status )


   SDS dimensions
   --------------

     Simple usage:

       call SetDim( sds, dim_index, 'name', 'unit', (/../), status [,knd=] )

     or using the expert routines:

       type(TSdsDim)  ::  dim
       call Init( dim, status )
       call Select( dim, sds, dim_index, status )   ! 0,..,n-1
       call SetName( dim, 'name'. status )
       call SetScale( dim, (/../), status [,knd=] )
       call Done( dim, status )


   Attributes
   ----------

     !
     ! select attribute index of certain attribute;
     ! status /= 0 if not found
     !
     call FindAttribute( hdf|sds|dim, 'name', attr_index, status )

     !
     ! get attribute params:
     !   attr_index       :  sets numbered 0,..,num_attrs-1
     !   data_type        :  internal hdf number, see hdf manual
     !   data_type_descr  :  'i', 'r', 's'  
     !                       (no 'l', since logicals are storred as integers)
     !
     call   GetAttributeInfo( hdf|sds|dim, attr_index, status &
                                [,name=] &
                                [,data_type=] [,data_type_descr=c] &
                                [,n_values=] )

     !
     ! check attribute params:
     !   name        :  case independent
     !   attr_index  :  sets numbered 0,..,num_attrs-1
     !
     !   status : on input  : if zero, print error messages; 
     !            on output : <0 check failed, =0 check success, >0 error
     !
     call CheckAttributeInfo( hdf|sds|dim, attr_index, status [,name=] [,data_type=] [,n_values=] )

     call  ReadAttribute( hdf|sds|dim, 'name', i, status )
     call  ReadAttribute( hdf|sds|dim, 'name', r, status )
     call  ReadAttribute( hdf|sds|dim, 'name', l, status )
     call  ReadAttribute( hdf|sds|dim, 'name', s, status )

     !
     !   status : on input  : if non-zero, do not print error messages
     !            on output : <0 check failed, =0 check success, >0 error
     !
     call CheckAttribute( hdf|sds|dim, 'name', 1     ,status )
     call CheckAttribute( hdf|sds|dim, 'name', 1.0   ,status )
     call CheckAttribute( hdf|sds|dim, 'name', .true.,status )
     call CheckAttribute( hdf|sds|dim, 'name', 's'   ,status )

     call WriteAttribute( hdf|sds|dim, 'name', 1     ,status [,knd=] )
     call WriteAttribute( hdf|sds|dim, 'name', 1.0   ,status [,knd=] )
     call WriteAttribute( hdf|sds|dim, 'name', .true.,status         )
     call WriteAttribute( hdf|sds|dim, 'name', 's'   ,status         )
 

   Time series
   -----------

     Write time series of n-D arrays to a hdf file.

     type(TTimeSeriesHDF)   :: F

     ! Open file, specify maximum number of data sets:
     call Init( F, 'test.hdf', 40, status )

     ! Add new record for field.
     ! If field does not exist yet, it is created with the specified:
     !  o unit as attribute
     !  o type key : 'real(4)', 'integer(2)', etc
     !  o maximum shape
     ! For arrays, the maximum size should be provided.

     ! first calls initialise the data sets and fill first temporal record:
     call AddRecord( F, 'psurf' , 'comment', 'hPa', 'real(4)',            1000.0, status )
     call AddRecord( F, 'press' , 'comment', 'hPa', 'real(4)', (/60/)   , pp(:) , status )
     call AddRecord( F, 'kernel', 'comment', 'c/c', 'real(4)', (/20,20/), A(:,:), status )
     call AddRecord( F, 'key', 5, 'ab123', status )

     ! extra calls add records:
     call AddRecord( F, 'press' , 'comment', 'hPa', 'real(4)', (/60/)   , pp(:) , status )
     call AddRecord( F, 'press' , 'comment', 'hPa', 'real(4)', (/60/)   , pp(:) , status )

     ! Close file:
     call Done( F, status )

Examples

   ! Extract array from existing hdf file.
   ! Sds is identified by name 'aaa' .
   ! Attribute 'version' should be 'v1.23' .
   ! Error messages are issued in case of any error.
   type(THdfFile)      ::  hdf
   type(TSds)          ::  sds
   real                ::  x(10,20)
   call Init( hdf, 'test.hdf', 'read', status )
   call Init( sds, hdf, 'aaa', status )
   call CheckAttribute( sds, 'version', 'v1.23', status )
   call ReadData( sds, x, status )
   call Done( sds, status )
   call Done( hdf, status )

   ! Extract array from existing hdf file.
   ! Sds is identified by name 'aaa' and a time attribure.
   ! Error messages are issued in case of any error.
   type(THdfFile)      ::  hdf
   type(TSds)          ::  sds
   real                ::  x(10,20)
   integer             ::  n, k
   integer             ::  status
   call Init( hdf, 'test.hdf', 'read', status )
   call Init( sds, status )
   call GetInfo( hdf, status, num_datasets=n )
   k = 0
   do
     k = k + 1
     if ( k > n ) stop 'sds not found'
     call Select( sds, hdf, k-1, status )     ! <-- sets numbered 0..n-1 !
     call CheckInfo( sds, name='aaa', status )
     if ( status /= 0 ) cycle
     call CheckAttribute( sds, 'time', (/2000,1,1,0,0,0/), status )
     if ( status /= 0 ) cycle
     call ReadData( sds, x, status )
   end do
   call Done( sds, status )
   call Done( hdf, status )

   ! Write array to a hdf file.
   type(THdfFile)      ::  hdf
   type(TSds)          ::  sds
   real                ::  x(10,20)
   x = 0.0
   call Init( hdf, 'test.hdf', 'create', status )
   call Init( sds, hdf, 'aaa', shape(x), 'real(4)', status )
   call SetDim( sds, 0, 'lon', 'deg', lons, status )
   call SetDim( sds, 1, 'lat', 'deg', lats, status )
   call Compress( sds, 'deflate', status, deflate_level=6 )
   call WriteData( sds, x, status )
   call Done( sds, status )
   call Done( hdf, status )

Source files

   configure            : script to generate source files and Makefile

   file_hdf_base.f90    : definition of types, basic routines

   file_hdf_iwp.F90.in  : template for routines dealing with integer 
                          variables of different kinds in files named:
                            file_hdf_i4.f90
                            file_hdf_i8.f90
                          etc; the template contains keys '<wp>' that are
                          replaced by '4', '8' etc via a sed command in
                          the makefile

   file_hdf_rwp.F90.in  : template for routines dealing with real
                          variables of different kinds

   file_hdf_l.f90       : routines dealing with logical variables

   file_hdf_s.f90       : routines dealing with charcter string variables

   file_hdf.f90.in      : Template for the main module that collects all other;
                          comments '!i<wp>!' etc are removed if the
                          corresponding kind specific modules are generated
                          Also contains types and routines for time series.

See also




next_inactive up previous
TM5 2009-03-03