!This subroutine sets the stage for MPI + OpenMP
Subroutine MPI_Subroutine
use Variables
use mpi
implicit none

!Starting up MPI
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,npes,ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,MyRank,ierr)

!Compute the size of local block (1D Decomposition)
Jmax = JmaxGlobal
Imax = ImaxGlobal/npes
if (MyRank.lt.(ImaxGlobal - npes*Imax)) then
  Imax = Imax + 1
end if
if (MyRank.ne.0.and.MyRank.ne.(npes-1)) then
  Imax = Imax + 2
Else
  Imax = Imax + 1
endif

! Computing neighboars
if (MyRank.eq.0) then
  Left = MPI_PROC_NULL
else
  Left = MyRank - 1
end if

if (MyRank.eq.(npes -1)) then
  Right = MPI_PROC_NULL
else
  Right = MyRank + 1
end if


! Initializing the Arrays in each processor, according to the number of local nodes
Call InitializeArrays

!Creating the channel of communication for this computation,
!Sending and receiving the u_old (Ghost cells)
Call MPI_SEND_INIT(u_old(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(1),ierr)
Call MPI_RECV_INIT(u_old(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(2),ierr)
Call MPI_SEND_INIT(u_old(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(3),ierr)
Call MPI_RECV_INIT(u_old(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(4),ierr)

!Sending and receiving the v_old (Ghost cells)
Call MPI_SEND_INIT(v_old(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(5),ierr)
Call MPI_RECV_INIT(v_old(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(6),ierr)
Call MPI_SEND_INIT(v_old(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(7),ierr)
Call MPI_RECV_INIT(v_old(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(8),ierr)

!Sending and receiving the r_old (Ghost cells)
Call MPI_SEND_INIT(r_old(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(9),ierr)
Call MPI_RECV_INIT(r_old(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(10),ierr)
Call MPI_SEND_INIT(r_old(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(11),ierr)
Call MPI_RECV_INIT(r_old(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(12),ierr)

!Sending and receiving the T_old (Ghost cells)
Call MPI_SEND_INIT(T_old(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(13),ierr)
Call MPI_RECV_INIT(T_old(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(14),ierr)
Call MPI_SEND_INIT(T_old(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(15),ierr)
Call MPI_RECV_INIT(T_old(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(16),ierr)

!Sending and receiving the u_new (Ghost cells)
Call MPI_SEND_INIT(u_new(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(17),ierr)
Call MPI_RECV_INIT(u_new(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(18),ierr)
Call MPI_SEND_INIT(u_new(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(19),ierr)
Call MPI_RECV_INIT(u_new(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(20),ierr)

!Sending and receiving the v_new (Ghost cells)
Call MPI_SEND_INIT(v_new(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(21),ierr)
Call MPI_RECV_INIT(v_new(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(22),ierr)
Call MPI_SEND_INIT(v_new(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(23),ierr)
Call MPI_RECV_INIT(v_new(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(24),ierr)

!Sending and receiving the r_new (Ghost cells)
Call MPI_SEND_INIT(r_new(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(25),ierr)
Call MPI_RECV_INIT(r_new(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(26),ierr)
Call MPI_SEND_INIT(r_new(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(27),ierr)
Call MPI_RECV_INIT(r_new(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(28),ierr)

!Sending and receiving the T_new (Ghost cells)
Call MPI_SEND_INIT(T_new(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(29),ierr)
Call MPI_RECV_INIT(T_new(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(30),ierr)
Call MPI_SEND_INIT(T_new(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(31),ierr)
Call MPI_RECV_INIT(T_new(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(32),ierr)

!Sending and receiving the Viscosity values (Ghost cells)
Call MPI_SEND_INIT(vMu(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(33),ierr)
Call MPI_RECV_INIT(vMu(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(34),ierr)
Call MPI_SEND_INIT(vMu(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(35),ierr)
Call MPI_RECV_INIT(vMu(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(36),ierr)

!Sending and receiving the Thermal conductivity values (Ghost cells)
Call MPI_SEND_INIT(tK(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(37),ierr)
Call MPI_RECV_INIT(tK(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(38),ierr)
Call MPI_SEND_INIT(tK(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(39),ierr)
Call MPI_RECV_INIT(tK(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(40),ierr)

!Sending and receiving the H_old (Ghost cells)
Call MPI_SEND_INIT(H_old(2,:),Jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(41),ierr)
Call MPI_RECV_INIT(H_old(Imax,:),jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(42),ierr)
Call MPI_SEND_INIT(H_old(Imax-1,:),Jmax,MPI_DOUBLE_PRECISION,Right,tag,MPI_COMM_WORLD,req(43),ierr)
Call MPI_RECV_INIT(H_old(1,:),jmax,MPI_DOUBLE_PRECISION,Left,tag,MPI_COMM_WORLD,req(44),ierr)


End Subroutine MPI_Subroutine
