Commit 82b34f9a authored by Ciarán Ó Rourke's avatar Ciarán Ó Rourke
Browse files

Sync to current state of private repo solutions

parents
This contains the solutions for exercises which have been covered during this course.
This diff is collapsed.
import cffi
ffibuilder = cffi.FFI()
ffibuilder.set_source("package._out", r"""
void evolve(double *u, double *u_previous, int nx, int ny,
double a, double dt, double dx2, double dy2)
{
int i, j;
int ij, ip, im, jp, jm;
for (i=1; i < nx-1; i++)
for (j=1; j < ny-1; j++) {
// Linearisation for 2D array
ij = j + i*nx;
ip = j + (i+1)*nx;
im = j + (i-1)*nx;
jp = (j + 1) + i*nx;
jm = (j - 1) + i*nx;
u[ij] = u_previous[ij] + a * dt * (
(u_previous[ip] - 2*u_previous[ij] + u_previous[im]) / dx2 +
(u_previous[jp] - 2*u_previous[ij] + u_previous[jm]) / dy2 );
}
memcpy(u_previous, u, nx*ny*sizeof(double));
}
""")
ffibuilder.cdef("""
void evolve(double *, double *, int, int, double, double, double, double);
""")
if __name__ == "__main__":
ffibuilder.compile(verbose=True)
CC=gcc
CFLAGS=-fPIC -O3
LDFLAGS=-shared
libevolve.so: evolve.h evolve.c
$(CC) -o libevolve.so $(LDFLAGS) $(CFLAGS) evolve.c
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
#include <string.h>
void evolve(double *u, double *u_previous, int nx, int ny,
double a, double dt, double dx2, double dy2)
{
int i, j;
int ij, ip, im, jp, jm;
for (i=1; i < nx-1; i++)
for (j=1; j < ny-1; j++) {
// Linearisation for 2D array
ij = j + i*nx;
ip = j + (i+1)*nx;
im = j + (i-1)*nx;
jp = (j + 1) + i*nx;
jm = (j - 1) + i*nx;
u[ij] = u_previous[ij] + a * dt * (
(u_previous[ip] - 2*u_previous[ij] + u_previous[im]) / dx2 +
(u_previous[jp] - 2*u_previous[ij] + u_previous[jm]) / dy2 );
}
memcpy(u_previous, u, nx*ny*sizeof(double));
}
void evolve(double *u, double *u_previous, int nx, int ny,
double a, double dt, double dx2, double dy2);
import matplotlib.pyplot as plt
import numpy as np
import time
### EDIT ME!
from evolve import evolve
###
# Set the colormap
plt.rcParams['image.cmap'] = 'BrBG'
# Basic parameters
a = 0.5 # Diffusion constant
timesteps = 200 # Number of time-steps to evolve system
image_interval = 4000 # Write frequency for png files
# Grid spacings
dx = 0.01
dy = 0.01
dx2 = dx**2
dy2 = dy**2
# For stability, this is the largest interval possible
# for the size of the time-step:
dt = dx2*dy2 / ( 2*a*(dx2+dy2) )
def initial_fields(filename):
field = np.loadtxt(filename)
field0 = np.copy(field)
return field, field0
def write_field(field, step):
plt.gca().clear()
#plt.hold(False)
plt.imshow(field)
plt.axis('off')
plt.savefig('heat_{0:03d}.png'.format(step))
def iterate(field, field0, timesteps, image_interval):
### EDIT ME: Define pointers, shape
###
for i in range(1,timesteps+1):
evolve(field, field0, a, dt, dx2, dy2)
if i % image_interval == 0:
write_field(field, i)
def main():
field, field0 = initial_fields('bottle.dat')
write_field(field, 0)
t0 = time.time()
iterate(field, field0, timesteps, image_interval)
t1 = time.time()
write_field(field, timesteps)
print ("Using cffi (A[B/P]I): Running Time: {0}".time.format(t1-t0))
main()
This diff is collapsed.
%% Cell type:markdown id: tags:
<img src="../img/ICHEC_Logo.png" alt="Drawing" style="width: 500px;"/>
<img src="../img/cythonlogo.png" alt="Drawing" style="width: 150px;"/>
%% Cell type:markdown id: tags:
# <center>Additional Exercises<center/>
## Optimising with Cython
- Based on a cProfile obtained for the simple (inefficient) heat equation script, write the `setup.py` file that creates a Cython module for the most time consuming part of the script. Below is the beginning of the cProfile for [`heat_equation_simple.py`](./heat_equation_simple.py).
- In its current state, running the script can be done using the following command either in the terminal or using `!` from the notebook;
%% Cell type:code id: tags:
``` python
!python heat_equation_simple.py bottle.dat
```
%% Output
Runtime: 18.743118286132812
%% Cell type:markdown id: tags:
- Using the inefficient script on the current setup the runtime of [`heat_equation_simple.py`](./heat_equation_simple.py) using;
- [`bottle.dat`](./bottle.dat) ≃ ~20 secs
- [`bottle_large.dat`](./bottle_large.dat)**~10 mins**
- The `time` module is being used to check the runtime of the `iterate` function, which implements `evolve`. The actual runtime of `heat_equation_simple.py` is slightly longer.
- How much can you improve the performance? You should be able to optimise it sufficiently to get the performance runtimes down to;
- `bottle.dat` < 0.1 sec
- `bottle_large.dat` < 5 secs
- Can you get it even better?
- **NB: Experiment with `bottle.dat` first, and ignore `bottle_large.dat` otherwise it will take too long! Get `bottle.dat` to run for ~0.5 secs before attempting with the larger dataset.**
<img src="cprofile.png" alt="Drawing" style="width: 600px;"/>
- Use the code segment below from [`evolve.py`](./evolve.py) to create an `evolve.pyx` file. If you wish, you can copy this into a text editor of your choosing.
- Create a setup file to compile the code
- Create the cython extension and investigate the effect on performance using any prefered timing technique.
- Insert static type declarations, function calls, `cnp` arrays and compiler directives where necessary.
%% Cell type:code id: tags:
``` python
%%writefile evolve_cyt.pyx
import numpy as np
cimport numpy as cnp
import cython
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
def evolve(cnp.ndarray[cnp.double_t , ndim =2]u , cnp.ndarray[cnp.double_t , ndim =2]u_previous, double a, double dt, double dx2, double dy2):
cdef int n = u.shape[0]
cdef int m = u.shape[1]
cdef int i,j
#multiplication is more efficient than division
cdef double dx2inv = 1. / dx2
cdef double dy2inv = 1. / dy2
for i in range(1, n-1):
for j in range(1, m-1):
u[i, j] = u_previous[i, j] + a * dt * ( \
(u_previous[i+1, j] - 2*u_previous[i, j] + \
u_previous[i-1, j]) *dx2inv + \
(u_previous[i, j+1] - 2*u_previous[i, j] + \
u_previous[i, j-1]) *dy2inv )
u_previous[:] = u[:]
```
%% Output
Writing evolve_cyt.pyx
%% Cell type:code id: tags:
``` python
%%writefile heat_setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy
setup(ext_modules = cythonize("evolve_cyt.pyx"),include_dirs=[numpy.get_include()])
```
%% Output
Writing heat_setup.py
%% Cell type:code id: tags:
``` python
!python heat_setup.py build_ext --inplace
```
%% Output
Compiling evolve_cyt.pyx because it changed.
[1/1] Cythonizing evolve_cyt.pyx
/Users/cilwerner/anaconda3/lib/python3.8/site-packages/Cython/Compiler/Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /Users/cilwerner/Documents/ICHEC/Courses/Teaching/Python_HPC_courses/ICHEC/hpc-python/march-2021-solutions/cython/evolve_cyt.pyx
tree = Parsing.p_module(s, pxd, full_module_name)
running build_ext
building 'evolve_cyt' extension
creating build
creating build/temp.macosx-10.9-x86_64-3.8
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/cilwerner/anaconda3/include -arch x86_64 -I/Users/cilwerner/anaconda3/include -arch x86_64 -I/Users/cilwerner/anaconda3/lib/python3.8/site-packages/numpy/core/include -I/Users/cilwerner/anaconda3/include/python3.8 -c evolve_cyt.c -o build/temp.macosx-10.9-x86_64-3.8/evolve_cyt.o
In file included from evolve_cyt.c:623:
In file included from /Users/cilwerner/anaconda3/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:4:
In file included from /Users/cilwerner/anaconda3/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12:
In file included from /Users/cilwerner/anaconda3/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1822:
/Users/cilwerner/anaconda3/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: 
"Using deprecated NumPy API, disable it with " "#define
NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-W#warnings]
#warning "Using deprecated NumPy API, disable it with " \
 ^
1 warning generated.
gcc -bundle -undefined dynamic_lookup -L/Users/cilwerner/anaconda3/lib -arch x86_64 -L/Users/cilwerner/anaconda3/lib -arch x86_64 -arch x86_64 build/temp.macosx-10.9-x86_64-3.8/evolve_cyt.o -o /Users/cilwerner/Documents/ICHEC/Courses/Teaching/Python_HPC_courses/ICHEC/hpc-python/march-2021-solutions/cython/evolve_cyt.cpython-38-darwin.so
%% Cell type:code id: tags:
``` python
!python heat_equation_simple_solution.py bottle.dat
```