Sample MPI Codes

  File Modified

File pi.f

Dec 10, 2015 by Indy Siva

File heat.cxx

Dec 10, 2015 by Indy Siva

File pi.c

Dec 10, 2015 by Indy Siva

File MPIHello2.c

Dec 10, 2015 by Indy Siva

File hworld.f90

Dec 10, 2015 by Indy Siva

heat.cxx

C++ code

# include <cstdlib>
# include <iostream>
# include <fstream>
# include <cmath>

using namespace std;

# include "mpi.h"

int main ( int argc, char *argv[] );
double boundary_condition ( double x, double time );
double initial_condition ( double x, double time );
double rhs ( double x, double time );
void update ( int id, int p );

//****************************************************************************80

int main ( int argc, char *argv[] )

//****************************************************************************80
//
//  Purpose:
//
//    MAIN is the main program for HEAT_MPI.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license. 
//
//  Modified:
//
//    23 April 2008
//
//  Author:
// 
//    John Burkardt
//
//  Reference:
//
//    William Gropp, Ewing Lusk, Anthony Skjellum,
//    Using MPI: Portable Parallel Programming with the
//    Message-Passing Interface,
//    Second Edition,
//    MIT Press, 1999,
//    ISBN: 0262571323,
//    LC: QA76.642.G76.
//
//    Marc Snir, Steve Otto, Steven Huss-Lederman, David Walker, 
//    Jack Dongarra,
//    MPI: The Complete Reference,
//    Volume I: The MPI Core,
//    Second Edition,
//    MIT Press, 1998,
//    ISBN: 0-262-69216-3,
//     LC: QA76.642.M65.
//
{
  int id;
  int p;
  double wtime;

  cout << "\n";
  cout << "HEAT_MPI:\n";
  cout << "  C++/MPI version\n";
  cout << "\n";
  cout << "  Solve the 1D time-dependent heat equation.\n";

  MPI::Init ( argc, argv );

  id = MPI::COMM_WORLD.Get_rank ( );

  p = MPI::COMM_WORLD.Get_size ( );
//
//  Record the starting time.
//
  if ( id == 0 ) 
  {
    wtime = MPI::Wtime ( );
  }

  update ( id, p );
//
//  Record the final time.
//
  if ( id == 0 )
  {
    wtime = MPI::Wtime ( ) - wtime;

    cout << "\n";       
    cout << "  Wall clock elapsed seconds = " << wtime << "\n";      
  }

  MPI::Finalize ( );

  cout << "\n";
  cout << "HEAT_MPI:\n";
  cout << "  Normal end of execution.\n";

  return 0;
}
//****************************************************************************80

void update ( int id, int p )

