Index: trunk/LMDZ.TITAN/libf/muphytitan/fsystem.F90
===================================================================
--- trunk/LMDZ.TITAN/libf/muphytitan/fsystem.F90	(revision 1793)
+++ trunk/LMDZ.TITAN/libf/muphytitan/fsystem.F90	(revision 1897)
@@ -1,5 +1,5 @@
-! Copyright Jérémie Burgalat (2010-2015)
+! Copyright Jérémie Burgalat (2010-2015,2017)
 ! 
-! burgalat.jeremie@gmail.com
+! jeremie.burgalat@univ-reims.fr
 ! 
 ! This software is a computer program whose purpose is to provide configuration 
@@ -33,7 +33,8 @@
 
 !! file: fsystem.F90
-!! summary: File system methods source file
-!! date: 2013-2015
-!! author: Burgalat
+!! summary: File system methods source file.
+!! author: J. Burgalat
+!! date: 2013-2015,2017
+
 
 #include "defined.h"
@@ -48,10 +49,31 @@
 
   PRIVATE :: get_umask
+  PRIVATE :: c2t
 
   INTEGER, PARAMETER :: MAX_PATH = 512 !! Maximum length of a path
 
-
+  TYPE, PUBLIC :: chrono
+    !! Define a simple chronometer
+    !!
+    !! This object can be used to get an approximation of the execution of some piece of code.
+    REAL(kind=8), PRIVATE    :: cpu_start = 0d0   
+      !! Starting CPU time
+    INTEGER(kind=8), PRIVATE :: clock_start = 0d0 
+      !! Starting clock time
+    LOGICAL, PRIVATE         :: on_run = .false.
+      !! Chrono running state.
+#if HAVE_FTNPROC
+    CONTAINS 
+      PROCEDURE :: is_running => chrono_is_running 
+      PROCEDURE :: start      => chrono_start
+      PROCEDURE :: stop       => chrono_stop
+      PROCEDURE :: reset      => chrono_reset
+      PROCEDURE :: get        => chrono_get
+#endif
+  END TYPE chrono
+
+#ifndef FORD_DOC
+  ! C interfaces
   INTERFACE
-
     FUNCTION strlen_c(s) RESULT(length) bind(C,name="strlen")
       !! Get length of C-string up to (but not including) the terminator
@@ -68,5 +90,5 @@
 
     FUNCTION errno_c() BIND(C,name="c_get_errno")
-      !! Get last error numbero
+      !! Get last error numero
       IMPORT C_INT
       INTEGER(kind=C_INT) :: errno_c !! Last errno
@@ -209,4 +231,12 @@
       INTEGER(kind=C_INT)                    :: mkdirp_c   !! 0 on success, last errno on failure 
     END FUNCTION mkdirp_c
+
+    FUNCTION copy_c(to,from) BIND(C,name="c_copy") 
+      !! Copy a file.
+      IMPORT c_char, C_INT
+      CHARACTER(kind=c_char), INTENT(in)  :: to(*)    !! Destination path.
+      CHARACTER(kind=c_char), INTENT(in)  :: from(*)  !! Input file path to copy.
+      INTEGER(kind=C_INT)                 :: copy_c !! 0 on success, 1 on failure.
+    END FUNCTION copy_c
 
     FUNCTION remove_c(path) BIND(C,name="c_remove") 
@@ -255,6 +285,26 @@
     END FUNCTION termsize_c
 
+    FUNCTION getCurrentRSS_c() BIND(C, name="c_getCurrentRSS")
+      !! Get the current resident set size memory in bytes.
+      IMPORT  C_SIZE_T
+      INTEGER(kind=C_SIZE_T) :: getCurrentRSS_c !! Current resident set size in bytes (0 if not available).
+    END FUNCTION getCurrentRSS_c 
+
+    FUNCTION getPeakRSS_c() BIND(C, name="c_getPeakRSS")
+      !! Get the peak resident set size memory in bytes.
+      IMPORT  C_SIZE_T
+      INTEGER(kind=C_SIZE_T) :: getPeakRSS_c !! Peak resident set size in bytes (0 if not available).
+    END FUNCTION getPeakRSS_c 
+
+    FUNCTION getSystemMemory_c(total,avail,free) BIND(C, name='c_getSystemMemory')
+      !! Get global memory informations.
+      IMPORT C_LONG_LONG,C_INT
+      INTEGER(kind=C_LONG_LONG), INTENT(out) :: total             !! Total available memory.
+      INTEGER(kind=C_LONG_LONG), INTENT(out) :: avail             !! Current available memory.
+      INTEGER(kind=C_LONG_LONG), INTENT(out) :: free              !! Current free memory.
+      INTEGER(kind=C_INT)                    :: getSystemMemory_c !! status, 0 on success, 1 otherwise. 
+    END FUNCTION getSystemMemory_c
   END INTERFACE
-
+#endif
 
   CONTAINS
