!----------------------------------------------------------------------
! NEMO system team, System and Interface for oceanic RElocable Nesting
!----------------------------------------------------------------------
!
! MODULE: iom_cdf
!
! DESCRIPTION:
!> @brief
!> This module is a library to read/write Netcdf file.
!>
!> @details
!>
!> to open netcdf file:
!> CALL iom_cdf_open(td_file)
!> - td_file is file structure (see file.f90)
!>
!> to write in netcdf file:
!> CALL iom_cdf_write_file(td_file)
!>
!> to close netcdf file:
!> CALL iom_cdf_close(tl_file)
!>
!> to read one dimension in netcdf file:
!> tl_dim = iom_cdf_read_dim(tl_file, id_dimid)
!> or
!> tl_dim = iom_cdf_read_dim(tl_file, cd_name)
!> - id_dimid is dimension id
!> - cd_name is dimension name
!>
!> to read one global attribute in netcdf file:
!> tl_att = iom_cdf_read_att(tl_file, id_varid, id_attid)
!> or
!> tl_att = iom_cdf_read_att(tl_file, id_varid, cd_name)
!> - id_varid is variable id
!> - id_attid is attribute id
!> - cd_name is attribute name
!>
!> to read one variable in netcdf file:
!> tl_var = iom_cdf_read_var(td_file, id_varid, [id_start, id_count])
!> or
!> tl_var = iom_cdf_read_var(td_file, cd_name, [id_start, [id_count,]] [cd_stdname])
!> - id_varid is variabale id
!> - cd_name is variabale name
!> - id_start is a integer(4) 1D table of index from which the data
!> values will be read (optional)
!> - id_count is a integer(4) 1D table of the number of indices selected
!> along each dimension (optional)
!> - cd_stdname is variable standard name (optional)
!>
!> @author
!> J.Paul
! REVISION HISTORY:
!> @date Nov, 2013 - Initial Version
!
!> @param MyModule_type : brief_description
!
!> @note Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
!
!> @todo
!> - inform variable pni, pnj, pnij, area, iglo, jglo
!> - use var_init when read new variable
!> - use dim_init when read new dimension
!> - use att_init when read new attribute
!> - add read td_dom
!> @todo
!> - voir si il ne faut pas redefinir (__copy) variable si elle vient de mpp
!> exemple CALL mpp_move_var( td_mpp, td_mpp%t_var )
!----------------------------------------------------------------------
MODULE iom_cdf
USE netcdf ! nf90 library
USE global ! global parameter
USE kind ! F90 kind parameter
USE fct ! basic useful function
USE logger ! log file manager
USE att ! attribute manage
USE dim ! dimension manager
USE var ! variable manager
USE file ! file manager
USE dom ! domain manager
! USE proc ! processor manager
IMPLICIT NONE
PRIVATE
! NOTE_avoid_public_variables_if_possible
! function and subroutine
PUBLIC :: iom_cdf_open !< open or create netcdf file, return file structure
PUBLIC :: iom_cdf_close !< close netcdf file
PUBLIC :: iom_cdf_read_dim !< read one dimension in an opened netcdf file, return dimension structure
PUBLIC :: iom_cdf_read_att !< read one attribute in an opened netcdf file, return attribute structure
PUBLIC :: iom_cdf_read_var !< read one variable in an opened netcdf file, return variable structure
PUBLIC :: iom_cdf_fill_var !< fill variable value in an opened netcdf file
PUBLIC :: iom_cdf_write_file !< write file structure contents in an opened netcdf file
! PUBLIC :: iom_cdf_get_mpp ! get sub domain decomposition in a netcdf file
PRIVATE :: iom_cdf__check !< provides a simple interface to netcdf error message
PRIVATE :: iom_cdf__get_info !< get global information in an opened netcdf file
PRIVATE :: iom_cdf__get_file_dim !< read dimension on an opened netcdf file, and reorder it
PRIVATE :: iom_cdf__get_file_att !< read global attribute on an opened netcdf file
PRIVATE :: iom_cdf__get_file_var !< read information about variable on an opened netcdf file
PRIVATE :: iom_cdf__read_dim_id !< read one dimension in an opened netcdf file, given dimension id.
PRIVATE :: iom_cdf__read_dim_name !< read one dimension in an opened netcdf file, given dimension name.
PRIVATE :: iom_cdf__read_att_name !< read variable or global attribute in an opened netcdf file, given attribute name.
PRIVATE :: iom_cdf__read_att_id !< read variable or global attribute in an opened netcdf file, given attribute id.
PRIVATE :: iom_cdf__read_var_id !< read variable value in an opened netcdf file, given variable id.
PRIVATE :: iom_cdf__read_var_name !< read variable value in an opened netcdf file, given variable name or standard name.
PRIVATE :: iom_cdf__read_var_meta !< read metadata of a variable in an opened netcdf file.
PRIVATE :: iom_cdf__read_var_dim !< read variable dimension in an opened netcdf file.
PRIVATE :: iom_cdf__read_var_att !< read variable attributes in an opened netcdf file.
PRIVATE :: iom_cdf__read_var_value !< read variable value in an opened netcdf file.
PRIVATE :: iom_cdf__write_dim !< write one dimension in an opened netcdf file in write mode.
PRIVATE :: iom_cdf__write_att !< write a variable attribute in an opened netcdf file.
PRIVATE :: iom_cdf__write_var !< write a variable in an opened netcdf file.
PRIVATE :: iom_cdf__write_var_def !< define variable in an opened netcdf file.
PRIVATE :: iom_cdf__write_var_value !< put variable value in an opened netcdf file.
PRIVATE :: iom_cdf__fill_var_id !< fill variable value in an opened netcdf file, given variable id
PRIVATE :: iom_cdf__fill_var_name !< fill variable value in an opened netcdf file, given variable name
PRIVATE :: iom_cdf__fill_var_all !< fill all variable value in an opened netcdf file
PRIVATE :: iom_cdf__del_var_dim !< remove variable dimension from an opened netcdf file
INTERFACE iom_cdf_read_var
MODULE PROCEDURE iom_cdf__read_var_id
MODULE PROCEDURE iom_cdf__read_var_name
END INTERFACE iom_cdf_read_var
INTERFACE iom_cdf_fill_var
MODULE PROCEDURE iom_cdf__fill_var_id
MODULE PROCEDURE iom_cdf__fill_var_name
MODULE PROCEDURE iom_cdf__fill_var_all
END INTERFACE iom_cdf_fill_var
INTERFACE iom_cdf_read_dim
MODULE PROCEDURE iom_cdf__read_dim_id
MODULE PROCEDURE iom_cdf__read_dim_name
END INTERFACE iom_cdf_read_dim
INTERFACE iom_cdf_read_att
MODULE PROCEDURE iom_cdf__read_att_id
MODULE PROCEDURE iom_cdf__read_att_name
END INTERFACE iom_cdf_read_att
CONTAINS
!-------------------------------------------------------------------
!> @brief This subroutine provides a simple interface to
!> netcdf error message
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] id_status : error status
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__check(id_status)
IMPLICIT NONE
! Argument
INTEGER(i4), INTENT(IN) :: id_status
!----------------------------------------------------------------
IF( id_status /= NF90_NOERR )THEN
CALL logger_error(TRIM(NF90_STRERROR(id_status)))
ENDIF
END SUBROUTINE iom_cdf__check
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine open a netcdf file in read or write mode
!> if try to open a file in write mode that did not exist, create it.
!> if file already exist, get information about:
!> - the number of variables
!> - the number of dimensions
!> - the number of global attributes
!> - the ID of the unlimited dimension
!> - the file format
!> and finally read dimensions.
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf_open(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
LOGICAL :: ll_exist
LOGICAL :: ll_open
INTEGER(i4) :: il_status
TYPE(TVAR) :: tl_lon
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check file existence
INQUIRE(FILE=TRIM(td_file%c_name), EXIST=ll_exist, OPENED=ll_open)
! ll_open do not work for netcdf file, always return FALSE
IF( .NOT. ll_exist .OR. TRIM(td_file%c_type) /= 'cdf' )THEN
IF( .NOT. td_file%l_wrt )THEN
CALL logger_fatal( " OPEN: can not open file "//&
& TRIM(td_file%c_name) )
td_file%i_id=-1
ELSE
CALL logger_info( " CREATE: file "//TRIM(td_file%c_name) )
il_status = NF90_CREATE( TRIM(td_file%c_name),&
& NF90_WRITE, &
& td_file%i_id)
CALL iom_cdf__check(il_status)
td_file%l_def=.TRUE.
ENDIF
ELSE
IF( td_file%i_id /= 0 )THEN
CALL logger_error( " OPEN: file "//&
& TRIM(td_file%c_name)//" already opened")
ELSE
IF( .NOT. td_file%l_wrt )THEN
CALL logger_info( " OPEN: file "//&
& TRIM(td_file%c_name)//" in read only mode" )
il_status = NF90_OPEN( TRIM(td_file%c_name), &
& NF90_NOWRITE, &
& td_file%i_id)
CALL iom_cdf__check(il_status)
CALL logger_debug("OPEN "//TRIM(td_file%c_name)//" "//TRIM(fct_str(td_file%i_id)))
ELSE
CALL logger_info( " OPEN: file "//&
& TRIM(td_file%c_name)//" in write mode" )
il_status = NF90_OPEN( TRIM(td_file%c_name), &
& NF90_WRITE, &
& td_file%i_id)
CALL iom_cdf__check(il_status)
ENDIF
! get general information about file
CALL iom_cdf__get_info(td_file)
! read dimension in file
CALL iom_cdf__get_file_dim(td_file)
! read global attribute in file
CALL iom_cdf__get_file_att(td_file)
! get information about variables in file
CALL iom_cdf__get_file_var(td_file)
! get ew overlap
tl_lon=iom_cdf_read_var(td_file,'longitude')
td_file%i_ew=dom_get_ew_overlap(tl_lon)
CALL logger_debug(" IOM OPEN EW "//TRIM(fct_str(td_file%i_ew)) )
WHERE( td_file%t_var(:)%t_dim(1)%l_use )
td_file%t_var(:)%i_ew=td_file%i_ew
END WHERE
CALL var_clean(tl_lon)
DO ji=1,td_file%i_nvar
CALL logger_debug(TRIM(td_file%t_var(ji)%c_name)//": "//TRIM(fct_str(td_file%t_var(ji)%i_ew)) )
ENDDO
! remove dimension variable from list of variable
CALL iom_cdf__del_var_dim(td_file)
ENDIF
ENDIF
END SUBROUTINE iom_cdf_open
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine close netcdf file
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf_close(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
INTEGER(i4) :: il_status
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " CLOSE: no id associated to file "//TRIM(td_file%c_name))
ELSE
CALL logger_info( &
& " CLOSE: file "//TRIM(td_file%c_name))
il_status = NF90_CLOSE(td_file%i_id)
CALL iom_cdf__check(il_status)
td_file%i_id = 0
ENDIF
END SUBROUTINE iom_cdf_close
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine get global information in an opened netcdf
!> file.
!> @details
!> It gets the number of variables, the number of dimensions,
!> the number of global attributes, the ID of the unlimited dimension
!> and finally the format version and filled file strucuture with it.
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @return file structure completed
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__get_info(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
INTEGER(i4) :: il_fmt ! format version
INTEGER(i4) :: il_status
!----------------------------------------------------------------
CALL logger_trace( &
& " GET INFO: about netcdf file "//TRIM(td_file%c_name))
il_status=NF90_INQUIRE(td_file%i_id, td_file%i_ndim, &
& td_file%i_nvar, td_file%i_natt, td_file%i_uldid, il_fmt)
CALL iom_cdf__check(il_status)
SELECT CASE(il_fmt)
CASE(nf90_format_classic, nf90_format_64bit)
td_file%c_type='cdf'
CASE(nf90_format_netcdf4, nf90_format_netcdf4_classic)
td_file%c_type='cdf4'
END SELECT
! record header infos
td_file%i_rhd=1
END SUBROUTINE iom_cdf__get_info
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read dimension on an opened netcdf file, and
!> reorder dimension to ('x', 'y', 'z', 't').
!> The dimension structure inside file structure is then completed.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @return file structure completed
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__get_file_dim(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! clean dimension
DO ji=1,ip_maxdim
CALL dim_clean(td_file%t_dim(ji))
ENDDO
IF( td_file%i_ndim > 0 )THEN
DO ji = 1, td_file%i_ndim
! read dimension information
td_file%t_dim(ji)=iom_cdf_read_dim( td_file, ji)
ENDDO
! inform unlimited dimension
IF( td_file%i_uldid == -1 )THEN
CALL logger_warn( &
& " GET FILE DIM: there is no unlimited dimension in file "//&
& TRIM(td_file%c_name))
ELSE
td_file%t_dim( td_file%i_uldid )%l_uld=.TRUE.
ENDIF
ELSE
CALL logger_warn( &
& " GET FILE DIM: there is no dimension in file "//&
& TRIM(td_file%c_name))
ENDIF
! reorder dimension to ('x','y','z','t')
CALL dim_reorder(td_file%t_dim(:))
END SUBROUTINE iom_cdf__get_file_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read global attribute on an opened netcdf
!> file.
!> The attribute structure inside file structure is then completed.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @return file structure completed
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__get_file_att(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
IF( td_file%i_natt > 0 )THEN
IF(ASSOCIATED(td_file%t_att))THEN
DEALLOCATE(td_file%t_att)
ENDIF
ALLOCATE(td_file%t_att(td_file%i_natt))
DO ji = 1, td_file%i_natt
! read global attribute
td_file%t_att(ji)=iom_cdf_read_att( td_file, NF90_GLOBAL, ji)
SELECT CASE(TRIM(td_file%t_att(ji)%c_name))
CASE('periodicity')
td_file%i_perio=INT(td_file%t_att(ji)%d_value(1),i4)
CASE('pivot_point')
td_file%i_pivot=INT(td_file%t_att(ji)%d_value(1),i4)
CASE('ew_overlap')
td_file%i_ew=INT(td_file%t_att(ji)%d_value(1),i4)
END SELECT
ENDDO
ELSE
CALL logger_debug( &
& " GET FILE ATT: there is no global attribute in file "//&
& TRIM(td_file%c_name))
ENDIF
END SUBROUTINE iom_cdf__get_file_att
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read information about variable of an
!> opened netcdf file.
!> The variable structure inside file structure is then completed.
!> @note variable value are not read !
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @return file structure completed
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__get_file_var(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
INTEGER(i4) :: il_attid
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
IF( td_file%i_nvar > 0 )THEN
IF(ASSOCIATED(td_file%t_var))THEN
DEALLOCATE(td_file%t_var)
ENDIF
ALLOCATE(td_file%t_var(td_file%i_nvar))
DO ji = 1, td_file%i_nvar
! read dimension information
td_file%t_var(ji)=iom_cdf__read_var_meta( td_file, ji)
SELECT CASE(td_file%t_var(ji)%i_ndim)
CASE(0)
td_file%i_n0d=td_file%i_n0d+1
CASE(1)
td_file%i_n1d=td_file%i_n1d+1
td_file%i_rhd=td_file%i_rhd+1
CASE(2)
td_file%i_n2d=td_file%i_n2d+1
td_file%i_rhd=td_file%i_rhd+1
CASE(3)
td_file%i_n3d=td_file%i_n3d+1
td_file%i_rhd=td_file%i_rhd+td_file%t_dim(3)%i_len
END SELECT
! look for depth id
IF( INDEX(TRIM(td_file%t_var(ji)%c_name),'depth') /= 0 )THEN
IF( td_file%i_depthid == 0 )THEN
td_file%i_depthid=ji
ELSE
CALL logger_error("IOM OPEN: find more than one "//&
& "depth variable in file "//&
& TRIM(td_file%c_name) )
ENDIF
ENDIF
! look for time id
IF( INDEX(TRIM(td_file%t_var(ji)%c_name),'time') /= 0 )THEN
IF( td_file%i_timeid == 0 )THEN
td_file%i_timeid=ji
ELSE
il_attid=0
IF( ASSOCIATED(td_file%t_var(ji)%t_att) )THEN
il_attid=att_get_id(td_file%t_var(ji)%t_att(:),'calendar')
ENDIF
IF( il_attid /= 0 )THEN
td_file%i_timeid=ji
!ELSE
! print *,'error'
! CALL logger_error("IOM OPEN: find more than one "//&
! & "time variable in file "//&
! & TRIM(td_file%c_name) )
ENDIF
ENDIF
ENDIF
ENDDO
ELSE
CALL logger_debug( &
& " GET FILE VAR: there is no variable in file "//&
& TRIM(td_file%c_name))
ENDIF
END SUBROUTINE iom_cdf__get_file_var
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine delete variable dimension from an
!> opened netcdf file.
!
!> @author J.Paul
!> - 2013- Initial Version
!
!> @param[inout] td_file : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__del_var_dim(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
CHARACTER(LEN=lc) :: cl_name
CHARACTER(LEN=lc) :: cl_sname
! loop indices
INTEGER(i4) :: ji
INTEGER(i4) :: jj
!----------------------------------------------------------------
IF( td_file%i_nvar > 0 )THEN
DO ji=td_file%i_nvar,1,-1
cl_name=TRIM(td_file%t_var(ji)%c_name)
DO jj=1,ip_maxdim
IF( td_file%t_dim(jj)%l_use )THEN
cl_sname=fct_upper(td_file%t_dim(jj)%c_sname)
IF( TRIM(cl_name) == TRIM(cl_sname) )THEN
CALL file_del_var(td_file,TRIM(cl_name))
EXIT
ENDIF
ENDIF
ENDDO
ENDDO
ELSE
CALL logger_debug( &
& " DEL VAR DIM: there is no variable in file "//&
& TRIM(td_file%c_name))
ENDIF
END SUBROUTINE iom_cdf__del_var_dim
!> @endcode
! !-------------------------------------------------------------------
! !> @brief This subroutine get variable time from an
! !> opened netcdf file.
! !
! !> @author J.Paul
! !> - 2013- Initial Version
! !
! !> @param[inout] td_file : file structure
! !-------------------------------------------------------------------
! !> @code
! SUBROUTINE iom_cdf__get_var_time(td_file)
! IMPLICIT NONE
! ! Argument
! TYPE(TFILE), INTENT(INOUT) :: td_file
!
! ! local variable
! CHARACTER(LEN=lc) :: cl_name
!
! ! loop indices
! INTEGER(i4) :: ji
! !----------------------------------------------------------------
! IF( td_file%i_nvar > 0 )THEN
! DO ji=1,td_file%i_nvar
! cl_name=TRIM(td_file%t_var(ji)%c_name)
! IF( INDEX(cl_name,'time') /= 0 )THEN
! ! read time variable
! td_file%t_time=iom_cdf_read_var(td_file,ji)
! ! remove time variable from variable list
! CALL file_del_ver(td_file,TRIM(cl_name))
! EXIT
! ENDIF
! ENDDO
! ELSE
! CALL logger_debug( &
! & " GET VAR TIME: there is no variable in file "//&
! & TRIM(td_file%c_name))
! ENDIF
! END SUBROUTINE iom_cdf__get_var_time
! !> @endcode
! !-------------------------------------------------------------------
! !> @brief This subroutine get variable depth from an
! !> opened netcdf file.
! !
! !> @author J.Paul
! !> - 2013- Initial Version
! !
! !> @param[inout] td_file : file structure
! !-------------------------------------------------------------------
! !> @code
! SUBROUTINE iom_cdf__get_var_depth(td_file)
! IMPLICIT NONE
! ! Argument
! TYPE(TFILE), INTENT(INOUT) :: td_file
!
! ! local variable
! CHARACTER(LEN=lc) :: cl_name
!
! ! loop indices
! INTEGER(i4) :: ji
! !----------------------------------------------------------------
! IF( td_file%i_nvar > 0 )THEN
! DO ji=1,td_file%i_nvar
! cl_name=TRIM(td_file%t_var(ji)%c_name)
! IF( INDEX(cl_name,'depth') /= 0 )THEN
! ! read depth variable
! td_file%t_depth=iom_cdf_read_var(td_file,ji)
! ! remove depth variable from variable list
! CALL file_del_ver(td_file,TRIM(cl_name))
! EXIT
! ENDIF
! ENDDO
! ELSE
! CALL logger_debug( &
! & " GET VAR TIME: there is no variable in file "//&
! & TRIM(td_file%c_name))
! ENDIF
! END SUBROUTINE iom_cdf__get_var_depth
! !> @endcode
!-------------------------------------------------------------------
!> @brief This function read one dimension in an opened netcdf file,
!> given dimension id.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] id_dimid : dimension id
!> @return dimension structure
!-------------------------------------------------------------------
!> @code
TYPE(TDIM) FUNCTION iom_cdf__read_dim_id(td_file, id_dimid)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_dimid
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_len
CHARACTER(LEN=lc) :: cl_name
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " READ DIM: no id associated to file "//TRIM(td_file%c_name))
ELSE
iom_cdf__read_dim_id%i_id=id_dimid
CALL logger_debug( &
& " READ DIM: dimension "//TRIM(fct_str(id_dimid))//&
& " in file "//TRIM(td_file%c_name))
il_status=NF90_INQUIRE_DIMENSION(td_file%i_id, id_dimid, &
& cl_name, il_len )
CALL iom_cdf__check(il_status)
iom_cdf__read_dim_id=dim_init(cl_name, il_len)
ENDIF
END FUNCTION iom_cdf__read_dim_id
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read one dimension in an opened netcdf file,
!> given dimension name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] cd_name : dimension name
!> @return dimension structure
!-------------------------------------------------------------------
!> @code
TYPE(TDIM) FUNCTION iom_cdf__read_dim_name(td_file, cd_name)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
CHARACTER(LEN=*), INTENT(IN) :: cd_name
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_dimid
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " READ DIM: no id associated to file "//TRIM(td_file%c_name))
ELSE
il_status=NF90_INQ_DIMID( td_file%i_id, TRIM(ADJUSTL(cd_name)), &
& il_dimid)
CALL iom_cdf__check(il_status)
iom_cdf__read_dim_name=iom_cdf_read_dim(td_file, il_dimid)
ENDIF
END FUNCTION iom_cdf__read_dim_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read variable or global attribute in an opened
!> netcdf file, given attribute name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] id_varid : variable id. use NF90_GLOBAL to read global
!> attribute in a file
!> @param[in] cd_name : attribute name
!> @return attribute structure
!-------------------------------------------------------------------
!> @code
TYPE(TATT) FUNCTION iom_cdf__read_att_name(td_file, id_varid, cd_name)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
CHARACTER(LEN=*), INTENT(IN) :: cd_name
! local variable
CHARACTER(LEN=lc) :: cl_name
INTEGER(i4) :: il_status
INTEGER(i4) :: il_attid
INTEGER(i4) :: il_type
INTEGER(i4) :: il_len
CHARACTER(LEN=lc) :: cl_value
INTEGER(i1), DIMENSION(:), ALLOCATABLE :: bl_value
INTEGER(i2), DIMENSION(:), ALLOCATABLE :: sl_value
INTEGER(i4), DIMENSION(:), ALLOCATABLE :: il_value
REAL(sp) , DIMENSION(:), ALLOCATABLE :: fl_value
REAL(dp) , DIMENSION(:), ALLOCATABLE :: dl_value
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " READ ATT: no id associated to file "//TRIM(td_file%c_name))
ELSE
cl_name=TRIM(ADJUSTL(cd_name))
! inquire attribute
IF( id_varid == NF90_GLOBAL )THEN
CALL logger_debug( &
& " READ ATT: inquire global attribute "//&
& " in file "//TRIM(td_file%c_name))
ELSE
CALL logger_debug( &
& " READ ATT: inquire attribute "//&
& " of variable "//TRIM(fct_str(id_varid))//&
& " in file "//TRIM(td_file%c_name))
ENDIF
il_status=NF90_INQUIRE_ATTRIBUTE(td_file%i_id, id_varid, &
& cl_name,&
& il_type,&
& il_len, &
& il_attid )
CALL iom_cdf__check(il_status)
!! get attribute value
CALL logger_debug( " READ ATT: get attribute "//TRIM(cl_name)//&
& " in file "//TRIM(td_file%c_name))
SELECT CASE( il_type )
CASE(NF90_CHAR)
! check string lengths
IF( LEN(cl_value) < il_len )THEN
CALL logger_error( &
& " READ ATT: not enough space to put attribute "//&
& TRIM(cl_name) )
ELSE
! Read the attributes
il_status=NF90_GET_ATT(td_file%i_id, id_varid, &
& cl_name, &
& cl_value )
CALL iom_cdf__check(il_status)
iom_cdf__read_att_name=att_init(cl_name, cl_value)
ENDIF
CASE(NF90_BYTE)
ALLOCATE( bl_value( il_len), &
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " READ ATT: not enough space to put attribute "//&
& TRIM(cl_name) )
ELSE
! Read the attributes
il_status=NF90_GET_ATT(td_file%i_id, id_varid, &
& cl_name, &
& bl_value(:))
CALL iom_cdf__check(il_status)
iom_cdf__read_att_name=att_init(cl_name, bl_value(:))
ENDIF
DEALLOCATE(bl_value)
CASE(NF90_SHORT)
ALLOCATE( sl_value( il_len), &
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " READ ATT: not enough space to put attribute "//&
& TRIM(cl_name) )
ELSE
! Read the attributes
il_status=NF90_GET_ATT(td_file%i_id, id_varid, &
& cl_name, &
& sl_value(:))
CALL iom_cdf__check(il_status)
iom_cdf__read_att_name=att_init(cl_name, sl_value(:))
ENDIF
DEALLOCATE(sl_value)
CASE(NF90_INT)
ALLOCATE( il_value( il_len), &
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " READ ATT: not enough space to put attribute "//&
& TRIM(cl_name) )
ELSE
! Read the attributes
il_status=NF90_GET_ATT(td_file%i_id, id_varid, &
& cl_name, &
& il_value(:))
CALL iom_cdf__check(il_status)
iom_cdf__read_att_name=att_init(cl_name, il_value(:))
ENDIF
DEALLOCATE(il_value)
CASE(NF90_FLOAT)
ALLOCATE( fl_value( il_len), &
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " READ ATT: not enough space to put attribute "//&
& TRIM(cl_name) )
ELSE
! Read the attributes
il_status=NF90_GET_ATT(td_file%i_id, id_varid, &
& cl_name, &
& fl_value(:))
CALL iom_cdf__check(il_status)
iom_cdf__read_att_name=att_init(cl_name, fl_value(:))
ENDIF
DEALLOCATE(fl_value)
CASE(NF90_DOUBLE)
ALLOCATE( dl_value( il_len), &
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " READ ATT: not enough space to put attribute "//&
& TRIM(cl_name) )
ELSE
! Read the attributes
il_status=NF90_GET_ATT(td_file%i_id, id_varid, &
& cl_name, &
& dl_value(:))
CALL iom_cdf__check(il_status)
iom_cdf__read_att_name=att_init(cl_name, dl_value(:))
ENDIF
DEALLOCATE(dl_value)
END SELECT
iom_cdf__read_att_name%i_id=il_attid
ENDIF
END FUNCTION iom_cdf__read_att_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read variable or global attribute in an opened
!> netcdf file, given attribute id.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] id_varid : variable id. use NF90_GLOBAL to read global
!> attribute in a file
!> @param[in] id_attid : attribute id
!> @return attribute structure
!-------------------------------------------------------------------
!> @code
TYPE(TATT) FUNCTION iom_cdf__read_att_id(td_file, id_varid, id_attid)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
INTEGER(i4), INTENT(IN) :: id_attid
! local variable
INTEGER(i4) :: il_status
CHARACTER(LEN=lc) :: cl_name
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " READ ATT: no id associated to file "//TRIM(td_file%c_name))
ELSE
! get attribute name
il_status=NF90_INQ_ATTNAME(td_file%i_id, id_varid, id_attid, cl_name)
CALL iom_cdf__check(il_status)
! read attribute
iom_cdf__read_att_id=iom_cdf__read_att_name(td_file, id_varid, cl_name)
ENDIF
END FUNCTION iom_cdf__read_att_id
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read variable value in an opened
!> netcdf file, given variable id.
!> start indices and number of indices selected along each dimension
!> could be specify in a 4 dimension table (/'x','y','z','t'/)
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] id_varid : variable id
!> @param[in] id_start : index in the variable from which the data values
!> will be read
!> @param[in] id_count : number of indices selected along each dimension
!> @return variable structure
!-------------------------------------------------------------------
!> @code
TYPE(TVAR) FUNCTION iom_cdf__read_var_id(td_file, id_varid,&
& id_start, id_count)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_start
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_count
! local variable
INTEGER(i4), DIMENSION(1) :: il_ind
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " IOM READ VAR: no id associated to file "//TRIM(td_file%c_name))
ELSE
! look for variable id
il_ind(:)=MINLOC(td_file%t_var(:)%i_id,mask=(td_file%t_var(:)%i_id==id_varid))
IF( il_ind(1) /= 0 )THEN
iom_cdf__read_var_id=td_file%t_var(il_ind(1))
print *,"iom_cdf__read_var_id ",trim(iom_cdf__read_var_id%c_name)," ",iom_cdf__read_var_id%i_ew
!!! read variable value
CALL iom_cdf__read_var_value(td_file, iom_cdf__read_var_id, &
& id_start, id_count)
ELSE
print *,"iom_cdf__read_var_id "
CALL logger_error( &
& " IOM READ VAR: there is no variable with id "//&
& TRIM(fct_str(id_varid))//" in file "//TRIM(td_file%c_name))
ENDIF
ENDIF
END FUNCTION iom_cdf__read_var_id
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read variable value in an opened
!> netcdf file, given variable name or standard name.
!> start indices and number of indices selected along each dimension
!> could be specify in a 4 dimension table (/'x','y','z','t'/)
!
!> @details
!> look first for variable name. If it doesn't
!> exist in file, look for variable standard name.
!> If variable name is not present, check variable standard name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] cd_name : variable name
!> @param[in] id_start : index in the variable from which the data values will be read
!> @param[in] id_count : number of indices selected along each dimension
!> @param[in] cd_stdname : variable standard name
!> @return variable structure
!-------------------------------------------------------------------
!> @code
TYPE(TVAR) FUNCTION iom_cdf__read_var_name(td_file, cd_name, &
& id_start, id_count )
IMPLICIT NONE
! Argument
TYPE(TFILE) , INTENT(IN) :: td_file
CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cd_name
INTEGER(i4) , DIMENSION(:), INTENT(IN), OPTIONAL :: id_start
INTEGER(i4) , DIMENSION(:), INTENT(IN), OPTIONAL :: id_count
! local variable
INTEGER(i4) :: il_ind
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " IOM READ VAR: no id associated to file "//TRIM(td_file%c_name))
ELSE
IF( .NOT. PRESENT(cd_name) )THEN
CALL logger_error( &
& " IOM READ VAR: you must specify a variable to read "//&
& " in file "//TRIM(td_file%c_name))
ELSE
il_ind=var_get_id(td_file%t_var(:), cd_name)
IF( il_ind /= 0 )THEN
iom_cdf__read_var_name=td_file%t_var(il_ind)
!!! read variable value
CALL iom_cdf__read_var_value( td_file, &
& iom_cdf__read_var_name, &
& id_start, id_count)
ELSE
CALL logger_error( &
& " IOM READ VAR: there is no variable with "//&
& " name or standard name "//TRIM(cd_name)//&
& " in file "//TRIM(td_file%c_name) )
ENDIF
ENDIF
ENDIF
END FUNCTION iom_cdf__read_var_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine fill variable value in an opened
!> netcdf file, given variable id.
!> start indices and number of indices selected along each dimension
!> could be specify in a 4 dimension table (/'x','y','z','t'/)
!
!> @note ne peut pas marcher qd on fait boucle sur les variable d'un
!> fichier. puisque change id.
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] id_start : index in the variable from which the data values
!> will be read
!> @param[in] id_count : number of indices selected along each dimension
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__fill_var_all(td_file, id_start, id_count)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
INTEGER(i4), DIMENSION(:), INTENT(IN ), OPTIONAL :: id_start
INTEGER(i4), DIMENSION(:), INTENT(IN ), OPTIONAL :: id_count
! local variable
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " FILL VAR: no id associated to file "//TRIM(td_file%c_name))
ELSE
DO ji=1,td_file%i_nvar
CALL iom_cdf_fill_var(td_file, ji, id_start, id_count)
ENDDO
ENDIF
END SUBROUTINE iom_cdf__fill_var_all
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine fill variable value in an opened
!> netcdf file, given variable id.
!> start indices and number of indices selected along each dimension
!> could be specify in a 4 dimension table (/'x','y','z','t'/)
!
!> @note ne peut pas marcher qd on fait boucle sur les variable d'un
!> fichier. puisque change id.
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] id_varid : variable id
!> @param[in] id_start : index in the variable from which the data values
!> will be read
!> @param[in] id_count : number of indices selected along each dimension
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__fill_var_id(td_file, id_varid, id_start, id_count)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_start
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_count
! local variable
INTEGER(i4), DIMENSION(1) :: il_ind
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " FILL VAR: no id associated to file "//TRIM(td_file%c_name))
ELSE
! look for variable id
il_ind(:)=MINLOC( td_file%t_var(:)%i_id, &
& mask=(td_file%t_var(:)%i_id==id_varid))
IF( il_ind(1) /= 0 )THEN
!!! read variable value
CALL iom_cdf__read_var_value(td_file, td_file%t_var(il_ind(1)), &
& id_start, id_count)
DO ji=1,td_file%i_nvar
CALL logger_debug(" var id "//TRIM(td_file%t_var(ji)%c_name)//" "//TRIM(fct_str(td_file%t_var(ji)%i_id)) )
ENDDO
ELSE
CALL logger_error( &
& " FILL VAR: there is no variable with id "//&
& TRIM(fct_str(id_varid))//" in file "//TRIM(td_file%c_name))
ENDIF
ENDIF
END SUBROUTINE iom_cdf__fill_var_id
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine fill variable value in an opened
!> netcdf file, given variable name or standard name.
!> start indices and number of indices selected along each dimension
!> could be specify in a 4 dimension table (/'x','y','z','t'/)
!
!> @details
!> look first for variable name. If it doesn't
!> exist in file, look for variable standard name.
!> If variable name is not present, check variable standard name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] cd_name : variable name or standard name
!> @param[in] id_start : index in the variable from which the data values will be read
!> @param[in] id_count : number of indices selected along each dimension
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__fill_var_name(td_file, cd_name, id_start, id_count )
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
CHARACTER(LEN=*), INTENT(IN) :: cd_name
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_start
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_count
! local variable
INTEGER(i4) :: il_ind
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " FILL VAR: no id associated to file "//TRIM(td_file%c_name))
ELSE
il_ind=var_get_id(td_file%t_var(:), cd_name)
IF( il_ind /= 0 )THEN
!!! read variable value
CALL iom_cdf__read_var_value(td_file, td_file%t_var(il_ind), &
& id_start, id_count)
ELSE
CALL logger_error( &
& " FILL VAR: there is no variable with "//&
& "name or standard name"//TRIM(cd_name)//&
& " in file "//TRIM(td_file%c_name))
ENDIF
ENDIF
END SUBROUTINE iom_cdf__fill_var_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read metadata of a variable in an opened
!> netcdf file.
!
!> @note variable value are not read
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] id_fileid : file id
!> @param[in] id_varid : variable id
!> @return variable structure
!-------------------------------------------------------------------
!> @code
TYPE(TVAR) FUNCTION iom_cdf__read_var_meta(td_file, id_varid)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
! local variable
CHARACTER(LEN=lc) :: cl_name
INTEGER(i4) :: il_status
INTEGER(i4) :: il_type
INTEGER(i4) :: il_ndim
INTEGER(i4) :: il_natt
INTEGER(i4) :: il_attid
INTEGER(i4), DIMENSION(NF90_MAX_VAR_DIMS) :: il_dimid
TYPE(TDIM) , DIMENSION(ip_maxdim) :: tl_dim
TYPE(TATT) :: tl_fill
TYPE(TATT) , DIMENSION(:) , ALLOCATABLE :: tl_att
TYPE(TATT) , DIMENSION(:) , ALLOCATABLE :: tl_tmp
! loop indices
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " READ ATT: no id associated to file "//TRIM(td_file%c_name))
ELSE
! inquire variable
CALL logger_trace( &
& " READ VAR: inquire variable "//TRIM(fct_str(id_varid))//&
& " in file "//TRIM(td_file%c_name))
il_dimid(:)=0
il_status=NF90_INQUIRE_VARIABLE( td_file%i_id, id_varid, &
& cl_name, &
& il_type, &
& il_ndim, &
& il_dimid(:),&
& il_natt )
CALL iom_cdf__check(il_status)
!!! fill variable dimension structure
tl_dim(:)=iom_cdf__read_var_dim( td_file, il_ndim, il_dimid(:) )
IF( il_natt /= 0 )THEN
ALLOCATE( tl_att(il_natt) )
!!! fill variable attribute structure
tl_att(:)=iom_cdf__read_var_att(td_file, id_varid, il_natt)
!! look for _FillValue. if none add one
il_attid=att_get_id(tl_att(:),'_FillValue')
IF( il_attid == 0 )THEN
CALL logger_warn("IOM READ VAR: no _FillValue for variable "//&
& TRIM(cl_name)//" in file "//TRIM(td_file%c_name) )
il_attid=att_get_id(tl_att(:),'missing_value')
IF( il_attid /= 0 )THEN
! create attribute _FillValue
CALL logger_warn("IOM READ VAR: assume _FillValue is equal to "//&
& "missing_value for variable "//TRIM(cl_name) )
tl_fill=att_init('_FillValue',tl_att(il_attid)%d_value(:))
ELSE
! create attribute _FillValue
CALL logger_warn("IOM READ VAR: assume _FillValue is equal to "//&
& "zero for variable "//TRIM(cl_name) )
tl_fill=att_init('_FillValue',0.)
!tl_fill=att_init('_FillValue',1.e20)
ENDIF
ALLOCATE( tl_tmp(il_natt) )
! save read attribut
tl_tmp(:)=tl_att(:)
! change number of attribute in table
DEALLOCATE( tl_att )
ALLOCATE( tl_att(il_natt+1) )
! copy read attribut
tl_att(1:il_natt)=tl_tmp(:)
DEALLOCATE( tl_tmp )
! create attribute _FillValue
tl_att(il_natt+1)=tl_fill
ENDIF
ELSE
ALLOCATE(tl_att(il_natt+1) )
! create attribute _FillValue
CALL logger_warn("IOM READ VAR: assume _FillValue is equal to "//&
& "zero for variable "//TRIM(cl_name) )
tl_fill=att_init('_FillValue',0.)
! create attribute _FillValue
tl_att(il_natt+1)=tl_fill
ENDIF
!! initialize variable
iom_cdf__read_var_meta=var_init( cl_name, il_type, tl_dim(:), &
& tl_att(:), id_id=id_varid )
DEALLOCATE( tl_att )
ENDIF
END FUNCTION iom_cdf__read_var_meta
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable dimension
!> in an opened netcdf file.
!
!> @details
!> the number of dimension can't exceed 4,
!> and should be 'x', 'y', 'z', 't' (whatever their order).
!> If the number of dimension read is less than 4, the table of dimension
!> strucure is filled with unused dimension.
!> So the table of dimension structure of a variable is always compose of 4
!> dimension (use or not).
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @return file structure completed
!-------------------------------------------------------------------
!> @code
FUNCTION iom_cdf__read_var_dim(td_file, id_ndim, id_dimid)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_ndim
INTEGER(i4), DIMENSION(:), INTENT(IN) :: id_dimid
! function
TYPE(TDIM), DIMENSION(ip_maxdim) :: iom_cdf__read_var_dim
! local variable
INTEGER(i4), DIMENSION(ip_maxdim) :: il_2xyzt
TYPE(TDIM) , DIMENSION(ip_maxdim) :: tl_dim
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
IF( id_ndim == 0 )THEN
tl_dim(:)%l_use=.FALSE.
! reorder dimension to ('x','y','z','t')
CALL dim_reorder(tl_dim(:))
iom_cdf__read_var_dim(:)=tl_dim(:)
ELSE IF( id_ndim > 0 .AND. id_ndim <= 4 )THEN
DO ji = 1, id_ndim
CALL logger_debug( " READ VAR DIM: get variable dimension "//&
& TRIM(fct_str(ji)) )
il_2xyzt(ji)=td_file%t_dim(id_dimid(ji))%i_2xyzt
! read dimension information
tl_dim(ji) = dim_init( td_file%t_dim(il_2xyzt(ji))%c_name, &
& td_file%t_dim(il_2xyzt(ji))%i_len )
ENDDO
! reorder dimension to ('x','y','z','t')
CALL dim_reorder(tl_dim(:))
iom_cdf__read_var_dim(:)=tl_dim(:)
ELSE
CALL logger_error(" READ VAR DIM: can't manage "//&
& TRIM(fct_str(id_ndim))//" dimension(s)" )
ENDIF
END FUNCTION iom_cdf__read_var_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable attributes
!> in an opened netcdf file.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[inout] td_var : variable structure
!> @return filled variable attribute structure
!-------------------------------------------------------------------
!> @code
FUNCTION iom_cdf__read_var_att(td_file, id_varid, id_natt)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
INTEGER(i4), INTENT(IN) :: id_natt
! function
TYPE(TATT), DIMENSION(id_natt) :: iom_cdf__read_var_att
! local variable
TYPE(TATT), DIMENSION(id_natt) :: tl_att
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
IF( id_natt > 0 )THEN
! read attributes
DO ji = 1, id_natt
CALL logger_debug( " READ VAR ATT: get attribute "//&
& TRIM(fct_str(ji)) )
tl_att(ji)=iom_cdf_read_att(td_file, id_varid, ji)
ENDDO
iom_cdf__read_var_att(:)=tl_att(:)
ELSE
CALL logger_debug( " READ VAR ATT: no attribute for variable " )
ENDIF
END FUNCTION iom_cdf__read_var_att
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an opened netcdf file.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[inout] td_var : variable structure
!> @param[in] id_start : index in the variable from which the data values will be read
!> @param[in] id_count : number of indices selected along each dimension
!> @return variable structure completed
!
!> @todo
!> - warning do not change fill value when use scale factor..
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__read_var_value(td_file, td_var, &
& id_start, id_count )
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
TYPE(TVAR) , INTENT(INOUT) :: td_var
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_start
INTEGER(i4), DIMENSION(:), INTENT(IN), OPTIONAL :: id_count
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_tmp1, il_tmp2, il_varid
INTEGER(i4), DIMENSION(ip_maxdim) :: il_start
INTEGER(i4), DIMENSION(ip_maxdim) :: il_count
INTEGER(i4), DIMENSION(ip_maxdim) :: il_start_ord
INTEGER(i4), DIMENSION(ip_maxdim) :: il_count_ord
REAL(dp) , DIMENSION(:,:,:,:), ALLOCATABLE :: dl_value
TYPE(TDIM), DIMENSION(ip_maxdim) :: tl_dim
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check id_count and id_start optionals parameters...
IF( ( PRESENT(id_start) .AND. (.NOT. PRESENT(id_count))) .OR. &
((.NOT. PRESENT(id_start)) .AND. PRESENT(id_count) ) )THEN
CALL logger_warn( &
& " READ VAR VALUE: id_start and id_count should be both specify")
ENDIF
IF( PRESENT(id_start).AND.PRESENT(id_count) )THEN
IF( SIZE(id_start(:)) /= ip_maxdim .OR. &
& SIZE(id_count(:)) /= ip_maxdim )THEN
CALL logger_error("READ VAR: dimension of table start or count "//&
& " are invalid to read variable "//TRIM(td_var%c_name)//&
& " in file "//TRIM(td_file%c_name) )
ENDIF
! change dimension order from ('x','y','z','t')
il_start(:)=dim_reorder_xyzt2(td_var%t_dim, id_start(:))
il_count(:)=dim_reorder_xyzt2(td_var%t_dim, id_count(:))
! keep ordered table ('x','y','z','t')
il_start_ord(:)=il_start(:)
il_count_ord(:)=il_count(:)
ELSE
! change dimension order from ('x','y','z','t')
il_start(:)=(/1,1,1,1/)
il_count(:)=dim_reorder_xyzt2(td_var%t_dim(:),td_var%t_dim(:)%i_len)
! keep ordered table ('x','y','z','t')
il_start_ord(:)=(/1,1,1,1/)
il_count_ord(:)=td_var%t_dim(:)%i_len
ENDIF
! check dimension
IF( .NOT. ALL(il_start_ord(:)>=(/1,1,1,1/)) )THEN
CALL logger_error( &
&" READ VAR VALUE: start indices should be greater than or equal to 1")
ENDIF
IF(.NOT.ALL(il_start_ord(:)+il_count_ord(:)-1<=(/td_var%t_dim(1)%i_len,&
& td_var%t_dim(2)%i_len,&
& td_var%t_dim(3)%i_len,&
& td_var%t_dim(4)%i_len &
& /)) )THEN
CALL logger_error( &
& " READ VAR VALUE: start + count exceed variable dimension" )
DO ji = 1, ip_maxdim
il_tmp1=il_start_ord(ji)+il_count_ord(ji)
il_tmp2=td_var%t_dim(ji)%i_len
CALL logger_debug( &
& " READ VAR VALUE: start + count -1 "//TRIM(fct_str(il_tmp1))//&
& " variable dimension"//TRIM(fct_str(il_tmp2)))
ENDDO
ELSE
! Allocate space to hold variable value (unorder)
ALLOCATE(dl_value( il_count(1), &
& il_count(2), &
& il_count(3), &
& il_count(4)),&
& stat=il_status)
IF( il_status /= 0 )THEN
CALL logger_error( &
& " READ VAR VALUE: not enough space to put variable "//&
& TRIM(td_var%c_name))
ENDIF
! read values
CALL logger_debug( &
& " READ VAR VALUE: get variable "//TRIM(td_var%c_name)//&
& " in file "//TRIM(td_file%c_name))
CALL logger_debug("start "//TRIM(fct_str(il_start(1)))//','//&
& TRIM(fct_str(il_start(2)))//','//&
& TRIM(fct_str(il_start(3)))//','//&
& TRIM(fct_str(il_start(4)))//')' )
CALL logger_debug("count "//TRIM(fct_str(il_count(1)))//','//&
& TRIM(fct_str(il_count(2)))//','//&
& TRIM(fct_str(il_count(3)))//','//&
& TRIM(fct_str(il_count(4)))//')' )
CALL logger_debug("dim "//TRIM(fct_str(td_file%t_dim(1)%i_len))//','//&
& TRIM(fct_str(td_file%t_dim(2)%i_len))//','//&
& TRIM(fct_str(td_file%t_dim(3)%i_len))//','//&
& TRIM(fct_str(td_file%t_dim(4)%i_len))//')' )
CALL logger_debug("shape "//TRIM(fct_str(SIZE(dl_value,DIM=1)))//","//&
& TRIM(fct_str(SIZE(dl_value,DIM=2)))//","//&
& TRIM(fct_str(SIZE(dl_value,DIM=3)))//","//&
& TRIM(fct_str(SIZE(dl_value,DIM=4)))//")" )
CALL logger_debug("var "//TRIM(td_var%c_name))
il_varid=var_get_id(td_file%t_var(:),TRIM(td_var%c_name))
CALL logger_debug("var id "//TRIM(fct_str(il_varid))//' '//TRIM(fct_str(td_var%i_id)))
CALL logger_debug("file id "//TRIM(fct_str(td_file%i_id)))
il_status = NF90_GET_VAR( td_file%i_id, td_var%i_id, &
& dl_value(:,:,:,:), &
& start = il_start(:),&
& count = il_count(:) )
CALL iom_cdf__check(il_status)
! Allocate space to hold variable value in structure
IF( ASSOCIATED(td_var%d_value) )THEN
DEALLOCATE(td_var%d_value)
ENDIF
! new dimension length
td_var%t_dim(:)%i_len=il_count_ord(:)
ALLOCATE(td_var%d_value( il_count_ord(1), &
& il_count_ord(2), &
& il_count_ord(3), &
& il_count_ord(4)),&
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " READ VAR VALUE: not enough space to put variable "//&
& TRIM(td_var%c_name)//&
& " in variable structure")
ENDIF
! FillValue by default
td_var%d_value(:,:,:,:)=td_var%d_fill
! reshape values to be ordered as ('x','y','z','t')
tl_dim(:)=td_var%t_dim(:)
td_var%d_value(:,:,:,:)=dim_reshape_2xyzt(tl_dim,dl_value(:,:,:,:))
DEALLOCATE(dl_value)
! force to change _FillValue to avoid mistake
! with dummy zero _FillValue
IF( td_var%d_fill == 0._dp )THEN
CALL var_chg_FillValue(td_var)
ENDIF
ENDIF
END SUBROUTINE iom_cdf__read_var_value
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine write file structure in an opened netcdf file.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf_write_file(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
INTEGER(i4), DIMENSION(:), ALLOCATABLE :: il_value
TYPE(TVAR) :: tl_var
TYPE(TDIM), DIMENSION(ip_maxdim) :: tl_dim
! loop indices
INTEGER(i4) :: ji
INTEGER(i4) :: jj
!----------------------------------------------------------------
! check if file opened
IF( td_file%i_id == 0 )THEN
CALL logger_error( &
& " WRITE FILE: no id associated to file "//TRIM(td_file%c_name))
ELSE
IF( td_file%l_wrt )THEN
! delete dummy variable
CALL file_del_var( td_file, 'no0d' )
CALL file_del_var( td_file, 'no1d' )
CALL file_del_var( td_file, 'no2d' )
CALL file_del_var( td_file, 'no3d' )
DO ji = 1, td_file%i_nvar
CALL var_check_dim( td_file%t_var(ji) )
ENDDO
! save usefull dimension
tl_dim(:)=var_max_dim(td_file%t_var(:))
DO ji=1,ip_maxdim
IF( tl_dim(ji)%l_use ) CALL file_move_dim(td_file, tl_dim(ji))
ENDDO
! write dimension in file
DO ji = 1, ip_maxdim
IF( td_file%t_dim(ji)%l_use )THEN
CALL iom_cdf__write_dim(td_file, td_file%t_dim(ji))
! write dimension variable
ALLOCATE(il_value(td_file%t_dim(ji)%i_len))
il_value(:)=(/(jj,jj=1,td_file%t_dim(ji)%i_len)/)
tl_var=var_init( fct_upper(td_file%t_dim(ji)%c_sname), &
& il_value(:), &
& td_dim=td_file%t_dim(ji) )
DEALLOCATE(il_value)
CALL iom_cdf__write_var(td_file,tl_var)
CALL var_clean(tl_var)
ENDIF
ENDDO
! write global attibute in file
DO ji = 1, td_file%i_natt
CALL iom_cdf__write_att(td_file, NF90_GLOBAL, td_file%t_att(ji))
ENDDO
! write variable in file
DO ji = 1, td_file%i_nvar
CALL iom_cdf__write_var(td_file, td_file%t_var(ji))
ENDDO
ELSE
CALL logger_error( &
& " WRITE FILE: try to write in file "//TRIM(td_file%c_name)//&
& ", not opened in write mode")
ENDIF
ENDIF
END SUBROUTINE iom_cdf_write_file
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine write one dimension in an opened netcdf
!> file in write mode.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[inout] td_dim : dimension structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__write_dim(td_file, td_dim)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TDIM), INTENT(INOUT) :: td_dim
! local variable
INTEGER(i4) :: il_status
!----------------------------------------------------------------
IF( .NOT. td_file%l_def )THEN
CALL logger_debug( &
& " WRITE FILE DIM: Enter define mode, file "//TRIM(td_file%c_name))
! Enter define mode
il_status=NF90_REDEF(td_file%i_id)
CALL iom_cdf__check(il_status)
td_file%l_def=.TRUE.
ENDIF
IF( td_dim%l_use )THEN
IF( td_dim%l_uld )THEN
! write unlimited dimension
CALL logger_debug( &
& " WRITE FILE DIM: write unlimited dimension "//&
& TRIM(td_dim%c_name)//" in file "//TRIM(td_file%c_name))
il_status=NF90_DEF_DIM(td_file%i_id, fct_upper(td_dim%c_sname), &
& NF90_UNLIMITED, td_dim%i_id)
CALL iom_cdf__check(il_status)
ELSE
! write not unlimited dimension
CALL logger_debug( &
& " WRITE FILE DIM: write dimension "//TRIM(td_dim%c_name)//&
& " in file "//TRIM(td_file%c_name))
il_status=NF90_DEF_DIM(td_file%i_id, fct_upper(td_dim%c_sname), &
& td_dim%i_len, td_dim%i_id)
CALL iom_cdf__check(il_status)
ENDIF
ENDIF
END SUBROUTINE iom_cdf__write_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine write a variable attribute in
!> an opened netcdf file.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] id_varid : variable id. use NF90_GLOBAL to write global attribute
!> in a file
!> @param[in] td_att : attribute structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__write_att(td_file, id_varid, td_att)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
INTEGER(i4), INTENT(IN) :: id_varid
TYPE(TATT), INTENT(IN) :: td_att
! local variable
INTEGER(i4) :: il_status
!----------------------------------------------------------------
IF( .NOT. td_file%l_def )THEN
CALL logger_debug( &
& " WRITE FILE ATT: Enter define mode, file "//TRIM(td_file%c_name))
! Enter define mode
il_status=NF90_REDEF(td_file%i_id)
CALL iom_cdf__check(il_status)
td_file%l_def=.TRUE.
ENDIF
!! put attribute value
CALL logger_debug( &
& " WRITE FILE ATT: write attribute "//TRIM(td_att%c_name)//&
& " of variable "//TRIM(fct_str(id_varid))//&
& " in file "//TRIM(td_file%c_name))
SELECT CASE( td_att%i_type )
CASE(NF90_CHAR)
! put the attribute
il_status = NF90_PUT_ATT(td_file%i_id, id_varid, &
& td_att%c_name, td_att%c_value )
CALL iom_cdf__check(il_status)
CASE(NF90_BYTE, NF90_SHORT, NF90_INT, NF90_FLOAT, NF90_DOUBLE)
! put the attribute
il_status = NF90_PUT_ATT(td_file%i_id, id_varid, &
& td_att%c_name, td_att%d_value )
CALL iom_cdf__check(il_status)
END SELECT
END SUBROUTINE iom_cdf__write_att
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine write a variable in an opened netcdf file.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[inout] td_var : variable structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__write_var(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TVAR), INTENT(INOUT) :: td_var
! local variable
INTEGER(i4) :: il_status
!----------------------------------------------------------------
IF( .NOT. td_file%l_def )THEN
CALL logger_debug( &
& " WRITE FILE VAR: Enter define mode, file "//TRIM(td_file%c_name))
! Enter define mode
il_status=NF90_REDEF(td_file%i_id)
CALL iom_cdf__check(il_status)
td_file%l_def=.TRUE.
ENDIF
! check if file and variable dimension conform
IF( file_check_var_dim(td_file, td_var) )THEN
! check variable dimension expected
CALL var_check_dim(td_var)
! change fill value to NETCDF standard
CALL var_chg_FillValue(td_var)
! define variable in file
td_var%i_id=iom_cdf__write_var_def(td_file, td_var)
IF( td_file%l_def )THEN
CALL logger_debug( &
& " WRITE FILE VAR: Leave define mode, file "//TRIM(td_file%c_name))
! Leave define mode
il_status=NF90_ENDDEF(td_file%i_id)
CALL iom_cdf__check(il_status)
td_file%l_def=.FALSE.
ENDIF
IF( ASSOCIATED(td_var%d_value) )THEN
! write variable value in file
CALL iom_cdf__write_var_value(td_file, td_var)
ENDIF
ENDIF
END SUBROUTINE iom_cdf__write_var
!> @endcode
!-------------------------------------------------------------------
!> @brief This function define variable in an opened netcdf file.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] td_var : variable structure
!> @return variable id
!-------------------------------------------------------------------
!> @code
INTEGER(i4) FUNCTION iom_cdf__write_var_def(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
TYPE(TVAR), INTENT(IN) :: td_var
! local variable
INTEGER(i4) :: il_status
INTEGER(i4), DIMENSION(ip_maxdim) :: il_dimid
! loop indices
INTEGER(i4) :: ji
INTEGER(i4) :: jj
!----------------------------------------------------------------
CALL logger_debug( &
& " WRITE FILE VAR DEF: get dimension to be used for variable "//&
& TRIM(td_var%c_name)//" in file "//TRIM(td_file%c_name))
IF( ALL( .NOT. td_var%t_dim(:)%l_use ) )THEN
! scalar value
il_status = NF90_DEF_VAR(td_file%i_id, TRIM(td_var%c_name), &
& td_var%i_type, varid=iom_cdf__write_var_def)
CALL iom_cdf__check(il_status)
ELSE
! check which dimension use
jj=0
il_dimid(:)=0
! reorder dimension, so unused dimension won't be written
DO ji = 1, ip_maxdim
IF( td_var%t_dim(ji)%l_use )THEN
jj=jj+1
CALL logger_debug(" get dim id for dimension "//TRIM(td_var%t_dim(ji)%c_name))
il_dimid(jj)=dim_get_id(td_file%t_dim(:),td_var%t_dim(ji)%c_name)
ENDIF
ENDDO
CALL logger_debug( &
& " WRITE FILE VAR DEF: define dimension to be used for variable "//&
& TRIM(td_var%c_name)//" in file "//TRIM(td_file%c_name))
DO ji=1,jj
CALL logger_debug(" WRITE FILE VAR DEF: dimid "//TRIM(fct_str(il_dimid(ji))) )
ENDDO
il_status = NF90_DEF_VAR(td_file%i_id, TRIM(td_var%c_name), &
& td_var%i_type, &
& il_dimid(1:jj), &
& varid=iom_cdf__write_var_def )
CALL iom_cdf__check(il_status)
ENDIF
DO ji = 1, td_var%i_natt
CALL logger_debug( &
& " WRITE FILE VAR DEF: put attribute "//TRIM(td_var%t_att(ji)%c_name)//&
& " for variable "//TRIM(td_var%c_name)//&
& " in file "//TRIM(td_file%c_name) )
IF( td_var%t_att(ji)%i_type == NF90_CHAR )THEN
!IF( TRIM(td_var%t_att(ji)%c_value) /= 'unknown' )THEN
IF( TRIM(td_var%t_att(ji)%c_value) /= '' )THEN
il_status = NF90_PUT_ATT(td_file%i_id, iom_cdf__write_var_def, &
& TRIM(td_var%t_att(ji)%c_name), &
& TRIM(td_var%t_att(ji)%c_value) )
CALL iom_cdf__check(il_status)
ENDIF
ELSE
SELECT CASE(td_var%t_att(ji)%i_type)
CASE(NF90_BYTE)
il_status = NF90_PUT_ATT(td_file%i_id, &
& iom_cdf__write_var_def, &
& TRIM(td_var%t_att(ji)%c_name), &
& INT(td_var%t_att(ji)%d_value(:),i1))
CASE(NF90_SHORT)
il_status = NF90_PUT_ATT(td_file%i_id, &
& iom_cdf__write_var_def, &
& TRIM(td_var%t_att(ji)%c_name), &
& INT(td_var%t_att(ji)%d_value(:),i2))
CASE(NF90_INT)
il_status = NF90_PUT_ATT(td_file%i_id, &
& iom_cdf__write_var_def, &
& TRIM(td_var%t_att(ji)%c_name), &
& INT(td_var%t_att(ji)%d_value(:),i4))
CASE(NF90_FLOAT)
il_status = NF90_PUT_ATT(td_file%i_id, &
& iom_cdf__write_var_def, &
& TRIM(td_var%t_att(ji)%c_name), &
& REAL(td_var%t_att(ji)%d_value(:),sp))
CASE(NF90_DOUBLE)
il_status = NF90_PUT_ATT(td_file%i_id, &
& iom_cdf__write_var_def, &
& TRIM(td_var%t_att(ji)%c_name), &
& REAL(td_var%t_att(ji)%d_value(:),dp))
END SELECT
CALL iom_cdf__check(il_status)
ENDIF
ENDDO
END FUNCTION iom_cdf__write_var_def
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine put variable value in an opened netcdf file.
!
!> @details
!> The variable is written in the type define in variable structure.
!> Only dimension used are printed, and fillValue in table are
!> replaced by default fill values defined in module netcdf for each type.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] td_var : variable structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_cdf__write_var_value(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
TYPE(TVAR), INTENT(IN) :: td_var
! local variable
INTEGER(i4) :: il_status
INTEGER(i4), DIMENSION(ip_maxdim) :: il_order
INTEGER(i4), DIMENSION(ip_maxdim) :: il_shape
REAL(dp), DIMENSION(:,:,:,:), ALLOCATABLE :: dl_value
! loop indices
INTEGER(i4) :: ji, jj
!----------------------------------------------------------------
! check which dimension use
CALL logger_debug( &
& " WRITE FILE VAR VALUE: get dimension to be used for variable "//&
& TRIM(td_var%c_name)//" in file "//TRIM(td_file%c_name))
jj=0
DO ji = 1, ip_maxdim
IF( td_var%t_dim(ji)%l_use )THEN
jj=jj+1
!il_order(ji)=jj
!il_shape(ji)=td_var%t_dim(jj)%i_len
il_order(jj)=ji
il_shape(jj)=td_var%t_dim(ji)%i_len
ENDIF
ENDDO
! dimension not use
DO ji = 1, ip_maxdim
IF( .NOT. td_var%t_dim(ji)%l_use )THEN
jj=jj+1
!il_order(ji)=jj
!il_shape(ji)=td_var%t_dim(jj)%i_len
il_order(jj)=ji
il_shape(jj)=td_var%t_dim(ji)%i_len
ENDIF
ENDDO
ALLOCATE( dl_value( il_shape(1),il_shape(2),il_shape(3),il_shape(4) ) )
! reshape table, so unused dimension won't be written
dl_value(:,:,:,:)=RESHAPE(source=td_var%d_value(:,:,:,:),&
& SHAPE = il_shape(:), &
& ORDER = il_order(:))
! put value
CALL logger_debug( &
& " WRITE FILE VAR VALUE: put "//TRIM(td_var%c_name)//" value "//&
& "in file "//TRIM(td_file%c_name))
il_status = NF90_PUT_VAR( td_file%i_id, td_var%i_id, dl_value(:,:,:,:))
CALL iom_cdf__check(il_status)
DEALLOCATE( dl_value )
END SUBROUTINE iom_cdf__write_var_value
!> @endcode
END MODULE iom_cdf