//****************************************************************************80
//
//  Purpose:
//
//    UPDATE computes the solution of the heat equation.
//
//  Discussion:
//
//    If there is only one processor ( P == 1 ), then the program writes the
//    values of X and H to files.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license. 
//
//  Modified:
//
//    23 April 2008
//
//  Author:
// 
//    John Burkardt
//
//  Parameters:
//
//    Input, int ID, the id of this processor.
//
//    Input, int P, the number of processors.
//
{
  double cfl;
  double *h;
  ofstream h_file;
  double *h_new;
  int i;
  int j;
  int j_min = 0;
  int j_max = 100;
  double k = 0.002;
  int n = 11;
  MPI::Status status;
  int tag;
  double time;
  double time_delta;
  double time_max = 10.0;
  double time_min = 0.0;
  double time_new;
  double *x;
  double x_delta;
  ofstream x_file;
  double x_max = 1.0;
  double x_min = 0.0;
//
//  Have process 0 print out some information.
//
  if ( id == 0 )
  {
    cout << "\n";
    cout << "  Compute an approximate solution to the time dependent\n";
    cout << "  one dimensional heat equation:\n";
    cout << "\n";
    cout << "    dH/dt - K * d2H/dx2 = f(x,t)\n";
    cout << "\n";
    cout << "  for " << x_min << " = x_min < x < x_max = " << x_max << "\n";
    cout << "\n";
    cout << "  and " << time_min << " = time_min < t <= t_max = " << time_max << "\n";
    cout << "\n";
    cout << "  Boundary conditions are specified at x_min and x_max.\n";
    cout << "  Initial conditions are specified at time_min.\n";
    cout << "\n";
    cout << "  The finite difference method is used to discretize the\n";
    cout << "  differential equation.\n";
    cout << "\n";
    cout << "  This uses " << p * n << " equally spaced points in X\n";
    cout << "  and " << j_max << " equally spaced points in time.\n";
    cout << "\n";
    cout << "  Parallel execution is done using " << p << " processors.\n";
    cout << "  Domain decomposition is used.\n";
    cout << "  Each processor works on " << n << " nodes, \n";
    cout << "  and shares some information with its immediate neighbors.\n";
  }
//
//  Set the X coordinates of the N nodes.
//  We don't actually need ghost values of X but we'll throw them in
//  as X[0] and X[N+1].
//
  x = new double[n+2];

  for ( i = 0; i <= n + 1; i++ )
  {
    x[i] = ( ( double ) (         id * n + i - 1 ) * x_max
           + ( double ) ( p * n - id * n - i     ) * x_min )
           / ( double ) ( p * n              - 1 );
  }
//
//  In single processor mode, write out the X coordinates for display.
//
  if ( p == 1 )
  {
    x_file.open ( "x_data.txt" );
    for ( i = 1; i <= n; i++ )
    {
      x_file << "  %f", x[i];
    }
    x_file << "\n";

    x_file.close ( );
  }
//
//  Set the values of H at the initial time.
//
  time = time_min;
  h = new double[n+2];
  h_new = new double[n+2];
  h[0] = 0.0;
  for ( i = 1; i <= n; i++ )
  {
    h[i] = initial_condition ( x[i], time );
  }
  h[n+1] = 0.0;
  
  time_delta = ( time_max - time_min ) / ( double ) ( j_max - j_min );
  x_delta = ( x_max - x_min ) / ( double ) ( p * n - 1 );
//
//  Check the CFL condition, have processor 0 print out its value,
//  and quit if it is too large.
//
  cfl = k * time_delta / x_delta / x_delta;

  if ( id == 0 ) 
  {
    cout << "\n";
    cout << "UPDATE\n";
    cout << "  CFL stability criterion value = " << cfl << "\n";;
  }

  if ( 0.5 <= cfl ) 
  {
    if ( id == 0 )
    {
      cout << "\n";
      cout << "UPDATE - Warning!\n";
      cout << "  Computation cancelled!\n";
      cout << "  CFL condition failed.\n";
      cout << "  0.5 <= K * dT / dX / dX = " << cfl << "\n";
    }
    return;
  }
//
//  In single processor mode, write out the values of H.
//
  if ( p == 1 )
  {
    h_file.open ( "h_data.txt" );

    for ( i = 1; i <= n; i++ )
    {
      h_file << "  " << h[i];
    }
    h_file << "\n";
  }
//
//  Compute the values of H at the next time, based on current data.
//
  for ( j = 1; j <= j_max; j++ )
  {

    time_new = ( ( double ) (         j - j_min ) * time_max
               + ( double ) ( j_max - j         ) * time_min )
               / ( double ) ( j_max     - j_min );
//
//  Send H[1] to ID-1.
//
    if ( 0 < id )
    {
      tag = 1;
      MPI::COMM_WORLD.Send ( &h[1], 1, MPI::DOUBLE, id-1, tag );
    }
//
//  Receive H[N+1] from ID+1.
//
    if ( id < p-1 )
    {
      tag = 1;
      MPI::COMM_WORLD.Recv ( &h[n+1], 1,  MPI::DOUBLE, id+1, tag, status );
    }
//
//  Send H[N] to ID+1.
//
    if ( id < p-1 )
    {
      tag = 2;
      MPI::COMM_WORLD.Send ( &h[n], 1, MPI::DOUBLE, id+1, tag );
    }
//
//  Receive H[0] from ID-1.
//
    if ( 0 < id )
    {
      tag = 2;
      MPI::COMM_WORLD.Recv ( &h[0], 1, MPI::DOUBLE, id-1, tag, status );
    }
//
//  Update the temperature based on the four point stencil.
//
    for ( i = 1; i <= n; i++ )
    {
      h_new[i] = h[i] 
      + ( time_delta * k / x_delta / x_delta ) * ( h[i-1] - 2.0 * h[i] + h[i+1] ) 
      + time_delta * rhs ( x[i], time );
    }
//
//  H at the extreme left and right boundaries was incorrectly computed
//  using the differential equation.  Replace that calculation by
//  the boundary conditions.
//
    if ( 0 == id )
    {
      h_new[1] = boundary_condition ( x[1], time_new );
    }
    if ( id == p - 1 )
    {
      h_new[n] = boundary_condition ( x[n], time_new );
    }
//
//  Update time and temperature.
//
    time = time_new;

    for ( i = 1; i <= n; i++ )
    {
      h[i] = h_new[i];
    }
//
//  In single processor mode, add current solution data to output file.
//
    if ( p == 1 )
    {
      for ( i = 1; i <= n; i++ )
      {
        h_file << "  " << h[i];
      }
      h_file << "\n";
    }
  }

  if ( p == 1 )
  {
    h_file.close ( );
  }

  delete [] h;
  delete [] h_new;
  delete [] x;

  return;
}
//****************************************************************************80

