MODULE utility !----------------------------------------------------------------------- ! NAME ! utility ! ! DESCRIPTION ! Contains some utility functions. ! ! AUTHORS & DATE ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use numerics, only: dp, qp, di, li, k4, minieps ! DECLARATION ! ----------- implicit none ! INTERFACES ! ---------- interface int2str module procedure int2str_di, int2str_li end interface int2str interface real2str module procedure real2str_dp, real2str_qp end interface real2str contains !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ !======================================================================= FUNCTION int2str_di(i) RESULT(str) !----------------------------------------------------------------------- ! NAME ! int2str_di ! ! DESCRIPTION ! Convert a default integer into a string. ! ! AUTHORS & DATE ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use stoppage, only: stop_clean ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- integer(di), intent(in) :: i ! LOCAL VARIABLES ! --------------- character(20) :: str_tmp character(:), allocatable :: str ! CODE ! ---- if (nb_digits(real(i,dp)) > len(str_tmp)) call stop_clean(__FILE__,__LINE__,'invalid integer for conversion!',1) write(str_tmp,'(i0)') i str = trim(adjustl(str_tmp)) END FUNCTION int2str_di !======================================================================= !======================================================================= FUNCTION int2str_li(i) RESULT(str) !----------------------------------------------------------------------- ! NAME ! int2str_li ! ! DESCRIPTION ! Convert a long integer into a string. ! ! AUTHORS & DATE ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use stoppage, only: stop_clean ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- integer(li), intent(in) :: i ! LOCAL VARIABLES ! --------------- character(20) :: str_tmp character(:), allocatable :: str ! CODE ! ---- if (nb_digits(real(i,dp)) > len(str_tmp)) call stop_clean(__FILE__,__LINE__,'invalid integer for conversion!',1) write(str_tmp,'(i0)') i str = trim(adjustl(str_tmp)) END FUNCTION int2str_li !======================================================================= !======================================================================= FUNCTION real2str_dp(x,frmt) RESULT(str) !----------------------------------------------------------------------- ! NAME ! real2str_dp ! ! DESCRIPTION ! Convert a double precision real into a string. ! ! AUTHORS & DATE ! JB Clement, 02/2026 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use stoppage, only: stop_clean ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), intent(in) :: x character(*), intent(in), optional :: frmt ! LOCAL VARIABLES ! --------------- !~ integer(di) :: len_trimmed character(32) :: str_tmp character(:), allocatable :: str ! CODE ! ---- if (present(frmt)) then write(str_tmp,frmt) x else write(str_tmp,'(G0)') x end if !~ ! Remove trailing zeros after decimal !~ len_trimmed = len_trim(tmp) !~ do while (len_trimmed > 0) !~ if (str_tmp(len_trimmed:len_trimmed) == '0' .or. str_tmp(len_trimmed:len_trimmed) == ' ') then !~ len_trimmed = len_trimmed - 1 !~ else !~ exit !~ end if !~ end do !~ str = str_tmp(1:len_trimmed) str = trim(adjustl(str_tmp)) END FUNCTION real2str_dp !======================================================================= !======================================================================= FUNCTION real2str_qp(x,frmt) RESULT(str) !----------------------------------------------------------------------- ! NAME ! real2str_qp ! ! DESCRIPTION ! Convert a quadruple precision real into a string. ! ! AUTHORS & DATE ! JB Clement, 02/2026 ! ! NOTES ! !----------------------------------------------------------------------- ! DEPENDENCIES ! ------------ use stoppage, only: stop_clean ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(qp), intent(in) :: x character(*), intent(in), optional :: frmt ! LOCAL VARIABLES ! --------------- !~ integer(di) :: len_trimmed character(32) :: str_tmp character(:), allocatable :: str ! CODE ! ---- if (present(frmt)) then write(str_tmp,frmt) x else write(str_tmp,'(G0)') x end if !~ ! Remove trailing zeros after decimal !~ len_trimmed = len_trim(tmp) !~ do while (len_trimmed > 0) !~ if (str_tmp(len_trimmed:len_trimmed) == '0' .or. str_tmp(len_trimmed:len_trimmed) == ' ') then !~ len_trimmed = len_trimmed - 1 !~ else !~ exit !~ end if !~ end do !~ str = str_tmp(1:len_trimmed) str = trim(adjustl(str_tmp)) END FUNCTION real2str_qp !======================================================================= !======================================================================= FUNCTION bool2str(l) RESULT(str) !----------------------------------------------------------------------- ! NAME ! bool2str ! ! DESCRIPTION ! Convert a logical into a string. ! ! AUTHORS & DATE ! JB Clement, 02/2026 ! ! NOTES ! !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- logical(k4), intent(in) :: l ! LOCAL VARIABLES ! --------------- character(5) :: str ! CODE ! ---- str = merge('true ','false',l) END FUNCTION bool2str !======================================================================= !======================================================================= FUNCTION nb_digits(x) RESULT(idigits) !----------------------------------------------------------------------- ! NAME ! nb_digits ! ! DESCRIPTION ! Give the number of digits for the integer part of a real number. ! ! AUTHORS & DATE ! JB Clement, 2023-2025 ! ! NOTES ! !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), intent(in) :: x ! LOCAL VARIABLES ! --------------- integer(di) :: idigits ! CODE ! ---- idigits = 1 ! If x /= 0 then: if (abs(x) >= minieps) idigits = int(log10(abs(x))) + 1 END FUNCTION nb_digits !======================================================================= !======================================================================= FUNCTION format_duration(secs) RESULT(str) !----------------------------------------------------------------------- ! NAME ! format_duration ! ! DESCRIPTION ! Converts a duration in seconds into a compact Xd HH:MM:SS format. ! ! AUTHORS & DATE ! JB Clement, 01/2026 ! ! NOTES ! !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- real(dp), intent(in) :: secs ! LOCAL VARIABLES ! --------------- integer(di) :: days, hours, minutes, seconds character(:), allocatable :: str character(32) :: tmp ! Work buffer ! CODE ! ---- days = int(secs/86400._dp,di) hours = int(mod(secs,86400._dp)/3600._dp,di) minutes = int(mod(secs,3600._dp)/60._dp,di) seconds = int(mod(secs,60._dp),di) if (days > 0_li) then write(tmp,'(i0,"d ",i2.2,":",i2.2,":",i2.2)') days, hours, minutes, seconds else write(tmp,'(i2.2,":",i2.2,":",i2.2)') hours, minutes, seconds end if str = trim(adjustl(tmp)) END FUNCTION format_duration !======================================================================= !======================================================================= FUNCTION is_id_1st_char(c) RESULT(valid_c) !----------------------------------------------------------------------- ! NAME ! is_id_1st_char ! ! DESCRIPTION ! Detects valid first character for Fortran identifer. ! ! AUTHORS & DATE ! JB Clement, 01/2026 ! ! NOTES ! A variable name is a Fortran identifier if it starts with a letter ! or _ and followed by letters, digits or _. !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- character(1), intent(in) :: c ! LOCAL VARIABLES ! --------------- logical(k4) :: valid_c ! CODE ! ---- valid_c = ('A' <= c .and. c <= 'Z') .or. ('a' <= c .and. c <= 'z') .or. (c == '_') END FUNCTION is_id_1st_char !======================================================================= !======================================================================= FUNCTION is_id_char(c) RESULT(valid_c) !----------------------------------------------------------------------- ! NAME ! is_id_char ! ! DESCRIPTION ! Detects valid character for Fortran identifer. ! ! AUTHORS & DATE ! JB Clement, 01/2026 ! ! NOTES ! A variable name is a Fortran identifier if it starts with a letter ! or _ and followed by letters, digits or _. !----------------------------------------------------------------------- ! DECLARATION ! ----------- implicit none ! ARGUMENTS ! --------- character(1), intent(in) :: c ! LOCAL VARIABLES ! --------------- logical(k4) :: valid_c ! CODE ! ---- valid_c = is_id_1st_char(c) .or. ('0' <= c .and. c <= '9') END FUNCTION is_id_char !======================================================================= END MODULE utility