MODULE transfert_omp_mod
  PRIVATE
  
  REAL,PARAMETER :: grow_factor=1.5
  INTEGER,PARAMETER :: size_min=1024
  
  CHARACTER(LEN=size_min),SAVE            :: buffer_c
!  INTEGER,SAVE                            :: size_c=0
  INTEGER,SAVE,ALLOCATABLE,DIMENSION(:)   :: buffer_i
  INTEGER,SAVE                            :: size_i=0
  REAL,SAVE,ALLOCATABLE,DIMENSION(:)      :: buffer_r
  INTEGER,SAVE                            :: size_r=0
  LOGICAL,SAVE,ALLOCATABLE,DIMENSION(:)   :: buffer_l
  INTEGER,SAVE                            :: size_l=0


  
  
  INTERFACE bcast_omp
    MODULE PROCEDURE bcast_omp_c,                                                     &
                     bcast_omp_i,bcast_omp_i1,bcast_omp_i2,bcast_omp_i3,bcast_omp_i4, &
                     bcast_omp_r,bcast_omp_r1,bcast_omp_r2,bcast_omp_r3,bcast_omp_r4, &
		     bcast_omp_l,bcast_omp_l1,bcast_omp_l2,bcast_omp_l3,bcast_omp_l4
  END INTERFACE

  INTERFACE reduce_sum_omp
    MODULE PROCEDURE reduce_sum_omp_i,reduce_sum_omp_i1,reduce_sum_omp_i2,reduce_sum_omp_i3,reduce_sum_omp_i4, &
                     reduce_sum_omp_r,reduce_sum_omp_r1,reduce_sum_omp_r2,reduce_sum_omp_r3,reduce_sum_omp_r4
  END INTERFACE 

  INTERFACE allreduce_sum_omp
    MODULE PROCEDURE allreduce_sum_omp_i,allreduce_sum_omp_i1,allreduce_sum_omp_i2,allreduce_sum_omp_i3,allreduce_sum_omp_i4, &
                     allreduce_sum_omp_r,allreduce_sum_omp_r1,allreduce_sum_omp_r2,allreduce_sum_omp_r3,allreduce_sum_omp_r4
  END INTERFACE 


  INTERFACE reduce_max_omp
    MODULE PROCEDURE reduce_max_omp_i,reduce_max_omp_i1,reduce_max_omp_i2,reduce_max_omp_i3,reduce_max_omp_i4, &
                     reduce_max_omp_r,reduce_max_omp_r1,reduce_max_omp_r2,reduce_max_omp_r3,reduce_max_omp_r4
  END INTERFACE 

  INTERFACE allreduce_max_omp
    MODULE PROCEDURE allreduce_max_omp_i,allreduce_max_omp_i1,allreduce_max_omp_i2,allreduce_max_omp_i3,allreduce_max_omp_i4, &
                     allreduce_max_omp_r,allreduce_max_omp_r1,allreduce_max_omp_r2,allreduce_max_omp_r3,allreduce_max_omp_r4
  END INTERFACE 


  PUBLIC bcast_omp, reduce_sum_omp, allreduce_sum_omp, reduce_max_omp, allreduce_max_omp
  
CONTAINS

  SUBROUTINE check_buffer_i(buff_size)
  IMPLICIT NONE
  INTEGER :: buff_size

!$OMP BARRIER
!$OMP MASTER
    IF (buff_size>size_i) THEN
      IF (ALLOCATED(buffer_i)) DEALLOCATE(buffer_i)
      size_i=MAX(size_min,INT(grow_factor*buff_size))
      ALLOCATE(buffer_i(size_i))
    ENDIF
!$OMP END MASTER
!$OMP BARRIER
  
  END SUBROUTINE check_buffer_i
  
  SUBROUTINE check_buffer_r(buff_size)
  IMPLICIT NONE
  INTEGER :: buff_size

!$OMP BARRIER
!$OMP MASTER
    IF (buff_size>size_r) THEN
      IF (ALLOCATED(buffer_r)) DEALLOCATE(buffer_r)
      size_r=MAX(size_min,INT(grow_factor*buff_size))
      ALLOCATE(buffer_r(size_r))
    ENDIF
