#C
Copy the code below into mapreduce.c
.
#include <stdio.h>
#include <malloc.h>
#include <math.h>
#include <mpi.h>
/* Define an Ion type to hold the
coordinates of an Ion */
typedef struct Ion
{
double x;
double y;
double z;
} Ion;
/* The reference Ion */
struct Ion reference_ion;
/* Return the square of a number */
double square(double x)
{
return x*x;
}
/* Energy function to be mapped */
double calc_energy( struct Ion ion )
{
double r;
= sqrt( square( reference_ion.x - ion.x ) +
r ( reference_ion.y - ion.y ) +
square( reference_ion.z - ion.z ) );
square
/* The energy is simply 1 / r */
return 1.0 / r;
}
/* You will need to fill in this function to read in
an array of ions and return the array */
struct Ion* readArrayOfIons(int *num_ions)
{
int i;
*ions = (Ion*)malloc(10 * sizeof(Ion));
Ion
*num_ions = 10;
for (i=0; i<10; ++i)
{
[i].x = 0.0;
ions[i].y = 0.0;
ions[i].z = i;
ions}
return ions;
}
int main(int argc, char **argv)
{
int i, start, stop, num_ions, num_calc;
struct Ion *ions_array;
double total_energy, energy;
int rank, nprocs;
(&argc, &argv);
MPI_Init
(MPI_COMM_WORLD, &rank);
MPI_Comm_rank(MPI_COMM_WORLD, &nprocs);
MPI_Comm_size
if (rank == 0)
{
/* Lets put the reference ion at (1,2,3) */
.x = 1.0;
reference_ion.y = 2.0;
reference_ion.z = 3.0;
reference_ion
/* Broadcast this to all processes */
if (nprocs > 1)
{
(&reference_ion, 3, MPI_DOUBLE, 0,
MPI_Bcast);
MPI_COMM_WORLD}
/* Now read in an array of ions */
= readArrayOfIons( &num_ions );
ions_array
/** Broadcast the array of ions. Note that it would be
more efficient to send each process only the ions that
it needs using MPI_Scatter... */
if (nprocs > 1)
{
(&num_ions, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(ions_array, 3*num_ions, MPI_DOUBLE, 0,
MPI_Bcast);
MPI_COMM_WORLD}
}
else
{
/** Receive the broadcast reference ion */
(&reference_ion, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast
/** Receive the number of ions in the array */
(&num_ions, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast
/** Create space for the ions */
= (Ion*)malloc(num_ions * sizeof(Ion));
ions_array
/** Receive the ions array */
(ions_array, 3*num_ions, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast}
= 0.0;
energy = 0.0;
total_energy
= num_ions / nprocs;
num_calc
= rank*num_calc;
start
if (rank == nprocs-1)
{
= num_ions;
stop }
else
{
= start + num_calc;
stop }
for (i=start; i<stop; ++i)
{
+= calc_energy( ions_array[i] );
energy }
("Process %d (%d to %d) Energy = %f\n",
printf, start, stop, energy);
rank
/* Reduce to get the result */
(&energy, &total_energy, 1, MPI_DOUBLE,
MPI_Reduce, 0, MPI_COMM_WORLD);
MPI_SUM
if (rank == 0)
{
("The total energy is %f\n", total_energy);
printf}
();
MPI_Finalize
return 0;
}
The new MPI function here is MPI_Bcast(void *message, int size, MPI_INT, int process, MPI_COMM_WORLD)
. This function copies the message held in message
on the process whose rank is in process
and broadcasts it so that it is received into message
by all of the other processes in the MPI process team. MPI_Bcast
is very useful when you want to send the same message to all processes in a team.
Compile the example using;
mpicc mapreduce.c -o mapreduce
This will give you an executable called mapreduce
.