Problem 4.3: (Continuation of Problem 2.1) In 3D, N particles are arranged, initially,
in a 101010 cube, i.e., any triplet of random numbers in [0, 10] can be the coordinates
of a particle. These particles interact under the so-called Lennard-Jones potential
Vij
1
2
rij12 rij6
where Vij is the pair-wise potential between particles i and j with distance rij. Write a
parallel program to minimize the total (Lennard-Jones potential) energy of the particle
system by adjusting particle positions. The system has N=5000 particles. Please do the
following three parts:
(1)
Write a program to use 8 processors to minimize the system total potential energy
by a Simulated Annealing Method.
(2)
Write a program to use 8 processors to minimize the system total potential energy
by a Molecular Dynamics Method. In this method, run enough time steps so that
the system energy you obtained is similar to (1).
(3)
Next, do similar work as in (1) and (2) above, but use 16 processors each
Algorithm Description
The Simulated Annealing Method is readily implemented from the previous codes
in project 2. Being Monte Carlo method, it utilizes biased random walks to lower the
energy of a given system. In algorithm for SA method, two things are being randomly
chosen: magnitude and direction of the movement. By using molecular dynamic, one
hopes to use physical forces to guide the random walks, fix either the magnitude or
direction of the move, therefore increase the acceptance rate. The molecular forces are
proportion negative derivative of the potential:
Fj
N
6
12
( 7
) ( x, y, z )
13
r
ij
r
ij
i 1,i j
However, since the forces involve very high power, the magnitude might be very large
comparing to cell size. It would be more ideal to just use the direction coupled with a
random magnitude that we control. It should be noted that calculation of forces requires
more computational power than random walk generation. Since the stochastic element
must remain in order for MC method to work, the force does not need to be explicitly
calculated. Approximation is much more efficient since precision is not required and
computational cost is more important. For this reason, timing results will be collected in
energy vs. iterations rather than real time, since this program implements explicit
calculation of forces. Problem with random number generator implemented in sequential,
which always give the same random number in order, is resolved by seeding the
generator with multiple of rank.
Program:
#include <math.h>
#include <iostream.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mpi.h"
struct Particle {
double x;
double y;
double z;
double U;
};
struct minloc {
double value;
int rank;
};
double U (Particle[]);
double U (Particle[], Particle, int);
double d (Particle, Particle);
double v (Particle, Particle);
void fj (Particle[], int, double[]);
void boundry (double&);
void mdboundry (double&, double);
double rnd();
void init (Particle[]);
void vibrate (Particle[], int);
void mdvibrate (Particle[], int);
const int pmax = 1000;
const int imax = 100000;
double range = 5;
using namespace MPI;
int main (int argc, char* argv[])
{
Particle pi [pmax];
Particle pj [pmax];
double min, uj, mint;
Init (argc, argv);
int rank = COMM_WORLD.Get_rank();
int size = COMM_WORLD.Get_size();
srand ((rank+1)*time(NULL));
if (rank == 0)
cout <<"MC : "<<size<<endl;
MPI_Datatype ptype;
MPI_Type_contiguous(4,MPI_DOUBLE,&ptype);
MPI_Type_commit(&ptype);
double st;
st = MPI_Wtime();
init(pi);
bool send;
min = U(pi);
if (rank == 0)
cout <<"0\t"<<min<<endl;
for (int i = 1; i <= imax; i++)
{
memcpy (pj, pi, sizeof(pj));
int k = int(floor(rnd()*pmax));
Particle p = pi[k];
vibrate(pi, k);
uj = U(pi, p, k);
if (uj < min)
min = uj;
else if(exp((min - uj))< rnd())
memcpy (pi, pj, sizeof (pj));
else
min = uj;
if (i%5000==0)
{
send = false;
mint = 0;
MPI_Allreduce (&min, &mint, 1, MPI_LONG_DOUBLE,
MPI_MIN, COMM_WORLD);
MPI_Barrier(COMM_WORLD);
if (mint == min && send == false)
{
MPI_Bcast (&pi, pmax, ptype, rank, COMM_WORLD);
send = true;
}
}
if (i%50==0&&rank==0)
cout <<i<<'\t'<<min<<endl;
}
Finalize();
}
void init (Particle ps[])
{
for (int i = 0; i< pmax; i++)
{
ps[i].x = rnd() * 10;
ps[i].y = rnd() * 10;
ps[i].z = rnd() * 10;
ps[i].U = 0;
}
}
void mdvibrate (Particle ps[], int i)
{
double v[3];
for (int p=0; p<3; p++)
v[p]=0;
mdboundry (ps[i].x, v[0]);
mdboundry (ps[i].y, v[1]);
mdboundry (ps[i].z, v[2]);
}
void fj (Particle ps[], int i, double v[])
{
double ds, f;
for (int j = 0; j < pmax; j++)
if (j != i)
{
ds = d(ps[i], ps[j]);
f = 6/pow(ds,7) - 12/pow(ds,13);
v[0] = f*(ps[j].x - ps[i].x)/ds;
v[1] = f*(ps[j].y - ps[i].y)/ds;
v[2] = f*(ps[j].z - ps[i].z)/ds;
}
ds = sqrt (pow(v[0],2)+pow(v[1],2)+pow(v[1],2));
for (int i1 = 0; i1 < 3; i1++)
v[i1]/=ds;
}
void vibrate (Particle ps[], int i)
{
boundry (ps[i].x);
boundry (ps[i].y);
boundry (ps[i].z);
}
void mdboundry (double& a, double d)
{
a+= d*range;
if (a>10)
a = a - 10;
else if (a < 0)
a = 10 + a;
}
void boundry (double& a)
{
a += range*rnd()-range/2;
if (a>10)
a = a - 10;
else if (a < 0)
a = 10 + a;
}
double U (Particle ps[])
{
double t = 0;
for (int i = 0; i < pmax; i++)
{
for (int j = 0; j < pmax; j++)
if (i != j)
ps[i].U += v (ps[i], ps[j]);
t+= ps[i].U;
}
return t;
}
double U (Particle ps[], Particle p, int mix)
{
ps[mix].U = 0;
double t = 0;
for (int i = 0; i < pmax; i++)
{
if (i != mix)
{
double newU = ps[i].U - v(ps[i],p) + v(ps[i], ps[mix]);
ps[i].U=newU;
ps[mix].U=ps[mix].U+v(ps[mix],ps[i]);
}
}
for (int i1 = 0; i1 < pmax; i1++)
t+= ps[i1].U;
return t;
}
double v (Particle i, Particle j)
{
return (double)1/pow(d(i,j),12)- (double)2/pow(d(i,j),6);
}
double d (Particle i, Particle j)
{
return sqrt(pow (i.x - j.x, 2) + pow (i.y - j.y, 2) + pow (i.z j.z, 2));
}
double rnd ()
{
return double(rand()) / double(RAND_MAX);
}
Result
The hypothesis for the algorithm is that MD should perform much better than MC
method since it has a much larger acceptance rate. However, the difference in result is
not as significant as predicted. There may be many factors that can contribute to this.
First, the magnitude or direct both or a mixture of the two. In order to generate random
walks, however, uncertainty in at least one element has to there. Some choice of
uncertainty will work better than others. Also important is the range of movement that’s
allowed by each random move, since average magnitude of force will decrease as the
energy become lowered.
2.E+03
MC Anealing
method
MD method
1.E+03
energy
0.E+00
-1.E+03
-2.E+03
-3.E+03
-4.E+03
0
20000
40000
60000
iteration
80000
100000
120000
© Copyright 2026 Paperzz