This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestVertexBasedCellSimulationsPythonTutorial.py.

In [1]:
# Jupyter notebook specific imports 
import matplotlib as mpl 
from IPython import display 
%matplotlib inline

Introduction

In this tutorial we show how Chaste can be used to create, run and visualize vertex-based simulations. Full details of the mechanical model proposed by T. Nagai and H. Honda ("A dynamic cell model for the formation of epithelial tissues", Philosophical Magazine Part B 81:699-719).

The Test

In [2]:
import matplotlib.pyplot as plt # Plotting
import numpy as np # Matrix tools
import chaste # The PyChaste module
chaste.init() # Set up MPI
import chaste.cell_based # Contains cell populations
import chaste.mesh # Contains meshes
import chaste.visualization # Visualization tools

Test 1 - A basic vertex-based simulation

In the first test, we run a simple vertex-based simulation, in which we create a monolayer of cells, using a mutable vertex mesh. Each cell is assigned a stochastic cell-cycle model.

In [3]:
# Set up the test 
chaste.cell_based.SetupNotebookTest()

First, we generate a vertex mesh. To create a MutableVertexMesh, we can use the HoneycombVertexMeshGenerator. This generates a honeycomb-shaped mesh, in which all nodes are equidistant. Here the first and second arguments define the size of the mesh - we have chosen a mesh that is 2 elements (i.e. cells) wide, and 2 elements high.

In [4]:
file_handler = chaste.core.OutputFileHandler("Python/TestVertexBasedCellSimulationsTutorial")
generator = chaste.mesh.HoneycombVertexMeshGenerator(2, 2)
mesh = generator.GetMesh()

Having created a mesh, we now create a std::vector of CellPtrs. To do this, we use the CellsGenerator helper class, which is templated over the type of cell model required and the dimension. We create an empty vector of cells and pass this into the method along with the mesh. The second argument represents the size of that the vector cells should become - one cell for each element, the third argument specifies the proliferative type of the cell.

In [5]:
cells = chaste.cell_based.VecCellPtr()
transit_type = chaste.cell_based.TransitCellProliferativeType()
cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()
cell_generator.GenerateBasicRandom(cells, mesh.GetNumElements(), transit_type)

Now we have a mesh and a set of cells to go with it, we can create a CellPopulation. In general, this class associates a collection of cells with a mesh. For this test, because we have a MutableVertexMesh, we use a particular type of cell population called a VertexBasedCellPopulation.

In [6]:
cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells)

We can set up a VtkScene to do a quick visualization of the population before running the analysis.

In [7]:
scene = chaste.visualization.VtkScene2()
scene.SetCellPopulation(cell_population)
nb_manager = chaste.visualization.JupyterNotebookManager()
nb_manager.vtk_show(scene, height=600)
Out[7]:

We then pass in the cell population into an OffLatticeSimulation, and set the output directory, output multiple and end time

In [8]:
simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)
simulator.SetOutputDirectory("Python/TestVertexBasedCellSimulationsTutorial")
simulator.SetEndTime(5.0)

For longer simulations, we may not want to output the results every time step. In this case we can use the following method, to print results every 50 time steps instead. As the default time step used by the simulator (for vertex based simulations), is 0.02 hours, this method will cause the simulator to print results every 6 minutes (i.e. 0.1 hours).

In [9]:
simulator.SetSamplingTimestepMultiple(50)

We must now create one or more force laws, which determine the mechanics of the vertices of each cell in a cell population. For this test, we use one force law, based on the Nagai-Honda mechanics, and pass it to the OffLatticeSimulation. For a list of possible forces see subclasses of AbstractForce. Note that some of these forces are not compatible with vertex-based simulations see the specific class documentation for details, if you try to use an incompatible class then you will receive a warning.

In [10]:
force = chaste.cell_based.NagaiHondaForce2()
simulator.AddForce(force)

A NagaiHondaForce assumes that each cell has a target area. The target areas of cells are used to determine pressure forces on each vertex and eventually determine the size of each cell in the simulation. In order to assign target areas to cells and update them in each time step we add a SimpleTargetAreaModifier to the simulation, which inherits from AbstractTargetAreaModifier.

In [11]:
growth_modifier = chaste.cell_based.SimpleTargetAreaModifier2()
simulator.AddSimulationModifier(growth_modifier)

Save snapshot images of the population during the simulation

