Skip to content

Commit

Permalink
add cpp simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
martinjrobins committed Aug 30, 2019
1 parent 4f149e5 commit 30e6347
Show file tree
Hide file tree
Showing 17 changed files with 599 additions and 202 deletions.
90 changes: 90 additions & 0 deletions 12_c_plus_plus_and_python/practicals/cell_model/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IndentCaseLabels: false
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

33 changes: 33 additions & 0 deletions 12_c_plus_plus_and_python/practicals/cell_model/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.1)

project(cell_model_cpp)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1 )

# OpenMP
find_package(OpenMP REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")

# Pybind11
add_subdirectory(pybind11 ${CMAKE_BINARY_DIR}/pybind11)

set(source_dir "src")

set(source_files
${source_dir}/Simulation.cpp
${source_dir}/Functions.cpp
${source_dir}/python_wrapper.cpp
)

set(header_files
${source_dir}/Simulation.hpp
${source_dir}/Functions.hpp
)


pybind11_add_module(cell_model_cpp ${source_files} ${header_files})
target_link_libraries(cell_model_cpp PRIVATE ${libs})
target_include_directories(cell_model_cpp PRIVATE ${source_dir})
5 changes: 3 additions & 2 deletions 12_c_plus_plus_and_python/practicals/cell_model/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Instructions

```bash
git clone https://github.com/pybind/pybind11.git
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt
python cell_model.py
pip install -e .
python simulate.py
```
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import time
import cProfile


class Simulation:
def __init__(self, x, y, size, max_dt):
Expand Down Expand Up @@ -32,8 +27,8 @@ def __init__(self, x, y, size, max_dt):
self.y = y
self.max_dt = max_dt

self.xn = np.empty_like(x)
self.yn = np.empty_like(y)
self.xn = np.copy(x)
self.yn = np.copy(y)

self.size = size

Expand Down Expand Up @@ -100,8 +95,6 @@ def step(self, dt):
position, and the simulation is ready for a new time-step.
"""
self.xn[:] = self.x
self.yn[:] = self.y

if self.calculate_interactions:
self.interactions(dt)
Expand All @@ -125,57 +118,4 @@ def integrate(self, period):
self.step(final_dt)


if __name__ == "__main__":

# np.seterr(divide='ignore', invalid='ignore')

# number of cells
n = 100

# mean and standard deviation of the initial positions of the cells
mu, sigma = 0.5, 0.05

# set the maximum timestep allowed as fraction of the average diffusion step
timestep_ratio = 0.23
size = 0.02
max_dt = (0.23 * size)**2 / 4.0

# end time for the simulation
end_time = 0.01

# number of output steps
nout = 10
integrate_time = end_time/nout

# create simulation
x = np.random.normal(mu, sigma, n)
y = np.random.normal(mu, sigma, n)
sim = Simulation(x, y, size, max_dt)

# Set to True to include excluded volume interactions
sim.calculate_interactions = False

# profile a single call to integrate
cProfile.run('sim.integrate(integrate_time)', sort='cumulative')

# now run the main simulation loop and visualise the positions of the cells at each
# output step
time_for_simulation = 0.0
f = plt.figure()
for i in range(nout):
# increment simulation
start_time = time.perf_counter()
sim.integrate(integrate_time)
end_time = time.perf_counter()
time_for_simulation += end_time - start_time

# plot
f.clear()
circles = [plt.Circle((xi,yi), radius=size) for xi,yi in
zip(sim.x,sim.y)]
c = matplotlib.collections.PatchCollection(circles)
f.gca().add_collection(c)
f.savefig('cells_{}.png'.format(i))

print('finished simulation, time taken (excluding plotting) was {}'.format(
time_for_simulation))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from cell_model import Simulation

This file was deleted.

91 changes: 91 additions & 0 deletions 12_c_plus_plus_and_python/practicals/cell_model/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import os
import re
import sys
import platform
import subprocess

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',
],
)

61 changes: 61 additions & 0 deletions 12_c_plus_plus_and_python/practicals/cell_model/simulate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import time
import cProfile
import cell_model

if __name__ == "__main__":

# np.seterr(divide='ignore', invalid='ignore')

# number of cells
n = 100

# mean and standard deviation of the initial positions of the cells
mu, sigma = 0.5, 0.05

# set the maximum timestep allowed as fraction of the average diffusion step
timestep_ratio = 0.23
size = 0.02
max_dt = (0.23 * size)**2 / 4.0

# end time for the simulation
end_time = 0.01

# number of output steps
nout = 10
integrate_time = end_time/nout

# create simulation
x = np.random.normal(mu, sigma, n)
y = np.random.normal(mu, sigma, n)
sim = cell_model.Simulation(x, y, size, max_dt)

# Set to True to include excluded volume interactions
sim.calculate_interactions = False

# profile a single call to integrate
cProfile.run('sim.integrate(integrate_time)', sort='cumulative')

# now run the main simulation loop and visualise the positions of the cells at each
# output step
time_for_simulation = 0.0
f = plt.figure()
for i in range(nout):
# increment simulation
start_time = time.perf_counter()
sim.integrate(integrate_time)
end_time = time.perf_counter()
time_for_simulation += end_time - start_time

# plot
f.clear()
circles = [plt.Circle((xi,yi), radius=size) for xi,yi in
zip(sim.x,sim.y)]
c = matplotlib.collections.PatchCollection(circles)
f.gca().add_collection(c)
f.savefig('cells_{}.png'.format(i))

print('finished simulation, time taken (excluding plotting) was {}'.format(
time_for_simulation))
Loading

0 comments on commit 30e6347

Please sign in to comment.