MODULE lmdz_checksum
  PRIVATE
  INTERFACE checksum
    MODULE PROCEDURE checksum_r0, checksum_r1, checksum_r2, checksum_r3, &
                     checksum_i0, checksum_i1, checksum_i2, checksum_i3, &
                     checksum_l0, checksum_l1, checksum_l2, checksum_l3
  END INTERFACE

  PUBLIC checksum

CONTAINS

  SUBROUTINE checksum_r0(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    REAL,INTENT(IN)             :: field
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i

    tot_sum=0
    intval=transfer(field,intval,2)
    tot_sum = tot_sum + intval(1) + intval(2)

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_r0

  SUBROUTINE checksum_r1(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    REAL,INTENT(IN)             :: field(:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i

    tot_sum=0
    DO i=1,SIZE(field,1)
      intval=transfer(field(i),intval,2)
      tot_sum = tot_sum + intval(1) + intval(2)
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_r1

  SUBROUTINE checksum_r2(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    REAL,INTENT(IN)             :: field(:,:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i,j

    tot_sum=0
    DO j=1,SIZE(field,2)
      DO i=1,SIZE(field,1)
        intval=transfer(field(i,j),intval,2)
        tot_sum = tot_sum + intval(1) + intval(2)
      ENDDO
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_r2

  SUBROUTINE checksum_r3(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    REAL,INTENT(IN)             :: field(:,:,:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i,j,k

    tot_sum=0
    DO k=1,SIZE(field,3)
      DO j=1,SIZE(field,2)
        DO i=1,SIZE(field,1)
          intval=transfer(field(i,j,k),intval,2)
          tot_sum = tot_sum + intval(1) + intval(2)
        ENDDO
      ENDDO
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_r3



  SUBROUTINE checksum_l0(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    LOGICAL,INTENT(IN)          :: field
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i

    tot_sum=0
    intval(1)=0
    IF (field) intval(1)=1
    intval(2)=0
    tot_sum = tot_sum + intval(1) + intval(2)

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_l0

  SUBROUTINE checksum_l1(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    LOGICAL,INTENT(IN)          :: field(:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i

    tot_sum=0
    DO i=1,SIZE(field,1)
      intval(1)=0
      IF (field(i)) intval(1)=1
      tot_sum = tot_sum + intval(1) + intval(2)
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_l1

  SUBROUTINE checksum_l2(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    LOGICAL,INTENT(IN)          :: field(:,:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i,j

    tot_sum=0
    DO j=1,SIZE(field,2)
      DO i=1,SIZE(field,1)
        intval(1)=0
        IF (field(i,j)) intval(1)=1
        intval(2)=0
        tot_sum = tot_sum + intval(1) + intval(2)
      ENDDO
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_l2

  SUBROUTINE checksum_l3(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    LOGICAL,INTENT(IN)          :: field(:,:,:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i,j,k

    tot_sum=0
    DO k=1,SIZE(field,3)
      DO j=1,SIZE(field,2)
        DO i=1,SIZE(field,1)
          intval(1)=0
          IF (field(i,j,k)) intval(1)=1
          intval(2)=0
          tot_sum = tot_sum + intval(1) + intval(2)
        ENDDO
      ENDDO
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_l3



  SUBROUTINE checksum_i0(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    INTEGER,INTENT(IN)          :: field
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i

    tot_sum=0
    intval(1)=field
    intval(2)=0
    tot_sum = tot_sum + intval(1) + intval(2)

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_i0

  SUBROUTINE checksum_i1(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    INTEGER,INTENT(IN)          :: field(:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i

    tot_sum=0
    DO i=1,SIZE(field,1)
      intval(1)=field(i)
      intval(2)=0
      tot_sum = tot_sum + intval(1) + intval(2)
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_i1

  SUBROUTINE checksum_i2(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    INTEGER,INTENT(IN)          :: field(:,:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i,j

    tot_sum=0
    DO j=1,SIZE(field,2)
      DO i=1,SIZE(field,1)
        intval(1)=field(i,j)
        intval(2)=0
        tot_sum = tot_sum + intval(1) + intval(2)
      ENDDO
    ENDDO

    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_i2

  SUBROUTINE checksum_i3(name, field)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    INTEGER,INTENT(IN)          :: field(:,:,:)
    INTEGER :: intval(2)
    INTEGER :: tot_sum
    INTEGER :: i,j,k

    tot_sum=0
    DO k=1,SIZE(field,3)
      DO j=1,SIZE(field,2)
        DO i=1,SIZE(field,1)
          intval(1)=field(i,j,k)
          intval(2)=0
          tot_sum = tot_sum + intval(1) + intval(2)
        ENDDO
      ENDDO
    ENDDO
    CALL print_checksum(name,tot_sum)
  END SUBROUTINE checksum_i3



  SUBROUTINE print_checksum(name, tot_sum)
  USE mod_phys_lmdz_para, ONLY : reduce_sum, is_master
  USE print_control_mod, ONLY: lunout
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(IN) :: name
    INTEGER, INTENT(IN) :: tot_sum
    INTEGER             :: tot_sum_glo

    CALL reduce_sum(tot_sum, tot_sum_glo)

    IF (is_master) WRITE(lunout,*) "CHECKSUM : ",TRIM(ADJUSTL(name)), " ==> ",tot_sum_glo
  END SUBROUTINE print_checksum
END MODULE lmdz_checksum