@@ -291,5 +341,5 @@
     !! @attention
     !! The method does not free the underlying C string and it should be free using 
-    !! [[fsystem(module):free_c(interface)]] method.
+    !! the subroutine free_c(_cstr_).
     TYPE(C_PTR), INTENT(in) :: cstr
       !! A TYPE(C_PTR) that represent the pointer to the C char array.
@@ -476,4 +526,17 @@
     RETURN
   END FUNCTION fs_getcwd
+
+  FUNCTION fs_copy(input,output) RESULT(ret)
+    !! Copy input file into output file.
+    CHARACTER(len=*), INTENT(in)  :: input  !! Input file path to copy.
+    CHARACTER(len=*), INTENT(in)  :: output !! Output file path destination.
+    LOGICAL :: ret                          !! True on success, false otherwise.
+    IF (LEN_TRIM(input) == 0 .OR. LEN_TRIM(output) == 0 .OR. input == output) THEN
+      ret = .false.
+    ELSE
+      ret = INT(copy_c(cstring(ADJUSTL(output)),cstring(ADJUSTL(input)))) == 0
+    ENDIF
+    RETURN
+  END FUNCTION fs_copy
 
   FUNCTION fs_remove(path) RESULT(ret)
@@ -880,4 +943,69 @@
   END SUBROUTINE fs_msleep
 
+  FUNCTION fs_get_memory(peak,units) RESULT(mem)
+    !! Get the memory usage of the current process.
+    LOGICAL, INTENT(in), OPTIONAL          :: peak  !! True to retrieve the peak RSS memory, otherwise retrieve the current RSS memory. Default to False.
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: units !! Output units: either 'B' (Bytes),'KB' (Kilo-),'MB' (Mega-),'GB' (Giga-). Default to 'B'.
+    REAL(kind=8)                           :: mem   !! Memory usage.
+    LOGICAL          :: zpeak
+    CHARACTER(len=2) :: zunits
+    zpeak = .false. ; IF (PRESENT(peak)) zpeak = peak
+    zunits = 'B '   ; IF (PRESENT(units)) zunits = units
+    IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B '
+    IF (zpeak) THEN
+      mem = REAL(getPeakRSS_c(),kind=8)
+    ELSE
+      mem = REAL(getCurrentRSS_c(),kind=8)
+    ENDIF
+    IF (zunits == 'KB') THEN
+      mem = mem / 1024d0
+    ELSE IF (zunits == 'MB') THEN
+      mem = mem / 1048576d0
+    ELSE IF (zunits == 'GB') THEN
+      mem = mem / 1073741824d0
+    ENDIF
+    RETURN
+  END FUNCTION fs_get_memory
+
+  FUNCTION fs_get_system_memory(total,available,free,units) RESULT(ret)
+    !! Get informations about system memory.
+    !!
+    !! If no informations is available, output arguments are set to 0 and the method returns false.
+    REAL(kind=8), INTENT(out), OPTIONAL    :: total      !! Total available memory.
+    REAL(kind=8), INTENT(out), OPTIONAL    :: available  !! Current available memory.
+    REAL(kind=8), INTENT(out), OPTIONAL    :: free       !! Current free memory.
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: units      !! Output units: either 'B' (Bytes),'KB' (Kilo-),'MB' (Mega-),'GB' (Giga-). Default to 'B'.
+    LOGICAL                                :: ret        !! True on success, false otherwise.
+    LOGICAL          :: zpeak
+    CHARACTER(len=2) :: zunits
+    INTEGER(kind=8)  :: ztot,zava,zfre    
+
+    zunits = 'B '   ; IF (PRESENT(units)) zunits = units
+    IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B '
+    ret = INT(getSystemMemory_c(ztot,zava,zfre),kind=4) == 0
+    ztot = ztot * 1024 ; zava = zava * 1024 ; zfre = zfre * 1024 
+
+    IF (PRESENT(total))     total     = ztot
+    IF (PRESENT(available)) available = zava
+    IF (PRESENT(free))      free      = zfre
+    IF (.NOT.ret) RETURN
+
+    IF (zunits == 'KB') THEN
+      IF (PRESENT(total))     total     = ztot / 1024d0
+      IF (PRESENT(available)) available = zava / 1024d0
+      IF (PRESENT(free))      free      = zfre / 1024d0
+    ELSE IF (zunits == 'MB') THEN
+      IF (PRESENT(total))     total     = ztot / 1048576d0
+      IF (PRESENT(available)) available = zava / 1048576d0
+      IF (PRESENT(free))      free      = zfre / 1048576d0
+    ELSE IF (zunits == 'GB') THEN
+      IF (PRESENT(total))     total     = ztot / 1073741824d0
+      IF (PRESENT(available)) available = zava / 1073741824d0
+      IF (PRESENT(free))      free      = zfre / 1073741824d0
+    ENDIF
+    RETURN
+  END FUNCTION fs_get_system_memory
+
+
 !===============================================================================
 ! MODULE MISCELLANEOUS METHODS
