Note: don't install mpich and openmpi at the same machine
[prefer mpich in linux distributions than openmpi]

MPI API manual pages: https://docs.open-mpi.org/en/v5.0.x/man-openmpi/man3/index.html

Open MPI commands: [https://www.open-mpi.org/doc/current/]
(section 1 man pages)
mpic++          mpif90          ompi_info           orted
mpicc           mpifort         opal_wrapper        orterun
mpicxx          mpirun          orte-clean
mpiexec         ompi-clean      orte-info
mpif77          ompi-server     orte-server


Open MPI general information:
(section 7 man pages)
ompi_crcp       orte_filem      orte_snapc
opal_crs        orte_hosts      orte_sstore


MPI Tutorial:
https://mpitutorial.com/tutorials/mpi-hello-world/
Using MPI and Using Advanced MPI:
http://wgropp.cs.illinois.edu/usingmpiweb/index.html
Using MPI with C:
https://curc.readthedocs.io/en/latest/programming/MPI-C.html
Using MPI with Fortran:
https://curc.readthedocs.io/en/latest/programming/MPI-Fortran.html
An introduction to the Message Passing Interface (MPI) using C:
http://condor.cc.ku.edu/~grobe/docs/intro-MPI-C.shtml
MPI C Examples:
https://people.math.sc.edu/Burkardt/c_src/mpi/mpi.html
Beginner's Guide to MPI (MPICH-v1.0.12) [University of Delaware DEC Alpha Cluster]:
https://www.eecis.udel.edu/~pollock/367/manual/manual.html
Hybrid Patternlets in MPI and OpenMP:
http://selkie.macalester.edu/csinparallel/modules/Patternlets/build/html/Hybrid/Hybrid_Patternlets.html

MPI Install:
$ doas apt-get install mpich
$ mpiexec --version /* information of build details */

To compile a single file program.c:
    mpicc -c program.c
To link the output and make an executable:
    mpicc -o program program.o
Combining compilation and linking in a single command:
    mpicc -o program program.c
To see the full compiler invocation line:
    mpicc -show

Reference: https://www.mpich.org/static/docs/v3.4.x/www1/mpicc.html

C language                  MPI environment
-----------------------------------------------------------
char                        MPI_CHAR
signed short int            MPI_SHORT
signed int                  MPI_INT
signed long int             MPI_LONG
signed long long int        MPI_LONG_LONG_INT
signed char                 MPI_SIGNED_CHAR
unsigned char               MPI_UNSIGNED_CHAR
unsigned short int          MPI_UNSIGNED_SHORT
unsigned int                MPI_UNSIGNED
unsigned long int           MPI_UNSIGNED_LONG
unsigned long long int      MPI_UNSIGNED_LONG_LONG
float                       MPI_FLOAT
double                      MPI_DOUBLE
long double                 MPI_LONG_DOUBLE
wchar_t                     MPI_WCHAR
_Bool                       MPI_C_BOOL
float _Complex              MPI_C_COMPLEX
double _Complex             MPI_C_DOUBLE_COMPLEX
long double _Complex        MPI_C_LONG_DOUBLE_COMPLEX
No cirrespondence           MPI_BYTE
No correspondence           MPI_PACKED


Collective computation built-in operations:
Operation handle            Operation
-----------------------------------------------------------
MPI_MIN                     minimum
MPI_MAX                     maximum
MPI_SUM                     sum
MPI_PROD                    product
MPI_LAND                    logical AND
MPI_LOR                     logical OR
MPI_LXOR                    logical Exclusive OR
MPI_BAND                    bitwise AND
MPI_BOR                     bitwise OR
MPI_EXOR                    bitwise Exclusive OR
MPI_MINLOC                  minimum value and location
MPI_MAXLOC                  maximum value and location


C reference:

#include <mpi.h>

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);


/* array gather */
double *wave = (double *) malloc(n * sizeof(double));
double *rwave = (double *) malloc(N * sizeof(double));
MPI_Gather(wave, n, MPI_DOUBLE, rwave, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);


Python reference:

from mpi4py import MPI

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

""" numpy array gather """
wave = np.sin(xval[sload:eload])
rwave = np.zeros(len(xval), dtype=np.float64)
comm.Gatherv(wave, rwave, 0)
