Sie sind auf Seite 1von 44

CS501: Homework 1

Yingwei Wang

Department of Mathematics, Purdue University, West Lafayette, IN, USA

Searching in Unix

Question: To what does [a-z]*.py expand, if used as an argument in a Unix command?


Might it include a directory? To what does *.??? expand?
Answer:
[a-z]*.py means the the files whose name begins with a letter (from a to z) and whose
extension name is .py.
It cannot include a directory.
*.??? means the files whose extension name includes exact three characters.

Remove lines

Question: Write a filter mfilter.py that removes all lines except those whose first character other than whitespace is not % and whose last character other than whitespace (or
newline) is not ;.
Answer: My python code mfilter.py is:
import sys
data = open(sys.argv[1])
list = []
for line in data:
st = line.strip()
if st:
if st.startswith(%):
pass

E-mail address: wywshtj@gmail.com; Tel : 765 237 7149

Yingwei Wang

Computing for Science and Engineering

elif st.endswith(;):
pass
else:
list.append(line)
sys.stdout.writelines(list[:-1])
Just type % python mfilter.py mfilter_input.txt, then we can get the results we
want.

Break lines

Question: Write a Python script next2m.py, which from a file listing pairs of neighboring
atoms with any number of pairs per line, constructs a file listing the immediate neighbors
of each atom with the atom number printed first followed by a list of its neighbors. You
may find it convenient to use a dict of lists.
Answer: My python code break.py is:
import sys
maxlength = int(sys.argv[2])
data = open(sys.argv[1])
list = []
for line in data:
linelength = len(line)
# print linelength
if linelength ==1:
pass
else:
index = 0
while (index < linelength):
max = index + maxlength+1
if max < linelength:
temp = line.rfind( , index, max)
if temp > 0:
2

Yingwei Wang

Computing for Science and Engineering

sys.stdout.write(line[index:temp])
print \t
index = temp + 1
else:
temp = line.find( ,max)
if temp > 0:
sys.stdout.write(line[index:temp])
print \n
index = linelength + 1
else:
sys.stdout.write(line[index:-1])
print \n
index = linelength + 1
else:
sys.stdout.write(line[index:-1])
print \n
index = linelength + 1
Just type % python break.py break.dat 39, then we can get the results we want.

Find pairs

Question: Write a Python script next2m.py, which from a file listing pairs of neighboring
atoms with any number of pairs per line, constructs a file listing the immediate neighbors
of each atom with the atom number printed first followed by a list of its neighbors. You
may find it convenient to use a dict of lists.
Answer: My python code next2me.py is:
import sys
data = open(sys.argv[1])
dist = {}
for line in data:
ss = line.split()
sl = len(ss)
for k in range(0,sl,2):
3

Yingwei Wang

Computing for Science and Engineering

ford = ss[k]
back = ss[k+1]
if dist.has_key(ford):
list = []
pp = dist[ford]
list.extend(pp)
if pp.count(back) == 0:
list.append(back)
dist[ford] = list
else:
pass
else:
dist[ford] = [back]
if dist.has_key(back):
list = []
pp = dist[back]
list.extend(pp)
if pp.count(ford) == 0:
list.append(ford)
dist[back] = list
else:
pass
else:
dist[back] = [ford]
keylist = dist.keys()
keylist.sort()
for key in keylist:
skey = str(dist[key])
sys.stdout.write(key+\t+skey+\n)
If pairs.dat contains
1
3
9
13
17
19

3
5
10
15
18
22

1
5
9
14
19

17
6
11
13
17

2
5
9
15
19

1
7
12
16
20

3
5
13
15
19

4
8
9
17
21

Yingwei Wang

Computing for Science and Engineering

the result of
$ python next2me.py pairs.dat
is
1
10
11
12
13
14
15
16
17
18
19
2
20
21
22
3
4
5
6
7
8
9

[3, 17, 2]
[9]
[9]
[9]
[9, 15, 14]
[13]
[13, 16, 17]
[15]
[1, 15, 18, 19]
[17]
[17, 20, 21, 22]
[1]
[19]
[19]
[19]
[1, 4, 5]
[3]
[3, 6, 7, 8]
[5]
[5]
[5]
[10, 11, 12, 13]

Remark 4.1. My result is a little bit different from what we want. The reason is that the
type of all the items in my dist, which is a dictionary, including keys and values, is string,
instead of int.

CS501: Homework 2
Yingwei Wang

Department of Mathematics, Purdue University, West Lafayette, IN, USA

Equally spaced points

Question: A piecewise linear path z in 2 dimensions can be represented as a list of 2-tuples


specifying the coordinates of the knots (the points that define the line segments). Write
a Python module equalizem that defines a function equalize(z) that returns a list of
2-tuples that are equally spaced from the beginning to the end of z as measured along the
path. This list should contain as many points as does z. Your function should not alter z.
Answer: My python code equalizem.py is:
#!/usr/bin/env python
import math
def equalize(z):
dx = []
dy = []

# equalizem.py

zt = 0.0
dz = []
dz.append(zt)
zz = []
zz.append(z[0])
zl = len(z)-1
for k in range(zl):
xt = z[k+1][0] - z[k][0]

E-mail address: wywshtj@gmail.com; Tel : 765 237 7149

Yingwei Wang

Computing for Science and Engineering

