-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#2 move some of the material from day 12 to 13, and add cython soluti…
…on for day 12
- Loading branch information
1 parent
0111caf
commit 1d16da2
Showing
36 changed files
with
826 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,88 +1,13 @@ | ||
import os | ||
import re | ||
import sys | ||
import platform | ||
import subprocess | ||
from setuptools import setup, find_packages | ||
|
||
from setuptools import setup, find_packages, Extension | ||
from setuptools.command.build_ext import build_ext | ||
from setuptools import find_packages | ||
from distutils.version import LooseVersion | ||
|
||
|
||
class CMakeExtension(Extension): | ||
|
||
def __init__(self, name, sourcedir=''): | ||
Extension.__init__(self, name, sources=[]) | ||
self.sourcedir = os.path.abspath(sourcedir) | ||
|
||
|
||
class CMakeBuild(build_ext): | ||
|
||
def run(self): | ||
try: | ||
out = subprocess.check_output(['cmake', '--version']) | ||
except OSError: | ||
raise RuntimeError("CMake must be installed to build the following extensions: " + | ||
", ".join(e.name for e in self.extensions)) | ||
|
||
if platform.system() == "Windows": | ||
cmake_version = LooseVersion( | ||
re.search(r'version\s*([\d.]+)', out.decode()).group(1)) | ||
if cmake_version < '3.1.0': | ||
raise RuntimeError("CMake >= 3.1.0 is required on Windows") | ||
|
||
for ext in self.extensions: | ||
self.build_extension(ext) | ||
|
||
def build_extension(self, ext): | ||
extdir = os.path.abspath( | ||
os.path.dirname(self.get_ext_fullpath(ext.name))) | ||
cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, | ||
'-DPYTHON_EXECUTABLE=' + sys.executable] | ||
|
||
cfg = 'Debug' if self.debug else 'Release' | ||
build_args = ['--config', cfg] | ||
|
||
if platform.system() == "Windows": | ||
cmake_args += [ | ||
'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] | ||
if sys.maxsize > 2**32: | ||
cmake_args += ['-A', 'x64'] | ||
build_args += ['--', '/m'] | ||
else: | ||
cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] | ||
build_args += ['--', '-j2'] | ||
|
||
env = os.environ.copy() | ||
env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), | ||
self.distribution.get_version()) | ||
if not os.path.exists(self.build_temp): | ||
os.makedirs(self.build_temp) | ||
subprocess.check_call( | ||
['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) | ||
subprocess.check_call( | ||
['cmake', '--build', '.'] + build_args, cwd=self.build_temp) | ||
|
||
|
||
# Load text for description and license | ||
with open('README.md') as f: | ||
readme = f.read() | ||
|
||
# Go! | ||
setup( | ||
name='cell_model', | ||
version='0.0.1', | ||
description='cell diffusion and excluded volume model', | ||
long_description=readme, | ||
license='BSD 3-clause license', | ||
maintainer='Martin Robinson', | ||
maintainer_email='[email protected]', | ||
# Packages to include | ||
packages=find_packages(include=('cell_model')), | ||
ext_modules=[CMakeExtension('cell_model_cpp',sourcedir='.')], | ||
cmdclass=dict(build_ext=CMakeBuild), | ||
# List of dependencies | ||
install_requires=[ | ||
'numpy', | ||
'matplotlib', | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,5 @@ pybind11 | |
*.egg-info | ||
*.so | ||
cell_model/__pycache__ | ||
cell_model/*.c | ||
cell_model/*.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
144 changes: 144 additions & 0 deletions
144
12_c_plus_plus_and_python/practicals/solution/cell_model/SimulationCython.pyx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import numpy as np | ||
|
||
from libc.math cimport exp, sqrt | ||
cimport cython | ||
|
||
@cython.boundscheck(False) # Deactivate bounds checking | ||
@cython.wraparound(False) # Deactivate negative indexing | ||
@cython.cdivision(True) # Deactivate normal python division checking | ||
@cython.initializedcheck(False) # Deactivate memoryview init checking | ||
cdef class SimulationCython: | ||
|
||
cdef public double[:] x | ||
cdef public double[:] y | ||
cdef double[:] xn | ||
cdef double[:] yn | ||
cdef double max_dt | ||
cdef double size | ||
cdef public int calculate_interactions | ||
|
||
def __init__(self, double[:] x, double[:] y, size, max_dt): | ||
""" | ||
Creates a new simulation objects that implements the cell model with diffusion | ||
and excluded volume interactions. Cells are defined on a unit square domain and | ||
periodic boundary condtions are implemented | ||
Parameters | ||
---------- | ||
x: np.ndarray | ||
array of x positions of the cells | ||
y: np.ndarray | ||
array of y positions of the cells. Must be same length as x | ||
size: float | ||
size of cells | ||
max_dt: float | ||
maximum timestep for the simulation | ||
""" | ||
self.x = x | ||
self.y = y | ||
self.max_dt = max_dt | ||
|
||
self.xn = np.copy(x) | ||
self.yn = np.copy(y) | ||
|
||
self.size = size | ||
|
||
self.calculate_interactions = False | ||
|
||
def boundaries(self, double dt): | ||
""" | ||
Any cells that are over the boundary of the domain are translated to the | ||
opposite side of the domain | ||
Updates self.xn and self.yn with the new position of the cells | ||
""" | ||
for i in range(len(self.x)): | ||
if self.xn[i] < 0.0: | ||
self.xn[i] = 0.0 - self.xn[i] | ||
elif self.xn[i] > 1.0: | ||
self.xn[i] = self.xn[i] - 1.0 | ||
if self.yn[i] < 0.0: | ||
self.yn[i] = 0.0 - self.yn[i] | ||
elif self.yn[i] > 1.0: | ||
self.yn[i] = self.yn[i] - 1.0 | ||
|
||
def diffusion(self, double dt): | ||
""" | ||
Perform a diffusion step for all cells | ||
Updates self.xn and self.yn with the new position of the cells | ||
""" | ||
for i in range(len(self.x)): | ||
self.xn[i] += np.sqrt(2.0 * dt) * np.random.randn() | ||
self.yn[i] += np.sqrt(2.0 * dt) * np.random.randn() | ||
|
||
def interactions(self, double dt): | ||
""" | ||
Calculates the pairwise interactions between cells, using a soft exponential | ||
repulsive force | ||
Uses self.x and self.y as the current positions of the cells | ||
Updates self.xn and self.yn with the new position of the cells | ||
""" | ||
cdef double dx | ||
cdef double dy | ||
cdef double r | ||
cdef double dp | ||
cdef int n = len(self.x) | ||
|
||
for i in range(n): | ||
for j in range(n): | ||
dx = self.x[i] - self.x[j] | ||
dy = self.y[i] - self.y[j] | ||
r = sqrt(dx**2 + dy**2) | ||
if r > 0.0: | ||
dp = (dt/self.size) * exp(-r/self.size) / r | ||
self.xn[i] += dp*dx | ||
self.yn[i] += dp*dy | ||
|
||
def step(self, dt): | ||
""" | ||
Perform a single time step for the simulation | ||
First the current positions of the cells are written to self.xn and self.yn, | ||
which will now represent the "next" position of the cells after the current | ||
time-step | ||
The self.interactions, self.diffusion and self.boundaries functions update the | ||
"next" position of the cells according to the cell-cell excluded volume | ||
interactions, the diffusion step and the boundaries respectivly | ||
Finally, the current position of the cells is set to the calculated "next" | ||
position, and the simulation is ready for a new time-step. | ||
""" | ||
|
||
if self.calculate_interactions: | ||
self.interactions(dt) | ||
self.diffusion(dt) | ||
self.boundaries(dt) | ||
|
||
self.x[:] = self.xn | ||
self.y[:] = self.yn | ||
|
||
def integrate(self, period): | ||
""" | ||
integrate over a time period given by period (float). | ||
""" | ||
|
||
n = int(np.floor(period / self.max_dt)) | ||
print('integrating for {} steps'.format(n+1)) | ||
for i in range(n): | ||
self.step(self.max_dt) | ||
final_dt = period - self.max_dt*n | ||
if final_dt > 0: | ||
self.step(final_dt) | ||
|
||
|
||
|
1 change: 1 addition & 0 deletions
1
12_c_plus_plus_and_python/practicals/solution/cell_model/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
from .Simulation import Simulation | ||
from .SimulationCython import SimulationCython |
Oops, something went wrong.