double boundary_condition ( double x, double time )

//****************************************************************************80
//
//  Purpose:
//
//    BOUNDARY_CONDITION evaluates the boundary condition of the differential equation.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license. 
//
//  Modified:
//
//    23 April 2008
//
//  Author:
// 
//    John Burkardt
//
//  Parameters:
//
//    Input, double X, TIME, the position and time.
//
//    Output, double BOUNDARY_CONDITION, the value of the boundary condition.
//
{
  double value;
//
//  Left condition:
//
  if ( x < 0.5 )
  {
    value = 100.0 + 10.0 * sin ( time );
  }
  else
  {
    value = 75.0;
  }
  return value;
}
//****************************************************************************80

double initial_condition ( double x, double time )

//****************************************************************************80
//
//  Purpose:
//
//    INITIAL_CONDITION evaluates the initial condition of the differential equation.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license. 
//
//  Modified:
//
//    23 April 2008
//
//  Author:
// 
//    John Burkardt
//
//  Parameters:
//
//    Input, double X, TIME, the position and time.
//
//    Output, double INITIAL_CONDITION, the value of the initial condition.
//
{
  double value;

  value = 95.0;

  return value;
}
//****************************************************************************80

double rhs ( double x, double time )

//****************************************************************************80
//
//  Purpose:
//
//    RHS evaluates the right hand side of the differential equation.
//
//  Licensing:
//
//    This code is distributed under the GNU LGPL license. 
//
//  Modified:
//
//    23 April 2008
//
//  Author:
// 
//    John Burkardt
//
//  Parameters:
//
//    Input, double X, TIME, the position and time.
//
//    Output, double RHS, the value of the right hand side function.
//
{
  double value;

  value = 0.0;

  return value;
}

pi.c

#include <mpi.h>
#include <stdio.h>
#include <math.h>

double f( double );
double f( double a )
{
    return (4.0 / (1.0 + a*a));
}

int main( int argc, char *argv[])
{
    int done = 0, n, myid, numprocs, i;
    double PI25DT = 3.141592653589793238462643;
    double mypi, pi, h, sum, x;
    double startwtime = 0.0, endwtime;
    int  namelen;
    char processor_name[MPI_MAX_PROCESSOR_NAME];

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
    MPI_Get_processor_name(processor_name,&namelen);

    fprintf(stderr,"Process %d on %s\n",
            myid, processor_name);

    n = 0;
    while (!done)
    {
        if (myid == 0)
        {
/*
 *             printf("Enter the number of intervals: (0 quits) ");
 *                         scanf("%d",&n);
 *                         */
            if (n==0) n=100; else n=0;

            startwtime = MPI_Wtime();
        }
        MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
        if (n == 0)
            done = 1;
        else
        {
            h   = 1.0 / (double) n;
            sum = 0.0;
            for (i = myid + 1; i <= n; i += numprocs)
            {
                x = h * ((double)i - 0.5);
                sum += f(x);
            }
            mypi = h * sum;

            MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

            if (myid == 0)
            {
                printf("pi is approximately %.16f, Error is %.16f\n",
                       pi, fabs(pi - PI25DT));
                endwtime = MPI_Wtime();
                printf("wall clock time = %f\n",
                       endwtime-startwtime);
            }
        }
    }
    MPI_Finalize();

    return 0;
}

MPIHello2.c