yt = z[k+1][1] - z[k][1]
zt = zt + math.sqrt(xt**2 + yt**2)
dz.append(zt)
dx.append(xt)
dy.append(yt)
h = dz[-1]/zl
rem = h
for j in range(zl):
xn = z[j][0]
yn = z[j][1]
R = dz[j+1] - dz[j]
r = rem - dz[j]
while (rem - dz[j+1] < 1e-6):
xx = dx[j]*r/R
yy = dy[j]*r/R
xn = xn + xx
yn = yn + yy
zz.append((xn,yn))
rem = rem + h
r = h
return zz
if __name__ == __main__:
print equalize([(0, 0), (3, 4), (6, 4), (6, 2), (6, 0)]); \
print [(0., 0.), (1.8, 2.4), (4., 4.), (6., 3.), (6., 0.)]

Find

Question: Write a Python script find.py which takes two arguments: (i) a valid path name
for some directory and (ii) a string. It examines the names of all files and subdirectories
that are below the given directory in the file hierarchy, and for each such file or subdirectory
whose name contains the given string, it prints the path of that file or subdirectory, one
path per line. If the given path is relative, it prints relative paths. If the given path is
absolute, it prints absolute paths.
2

Yingwei Wang

Computing for Science and Engineering

Answer: My python code find.py is:


# findtest.py
import sys
import os
path = str(sys.argv[1])
string = str(sys.argv[2])
for root, dirs, files in os.walk(path):
for dir in dirs:
df = os.path.join(root,dir)
# print df
st = df.rfind(/)
if df.find(string,st) > 0:
sys.stdout.write(df)
sys.stdout.write(\t\n)
for file in files:
tf = os.path.join(root, file)
# print tf
if tf.find(string) > 0:
sys.stdout.write(tf)
sys.stdout.write(\n)
For example, if the script
#!/usr/bin/env python
import os
os.makedirs(junk/Myperl)
os.makedirs(junk/Mypython/current)
open(junk/pythagoras, w).close()
open(junk/ipython.txt, w).close()
open(junk/Myperl/pl2python, w).close()
open(junk/Myperl/pyth2pl, w).close()
open(junk/Mypython/current/python2.5, w).close()

is first executed, then


$ find.py junk python
junk/Mypython
junk/ipython.txt

Yingwei Wang

Computing for Science and Engineering

junk/Myperl/pl2python
junk/Mypython/current/python2.5

Polynomial

Question:
Construct a module polynomial.py that defines a Polynomial class. The constructor
should take as its argument a dictionary whose keys are exponents of the variable x, each a
value that is an integer coefficient of the corresponding term. Terms with zero coefficients,
if any, should be omitted. Define a method for the str function that prints the polynomial
as illustrated in the template given below. Note that a leading plus sign is omitted and that
terms are ordered from highest exponent to lowest. Also, define a method that constructs
the product of two polynomials, one that evaluates a polynomial, and one that returns the
degree of a polynomial. Define the degree of the zero polynomial to be float(-inf).
Answer: My python code polynomial.py is:
#!/usr/bin/env python polynomial.py
class Polynomial(object):
def __init__(self, data):
try:
for key in data.keys():
if data[key] == 0:
del data[key]
except IndexError:
pass
self.data = data.copy()
def __repr__(self):
return Polynomial( + repr(self.data) + )
def __str__(self):
keylist = self.data.keys()
keylist.sort()
if len(keylist) == 0:
return 0
result = []
k = 0
4

Yingwei Wang

Computing for Science and Engineering

for key in reversed(keylist):


val = self.data[key]
if val == 0:
continue
if val < 0:
result.append(-)
val = - val
elif val > 0 and k != 0:
result.append(+)
result.append(%gx^%d %(val,key))
k += 1
return .join(result)
def __mul__(self, other):
key1 = self.data.keys()
key1.sort()
d1 = len(key1)
key2 = other.data.keys()
key2.sort()
d2 = len(key2)
prod = {}
for k1 in key1:
for k2 in key2:
keyp = prod.keys()
kk = k1 + k2
kv = self.data[k1]*other.data[k2]
if (keyp.count(kk) > 0):
prod[kk] += kv
if prod[kk] == 0:
del prod[kk]
else:
prod[kk] = kv
return Polynomial(prod)
def __call__(self, x):
"Evaluate at X==x"
5

Yingwei Wang

Computing for Science and Engineering

res = 0
px = 1
for key in self.data:
px = x**key
res += px*self.data[key]
return res
def degree(self):
deg = 0
if self.data == {}:
deg = -float(inf)
else:
deg = max(self.data.keys())
return deg
if __name__ == __main__:
p = Polynomial({0:2, 2:-1})
print repr(p)
print p(%d) = %d % (3, p(3)); \
print p(3) = -7
print p*p; \
print 1x^4-4x^2+4x^0
q = Polynomial({2:1, 0:2})
print degree(%s) = %d % (str(q), q.degree()); \
print degree(1x^2+2x^0) = 2
print p, , q; \
print -1x^2+2x^0 1x^2+2x^0
print p*q; \
print -1x^4+4x^0
print Polynomial({}); \
print 0
print Polynomial({}).degree(); \
print -inf
rdata = {0:2, 2:-1}; r = Polynomial(rdata)
rdata[2] = 3
print r ;\
print -1x^2+2x^0

CS501: Homework 3
Yingwei Wang

Department of Mathematics, Purdue University, West Lafayette, IN, USA

Underflow

Question: Give an example of three double precision machine numbers x, y, z such that (x
* y) * z underflows to zero but x * (y * z) does not.
Answer:
x = 21000 , y = 21000 , z = 21000 .

Assemblem

Question: Complete the following template for script assemblem.py by completing the
definiiton of the vectorized function assembleV so that it has no (explicit) loop, i.e., it does
not use for, while, or recursion. A way of doing this is to use (i) relational ufuncs, (ii)
numpy.where, and (iii) tuples of arrays for indexing.
Answer:
#!/usr/bin/env python # assemblem.py
import numpy as np
import time
def assemble(N): # N = grid size
n = N*N # number of unknowns
a = np.zeros((n, n))
t0 = time.time()
for i in range(n):
ix = i // N; iy = i % N # (ix, iy) is the 2D grid index

