mpi

Enabling MPI is done in two steps:

  • you need to have the following import:

    from pyccel.mpi import *
    
  • you need to compile your file with a valid mpi compiler:

    pyccel --language="fortran" --compiler=mpif90 --filename=tests/examples/mpi/ex_0.py
    mpirun -n 2 tests/examples/mpi/ex_0
    

Let’s start with a simple example (tests/examples/mpi/ex_0.py):

from pyccel.mpi import *

ierr = mpi_init()

comm = mpi_comm_world
size = comm.size
rank = comm.rank

print ('I process ', rank, ', among ', size, ' processes')

ierr = mpi_finalize()

we compile the file using:

pyccel --language="fortran" --compiler=mpif90 --filename=tests/examples/mpi/ex_0.py

The generated Fortran code is

program main
use MPI
implicit none
integer, dimension(MPI_STATUS_SIZE) :: i_mpi_status
integer :: ierr
integer :: comm
integer :: rank
integer :: i_mpi_error
integer :: size

!
call mpi_init(ierr)
comm = MPI_comm_world
call mpi_comm_size (comm, size, i_mpi_error)
call mpi_comm_rank (comm, rank, i_mpi_error)
print * ,'I process ',rank,', among ',size,' processes'
call mpi_finalize(ierr)

end

now let’s run the executable:

mpirun -n 4 tests/examples/mpi/ex_0

the result is:

I process            1 , among            4  processes
I process            2 , among            4  processes
I process            3 , among            4  processes
I process            0 , among            4  processes

Note that comm is considered as an object in our python file. A communicator has the following attributs:

  • size : total number of processes within the communicator,
  • rank : rank of the current process.

A communicator has also (many of) MPI procedures, defined as methods. The following example shows how to use the send and recv actions with respect to a given communicator.

(listing of tests/examples/mpi/ex_1.py)

# coding: utf-8

from pyccel.mpi import *

ierr = mpi_init()

comm = mpi_comm_world
size = comm.size
rank = comm.rank

n = 4
x = zeros(n, double)
y = zeros((3,2), double)

if rank == 0:
    x = 1.0
    y = 1.0

source = 0
dest   = 1
tagx = 1234
if rank == source:
    ierr = comm.send(x, dest, tagx)
    print("processor ", rank, " sent ", x)

if rank == dest:
    ierr = comm.recv(x, source, tagx)
    print("processor ", rank, " got  ", x)

tag1 = 5678
if rank == source:
    x[1] = 2.0
    ierr = comm.send(x[1], dest, tag1)
    print("processor ", rank, " sent x(1) = ", x[1])

if rank == dest:
    ierr = comm.recv(x[1], source, tag1)
    print("processor ", rank, " got  x(1) = ", x[1])


tagx = 4321
if rank == source:
    ierr = comm.send(y, dest, tagx)
    print("processor ", rank, " sent ", y)

if rank == dest:
    ierr = comm.recv(y, source, tagx)
    print("processor ", rank, " got  ", y)

tag1 = 8765
if rank == source:
    y[1,1] = 2.0
    ierr = comm.send(y[1,1], dest, tag1)
    print("processor ", rank, " sent y(1,1) = ", y[1,1])

if rank == dest:
    ierr = comm.recv(y[1,1], source, tag1)
    print("processor ", rank, " got  y(1,1) = ", y[1,1])

tag1 = 6587
if rank == source:
    y[1,:] = 2.0
    ierr = comm.send(y[1,:], dest, tag1)
    print("processor ", rank, " sent y(1,:) = ", y[1,:])

if rank == dest:
    ierr = comm.recv(y[1,:], source, tag1)
    print("processor ", rank, " got  y(1,:) = ", y[1,:])

ierr = mpi_finalize()

compile the file and execute it using:

pyccel --language="fortran" --compiler=mpif90 --filename=tests/examples/mpi/ex_1.py
mpirun -n 2 tests/examples/mpi/ex_1

the result is:

processor            0  sent    1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000
processor            0  sent x(1) =    2.0000000000000000
processor            0  sent    1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000
processor            0  sent y(1,1) =    2.0000000000000000
processor            1  got     1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000
processor            1  got  x(1) =    2.0000000000000000
processor            1  got     1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000        1.0000000000000000
processor            1  got  y(1,1) =    2.0000000000000000
processor            0  sent y(1,:) =    2.0000000000000000        2.0000000000000000
processor            1  got  y(1,:) =    2.0000000000000000        2.0000000000000000

other examples can be found in tests/examples/mpi.