!$OMP END MASTER
!$OMP BARRIER
  
  END SUBROUTINE check_buffer_r
  
  SUBROUTINE check_buffer_l(buff_size)
  IMPLICIT NONE
  INTEGER :: buff_size

!$OMP BARRIER
!$OMP MASTER
    IF (buff_size>size_l) THEN
      IF (ALLOCATED(buffer_l)) DEALLOCATE(buffer_l)
      size_l=MAX(size_min,INT(grow_factor*buff_size))
      ALLOCATE(buffer_l(size_l))
    ENDIF
!$OMP END MASTER
!$OMP BARRIER
  
  END SUBROUTINE check_buffer_l
    
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Definition des Broadcast --> 4D   !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!! -- Les chaine de charact�re -- !!

  SUBROUTINE bcast_omp_c(var)
  IMPLICIT NONE
    CHARACTER(LEN=*),INTENT(INOUT) :: Var
    INTEGER :: lenvar
    lenvar=len(Var)
    CALL bcast_omp_i(lenvar)
    CALL bcast_omp_cgen(Var,lenvar,buffer_c)    
  END SUBROUTINE bcast_omp_c

!! -- Les entiers -- !!
  
  SUBROUTINE bcast_omp_i(var)
  IMPLICIT NONE
    INTEGER,INTENT(INOUT) :: Var
    INTEGER :: Var_tmp(1)
    
    Var_tmp(1)=Var
    CALL check_buffer_i(1)
    CALL bcast_omp_igen(Var_tmp,1,buffer_i)
    Var=Var_tmp(1)

  END SUBROUTINE bcast_omp_i


  SUBROUTINE bcast_omp_i1(var)
  IMPLICIT NONE
    INTEGER,INTENT(INOUT) :: Var(:)
   
    CALL check_buffer_i(size(Var))
    CALL bcast_omp_igen(Var,size(Var),buffer_i)

  END SUBROUTINE bcast_omp_i1


  SUBROUTINE bcast_omp_i2(var)
  IMPLICIT NONE
    INTEGER,INTENT(INOUT) :: Var(:,:)
   
    CALL check_buffer_i(size(Var))
    CALL bcast_omp_igen(Var,size(Var),buffer_i)

  END SUBROUTINE bcast_omp_i2


  SUBROUTINE bcast_omp_i3(var)
  IMPLICIT NONE
    INTEGER,INTENT(INOUT) :: Var(:,:,:)

    CALL check_buffer_i(size(Var))
    CALL bcast_omp_igen(Var,size(Var),buffer_i)

  END SUBROUTINE bcast_omp_i3


  SUBROUTINE bcast_omp_i4(var)
  IMPLICIT NONE
    INTEGER,INTENT(INOUT) :: Var(:,:,:,:)
   
    CALL check_buffer_i(size(Var))
    CALL bcast_omp_igen(Var,size(Var),buffer_i)

  END SUBROUTINE bcast_omp_i4


!! -- Les reels -- !!

  SUBROUTINE bcast_omp_r(var)
  IMPLICIT NONE
    REAL,INTENT(INOUT) :: Var
    REAL :: Var_tmp(1)
    
    Var_tmp(1)=Var
    CALL check_buffer_r(1)
    CALL bcast_omp_rgen(Var_tmp,1,buffer_r)
    Var=Var_tmp(1)

  END SUBROUTINE bcast_omp_r


  SUBROUTINE bcast_omp_r1(var)
  IMPLICIT NONE
    REAL,INTENT(INOUT) :: Var(:)
   
    CALL check_buffer_r(size(Var))
    CALL bcast_omp_rgen(Var,size(Var),buffer_r)

  END SUBROUTINE bcast_omp_r1


  SUBROUTINE bcast_omp_r2(var)
  IMPLICIT NONE
    REAL,INTENT(INOUT) :: Var(:,:)
   
    CALL check_buffer_r(size(Var))
    CALL bcast_omp_rgen(Var,size(Var),buffer_r)

  END SUBROUTINE bcast_omp_r2


  SUBROUTINE bcast_omp_r3(var)
  IMPLICIT NONE
    REAL,INTENT(INOUT) :: Var(:,:,:)

    CALL check_buffer_r(size(Var))
    CALL bcast_omp_rgen(Var,size(Var),buffer_r)

  END SUBROUTINE bcast_omp_r3


  SUBROUTINE bcast_omp_r4(var)
  IMPLICIT NONE
    REAL,INTENT(INOUT) :: Var(:,:,:,:)
   
    CALL check_buffer_r(size(Var))
    CALL bcast_omp_rgen(Var,size(Var),buffer_r)

  END SUBROUTINE bcast_omp_r4

  
