!----------------------------------------------------------------------
! NEMO system team, System and Interface for oceanic RElocable Nesting
!----------------------------------------------------------------------
!
! MODULE: file
!
!> @brief
!> This module manage file structure.
!
!> @details
!>
!> define type TFILE:
!> TYPE(TFILE) :: tl_file
!>
!> to initialise a file structure:
!> tl_file=file_init(cd_file [,cd_type] [,ld_wrt])
!> - cd_file is the file name
!> - cd_type is the type of the file ('cdf', 'dimg') (optional)
!> - ld_wrt file in write mode or not (optional)
!>
!> to get file name:
!> - tl_file\%c_name
!>
!> to get file id (units):
!> - tl_file\%i_id
!>
!> to get the type of the file (cdf, cdf4, dimg):
!> - tl_file\%c_type
!>
!> to know if file was open in write mode:
!> - tl_file\%l_wrt
!>
!> to get the record length of the file:
!> - tl_file\%i_recl
!>
!> Files variables
!> to get the number of variable in the file:
!> - tl_file\%i_nvar
!>
!> to get the table of variable structure associated to the file:
!> - tl_file\%t_var(:)
!>
!> Files attributes
!> to get the nmber of global attributes of the file:
!> - tl_file\%i_natt
!>
!> to get the table of attributes structure associated to the file:
!> - tl_file\%t_att(:)
!>
!> Files dimensions
!> to get the number of dimension used in the file:
!> - tl_file\%i_ndim
!>
!> to get the table of dimension structure (4 elts) associated to the
!> file:
!> - tl_file\%t_dim(:)
!>
!> to print information about file structure:
!> CALL file_print(td_file)
!>
!> to add a global attribute structure in file structure:
!> CALL file_add_att(td_file, td_att)
!> - td_att is an attribute structure
!>
!> to add a dimension structure in file structure:
!> CALL file_add_dim(td_file, td_dim)
!> - td_dim is a dimension structure
!>
!> to add a variable structure in file structure:
!> CALL file_add_var(td_file, td_var)
!> - td_var is a variable structure
!>
!> to delete a global attribute structure in file structure:
!> CALL file_del_att(td_file, td_att)
!> - td_att is an attribute structure
!>
!> to delete a dimension structure in file structure:
!> CALL file_del_dim(td_file, td_dim)
!> - td_dim is a dimension structure
!>
!> to delete a variable structure in file structure:
!> CALL file_del_var(td_file, td_var)
!> - td_var is a variable structure
!>
!> to overwrite one attribute structure in file structure:
!> CALL file_move_att(td_file, td_att)
!> - td_att is an attribute structure
!>
!> to overwrite one dimension strucutre in file structure:
!> CALL file_move_dim(td_file, td_dim)
!> - td_dim is a dimension structure
!>
!> to overwrite one variable structure in file structure:
!> CALL file_move_var(td_file, td_var)
!> - td_var is a variable structure
!>
!> to check if file and variable structure share same dimension:
!> ll_check_dim = file_check_var_dim(td_file, td_var)
!> - td_var is a variable structure
!>
!> @author
!> J.Paul
! REVISION HISTORY:
!> @date Nov, 2013- Initial Version
!>
!> @note Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
!> @todo
!> - file_get_var(td_file, varname)
!> - add description generique de l'objet file
!----------------------------------------------------------------------
MODULE file
USE kind ! F90 kind parameter
USE global ! global variable
USE fct ! basic useful function
USE logger ! log file manager
USE dim ! dimension manager
USE att ! attribute manager
USE var ! variable manager
IMPLICIT NONE
PRIVATE
! NOTE_avoid_public_variables_if_possible
! type and variable
PUBLIC :: TFILE ! file structure
! function and subroutine
PUBLIC :: ASSIGNMENT(=) !< copy file structure
PUBLIC :: file_print !< print information about file structure
PUBLIC :: file_clean !< clean file structure
PUBLIC :: file_init !< initialise file structure
PUBLIC :: file_add_att !< add one attribute structure in file structure
PUBLIC :: file_add_var !< add one variable structure in file structure
PUBLIC :: file_add_dim !< add one dimension strucutre in file structure
PUBLIC :: file_del_att !< delete one attribute structure of file structure
PUBLIC :: file_del_var !< delete one variable structure of file structure
PUBLIC :: file_del_dim !< delete one dimension strucutre of file structure
PUBLIC :: file_move_att !< overwrite one attribute structure in file structure
PUBLIC :: file_move_var !< overwrite one variable structure in file structure
PUBLIC :: file_move_dim !< overwrite one dimension strucutre in file structure
PUBLIC :: file_check_var_dim !< check if file and variable structure use same dimension.
PUBLIC :: file_get_type !< get type of file
PUBLIC :: file_get_id !< get file id
PUBLIC :: file_rename !< rename file name
PUBLIC :: file_add_suffix !< add suffix to file name
PRIVATE :: file__del_var_name !< delete a variable structure in file structure, given variable name or standard name
PRIVATE :: file__del_var_str !< delete a variable structure in file structure, given variable structure
PRIVATE :: file__del_att_name !< delete a attribute structure in file structure, given attribute name
PRIVATE :: file__del_att_str !< delete a attribute structure in file structure, given attribute structure
PRIVATE :: file__get_number !< get number in file name without suffix
PRIVATE :: file__get_suffix !< get suffix of file name
PRIVATE :: file__copy_unit !< copy file structure
PRIVATE :: file__copy_tab !< copy file structure
!> @struct
TYPE TFILE
! general
CHARACTER(LEN=lc) :: c_name = "" !< file name
CHARACTER(LEN=lc) :: c_type = "" !< type of the file (cdf, cdf4, dimg)
INTEGER(i4) :: i_id = 0 !< file id
LOGICAL :: l_wrt = .FALSE. !< read or write mode
INTEGER(i4) :: i_nvar = 0 !< number of variable
TYPE(TVAR), DIMENSION(:), POINTER :: t_var => NULL() !< file variables
CHARACTER(LEN=lc) :: c_grid = 'ARAKAWA-C' !< grid type
INTEGER(i4) :: i_ew =-1 !< east-west overlap
INTEGER(i4) :: i_perio =-1 !< NEMO periodicity index
INTEGER(i4) :: i_pivot =-1 !< NEMO pivot point index F(0),T(1)
INTEGER(i4) :: i_depthid = 0 !< variable id of depth
INTEGER(i4) :: i_timeid = 0 !< variable id of time
! netcdf file
INTEGER(i4) :: i_ndim = 0 !< number of dimensions used in the file
INTEGER(i4) :: i_natt = 0 !< number of global attributes in the file
INTEGER(i4) :: i_uldid = 0 !< id of the unlimited dimension in the file
LOGICAL :: l_def = .FALSE. !< define mode or not
TYPE(TATT), DIMENSION(:), POINTER :: t_att => NULL() !< global attributes
TYPE(TDIM), DIMENSION(ip_maxdim) :: t_dim !< dimension structure
! dimg file
INTEGER(i4) :: i_recl = 0 !< record length (binary file)
INTEGER(i4) :: i_n0d = 0 !< number of scalar variable
INTEGER(i4) :: i_n1d = 0 !< number of 1D variable
INTEGER(i4) :: i_n2d = 0 !< number of 2D variable
INTEGER(i4) :: i_n3d = 0 !< number of 3D variable
INTEGER(i4) :: i_rhd = 0 !< record of the header infos (last record)
! mpp
! only use for massively parallel processing
INTEGER(i4) :: i_pid = -1 !< processor id (start to 1)
INTEGER(i4) :: i_impp = 0 !< i-indexes for mpp-subdomain left bottom
INTEGER(i4) :: i_jmpp = 0 !< j-indexes for mpp-subdomain left bottom
INTEGER(i4) :: i_lci = 0 !< i-dimensions of subdomain
INTEGER(i4) :: i_lcj = 0 !< j-dimensions of subdomain
INTEGER(i4) :: i_ldi = 0 !< first indoor i-indices
INTEGER(i4) :: i_ldj = 0 !< first indoor j-indices
INTEGER(i4) :: i_lei = 0 !< last indoor i-indices
INTEGER(i4) :: i_lej = 0 !< last indoor j-indices
LOGICAL :: l_ctr = .FALSE. !< domain is on border
LOGICAL :: l_use = .FALSE. !< domain is used
! only use to draw domain decomposition when initialise with mpp_init
INTEGER(i4) :: i_iind = 0 !< i-direction indices
INTEGER(i4) :: i_jind = 0 !< j-direction indices
END TYPE TFILE
INTERFACE file_del_var
MODULE PROCEDURE file__del_var_name
MODULE PROCEDURE file__del_var_str
END INTERFACE file_del_var
INTERFACE file_del_att
MODULE PROCEDURE file__del_att_name
MODULE PROCEDURE file__del_att_str
END INTERFACE file_del_att
INTERFACE file_rename
MODULE PROCEDURE file__rename_char
MODULE PROCEDURE file__rename_str
END INTERFACE file_rename
INTERFACE ASSIGNMENT(=)
MODULE PROCEDURE file__copy_unit ! copy file structure
MODULE PROCEDURE file__copy_tab ! copy file structure
END INTERFACE
CONTAINS
!-------------------------------------------------------------------
!> @brief
!> This function copy file structure in another file
!> structure
!> @details
!> file variable and attribute value are copied in a temporary table,
!> so input and output file structure value do not point on the same
!> "memory cell", and so on are independant.
!>
!> @note new file is assume to be closed.
!>
!> @warning to avoid infinite loop, do not use any function inside
!> this subroutine
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[out] td_file1 : file structure
!> @param[in] td_file2 : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE file__copy_unit( td_file1, td_file2 )
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT( OUT) :: td_file1
TYPE(TFILE), INTENT(IN ) :: td_file2
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
CALL logger_trace("COPY: file "//TRIM(td_file2%c_name) )
! copy file variable
td_file1%c_name = TRIM(td_file2%c_name)
td_file1%c_type = TRIM(td_file2%c_type)
! file1 should be closed even if file2 is opened right now
td_file1%i_id = 0
td_file1%l_wrt = td_file2%l_wrt
td_file1%i_nvar = td_file2%i_nvar
td_file1%c_grid = td_file2%c_grid
td_file1%i_ew = td_file2%i_ew
td_file1%i_perio= td_file2%i_perio
td_file1%i_pivot= td_file2%i_pivot
! copy variable structure
IF( ASSOCIATED(td_file1%t_var) ) DEALLOCATE(td_file1%t_var)
IF( ASSOCIATED(td_file2%t_var) .AND. td_file1%i_nvar > 0 )THEN
ALLOCATE( td_file1%t_var(td_file1%i_nvar) )
DO ji=1,td_file1%i_nvar
td_file1%t_var(ji) = td_file2%t_var(ji)
ENDDO
ENDIF
! copy netcdf variable
td_file1%i_ndim = td_file2%i_ndim
td_file1%i_natt = td_file2%i_natt
td_file1%i_uldid = td_file2%i_uldid
td_file1%l_def = td_file2%l_def
! copy dimension
td_file1%t_dim(:) = td_file2%t_dim(:)
! copy attribute structure
IF( ASSOCIATED(td_file1%t_att) ) DEALLOCATE(td_file1%t_att)
IF( ASSOCIATED(td_file2%t_att) .AND. td_file1%i_natt > 0 )THEN
ALLOCATE( td_file1%t_att(td_file1%i_natt) )
DO ji=1,td_file1%i_natt
td_file1%t_att(ji) = td_file2%t_att(ji)
ENDDO
ENDIF
! copy dimg variable
td_file1%i_recl = td_file2%i_recl
td_file1%i_n0d = td_file2%i_n0d
td_file1%i_n1d = td_file2%i_n1d
td_file1%i_n2d = td_file2%i_n2d
td_file1%i_n3d = td_file2%i_n3d
td_file1%i_rhd = td_file2%i_rhd
! copy mpp variable
td_file1%i_pid = td_file2%i_pid
td_file1%i_impp = td_file2%i_impp
td_file1%i_jmpp = td_file2%i_jmpp
td_file1%i_lci = td_file2%i_lci
td_file1%i_lcj = td_file2%i_lcj
td_file1%i_ldi = td_file2%i_ldi
td_file1%i_ldj = td_file2%i_ldj
td_file1%i_lei = td_file2%i_lei
td_file1%i_lej = td_file2%i_lej
td_file1%l_ctr = td_file2%l_ctr
td_file1%l_use = td_file2%l_use
td_file1%i_iind = td_file2%i_iind
td_file1%i_jind = td_file2%i_jind
END SUBROUTINE file__copy_unit
!> @endcode
!-------------------------------------------------------------------
!> @brief
!> This function copy file structure in another file
!> structure
!> @details
!> file variable and attribute value are copied in a temporary table,
!> so input and output file structure value do not point on the same
!> "memory cell", and so on are independant.
!>
!> @note new file is assume to be closed.
!>
!> @warning to avoid infinite loop, do not use any function inside
!> this subroutine
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[out] td_file1 : file structure
!> @param[in] td_file2 : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE file__copy_tab( td_file1, td_file2 )
IMPLICIT NONE
! Argument
TYPE(TFILE), DIMENSION(:) , INTENT(IN ) :: td_file2
TYPE(TFILE), DIMENSION(SIZE(td_file2(:))), INTENT( OUT) :: td_file1
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
DO ji=1,SIZE(td_file2(:))
td_file1(ji)=td_file2(ji)
ENDDO
END SUBROUTINE file__copy_tab
!> @endcode
!-------------------------------------------------------------------
!> @brief This function initialise file structure.
!> If cd_type is not specify, check if file name include '.nc' or
!> .'dimg'
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] cd_file : file name
!> @param[in] cd_type : file type ('cdf', 'dimg')
!> @param[in] ld_wrt : write mode (default .FALSE.)
!> @return file structure
!-------------------------------------------------------------------
!> @code
TYPE(TFILE) FUNCTION file_init( cd_file, cd_type, ld_wrt, &
& id_ew, id_perio, id_pivot,&
& cd_grid)
IMPLICIT NONE
! Argument
CHARACTER(LEN=*), INTENT(IN) :: cd_file
CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cd_type
LOGICAL , INTENT(IN), OPTIONAL :: ld_wrt
INTEGER(i4) , INTENT(IN), OPTIONAL :: id_ew
INTEGER(i4) , INTENT(IN), OPTIONAL :: id_perio
INTEGER(i4) , INTENT(IN), OPTIONAL :: id_pivot
CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cd_grid
! local variable
TYPE(TATT) :: tl_att
!----------------------------------------------------------------
! clean file
CALL file_clean(file_init)
file_init%c_name=TRIM(ADJUSTL(cd_file))
CALL logger_trace("INIT: initialise file "//TRIM(file_init%c_name))
! create some global attribute
tl_att=att_init("Conventions","CF-1.5")
CALL file_add_att(file_init,tl_att)
tl_att=att_init("Grid",TRIM(file_init%c_grid))
CALL file_add_att(file_init,tl_att)
! check type
IF( PRESENT(cd_type) )THEN
SELECT CASE(TRIM(cd_type))
CASE('cdf')
file_init%c_type='cdf'
CASE('dimg')
file_init%c_type='dimg'
CASE DEFAULT
CALL logger_error( " INIT: can't initialise file "//&
& TRIM(file_init%c_name)//" : type unknown " )
END SELECT
ELSE
file_init%c_type=TRIM(file_get_type(cd_file))
ENDIF
IF( PRESENT(ld_wrt) )THEN
file_init%l_wrt=ld_wrt
ENDIF
IF( PRESENT(id_ew) )THEN
file_init%i_ew=id_ew
IF( id_ew >= 0 )THEN
tl_att=att_init('ew_overlap',id_ew)
CALL file_move_att(file_init, tl_att)
ENDIF
ENDIF
IF( PRESENT(id_perio) )THEN
file_init%i_perio=id_perio
IF( id_perio >= 0 )THEN
tl_att=att_init('periodicity',id_perio)
CALL file_move_att(file_init, tl_att)
ENDIF
ENDIF
IF( PRESENT(id_pivot) )THEN
file_init%i_pivot=id_pivot
IF( id_pivot > 0 )THEN
tl_att=att_init('pivot_point',id_pivot)
CALL file_move_att(file_init, tl_att)
ENDIF
ENDIF
IF( PRESENT(cd_grid) )THEN
file_init%c_grid=cd_grid
ENDIF
END FUNCTION file_init
!> @endcode
!-------------------------------------------------------------------
!> @brief
!> This function get type of file, given file name.
!> @details
!> Actually it get suffix of the file name, and compare it to 'nc', 'cdf' or
!> 'dimg'
!> If no suffix or suffix not identify, we assume file is dimg
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] cd_file : file name
!> @return type of file
!-------------------------------------------------------------------
!> @code
CHARACTER(LEN=lc) FUNCTION file_get_type(cd_file)
IMPLICIT NONE
! Argument
CHARACTER(LEN=*), INTENT(IN) :: cd_file
!local variable
CHARACTER(LEN=lc) :: cl_suffix
!----------------------------------------------------------------
cl_suffix=file__get_suffix(cd_file)
SELECT CASE( TRIM(fct_lower(cl_suffix)) )
CASE('.nc','.cdf')
CALL logger_debug(" GET TYPE: file "//TRIM(cd_file)//" is cdf")
file_get_type='cdf'
CASE('.dimg')
CALL logger_debug(" GET TYPE: file "//TRIM(cd_file)//" is dimg" )
file_get_type='dimg'
CASE DEFAULT
CALL logger_warn(" GET TYPE: type unknown, we assume file: "//&
& TRIM(cd_file)//" is dimg ")
file_get_type='dimg'
END SELECT
END FUNCTION file_get_type
!> @endcode
!-------------------------------------------------------------------
!> @brief This function check if variable dimension to be used
!> have the same length that in file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] td_var : variable structure
!> @return dimension of variable and file structure agree (or not)
!-------------------------------------------------------------------
!> @code
LOGICAL FUNCTION file_check_var_dim(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
TYPE(TVAR), INTENT(IN) :: td_var
! local variable
INTEGER(i4) :: il_ndim
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
file_check_var_dim=.TRUE.
! check used dimension
IF( ANY( td_var%t_dim(:)%l_use .AND. &
& td_var%t_dim(:)%i_len /= td_file%t_dim(:)%i_len) )THEN
file_check_var_dim=.FALSE.
CALL logger_error( &
& " FILE CHECK VAR DIM: variable and file dimension differ"//&
& " for variable "//TRIM(td_var%c_name)//&
& " and file "//TRIM(td_file%c_name))
CALL logger_debug( &
& " file dimension: "//TRIM(fct_str(td_file%i_ndim))//&
& " variable dimension: "//TRIM(fct_str(td_var%i_ndim)) )
il_ndim=MIN(td_var%i_ndim, td_file%i_ndim )
DO ji = 1, il_ndim
CALL logger_debug( &
& " FILE CHECK VAR DIM: for dimension "//&
& TRIM(td_file%t_dim(ji)%c_name)//&
& ", file length: "//&
& TRIM(fct_str(td_file%t_dim(ji)%i_len))//&
& ", variable length: "//&
& TRIM(fct_str(td_var%t_dim(ji)%i_len))//&
& ", variable used "//TRIM(fct_str(td_var%t_dim(ji)%l_use)))
ENDDO
ELSE
IF( ANY( td_var%t_dim(:)%l_use .AND. &
& .NOT. td_file%t_dim(:)%l_use ) )THEN
CALL logger_info("FILE CHECK VAR DIM: variable use more dimension "//&
& " than file do until now. file dimension use will change.")
ENDIF
ENDIF
END FUNCTION file_check_var_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine add a variable structure in a file structure.
!> Do not overwrite, if variable already in file structure.
!
!> @note variable value is suppose to be ordered ('x','y','z','t')
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_var : variable structure
!
!> @todo
!> - check dimension order
!> - voir pour ajouter variable avec plus de dim que deja presente dans fichier
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_add_var(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TVAR) , INTENT(IN ) :: td_var
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_varid
INTEGER(i4) :: il_rec
INTEGER(i4) :: il_ind
TYPE(TVAR), DIMENSION(:), ALLOCATABLE :: tl_var
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if file opened
!IF( TRIM(td_file%c_name) == "unknown" )THEN
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " ADD VAR: structure file unknown" )
CALL logger_debug( " ADD VAR: you should have used file_init before "//&
& "running file_add_var" )
ELSE
! check if variable exist
IF( TRIM(td_var%c_name) == '' .AND. &
& TRIM(td_var%c_stdname) == '' )THEN
CALL logger_error(" ADD VAR: variable not define ")
ELSE
! check if variable already in file structure
il_varid=0
IF( ASSOCIATED(td_file%t_var) )THEN
il_varid=var_get_id( td_file%t_var(:), td_var%c_name, &
& td_var%c_stdname )
ENDIF
IF( il_varid /= 0 )THEN
CALL logger_error( &
& " ADD VAR: variable "//TRIM(td_var%c_name)//&
& ", standard name "//TRIM(td_var%c_stdname)//&
& ", already in file "//TRIM(td_file%c_name) )
DO ji=1,td_file%i_nvar
CALL logger_debug( " ADD VAR: in file : &
& variable "//TRIM(td_file%t_var(ji)%c_name)//&
& ", standard name "//TRIM(td_file%t_var(ji)%c_stdname) )
ENDDO
ELSE
CALL logger_info( &
& " ADD VAR: add variable "//TRIM(td_var%c_name)//&
& ", standard name "//TRIM(td_var%c_stdname)//&
& ", in file "//TRIM(td_file%c_name) )
! if none, force to use variable dimension
IF( ALL( .NOT. td_file%t_dim(:)%l_use) )THEN
td_file%t_dim(:)=td_var%t_dim(:)
ENDIF
! check used dimension
IF( file_check_var_dim(td_file, td_var) )THEN
SELECT CASE(td_var%i_ndim)
CASE(0)
il_ind=td_file%i_n0d+1
il_rec=0
CASE(1)
il_ind=td_file%i_n0d+td_file%i_n1d+1
il_rec=1
CASE(2)
il_ind=td_file%i_n0d+td_file%i_n1d+td_file%i_n2d+1
il_rec=1
CASE(3,4)
il_ind=td_file%i_n0d+td_file%i_n1d+td_file%i_n2d+td_file%i_n3d+1
il_rec=td_file%t_dim(3)%i_len
END SELECT
IF( td_file%i_nvar > 0 )THEN
! already other variable in file structure
ALLOCATE( tl_var(td_file%i_nvar), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD VAR: not enough space to put variables "//&
& "from "//TRIM(td_file%c_name)//&
& " in variable structure")
ELSE
! save temporary variable of file structure
tl_var(:)=td_file%t_var(:)
DEALLOCATE( td_file%t_var )
ALLOCATE( td_file%t_var(td_file%i_nvar+1), &
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD VAR: not enough space to put variable "//&
& "in file structure "//TRIM(td_file%c_name) )
ENDIF
! copy variable in file before
! variable with less than or equal dimension that new variable
td_file%t_var( 1:il_ind-1 ) = tl_var( 1:il_ind-1 )
! variable with greater dimension than new variable
td_file%t_var( il_ind+1 : td_file%i_nvar+1 ) = &
& tl_var( il_ind : td_file%i_nvar )
! update id
td_file%t_var( il_ind+1 : td_file%i_nvar+1 )%i_id = &
& tl_var( il_ind : td_file%i_nvar )%i_id + 1
! update record index
td_file%t_var( il_ind+1 : td_file%i_nvar+1 )%i_rec = &
& tl_var( il_ind : td_file%i_nvar )%i_rec + il_rec
DEALLOCATE(tl_var)
ENDIF
ELSE
! no variable in file structure
IF( ASSOCIATED(td_file%t_var) )THEN
DEALLOCATE(td_file%t_var)
ENDIF
ALLOCATE( td_file%t_var(td_file%i_nvar+1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD VAR: not enough space to put variable "//&
& "in file structure "//TRIM(td_file%c_name) )
ENDIF
ENDIF
ALLOCATE( tl_var(1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD VAR: not enough space to put variables from "//&
& TRIM(td_var%c_name)//" in variable structure")
ELSE
tl_var(1)=td_var
! update dimension name in new variable
tl_var(1)%t_dim(:)%c_name = td_file%t_dim(:)%c_name
! add new variable
td_file%t_var(il_ind)=tl_var(1)
! update number of variable
td_file%i_nvar=td_file%i_nvar+1
SELECT CASE(tl_var(1)%i_ndim)
CASE(0)
td_file%i_n0d=td_file%i_n0d+1
CASE(1)
td_file%i_n1d=td_file%i_n1d+1
CASE(2)
td_file%i_n2d=td_file%i_n2d+1
CASE(3)
td_file%i_n3d=td_file%i_n3d+1
END SELECT
! update variable id
td_file%t_var(il_ind)%i_id=il_ind
! update record header index
td_file%i_rhd=td_file%i_rhd+il_rec
! update record index
IF( il_ind > 1 )THEN
td_file%t_var(il_ind)%i_rec = &
& td_file%t_var(il_ind-1)%i_rec+il_rec
ELSE
td_file%t_var(il_ind)%i_rec = il_rec
ENDIF
! update dimension used
td_file%t_dim(:)%l_use=.FALSE.
DO ji=1,ip_maxdim
IF( ANY(td_file%t_var(:)%t_dim(ji)%l_use) )THEN
td_file%t_dim(ji)%l_use=.TRUE.
ENDIF
ENDDO
CALL dim_reorder(td_file%t_dim(:))
! update number of dimension
td_file%i_ndim=COUNT(td_file%t_dim(:)%l_use)
DEALLOCATE( tl_var )
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
END SUBROUTINE file_add_var
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine delete a variable structure
!> in file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] cd_name : variable name or standard name
!-------------------------------------------------------------------
!> @code
SUBROUTINE file__del_var_name(td_file, cd_name )
IMPLICIT NONE
! Argument
TYPE(TFILE) , INTENT(INOUT) :: td_file
CHARACTER(LEN=*), INTENT(IN ) :: cd_name
! local variable
INTEGER(i4) :: il_varid
!----------------------------------------------------------------
! check if file opened
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " DEL VAR NAME: file structure unknown ")
CALL logger_debug( " DEL VAR NAME: you should have used file_init before "//&
& "running file_del_var" )
ELSE
IF( td_file%i_nvar /= 0 )THEN
! get the variable id, in file variable structure
il_varid=0
IF( ASSOCIATED(td_file%t_var) )THEN
il_varid=var_get_id(td_file%t_var(:), cd_name )
ENDIF
IF( il_varid /= 0 )THEN
CALL file_del_var(td_file, td_file%t_var(il_varid))
ELSE
CALL logger_warn( &
& " DEL VAR NAME: there is no variable with name or "//&
& "standard name "//TRIM(cd_name)//" in file "//&
& TRIM(td_file%c_name))
ENDIF
ELSE
CALL logger_debug( " DEL VAR NAME: no variable associated to file "//&
& TRIM(td_file%c_name) )
ENDIF
ENDIF
END SUBROUTINE file__del_var_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine delete a variable structure
!> in file structure, given variable structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_var : variable structure
!> @todo
!> - verifier pose pas de souci de ne pas modifier id
!-------------------------------------------------------------------
!> @code
SUBROUTINE file__del_var_str(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TVAR), INTENT(IN) :: td_var
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_varid
INTEGER(i4) :: il_rec
TYPE(TVAR), DIMENSION(:), ALLOCATABLE :: tl_var
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if file opened
!IF( TRIM(td_file%c_name) == "unknown" )THEN
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " DEL VAR: file structure unknown ")
CALL logger_debug( " DEL VAR: you should have used file_init before "//&
& "running file_del_var" )
ELSE
! check if variable already in file structure
il_varid=var_get_id(td_file%t_var(:), td_var%c_name, td_var%c_stdname )
IF( il_varid == 0 )THEN
CALL logger_error( &
& " DEL VAR: no variable "//TRIM(td_var%c_name)//&
& ", in file "//TRIM(td_file%c_name) )
DO ji=1,td_file%i_nvar
CALL logger_debug( &
& " DEL VAR: in file "//TRIM(td_file%t_var(ji)%c_name)//&
& ", standard name "//TRIM(td_file%t_var(ji)%c_stdname) )
ENDDO
ELSE
CALL logger_trace( &
& " DEL VAR: delete variable "//TRIM(td_var%c_name)//&
& ", from file "//TRIM(td_file%c_name) )
ALLOCATE( tl_var(td_file%i_nvar-1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " DEL VAR: not enough space to put variables from "//&
& TRIM(td_file%c_name)//" in temporary variable structure")
ELSE
! save temporary variable's file structure
tl_var(1:il_varid-1)=td_file%t_var(1:il_varid-1)
tl_var(il_varid:)=td_file%t_var(il_varid+1:)
! new number of variable in file
td_file%i_nvar=td_file%i_nvar-1
SELECT CASE(td_var%i_ndim)
CASE(0)
td_file%i_n0d=td_file%i_n0d-1
il_rec=0
CASE(1)
td_file%i_n1d=td_file%i_n1d-1
il_rec=1
CASE(2)
td_file%i_n2d=td_file%i_n2d-1
il_rec=1
CASE(3,4)
td_file%i_n3d=td_file%i_n3d-1
il_rec=td_file%t_dim(3)%i_len
END SELECT
DEALLOCATE( td_file%t_var )
IF( td_file%i_nvar > 0 )THEN
ALLOCATE( td_file%t_var(td_file%i_nvar), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " DEL VAR: not enough space to put variables "//&
& "in file structure "//TRIM(td_file%c_name) )
ENDIF
! copy attribute in file before
td_file%t_var(:)=tl_var(:)
! update record header index
td_file%i_rhd = td_file%i_rhd - il_rec
! ! update id
! td_file%t_var( il_varid : td_file%i_nvar )%i_id = &
! & td_file%t_var( il_varid : td_file%i_nvar )%i_id - 1
! update record index
td_file%t_var( il_varid : td_file%i_nvar )%i_rec = &
& td_file%t_var( il_varid : td_file%i_nvar )%i_rec - il_rec
! update dimension used
td_file%t_dim(:)%l_use=.FALSE.
DO ji=1,ip_maxdim
IF( ANY(td_file%t_var(:)%t_dim(ji)%l_use) )THEN
td_file%t_dim(ji)%l_use=.TRUE.
ENDIF
ENDDO
CALL dim_reorder(td_file%t_dim(:))
! update number of dimension
td_file%i_ndim=COUNT(td_file%t_dim(:)%l_use)
ENDIF
DEALLOCATE(tl_var)
ENDIF
ENDIF
ENDIF
END SUBROUTINE file__del_var_str
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine overwrite variable structure
!> in file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_var : variable structure
!> @todo
!> - check independance td_var (cf move dim variable)
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_move_var(td_file, td_var)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TVAR), INTENT(IN) :: td_var
! local variable
TYPE(TVAR) :: tl_var
INTEGER(i4):: il_varid
!----------------------------------------------------------------
! copy variable
tl_var=td_var
IF( ASSOCIATED(td_file%t_var) )THEN
il_varid=var_get_id(td_file%t_var(:),TRIM(tl_var%c_name))
IF( il_varid /= 0 )THEN
! remove variable with same name or standard name
CALL file_del_var(td_file, tl_var)
ENDIF
ENDIF
! add new variable
CALL file_add_var(td_file, tl_var)
END SUBROUTINE file_move_var
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine add a global attribute
!> in a file structure.
!> Do not overwrite, if attribute already in file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_att : attribute structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_add_att(td_file, td_att)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TATT), INTENT(IN) :: td_att
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_attid
TYPE(TATT), DIMENSION(:), ALLOCATABLE :: tl_att
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if file opened
!IF( TRIM(td_file%c_name) == "unknown" )THEN
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " ADD ATT: file structure unknown ")
CALL logger_debug( " ADD ATT: you should have used file_init before "//&
& "running file_add_att" )
ELSE
! check if attribute already in file structure
il_attid=0
IF( ASSOCIATED(td_file%t_att) )THEN
il_attid=att_get_id( td_file%t_att(:), td_att%c_name )
ENDIF
IF( il_attid /= 0 )THEN
CALL logger_error( &
& " ADD ATT: attribute "//TRIM(td_att%c_name)//&
& ", already in file "//TRIM(td_file%c_name) )
CALL logger_flush()
DO ji=1,td_file%i_natt
CALL logger_debug( &
& " ADD ATT: in file "//TRIM(td_file%t_att(ji)%c_name) )
ENDDO
ELSE
CALL logger_debug( &
& " ADD ATT: add attribute "//TRIM(td_att%c_name)//&
& ", in file "//TRIM(td_file%c_name) )
IF( td_file%i_natt > 0 )THEN
! already other attribute in file structure
ALLOCATE( tl_att(td_file%i_natt), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD ATT: not enough space to put attributes from "//&
& TRIM(td_file%c_name)//" in temporary attribute structure")
ELSE
! save temporary global attribute's file structure
tl_att(:)=td_file%t_att(:)
DEALLOCATE( td_file%t_att )
ALLOCATE( td_file%t_att(td_file%i_natt+1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD ATT: not enough space to put attributes "//&
& "in file structure "//TRIM(td_file%c_name) )
ENDIF
! copy attribute in file before
td_file%t_att(1:td_file%i_natt)=tl_att(:)
DEALLOCATE(tl_att)
ENDIF
ELSE
! no attribute in file structure
IF( ASSOCIATED(td_file%t_att) )THEN
DEALLOCATE(td_file%t_att)
ENDIF
CALL logger_debug(" natt "//TRIM(fct_str(td_file%i_natt)) )
ALLOCATE( td_file%t_att(td_file%i_natt+1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD ATT: not enough space to put attributes "//&
& "in file structure "//TRIM(td_file%c_name) )
ENDIF
ENDIF
! add new attributes
td_file%t_att(td_file%i_natt+1)=td_att
! update attributes id
td_file%t_att(td_file%i_natt+1)%i_id=td_file%i_natt+1
! update number of attribute
td_file%i_natt=td_file%i_natt+1
ENDIF
ENDIF
END SUBROUTINE file_add_att
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine delete a variable structure
!> in file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] cd_name : variable name or standard name
!-------------------------------------------------------------------
!> @code
SUBROUTINE file__del_att_name(td_file, cd_name )
IMPLICIT NONE
! Argument
TYPE(TFILE) , INTENT(INOUT) :: td_file
CHARACTER(LEN=*), INTENT(IN ) :: cd_name
! local variable
INTEGER(i4) :: il_attid
!----------------------------------------------------------------
! check if file opened
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " DEL ATT NAME: file structure unknown ")
CALL logger_debug( " DEL ATT NAME: you should have used file_init before "//&
& "running file_del_var" )
ELSE
IF( td_file%i_natt /= 0 )THEN
! get the variable id, in file variable structure
il_attid=0
IF( ASSOCIATED(td_file%t_att) )THEN
il_attid=att_get_id(td_file%t_att(:), cd_name )
ENDIF
IF( il_attid /= 0 )THEN
CALL file_del_att(td_file, td_file%t_att(il_attid))
ELSE
CALL logger_warn( &
& " DEL ATT NAME: there is no attribute with name "//&
& TRIM(cd_name)//" in file "//TRIM(td_file%c_name))
ENDIF
ELSE
CALL logger_debug( " DEL ATT NAME: no attribute associated to file "//&
& TRIM(td_file%c_name) )
ENDIF
ENDIF
END SUBROUTINE file__del_att_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine delete a global attribute structure
!> from file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_att : attribute structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE file__del_att_str(td_file, td_att)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TATT), INTENT(IN) :: td_att
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_attid
TYPE(TATT), DIMENSION(:), ALLOCATABLE :: tl_att
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if file opened
!IF( TRIM(td_file%c_name) == "unknown" )THEN
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " DEL ATT: file structure unknown ")
CALL logger_debug( " DEL ATT: you should have used file_init before "//&
& "running file_del_att" )
ELSE
! check if attribute already in file structure
il_attid=0
IF( ASSOCIATED(td_file%t_att) )THEN
il_attid=att_get_id( td_file%t_att(:), td_att%c_name )
ENDIF
IF( il_attid == 0 )THEN
CALL logger_error( &
& " DEL ATT: no attribute "//TRIM(td_att%c_name)//&
& ", in file "//TRIM(td_file%c_name) )
ELSE
CALL logger_debug( &
& " DEL ATT: del attribute "//TRIM(td_att%c_name)//&
& ", in file "//TRIM(td_file%c_name) )
ALLOCATE( tl_att(td_file%i_natt-1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD ATT: not enough space to put attributes from "//&
& TRIM(td_file%c_name)//" in temporary attribute structure")
ELSE
! save temporary global attribute's file structure
tl_att(1:il_attid-1)=td_file%t_att(1:il_attid-1)
tl_att(il_attid:)=td_file%t_att(il_attid+1:)
DEALLOCATE( td_file%t_att )
! new number of attribute in file
td_file%i_natt=td_file%i_natt-1
ALLOCATE( td_file%t_att(td_file%i_natt), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " ADD ATT: not enough space to put attributes "//&
& "in file structure "//TRIM(td_file%c_name) )
ENDIF
! copy attribute in file before
td_file%t_att(1:td_file%i_natt)=tl_att(:)
! update attribute id
DO ji=1,td_file%i_natt
td_file%t_att(ji)%i_id=ji
ENDDO
DEALLOCATE(tl_att)
ENDIF
ENDIF
ENDIF
END SUBROUTINE file__del_att_str
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine move a global attribute structure
!> from file structure.
!> @note attribute id could be change
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_att : attribute structure
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_move_att(td_file, td_att)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TATT), INTENT(IN) :: td_att
! local variable
TYPE(TATT) :: tl_att
INTEGER(i4) :: il_attid
!----------------------------------------------------------------
! copy attribute
tl_att=td_att
IF( ASSOCIATED(td_file%t_att) )THEN
il_attid=att_get_id(td_file%t_att(:),TRIM(tl_att%c_name))
IF( il_attid /= 0 )THEN
! remove attribute with same name
CALL file_del_att(td_file, tl_att)
ENDIF
ENDIF
! add new attribute
CALL file_add_att(td_file, tl_att)
END SUBROUTINE file_move_att
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine add a dimension structure in file
!> structure.
!> Do not overwrite, if dimension already in file structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_dim : dimension structure
!
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_add_dim(td_file, td_dim)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TDIM), INTENT(IN) :: td_dim
! local variable
INTEGER(i4) :: il_dimid
!----------------------------------------------------------------
! check if file opened
!IF( TRIM(td_file%c_name) == "unknown" )THEN
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " ADD DIM: file structure unknown ")
CALL logger_debug( " ADD DIM: you should have used file_init before "//&
& "running file_add_dim" )
ELSE
IF( td_file%i_ndim <= 4 )THEN
! check if dimension already in file structure
il_dimid=dim_get_id(td_file%t_dim(:), td_dim%c_name, td_dim%c_sname)
IF( il_dimid /= 0 )THEN
CALL logger_warn("ADD DIM: dimension "//TRIM(td_dim%c_name)//&
& ", short name "//TRIM(td_dim%c_sname)//&
& ", already in file "//TRIM(td_file%c_name) )
IF( td_file%t_dim(il_dimid)%i_len /= td_dim%i_len )THEN
CALL logger_error( &
& "ADD DIM: dimension "//TRIM(td_dim%c_name)//&
& " already in file "//TRIM(td_file%c_name)//&
& " differ from added dimension ")
ENDIF
ELSE
CALL logger_debug( &
& " ADD DIM: add dimension "//TRIM(td_dim%c_name)//&
& ", short name "//TRIM(td_dim%c_sname)//&
& ", in file "//TRIM(td_file%c_name) )
IF( td_file%i_ndim == 4 )THEN
! search empty dimension
il_dimid=dim_get_void_id(td_file%t_dim(:),TRIM(td_dim%c_name), &
& TRIM(td_dim%c_sname))
! replace empty dimension
td_file%t_dim(il_dimid)=td_dim
td_file%t_dim(il_dimid)%i_id=il_dimid
td_file%t_dim(il_dimid)%l_use=.TRUE.
ELSE
! add new dimension
il_dimid=dim_get_void_id(td_file%t_dim(:),TRIM(td_dim%c_name), &
& TRIM(td_dim%c_sname))
td_file%t_dim(il_dimid)=td_dim
td_file%t_dim(il_dimid)%i_id=td_file%i_ndim+1
td_file%t_dim(il_dimid)%l_use=.TRUE.
! update number of attribute
td_file%i_ndim=COUNT(td_file%t_dim(:)%l_use)
ENDIF
! reorder dimension to ('x','y','z','t')
CALL dim_reorder(td_file%t_dim)
ENDIF
ELSE
CALL logger_error( &
& " ADD DIM: too much dimension in file "//&
& TRIM(td_file%c_name)//" ("//TRIM(fct_str(td_file%i_ndim))//")")
ENDIF
ENDIF
END SUBROUTINE file_add_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine delete a dimension structure in file
!> structure.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_dim : dimension structure
!
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_del_dim(td_file, td_dim)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TDIM), INTENT(IN) :: td_dim
! local variable
INTEGER(i4) :: il_status
INTEGER(i4) :: il_dimid
TYPE(TDIM), DIMENSION(:), ALLOCATABLE :: tl_dim
!----------------------------------------------------------------
! check if file opened
!IF( TRIM(td_file%c_name) == "unknown" )THEN
IF( TRIM(td_file%c_name) == '' )THEN
CALL logger_error( " DEL DIM: file structure unknown ")
CALL logger_debug( " DEL DIM: you should have used file_init before "//&
& "running file_del_dim" )
ELSE
IF( td_file%i_ndim <= 4 )THEN
! check if dimension already in file structure
il_dimid=dim_get_id(td_file%t_dim(:), td_dim%c_name, td_dim%c_sname)
IF( il_dimid == 0 )THEN
CALL logger_error( &
& " DEL DIM: no dimension "//TRIM(td_dim%c_name)//&
& ", short name "//TRIM(td_dim%c_sname)//&
& ", in file "//TRIM(td_file%c_name) )
ELSE
CALL logger_debug( &
& " DEL DIM: delete dimension "//TRIM(td_dim%c_name)//&
& ", short name "//TRIM(td_dim%c_sname)//&
& ", in file "//TRIM(td_file%c_name) )
IF( td_file%i_ndim == 4 )THEN
ALLOCATE( tl_dim(1), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " DEL DIM: not enough space to put dimensions from "//&
& TRIM(td_file%c_name)//" in temporary dimension structure")
ELSE
! replace dimension by empty one
td_file%t_dim(il_dimid)=tl_dim(1)
ENDIF
DEALLOCATE(tl_dim)
ELSE
!
!ALLOCATE( tl_dim(td_file%i_ndim), stat=il_status )
ALLOCATE( tl_dim(ip_maxdim), stat=il_status )
IF(il_status /= 0 )THEN
CALL logger_error( &
& " DEL DIM: not enough space to put dimensions from "//&
& TRIM(td_file%c_name)//" in temporary dimension structure")
ELSE
print *,"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
print *,'il_dimid '//TRIM(fct_str(il_dimid))
CALL dim_print(td_file%t_dim(:))
! save temporary dimension's file structure
tl_dim( 1 : il_dimid-1 ) = td_file%t_dim( 1 : il_dimid-1 )
!tl_dim( il_dimid : td_file%i_ndim-1 ) = &
!& td_file%t_dim( il_dimid+1 : td_file%i_ndim )
tl_dim( il_dimid : ip_maxdim-1 ) = &
& td_file%t_dim( il_dimid+1 : ip_maxdim )
print *,"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
CALL dim_print(tl_dim(:))
! copy dimension in file, except one
!td_file%t_dim(1:td_file%i_ndim)=tl_dim(:)
td_file%t_dim(:)=tl_dim(:)
print *,"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
CALL dim_print(td_file%t_dim(:))
! update number of dimension
td_file%i_ndim=td_file%i_ndim-1
ENDIF
ENDIF
! reorder dimension to ('x','y','z','t')
CALL dim_reorder(td_file%t_dim)
ENDIF
ELSE
CALL logger_error( &
& " DEL DIM: too much dimension in file "//&
& TRIM(td_file%c_name)//" ("//TRIM(fct_str(td_file%i_ndim))//")")
ENDIF
ENDIF
END SUBROUTINE file_del_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine move a dimension structure
!> in file structure.
!> @warning dimension order Nov have changed
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_file : file structure
!> @param[in] td_dim : dimension structure
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_move_dim(td_file, td_dim)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
TYPE(TDIM), INTENT(IN) :: td_dim
! local variable
TYPE(TDIM) :: tl_dim
INTEGER(i4) :: il_dimid
!----------------------------------------------------------------
! copy dimension
tl_dim=td_dim
il_dimid=dim_get_id(td_file%t_dim(:), TRIM(td_dim%c_name), &
& TRIM(td_dim%c_sname))
IF( il_dimid /= 0 )THEN
! remove dimension with same name
CALL file_del_dim(td_file, tl_dim)
ENDIF
! add new dimension
CALL file_add_dim(td_file, tl_dim)
END SUBROUTINE file_move_dim
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine print some information about file strucutre.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_print(td_file)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
! local variable
CHARACTER(LEN=lc) :: cl_mode
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
cl_mode='READ'
IF( td_file%l_wrt ) cl_mode='WRITE'
WRITE(*,'((a,a),2(/3x,a,a),4(/3x,a,i0))')&
& "File : ",TRIM(td_file%c_name), &
& " type : ",TRIM(td_file%c_type), &
& " mode : ",TRIM(cl_mode), &
& " id : ",td_file%i_id, &
& " ndim : ",td_file%i_ndim, &
& " natt : ",td_file%i_natt, &
& " nvar : ",td_file%i_nvar
SELECT CASE(TRIM(td_file%c_type))
CASE('cdf')
WRITE(*,'((/3x,a,a),(/3x,a,i3))')&
& "define mode : ",TRIM(fct_str(td_file%l_def)),&
& "unlimited id : ",td_file%i_uldid
CASE('dimg')
WRITE(*,'(5(/3x,a,i0))')&
& " record length : ",td_file%i_recl, &
& " n0d : ",td_file%i_n0d, &
& " n1d : ",td_file%i_n1d, &
& " n2d : ",td_file%i_n2d, &
& " n3d : ",td_file%i_n3d
END SELECT
! print dimension
IF( td_file%i_ndim /= 0 )THEN
WRITE(*,'(/a)') " File dimension"
DO ji=1,ip_maxdim
IF( td_file%t_dim(ji)%l_use )THEN
CALL dim_print(td_file%t_dim(ji))
ENDIF
ENDDO
ENDIF
! print global attribute
IF( td_file%i_natt /= 0 )THEN
WRITE(*,'(/a)') " File attribute"
DO ji=1,td_file%i_natt
CALL att_print(td_file%t_att(ji))
ENDDO
ENDIF
! print variable
IF( td_file%i_nvar /= 0 )THEN
WRITE(*,'(/a)') " File variable"
DO ji=1,td_file%i_nvar
CALL var_print(td_file%t_var(ji))!,.FALSE.)
ENDDO
ENDIF
END SUBROUTINE file_print
!> @endcode
!-------------------------------------------------------------------
!> @brief This function get suffix of file name.
!> @details
!> we assume suffix is define as alphanumeric character following the
!> last '.' in file name
!> If no suffix is found, return empty character.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] cd_file : file structure
!> @return suffix
!-------------------------------------------------------------------
!> @code
CHARACTER(LEN=lc) FUNCTION file__get_suffix(cd_file)
IMPLICIT NONE
! Argument
CHARACTER(LEN=*), INTENT(IN) :: cd_file
! local variable
INTEGER(i4) :: il_ind
!----------------------------------------------------------------
CALL logger_trace( "GET SUFFIX: look for suffix in file name "//&
& TRIM(cd_file) )
il_ind=INDEX(TRIM(cd_file),'.',BACK=.TRUE.)
IF( il_ind /= 0 )THEN
! read number in basename
READ( cd_file(il_ind:),'(a)' ) file__get_suffix
IF( fct_is_num(file__get_suffix) )THEN
file__get_suffix=''
ENDIF
ELSE
file__get_suffix=''
ENDIF
END FUNCTION file__get_suffix
!> @endcode
!-------------------------------------------------------------------
!> @brief This function get number in file name without suffix.
!> @details
!> Actually it get the number following the last separator.
!> separator could be '.' or '_'
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] cd_file : file name (without suffix)
!> @return file structure
!-------------------------------------------------------------------
!> @code
CHARACTER(LEN=lc) FUNCTION file__get_number(cd_file)
IMPLICIT NONE
! Argument
CHARACTER(LEN=lc), INTENT(IN) :: cd_file
! local variable
INTEGER(i4) :: il_indmax
INTEGER(i4) :: il_ind
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! get number position in file name
il_indmax=0
DO ji=1,ig_nsep
il_ind=INDEX(TRIM(cd_file),TRIM(cg_sep(ji)),BACK=.TRUE.)
IF( il_ind > il_indmax )THEN
il_indmax=il_ind
ENDIF
ENDDO
IF( il_indmax /= 0 )THEN
! read number in basename
READ( cd_file(il_indmax:),'(a)' ) file__get_number
IF( .NOT. fct_is_num(file__get_number(2:)) )THEN
file__get_number=''
ENDIF
ELSE
file__get_number=''
ENDIF
END FUNCTION file__get_number
!> @endcode
!-------------------------------------------------------------------
!> @brief This function rename file name.
!> @details
!> If no processor number is given, return file name without number
!> If processor number is given, return file name with new number
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] id_num : processor number (start to 1)
!> @return file structure
!-------------------------------------------------------------------
!> @code
CHARACTER(LEN=lc) FUNCTION file__rename_char(cd_file, id_num)
IMPLICIT NONE
! Argument
CHARACTER(LEN=*), INTENT(IN) :: cd_file
INTEGER(i4), INTENT(IN), OPTIONAL :: id_num
! local variable
CHARACTER(LEN=lc) :: cl_suffix
CHARACTER(LEN=lc) :: cl_file
CHARACTER(LEN=lc) :: cl_number
CHARACTER(LEN=lc) :: cl_base
CHARACTER(LEN=lc) :: cl_sep
CHARACTER(LEN=lc) :: cl_format
INTEGER(i4) :: il_ind
INTEGER(i4) :: il_numlen
!----------------------------------------------------------------
! get suffix
cl_suffix=file__get_suffix(cd_file)
IF( TRIM(cl_suffix) /= '' )THEN
il_ind=INDEX(TRIM(cd_file),TRIM(cl_suffix(1:1)),BACK=.TRUE.)
cl_file=TRIM(cd_file(:il_ind-1))
ELSE
cl_file=TRIM(cd_file)
ENDIF
cl_number=file__get_number(cl_file)
IF( TRIM(cl_number) /= '' )THEN
il_ind=INDEX(TRIM(cl_file),TRIM(cl_number(1:1)),BACK=.TRUE.)
cl_base=TRIM(cl_file(:il_ind-1))
cl_sep=TRIM(cl_number(1:1))
il_numlen=LEN(TRIM(cl_number))-1
ELSE
cl_base=TRIM(cl_file)
il_numlen=4
cl_sep='_'
ENDIF
IF( PRESENT(id_num) )THEN
! format
WRITE(cl_format,'(a,i1.1,a,i1.1,a)') '(a,a,i',il_numlen,'.',il_numlen,',a)'
WRITE(file__rename_char,cl_format) TRIM(cl_base),TRIM(cl_sep),id_num,TRIM(cl_suffix)
ELSE
WRITE(file__rename_char,'(a,a)') TRIM(cl_base),TRIM(cl_suffix)
ENDIF
CALL logger_trace(" RENAME : "//TRIM(file__rename_char))
END FUNCTION file__rename_char
!> @endcode
!-------------------------------------------------------------------
!> @brief This function rename file name, given file structure.
!> @details
!> If no processor number is given, return file name without number
!> I processor number is given, return file name with new number
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @param[in] id_num : processor number (start to 1)
!> @return file structure
!-------------------------------------------------------------------
!> @code
TYPE(TFILE) FUNCTION file__rename_str(td_file, id_num)
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(IN) :: td_file
INTEGER(i4), INTENT(IN), OPTIONAL :: id_num
! local variable
CHARACTER(LEN=lc) :: cl_name
!----------------------------------------------------------------
! change name
cl_name=TRIM( file_rename(td_file%c_name, id_num) )
file__rename_str=file_init(TRIM(cl_name), TRIM(td_file%c_type))
END FUNCTION file__rename_str
!> @endcode
!-------------------------------------------------------------------
!> @brief This function add suffix to file name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!> @return file structure
!-------------------------------------------------------------------
!> @code
CHARACTER(LEN=lc) FUNCTION file_add_suffix(cd_file, cd_type)
IMPLICIT NONE
! Argument
CHARACTER(LEN=*), INTENT(IN) :: cd_file
CHARACTER(LEN=*), INTENT(IN) :: cd_type
! local variable
INTEGER(i4) :: il_ind
CHARACTER(LEN=lc) :: cl_file
CHARACTER(LEN=lc) :: cl_suffix
!----------------------------------------------------------------
! get suffix
cl_suffix=file__get_suffix(cd_file)
IF( TRIM(cl_suffix) /= '' )THEN
il_ind=INDEX(TRIM(cd_file),TRIM(cl_suffix(1:1)),BACK=.TRUE.)
cl_file=TRIM(cd_file(:il_ind-1))
ELSE
cl_file=TRIM(cd_file)
ENDIF
SELECT CASE(TRIM(cd_type))
CASE('cdf')
file_add_suffix=TRIM(cl_file)//'.nc'
CASE('dimg')
IF( TRIM(cl_suffix) /= '' )THEN
file_add_suffix=TRIM(cl_file)//'.dimg'
ELSE
file_add_suffix=TRIM(cl_file)
ENDIF
CASE DEFAULT
CALL logger_error( " ADD SUFFIX: type unknown "//TRIM(cd_type) )
END SELECT
END FUNCTION file_add_suffix
!> @endcode
!-------------------------------------------------------------------
!> @brief
!> This subroutine clean mpp strcuture.
!
!> @author J.Paul
!> @date Nov, 2013
!
!> @param[inout] td_mpp : mpp strcuture
!-------------------------------------------------------------------
!> @code
SUBROUTINE file_clean( td_file )
IMPLICIT NONE
! Argument
TYPE(TFILE), INTENT(INOUT) :: td_file
! local variable
TYPE(TFILE) :: tl_file ! empty file structure
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
CALL logger_info( &
& " CLEAN: reset file "//TRIM(td_file%c_name) )
! del attribute
IF( ASSOCIATED( td_file%t_att ) )THEN
DO ji=td_file%i_natt,1,-1
CALL att_clean( td_file%t_att(ji) )
ENDDO
DEALLOCATE( td_file%t_att )
ENDIF
! del dimension
IF( td_file%i_ndim /= 0 )THEN
DO ji=td_file%i_ndim,1,-1
CALL dim_clean( td_file%t_dim(ji) )
ENDDO
ENDIF
! del variable
IF( ASSOCIATED( td_file%t_var ) )THEN
DO ji=td_file%i_nvar,1,-1
CALL var_clean( td_file%t_var(ji) )
ENDDO
DEALLOCATE( td_file%t_var )
ENDIF
! replace by empty structure
td_file=tl_file
END SUBROUTINE file_clean
!> @endcode
!-------------------------------------------------------------------
!> @brief This function return the file id, in a table of file
!> structure, given file name
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : table of file structure
!> @param[in] cd_name : file name
!> @return file id in table of file structure (0 if not found)
!-------------------------------------------------------------------
!> @code
INTEGER(i4) FUNCTION file_get_id(td_file, cd_name)
IMPLICIT NONE
! Argument
TYPE(TFILE) , DIMENSION(:), INTENT(IN) :: td_file
CHARACTER(LEN=*), INTENT(IN) :: cd_name
! local variable
INTEGER(i4) :: il_size
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
file_get_id=0
il_size=SIZE(td_file(:))
! check if file is in table of file structure
DO ji=1,il_size
! look for file name
CALL logger_debug(" cd_name "//TRIM(fct_lower(cd_name)) )
IF( fct_lower(td_file(ji)%c_name) == fct_lower(cd_name) )THEN
file_get_id=ji
EXIT
ENDIF
ENDDO
END FUNCTION file_get_id
!> @endcode
END MODULE file