! ======================================
! TREEMPI: Contains all MPI Send/Recives
! ======================================


SUBROUTINE SEND_PARAMETERS
IMPLICIT NONE
INCLUDE 'treedefs.f90'
DOUBLE PRECISION :: Start_Send,End_Send,Delta


Start_Send = MPI_WTIME()
DO Dest = 1, workers
		CALL MPI_SEND(NSTEPS,1,MPI_INTEGER,dest,params_tag, MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(NOUT,1, MPI_INTEGER, dest, params_tag, MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(DTIME,1,MPI_DOUBLE_PRECISION,dest,params_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(THETA,1,MPI_DOUBLE_PRECISION,dest,params_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(EPS,1,MPI_DOUBLE_PRECISION,dest,params_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(USQUAD,1,MPI_LOGICAL,dest,params_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(MASS,SIZE(MASS),MPI_DOUBLE_PRECISION,dest,mass_tag,MPI_COMM_WORLD,ierr)
		!PRINT *, "Parameters distributed to process" , dest
END DO        
End_Send = MPI_WTIME()
delta = end_send - start_send
!PRINT *,  "Sending Parameters Took ",delta, "Seconds"  
END SUBROUTINE SEND_PARAMETERS


SUBROUTINE RECV_PARAMETERS
IMPLICIT NONE
INCLUDE 'treedefs.f90'

CALL MPI_RECV(NSTEPS,1,MPI_INTEGER,MASTER,params_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(NOUT,1,MPI_INTEGER,MASTER,params_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(DTIME,1,MPI_DOUBLE_PRECISION,MASTER,params_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(THETA,1,MPI_DOUBLE_PRECISION,MASTER,params_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(EPS,1,MPI_DOUBLE_PRECISION,MASTER,params_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(USQUAD,1,MPI_LOGICAL,MASTER, params_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(MASS,SIZE(MASS),MPI_DOUBLE_PRECISION,MASTER,mass_tag,MPI_COMM_WORLD,status,ierr)

!PRINT *, "Parameter Data Recieved from Master"

END SUBROUTINE RECV_PARAMETERS


SUBROUTINE RECV_RAW_DATA
IMPLICIT NONE
INCLUDE 'treedefs.f90'
INTEGER :: subp_workload

CALL MPI_RECV(mpi_index,1,MPI_INTEGER,MASTER,ind_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(ROOT,1,MPI_INTEGER,MASTER,root_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(POS,SIZE(POS),MPI_DOUBLE_PRECISION,MASTER,pos_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(subp_workload,1,MPI_INTEGER,MASTER,ind_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(SUBP,subp_workload,MPI_DOUBLE_PRECISION,MASTER,subp_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(RCRIT2,subp_workload,MPI_DOUBLE_PRECISION,MASTER,rcrit2_tag,MPI_COMM_WORLD,status,ierr)
CALL MPI_RECV(MASS(INCELL),MXBODY,MPI_DOUBLE_PRECISION,MASTER,mass_tag,MPI_COMM_WORLD,status,ierr)
PRINT *, "The Subp_workload is: " , subp_workload
END SUBROUTINE

SUBROUTINE SEND_PROCESSED_DATA
IMPLICIT NONE
INCLUDE 'treedefs.f90'

CALL MPI_SEND(mpi_index,1,MPI_INTEGER,MASTER,ind_tag,MPI_COMM_WORLD,ierr)
CALL MPI_SEND(ACC(mpi_index,1),workload(my_rank),MPI_DOUBLE_PRECISION,MASTER,acc_tag, &
		MPI_COMM_WORLD,ierr)
CALL MPI_SEND(ACC(mpi_index,2),workload(my_rank), MPI_DOUBLE_PRECISION,MASTER,acc_tag, &
		MPI_COMM_WORLD,ierr)
CALL MPI_SEND(ACC(mpi_index,3),workload(my_rank), MPI_DOUBLE_PRECISION,MASTER,acc_tag, &
		MPI_COMM_WORLD,ierr)
CALL MPI_SEND(PHI(mpi_index),workload(my_rank), MPI_DOUBLE_PRECISION,MASTER,phi_tag, &
		MPI_COMM_WORLD,ierr)
		
CALL MPI_SEND(NBTOT,1,MPI_INTEGER,MASTER,nb_tag,MPI_COMM_WORLD,ierr)
CALL MPI_SEND(NCTOT,1,MPI_INTEGER,MASTER,nb_tag,MPI_COMM_WORLD,ierr)
CALL MPI_SEND(NTMAX,1,MPI_INTEGER,MASTER,nb_tag,MPI_COMM_WORLD,ierr)
	
!PRINT *, "Processed Data returned to master"

END SUBROUTINE SEND_PROCESSED_DATA

SUBROUTINE SEND_RAW_DATA
IMPLICIT NONE
INCLUDE 'treedefs.f90'
DOUBLE PRECISION :: Start_Time, End_Time,delta
INTEGER :: Kj, subp_workload,subp_sum,subp_end

!  -------------------------------------------------------
!  Determine How much of the SubP array needs to be sent
!  -------------------------------------------------------
		subp_workload = 0
	DO Kj = INCELL,MXNODE
		subp_sum = 0
		subp_sum = SUM(SUBP(Kj,1:NSUBC))
		IF (subp_sum == 0) THEN
			subp_end = Kj
			subp_workload = NSUBC * (subp_end - INCELL)
			EXIT	
		END IF
	END DO

IF (subp_workload == 0) subp_workload = SIZE(SUBP) !SUBP index is filled
PRINT *, "The size of subp is: ", subp_workload

Start_Time = MPI_WTIME()

mpi_index = 1
	Do dest = 1, workers
		CALL MPI_SEND(mpi_index,1,MPI_INTEGER,dest,ind_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(ROOT,1,MPI_INTEGER,dest,root_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(POS,SIZE(POS),MPI_DOUBLE_PRECISION,dest,pos_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(subp_workload,1,MPI_INTEGER,dest,ind_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(SUBP,subp_workload,MPI_INTEGER,dest,subp_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(RCRIT2,subp_workload,MPI_DOUBLE_PRECISION,dest,rcrit2_tag,MPI_COMM_WORLD,ierr)
		CALL MPI_SEND(MASS(INCELL),MXBODY,MPI_DOUBLE_PRECISION,dest,mass_tag,MPI_COMM_WORLD,ierr)
		mpi_index = mpi_index + workload(dest)
	END DO
!PRINT *, "Body Data distributed to nodes"
End_Time = MPI_WTIME()
delta = end_time - start_time
WRITE(RAW_SEND, '(F10.5)') delta
END SUBROUTINE SEND_RAW_DATA

SUBROUTINE RECV_PROCESSED_DATA
IMPLICIT NONE
INCLUDE 'treedefs.f90'
INTEGER :: nc_temp,nb_temp,nt_temp
DOUBLE PRECISION :: end_time,start_time,delta,mid_time,wait_time

start_time = MPI_WTIME()
Do source = 1, workers
		CALL MPI_RECV(mpi_index,1,MPI_INTEGER,source,ind_tag,MPI_COMM_WORLD,status,ierr)
		IF (source .EQ. 1) THEN
			mid_time = MPI_WTIME()
		END IF
		CALL MPI_RECV(ACC(mpi_index,1),workload(source),MPI_DOUBLE_PRECISION,source,acc_tag, &
			MPI_COMM_WORLD,status,ierr)
	    CALL MPI_RECV(ACC(mpi_index,2),workload(source),MPI_DOUBLE_PRECISION,source,acc_tag, &
			MPI_COMM_WORLD,status,ierr)
		CALL MPI_RECV(ACC(mpi_index,3),workload(source),MPI_DOUBLE_PRECISION,source,acc_tag, &
			MPI_COMM_WORLD,status,ierr)
		CALL MPI_RECV(PHI(mpi_index),workload(source),MPI_DOUBLE_PRECISION,source,phi_tag,&
			MPI_COMM_WORLD,status,ierr)
		
		CALL MPI_RECV(NB_temp,1,MPI_INTEGER,source,nb_tag,MPI_COMM_WORLD,status,ierr)
		CALL MPI_RECV(NC_temp,1,MPI_INTEGER,source,nb_tag,MPI_COMM_WORLD,status,ierr)
		CALL MPI_RECV(NT_temp,1,MPI_INTEGER,source,nb_tag,MPI_COMM_WORLD,status,ierr)
		!PRINT *, "The size of the workload of process ", source, "is ", workload(source)
		!PRINT *, "The index of process ", source, " is", mpi_index
		NBTOT = NBTOT + NB_temp
		NCTOT = NCTOT + NC_temp
		NTMAX = NTMAX + NT_temp
		END DO
end_time = MPI_WTIME()
wait_time = mid_time - start_time
delta = end_time - start_time

WRITE (PROC_RECV, '(2F10.5)') wait_time, delta
END SUBROUTINE RECV_PROCESSED_DATA