!---------------------------------------------------------------------- ! 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