!---------------------------------------------------------------------- ! NEMO system team, System and Interface for oceanic RElocable Nesting !---------------------------------------------------------------------- ! ! MODULE: fct ! ! DESCRIPTION: !> @brief !> This module group some basic useful function ! !> @author !> J.Paul ! REVISION HISTORY: !> @date Nov, 2013 - Initial Version ! !> @todo !> - TODO_describe_appropriate_changes - TODO_name !> @param MyModule_type : brief_description ! !> @note Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt) !---------------------------------------------------------------------- MODULE fct USE kind ! F90 kind parameter IMPLICIT NONE PRIVATE ! NOTE_avoid_public_variables_if_possible ! function and subroutine PUBLIC :: OPERATOR(//) PUBLIC :: fct_getunit! returns free unit number PUBLIC :: fct_err ! handle fortran error status PUBLIC :: fct_str ! convert numeric to string character PUBLIC :: fct_concat ! concatenate all the element of a character table PUBLIC :: fct_upper ! convert lower character to upper case PUBLIC :: fct_lower ! convert upper character to lower case PUBLIC :: fct_is_num ! check if character is numeric PUBLIC :: fct_split ! split string into substring PUBLIC :: fct_basename ! return basename (name without path) PUBLIC :: fct_dirname ! return dirname (path without name) PRIVATE :: fct__i1_str ! convert integer(1) to string character PRIVATE :: fct__i2_str ! convert integer(2) to string character PRIVATE :: fct__i4_str ! convert integer(4) to string character PRIVATE :: fct__i8_str ! convert integer(8) to string character PRIVATE :: fct__r4_str ! convert real(4) to string character PRIVATE :: fct__r8_str ! convert real(8) to string character PRIVATE :: fct__l_str ! convert logical to string character INTERFACE fct_str MODULE PROCEDURE fct__i1_str ! convert integer(1) to string character MODULE PROCEDURE fct__i2_str ! convert integer(2) to string character MODULE PROCEDURE fct__i4_str ! convert integer(4) to string character MODULE PROCEDURE fct__i8_str ! convert integer(8) to string character MODULE PROCEDURE fct__r4_str ! convert real(4) to string character MODULE PROCEDURE fct__r8_str ! convert real(8) to string character MODULE PROCEDURE fct__l_str ! convert logical to string character END INTERFACE fct_str INTERFACE OPERATOR(//) MODULE PROCEDURE fct__i4_cat ! concatenate integer(4) to string character MODULE PROCEDURE fct__i8_cat ! concatenate integer(8) to string character MODULE PROCEDURE fct__r4_cat ! concatenate real(4) to string character MODULE PROCEDURE fct__r8_cat ! concatenate real(8) to string character MODULE PROCEDURE fct__l_cat ! concatenate logical to string character END INTERFACE CONTAINS !------------------------------------------------------------------- !> @brief This routine concatenate character and integer(4) (as character). ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @return string character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__i4_cat(cd_char, id_val) ! arguments CHARACTER(LEN=lc), INTENT(IN) :: cd_char INTEGER(i4), INTENT(IN) :: id_val ! local variable CHARACTER(LEN=lc) :: cl_val !---------------------------------------------------------------- cl_val = fct_str(id_val) fct__i4_cat=TRIM(cd_char)//TRIM(cl_val) END FUNCTION fct__i4_cat ! @endcode !------------------------------------------------------------------- !> @brief This routine concatenate character and integer(8) (as character). ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @return string character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__i8_cat(cd_char, kd_val) ! arguments CHARACTER(LEN=lc), INTENT(IN) :: cd_char INTEGER(i8), INTENT(IN) :: kd_val ! local variable CHARACTER(LEN=lc) :: cl_val !---------------------------------------------------------------- cl_val = fct_str(kd_val) fct__i8_cat=TRIM(cd_char)//TRIM(cl_val) END FUNCTION fct__i8_cat ! @endcode !------------------------------------------------------------------- !> @brief This routine concatenate character and real(4) (as character). ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @return string character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__r4_cat(cd_char, rd_val) ! arguments CHARACTER(LEN=lc), INTENT(IN) :: cd_char REAL(sp), INTENT(IN) :: rd_val ! local variable CHARACTER(LEN=lc) :: cl_val !---------------------------------------------------------------- cl_val = fct_str(rd_val) fct__r4_cat=TRIM(cd_char)//TRIM(cl_val) END FUNCTION fct__r4_cat ! @endcode !------------------------------------------------------------------- !> @brief This routine concatenate character and real(8) (as character). ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @return string character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__r8_cat(cd_char, dd_val) ! arguments CHARACTER(LEN=lc), INTENT(IN) :: cd_char REAL(dp), INTENT(IN) :: dd_val ! local variable CHARACTER(LEN=lc) :: cl_val !---------------------------------------------------------------- cl_val = fct_str(dd_val) fct__r8_cat=TRIM(cd_char)//TRIM(cl_val) END FUNCTION fct__r8_cat ! @endcode !------------------------------------------------------------------- !> @brief This routine concatenate character and logical (as character). ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @return string character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__l_cat(cd_char, ld_val) ! arguments CHARACTER(LEN=lc), INTENT(IN) :: cd_char LOGICAL, INTENT(IN) :: ld_val ! local variable CHARACTER(LEN=lc) :: cl_val !---------------------------------------------------------------- cl_val = fct_str(ld_val) fct__l_cat=TRIM(cd_char)//TRIM(cl_val) END FUNCTION fct__l_cat ! @endcode !------------------------------------------------------------------- !> @brief This routine returns the next available I/O unit number. ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @return file id !------------------------------------------------------------------- ! @code INTEGER(i4) FUNCTION fct_getunit() ! local variable LOGICAL :: ll_opened !---------------------------------------------------------------- ! initialise fct_getunit = 10 INQUIRE(UNIT=fct_getunit, OPENED=ll_opened) DO WHILE( ll_opened ) fct_getunit = fct_getunit + 1 INQUIRE(UNIT=fct_getunit, OPENED=ll_opened) ENDDO END FUNCTION fct_getunit ! @endcode !------------------------------------------------------------------- !> @brief This routine handle Fortran status. ! !> @author J.Paul !> - Nov, 2013- Initial Version !------------------------------------------------------------------- ! @code SUBROUTINE fct_err(id_status) ! Argument INTEGER(i4), INTENT(IN) :: id_status !---------------------------------------------------------------- IF( id_status /= 0 )THEN !CALL ERRSNS() ! not F95 standard PRINT *, "FORTRAN ERROR" !STOP ENDIF END SUBROUTINE fct_err ! @endcode !------------------------------------------------------------------- !> @brief This function convert logical to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] ld_var : logical variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__l_str(ld_var) IMPLICIT NONE ! Argument LOGICAL, INTENT(IN) :: ld_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) ld_var fct__l_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__l_str ! @endcode !------------------------------------------------------------------- !> @brief This function convert integer(1) to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] bd_var : integer(1) variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__i1_str(bd_var) IMPLICIT NONE ! Argument INTEGER(i1), INTENT(IN) :: bd_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) bd_var fct__i1_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__i1_str ! @endcode !------------------------------------------------------------------- !> @brief This function convert integer(2) to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] sd_var : integer(2) variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__i2_str(sd_var) IMPLICIT NONE ! Argument INTEGER(i2), INTENT(IN) :: sd_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) sd_var fct__i2_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__i2_str ! @endcode !------------------------------------------------------------------- !> @brief This function convert integer(4) to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] id_var : integer(4) variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__i4_str(id_var) IMPLICIT NONE ! Argument INTEGER(i4), INTENT(IN) :: id_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) id_var fct__i4_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__i4_str ! @endcode !------------------------------------------------------------------- !> @brief This function convert integer(8) to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] kd_var : integer(8) variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__i8_str(kd_var) IMPLICIT NONE ! Argument INTEGER(i8), INTENT(IN) :: kd_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) kd_var fct__i8_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__i8_str ! @endcode !------------------------------------------------------------------- !> @brief This function convert real(4) to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] rd_var : real(4) variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__r4_str(rd_var) IMPLICIT NONE ! Argument REAL(sp), INTENT(IN) :: rd_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) rd_var fct__r4_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__r4_str ! @endcode !------------------------------------------------------------------- !> @brief This function convert real(8) to string character. !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] dd_var : real(8) variable !> @return character of this integer variable !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct__r8_str(dd_var) IMPLICIT NONE ! Argument REAL(dp), INTENT(IN) :: dd_var ! local variable CHARACTER(LEN=lc) :: cl_tmp !---------------------------------------------------------------- write(cl_tmp,*) dd_var fct__r8_str=TRIM(ADJUSTL(cl_tmp)) END FUNCTION fct__r8_str ! @endcode !------------------------------------------------------------------- !> @brief This function concatenate all the element of a character table !> except unknown one, in a character string. !> !> optionnally a separator could be added between each element !> !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_tab : table of character !> @return character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct_concat(cd_tab,cd_sep) IMPLICIT NONE ! Argument CHARACTER(*), DIMENSION(:), INTENT(IN) :: cd_tab CHARACTER(*), INTENT(IN), OPTIONAL :: cd_sep ! local variable CHARACTER(LEN=lc) :: cl_tmp CHARACTER(LEN=lc) :: cl_sep INTEGER(i4) :: il_size ! loop indices INTEGER(i4) :: ji !---------------------------------------------------------------- cl_sep='' IF(PRESENT(cd_sep)) cl_sep=cd_sep il_size=SIZE(cd_tab) fct_concat='' cl_tmp='' DO ji=1,il_size !IF( TRIM(ADJUSTL(cd_tab(ji))) /= 'unknown' )THEN WRITE(cl_tmp,*) TRIM(fct_concat)//TRIM(ADJUSTL(cd_tab(ji)))//TRIM(cl_sep) !ENDIF fct_concat=TRIM(ADJUSTL(cl_tmp)) ENDDO END FUNCTION fct_concat ! @endcode !------------------------------------------------------------------- !> @brief This function convert string character upper case to lower case. ! !> @details !> The function IACHAR returns the ASCII value of the character passed !> as argument. The ASCII code has the uppercase alphabet starting at !> code 65, and the lower case one at code 101, therefore !> IACHAR('a')- IACHAR('A') would be the difference between the uppercase !> and the lowercase codes. ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_var : character !> @return lower case character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct_lower(cd_var) IMPLICIT NONE ! Argument CHARACTER(*), INTENT(IN) :: cd_var ! local variable INTEGER(i4) :: il_nletter ! number of letters in variable CHARACTER(LEN=lc) :: cl_var CHARACTER(LEN=lc), DIMENSION(:), ALLOCATABLE :: cl_tmp INTEGER(i4) :: il_icode ! ASCII value INTEGER(i4) :: il_lacode ! ASCII value of the lower case 'a' INTEGER(i4) :: il_uacode ! ASCII value of the upper case 'A' INTEGER(i4) :: il_uzcode ! ASCII value of the upper case 'z' ! loop indices INTEGER(i4) :: ji !---------------------------------------------------------------- il_lacode=IACHAR('a') il_uacode=IACHAR('A') il_uzcode=IACHAR('Z') cl_var=TRIM(ADJUSTL(cd_var)) il_nletter=LEN(TRIM(cl_var)) ALLOCATE(cl_tmp(il_nletter)) DO ji=1,il_nletter il_icode=IACHAR(cl_var(ji:ji)) IF( il_icode >= il_uacode .AND. il_icode <= il_uzcode )THEN ! upper case cl_tmp(ji)=TRIM(CHAR(il_icode + (il_lacode - il_uacode) )) ELSE ! lower case and other character cl_tmp(ji)=TRIM(CHAR(il_icode)) ENDIF ENDDO fct_lower=TRIM(ADJUSTL(fct_concat(cl_tmp(:)))) DEALLOCATE(cl_tmp) END FUNCTION fct_lower ! @endcode !------------------------------------------------------------------- !> @brief This function convert string character lower case to upper case. ! !> @details !> The function IACHAR returns the ASCII value of the character passed !> as argument. The ASCII code has the uppercase alphabet starting at !> code 65, and the lower case one at code 101, therefore !> IACHAR('a')- IACHAR('A') would be the difference between the uppercase !> and the lowercase codes. ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_var : character !> @return upper case character !------------------------------------------------------------------- ! @code PURE CHARACTER(LEN=lc) FUNCTION fct_upper(cd_var) IMPLICIT NONE ! Argument CHARACTER(*), INTENT(IN) :: cd_var ! local variable INTEGER(i4) :: il_nletter ! number of letters in cd_var CHARACTER(LEN=lc) :: cl_var CHARACTER(LEN=lc), DIMENSION(:), ALLOCATABLE :: cl_tmp INTEGER(i4) :: il_icode ! ASCII value INTEGER(i4) :: il_lacode ! ASCII value of the lower case 'a' INTEGER(i4) :: il_uacode ! ASCII value of the upper case 'A' INTEGER(i4) :: il_lzcode ! ASCII value of the lower case 'z' ! loop indices INTEGER(i4) :: ji !---------------------------------------------------------------- il_lacode=ICHAR('a') il_uacode=ICHAR('A') il_lzcode=IACHAR('z') cl_var=TRIM(ADJUSTL(cd_var)) il_nletter=LEN(TRIM(cl_var)) ALLOCATE(cl_tmp(il_nletter)) DO ji=1,il_nletter il_icode=IACHAR(cl_var(ji:ji)) IF( il_icode >= il_lacode .AND. il_icode <= il_lzcode )THEN ! lower case cl_tmp(ji)=CHAR(il_icode - (il_lacode - il_uacode) ) ELSE ! upper case and other character cl_tmp(ji)=CHAR(il_icode) ENDIF ENDDO fct_upper=TRIM(ADJUSTL(fct_concat(cl_tmp(:)))) DEALLOCATE(cl_tmp) END FUNCTION fct_upper ! @endcode !------------------------------------------------------------------- !> @brief This function check if character is numeric. ! !> @details ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_var : character !> @return character is numeric !------------------------------------------------------------------- ! @code PURE LOGICAL FUNCTION fct_is_num(cd_var) IMPLICIT NONE ! Argument CHARACTER(LEN=*), INTENT(IN) :: cd_var ! loop indices INTEGER(i4) :: ji !---------------------------------------------------------------- DO ji=1,LEN(TRIM(cd_var)) IF( IACHAR(cd_var(ji:ji)) >= IACHAR('0') .AND. & & IACHAR(cd_var(ji:ji)) <= IACHAR('9') )THEN fct_is_num=.TRUE. ELSE fct_is_num=.FALSE. EXIT ENDIF ENDDO END FUNCTION fct_is_num ! @endcode !------------------------------------------------------------------- !> @brief This function split string of character !> using separator character, by default '|', !> and return the element on index ind ! !> @details ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_string : string of character !> @param[in] id_ind : indice !> @param[in] cd_sep separator character !> @return return the element on index id_ind !------------------------------------------------------------------- ! @code PURE FUNCTION fct_split(cd_string, id_ind, cd_sep) IMPLICIT NONE ! Argument CHARACTER(LEN=*), INTENT(IN) :: cd_string INTEGER(i4) , INTENT(IN) :: id_ind CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cd_sep ! function CHARACTER(LEN=lc) :: fct_split ! local variable CHARACTER(LEN=lc) :: cl_sep CHARACTER(LEN=lc) :: cl_string INTEGER(i4) :: il_sep ! loop indices INTEGER(i4) :: ji !---------------------------------------------------------------- ! initialize fct_split='' cl_string=ADJUSTL(cd_string) ! get separator cl_sep='|' IF( PRESENT(cd_sep) ) cl_sep=TRIM(ADJUSTL(cd_sep)) ! get separator index il_sep=INDEX( TRIM(cl_string), TRIM(cl_sep) ) IF( il_sep /= 0 )THEN fct_split=TRIM(ADJUSTL(cl_string(1:il_sep-1))) ELSE fct_split=TRIM(ADJUSTL(cl_string)) ENDIF ji=1 DO WHILE( il_sep /= 0 .AND. ji /= id_ind ) ji=ji+1 cl_string=TRIM(cl_string(il_sep+1:)) il_sep=INDEX( TRIM(cl_string), TRIM(cl_sep) ) IF( il_sep /= 0 )THEN fct_split=TRIM(ADJUSTL(cl_string(1:il_sep-1))) ELSE fct_split=TRIM(ADJUSTL(cl_string)) ENDIF ENDDO IF( ji /= id_ind ) fct_split='' END FUNCTION fct_split ! @endcode !------------------------------------------------------------------- !> @brief This function return basename of a filename. ! !> @details !> actually it splits filename using sperarator '/' !> and return last string character ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_string : filename !> @return basename (filename without path) !------------------------------------------------------------------- ! @code PURE FUNCTION fct_basename(cd_string, cd_sep) IMPLICIT NONE ! Argument CHARACTER(LEN=*), INTENT(IN) :: cd_string CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cd_sep ! function CHARACTER(LEN=lc) :: fct_basename ! local variable CHARACTER(LEN=lc) :: cl_sep CHARACTER(LEN=lc) :: cl_string INTEGER(i4) :: il_sep ! loop indices !---------------------------------------------------------------- ! initialize cl_string=TRIM(ADJUSTL(cd_string)) ! get separator cl_sep='/' IF( PRESENT(cd_sep) ) cl_sep=TRIM(ADJUSTL(cd_sep)) il_sep=INDEX( TRIM(cl_string), TRIM(cl_sep), BACK=.TRUE.) fct_basename=TRIM(cl_string(il_sep+1:)) END FUNCTION fct_basename ! @endcode !------------------------------------------------------------------- !> @brief This function return dirname of a filename. ! !> @details !> actually it splits filename using sperarator '/' !> and return all exept last string character ! !> @author J.Paul !> - Nov, 2013- Initial Version ! !> @param[in] cd_string : filename !> @return dirname (path of the filename) !------------------------------------------------------------------- ! @code PURE FUNCTION fct_dirname(cd_string, cd_sep) IMPLICIT NONE ! Argument CHARACTER(LEN=*), INTENT(IN) :: cd_string CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cd_sep ! function CHARACTER(LEN=lc) :: fct_dirname ! local variable CHARACTER(LEN=lc) :: cl_sep CHARACTER(LEN=lc) :: cl_string INTEGER(i4) :: il_sep ! loop indices !---------------------------------------------------------------- ! initialize cl_string=TRIM(ADJUSTL(cd_string)) ! get separator cl_sep='/' IF( PRESENT(cd_sep) ) cl_sep=TRIM(ADJUSTL(cd_sep)) il_sep=INDEX( TRIM(cl_string), TRIM(cl_sep), BACK=.TRUE.) IF( il_sep == 0 )THEN fct_dirname='' ELSE fct_dirname=TRIM(cl_string(1:il_sep)) ENDIF END FUNCTION fct_dirname ! @endcode END MODULE fct