module mpi_params

   USE MPI
   implicit none
	integer	:: Number_Sources_4MPI, sources_per_proc
	integer :: nb_procs, my_rank, ierr
	integer :: mpi_source_start, mpi_source_end
	integer :: mpi_receptor_start,mpi_receptor_end
	integer :: mpi_met_start,mpi_met_end
	integer :: req,  code
	integer, dimension( MPI_STATUS_SIZE)  :: statut

	type :: timer_cpu
 		real :: t1                    !< Intial monitored time
		real :: t2                    !< Final monitored time
		real :: delta                 !< Computed elapsed time
  		real :: total = 0.0e0         !< Cumulative elapsed time
  		contains
  			    procedure :: start => start_timer_cpu
  			    procedure :: stop => stop_timer_cpu
  			    procedure :: print => print_timer_cpu
  			    procedure :: print_mpi => print_mpi_timer_cpu
	end type timer_cpu
	
contains

	subroutine start_timer_cpu(self)
		class(timer_cpu) :: self
		call cpu_time(self%t1)
		self%t2    = self%t1 
		self%delta = 0.0
	end subroutine start_timer_cpu

	subroutine stop_timer_cpu(self)
		class(timer_cpu) :: self

		call cpu_time(self%t2)
		self%delta = self%t2 - self%t1
		self%total = self%total + self%delta
		self%t1 = self%t2
	end subroutine stop_timer_cpu	

	subroutine print_timer_cpu(self, header)
		class(timer_cpu) 	:: self
		character(len=*), optional :: header
		integer :: i, nCPU

		if (my_rank == 0) then
			if (present(header)) then
			  write(*,*) "     Timer "//trim(header), self%total, " seconds"
			else
			  write(*,*) "     Timer :", self%total, " seconds"
			endif	   
		endif

	end subroutine print_timer_cpu	

	subroutine print_mpi_timer_cpu(self, header)
		class(timer_cpu) 	:: self
    	integer, Parameter  :: Double=8       ! Compiler dependent value		
		character(len=*), optional :: header		
      	Real(kind=double)  	::  time_max, time_min, time_mean, ratio, val
		integer :: i, nCPU

		time_max  = 0d0
		time_min  = 0d0
		time_mean = 0d0
		val       = self%total

		call mpi_reduce(val, time_max , 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, ierr) 
		call mpi_reduce(val, time_min , 1, MPI_DOUBLE_PRECISION, MPI_MIN, 0, MPI_COMM_WORLD, ierr) 
		call mpi_reduce(val, time_mean, 1, MPI_DOUBLE_PRECISION, MPI_SUM, 0, MPI_COMM_WORLD, ierr) 

		if (my_rank == 0) then
		  time_mean = time_mean/real(nb_procs)
		  write(*,*) "----------------------------------------------"
		  write(*,*) "Time on:  "
		  if (present(header)) write(*,*) header		  
		  write(*,*) "Ave time: ", time_mean," seconds"
		  write(*,*) "Min time:", time_min, " seconds"
		  write(*,*) "Max time:", time_max, " seconds"	
		  write(*,*) "----------------------------------------------"		  	   
		endif
	end subroutine print_mpi_timer_cpu	


	subroutine init_mpi_params(Number_Sources_4MPI,istart,iend)
	! Desciption: Initialize MPI features and divide the total number of sources among procs.	
		integer, intent(in)						:: Number_Sources_4MPI
		integer, intent(out)					:: istart,iend
      	integer status(MPI_STATUS_SIZE)
      	integer :: request,ierr
		integer                                 :: i

		! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - !
		! - - - Determine how many sources handles each proc - - - - - - -  !
		! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - !

		 if ( mod(Number_Sources_4MPI,nb_procs)==0 ) then
		    sources_per_proc = Number_Sources_4MPI/nb_procs
		 else
		    sources_per_proc = (Number_Sources_4MPI-mod(Number_Sources_4MPI,nb_procs))/nb_procs
		    if (my_rank == nb_procs-1) sources_per_proc = Number_Sources_4MPI - sources_per_proc*(nb_procs-1)
		 end if


		! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - !
		! - - - Determine istart and iend index for this proc's points - - - -  !
		! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - !

		istart = my_rank * sources_per_proc + 1
		if (my_rank  == nb_procs-1 ) istart = my_rank*(Number_Sources_4MPI-mod(Number_Sources_4MPI,nb_procs))/nb_procs +1
		iend = istart + sources_per_proc - 1
		if (my_rank  == nb_procs-1 ) iend = Number_Sources_4MPI


	end subroutine 




end module mpi_params
