Tutorial
========


Invoking the interpreter
------------------------

In the following examples, we assume that a parallelized version of
the Python interpreter was launched using the implementation-provided
MPI startup mechanism. With the MPICH distribution on a cluster of
five PC's running GNU/Linux and listed in file ``nodes.dat``, this can
be accomplished by typing::

       $ mpirun -np 5 -machinefile nodes.dat <prefix>/bin/bwpython -i

from a command-line shell environment like bash. After that, the
``MPI`` module can be imported by typing::

       >>> from mpi4py import MPI


Hello World!
------------

By typing the following sentences in the Python prompt, output from
all processes should be obtained.

>>> print 'Hello World! I am process', MPI.rank, 'of', MPI.size
Hello World! I am process 0 of 5
Hello World! I am process 4 of 5
Hello World! I am process 2 of 5
Hello World! I am process 1 of 5
Hello World! I am process 3 of 5


Point-to-Point communications
-----------------------------

First, we prepare some different data in each process.

>>> sendbuf = 10 * MPI.size + MPI.rank
>>> print '[%d]' % MPI.rank, sendbuf
[0] 50
[4] 54
[2] 52
[1] 51
[3] 53

Next, we can try some point-to-point communications.

* using standard form ...

>>> MPI.COMM_WORLD.Send(sendbuf, dest=0, tag=7)
>>> recvbuf = []
>>> if MPI.rank == 0:
...     for i in xrange(MPI.size):
...         data = MPI.COMM_WORLD.Recv(source=i, tag=7)
...         recvbuf.append(data)
...
>>> print '[%d] %s' % (MPI.rank, recvbuf)
[0] [50, 51, 52, 53, 54]
[4] []
[2] []
[1] []
[3] []

* using ports ...

>>> MPI.COMM_WORLD[0].Send(sendbuf) # get port 0, send with default tag
>>> recvbuf = []
>>> if MPI.rank == 0:
...     for p in MPI.COMM_WORLD:         # iterate over comm
...         recvbuf += [ p.Recv() ] # recv with default tag
...
>>> print '[%d] %s' % (MPI.rank, recvbuf)
[0] [50, 51, 52, 53, 54]
[4] []
[2] []
[1] []
[3] []

* using ports with stream syntax ...

>>> MPI.COMM_WORLD[0] << [ sendbuf ] # input stream must be list !!!
>>>
>>> recvbuf = [] # output stream must be list, too !!!
>>> if MPI.rank == 0:
...     for p in MPI.COMM_WORLD:
...         p >> recvbuf
...
>>> print '[%d] %s' % (MPI.rank, recvbuf)
[0] [50, 51, 52, 53, 54]
[4] []
[2] []
[1] []
[3] []


Collective communications
-------------------------

* broadcast using standard form ...

>>> sendbuf = MPI.rank**2 # square of process rank
>>>
>>> root = MPI.size-1 # last process
>>> recvbuf = MPI.COMM_WORLD.Bcast(sendbuf, root)
>>> MPI.pprint( '[%d] %s' % (MPI.rank, recvbuf) )
[0] 16
[1] 16
[2] 16
[3] 16
[4] 16

* gather using ports ...

>>> sendbuf = [ MPI.rank**2 , MPI.rank%2!=0 ]
>>> MPI.pprint( '[%d] %s' % (MPI.rank, sendbuf) )
[0] [0, False]
[1] [1, True]
[2] [4, False]
[3] [9, True]
[4] [16, False]
>>>
>>> root = MPI.size/2 # middle process
>>> recvbuf = MPI.COMM_WORLD[root].Gather(sendbuf)
>>> MPI.pprint( '[%d] %s' % (MPI.rank, recvbuf) )
[0] None
[1] None
[2] [[0, False], [1, True], [4, False], [9, True], [16, False]]
[3] None
[4] None

* scatter using ports ...

>>> root = MPI.size/2 # middle process
>>>
>>> sendbuf = None
>>> if MPI.rank = root: # set data in root
...     sendbuf = [ (i, i**2, i**3) for i in range(MPI.size) ]
>>> MPI.pprint( '[%d] %s' % (MPI.rank, sendbuf) )
[0] None
[1] None
[2] [(0, 0, 0), (1, 1, 1), (2, 4, 8), (3, 9, 27), (4, 16, 64)]
[3] None
[4] None
>>>
>>> p = MPI.COMM_WORLD[root]
>>> recvbuf = p.Scatter(sendbuf)
>>> MPI.pprint( '[%d] %s' % (MPI.rank, recvbuf) )
[0] (0, 0, 0)
[1] (1, 1, 1)
[2] (2, 4, 8)
[3] (3, 9, 27)
[4] (4, 16, 64)


Communicators
--------------

* duplication and comparison ...

>>> MPI.rprint([MPI.IDENT, MPI.CONGRUENT, MPI.SIMILAR, MPI.UNEQUAL])
[1, 2, 3, 4]
>>>
>>> comm = MPI.COMM_WORLD.Dup();
>>> rslt = MPI.Comm.Compare(comm, MPI.COMM_WORLD)
>>> MPI.pprint( '[%d] %s' % (MPI.rank, rslt) )
[0] 2
[1] 2
[2] 2
[3] 2
[4] 2
>>>
>>> flag = ( comm == MPI.COMM_WORLD )
>>> MPI.pprint( '[%d] %s' % (MPI.rank, flag) )
[0] True
[1] True
[2] True
[3] True
[4] True



* splitting ...

>>> color = int(MPI.rank < MPI.size/2)
>>> key   = MPI.size-MPI.rank
>>> fmt = '[%d] color: %s - key: %s'
>>> MPI.pprint( fmt % (MPI.rank, color, key) )
[0] color: 1 - key: 5
[1] color: 1 - key: 4
[2] color: 0 - key: 3
[3] color: 0 - key: 2
[4] color: 0 - key: 1
>>>
>>> comm = MPI.COMM_WORLD.Split(color, key)
>>> rk = comm.Get_rank()
>>> sz = comm.Get_size()
>>>
>>> fmt = '[%d] rank: %d - size: %d'
>>> MPI.pprint( fmt % (MPI.rank, rk, sz) )
[0] rank: 1 - size: 2
[1] rank: 0 - size: 2
[2] rank: 2 - size: 3
[3] rank: 1 - size: 3
[4] rank: 0 - size: 3