#include <stdio.h>
#include <mpi.h>

int main(int argc, char *argv[])
{
   int rank, numprocs;

   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
   printf("Hello World from proces %d of %d.\n",rank,numprocs);
   MPI_Finalize();
}

hworld.f90

program hworld
USE MPI

character*(MPI_MAX_PROCESSOR_NAME) host
integer ncores,rank,ierr,hostname_len

call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,ncores,ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr)
call MPI_GET_PROCESSOR_NAME(host,hostname_len,ierr)
write (6,'(''  Hello from mpif90 on host '' , a10, '', core '',i5, '' of '',i5,'' cores'')') &
        host,rank,ncores
call MPI_FINALIZE(ierr)

stop
end

pi.f

c**********************************************************************
c     This program calculates the value of pi, using numerical integration
c     with parallel processing.  The user selects the number of points of
c     integration.  By selecting more points you get more accurate results
c     at the expense of additional computation
c
c     This version is written using p4 calls to handle message passing
c     It should run without changes on most workstation clusters and MPPs.
c
c     Each node:
c     1) receives the number of rectangles used in the approximation.
c     2) calculates the areas of it's rectangles.
c     3) Synchronizes for a global summation.
c     Node 0 prints the result.
c
c     Constants:
c
c     SIZETYPE    initial message to the cube
c     ALLNODES    used to load all nodes in cube with a node process
c     INTSIZ      four bytes for an integer
c     DBLSIZ      eight bytes for double precision
c
c     Variables:
c
c     pi  the calculated result
c     n   number of points of integration.
c     x           midpoint of each rectangle's interval
c     f           function to integrate
c     sum,pi      area of rectangles
c     tmp         temporary scratch space for global summation
c     i           do loop index
c****************************************************************************
      program main

      include 'mpif.h'

      double precision  PI25DT
      parameter        (PI25DT = 3.141592653589793238462643d0)

      integer   INTSIZ , DBLSIZ,  ALLNODES,   ANYNODE
      parameter(INTSIZ=4,DBLSIZ=8,ALLNODES=-1,ANYNODE=-1)

      double precision  pi, h, sum, x, f, a, temp
      integer n, myid, numnodes, i, rc
      integer sumtype, sizetype, masternode
      integer status(3)

c     function to integrate
      f(a) = 4.d0 / (1.d0 + a*a)

      call MPI_INIT( ierr )
      call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )
      call MPI_COMM_SIZE( MPI_COMM_WORLD, numnodes, ierr )
c     print *, "Process ", myid, " of ", numnodes, " is alive"

      sizetype   = 10
      sumtype    = 17
      masternode =  0

 10      if ( myid .eq. 0 ) then

         write(6,98)
 98            format('Enter the number of intervals: (0 quits)')
         read(5,99)n
 99            format(i10)

         do i=1,numnodes-1
            call MPI_SEND(n,1,MPI_INTEGER,i,sizetype,MPI_COMM_WORLD,rc)
         enddo

      else

         call MPI_RECV(n,1,MPI_INTEGER,masternode,sizetype,
     +        MPI_COMM_WORLD,status,rc)

      endif

c     check for quit signal
      if ( n .le. 0 ) goto 30

c     calculate the interval size
      h = 1.0d0/n

      sum  = 0.0d0
      do 20 i = myid+1, n, numnodes
         x = h * (dble(i) - 0.5d0)
         sum = sum + f(x)
 20         continue
      pi = h * sum

      if (myid .ne. 0) then

         call MPI_SEND(pi,1,MPI_DOUBLE_PRECISION,masternode,sumtype,
     +        MPI_COMM_WORLD,rc)

      else

         do i=1,numnodes-1
            call MPI_RECV(temp,1,MPI_DOUBLE_PRECISION,i,sumtype,
     +           MPI_COMM_WORLD,status,rc)
            pi = pi + temp
         enddo
      endif

c     node 0 prints the answer.
      if (myid .eq. 0) then
         write(6, 97) pi, abs(pi - PI25DT)
 97            format('  pi is approximately: ', F18.16,
     +        '  Error is: ', F18.16)
      endif

      goto 10

 30      call MPI_FINALIZE(rc)
      end

Reference

1. http://people.sc.fsu.edu/~jburkardt/cpp_src/heat_mpi/heat_mpi.html
2.

 pi.f