E-mail address: wywshtj@gmail.com; Tel : 765 237 7149

Yingwei Wang

Computing for Science and Engineering

a[i, i] = 4.
if iy > 0:
a[i-1, i] = -1.
if iy < N-1: a[i+1, i] = -1.
if ix > 0:
a[i-N, i] = -1.
if ix < N-1: a[i+N, i] = -1.
t1 = time.time()
print elapsed time is, t1 - t0
return a
def assembleV(N):
n = N*N
a = np.zeros((n, n))
t0 = time.time()
b = 2*np.eye(N) - np.eye(N,M=None, k=1) - np.eye(N,M=None, k=-1)
c = np.eye(N)
a = np.kron(b,c) + np.kron(c,b)
t1 = time.time()
print elapsed time is, t1 - t0
return a
if __name__ == __main__:
N = 6
a = assemble(N)
aV = assembleV(N)
print np.all(aV == a)

Energy

Question: Complete the following template for a file coulomb.py by writing functions that
return the electrostatic energy (in kcal/mol) for a set of particles with 3-dimensional positions rvec[0], rvec[1], . . . , rvec[N-1] (in Angstroms) and partial charges q[0], q[1],
. . . , q[N-1] (in elementary charges). (Pardon the use of non-SI units!) The formula for N
particles is
N X
N
X
qi qj
electrostatic energy =
const
krj ri k2
i=1 j=i+1
where the constant is given in the code and the 2-norm is Euclidean distance.
1. The function energy should be a reasonably straightforward rendition of the formula
2

Yingwei Wang

Computing for Science and Engineering

as a double for loop.


2. The function energyV should be a vectorized single-loop version.
3. The function energyW should be a doubly vectorized loopless version. You are
allowed to do twice as much computation to achieve this!
Answer:
#!/usr/bin/env python # coulumb.py
import numpy as np
const = 332.063681 # A kcal/mol/e^2
def energy(q, rvec):
N = len(q)
eg = 0
for i in range(N):
for j in range(i+1,N):
df = rvec[i] - rvec[j]
dis = np.sqrt((df*df).sum())
eg += const*q[i]*q[j]/dis
return eg
def energyV(q, rvec):
N = len(q)
eg = 0
for i in range(N-1):
rf = np.subtract(rvec,rvec[i])
rs = np.add.reduce(rf*rf, axis=1)
rr = np.sqrt(rs)
qq = q[i]*q
tt = qq[i+1:]/rr[i+1:]
eg += const*np.sum(tt)
return eg
def energyW(q, rvec):
N = len(q)
a = np.ones((N,N))
c = np.reshape(np.triu(a,1),(1,N**2))
rd= np.where(c==1)
q1 = np.outer(q,q)
3

Yingwei Wang

Computing for Science and Engineering

q2 = np.reshape(q1,(1,N**2))
qq = q2[rd]
rx = rvec[:,0]
rx1 = np.subtract.outer(rx,rx)
rx2 = np.reshape(rx1,(1,N**2))
rx3 = (rx2[rd])**2
ry = rvec[:,1]
ry1 = np.subtract.outer(ry,ry)
ry2 = np.reshape(ry1,(1,N**2))
ry3 = (ry2[rd])**2
rz = rvec[:,2]
rz1 = np.subtract.outer(rz,rz)
rz2 = np.reshape(rz1,(1,N**2))
rz3 = (rz2[rd])**2
rr = np.sqrt(rx3+ry3+rz3)
qr = qq/rr
eg = const*np.sum(qr)
return eg

if __name__ == __main__:
rvec = np.array([[0.8, 0., 1.], [0., -0.6, 1.]])
q = np.array([1.0, -1.0])
en = energy(q, rvec)
print energy = %.2f % en
#
env = energyV(q, rvec)
#
print energyV = %.2f % env
#
enw = energyW(q, rvec)
#
print energyW = %.2f % enw
execfile(readatoms.py)
import time
for energy_ in [energy, energyV, energyW]:
t0 = time.time()
en = energy_(q, rvec)
t1 = time.time()
print energy = %.2f, CPU time = %.2f % (en, t1 - t0)

Yingwei Wang

Computing for Science and Engineering

My timing:
1. energy : CPU time = 5.36
2. energyV : CPU time = 0.07
3. energyW : CPU time = 0.16
Actually, twice computation is done in energyW. That is why the time is doubled.

Power Spectrum

Question: Complete the following template for a file fourier.py by defining a function
powerspectrum that uses numpy.fft.fft to compute the power spectrum of data representing function values at equally spaced points on the interval 0 to 2. Its one parameter
is a numpy.ndarray with elements u[0], u[1], . . . , u[N-1] that are the values of some
function at points 0, h, . . . , (N 1)h where h = 2/N.
Answer:
#!/usr/bin/env python # fourier.py
import numpy as np
import pylab
def powerspectrum(u):
N = len(u)
M = int(N/2)
v = np.fft.fft(u)
p = abs(v/N)
pp = p[0:(M+1)]
#
print M
#
print len(pp)
pp[1:M] = 2*pp[1:M]
return pp
if __name__ == __main__:
N = 1024
n = int(N/2)
n1 = int(N/4)
pp = np.pi
h = 2*pp/N
5

Yingwei Wang

Computing for Science and Engineering