!! -- Les booleans -- !!

  SUBROUTINE bcast_omp_l(var)
  IMPLICIT NONE
    LOGICAL,INTENT(INOUT) :: Var
    LOGICAL :: Var_tmp(1)
    
    Var_tmp(1)=Var
    CALL check_buffer_l(1)
    CALL bcast_omp_lgen(Var_tmp,1,buffer_l)
    Var=Var_tmp(1)

  END SUBROUTINE bcast_omp_l


  SUBROUTINE bcast_omp_l1(var)
  IMPLICIT NONE
    LOGICAL,INTENT(INOUT) :: Var(:)
   
    CALL check_buffer_l(size(Var))
    CALL bcast_omp_lgen(Var,size(Var),buffer_l)

  END SUBROUTINE bcast_omp_l1


  SUBROUTINE bcast_omp_l2(var)
  IMPLICIT NONE
    LOGICAL,INTENT(INOUT) :: Var(:,:)
   
    CALL check_buffer_l(size(Var))
    CALL bcast_omp_lgen(Var,size(Var),buffer_l)

  END SUBROUTINE bcast_omp_l2


  SUBROUTINE bcast_omp_l3(var)
  IMPLICIT NONE
    LOGICAL,INTENT(INOUT) :: Var(:,:,:)

    CALL check_buffer_l(size(Var))
    CALL bcast_omp_lgen(Var,size(Var),buffer_l)

  END SUBROUTINE bcast_omp_l3


  SUBROUTINE bcast_omp_l4(var)
  IMPLICIT NONE
    LOGICAL,INTENT(INOUT) :: Var(:,:,:,:)
   
    CALL check_buffer_l(size(Var))
    CALL bcast_omp_lgen(Var,size(Var),buffer_l)

  END SUBROUTINE bcast_omp_l4
  



  SUBROUTINE reduce_sum_omp_i(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN)  :: VarIn
    INTEGER,INTENT(OUT) :: VarOut
    INTEGER             :: VarIn_tmp(1)
    INTEGER             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_i(1)   
    CALL reduce_sum_omp_igen(VarIn_tmp,Varout_tmp,1,buffer_i)
    VarOut=VarOut_tmp(1)
    
  END SUBROUTINE reduce_sum_omp_i

  SUBROUTINE reduce_sum_omp_i1(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
   
  END SUBROUTINE reduce_sum_omp_i1
  
  
  SUBROUTINE reduce_sum_omp_i2(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:) :: VarOut

    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE reduce_sum_omp_i2


  SUBROUTINE reduce_sum_omp_i3(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE reduce_sum_omp_i3


  SUBROUTINE reduce_sum_omp_i4(VarIn, VarOut)
    IMPLICIT NONE

    INTEGER,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE reduce_sum_omp_i4


  SUBROUTINE reduce_sum_omp_r(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN)  :: VarIn
    REAL,INTENT(OUT) :: VarOut
    REAL             :: VarIn_tmp(1)
    REAL             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_r(1)   
    CALL reduce_sum_omp_rgen(VarIn_tmp,Varout_tmp,1,buffer_r)
    VarOut=VarOut_tmp(1)
  
  END SUBROUTINE reduce_sum_omp_r

  SUBROUTINE reduce_sum_omp_r1(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
   
  END SUBROUTINE reduce_sum_omp_r1
  
  
  SUBROUTINE reduce_sum_omp_r2(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE reduce_sum_omp_r2


  SUBROUTINE reduce_sum_omp_r3(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE reduce_sum_omp_r3


  SUBROUTINE reduce_sum_omp_r4(VarIn, VarOut)
    IMPLICIT NONE

    REAL,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE reduce_sum_omp_r4  
  
  
  
  
    SUBROUTINE allreduce_sum_omp_i(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN)  :: VarIn
    INTEGER,INTENT(OUT) :: VarOut
    INTEGER             :: VarIn_tmp(1)
    INTEGER             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_i(1)   
    CALL allreduce_sum_omp_igen(VarIn_tmp,Varout_tmp,1,buffer_i)
    VarOut=VarOut_tmp(1)
    
  END SUBROUTINE allreduce_sum_omp_i

  SUBROUTINE allreduce_sum_omp_i1(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
   
  END SUBROUTINE allreduce_sum_omp_i1
  
  
  SUBROUTINE allreduce_sum_omp_i2(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:) :: VarOut

    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE allreduce_sum_omp_i2


  SUBROUTINE allreduce_sum_omp_i3(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE allreduce_sum_omp_i3


  SUBROUTINE allreduce_sum_omp_i4(VarIn, VarOut)
    IMPLICIT NONE

    INTEGER,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_sum_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE allreduce_sum_omp_i4


  SUBROUTINE allreduce_sum_omp_r(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN)  :: VarIn
    REAL,INTENT(OUT) :: VarOut
    REAL             :: VarIn_tmp(1)
    REAL             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_r(1)   
    CALL allreduce_sum_omp_rgen(VarIn_tmp,Varout_tmp,1,buffer_r)
    VarOut=VarOut_tmp(1)
  
  END SUBROUTINE allreduce_sum_omp_r

  SUBROUTINE allreduce_sum_omp_r1(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
   
  END SUBROUTINE allreduce_sum_omp_r1
  
  
  SUBROUTINE allreduce_sum_omp_r2(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE allreduce_sum_omp_r2


  SUBROUTINE allreduce_sum_omp_r3(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE allreduce_sum_omp_r3


  SUBROUTINE allreduce_sum_omp_r4(VarIn, VarOut)
    IMPLICIT NONE

    REAL,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_sum_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE allreduce_sum_omp_r4  
  











  SUBROUTINE reduce_max_omp_i(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN)  :: VarIn
    INTEGER,INTENT(OUT) :: VarOut
    INTEGER             :: VarIn_tmp(1)
    INTEGER             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_i(1)   
    CALL reduce_max_omp_igen(VarIn_tmp,Varout_tmp,1,buffer_i)
    VarOut=VarOut_tmp(1)
    
  END SUBROUTINE reduce_max_omp_i

  SUBROUTINE reduce_max_omp_i1(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
   
  END SUBROUTINE reduce_max_omp_i1
  
  
  SUBROUTINE reduce_max_omp_i2(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:) :: VarOut

    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE reduce_max_omp_i2


  SUBROUTINE reduce_max_omp_i3(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE reduce_max_omp_i3


  SUBROUTINE reduce_max_omp_i4(VarIn, VarOut)
    IMPLICIT NONE

    INTEGER,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_i(size(VarIn))   
    CALL reduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE reduce_max_omp_i4


  SUBROUTINE reduce_max_omp_r(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN)  :: VarIn
    REAL,INTENT(OUT) :: VarOut
    REAL             :: VarIn_tmp(1)
    REAL             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_r(1)   
    CALL reduce_max_omp_rgen(VarIn_tmp,Varout_tmp,1,buffer_r)
    VarOut=VarOut_tmp(1)
  
  END SUBROUTINE reduce_max_omp_r

  SUBROUTINE reduce_max_omp_r1(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
   
  END SUBROUTINE reduce_max_omp_r1
  
  
  SUBROUTINE reduce_max_omp_r2(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE reduce_max_omp_r2


  SUBROUTINE reduce_max_omp_r3(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE reduce_max_omp_r3


  SUBROUTINE reduce_max_omp_r4(VarIn, VarOut)
    IMPLICIT NONE

    REAL,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_r(size(VarIn))   
    CALL reduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE reduce_max_omp_r4  
  
  
  
  
    SUBROUTINE allreduce_max_omp_i(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN)  :: VarIn
    INTEGER,INTENT(OUT) :: VarOut
    INTEGER             :: VarIn_tmp(1)
    INTEGER             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_i(1)   
    CALL allreduce_max_omp_igen(VarIn_tmp,Varout_tmp,1,buffer_i)
    VarOut=VarOut_tmp(1)
    
  END SUBROUTINE allreduce_max_omp_i

  SUBROUTINE allreduce_max_omp_i1(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
   
  END SUBROUTINE allreduce_max_omp_i1
  
  
  SUBROUTINE allreduce_max_omp_i2(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:) :: VarOut

    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE allreduce_max_omp_i2


  SUBROUTINE allreduce_max_omp_i3(VarIn, VarOut)
    IMPLICIT NONE
  
    INTEGER,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE allreduce_max_omp_i3


  SUBROUTINE allreduce_max_omp_i4(VarIn, VarOut)
    IMPLICIT NONE

    INTEGER,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_i(size(VarIn))   
    CALL allreduce_max_omp_igen(VarIn,Varout,Size(VarIn),buffer_i)
  
  END SUBROUTINE allreduce_max_omp_i4


  SUBROUTINE allreduce_max_omp_r(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN)  :: VarIn
    REAL,INTENT(OUT) :: VarOut
    REAL             :: VarIn_tmp(1)
    REAL             :: VarOut_tmp(1)
    
    VarIn_tmp(1)=VarIn
    CALL Check_buffer_r(1)   
    CALL allreduce_max_omp_rgen(VarIn_tmp,Varout_tmp,1,buffer_r)
    VarOut=VarOut_tmp(1)
  
  END SUBROUTINE allreduce_max_omp_r

  SUBROUTINE allreduce_max_omp_r1(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
   
  END SUBROUTINE allreduce_max_omp_r1
  
  
  SUBROUTINE allreduce_max_omp_r2(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE allreduce_max_omp_r2


  SUBROUTINE allreduce_max_omp_r3(VarIn, VarOut)
    IMPLICIT NONE
  
    REAL,INTENT(IN),DIMENSION(:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:) :: VarOut
    
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE allreduce_max_omp_r3


  SUBROUTINE allreduce_max_omp_r4(VarIn, VarOut)
    IMPLICIT NONE

    REAL,INTENT(IN),DIMENSION(:,:,:,:)  :: VarIn
    REAL,INTENT(OUT),DIMENSION(:,:,:,:) :: VarOut
  
    CALL Check_buffer_r(size(VarIn))   
    CALL allreduce_max_omp_rgen(VarIn,Varout,Size(VarIn),buffer_r)
  
  END SUBROUTINE allreduce_max_omp_r4  

  
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!    LES ROUTINES GENERIQUES    !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  SUBROUTINE bcast_omp_cgen(Var,Nb,Buff)
  IMPLICIT NONE
    INTEGER,INTENT(IN) :: Nb
    CHARACTER(LEN=*),INTENT(INOUT) :: Var
    CHARACTER(LEN=*),INTENT(INOUT) :: Buff
    
    INTEGER :: i
  
  !$OMP MASTER
      Buff=Var
  !$OMP END MASTER
  !$OMP BARRIER

    DO i=1,Nb
      Var=Buff
    ENDDO
  !$OMP BARRIER      
  
  END SUBROUTINE bcast_omp_cgen



  SUBROUTINE bcast_omp_igen(Var,Nb,Buff)
  IMPLICIT NONE
    INTEGER,INTENT(IN) :: Nb
    INTEGER,DIMENSION(Nb),INTENT(INOUT) :: Var
    INTEGER,DIMENSION(Nb),INTENT(INOUT) :: Buff

    INTEGER :: i
    
  !$OMP MASTER
    DO i=1,Nb
      Buff(i)=Var(i)
    ENDDO
  !$OMP END MASTER
  !$OMP BARRIER

    DO i=1,Nb
      Var(i)=Buff(i)
    ENDDO
  !$OMP BARRIER        

  END SUBROUTINE bcast_omp_igen


  SUBROUTINE bcast_omp_rgen(Var,Nb,Buff)
  IMPLICIT NONE
    INTEGER,INTENT(IN) :: Nb
    REAL,DIMENSION(Nb),INTENT(INOUT) :: Var
    REAL,DIMENSION(Nb),INTENT(INOUT) :: Buff

    INTEGER :: i
    
  !$OMP MASTER
    DO i=1,Nb
      Buff(i)=Var(i)
    ENDDO
  !$OMP END MASTER
  !$OMP BARRIER

    DO i=1,Nb
      Var(i)=Buff(i)
    ENDDO
  !$OMP BARRIER        

  END SUBROUTINE bcast_omp_rgen

  SUBROUTINE bcast_omp_lgen(Var,Nb,Buff)
  IMPLICIT NONE
    INTEGER,INTENT(IN) :: Nb
    LOGICAL,DIMENSION(Nb),INTENT(INOUT) :: Var
    LOGICAL,DIMENSION(Nb),INTENT(INOUT) :: Buff

    INTEGER :: i
    
  !$OMP MASTER
    DO i=1,Nb
      Buff(i)=Var(i)
    ENDDO
  !$OMP END MASTER
  !$OMP BARRIER

    DO i=1,Nb
      Var(i)=Buff(i)
    ENDDO
  !$OMP BARRIER        

  END SUBROUTINE bcast_omp_lgen
  

  SUBROUTINE reduce_sum_omp_igen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    INTEGER,INTENT(IN),DIMENSION(dimsize) :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    INTEGER,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=0
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=Buff(i)+VarIn(i)
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
  !$OMP MASTER
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO
  !$OMP END MASTER
  !$OMP BARRIER
  
  END SUBROUTINE reduce_sum_omp_igen

  SUBROUTINE reduce_sum_omp_rgen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    REAL,INTENT(IN),DIMENSION(dimsize) :: VarIn
    REAL,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    REAL,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=0
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=Buff(i)+VarIn(i)
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO
  !$OMP BARRIER
  
  END SUBROUTINE reduce_sum_omp_rgen



  SUBROUTINE allreduce_sum_omp_igen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    INTEGER,INTENT(IN),DIMENSION(dimsize) :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    INTEGER,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=0
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=Buff(i)+VarIn(i)
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO
  !$OMP BARRIER
  
  END SUBROUTINE allreduce_sum_omp_igen

  SUBROUTINE allreduce_sum_omp_rgen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    REAL,INTENT(IN),DIMENSION(dimsize) :: VarIn
    REAL,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    REAL,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=0
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=Buff(i)+VarIn(i)
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO

  !$OMP BARRIER
  
  END SUBROUTINE allreduce_sum_omp_rgen






  SUBROUTINE reduce_max_omp_igen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    INTEGER,INTENT(IN),DIMENSION(dimsize) :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    INTEGER,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=VarIn(1)
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=MAX(Buff(i),VarIn(i))
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
  !$OMP MASTER
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO
  !$OMP END MASTER
  !$OMP BARRIER
  
  END SUBROUTINE reduce_max_omp_igen

  SUBROUTINE reduce_max_omp_rgen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    REAL,INTENT(IN),DIMENSION(dimsize) :: VarIn
    REAL,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    REAL,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=VarIn(1)
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=MAX(Buff(i),VarIn(i))
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO
  !$OMP BARRIER
  
  END SUBROUTINE reduce_max_omp_rgen



  SUBROUTINE allreduce_max_omp_igen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    INTEGER,INTENT(IN),DIMENSION(dimsize) :: VarIn
    INTEGER,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    INTEGER,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=VarIn(1)
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=MAX(Buff(i),VarIn(i))
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO
  !$OMP BARRIER
  
  END SUBROUTINE allreduce_max_omp_igen

  SUBROUTINE allreduce_max_omp_rgen(VarIn,VarOut,dimsize,Buff)
  IMPLICIT NONE

    INTEGER,INTENT(IN) :: dimsize
    REAL,INTENT(IN),DIMENSION(dimsize) :: VarIn
    REAL,INTENT(OUT),DIMENSION(dimsize) :: VarOut
    REAL,INTENT(INOUT),DIMENSION(dimsize) :: Buff

    INTEGER :: i

  !$OMP MASTER
    Buff(:)=VarIn(1)
  !$OMP END MASTER
  !$OMP BARRIER
  
  !$OMP CRITICAL     
    DO i=1,dimsize
      Buff(i)=MAX(Buff(i),VarIn(i))
    ENDDO
  !$OMP END CRITICAL
  !$OMP BARRIER  
  
    DO i=1,dimsize
      VarOut(i)=Buff(i)
    ENDDO

  !$OMP BARRIER
  
  END SUBROUTINE allreduce_max_omp_rgen
    










    
END MODULE transfert_omp_mod