In [12]:
scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)
scene_modifier.SetVtkScene(scene)
scene_modifier.SetUpdateFrequency(100)
simulator.AddSimulationModifier(scene_modifier)

To run the simulation, we call Solve(). We can again do a quick rendering of the population at the end of the simulation

In [13]:
scene.Start()
simulator.Solve()
scene.End()

The next two lines are for test purposes only and are not part of this tutorial. If different simulation input parameters are being explored the lines should be removed.

In [14]:
# Tear down the test 
chaste.cell_based.TearDownNotebookTest()

Test 2 - introducing periodicity, boundaries and cell killers

In the second test, we run a simple vertex-based simulation, in which we create a monolayer of cells in a periodic geometry, using a cylindrical vertex mesh. We also include a fixed boundary which cells can't pass through and a cell killer which removes cells once they leave a region. As before each cell is assigned a stochastic cell-cycle model.

In [15]:
# Set up the test 
chaste.cell_based.SetupNotebookTest()

First, we generate a periodic vertex mesh. To create a Cylindrical2dVertexMesh, we can use the CylindricalHoneycombVertexMeshGenerator. This generates a honeycomb-shaped mesh, in which all nodes are equidistant and the right hand side is associated with the left hand side. Here the first and second arguments define the size of the mesh - we have chosen a mesh that is 4 elements (i.e. cells) wide, and 4 elements high.

In [16]:
generator = chaste.mesh.CylindricalHoneycombVertexMeshGenerator(4, 4)
mesh = generator.GetCylindricalMesh()

Having created a mesh, we now create a VecCellPtrs. This is exactly the same as the above test.

In [17]:
cells = chaste.cell_based.VecCellPtr()
transit_type = chaste.cell_based.TransitCellProliferativeType()
cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()
cell_generator.GenerateBasicRandom(cells, mesh.GetNumElements(), transit_type)

Now we have a mesh and a set of cells to go with it, we can create a CellPopulation. This is also the same as in the above test.

In [18]:
cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells)

We then pass in the cell population into an OffLatticeSimulation, and set the output directory, output multiple and end time

In [19]:
simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)
simulator.SetOutputDirectory("Python/TestPeriodicVertexBasedCellPopulation")
simulator.SetEndTime(1.0)
simulator.SetSamplingTimestepMultiple(50)

We now make a pointer to an appropriate force and pass it to the OffLatticeSimulation.

In [20]:
force = chaste.cell_based.NagaiHondaForce2()
simulator.AddForce(force)

We also make a pointer to the target area modifier and add it to the simulator.

In [21]:
growth_modifier = chaste.cell_based.SimpleTargetAreaModifier2()
simulator.AddSimulationModifier(growth_modifier)

We now create one or more CellPopulationBoundaryConditions, which determine any conditions which each cell in a cell population must satisfy. For this test, we use a PlaneBoundaryCondition, and pass it to the OffLatticeSimulation. For a list of possible boundary condition see subclasses of AbstractCellPopulationBoundaryCondition. Note that some of these boundary conditions are not compatible with vertex-based simulations see the specific class documentation for details, if you try to use an incompatible class then you will receive a warning. The first step is to define a point on the plane boundary and a normal to the plane.

In [22]:
point = (0.0, 0.0)
normal = (0.0, -1.0)

We can now make a PlaneBoundaryCondition (passing the point and normal to the plane) and pass it to the OffLatticeSimulation.

In [23]:
bc = chaste.cell_based.PlaneBoundaryCondition2_2(cell_population, point, normal)
simulator.AddCellPopulationBoundaryCondition(bc)

We now create one or more CellKillers, which determine how cells are removed from the simulation. For this test, we use a PlaneBasedCellKiller, and pass it to the OffLatticeSimulation. For a list of possible cell killers see subclasses of AbstractCellKiller. The first step is to define a point on the plane boundary and a normal to the plane.

In [24]:
point = (0.0, 3.0)
normal = (0.0, 1.0)

Finally we now make a PlaneBasedCellKiller (passing the point and normal to the plane) and pass it to the OffLatticeSimulation.

In [25]:
killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population, point, normal)
simulator.AddCellKiller(killer)

To run the simulation, we call Solve().

In [26]:
simulator.Solve()

The next two lines are for test purposes only and are not part of this tutorial. If different simulation input parameters are being explored the lines should be removed.

In [ ]:
# Tear down the test 
chaste.cell_based.TearDownNotebookTest()