x = h*np.array(range(N))
u = np.ndarray((3,N),dtype = float)
xp = x/pp-1
u[0,] = 4*(np.abs(xp)-1)*xp
u[1,] = 8/pp*np.abs(xp) - 4/pp
u[2,0] = 0
u[2,n] = 0
u[2,1:n] = -8/(pp**2)
u[2,(n+1):N] = 8/(pp**2)
#
v0 = powerspectrum(u[0,])
v1 = powerspectrum(u[1,])
v2 = powerspectrum(u[2,])
m = range(1,n1,2)
p0, = pylab.semilogy(m,v0[m])
p1, = pylab.semilogy(m,v1[m])
p2, = pylab.semilogy(m,v2[m])
pylab.xlabel(Angular frequency (odd) m)
pylab.ylabel(Log power spectrum)
pylab.title(Fourier power spectrum)
pylab.legend([p0,p1,p2],[u_0,u_1,u_2])
pylab.savefig(Fourier)
pylab.show()
pylab.close

1. generates periodic discrete data from each of


x
x
1| 1)( 1)

8 x
4
u1 (x) =
| 1|

2
8/ , if 0 < x < ,
8/ 2 ,
if < x < 2,
u2 (x) =

0,
otherwise.
u0 (x) = 4(|

for x = 0, h, . . . , (N 1)h for h = 2/N for N = 1024, and


6

Yingwei Wang

Computing for Science and Engineering

2. computes and plots the log power spectrum vs. angular frequency m for odd values of
m up to N/4 all on the same graph. See Fig.1.

Fourier power spectrum

101

u_0
u_1
u_2

100

Log power spectrum

10-1
10-2
10-3
10-4
10-5
10-6
10-7
10-8 0

50

100
150
200
Angular frequency (odd) m

250

Figure 1: Log power spectrum vs. angular frequency

300

CS501: Homework 4
Yingwei Wang

Department of Mathematics, Purdue University, West Lafayette, IN, USA

Stack

Question: The linked list implementation of a stack of the class notes is based on the
structures
typedef struct Node {
int value;
struct Node *next;
} Node;
typedef struct Stack {
Node *top;
} Stack;

Write a function Stack size that has as its argument a pointer to a stack and returns the
number of items in the stack: You are not allowed to augment the structures. The only way
to solve the problem is to chase pointers until a NULL pointer is reached and count Nodes
along the way.
Answer:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node {
int value;
struct Node *next; // an incomplete type--at this point

E-mail address: wywshtj@gmail.com; Tel : 765 237 7149

Yingwei Wang

Computing for Science and Engineering

} Node;
typedef struct Stack {
Node *top;
} Stack;
Stack *Stack_new(void) {
Stack *stack = (Stack *)malloc(sizeof(Stack));
stack->top = NULL;
return stack;
}
void Stack_push(Stack *stack, int a) {
Node *newNode = (Node *)malloc(sizeof(Node));
if ( newNode == NULL ) {
fprintf(stderr, "Out of memory.\n");
exit(1);
}
newNode->value = a;
newNode->next = stack->top;
stack->top = newNode;
}
int Stack_pop(Stack *stack) {
Node *topNode = stack->top;
if ( topNode == NULL ) {
fprintf(stderr, "Cannot pop empty stack.\n");
exit(1);
}
int a = topNode->value;
stack->top = topNode->next;
free(topNode);
return a;
}
// begin to size
int Stack_size(Stack *stack) {
int size = 0;
Node *cNode = stack->top;
while (cNode != NULL){
cNode = cNode->next;
2

Yingwei Wang

Computing for Science and Engineering

size++;
}
return size;
}

Geometric hashing

Question: You will develop an efficient C code for computing short-range interactions for a
set of N particles in 1 dimension. (Extension to 3 dimensions would not be too difficult.)
Define constants = 120 0.00198721 kcal/mol, = 3.405
A, and rcut = 2.5. (120 K is the
temperature.) The energy for a particle pair separated by distance r is


4 ( )12 ( )6
r
r
if r < rcut and 0 otherwise. You are to write four functions, whose prototypes are given in
the main program below. Your code is to be contained in a single file energy.c.
1. (6 points) As a check, write a function energy, which does a straightforward calculation in order N 2 time by computing the distance (and nonzero energies) between
each pair of particles. The array r[] in the parameter list contains particle positions
in
Angstroms.
2. (6 points) Write a function calc grid that designs a grid of Nc cells, each of width
r cut. The number of cells Nc is to be calculated so that the grid just covers all
particles. (Having one cell too many is all right, but having one cell too few is not.)
Note that the floor function gives a quotient without the fractional part. The first
cell should begin at the least particle position rmin, which is also to be calculated.
3. (9 points) Write a function fill grid that places each particle into the appropriate
grid cell. This is done by creating a linked list of particle numbers for each cell. The
ordering of particles in the list is arbitrary. For simplicity, you will use arrays of ints
instead of pointers. The array element first[i] is to contain the first particle of
cell i, unless it is empty, in which case it is to contain -1. The particle that follows
particle m is to be placed in array element next[m]. Again, -1 is used if there is no
such particle. The addition of a particle to a list can be performed in the same manner
as the Stack push method in the class notes. For each particle, you need to compute
the index of its cell.
3

Yingwei Wang

Computing for Science and Engineering

4. (9 points) Write a function energyF that does a Fast order N calculation by employing
the grid cells to limit pair calculationsincluding distance calculationsto particles
that are either in the same cell or in adjacent cells.
Answer:
My energy.c is :
/* energy.c */
#include <stdio.h>
#include <math.h>
#include <time.h>
static double sigma = 3.405;
static double r_cut = 2.5*3.405;
static double ep = 120*0.00198721;

void init_atoms(int N, double r[N]);


double energy(int N, double r[N]);
double energy2(int N, double r[N], int M, double s[M]);
void calc_grid(int N, double r[N], double r_cut, double *rmin, int *Nc);
void fill_grid(int N, double r[N], double r_cut, double rmin, int Nc, int first[Nc], int
double energyF(int N, double r[N]);

double energy(int N, double r[N]){


double en = 0;
double d = 0;
double ds = 0;
int i;
int j;
for (i=0; i<N; i++)
for (j=i+1; j<N; j++)
{d = fabs(r[j]-r[i]);
if (d < r_cut)
{ds = sigma/d;
en += 4*ep*(pow(ds,12) - pow(ds,6));
}
}

Yingwei Wang

Computing for Science and Engineering

return (en);
}
void calc_grid(int N, double r[N], double r_cut, double *rmin, int *Nc){
double p = r[0];
double q = r[0];
double m;
int i;
for (i = 1; i<N; i++)
{ if (r[i] < p)
p = r[i];
else if (r[i] > q)
q = r[i];
}
*rmin = p;
m = (q-p)/r_cut;
*Nc = floor(m)+1;
}
void fill_grid (int N, double r[N], double r_cut, double rmin, int Nc,
int first[Nc], int next[N])
{
int i;
int j = -2;
double dd;
int dn;
for (i=0; i<Nc; i++)
{ first[i] = -1;
}
for (i=0; i<N; i++)
{ next[i] = -1;
}

for (i=0; i<N; i++)


5

Yingwei Wang

Computing for Science and Engineering

{ dd = fabs(r[i] - rmin);
dn = floor(dd/r_cut);
if (first[dn] == -1)
first[dn] = i;
else
{ j = first[dn];
while(next[j] != -1)
{ j = next[j];
}
next[j] = i;
}
}
}

double energyF(int N, double r[N]){


double en = 0;
double rmin;
int Nc;
calc_grid(N, r, r_cut, &rmin, &Nc);
int first[Nc], next[N];
fill_grid(N, r, r_cut, rmin, Nc, first,next);
int i = 0;
int p = 0;
int q = 0;
int fn[Nc];
// inside the cell
for (i = 0; i<Nc; i++)
{
// find the size
int mi = 0;
p = first[i];
if (p == -1)
{fn[i] = mi;continue;}
else
6

Yingwei Wang

Computing for Science and Engineering

{ mi = 1;
while (next[p] != -1)
{ mi++;
p = next[p];
}
}
fn[i] = mi;
// find the vector and energy
if (mi>1)
{double a[mi];
int j = 1;
p = first[i];
a[0] = r[p];
while (next[p] != -1)
{ p = next[p];
a[j] = r[p];
j++;
}
double ee=0;
ee = energy(mi, a);
en += ee;
}
}
// between two cells
for (i = 0; i<Nc-1; i++)
{
// find the sizes
int m1 = 0;
int m2 = 0;
m1 = fn[i];
m2 = fn[i+1];
if (m1 == 0 || m2 == 0)
{continue;}
else
{
// find the vectors
double a[m1];
7

Yingwei Wang

Computing for Science and Engineering

double b[m2];
int j1 = 1;
int j2 = 1;
p = first[i];
q = first[i+1];
a[0] = r[p];
b[0] = r[q];
while (next[p] != -1)
{ p = next[p];
a[j1] = r[p];
j1++;
}
while (next[q] != -1)
{ q = next[q];
b[j2] = r[q];
j2++;
}
// find the energies
double ee = 0;
ee = energy2(j1, a, j2, b);
en += ee;
}
}
return en;
}

double energy2(int N, double r[N], int M, double s[M]){


double en = 0;
double d = 0;
double ds = 0;
int i;
int j;
for (i=0; i<N; i++)
{ j = 0;
while (j<M)
{ d = fabs(r[i]-s[j]);
8

Yingwei Wang

Computing for Science and Engineering

if (d < r_cut)
{ds = sigma/d;
en += 4*ep*(pow(ds,12) - pow(ds,6));
}
j++;
}
}
return (en);
}

Remark 2.1. I tested my energy.c with the energy_testscript.py. The result is


The desired output is:
energy = -0.24
rmin = 0.85, Nc = 3
first = 2 -1 3
next = -1 0 1 -1
energy = -7457.36, CPU time = ts
energy = -7457.36, CPU time = tf
Your output is:
energy = -0.24
rmin = 0.85, Nc = 3
first = 0 -1 3
next = 1 2 -1 -1
energy = -7457.36, CPU time = 3.76
energy = -7457.36, CPU time = 0.04
The
The
The
The

function
function
function
function

energy is correct.
calc_grid is correct.
fill_grid is incorrect.
energyF is correct.

However, I want to say that actually my fill_grid is also correct. The only difference
between my output and the desired output is the order of the elements in the first and
next, which has no effect on the energy computation.

CS501: Homework 5
Yingwei Wang

Department of Mathematics, Purdue University, West Lafayette, IN, USA

Plotting

Question: The aim is to plot the time series for the total energy and as well particle positions
for the given script. There should be two plots. The second plot should show positions for all
40 particles. Use the data generated for all time steps. Do this by (i) removing statements
marked by //.., (ii) inserting disk file I/O operations into integrate.c, and (iii) appending
I/O and plotting commands to driver.py. Name the modified files integrate1.c and
driver1.py, respectively.
Answer: My integrate1.c and driver1.py are listed as following:
/* integrate1.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h> //..
static double mass = 39.95 * 1.66053886e-27 / 6.94771e-25;
// kcal/mol*ps^2/\AA^2
double forces(int N, double r[N], double F[N]);
int main(int argc, char *argv[argc]){
int nsteps = atoi(argv[1]);
double dt = atof(argv[2]); // ps
FILE *coordfile = fopen("coord.dat", "r");
FILE *rfile = fopen("rfile.dat","w");
FILE *vfile = fopen("vfile.dat","w");
FILE *efile = fopen("efile.dat","w");

E-mail address: wywshtj@gmail.com; Tel : 765 237 7149

Yingwei Wang

Computing for Science and Engineering

int N; fscanf(coordfile, "%d\n", &N);


double r[N], v[N];
for (int n = 0; n < N; n += 1){
fscanf(coordfile, "%lg\n", &r[n]);
fprintf(rfile,"%f\n", r[n]);}
for (int n = 0; n < N; n += 1){
fscanf(coordfile, "%lg\n", &v[n]);
fprintf(vfile,"%f\n", v[n]);}
fclose(coordfile);

double F[N];
double pot_en = forces(N, r, F);
double kin_en = 0.;
for (int n = 1; n < N-1; n += 1) kin_en += v[n]*v[n];
kin_en *= 0.5*mass;
fprintf(efile,"%f\n", kin_en+pot_en);
for (int k = 1; k <= nsteps; k += 1){
for (int n = 1; n < N-1; n += 1){
v[n] += 0.5*dt*F[n]/mass;
r[n] += dt*v[n];
// fprintf(rfile,"%d ", k);
fprintf(rfile,"%f\n", r[n]);}
pot_en = forces(N, r, F);
for (int n = 1; n < N-1; n += 1) v[n] += 0.5*dt*F[n]/mass;
kin_en = 0.;
for (int n = 1; n < N-1; n += 1) {kin_en += v[n]*v[n];}
kin_en *= 0.5*mass;
fprintf(efile,"%f\n", kin_en + pot_en);
}
fclose(rfile);
fclose(vfile);
fclose(efile);
}

#!/usr/bin/env python

# driver1.py
2

Yingwei Wang

Computing for Science and Engineering

"""
Created on Wed Nov 07 23:29:07 2012
@author: Yingwei
"""
from subprocess import call
from init import initialize
from os import curdir, sep
import numpy as np
from pylab import *
N = 40

call(gcc -std=c99 integrate1.c Ffunc.c -lm -o integrate1, shell=True)


initialize(N)
call(curdir+sep+integrate1 500 0.02, shell=True)

r = loadtxt(rfile.dat)
K = 500
r1 = r[0]*np.ones((K+1,1));
rn = r[N-1]*np.ones((K+1,1));
kk = range(K+1)
figure(1)
hold(True)
plot(kk,r1)
title(Particle position vs. time series)

plot(kk,rn)
for n in range(1,N-1,1):
rn = r[n];
rr = r.take([range(n+N-1,N+(K-1)*(N-2)+n,N-2)]);
rt = concatenate((rn,rr), axis=None);
plot(kk,rt);
3

Yingwei Wang

Computing for Science and Engineering

savefig(position.pdf)
show()
close()

en = loadtxt(efile.dat)
figure(2)
plot(kk,en)
title(Total energy vs. time series)
savefig(energy.pdf)
show()
close()

The results of plot are Fig.1 and Fig.2.

Yingwei Wang

Computing for Science and Engineering

Particle position vs. time series

160
140
120
100
80
60
40
20
0
0

100

200

300

400

Figure 1: Particle position at each time step

500

Yingwei Wang

Computing for Science and Engineering

Total energy vs. time series

64.0
63.5
63.0
62.5
62.0
61.5
61.0
60.5
60.0
0

100

200

300

400

500

Figure 2: Total energy at each time step

C to DL

Question: Create a dynamically loaded library for the function forces using the driver2_py.
Modify (the original) integrate.c so that it uses the library you created. Name the modified file integrate2.c.
Answer: My integrate2.c is
/* integrate2.c */
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <time.h> //..
#include <dlfcn.h> // dynamic linking functions

Yingwei Wang

Computing for Science and Engineering

static double mass = 39.95 * 1.66053886e-27 / 6.94771e-25;


// kcal/mol*ps^2/\AA^2
double forces(int N, double r[N], double F[N]);
int main(int argc, char *argv[argc]){
int nsteps = atoi(argv[1]);
double dt = atof(argv[2]); // ps
FILE *coordfile = fopen("coord.dat", "r");
int N; fscanf(coordfile, "%d\n", &N);
double r[N], v[N];
for (int n = 0; n < N; n += 1) fscanf(coordfile, "%lg\n", &r[n]);
for (int n = 0; n < N; n += 1) fscanf(coordfile, "%lg\n", &v[n]);
fclose(coordfile);
double F[N];
double pot_en ;
void *handle = dlopen("./_Ffunc.so", RTLD_LAZY);
if (handle == NULL) {printf("%s\n", dlerror()); exit(1);}
double (*pforces)(int N, double r[], double F[]) = dlsym(handle,"forces");
pot_en = (*pforces)(N, r, F);
double kin_en = 0.;
for (int n = 1; n < N-1; n += 1) kin_en += v[n]*v[n];
kin_en *= 0.5*mass;
printf("energy = %.17g\n", kin_en + pot_en); //..
clock_t t0 = clock(); //..
for (int k = 1; k <= nsteps; k += 1){
for (int n = 1; n < N-1; n += 1){
v[n] += 0.5*dt*F[n]/mass;
r[n] += dt*v[n];}
pot_en = (*pforces)(N, r, F);
for (int n = 1; n < N-1; n += 1) v[n] += 0.5*dt*F[n]/mass;}
kin_en = 0.;
for (int n = 1; n < N-1; n += 1) kin_en += v[n]*v[n];
kin_en *= 0.5*mass;
clock_t t1 = clock(); //..
printf("energy = %.17g\n", kin_en + pot_en); //..
printf("CPU time = %.2f\n", (double)(t1 - t0)/CLOCKS_PER_SEC);
dlclose(handle);
7

//..

Yingwei Wang

Computing for Science and Engineering

}
Three line output:
energy = 1620.0801577672062
energy = 1620.0632661879254
CPU time = 0.00

Py to DL

Question: Supply integrate.py by writing a Python wrapper wrapDL.py module containing a wrapper forces for the C dynamically linked library function of the same name.
Answer: My wrapDL.py is
# wrapDL.py
"""
Created on Mon Nov 12 20:19:22 2012
@author: Yingwei
"""
import ctypes as C
import numpy as np
_Ffunc = np.ctypeslib.load_library(_Ffunc.so,.)
pt = C.POINTER(C.c_double)
_Ffunc.forces.argtypes = [C.c_int, pt, pt]
def forces(N,r,F):
en = _Ffunc.forces(N, r.ctypes.data_as(pt),F.ctypes.data_as(pt))
return en, F.ctypes.data_as(pt)
Three line output:
energy = 1620.0801577672062
energy = 1620.0632661879254
CPU time = 0.00

Disk

Question: You are to write a Python wrapper wrapDisk.py module containing a wrapper
forces that communicates with the C program using temporary disk files.
Answer: My wrapDisk.py is
8

Yingwei Wang

Computing for Science and Engineering

# wrapDisk.py
"""
Created on Mon Nov 12 20:19:22 2012
@author: Yingwei
"""
from tempfile import mktemp
from os import getcwd, remove
from subprocess import Popen
import numpy as np
def forces(r):
N = len(r)
iname = mktemp(dir = getcwd())
oname = mktemp(dir = getcwd())
ifile = open(iname,w)
ifile.write(np.getbuffer(r))
ifile.close()
proc = Popen(./Fprog + str(N) + + iname + + oname, shell=True)
proc.wait()
en = eval(proc.communicate()[0])
ofile = open(oname,r)
FF = ofile.readline().split()
F = np.frombuffer(FF)
ofile.close()
remove(iname); remove(oname)
return float(en), float(F)
Three line output:
energy = 646.16067378081834
energy = 646.14402599835068
CPU time = 0.00

Pipe

Question: Using disk files to communicate between separate processes is inefficient. More
direct communication can be accomplished using pipes or MPI (often implemented on top
of sockets) or yet other mechanisms. Answer: My wrapDisk.py is
9

Yingwei Wang

Computing for Science and Engineering

# wrapPipe.py
"""
Created on Mon Nov 12 20:19:22 2012
@author: Yingwei
"""
from tempfile import mktemp
from os import getcwd, remove,mkfifo
from subprocess import Popen
import numpy as np
def forces(r):
N = len(r)
iname = mktemp(dir = getcwd())
oname = mktemp(dir = getcwd())
mkfifo(iname)
mkfifo(oname)
proc = Popen(./Fprog + str(N) + + iname + + oname, shell=True)
ifile = open(iname,w)
ifile.write(np.getbuffer(r))
ifile.close()
en = eval(proc.communicate()[0])
ofile = open(oname,r)
proc.wait()
FF = ofile.readline().split()
F = np.frombuffer(FF)
ofile.close()
remove(iname); remove(oname)
return float(en), float(F)
Three line output:
energy = 646.16067378081834
energy = 646.14402599835068
CPU time = 0.00

10

CS501: Homework 6
Yingwei Wang

Department of Mathematics, Purdue University, West Lafayette, IN, USA

MPI

Answer: My MPIdynamics.py is listed as following:


#!/usr/bin/env python # MPIdynamics.py
import sys
import numpy as np
import time
from mpi4py import MPI
epsilon = 120.*0.00198721 # kcal/mol
sigma = 3.405 # \AA
r_cut = 2.5 * sigma # \AA
mass = 39.95 * 1.66053886e-27 / 6.94771e-25 # kcal/mol*ps^2/\AA^2
dN = int(np.ceil(r_cut/(0.8*sigma)))
cw = MPI.COMM_WORLD
nproc = cw.Get_size()
rank = cw.Get_rank()
def main():
nsteps = int(sys.argv[1])
dt = float(sys.argv[2])
coordfile = open("coord.dat", "r")
N = int(coordfile.readline())
r = np.array(map(float, coordfile.readline().split()))
v = np.array(map(float, coordfile.readline().split()))
coordfile.close()

E-mail address: wywshtj@gmail.com; Tel : 765 237 7149

Yingwei Wang

Computing for Science and Engineering

Ng = np.empty(1, int32) # N_global container


Ng = cw.Bcast(N, root = 0)
n = int(np.ceil(N/nproc))
# initialize r
rg = cw.Scatter(r,root)
rj = np.zeros(n+2*dN,1)
rj[dN:n+dN] = rg[:,rank]
if rank > 0: sendL = cw.Isend(rj[dN:2*dN], dest = rank-1)
if rank < nproc: sendR = cw.Isend(rj[n-dN:n],dest = rank+1)
if rank > 0: recvL = cw.Irecv(rj[:dN], source = rank-1)
if rank < nproc: recvR = cw.Irecv(rj[n:],source = rank+1)
# initialize v
vg = cw.Scatter(r,root)
vj = np.zeros(n+2*dN,1)
vj[dN:n+dN] = vg[:,rank]
if rank > 0: sendL = cw.Isend(vj[dN:2*dN], dest = rank-1)
if rank < nproc: sendR = cw.Isend(vj[n-dN:n],dest = rank+1)
if rank > 0: recvL = cw.Irecv(vj[:dN], source = rank-1)
if rank < nproc: recvR = cw.Irecv(vj[n:],source = rank+1)
# compute
enj, rj, vj = integrate(rj, vj, 0, dt)
cw.Gather(enj,eng,root = 0)
print "energy = %.17g" % eng
t0 = time.time()
enj, rj, vj = integrate(rj, vj, nsteps, dt)
t1 = time.time()
cw.Gather(enj,eng,root = 0)
print "energy = %.17g" % eng
print "CPU time = %.2f" % (t1 - t0)
def integrate(r, v, nsteps, dt):
r = r.copy(); v = v.copy()
pot_en, F = forces(r)
F[0] = 0.; F[-1] = 0.
for k in range(nsteps):
v += (0.5*dt/mass)*F
r += dt*v
pot_en, F = forces(r)
2

Yingwei Wang

Computing for Science and Engineering

F[0] = 0.; F[-1] = 0.


v += (0.5*dt/mass)*F
kin_en = 0.5*mass*np.sum(v*v)
return kin_en + pot_en, r, v

def forces(r):
N = len(r)
if rank == nproc-1:
N2 = N
else:
N2 = N + dN
r = np.concatenate((r, np.empty(dN)))
pot_en = 0.
F = np.zeros(N2)
for m in range(N2-1):
near = True
n = m + 1
while n < N2 and near:
rmn = r[n] - r[m]
if rmn < r_cut:
r_6 = (sigma/rmn)**6
pot_en += 4.*epsilon*r_6*(r_6 - 1.)
Fmn = 24.*epsilon*r_6*(2.*r_6 - 1.)/rmn
F[n] += Fmn; F[m] -= Fmn
else:
near = False
n += 1
return pot_en, F
main()

My output of from MPIdriver.py is


energy = -1228.9434035336258
energy = -1228.943324123999
CPU time = 0.58

Yingwei Wang

Computing for Science and Engineering

energy = -1228.9434035336258
energy = -1228.943324123999
CPU time = 0.30
energy = -1228.9434035336258
energy = -1228.943324123999
CPU time = 0.16

Yingwei Wang

Computing for Science and Engineering

OpenMP

Answer: My OMPdynamics.c is listed as following:


/* OMPdynamics.c */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#include <omp.h>
static double mass = 39.95 * 1.66053886e-27 / 6.94771e-25;
// kcal/mol*ps^2/\AA^2
static double epsilon = 120.*0.00198721; // kcal/mol
static double sigma = 3.405; // \AA
static double r_cut = 2.5*3.405; // \AA
double integrate(int Ng, double r[Ng], double v[Ng], int nsteps, double dt);
double forces(int Ng, double r[Ng], double F[Ng]);
int main(int argc, char *argv[argc]){
int nsteps = atoi(argv[1]);
double dt = atof(argv[2]); // ps
FILE *coordfile = fopen("coord.dat", "r");
int N; fscanf(coordfile, "%d\n", &N);
double r[N], v[N];
for (int n = 0; n < N; n += 1)
fscanf(coordfile, "%lg\n", &r[n]);
for (int n = 0; n < N; n += 1)
fscanf(coordfile, "%lg\n", &v[n]);
fclose(coordfile);
double en = integrate(N, r, v, 0, dt);
printf("energy = %.17g\n", en);
clock_t t0 = clock();
en = integrate(N, r, v, nsteps, dt);
clock_t t1 = clock();
printf("energy = %.17g\n", en);
printf("CPU time = %.2f\n", (double)(t1 - t0)/CLOCKS_PER_SEC);}
double integrate(int Ng, double r[Ng], double v[Ng], int nsteps, double dt){
double F[Ng];
int nthreads;
5

Yingwei Wang

Computing for Science and Engineering

#pragma omp parallel


nthreads = omp_get_num_threads();
int N = Ng/nthreads;
double myen[nthreads];
int k =1;
#pragma omp parallel
{int rank = omp_get_thread_num();
while (k <= nsteps){
if (rank == 0){
F[0] = 0;}
if rank == nthreads - 1{
F[N] = 0;}
for (int k =0; k<nsteps; k++){
v += (0.5*dt/mass)*F;
r += de*v;
myen[rank] = forces(N, r, F);
if rank == 0{ F[0] = 0;}
if rank == nthreads-1{ F[N]=0;}
v += (0.5*dt/mass)*F;}
# programa omp barrier
if (rank == 0) { k++; }
}
}
double kin_en = 0.;
for (int n = 1; n < N-1; n += 1) kin_en += v[n]*v[n];
kin_en *= 0.5*mass;
return kin_en + pot_en;}
double forces(int Ng, double r[Ng], double F[Ng]){
int dN = (int)ceil(r_cut/(0.8*sigma));
int nthreads = omp_get_num_threads();
int N = Ng/nthreads;
int rank = omp_get_thread_num();
int N2 = (rank < nthreads - 1) ? N + dN : N;
double myF[N2];
double pot_en = 0.;
for (int n = 0; n < N2; n += 1) F[n] = 0.;
for (int m = 0; m < N2-1; m += 1){
6

Yingwei Wang

Computing for Science and Engineering

bool near = true;


for (int n = m+1; n < N2 && near; n += 1){
double rmn = r[n] - r[m];
if (rmn < r_cut){
double r_6 = pow(sigma/rmn, 6);
pot_en += 4.*epsilon*r_6*(r_6 - 1.);
double Fmn = 24.*epsilon*r_6*(2.*r_6 - 1.)/rmn;
F[n] += Fmn; F[m] -= Fmn;}
else near = false;}}
return pot_en;}

Das könnte Ihnen auch gefallen