@@ -1032,3 +1160,102 @@
   END FUNCTION sz2str
 
+  FUNCTION chrono_is_running(this) RESULT (ret)
+    !! Get chrono's state.
+    OBJECT(chrono), INTENT(in) :: this !! Chrono object reference.
+    LOGICAL :: ret                    !! Running state.
+    ret = this%on_run
+    RETURN
+  END FUNCTION chrono_is_running
+
+  SUBROUTINE chrono_start(this)
+    !! Start the chrono. 
+    !!
+    !! @note
+    !! Calling the method multiple times without explicitly stopping the chrono
+    !! [[chrono(type):stop(bound)]] does nothing (except for the first called).
+    OBJECT(chrono), INTENT(inout) :: this  !! Chrono object reference.
+    IF (.NOT.this%on_run) THEN
+      CALL CPU_TIME(this%cpu_start)
+      CALL SYSTEM_CLOCK(this%clock_start)
+    ENDIF
+    this%on_run = .true.
+  END SUBROUTINE chrono_start 
+
+  SUBROUTINE chrono_stop(this)
+    !! Stop the chrono.
+    OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference.
+    REAL(kind=8)    :: ecpu
+    INTEGER(kind=8) :: eclk,nbm,nbr
+    this%on_run = .false.
+  END SUBROUTINE chrono_stop
+
+  SUBROUTINE chrono_reset(this)
+    !! Reset the chrono's internal elapsed times.
+    OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference.
+    CALL CPU_TIME(this%cpu_start)
+    CALL SYSTEM_CLOCK(this%clock_start)
+  END SUBROUTINE chrono_reset
+
+  SUBROUTINE chrono_get(this,cpu,clock,units) 
+    !! Get elapsed time since last call of start or reset methods.
+    !! 
+    !! The method computes the time elapsed in two ways :
+    !!
+    !! - If the [[fsystem(module):chrono(type)]] is not running, the method retruns 0.
+    !! - Otherwise, elapsed time since the last call of 
+    !!   [[chrono(type):start(bound)]] (or [[chrono(type):reset(bound)]]).
+    OBJECT(chrono), INTENT(in)             :: this
+      !! Chrono object reference.
+    REAL(kind=8), INTENT(out), OPTIONAL    :: cpu
+      !! Elapsed cpu time in seconds by default (see units argument).
+    REAL(kind=8), INTENT(out), OPTIONAL    :: clock 
+      !! Elapsed system clock time in seconds by default (see units argument).
+    CHARACTER(len=2), INTENT(in), OPTIONAL :: units
+      !! A two characters wide string with the units to convert in. Units should
+      !! be one of the following : 'ms', 's' (default), 'm', 'h' or 'd'. 
+    CHARACTER(len=2) :: zu
+    REAL(kind=8)     :: cu, fact
+    INTEGER(kind=8)  :: ck, r, m
+    IF (this%on_run) THEN
+      IF (PRESENT(cpu)) THEN
+        CALL CPU_TIME(cu)
+        cpu = (cu - this%cpu_start)
+      ENDIF
+      IF (PRESENT(clock)) THEN
+        CALL SYSTEM_CLOCK(ck,r,m) 
+        clock = c2t(ck,this%clock_start,r,m)
+      ENDIF
+    ELSE
+      IF (PRESENT(cpu))   cpu = 0d0
+      IF (PRESENT(clock)) clock = 0d0
+    ENDIF
+    fact = 1d0
+    zu = 's' 
+    IF (PRESENT(units))  THEN
+      zu = units
+      SELECT CASE(zu)
+        CASE ('d') ; fact = 3600d0*24.
+        CASE ('h') ; fact = 3600d0
+        CASE ('m') ; fact = 60d0
+        CASE ('ms') ; fact = 1d-3
+        CASE DEFAULT ; fact = 1d0
+      END SELECT
+    ENDIF
+    IF (PRESENT(cpu)) cpu = cpu / fact 
+    IF (PRESENT(clock)) clock = clock / fact
+  END SUBROUTINE chrono_get
+
+  FUNCTION c2t(e,i,r,m) RESULT(time)
+    !! Get the real-time between two clock counts from system_clock.
+    INTEGER(kind=8), INTENT(in) :: e !! Final clock count
+    INTEGER(kind=8), INTENT(in) :: i !! Initial clock count 
+    INTEGER(kind=8), INTENT(in) :: r !! Clock count rate
+    INTEGER(kind=8), INTENT(in) :: m !! Maximum Clock count value
+    REAL(kind=8)    :: time          !! Time in seconds
+    INTEGER(kind=8) :: nc
+    nc = e-i ; IF (e < i) nc = nc+m
+    time = REAL(nc,kind=8)/r
+    RETURN
+  END FUNCTION c2t
 END MODULE FSYSTEM
+
