diff --git a/.github/workflows/update-pychaste-tutorials.yml b/.github/workflows/update-pychaste-tutorials.yml index 3e224ce0..e20ee15f 100644 --- a/.github/workflows/update-pychaste-tutorials.yml +++ b/.github/workflows/update-pychaste-tutorials.yml @@ -44,10 +44,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Download pychaste-tutorials markdown + - name: Download pychaste-tutorials-markdown uses: actions/download-artifact@v3 with: - name: pychaste-tutorials markdown + name: pychaste-tutorials-markdown - name: Checkout website repository uses: actions/checkout@v4 diff --git a/doc/tutorials/TestCellSortingTutorial.ipynb b/doc/tutorials/TestCellSortingTutorial.ipynb index 35a78214..3b7c75e7 100644 --- a/doc/tutorials/TestCellSortingTutorial.ipynb +++ b/doc/tutorials/TestCellSortingTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "296c5d00", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestCellSortingTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestCellSortingTutorial.py.\n", "\n" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, + "id": "85518493", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "425c7509", "metadata": {}, "source": [ "\n", @@ -37,7 +40,8 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, + "id": "ad3b4b3d", "metadata": {}, "outputs": [], "source": [ @@ -52,6 +56,7 @@ }, { "cell_type": "markdown", + "id": "0859ed0f", "metadata": {}, "source": [ "## Test 1 - Cell sorting\n", @@ -62,7 +67,8 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, + "id": "914c5dbe", "metadata": {}, "outputs": [], "source": [ @@ -72,6 +78,7 @@ }, { "cell_type": "markdown", + "id": "6b89b200", "metadata": {}, "source": [ "First, we generate a `Potts` mesh. To create a `PottsMesh`, we can use the `PottsMeshGenerator`.\n", @@ -82,7 +89,8 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, + "id": "53498c64", "metadata": {}, "outputs": [], "source": [ @@ -92,6 +100,7 @@ }, { "cell_type": "markdown", + "id": "55826799", "metadata": {}, "source": [ "Having created a mesh, we now create some cells. To do this, we the `CellsGenerator` helper class,\n", @@ -101,7 +110,8 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, + "id": "83100d25", "metadata": {}, "outputs": [], "source": [ @@ -112,6 +122,7 @@ }, { "cell_type": "markdown", + "id": "ab73135c", "metadata": {}, "source": [ "Before we make a CellPopulation we make a cell label and then assign this label to some randomly chosen cells.\n", @@ -120,7 +131,8 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, + "id": "4c965778", "metadata": {}, "outputs": [], "source": [ @@ -132,6 +144,7 @@ }, { "cell_type": "markdown", + "id": "63891d61", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", @@ -140,7 +153,8 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, + "id": "56507a69", "metadata": {}, "outputs": [], "source": [ @@ -149,6 +163,7 @@ }, { "cell_type": "markdown", + "id": "84a90a0d", "metadata": {}, "source": [ "In order to visualize labelled cells we need to use the following command.\n", @@ -157,7 +172,8 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, + "id": "46963d23", "metadata": {}, "outputs": [], "source": [ @@ -166,6 +182,7 @@ }, { "cell_type": "markdown", + "id": "6571a038", "metadata": {}, "source": [ "PyChaste can do simple 3D rendering with VTK. We set up a VtkScene so that we can\n", @@ -175,7 +192,8 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, + "id": "13078a02", "metadata": {}, "outputs": [], "source": [ @@ -183,11 +201,12 @@ "scene.SetCellPopulation(cell_population)\n", "scene.GetCellPopulationActorGenerator().SetShowPottsMeshEdges(True)\n", "nb_manager = chaste.visualization.JupyterNotebookManager()\n", - "#nb_manager.vtk_show(scene, height=600)" + "nb_manager.vtk_show(scene, height=600)" ] }, { "cell_type": "markdown", + "id": "73bf51b5", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", @@ -196,7 +215,8 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, + "id": "4c4b7723", "metadata": {}, "outputs": [], "source": [ @@ -208,6 +228,7 @@ }, { "cell_type": "markdown", + "id": "9a2f7393", "metadata": {}, "source": [ "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", @@ -219,7 +240,8 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, + "id": "4e6905d0", "metadata": {}, "outputs": [], "source": [ @@ -231,6 +253,7 @@ }, { "cell_type": "markdown", + "id": "ce8333cb", "metadata": {}, "source": [ "We repeat the process for any other update rules.\n", @@ -239,7 +262,8 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, + "id": "85b15aac", "metadata": {}, "outputs": [], "source": [ @@ -254,6 +278,7 @@ }, { "cell_type": "markdown", + "id": "0c443ccd", "metadata": {}, "source": [ "Set up plotting\n", @@ -262,7 +287,8 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, + "id": "0ccc598e", "metadata": {}, "outputs": [], "source": [ @@ -274,6 +300,7 @@ }, { "cell_type": "markdown", + "id": "ac2f8034", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`.\n", @@ -282,57 +309,19 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, + "id": "aad50aa1", "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "Unable to convert function return value to a Python type! The signature was\n\t(self: chaste.visualization._chaste_project_PyChaste_visualization.VtkScene2) -> vtkSmartPointer", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mscene\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mStart\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0msimulator\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSolve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;31m# Tear down the test\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mchaste\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcell_based\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTearDownNotebookTest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Code/chaste-build/projects/PyChaste/python/chaste/visualization/fortests.py\u001b[0m in \u001b[0;36mUpdateAtEndOfTimeStep\u001b[0;34m(self, cell_population)\u001b[0m\n\u001b[1;32m 179\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 180\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutput_format\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'png'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 181\u001b[0;31m \u001b[0mIPython\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdisplay\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplotting_manager\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvtk_show\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGetVtkScene\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput_format\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutput_format\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 182\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 183\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplotting_manager\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvtk_show\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGetVtkScene\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput_format\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutput_format\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Code/chaste-build/projects/PyChaste/python/chaste/visualization/fortests.py\u001b[0m in \u001b[0;36mvtk_show\u001b[0;34m(self, scene, width, height, output_format, increment)\u001b[0m\n\u001b[1;32m 132\u001b[0m \u001b[0mrenderWindow\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvtk\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvtkRenderWindow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 133\u001b[0m \u001b[0mrenderWindow\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSetOffScreenRendering\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 134\u001b[0;31m \u001b[0mrenderWindow\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mAddRenderer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mscene\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGetRenderer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 135\u001b[0m \u001b[0mrenderWindow\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSetSize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidth\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheight\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 136\u001b[0m \u001b[0mrenderWindow\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRender\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: Unable to convert function return value to a Python type! The signature was\n\t(self: chaste.visualization._chaste_project_PyChaste_visualization.VtkScene2) -> vtkSmartPointer" - ] - } - ], + "outputs": [], "source": [ "scene.Start()\n", "simulator.Solve()\n", "# Tear down the test \n", "chaste.cell_based.TearDownNotebookTest()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.9" - } - }, + "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestCellSortingTutorial.md b/doc/tutorials/TestCellSortingTutorial.md index ca58a7cb..e73f6d08 100644 --- a/doc/tutorials/TestCellSortingTutorial.md +++ b/doc/tutorials/TestCellSortingTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Cell Sorting Tutorial +title : "Test Cell Sorting Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestCellSortingTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestCellSortingTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestCellSortingTutorial.py . Note that the code is given in full at the bottom of the page. diff --git a/doc/tutorials/TestCellSortingTutorial.nbconvert.ipynb b/doc/tutorials/TestCellSortingTutorial.nbconvert.ipynb new file mode 100644 index 00000000..3b7c75e7 --- /dev/null +++ b/doc/tutorials/TestCellSortingTutorial.nbconvert.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "296c5d00", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestCellSortingTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85518493", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "425c7509", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "This test is a demonstration of cell sorting using a Cellular Potts based framework.\n", + "It shows:\n", + " * How to set up a Potts simulation\n", + " * Working with labels\n", + " \n", + "## The Test\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad3b4b3d", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt # Plotting\n", + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "chaste.init() # Set up MPI\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.visualization # Visualization tools" + ] + }, + { + "cell_type": "markdown", + "id": "0859ed0f", + "metadata": {}, + "source": [ + "## Test 1 - Cell sorting\n", + "The next test generates a collection of cells, there are two types of cells, labelled ones and non labelled ones,\n", + "there is differential adhesion between the cell types. For the parameters specified, the cells sort into separate types.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "914c5dbe", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "6b89b200", + "metadata": {}, + "source": [ + "First, we generate a `Potts` mesh. To create a `PottsMesh`, we can use the `PottsMeshGenerator`.\n", + "This generates a regular square-shaped mesh, in which all elements are the same size.\n", + "We have chosen an 8 by 8 block of elements each consisting of 4 by 4 ( = 16) lattice sites.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53498c64", + "metadata": {}, + "outputs": [], + "source": [ + "generator = chaste.mesh.PottsMeshGenerator2(50, 8, 4, 50, 8, 4)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "55826799", + "metadata": {}, + "source": [ + "Having created a mesh, we now create some cells. To do this, we the `CellsGenerator` helper class,\n", + "as before but this time the third argument is set to make all cells non-proliferative.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83100d25", + "metadata": {}, + "outputs": [], + "source": [ + "differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), differentiated_type)" + ] + }, + { + "cell_type": "markdown", + "id": "ab73135c", + "metadata": {}, + "source": [ + "Before we make a CellPopulation we make a cell label and then assign this label to some randomly chosen cells.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c965778", + "metadata": {}, + "outputs": [], + "source": [ + "label = chaste.cell_based.CellLabel()\n", + "for eachCell in cells:\n", + " if(chaste.core.RandomNumberGenerator.Instance().ranf()<0.5):\n", + " eachCell.AddCellProperty(label)" + ] + }, + { + "cell_type": "markdown", + "id": "63891d61", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56507a69", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.PottsBasedCellPopulation2(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "84a90a0d", + "metadata": {}, + "source": [ + "In order to visualize labelled cells we need to use the following command.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46963d23", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.AddCellWriterCellLabelWriter()" + ] + }, + { + "cell_type": "markdown", + "id": "6571a038", + "metadata": {}, + "source": [ + "PyChaste can do simple 3D rendering with VTK. We set up a VtkScene so that we can\n", + "see the population evovle in real time.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13078a02", + "metadata": {}, + "outputs": [], + "source": [ + "scene= chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "scene.GetCellPopulationActorGenerator().SetShowPottsMeshEdges(True)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "73bf51b5", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c4b7723", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OnLatticeSimulation2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestCellSorting\")\n", + "simulator.SetEndTime(20.0)\n", + "simulator.SetSamplingTimestepMultiple(10)" + ] + }, + { + "cell_type": "markdown", + "id": "9a2f7393", + "metadata": {}, + "source": [ + "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", + "For this test, we use two update rules based upon a volume constraint (`VolumeConstraintPottsUpdateRule`) and\n", + "differential adhesion between cells (`DifferentialAdhesionPottsUpdateRule`), set appropriate parameters, and\n", + "pass them to the `OnLatticeSimulation`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e6905d0", + "metadata": {}, + "outputs": [], + "source": [ + "volume_constraint_update_rule = chaste.cell_based.VolumeConstraintPottsUpdateRule2()\n", + "volume_constraint_update_rule.SetMatureCellTargetVolume(16)\n", + "volume_constraint_update_rule.SetDeformationEnergyParameter(0.2)\n", + "simulator.AddUpdateRule(volume_constraint_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "ce8333cb", + "metadata": {}, + "source": [ + "We repeat the process for any other update rules.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85b15aac", + "metadata": {}, + "outputs": [], + "source": [ + "differential_adhesion_update_rule = chaste.cell_based.DifferentialAdhesionPottsUpdateRule2()\n", + "differential_adhesion_update_rule.SetLabelledCellLabelledCellAdhesionEnergyParameter(0.16)\n", + "differential_adhesion_update_rule.SetLabelledCellCellAdhesionEnergyParameter(0.11)\n", + "differential_adhesion_update_rule.SetCellCellAdhesionEnergyParameter(0.02)\n", + "differential_adhesion_update_rule.SetLabelledCellBoundaryAdhesionEnergyParameter(0.16)\n", + "differential_adhesion_update_rule.SetCellBoundaryAdhesionEnergyParameter(0.16)\n", + "simulator.AddUpdateRule(differential_adhesion_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "0c443ccd", + "metadata": {}, + "source": [ + "Set up plotting\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ccc598e", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(1000)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "ac2f8034", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aad50aa1", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.ipynb b/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.ipynb index 27df954c..6d825047 100644 --- a/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.ipynb +++ b/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "91bf95f6", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestMeshBasedCellSimulationsPythonTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestMeshBasedCellSimulationsPythonTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "4b6811ea", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "218fbe30", "metadata": {}, "source": [ "\n", @@ -36,6 +39,7 @@ { "cell_type": "code", "execution_count": null, + "id": "d8cc5664", "metadata": {}, "outputs": [], "source": [ @@ -50,6 +54,7 @@ }, { "cell_type": "markdown", + "id": "1559ec87", "metadata": {}, "source": [ "## Test 1 - a basic mesh-based simulation\n", @@ -61,6 +66,7 @@ { "cell_type": "code", "execution_count": null, + "id": "73fea897", "metadata": {}, "outputs": [], "source": [ @@ -70,6 +76,7 @@ }, { "cell_type": "markdown", + "id": "542e3991", "metadata": {}, "source": [ "Next, we generate a mutable mesh. To create a `MutableMesh`, we can use the `HoneycombMeshGenerator`.\n", @@ -81,6 +88,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3c6457ec", "metadata": {}, "outputs": [], "source": [ @@ -91,6 +99,7 @@ }, { "cell_type": "markdown", + "id": "b320437c", "metadata": {}, "source": [ "Having created a mesh, we now create some cells. To do this, we use the `CellsGenerator` helper class,\n", @@ -106,6 +115,7 @@ { "cell_type": "code", "execution_count": null, + "id": "63821a1e", "metadata": {}, "outputs": [], "source": [ @@ -117,6 +127,7 @@ }, { "cell_type": "markdown", + "id": "da78910f", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", @@ -128,6 +139,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7d4eae36", "metadata": {}, "outputs": [], "source": [ @@ -137,6 +149,7 @@ }, { "cell_type": "markdown", + "id": "0d4578de", "metadata": {}, "source": [ "To view the results of this and the next test in Paraview it is necessary to explicitly\n", @@ -147,6 +160,7 @@ { "cell_type": "code", "execution_count": null, + "id": "2eff0fa5", "metadata": {}, "outputs": [], "source": [ @@ -155,6 +169,7 @@ }, { "cell_type": "markdown", + "id": "94e159f7", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -164,6 +179,7 @@ { "cell_type": "code", "execution_count": null, + "id": "f9b1c415", "metadata": {}, "outputs": [], "source": [ @@ -175,6 +191,7 @@ }, { "cell_type": "markdown", + "id": "a36000b5", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time.\n", @@ -184,6 +201,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3977141e", "metadata": {}, "outputs": [], "source": [ @@ -194,6 +212,7 @@ }, { "cell_type": "markdown", + "id": "4611308a", "metadata": {}, "source": [ "For longer simulations, we may not want to output the results every time step. In this case we can use the following method,\n", @@ -205,6 +224,7 @@ { "cell_type": "code", "execution_count": null, + "id": "bb5d898b", "metadata": {}, "outputs": [], "source": [ @@ -213,6 +233,7 @@ }, { "cell_type": "markdown", + "id": "c0d461f0", "metadata": {}, "source": [ "We must now create one or more force laws, which determine the mechanics of the centres of each cell in a cell population.\n", @@ -225,6 +246,7 @@ { "cell_type": "code", "execution_count": null, + "id": "173e1110", "metadata": {}, "outputs": [], "source": [ @@ -234,6 +256,7 @@ }, { "cell_type": "markdown", + "id": "e6fcc6b2", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -243,6 +266,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5fe3edbf", "metadata": {}, "outputs": [], "source": [ @@ -254,6 +278,7 @@ }, { "cell_type": "markdown", + "id": "179569e3", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -263,6 +288,7 @@ { "cell_type": "code", "execution_count": null, + "id": "b42dcacc", "metadata": {}, "outputs": [], "source": [ @@ -275,6 +301,7 @@ }, { "cell_type": "markdown", + "id": "78155c5d", "metadata": {}, "source": [ "Full results can be visualized in Paraview from the `file_handler.GetOutputDirectoryFullPath()` directory.\n", @@ -288,6 +315,7 @@ { "cell_type": "code", "execution_count": null, + "id": "1fd245e8", "metadata": {}, "outputs": [], "source": [ @@ -297,6 +325,7 @@ }, { "cell_type": "markdown", + "id": "95e70d26", "metadata": {}, "source": [ "We start by generating a mutable mesh. To create a `MutableMesh`, we can use the `HoneycombMeshGenerator` as before.\n", @@ -308,6 +337,7 @@ { "cell_type": "code", "execution_count": null, + "id": "68560f1c", "metadata": {}, "outputs": [], "source": [ @@ -318,6 +348,7 @@ }, { "cell_type": "markdown", + "id": "2d761a92", "metadata": {}, "source": [ "We only want to create cells to attach to real nodes, so we use the method `GetCellLocationIndices` to get the\n", @@ -328,6 +359,7 @@ { "cell_type": "code", "execution_count": null, + "id": "120e5f8e", "metadata": {}, "outputs": [], "source": [ @@ -336,6 +368,7 @@ }, { "cell_type": "markdown", + "id": "d249e8fa", "metadata": {}, "source": [ "Having created a mesh, we now create some cells. To do this, we use the `CellsGenerator` helper class again.\n", @@ -347,6 +380,7 @@ { "cell_type": "code", "execution_count": null, + "id": "10d6eb30", "metadata": {}, "outputs": [], "source": [ @@ -358,6 +392,7 @@ }, { "cell_type": "markdown", + "id": "2b2a347f", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", @@ -371,6 +406,7 @@ { "cell_type": "code", "execution_count": null, + "id": "97d7464b", "metadata": {}, "outputs": [], "source": [ @@ -381,6 +417,7 @@ }, { "cell_type": "markdown", + "id": "a8d3d3ec", "metadata": {}, "source": [ "Again Paraview output is explicitly requested.\n", @@ -390,6 +427,7 @@ { "cell_type": "code", "execution_count": null, + "id": "bb36fcce", "metadata": {}, "outputs": [], "source": [ @@ -398,6 +436,7 @@ }, { "cell_type": "markdown", + "id": "61e6cf6f", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -407,6 +446,7 @@ { "cell_type": "code", "execution_count": null, + "id": "a69f8753", "metadata": {}, "outputs": [], "source": [ @@ -418,6 +458,7 @@ }, { "cell_type": "markdown", + "id": "f81867de", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time.\n", @@ -427,6 +468,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5a980c00", "metadata": {}, "outputs": [], "source": [ @@ -438,6 +480,7 @@ }, { "cell_type": "markdown", + "id": "6fc2d3b8", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -447,6 +490,7 @@ { "cell_type": "code", "execution_count": null, + "id": "8e9a3827", "metadata": {}, "outputs": [], "source": [ @@ -458,6 +502,7 @@ }, { "cell_type": "markdown", + "id": "555e3e43", "metadata": {}, "source": [ "Again we create a force law, and pass it to the `OffLatticeSimulation`.\n", @@ -468,6 +513,7 @@ { "cell_type": "code", "execution_count": null, + "id": "0422077e", "metadata": {}, "outputs": [], "source": [ @@ -477,6 +523,7 @@ }, { "cell_type": "markdown", + "id": "4f463244", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`.\n", @@ -486,6 +533,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3b41d339", "metadata": {}, "outputs": [], "source": [ @@ -495,6 +543,7 @@ }, { "cell_type": "markdown", + "id": "5634e56f", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -505,6 +554,7 @@ { "cell_type": "code", "execution_count": null, + "id": "11da50ec", "metadata": {}, "outputs": [], "source": [ @@ -514,6 +564,7 @@ }, { "cell_type": "markdown", + "id": "7cfc1fac", "metadata": {}, "source": [ "Full results can be visualized in Paraview from the `file_handler.GetOutputDirectoryFullPath()` directory.\n", @@ -523,5 +574,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.md b/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.md index 4cc9879d..e54cd5b9 100644 --- a/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.md +++ b/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Mesh Based Cell Simulations Python Tutorial +title : "Test Mesh Based Cell Simulations Python Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestMeshBasedCellSimulationsPythonTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestMeshBasedCellSimulationsPythonTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestMeshBasedCellSimulationsPythonTutorial.py . Note that the code is given in full at the bottom of the page. diff --git a/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.nbconvert.ipynb b/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.nbconvert.ipynb new file mode 100644 index 00000000..6d825047 --- /dev/null +++ b/doc/tutorials/TestMeshBasedCellSimulationsPythonTutorial.nbconvert.ipynb @@ -0,0 +1,578 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "91bf95f6", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestMeshBasedCellSimulationsPythonTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b6811ea", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "218fbe30", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "In this tutorial we show how Chaste can be used to create, run and visualize mesh-based simulations.\n", + "Full details of the mathematical model can be found in van Leeuwen et al. (2009) [doi:10.1111/j.1365-2184.2009.00627.x].\n", + "\n", + "## Imports and Setup\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8cc5664", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt # Plotting\n", + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "chaste.init() # Set up MPI\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.visualization # Visualization tools" + ] + }, + { + "cell_type": "markdown", + "id": "1559ec87", + "metadata": {}, + "source": [ + "## Test 1 - a basic mesh-based simulation\n", + "In the first test, we run a simple mesh-based simulation,\n", + "in which we create a monolayer of cells, using a mutable mesh. Each cell is assigned a stochastic cell-cycle model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73fea897", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "542e3991", + "metadata": {}, + "source": [ + "Next, we generate a mutable mesh. To create a `MutableMesh`, we can use the `HoneycombMeshGenerator`.\n", + "This generates a honeycomb-shaped mesh, in which all nodes are equidistant. Here the first and second arguments define the size of the mesh -\n", + "we have chosen a mesh that is 4 nodes (i.e. cells) wide, and 4 nodes high.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c6457ec", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestMeshBasedCellSimulationsTutorial\")\n", + "generator = chaste.mesh.HoneycombMeshGenerator(4, 4)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "b320437c", + "metadata": {}, + "source": [ + "Having created a mesh, we now create some cells. To do this, we use the `CellsGenerator` helper class,\n", + "which is specialized by the type of cell cycle model required (here `UniformCellCycleModel`) and the dimension.\n", + "For a list of possible cell cycle models see subclasses of `AbstractCellCycleModel`.\n", + "Note that some of these models will require information on the surrounding medium such as Oxygen concentration to work,\n", + "see specific class documentation for details. We create an empty vector of cells and pass this into the method along with the mesh.\n", + "The second argument represents the size of that the list of cells should become - one cell for each node,\n", + "the third argument specifies the proliferative type of the cell.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63821a1e", + "metadata": {}, + "outputs": [], + "source": [ + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(),\n", + " transit_type)" + ] + }, + { + "cell_type": "markdown", + "id": "da78910f", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", + "In general, this class associates a collection of cells with a mesh. For this test, because we have a `MutableMesh`,\n", + "we use a particular type of cell population called a `MeshBasedCellPopulation`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d4eae36", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.MeshBasedCellPopulation2_2(mesh,\n", + " cells)" + ] + }, + { + "cell_type": "markdown", + "id": "0d4578de", + "metadata": {}, + "source": [ + "To view the results of this and the next test in Paraview it is necessary to explicitly\n", + "generate the required .vtu files.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2eff0fa5", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.AddPopulationWriterVoronoiDataWriter()" + ] + }, + { + "cell_type": "markdown", + "id": "94e159f7", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9b1c415", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "a36000b5", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3977141e", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestMeshBasedCellSimulationsTutorial\")\n", + "simulator.SetEndTime(10.0)" + ] + }, + { + "cell_type": "markdown", + "id": "4611308a", + "metadata": {}, + "source": [ + "For longer simulations, we may not want to output the results every time step. In this case we can use the following method,\n", + "to print results every 12 time steps instead. As the default time step used by the simulator is 30 seconds,\n", + "this method will cause the simulator to print results every 6 minutes (or 0.1 hours).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb5d898b", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.SetSamplingTimestepMultiple(12)" + ] + }, + { + "cell_type": "markdown", + "id": "c0d461f0", + "metadata": {}, + "source": [ + "We must now create one or more force laws, which determine the mechanics of the centres of each cell in a cell population.\n", + "For this test, we use one force law, based on the spring based model, and pass it to the `OffLatticeSimulation`.\n", + "For a list of possible forces see subclasses of `AbstractForce`. Note that some of these forces are not compatible with mesh-based simulations,\n", + "see the specific class documentation for details. If you try to use an incompatible class then you will receive a warning.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "173e1110", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.GeneralisedLinearSpringForce2_2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "e6fcc6b2", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fe3edbf", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "179569e3", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b42dcacc", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "scene.End()\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "78155c5d", + "metadata": {}, + "source": [ + "Full results can be visualized in Paraview from the `file_handler.GetOutputDirectoryFullPath()` directory.\n", + "\n", + "## Test 2 - a basic mesh-based simulation with ghost nodes\n", + "In the second test, we run a simple mesh-based simulation with ghost nodes, in which we create a monolayer of cells, using a mutable mesh.\n", + "Each cell is assigned a stochastic cell-cycle model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fd245e8", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "95e70d26", + "metadata": {}, + "source": [ + "We start by generating a mutable mesh. To create a `MutableMesh`, we can use the `HoneycombMeshGenerator` as before.\n", + "Here the first and second arguments define the size of the mesh - we have chosen a mesh that is 2 nodes (i.e. cells) wide,\n", + "and 2 nodes high. The third argument specifies the number of layers of ghost nodes to make.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68560f1c", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestMeshBasedCellPopulationWithGhostNodes\")\n", + "generator = chaste.mesh.HoneycombMeshGenerator(5, 5, 2)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "2d761a92", + "metadata": {}, + "source": [ + "We only want to create cells to attach to real nodes, so we use the method `GetCellLocationIndices` to get the\n", + "indices of the real nodes in the mesh. This will be passed in to the cell population later on.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "120e5f8e", + "metadata": {}, + "outputs": [], + "source": [ + "locs = generator.GetCellLocationIndices()" + ] + }, + { + "cell_type": "markdown", + "id": "d249e8fa", + "metadata": {}, + "source": [ + "Having created a mesh, we now create some cells. To do this, we use the `CellsGenerator` helper class again.\n", + "This time the second argument is different and is the number of real nodes in the mesh.\n", + "As before all cells have `TransitCellProliferativeType`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10d6eb30", + "metadata": {}, + "outputs": [], + "source": [ + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(len(locs),\n", + " transit_type)" + ] + }, + { + "cell_type": "markdown", + "id": "2b2a347f", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", + "In general, this class associates a collection of cells with a set of elements or a mesh.\n", + "For this test, because we have a `MutableMesh`, and ghost nodes we use a particular type of cell population called\n", + "a `MeshBasedCellPopulationWithGhostNodes`. The third argument of the constructor takes a vector of the indices of the real nodes\n", + "and should be the same length as the vector of cell pointers.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97d7464b", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.MeshBasedCellPopulationWithGhostNodes2(mesh,\n", + " cells,\n", + " locs)" + ] + }, + { + "cell_type": "markdown", + "id": "a8d3d3ec", + "metadata": {}, + "source": [ + "Again Paraview output is explicitly requested.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb36fcce", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.AddPopulationWriterVoronoiDataWriter()" + ] + }, + { + "cell_type": "markdown", + "id": "61e6cf6f", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a69f8753", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "scene.GetCellPopulationActorGenerator().SetShowVoronoiMeshEdges(True)\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "f81867de", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a980c00", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestMeshBasedCellPopulationWithGhostNodes\")\n", + "simulator.SetEndTime(10.0)\n", + "simulator.SetSamplingTimestepMultiple(12)" + ] + }, + { + "cell_type": "markdown", + "id": "6fc2d3b8", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e9a3827", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(300)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "555e3e43", + "metadata": {}, + "source": [ + "Again we create a force law, and pass it to the `OffLatticeSimulation`.\n", + "This force law ensures that ghost nodes don't exert forces on real nodes but real nodes exert forces on ghost nodes.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0422077e", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.GeneralisedLinearSpringForce2_2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "4f463244", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b41d339", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()" + ] + }, + { + "cell_type": "markdown", + "id": "5634e56f", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11da50ec", + "metadata": {}, + "outputs": [], + "source": [ + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "7cfc1fac", + "metadata": {}, + "source": [ + "Full results can be visualized in Paraview from the `file_handler.GetOutputDirectoryFullPath()` directory.\n", + "\n" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.ipynb b/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.ipynb index 07f3621f..9e52ec88 100644 --- a/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.ipynb +++ b/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "77e70b3c", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestNodeBasedCellSimulationsPythonTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestNodeBasedCellSimulationsPythonTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "52d0e910", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "57ab20c9", "metadata": {}, "source": [ "\n", @@ -36,6 +39,7 @@ { "cell_type": "code", "execution_count": null, + "id": "fda73917", "metadata": {}, "outputs": [], "source": [ @@ -49,6 +53,7 @@ }, { "cell_type": "markdown", + "id": "92769e61", "metadata": {}, "source": [ "## Test 1 - A basic node-based simulation\n", @@ -60,6 +65,7 @@ { "cell_type": "code", "execution_count": null, + "id": "cb9550e8", "metadata": {}, "outputs": [], "source": [ @@ -69,6 +75,7 @@ }, { "cell_type": "markdown", + "id": "35285203", "metadata": {}, "source": [ "The first thing we do is generate a nodes only mesh. To do this we first create a `MutableMesh` to use as a generating mesh.\n", @@ -80,6 +87,7 @@ { "cell_type": "code", "execution_count": null, + "id": "e51780bb", "metadata": {}, "outputs": [], "source": [ @@ -90,6 +98,7 @@ }, { "cell_type": "markdown", + "id": "24f331ad", "metadata": {}, "source": [ "Once we have a MutableMesh we can generate a NodesOnlyMesh from it using the following commands.\n", @@ -100,6 +109,7 @@ { "cell_type": "code", "execution_count": null, + "id": "d7038391", "metadata": {}, "outputs": [], "source": [ @@ -108,6 +118,7 @@ }, { "cell_type": "markdown", + "id": "8119355c", "metadata": {}, "source": [ "To run node-based simulations you need to define a cut off length (second argument in `ConstructNodesWithoutMesh`),\n", @@ -118,6 +129,7 @@ { "cell_type": "code", "execution_count": null, + "id": "917cb122", "metadata": {}, "outputs": [], "source": [ @@ -126,6 +138,7 @@ }, { "cell_type": "markdown", + "id": "e796f6e5", "metadata": {}, "source": [ "Having created a mesh, we now create a (wrapped) vector of CellPtrs. To do this, we use the `CellsGenerator` helper class,\n", @@ -139,17 +152,18 @@ { "cell_type": "code", "execution_count": null, + "id": "808fbbbd", "metadata": {}, "outputs": [], "source": [ "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", - "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(),\n", - " transit_type)" + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type)" ] }, { "cell_type": "markdown", + "id": "3168b24b", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", @@ -161,15 +175,16 @@ { "cell_type": "code", "execution_count": null, + "id": "7b4ed9b9", "metadata": {}, "outputs": [], "source": [ - "cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh,\n", - " cells)" + "cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh, cells)" ] }, { "cell_type": "markdown", + "id": "02d07e5c", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -179,6 +194,7 @@ { "cell_type": "code", "execution_count": null, + "id": "4bd3cab0", "metadata": {}, "outputs": [], "source": [ @@ -190,6 +206,7 @@ }, { "cell_type": "markdown", + "id": "9f9973a6", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", @@ -199,6 +216,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3179c673", "metadata": {}, "outputs": [], "source": [ @@ -210,6 +228,7 @@ }, { "cell_type": "markdown", + "id": "5580aefb", "metadata": {}, "source": [ "We now pass a force law to the simulation.\n", @@ -219,6 +238,7 @@ { "cell_type": "code", "execution_count": null, + "id": "585ce23f", "metadata": {}, "outputs": [], "source": [ @@ -228,6 +248,7 @@ }, { "cell_type": "markdown", + "id": "72d98417", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -237,6 +258,7 @@ { "cell_type": "code", "execution_count": null, + "id": "383346b9", "metadata": {}, "outputs": [], "source": [ @@ -248,6 +270,7 @@ }, { "cell_type": "markdown", + "id": "af92ab8b", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -257,6 +280,7 @@ { "cell_type": "code", "execution_count": null, + "id": "53da8e15", "metadata": {}, "outputs": [], "source": [ @@ -267,6 +291,7 @@ }, { "cell_type": "markdown", + "id": "9f0185e0", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -277,6 +302,7 @@ { "cell_type": "code", "execution_count": null, + "id": "e88ccc10", "metadata": {}, "outputs": [], "source": [ @@ -286,6 +312,7 @@ }, { "cell_type": "markdown", + "id": "8a2b6027", "metadata": {}, "source": [ "## Test 2 - a basic node-based simulation in 3D\n", @@ -297,6 +324,7 @@ { "cell_type": "code", "execution_count": null, + "id": "9f9ea318", "metadata": {}, "outputs": [], "source": [ @@ -306,6 +334,7 @@ }, { "cell_type": "markdown", + "id": "731b0057", "metadata": {}, "source": [ "First, we generate a nodes only mesh. This time we specify the nodes manually by first creating a vector of nodes\n", @@ -315,6 +344,7 @@ { "cell_type": "code", "execution_count": null, + "id": "9451df74", "metadata": {}, "outputs": [], "source": [ @@ -328,6 +358,7 @@ }, { "cell_type": "markdown", + "id": "601163f3", "metadata": {}, "source": [ "Finally a NodesOnlyMesh is created and the vector of nodes is passed to the ConstructNodesWithoutMesh method.\n", @@ -337,6 +368,7 @@ { "cell_type": "code", "execution_count": null, + "id": "6a15344d", "metadata": {}, "outputs": [], "source": [ @@ -345,6 +377,7 @@ }, { "cell_type": "markdown", + "id": "ec9d87c4", "metadata": {}, "source": [ "To run node-based simulations you need to define a cut off length (second argument in ConstructNodesWithoutMesh),\n", @@ -355,6 +388,7 @@ { "cell_type": "code", "execution_count": null, + "id": "be7b899a", "metadata": {}, "outputs": [], "source": [ @@ -363,6 +397,7 @@ }, { "cell_type": "markdown", + "id": "14129c6d", "metadata": {}, "source": [ "Having created a mesh, we now create a std::vector of CellPtrs.\n", @@ -373,17 +408,18 @@ { "cell_type": "code", "execution_count": null, + "id": "a19b015a", "metadata": {}, "outputs": [], "source": [ "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3()\n", - "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(),\n", - " transit_type)" + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type)" ] }, { "cell_type": "markdown", + "id": "73409bc2", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", @@ -395,15 +431,16 @@ { "cell_type": "code", "execution_count": null, + "id": "37876a5f", "metadata": {}, "outputs": [], "source": [ - "cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh,\n", - " cells)" + "cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells)" ] }, { "cell_type": "markdown", + "id": "21c26dc2", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -413,6 +450,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5a273b33", "metadata": {}, "outputs": [], "source": [ @@ -423,6 +461,7 @@ }, { "cell_type": "markdown", + "id": "4afd1a22", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", @@ -432,6 +471,7 @@ { "cell_type": "code", "execution_count": null, + "id": "e87be123", "metadata": {}, "outputs": [], "source": [ @@ -443,6 +483,7 @@ }, { "cell_type": "markdown", + "id": "3e9aa750", "metadata": {}, "source": [ "We now pass a force law to the simulation.\n", @@ -452,6 +493,7 @@ { "cell_type": "code", "execution_count": null, + "id": "76b09516", "metadata": {}, "outputs": [], "source": [ @@ -461,6 +503,7 @@ }, { "cell_type": "markdown", + "id": "b275a15c", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -470,6 +513,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3143d3b0", "metadata": {}, "outputs": [], "source": [ @@ -481,6 +525,7 @@ }, { "cell_type": "markdown", + "id": "b68d807a", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -490,6 +535,7 @@ { "cell_type": "code", "execution_count": null, + "id": "9d869949", "metadata": {}, "outputs": [], "source": [ @@ -500,6 +546,7 @@ }, { "cell_type": "markdown", + "id": "a6e8e951", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -510,16 +557,17 @@ { "cell_type": "code", "execution_count": null, + "id": "1fa74bdb", "metadata": {}, "outputs": [], "source": [ - " 10.0, 6)\n", "# Tear down the test \n", "chaste.cell_based.TearDownNotebookTest()" ] }, { "cell_type": "markdown", + "id": "8e043c5d", "metadata": {}, "source": [ "## Test 3 - a node-based simulation on a restricted geometry\n", @@ -531,6 +579,7 @@ { "cell_type": "code", "execution_count": null, + "id": "50ceb577", "metadata": {}, "outputs": [], "source": [ @@ -540,6 +589,7 @@ }, { "cell_type": "markdown", + "id": "17029d10", "metadata": {}, "source": [ "In the third test we run a node-based simulation restricted to the surface of a sphere.\n", @@ -549,6 +599,7 @@ { "cell_type": "code", "execution_count": null, + "id": "76793e02", "metadata": {}, "outputs": [], "source": [ @@ -563,6 +614,7 @@ }, { "cell_type": "markdown", + "id": "5393d13d", "metadata": {}, "source": [ "To run node-based simulations you need to define a cut off length (second argument in ConstructNodesWithoutMesh),\n", @@ -573,20 +625,20 @@ { "cell_type": "code", "execution_count": null, + "id": "05cc0ffe", "metadata": {}, "outputs": [], "source": [ "mesh.ConstructNodesWithoutMesh(nodes, 1.5)\n", "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3()\n", - "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(),\n", - " transit_type)\n", - "cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh,\n", - " cells)" + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type)\n", + "cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells)" ] }, { "cell_type": "markdown", + "id": "9dd8d022", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -596,6 +648,7 @@ { "cell_type": "code", "execution_count": null, + "id": "37e6c49c", "metadata": {}, "outputs": [], "source": [ @@ -610,6 +663,7 @@ }, { "cell_type": "markdown", + "id": "f7f34f19", "metadata": {}, "source": [ "We now pass a force law to the simulation.\n", @@ -619,6 +673,7 @@ { "cell_type": "code", "execution_count": null, + "id": "83933153", "metadata": {}, "outputs": [], "source": [ @@ -628,6 +683,7 @@ }, { "cell_type": "markdown", + "id": "570d8800", "metadata": {}, "source": [ "This time we create a CellPopulationBoundaryCondition and pass this to the OffLatticeSimulation.\n", @@ -642,20 +698,20 @@ { "cell_type": "code", "execution_count": null, + "id": "c13b64c5", "metadata": {}, "outputs": [], "source": [ "centre = np.array([0.0, 0.0, 1.0])\n", "radius = 5.0\n", "point2 = chaste.mesh.ChastePoint3(centre)\n", - "boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population,\n", - " point2.rGetLocation(),\n", - " radius)\n", + "boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population, point2.rGetLocation(), radius)\n", "simulator.AddCellPopulationBoundaryCondition(boundary_condition)" ] }, { "cell_type": "markdown", + "id": "bdf1db06", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -665,6 +721,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5ed9087d", "metadata": {}, "outputs": [], "source": [ @@ -675,6 +732,7 @@ }, { "cell_type": "markdown", + "id": "3787ebeb", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -684,6 +742,7 @@ { "cell_type": "code", "execution_count": null, + "id": "40df3af8", "metadata": {}, "outputs": [], "source": [ @@ -694,6 +753,7 @@ }, { "cell_type": "markdown", + "id": "8fda7129", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -704,6 +764,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7627d6d3", "metadata": {}, "outputs": [], "source": [ @@ -715,5 +776,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.md b/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.md index c2ab5290..510fc1de 100644 --- a/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.md +++ b/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Node Based Cell Simulations Python Tutorial +title : "Test Node Based Cell Simulations Python Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestNodeBasedCellSimulationsPythonTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestNodeBasedCellSimulationsPythonTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestNodeBasedCellSimulationsPythonTutorial.py . Note that the code is given in full at the bottom of the page. @@ -68,8 +73,7 @@ the third argument specifies the proliferative type of the cell. ```python transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type) ``` Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`. @@ -77,8 +81,7 @@ In general, this class associates a collection of cells with a mesh. For this te because we have a `NodesOnlyMesh`, we use a particular type of cell population called a `NodeBasedCellPopulation`. ```python - cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh, - cells) + cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh, cells) ``` We can set up a `VtkScene` to do a quick visualization of the population before running the analysis. @@ -173,8 +176,7 @@ As before, we do this with the CellsGenerator helper class (this time with dimen ```python transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type) ``` Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`. @@ -182,8 +184,7 @@ In general, this class associates a collection of cells with a mesh. For this te because we have a `NodesOnlyMesh`, we use a particular type of cell population called a `NodeBasedCellPopulation`. ```python - cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, - cells) + cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells) ``` We can set up a `VtkScene` to do a quick visualization of the population before running the analysis. @@ -232,8 +233,7 @@ If different simulation input parameters are being explored the lines should be ```python self.assertEqual(cell_population.GetNumRealCells(), 8) - self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), - 10.0, 6) + self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), 10.0, 6) # JUPYTER_TEARDOWN @@ -268,10 +268,8 @@ which defines the connectivity of the nodes by defining a radius of interaction. transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), - transit_type) - cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, - cells) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type) + cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells) ``` We can set up a `VtkScene` to do a quick visualization of the population before running the analysis. @@ -305,9 +303,7 @@ First we set the centre (0,0,1) and radius of the sphere (1). centre = np.array([0.0, 0.0, 1.0]) radius = 5.0 point2 = chaste.mesh.ChastePoint3(centre) - boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population, - point2.rGetLocation(), - radius) + boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population, point2.rGetLocation(), radius) simulator.AddCellPopulationBoundaryCondition(boundary_condition) ``` @@ -373,11 +369,9 @@ class TestRunningNodeBasedSimulationsTutorial(chaste.cell_based.AbstractCellBase transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type) - cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh, - cells) + cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh, cells) scene = chaste.visualization.VtkScene2() scene.SetCellPopulation(cell_population) @@ -423,11 +417,9 @@ class TestRunningNodeBasedSimulationsTutorial(chaste.cell_based.AbstractCellBase transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type) - cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, - cells) + cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells) scene = chaste.visualization.VtkScene3() scene.SetCellPopulation(cell_population) @@ -451,8 +443,7 @@ class TestRunningNodeBasedSimulationsTutorial(chaste.cell_based.AbstractCellBase scene.End() self.assertEqual(cell_population.GetNumRealCells(), 8) - self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), - 10.0, 6) + self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), 10.0, 6) # JUPYTER_TEARDOWN @@ -472,10 +463,8 @@ class TestRunningNodeBasedSimulationsTutorial(chaste.cell_based.AbstractCellBase transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), - transit_type) - cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, - cells) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type) + cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells) scene = chaste.visualization.VtkScene3() scene.SetCellPopulation(cell_population) @@ -492,9 +481,7 @@ class TestRunningNodeBasedSimulationsTutorial(chaste.cell_based.AbstractCellBase centre = np.array([0.0, 0.0, 1.0]) radius = 5.0 point2 = chaste.mesh.ChastePoint3(centre) - boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population, - point2.rGetLocation(), - radius) + boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population, point2.rGetLocation(), radius) simulator.AddCellPopulationBoundaryCondition(boundary_condition) scene_modifier.SetVtkScene(scene) diff --git a/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.nbconvert.ipynb b/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.nbconvert.ipynb new file mode 100644 index 00000000..9e52ec88 --- /dev/null +++ b/doc/tutorials/TestNodeBasedCellSimulationsPythonTutorial.nbconvert.ipynb @@ -0,0 +1,780 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "77e70b3c", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestNodeBasedCellSimulationsPythonTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52d0e910", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "57ab20c9", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "In this tutorial we show how Chaste can be used to create, run and visualize node-based simulations. Full details of the mechanical model can be found in Pathamathan et\n", + "al \"A computational study of discrete mechanical tissue models\", Physical Biology. Vol. 6. No. 3. 2009.. DOI (10.1088/1478-3975/6/3/036001).\n", + "\n", + "## The Test\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fda73917", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.visualization # Visualization tools\n", + "chaste.init() # Set up MPI" + ] + }, + { + "cell_type": "markdown", + "id": "92769e61", + "metadata": {}, + "source": [ + "## Test 1 - A basic node-based simulation\n", + "In the first test, we run a simple node-based simulation, in which we create a monolayer of cells,\n", + "using a nodes only mesh. Each cell is assigned a uniform cell-cycle model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb9550e8", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "35285203", + "metadata": {}, + "source": [ + "The first thing we do is generate a nodes only mesh. To do this we first create a `MutableMesh` to use as a generating mesh.\n", + "To do this we can use the `HoneycombMeshGenerator`. This generates a honeycomb-shaped mesh, in which all nodes are equidistant.\n", + "Here the first and second arguments define the size of the mesh - we have chosen a mesh that is 2 nodes (i.e. cells) wide, and 2 nodes high.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e51780bb", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestNodeBasedCellSimulationsTutorial\")\n", + "generator = chaste.mesh.HoneycombMeshGenerator(2, 2)\n", + "generating_mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "24f331ad", + "metadata": {}, + "source": [ + "Once we have a MutableMesh we can generate a NodesOnlyMesh from it using the following commands.\n", + "Note you can also generate the NodesOnlyMesh from a collection of nodes.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7038391", + "metadata": {}, + "outputs": [], + "source": [ + "mesh = chaste.mesh.NodesOnlyMesh2()" + ] + }, + { + "cell_type": "markdown", + "id": "8119355c", + "metadata": {}, + "source": [ + "To run node-based simulations you need to define a cut off length (second argument in `ConstructNodesWithoutMesh`),\n", + "which defines the connectivity of the nodes by defining a radius of interaction.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "917cb122", + "metadata": {}, + "outputs": [], + "source": [ + "mesh.ConstructNodesWithoutMesh(generating_mesh, 1.5)" + ] + }, + { + "cell_type": "markdown", + "id": "e796f6e5", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a (wrapped) vector of CellPtrs. To do this, we use the `CellsGenerator` helper class,\n", + "which is specialized for the type of cell model required (here `UniformCellCycleModel`) and the dimension.\n", + "We create an empty vector of cells and pass this into the method along with the mesh.\n", + "The second argument represents the size of that the vector cells should become - one cell for each node,\n", + "the third argument specifies the proliferative type of the cell.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "808fbbbd", + "metadata": {}, + "outputs": [], + "source": [ + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type)" + ] + }, + { + "cell_type": "markdown", + "id": "3168b24b", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", + "In general, this class associates a collection of cells with a mesh. For this test,\n", + "because we have a `NodesOnlyMesh`, we use a particular type of cell population called a `NodeBasedCellPopulation`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b4ed9b9", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.NodeBasedCellPopulation2(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "02d07e5c", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4bd3cab0", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "9f9973a6", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3179c673", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestNodeBasedCellSimulationsTutorial\")\n", + "simulator.SetSamplingTimestepMultiple(100)\n", + "simulator.SetEndTime(10.0)" + ] + }, + { + "cell_type": "markdown", + "id": "5580aefb", + "metadata": {}, + "source": [ + "We now pass a force law to the simulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "585ce23f", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.GeneralisedLinearSpringForce2_2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "72d98417", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "383346b9", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "af92ab8b", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53da8e15", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "scene.End()" + ] + }, + { + "cell_type": "markdown", + "id": "9f0185e0", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e88ccc10", + "metadata": {}, + "outputs": [], + "source": [ + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "8a2b6027", + "metadata": {}, + "source": [ + "## Test 2 - a basic node-based simulation in 3D\n", + "In the second test we run a simple node-based simulation in 3D. This is very similar to the 2D test with the dimension changed from 2 to 3 and\n", + "instead of using a mesh generator we generate the nodes directly.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f9ea318", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "731b0057", + "metadata": {}, + "source": [ + "First, we generate a nodes only mesh. This time we specify the nodes manually by first creating a vector of nodes\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9451df74", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestNodeBasedCellSimulationsSpheroidTutorial\")\n", + "nodes = []\n", + "nodes.append(chaste.mesh.Node3(0, False, 0.5, 0.0, 0.0))\n", + "nodes.append(chaste.mesh.Node3(1, False, -0.5, 0.0, 0.0))\n", + "nodes.append(chaste.mesh.Node3(2, False, 0.0, 0.5, 0.0))\n", + "nodes.append(chaste.mesh.Node3(3, False, 0.0, -0.5, 0.0))" + ] + }, + { + "cell_type": "markdown", + "id": "601163f3", + "metadata": {}, + "source": [ + "Finally a NodesOnlyMesh is created and the vector of nodes is passed to the ConstructNodesWithoutMesh method.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a15344d", + "metadata": {}, + "outputs": [], + "source": [ + "mesh = chaste.mesh.NodesOnlyMesh3()" + ] + }, + { + "cell_type": "markdown", + "id": "ec9d87c4", + "metadata": {}, + "source": [ + "To run node-based simulations you need to define a cut off length (second argument in ConstructNodesWithoutMesh),\n", + "which defines the connectivity of the nodes by defining a radius of interaction.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be7b899a", + "metadata": {}, + "outputs": [], + "source": [ + "mesh.ConstructNodesWithoutMesh(nodes, 1.5)" + ] + }, + { + "cell_type": "markdown", + "id": "14129c6d", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a std::vector of CellPtrs.\n", + "As before, we do this with the CellsGenerator helper class (this time with dimension 3).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a19b015a", + "metadata": {}, + "outputs": [], + "source": [ + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type)" + ] + }, + { + "cell_type": "markdown", + "id": "73409bc2", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation`.\n", + "In general, this class associates a collection of cells with a mesh. For this test,\n", + "because we have a `NodesOnlyMesh`, we use a particular type of cell population called a `NodeBasedCellPopulation`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37876a5f", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "21c26dc2", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a273b33", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene3()\n", + "scene.SetCellPopulation(cell_population)\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "4afd1a22", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e87be123", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation3_3(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestNodeBasedCellSimulationsSpheroidTutorial\")\n", + "simulator.SetSamplingTimestepMultiple(12)\n", + "simulator.SetEndTime(10.0)" + ] + }, + { + "cell_type": "markdown", + "id": "3e9aa750", + "metadata": {}, + "source": [ + "We now pass a force law to the simulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76b09516", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.GeneralisedLinearSpringForce3_3()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "b275a15c", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3143d3b0", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier3(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "b68d807a", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d869949", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "scene.End()" + ] + }, + { + "cell_type": "markdown", + "id": "a6e8e951", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fa74bdb", + "metadata": {}, + "outputs": [], + "source": [ + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "8e043c5d", + "metadata": {}, + "source": [ + "## Test 3 - a node-based simulation on a restricted geometry\n", + "In the second test we run a simple node-based simulation in 3D. This is very similar to the 2D test with the dimension changed from 2 to 3 and\n", + "instead of using a mesh generator we generate the nodes directly.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50ceb577", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "17029d10", + "metadata": {}, + "source": [ + "In the third test we run a node-based simulation restricted to the surface of a sphere.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76793e02", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestNodeBasedCellSimulationsRestrictedSpheroidTutorial\")\n", + "nodes = []\n", + "nodes.append(chaste.mesh.Node3(0, False, 0.5, 0.0, 0.0))\n", + "nodes.append(chaste.mesh.Node3(1, False, -0.5, 0.0, 0.0))\n", + "nodes.append(chaste.mesh.Node3(2, False, 0.0, 0.5, 0.0))\n", + "nodes.append(chaste.mesh.Node3(3, False, 0.0, -0.5, 0.0))\n", + "mesh = chaste.mesh.NodesOnlyMesh3()" + ] + }, + { + "cell_type": "markdown", + "id": "5393d13d", + "metadata": {}, + "source": [ + "To run node-based simulations you need to define a cut off length (second argument in ConstructNodesWithoutMesh),\n", + "which defines the connectivity of the nodes by defining a radius of interaction.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05cc0ffe", + "metadata": {}, + "outputs": [], + "source": [ + "mesh.ConstructNodesWithoutMesh(nodes, 1.5)\n", + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), transit_type)\n", + "cell_population = chaste.cell_based.NodeBasedCellPopulation3(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "9dd8d022", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37e6c49c", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene3()\n", + "scene.SetCellPopulation(cell_population)\n", + "nb_manager.vtk_show(scene, height=600)\n", + "simulator = chaste.cell_based.OffLatticeSimulation3_3(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestNodeBasedCellSimulationsRestrictedSpheroidTutorial\")\n", + "simulator.SetSamplingTimestepMultiple(12)\n", + "simulator.SetEndTime(10.0)" + ] + }, + { + "cell_type": "markdown", + "id": "f7f34f19", + "metadata": {}, + "source": [ + "We now pass a force law to the simulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83933153", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.GeneralisedLinearSpringForce3_3()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "570d8800", + "metadata": {}, + "source": [ + "This time we create a CellPopulationBoundaryCondition and pass this to the OffLatticeSimulation.\n", + "Here we use a SphereGeometryBoundaryCondition which restricts cells to lie on a sphere (in 3D) or circle (in 2D).\n", + "For a list of possible boundary conditions see subclasses of AbstractCellPopulationBoundaryCondition.\n", + "Note that some of these boundary conditions are not compatible with node-based simulations see the specific class documentation\n", + "for details, if you try to use an incompatible class then you will receive a warning.\n", + "First we set the centre (0,0,1) and radius of the sphere (1).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c13b64c5", + "metadata": {}, + "outputs": [], + "source": [ + "centre = np.array([0.0, 0.0, 1.0])\n", + "radius = 5.0\n", + "point2 = chaste.mesh.ChastePoint3(centre)\n", + "boundary_condition = chaste.cell_based.SphereGeometryBoundaryCondition3(cell_population, point2.rGetLocation(), radius)\n", + "simulator.AddCellPopulationBoundaryCondition(boundary_condition)" + ] + }, + { + "cell_type": "markdown", + "id": "bdf1db06", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "scene_modifier = chaste.cell_based.VtkSceneModifier3()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ed9087d", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "3787ebeb", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40df3af8", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "scene.End()" + ] + }, + { + "cell_type": "markdown", + "id": "8fda7129", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7627d6d3", + "metadata": {}, + "outputs": [], + "source": [ + " 10.0, 6)\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.ipynb b/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.ipynb index 63b8d1c5..9e3675eb 100644 --- a/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.ipynb +++ b/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "19f2f0f9", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestPottsBasedCellSimulationsPythonTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestPottsBasedCellSimulationsPythonTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "32862ad6", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "cc57e771", "metadata": {}, "source": [ "\n", @@ -36,6 +39,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3d66baea", "metadata": {}, "outputs": [], "source": [ @@ -48,6 +52,7 @@ }, { "cell_type": "markdown", + "id": "b81ac981", "metadata": {}, "source": [ "## Test 1 - A basic node-based simulation\n", @@ -59,6 +64,7 @@ { "cell_type": "code", "execution_count": null, + "id": "bc00e31a", "metadata": {}, "outputs": [], "source": [ @@ -68,6 +74,7 @@ }, { "cell_type": "markdown", + "id": "4e84f214", "metadata": {}, "source": [ "First, we generate a Potts mesh. To create a PottsMesh, we can use the PottsMeshGenerator.\n", @@ -81,6 +88,7 @@ { "cell_type": "code", "execution_count": null, + "id": "0ddcb8f1", "metadata": {}, "outputs": [], "source": [ @@ -92,6 +100,7 @@ }, { "cell_type": "markdown", + "id": "83ed5d9d", "metadata": {}, "source": [ "Having created a mesh, we now create a vector of CellPtrs. To do this, we the CellsGenerator helper class,\n", @@ -105,6 +114,7 @@ { "cell_type": "code", "execution_count": null, + "id": "4e8b891c", "metadata": {}, "outputs": [], "source": [ @@ -114,6 +124,7 @@ }, { "cell_type": "markdown", + "id": "e056ad92", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", @@ -125,6 +136,7 @@ { "cell_type": "code", "execution_count": null, + "id": "c23592f7", "metadata": {}, "outputs": [], "source": [ @@ -134,6 +146,7 @@ }, { "cell_type": "markdown", + "id": "6d71cf2c", "metadata": {}, "source": [ "We can set the \"Temperature\" to be used in the Potts Simulation using the optional command below. The default value is 0.1.\n", @@ -143,6 +156,7 @@ { "cell_type": "code", "execution_count": null, + "id": "c989327e", "metadata": {}, "outputs": [], "source": [ @@ -151,6 +165,7 @@ }, { "cell_type": "markdown", + "id": "9113a155", "metadata": {}, "source": [ "By default the Potts simulation will make 1 sweep over the whole domain per timestep.\n", @@ -161,6 +176,7 @@ { "cell_type": "code", "execution_count": null, + "id": "8289feeb", "metadata": {}, "outputs": [], "source": [ @@ -169,6 +185,7 @@ }, { "cell_type": "markdown", + "id": "99e056fc", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -178,6 +195,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7db9fc5b", "metadata": {}, "outputs": [], "source": [ @@ -190,6 +208,7 @@ }, { "cell_type": "markdown", + "id": "528e59be", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", @@ -199,6 +218,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7d750ce2", "metadata": {}, "outputs": [], "source": [ @@ -209,6 +229,7 @@ }, { "cell_type": "markdown", + "id": "e4d5c4aa", "metadata": {}, "source": [ "The default timestep is 0.1, but can be changed using the below command. The timestep is used in conjunction with the \"Temperature\"\n", @@ -220,6 +241,7 @@ { "cell_type": "code", "execution_count": null, + "id": "0d507968", "metadata": {}, "outputs": [], "source": [ @@ -229,6 +251,7 @@ }, { "cell_type": "markdown", + "id": "2156ab5f", "metadata": {}, "source": [ "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", @@ -241,6 +264,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5695e258", "metadata": {}, "outputs": [], "source": [ @@ -249,6 +273,7 @@ }, { "cell_type": "markdown", + "id": "e61aafb8", "metadata": {}, "source": [ "Set an appropriate target volume in number of lattice sites. Here we use the default value of 16 lattice sites.\n", @@ -258,6 +283,7 @@ { "cell_type": "code", "execution_count": null, + "id": "92e25726", "metadata": {}, "outputs": [], "source": [ @@ -266,6 +292,7 @@ }, { "cell_type": "markdown", + "id": "276fcdbd", "metadata": {}, "source": [ "You can also vary the deformation energy parameter.\n", @@ -276,6 +303,7 @@ { "cell_type": "code", "execution_count": null, + "id": "bddcb2b8", "metadata": {}, "outputs": [], "source": [ @@ -284,6 +312,7 @@ }, { "cell_type": "markdown", + "id": "f26aad41", "metadata": {}, "source": [ "Finally we add the update rule to the simulator.\n", @@ -293,6 +322,7 @@ { "cell_type": "code", "execution_count": null, + "id": "91deabd8", "metadata": {}, "outputs": [], "source": [ @@ -301,6 +331,7 @@ }, { "cell_type": "markdown", + "id": "e8177fd5", "metadata": {}, "source": [ "We repeat the process for any other update rules.\n", @@ -310,6 +341,7 @@ { "cell_type": "code", "execution_count": null, + "id": "e78fe9c8", "metadata": {}, "outputs": [], "source": [ @@ -319,6 +351,7 @@ }, { "cell_type": "markdown", + "id": "280b6408", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -328,6 +361,7 @@ { "cell_type": "code", "execution_count": null, + "id": "6ba7bdda", "metadata": {}, "outputs": [], "source": [ @@ -339,6 +373,7 @@ }, { "cell_type": "markdown", + "id": "a7a40e12", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -348,6 +383,7 @@ { "cell_type": "code", "execution_count": null, + "id": "ee54db29", "metadata": {}, "outputs": [], "source": [ @@ -357,6 +393,7 @@ }, { "cell_type": "markdown", + "id": "2631a8d8", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -367,6 +404,7 @@ { "cell_type": "code", "execution_count": null, + "id": "9aedfa4f", "metadata": {}, "outputs": [], "source": [ @@ -377,6 +415,7 @@ }, { "cell_type": "markdown", + "id": "8f0fb47a", "metadata": {}, "source": [ "## Test 2 - Cell sorting\n", @@ -388,6 +427,7 @@ { "cell_type": "code", "execution_count": null, + "id": "6b02e3c2", "metadata": {}, "outputs": [], "source": [ @@ -397,6 +437,7 @@ }, { "cell_type": "markdown", + "id": "a5933986", "metadata": {}, "source": [ "First, we generate a Potts mesh. To create a PottsMesh, we can use the PottsMeshGenerator.\n", @@ -408,6 +449,7 @@ { "cell_type": "code", "execution_count": null, + "id": "0fbd8e4a", "metadata": {}, "outputs": [], "source": [ @@ -418,6 +460,7 @@ }, { "cell_type": "markdown", + "id": "415bd93e", "metadata": {}, "source": [ "Having created a mesh, we now create a VectorSharedPtrCells. To do this, we the CellsGenerator helper class,\n", @@ -428,6 +471,7 @@ { "cell_type": "code", "execution_count": null, + "id": "57803d88", "metadata": {}, "outputs": [], "source": [ @@ -439,6 +483,7 @@ }, { "cell_type": "markdown", + "id": "60e6297b", "metadata": {}, "source": [ "Before we make a CellPopulation we make a cell label and then assign this label to some randomly chosen cells.\n", @@ -448,6 +493,7 @@ { "cell_type": "code", "execution_count": null, + "id": "d197149c", "metadata": {}, "outputs": [], "source": [ @@ -459,6 +505,7 @@ }, { "cell_type": "markdown", + "id": "1444786a", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", @@ -468,6 +515,7 @@ { "cell_type": "code", "execution_count": null, + "id": "92b3b708", "metadata": {}, "outputs": [], "source": [ @@ -477,6 +525,7 @@ }, { "cell_type": "markdown", + "id": "02b97221", "metadata": {}, "source": [ "In order to visualize labelled cells we need to use the following command.\n", @@ -486,6 +535,7 @@ { "cell_type": "code", "execution_count": null, + "id": "0577431b", "metadata": {}, "outputs": [], "source": [ @@ -494,6 +544,7 @@ }, { "cell_type": "markdown", + "id": "a280deb7", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", @@ -503,6 +554,7 @@ { "cell_type": "code", "execution_count": null, + "id": "37dce360", "metadata": {}, "outputs": [], "source": [ @@ -514,6 +566,7 @@ }, { "cell_type": "markdown", + "id": "55f2ef5e", "metadata": {}, "source": [ "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", @@ -526,6 +579,7 @@ { "cell_type": "code", "execution_count": null, + "id": "98da52bc", "metadata": {}, "outputs": [], "source": [ @@ -537,6 +591,7 @@ }, { "cell_type": "markdown", + "id": "1e372374", "metadata": {}, "source": [ "We repeat the process for any other update rules.\n", @@ -546,6 +601,7 @@ { "cell_type": "code", "execution_count": null, + "id": "2c1e84b4", "metadata": {}, "outputs": [], "source": [ @@ -560,6 +616,7 @@ }, { "cell_type": "markdown", + "id": "6c275247", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`.\n", @@ -569,6 +626,7 @@ { "cell_type": "code", "execution_count": null, + "id": "37549cdb", "metadata": {}, "outputs": [], "source": [ @@ -577,6 +635,7 @@ }, { "cell_type": "markdown", + "id": "9e41d672", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -587,6 +646,7 @@ { "cell_type": "code", "execution_count": null, + "id": "169a61f8", "metadata": {}, "outputs": [], "source": [ @@ -597,6 +657,7 @@ }, { "cell_type": "markdown", + "id": "b7e6cb90", "metadata": {}, "source": [ "## Test 3 - 3D Cell Sorting\n", @@ -607,6 +668,7 @@ { "cell_type": "code", "execution_count": null, + "id": "782c9629", "metadata": {}, "outputs": [], "source": [ @@ -616,6 +678,7 @@ }, { "cell_type": "markdown", + "id": "bc1b2f05", "metadata": {}, "source": [ "First, we generate a Potts mesh. To create a PottsMesh, we can use the PottsMeshGenerator.\n", @@ -630,6 +693,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3e099ae2", "metadata": {}, "outputs": [], "source": [ @@ -641,6 +705,7 @@ }, { "cell_type": "markdown", + "id": "2a93a3f2", "metadata": {}, "source": [ "Having created a mesh, we now create a VectorSharedPtrCells. To do this, we the CellsGenerator helper class,\n", @@ -651,6 +716,7 @@ { "cell_type": "code", "execution_count": null, + "id": "1b59f72b", "metadata": {}, "outputs": [], "source": [ @@ -662,6 +728,7 @@ }, { "cell_type": "markdown", + "id": "56e31deb", "metadata": {}, "source": [ "As for the 2D case before we make a CellPopulation we make a pointer to a cell label and then assign this label to some randomly chosen cells.\n", @@ -671,6 +738,7 @@ { "cell_type": "code", "execution_count": null, + "id": "78d8845c", "metadata": {}, "outputs": [], "source": [ @@ -682,6 +750,7 @@ }, { "cell_type": "markdown", + "id": "26a025de", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", @@ -691,6 +760,7 @@ { "cell_type": "code", "execution_count": null, + "id": "96bf7ba5", "metadata": {}, "outputs": [], "source": [ @@ -700,6 +770,7 @@ }, { "cell_type": "markdown", + "id": "97beee30", "metadata": {}, "source": [ "In order to visualize labelled cells we need to use the following command.\n", @@ -709,6 +780,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7e88cf66", "metadata": {}, "outputs": [], "source": [ @@ -717,6 +789,7 @@ }, { "cell_type": "markdown", + "id": "e5e15bd2", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", @@ -726,6 +799,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5707e277", "metadata": {}, "outputs": [], "source": [ @@ -737,6 +811,7 @@ }, { "cell_type": "markdown", + "id": "16f312dd", "metadata": {}, "source": [ "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", @@ -747,6 +822,7 @@ { "cell_type": "code", "execution_count": null, + "id": "037e1d6b", "metadata": {}, "outputs": [], "source": [ @@ -758,6 +834,7 @@ }, { "cell_type": "markdown", + "id": "6ce4b0a8", "metadata": {}, "source": [ "We use the same differential adhesion parameters as in the 2D case.\n", @@ -767,6 +844,7 @@ { "cell_type": "code", "execution_count": null, + "id": "4e04b895", "metadata": {}, "outputs": [], "source": [ @@ -781,6 +859,7 @@ }, { "cell_type": "markdown", + "id": "321efe1a", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`.\n", @@ -790,6 +869,7 @@ { "cell_type": "code", "execution_count": null, + "id": "f176a3bc", "metadata": {}, "outputs": [], "source": [ @@ -798,6 +878,7 @@ }, { "cell_type": "markdown", + "id": "1274cc35", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -808,6 +889,7 @@ { "cell_type": "code", "execution_count": null, + "id": "81e55ee8", "metadata": {}, "outputs": [], "source": [ @@ -819,5 +901,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.md b/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.md index f3cae677..b14a20ba 100644 --- a/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.md +++ b/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Potts Based Cell Simulations Python Tutorial +title : "Test Potts Based Cell Simulations Python Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestPottsBasedCellSimulationsPythonTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestPottsBasedCellSimulationsPythonTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestPottsBasedCellSimulationsPythonTutorial.py . Note that the code is given in full at the bottom of the page. diff --git a/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.nbconvert.ipynb b/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.nbconvert.ipynb new file mode 100644 index 00000000..9e3675eb --- /dev/null +++ b/doc/tutorials/TestPottsBasedCellSimulationsPythonTutorial.nbconvert.ipynb @@ -0,0 +1,905 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "19f2f0f9", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestPottsBasedCellSimulationsPythonTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32862ad6", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "cc57e771", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "In this tutorial we show how Chaste can be used to create, run and visualize Potts-based simulations.\n", + "Full details of the mathematical model can be found in Graner, F. and Glazier, J. A. (1992).\n", + "\n", + "## The Test\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d66baea", + "metadata": {}, + "outputs": [], + "source": [ + "import chaste # The PyChaste module\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.visualization # Visualization tools\n", + "chaste.init() # Set up MPI" + ] + }, + { + "cell_type": "markdown", + "id": "b81ac981", + "metadata": {}, + "source": [ + "## Test 1 - A basic node-based simulation\n", + "In the first test, we run a simple Potts-based simulation, in which we create a monolayer of cells, using a Potts mesh.\n", + "Each cell is assigned a stochastic cell-cycle model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc00e31a", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "4e84f214", + "metadata": {}, + "source": [ + "First, we generate a Potts mesh. To create a PottsMesh, we can use the PottsMeshGenerator.\n", + "This generates a regular square-shaped mesh, in which all elements are the same size.\n", + "Here the first three arguments specify the domain width; the number of elements across; and the width of elements.\n", + "The second set of three arguments specify the domain height; the number of elements up; and the height of individual elements.\n", + "We have chosen a 2 by 2 block of elements, each consisting of 4 by 4 ( = 16) lattice sites.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ddcb8f1", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestPottsBasedCellSimulationsTutorial\")\n", + "generator = chaste.mesh.PottsMeshGenerator2(50, 2, 4,\n", + " 50, 2, 4)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "83ed5d9d", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a vector of CellPtrs. To do this, we the CellsGenerator helper class,\n", + "which is templated over the type of cell model required and the dimension.\n", + "We create an empty vector of cells and pass this into the method along with the mesh.\n", + "The second argument represents the size of that the vector cells should become - one cell for each element.\n", + "Third argument makes all cells proliferate.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e8b891c", + "metadata": {}, + "outputs": [], + "source": [ + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasic(mesh.GetNumElements())" + ] + }, + { + "cell_type": "markdown", + "id": "e056ad92", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", + "In general, this class associates a collection of cells with a mesh. For this test, because we have a PottsMesh,\n", + "we use a particular type of cell population called a PottsBasedCellPopulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c23592f7", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.PottsBasedCellPopulation2(mesh,\n", + " cells)" + ] + }, + { + "cell_type": "markdown", + "id": "6d71cf2c", + "metadata": {}, + "source": [ + "We can set the \"Temperature\" to be used in the Potts Simulation using the optional command below. The default value is 0.1.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c989327e", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.SetTemperature(0.1)" + ] + }, + { + "cell_type": "markdown", + "id": "9113a155", + "metadata": {}, + "source": [ + "By default the Potts simulation will make 1 sweep over the whole domain per timestep.\n", + "To use a different number of sweeps per timestep use the command.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8289feeb", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.SetNumSweepsPerTimestep(1)" + ] + }, + { + "cell_type": "markdown", + "id": "99e056fc", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7db9fc5b", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "scene.GetCellPopulationActorGenerator().SetShowPottsMeshEdges(True)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "528e59be", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d750ce2", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OnLatticeSimulation2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestPottsBasedCellSimulationsTutorial\")\n", + "simulator.SetEndTime(50.0)" + ] + }, + { + "cell_type": "markdown", + "id": "e4d5c4aa", + "metadata": {}, + "source": [ + "The default timestep is 0.1, but can be changed using the below command. The timestep is used in conjunction with the \"Temperature\"\n", + "and number of sweeps per timestep to specify the relationship between cell movement and proliferation.\n", + "We also set the simulation to only output every 10 steps i.e. once per hour.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d507968", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.SetDt(0.1)\n", + "simulator.SetSamplingTimestepMultiple(10)" + ] + }, + { + "cell_type": "markdown", + "id": "2156ab5f", + "metadata": {}, + "source": [ + "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", + "For this test, we use two update rules based upon a volume constraint (VolumeConstraintPottsUpdateRule)\n", + "and adhesion between cells (AdhesionPottsUpdateRule) and pass them to the OnLatticeSimulation.\n", + "For a list of possible update rules see subclasses of AbstractPottsUpdateRule.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5695e258", + "metadata": {}, + "outputs": [], + "source": [ + "volume_constraint_update_rule = chaste.cell_based.VolumeConstraintPottsUpdateRule2()" + ] + }, + { + "cell_type": "markdown", + "id": "e61aafb8", + "metadata": {}, + "source": [ + "Set an appropriate target volume in number of lattice sites. Here we use the default value of 16 lattice sites.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92e25726", + "metadata": {}, + "outputs": [], + "source": [ + "volume_constraint_update_rule.SetMatureCellTargetVolume(16)" + ] + }, + { + "cell_type": "markdown", + "id": "276fcdbd", + "metadata": {}, + "source": [ + "You can also vary the deformation energy parameter.\n", + "The larger the parameter the more cells will try to maintain target volume. Here we use the default value of 0.2.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bddcb2b8", + "metadata": {}, + "outputs": [], + "source": [ + "volume_constraint_update_rule.SetDeformationEnergyParameter(0.2)" + ] + }, + { + "cell_type": "markdown", + "id": "f26aad41", + "metadata": {}, + "source": [ + "Finally we add the update rule to the simulator.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91deabd8", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.AddUpdateRule(volume_constraint_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "e8177fd5", + "metadata": {}, + "source": [ + "We repeat the process for any other update rules.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e78fe9c8", + "metadata": {}, + "outputs": [], + "source": [ + "adhesion_update_rule = chaste.cell_based.AdhesionPottsUpdateRule2()\n", + "simulator.AddUpdateRule(adhesion_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "280b6408", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ba7bdda", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "a7a40e12", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee54db29", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()" + ] + }, + { + "cell_type": "markdown", + "id": "2631a8d8", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9aedfa4f", + "metadata": {}, + "outputs": [], + "source": [ + " 50.0, 6)\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "8f0fb47a", + "metadata": {}, + "source": [ + "## Test 2 - Cell sorting\n", + "The next test generates a collection of cells, there are two types of cells, labelled ones and non labelled ones,\n", + "there is differential adhesion between the cell types. For the parameters specified, the cells sort into separate types.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b02e3c2", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "a5933986", + "metadata": {}, + "source": [ + "First, we generate a Potts mesh. To create a PottsMesh, we can use the PottsMeshGenerator.\n", + "This generates a regular square-shaped mesh, in which all elements are the same size.\n", + "We have chosen an 8 by 8 block of elements each consisting of 4 by 4 ( = 16) lattice sites.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fbd8e4a", + "metadata": {}, + "outputs": [], + "source": [ + "generator = chaste.mesh.PottsMeshGenerator2(50, 8, 4,\n", + " 50, 8, 4)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "415bd93e", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a VectorSharedPtrCells. To do this, we the CellsGenerator helper class,\n", + "as before but this time the third argument is set to make all cells non-proliferative.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57803d88", + "metadata": {}, + "outputs": [], + "source": [ + "differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(),\n", + " differentiated_type)" + ] + }, + { + "cell_type": "markdown", + "id": "60e6297b", + "metadata": {}, + "source": [ + "Before we make a CellPopulation we make a cell label and then assign this label to some randomly chosen cells.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d197149c", + "metadata": {}, + "outputs": [], + "source": [ + "label = chaste.cell_based.CellLabel()\n", + "for eachCell in cells:\n", + " if(chaste.core.RandomNumberGenerator.Instance().ranf() < 0.5):\n", + " eachCell.AddCellProperty(label)" + ] + }, + { + "cell_type": "markdown", + "id": "1444786a", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92b3b708", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.PottsBasedCellPopulation2(mesh,\n", + " cells)" + ] + }, + { + "cell_type": "markdown", + "id": "02b97221", + "metadata": {}, + "source": [ + "In order to visualize labelled cells we need to use the following command.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0577431b", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.AddCellWriterCellLabelWriter()" + ] + }, + { + "cell_type": "markdown", + "id": "a280deb7", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37dce360", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OnLatticeSimulation2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestPottsBasedCellSorting\")\n", + "simulator.SetEndTime(20.0)\n", + "simulator.SetSamplingTimestepMultiple(10)" + ] + }, + { + "cell_type": "markdown", + "id": "55f2ef5e", + "metadata": {}, + "source": [ + "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", + "For this test, we use two update rules based upon a volume constraint (VolumeConstraintPottsUpdateRule) and\n", + "differential adhesion between cells (DifferentialAdhesionPottsUpdateRule), set appropriate parameters, and\n", + "pass them to the OnLatticeSimulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98da52bc", + "metadata": {}, + "outputs": [], + "source": [ + "volume_constraint_update_rule = chaste.cell_based.VolumeConstraintPottsUpdateRule2()\n", + "volume_constraint_update_rule.SetMatureCellTargetVolume(16)\n", + "volume_constraint_update_rule.SetDeformationEnergyParameter(0.2)\n", + "simulator.AddUpdateRule(volume_constraint_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "1e372374", + "metadata": {}, + "source": [ + "We repeat the process for any other update rules.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c1e84b4", + "metadata": {}, + "outputs": [], + "source": [ + "differential_adhesion_update_rule = chaste.cell_based.DifferentialAdhesionPottsUpdateRule2()\n", + "differential_adhesion_update_rule.SetLabelledCellLabelledCellAdhesionEnergyParameter(0.16)\n", + "differential_adhesion_update_rule.SetLabelledCellCellAdhesionEnergyParameter(0.11)\n", + "differential_adhesion_update_rule.SetCellCellAdhesionEnergyParameter(0.02)\n", + "differential_adhesion_update_rule.SetLabelledCellBoundaryAdhesionEnergyParameter(0.16)\n", + "differential_adhesion_update_rule.SetCellBoundaryAdhesionEnergyParameter(0.16)\n", + "simulator.AddUpdateRule(differential_adhesion_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "6c275247", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37549cdb", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.Solve()" + ] + }, + { + "cell_type": "markdown", + "id": "9e41d672", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "169a61f8", + "metadata": {}, + "outputs": [], + "source": [ + " 20.0, 6)\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "b7e6cb90", + "metadata": {}, + "source": [ + "## Test 3 - 3D Cell Sorting\n", + "The next test extends the previous example to three dimensions.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "782c9629", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "bc1b2f05", + "metadata": {}, + "source": [ + "First, we generate a Potts mesh. To create a PottsMesh, we can use the PottsMeshGenerator.\n", + "This generates a regular square-shaped mesh, in which all elements are the same size.\n", + "Here the first three arguments specify the domain width; the number of elements across; and the width of elements.\n", + "The second set of three arguments specify the domain height; the number of elements up; and the height of individual elements.\n", + "The third set of three arguments specify the domain depth; the number of elements deep; and the depth of individual elements.\n", + "We have chosen an 4 by 4 by 4 ( = 64) block of elements each consisting of 2 by 2 by 2 ( = 8) lattice sites.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e099ae2", + "metadata": {}, + "outputs": [], + "source": [ + "generator = chaste.mesh.PottsMeshGenerator3(10, 4, 2,\n", + " 10, 4, 2,\n", + " 10, 4, 2)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "2a93a3f2", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a VectorSharedPtrCells. To do this, we the CellsGenerator helper class,\n", + "as before but this time the third argument is set to make all cells non-proliferative.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b59f72b", + "metadata": {}, + "outputs": [], + "source": [ + "differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformCellCycleModel_3()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(),\n", + " differentiated_type)" + ] + }, + { + "cell_type": "markdown", + "id": "56e31deb", + "metadata": {}, + "source": [ + "As for the 2D case before we make a CellPopulation we make a pointer to a cell label and then assign this label to some randomly chosen cells.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78d8845c", + "metadata": {}, + "outputs": [], + "source": [ + "label = chaste.cell_based.CellLabel()\n", + "for eachCell in cells:\n", + " if(chaste.core.RandomNumberGenerator.Instance().ranf() < 0.5):\n", + " eachCell.AddCellProperty(label)" + ] + }, + { + "cell_type": "markdown", + "id": "26a025de", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96bf7ba5", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.PottsBasedCellPopulation3(mesh,\n", + " cells)" + ] + }, + { + "cell_type": "markdown", + "id": "97beee30", + "metadata": {}, + "source": [ + "In order to visualize labelled cells we need to use the following command.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e88cf66", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.AddCellWriterCellLabelWriter()" + ] + }, + { + "cell_type": "markdown", + "id": "e5e15bd2", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5707e277", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OnLatticeSimulation3(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestPottsBasedCellSorting3D\")\n", + "simulator.SetEndTime(20.0)\n", + "simulator.SetSamplingTimestepMultiple(10)" + ] + }, + { + "cell_type": "markdown", + "id": "16f312dd", + "metadata": {}, + "source": [ + "We must now create one or more update rules, which determine the Hamiltonian in the Potts simulation.\n", + "Now set the target volume to be appropriate for this 3D simulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "037e1d6b", + "metadata": {}, + "outputs": [], + "source": [ + "volume_constraint_update_rule = chaste.cell_based.VolumeConstraintPottsUpdateRule3()\n", + "volume_constraint_update_rule.SetMatureCellTargetVolume(8)\n", + "volume_constraint_update_rule.SetDeformationEnergyParameter(0.2)\n", + "simulator.AddUpdateRule(volume_constraint_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "6ce4b0a8", + "metadata": {}, + "source": [ + "We use the same differential adhesion parameters as in the 2D case.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e04b895", + "metadata": {}, + "outputs": [], + "source": [ + "differential_adhesion_update_rule = chaste.cell_based.DifferentialAdhesionPottsUpdateRule3()\n", + "differential_adhesion_update_rule.SetLabelledCellLabelledCellAdhesionEnergyParameter(0.16)\n", + "differential_adhesion_update_rule.SetLabelledCellCellAdhesionEnergyParameter(0.11)\n", + "differential_adhesion_update_rule.SetCellCellAdhesionEnergyParameter(0.02)\n", + "differential_adhesion_update_rule.SetLabelledCellBoundaryAdhesionEnergyParameter(0.16)\n", + "differential_adhesion_update_rule.SetCellBoundaryAdhesionEnergyParameter(0.16)\n", + "simulator.AddUpdateRule(differential_adhesion_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "321efe1a", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f176a3bc", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.Solve()" + ] + }, + { + "cell_type": "markdown", + "id": "1274cc35", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81e55ee8", + "metadata": {}, + "outputs": [], + "source": [ + " 20.0, 6)\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestScratchAssayTutorial.ipynb b/doc/tutorials/TestScratchAssayTutorial.ipynb index 941be958..afc87683 100644 --- a/doc/tutorials/TestScratchAssayTutorial.ipynb +++ b/doc/tutorials/TestScratchAssayTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "57d70ef8", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestScratchAssayTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestScratchAssayTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "d2811228", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "1bfa3280", "metadata": {}, "source": [ "\n", @@ -41,6 +44,7 @@ { "cell_type": "code", "execution_count": null, + "id": "9a6d4b17", "metadata": {}, "outputs": [], "source": [ @@ -55,6 +59,7 @@ }, { "cell_type": "markdown", + "id": "929c20cd", "metadata": {}, "source": [ "## Test 1 - Scratch Assay\n", @@ -66,6 +71,7 @@ { "cell_type": "code", "execution_count": null, + "id": "adda7560", "metadata": {}, "outputs": [], "source": [ @@ -75,6 +81,7 @@ }, { "cell_type": "markdown", + "id": "b680daf4", "metadata": {}, "source": [ "Chaste is based on the concept of `Cells` and `Meshes`. 'Cells' do not store their position in space,\n", @@ -89,6 +96,7 @@ { "cell_type": "code", "execution_count": null, + "id": "f6343803", "metadata": {}, "outputs": [], "source": [ @@ -100,6 +108,7 @@ }, { "cell_type": "markdown", + "id": "07e82bd3", "metadata": {}, "source": [ "Note that we are using a `PottsMeshGenerator2` to set up the grid and we are setting some terms to 0. Chaste\n", @@ -119,6 +128,7 @@ { "cell_type": "code", "execution_count": null, + "id": "60cc6275", "metadata": {}, "outputs": [], "source": [ @@ -128,6 +138,7 @@ }, { "cell_type": "markdown", + "id": "9336ce99", "metadata": {}, "source": [ "We are not interested in cell cycling so we specialize the generator to NoCellCycleModel.\n", @@ -137,6 +148,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5aa3284c", "metadata": {}, "outputs": [], "source": [ @@ -145,6 +157,7 @@ }, { "cell_type": "markdown", + "id": "8837c17f", "metadata": {}, "source": [ "We want two sets of cells, starting on opposite sides of the mesh. We use `location_indices` to map cells onto\n", @@ -156,6 +169,7 @@ { "cell_type": "code", "execution_count": null, + "id": "743824ce", "metadata": {}, "outputs": [], "source": [ @@ -171,6 +185,7 @@ }, { "cell_type": "markdown", + "id": "b7b6348c", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", @@ -180,6 +195,7 @@ { "cell_type": "code", "execution_count": null, + "id": "dc362625", "metadata": {}, "outputs": [], "source": [ @@ -190,6 +206,7 @@ }, { "cell_type": "markdown", + "id": "b72ee65e", "metadata": {}, "source": [ "Next, we set up an `OffLatticeSimulation` which will manage the solver. We need to add some custom rules to\n", @@ -200,6 +217,7 @@ { "cell_type": "code", "execution_count": null, + "id": "b02679a1", "metadata": {}, "outputs": [], "source": [ @@ -212,6 +230,7 @@ }, { "cell_type": "markdown", + "id": "f62ea6f9", "metadata": {}, "source": [ "We must now create a rule for cell migration. We will use an existing diffusion type rule.\n", @@ -221,6 +240,7 @@ { "cell_type": "code", "execution_count": null, + "id": "a3436590", "metadata": {}, "outputs": [], "source": [ @@ -230,6 +250,7 @@ }, { "cell_type": "markdown", + "id": "94d375c8", "metadata": {}, "source": [ "PyChaste can do simple 3D rendering with VTK. We set up a `VtkScene` so that we can see the population\n", @@ -240,6 +261,7 @@ { "cell_type": "code", "execution_count": null, + "id": "aace3b92", "metadata": {}, "outputs": [], "source": [ @@ -252,6 +274,7 @@ }, { "cell_type": "markdown", + "id": "9af898ef", "metadata": {}, "source": [ "We add the scene to the simulation for real-time updating using a `VtkSceneModifier`. Such\n", @@ -264,6 +287,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7db25cdf", "metadata": {}, "outputs": [], "source": [ @@ -275,6 +299,7 @@ }, { "cell_type": "markdown", + "id": "31ed5688", "metadata": {}, "source": [ "Chaste and PyChaste use object oriented programming. This may require some background reading,\n", @@ -290,6 +315,7 @@ { "cell_type": "code", "execution_count": null, + "id": "c7c43e8e", "metadata": {}, "outputs": [], "source": [ @@ -336,6 +362,7 @@ }, { "cell_type": "markdown", + "id": "77624148", "metadata": {}, "source": [ "To run the simulation, we call `Solve()` and optionally set up interactive plotting. We will see the cells\n", @@ -346,6 +373,7 @@ { "cell_type": "code", "execution_count": null, + "id": "a1747014", "metadata": {}, "outputs": [], "source": [ @@ -360,5 +388,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestScratchAssayTutorial.md b/doc/tutorials/TestScratchAssayTutorial.md index 8e252622..ad6c0727 100644 --- a/doc/tutorials/TestScratchAssayTutorial.md +++ b/doc/tutorials/TestScratchAssayTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Scratch Assay Tutorial +title : "Test Scratch Assay Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestScratchAssayTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestScratchAssayTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestScratchAssayTutorial.py . Note that the code is given in full at the bottom of the page. diff --git a/doc/tutorials/TestScratchAssayTutorial.nbconvert.ipynb b/doc/tutorials/TestScratchAssayTutorial.nbconvert.ipynb new file mode 100644 index 00000000..afc87683 --- /dev/null +++ b/doc/tutorials/TestScratchAssayTutorial.nbconvert.ipynb @@ -0,0 +1,392 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "57d70ef8", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestScratchAssayTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2811228", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "1bfa3280", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "This tutorial is an example of modelling a scratch assay using a simple cellular automaton\n", + "representation of cells. It will cover the following techniques:\n", + "\n", + " * Setting up a regular mesh (or lattice)\n", + " * Visualizing the mesh\n", + " * Working with file-based output\n", + " * Generating cells and adding them to the mesh\n", + " * Simulating cell migration on the mesh\n", + " * Real-time visualization of the cell population and plotting of population statistics\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a6d4b17", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt # Plotting\n", + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "chaste.init() # Set up MPI\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.visualization # Visualization tools" + ] + }, + { + "cell_type": "markdown", + "id": "929c20cd", + "metadata": {}, + "source": [ + "## Test 1 - Scratch Assay\n", + "In this test we will create a scratch along the middle of a domain and quantify the migration\n", + "of cells into the region. Cells will migrate by random walk on the their regular mesh (lattice).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "adda7560", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "b680daf4", + "metadata": {}, + "source": [ + "Chaste is based on the concept of `Cells` and `Meshes`. 'Cells' do not store their position in space,\n", + "or connectivity, these are managed by a `Mesh`. The first step in most Chaste simulations is to\n", + "set up a mesh, on which we can locate cells. A collection of `Cells` and a `Mesh` are a `CellPopulation`\n", + "in Chaste terminology. The most simple `CellPopulation` is the `CaBasedCellPopulation` which corresponds\n", + "to cells occupying discrete locations on a regular mesh (lattice). Our first step is to set up the mesh.\n", + "Here we set up a 2D lattice.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6343803", + "metadata": {}, + "outputs": [], + "source": [ + "num_points_in_x = 100\n", + "num_points_in_y = 12\n", + "generator = chaste.mesh.PottsMeshGenerator2(num_points_in_x, 0, 0, num_points_in_y, 0, 0)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "07e82bd3", + "metadata": {}, + "source": [ + "Note that we are using a `PottsMeshGenerator2` to set up the grid and we are setting some terms to 0. Chaste\n", + "design is based on re-use of components, the `PottsMeshGenerator` can be used to set up other types of\n", + "cell population which require these extra terms. Note also the '2' at the end of the class name. This\n", + "tells us that we are working in 2D. Most Chaste classes are specialized (templated) for spatial dimension,\n", + "so we need to make sure we are consistent in the dimensionality of the classes we are using.\n", + "\n", + "Next we set up some cells. We create and empty container `VectorSharedPtrCell` (which will behave like a Python list)\n", + "and will fill it with cells of our chosen type. In Chaste cells can be assinged a number of proliferative types\n", + "(Default, Differentiated, Stem, Transit or User Defined). These types will define how cells behave in certain\n", + "simulations, for example whether they will proliferate. We just want our cells to migrate in this example, so\n", + "we set a DifferentiatedCellProliferativeType.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60cc6275", + "metadata": {}, + "outputs": [], + "source": [ + "cells = []\n", + "differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType()" + ] + }, + { + "cell_type": "markdown", + "id": "9336ce99", + "metadata": {}, + "source": [ + "We are not interested in cell cycling so we specialize the generator to NoCellCycleModel.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5aa3284c", + "metadata": {}, + "outputs": [], + "source": [ + "cell_generator = chaste.cell_based.CellsGeneratorNoCellCycleModel_2()" + ] + }, + { + "cell_type": "markdown", + "id": "8837c17f", + "metadata": {}, + "source": [ + "We want two sets of cells, starting on opposite sides of the mesh. We use `location_indices` to map cells onto\n", + "locations (or Nodes) on the mesh. For our regular mesh the Node indices increase fastest in x, then y. We will\n", + "add four layers of cells to each side of the mesh.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "743824ce", + "metadata": {}, + "outputs": [], + "source": [ + "num_cell_layers = 4\n", + "bottom_location_indices = list(range(num_cell_layers*num_points_in_x))\n", + "num_grid_points = num_points_in_x*num_points_in_y\n", + "top_location_indices = list(range(num_grid_points-1, num_grid_points -\n", + " num_cell_layers*num_points_in_x-1, -1))\n", + "cells = cell_generator.GenerateGivenLocationIndices(\n", + " bottom_location_indices + top_location_indices,\n", + " differentiated_type)" + ] + }, + { + "cell_type": "markdown", + "id": "b7b6348c", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc362625", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.CaBasedCellPopulation2(mesh, cells,\n", + " bottom_location_indices +\n", + " top_location_indices)" + ] + }, + { + "cell_type": "markdown", + "id": "b72ee65e", + "metadata": {}, + "source": [ + "Next, we set up an `OffLatticeSimulation` which will manage the solver. We need to add some custom rules to\n", + "this solver to specify how we want the cells to migrate.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b02679a1", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OnLatticeSimulation2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestScratchAssayTutorial\")\n", + "simulator.SetEndTime(10.0)\n", + "simulator.SetDt(0.1)\n", + "simulator.SetSamplingTimestepMultiple(1)" + ] + }, + { + "cell_type": "markdown", + "id": "f62ea6f9", + "metadata": {}, + "source": [ + "We must now create a rule for cell migration. We will use an existing diffusion type rule.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3436590", + "metadata": {}, + "outputs": [], + "source": [ + "diffusion_update_rule = chaste.cell_based.DiffusionCaUpdateRule2()\n", + "simulator.AddUpdateRule(diffusion_update_rule)" + ] + }, + { + "cell_type": "markdown", + "id": "94d375c8", + "metadata": {}, + "source": [ + "PyChaste can do simple 3D rendering with VTK. We set up a `VtkScene` so that we can see the population\n", + "evovle in real time.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aace3b92", + "metadata": {}, + "outputs": [], + "source": [ + "scene= chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "scene.GetCellPopulationActorGenerator().SetShowCellCentres(True)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "9af898ef", + "metadata": {}, + "source": [ + "We add the scene to the simulation for real-time updating using a `VtkSceneModifier`. Such\n", + "modifiers are called by the simulator at regular periods during the main time loop and\n", + "have access to the cell population. We will use a similar idea in a moment to record cell\n", + "positions for real time plotting.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7db25cdf", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(10)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "31ed5688", + "metadata": {}, + "source": [ + "Chaste and PyChaste use object oriented programming. This may require some background reading,\n", + "but allows for great flexibility in terms of modifying existing functionality. In\n", + "order to pull the data we want out of the simulation as it runs we will create our own\n", + "simulation modifier class and use it for real time plotting. This Python class over-rides\n", + "one of the built-in classes, giving us access to the quantities we want during the simulation.\n", + "Usually we would define such a class in a different module and import it, it is placed\n", + "here for the purposes of the tutorial.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7c43e8e", + "metadata": {}, + "outputs": [], + "source": [ + "class PlottingModifier(chaste.cell_based.PythonSimulationModifier2):\n", + " \"\"\" Class for real time plotting of cell numbers using Matplotlib\n", + " \"\"\"\n", + " def __init__(self, num_points_in_x, num_points_in_y):\n", + " super(PlottingModifier, self).__init__()\n", + " # Set up a figure for plotting\n", + " plt.ioff()\n", + " self.fig = plt.figure()\n", + " self.fig.ax = self.fig.add_subplot(111)\n", + " self.fig.ax.set_xlabel(\"y - Position (Cell Lengths)\")\n", + " self.fig.ax.set_ylabel(\"Number Of Cells\")\n", + " self.plot_frequency = 10 # only plot every 10 steps\n", + " self.num_points_in_x = num_points_in_x\n", + " self.num_points_in_y = num_points_in_y\n", + " def UpdateAtEndOfTimeStep(self, cell_population):\n", + " \"\"\" Plot the number of cells at each lattice point and time-point\n", + " Use the SimulationTime singleton to determine when to plot.\n", + " \"\"\"\n", + " num_increments = chaste.cell_based.SimulationTime.Instance().GetTimeStepsElapsed()\n", + " if num_increments % self.plot_frequency == 0:\n", + " y_locations = np.linspace(0, num_points_in_y, num_points_in_y)\n", + " num_cells = []\n", + " for idx in range(num_points_in_y):\n", + " counter = 0\n", + " for jdx in range(num_points_in_x):\n", + " if cell_population.IsCellAttachedToLocationIndex(jdx +\n", + " idx*num_points_in_x):\n", + " counter +=1\n", + " num_cells.append(counter)\n", + " self.fig.ax.plot(y_locations, num_cells, color='black')\n", + " self.fig.canvas.draw()\n", + " #display.display(self.fig)\n", + " #display.clear_output(wait=True)\n", + " def SetupSolve(self, cell_population, output_directory):\n", + " \"\"\" Ensure the cell population is in the correct state at the start of the simulation\n", + " \"\"\"\n", + " cell_population.Update()\n", + "plotting_modifier = PlottingModifier(num_points_in_x, num_points_in_y)\n", + "simulator.AddSimulationModifier(plotting_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "77624148", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()` and optionally set up interactive plotting. We will see the cells\n", + "migrate and the population distribution gradually become more uniform.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1747014", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "plt.ion()\n", + "plt.show()\n", + "simulator.Solve()\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestSpheroidTutorial.ipynb b/doc/tutorials/TestSpheroidTutorial.ipynb index d1af2a8a..5a11ebfc 100644 --- a/doc/tutorials/TestSpheroidTutorial.ipynb +++ b/doc/tutorials/TestSpheroidTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "235f3c80", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestSpheroidTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestSpheroidTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "9d938ef9", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "f8c85ede", "metadata": {}, "source": [ "\n", @@ -39,6 +42,7 @@ { "cell_type": "code", "execution_count": null, + "id": "fb52493e", "metadata": {}, "outputs": [], "source": [ @@ -54,6 +58,7 @@ }, { "cell_type": "markdown", + "id": "e855b4fc", "metadata": {}, "source": [ "## Test 1 - a 2D mesh-based spheroid\n", @@ -65,6 +70,7 @@ { "cell_type": "code", "execution_count": null, + "id": "eda7a4e9", "metadata": {}, "outputs": [], "source": [ @@ -74,6 +80,7 @@ }, { "cell_type": "markdown", + "id": "c626df14", "metadata": {}, "source": [ "This time we will use on off-lattice `MeshBased` cell population. Cell centres are joined with\n", @@ -90,6 +97,7 @@ { "cell_type": "code", "execution_count": null, + "id": "896a0d68", "metadata": {}, "outputs": [], "source": [ @@ -100,6 +108,7 @@ }, { "cell_type": "markdown", + "id": "36af7ad1", "metadata": {}, "source": [ "We create some cells next, with a stem-like proliferative type. This means they will continually\n", @@ -110,6 +119,7 @@ { "cell_type": "code", "execution_count": null, + "id": "c9188ddf", "metadata": {}, "outputs": [], "source": [ @@ -120,6 +130,7 @@ }, { "cell_type": "markdown", + "id": "2a04fdbb", "metadata": {}, "source": [ "Define when cells become apoptotic\n", @@ -129,6 +140,7 @@ { "cell_type": "code", "execution_count": null, + "id": "91b0f870", "metadata": {}, "outputs": [], "source": [ @@ -149,6 +161,7 @@ }, { "cell_type": "markdown", + "id": "5b5c16c3", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation` as before.\n", @@ -158,6 +171,7 @@ { "cell_type": "code", "execution_count": null, + "id": "6f448f12", "metadata": {}, "outputs": [], "source": [ @@ -166,6 +180,7 @@ }, { "cell_type": "markdown", + "id": "57b8ba00", "metadata": {}, "source": [ "To view the results of this and the next test in Paraview it is necessary to explicitly generate the required .vtu files.\n", @@ -175,6 +190,7 @@ { "cell_type": "code", "execution_count": null, + "id": "b03ee760", "metadata": {}, "outputs": [], "source": [ @@ -183,6 +199,7 @@ }, { "cell_type": "markdown", + "id": "d994af36", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time.\n", @@ -192,6 +209,7 @@ { "cell_type": "code", "execution_count": null, + "id": "bd18cf80", "metadata": {}, "outputs": [], "source": [ @@ -202,6 +220,7 @@ }, { "cell_type": "markdown", + "id": "c21d30ab", "metadata": {}, "source": [ "We ask for output every 12 increments\n", @@ -211,6 +230,7 @@ { "cell_type": "code", "execution_count": null, + "id": "1d1c3057", "metadata": {}, "outputs": [], "source": [ @@ -219,6 +239,7 @@ }, { "cell_type": "markdown", + "id": "25416a78", "metadata": {}, "source": [ "We define how the springs between cells behave using a force law.\n", @@ -228,6 +249,7 @@ { "cell_type": "code", "execution_count": null, + "id": "66025701", "metadata": {}, "outputs": [], "source": [ @@ -237,6 +259,7 @@ }, { "cell_type": "markdown", + "id": "e011d650", "metadata": {}, "source": [ "We set up a PDE for oxygen diffusion and consumption by cells, setting the rate of consumption to 0.1\n", @@ -246,6 +269,7 @@ { "cell_type": "code", "execution_count": null, + "id": "16a169b9", "metadata": {}, "outputs": [], "source": [ @@ -254,6 +278,7 @@ }, { "cell_type": "markdown", + "id": "be361fbf", "metadata": {}, "source": [ "We set a constant amount of oxygen on the edge of the spheroid\n", @@ -263,6 +288,7 @@ { "cell_type": "code", "execution_count": null, + "id": "86bac00d", "metadata": {}, "outputs": [], "source": [ @@ -272,6 +298,7 @@ }, { "cell_type": "markdown", + "id": "56e57a8e", "metadata": {}, "source": [ "Set up a pde modifier to solve the PDE at each simulation time step\n", @@ -281,6 +308,7 @@ { "cell_type": "code", "execution_count": null, + "id": "a0938fd2", "metadata": {}, "outputs": [], "source": [ @@ -290,6 +318,7 @@ }, { "cell_type": "markdown", + "id": "834cc15f", "metadata": {}, "source": [ "As before, we set up a scene modifier for real-time visualization\n", @@ -299,6 +328,7 @@ { "cell_type": "code", "execution_count": null, + "id": "846a01a5", "metadata": {}, "outputs": [], "source": [ @@ -317,6 +347,7 @@ }, { "cell_type": "markdown", + "id": "d850618f", "metadata": {}, "source": [ "Eventually remove apoptotic cells\n", @@ -326,6 +357,7 @@ { "cell_type": "code", "execution_count": null, + "id": "0557f3b9", "metadata": {}, "outputs": [], "source": [ @@ -335,6 +367,7 @@ }, { "cell_type": "markdown", + "id": "a126f1fc", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -344,6 +377,7 @@ { "cell_type": "code", "execution_count": null, + "id": "2f8db77e", "metadata": {}, "outputs": [], "source": [ @@ -355,6 +389,7 @@ }, { "cell_type": "markdown", + "id": "e20112d6", "metadata": {}, "source": [ "Full results can be visualized in Paraview from the `file_handler.GetOutputDirectoryFullPath()` directory.\n", @@ -364,5 +399,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestSpheroidTutorial.md b/doc/tutorials/TestSpheroidTutorial.md index dc0a7a1f..e3fa4b8e 100644 --- a/doc/tutorials/TestSpheroidTutorial.md +++ b/doc/tutorials/TestSpheroidTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Spheroid Tutorial +title : "Test Spheroid Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestSpheroidTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestSpheroidTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestSpheroidTutorial.py . Note that the code is given in full at the bottom of the page. diff --git a/doc/tutorials/TestSpheroidTutorial.nbconvert.ipynb b/doc/tutorials/TestSpheroidTutorial.nbconvert.ipynb new file mode 100644 index 00000000..5a11ebfc --- /dev/null +++ b/doc/tutorials/TestSpheroidTutorial.nbconvert.ipynb @@ -0,0 +1,403 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "235f3c80", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestSpheroidTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d938ef9", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "f8c85ede", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "This tutorial is an example of modelling spheroid growth with a nutrient.\n", + "It covers:\n", + " * Setting up an off-lattice cell population\n", + " * Setting up a cell cycle model with oxygen dependence\n", + " * Setting up and solving an oxygen transport PDE\n", + " * Setting up a cell killer\n", + " ## Imports and Setup\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb52493e", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt # Plotting\n", + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.pde # PDEs\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.visualization # Visualization tools\n", + "chaste.init() # Set up MPI" + ] + }, + { + "cell_type": "markdown", + "id": "e855b4fc", + "metadata": {}, + "source": [ + "## Test 1 - a 2D mesh-based spheroid\n", + "In this test we set up a spheroid with a plentiful supply of oxygen on the boundary and watch it grow\n", + "over time. Cells can gradually become apoptotic if the oxygen tension is too low.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eda7a4e9", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "c626df14", + "metadata": {}, + "source": [ + "This time we will use on off-lattice `MeshBased` cell population. Cell centres are joined with\n", + "springs with a Delauney Triangulation used to identify neighbours. Cell area is given by the dual\n", + "(Voronoi Tesselation). We start off with a small number of cells. We use a `MutableMesh` which\n", + "can change connectivity over time and a `HoneycombMeshGenerator` to set it up with a simple\n", + "honeycomb pattern. Here the first and second arguments define the size of the mesh -\n", + "we have chosen a mesh that is 5 nodes (i.e. cells) wide, and 5 nodes high. The extra '2' argument puts\n", + "two layers of non-cell elements around the mesh, which help to form a nicer voronoi tesselation\n", + "for area calculations.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "896a0d68", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestSpheroidTutorial\")\n", + "generator = chaste.mesh.HoneycombMeshGenerator(5, 5)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "36af7ad1", + "metadata": {}, + "source": [ + "We create some cells next, with a stem-like proliferative type. This means they will continually\n", + "proliferate if there is enough oxygen, similar to how a tumour spheroid may behave.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9188ddf", + "metadata": {}, + "outputs": [], + "source": [ + "stem_type = chaste.cell_based.StemCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorSimpleOxygenBasedCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumNodes(), stem_type)" + ] + }, + { + "cell_type": "markdown", + "id": "2a04fdbb", + "metadata": {}, + "source": [ + "Define when cells become apoptotic\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91b0f870", + "metadata": {}, + "outputs": [], + "source": [ + "for eachCell in cells:\n", + " cell_cycle_model = eachCell.GetCellCycleModel()\n", + " eachCell.GetCellData().SetItem(\"oxygen\", 30.0)\n", + " cell_cycle_model.SetDimension(2)\n", + " cell_cycle_model.SetStemCellG1Duration(4.0)\n", + " cell_cycle_model.SetHypoxicConcentration(0.1)\n", + " cell_cycle_model.SetQuiescentConcentration(0.3)\n", + " cell_cycle_model.SetCriticalHypoxicDuration(8)\n", + " g1_duration = cell_cycle_model.GetStemCellG1Duration()\n", + " sg2m_duration = cell_cycle_model.GetSG2MDuration()\n", + " rnum = chaste.core.RandomNumberGenerator.Instance().ranf()\n", + " birth_time = -rnum * (g1_duration + sg2m_duration)\n", + " eachCell.SetBirthTime(birth_time)" + ] + }, + { + "cell_type": "markdown", + "id": "5b5c16c3", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a `CellPopulation` as before.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f448f12", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.MeshBasedCellPopulation2_2(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "57b8ba00", + "metadata": {}, + "source": [ + "To view the results of this and the next test in Paraview it is necessary to explicitly generate the required .vtu files.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b03ee760", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population.AddPopulationWriterVoronoiDataWriter()" + ] + }, + { + "cell_type": "markdown", + "id": "d994af36", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory and end time.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd18cf80", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestSpheroidTutorial\")\n", + "simulator.SetEndTime(5.0)" + ] + }, + { + "cell_type": "markdown", + "id": "c21d30ab", + "metadata": {}, + "source": [ + "We ask for output every 12 increments\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d1c3057", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.SetSamplingTimestepMultiple(100)" + ] + }, + { + "cell_type": "markdown", + "id": "25416a78", + "metadata": {}, + "source": [ + "We define how the springs between cells behave using a force law.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66025701", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.GeneralisedLinearSpringForce2_2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "e011d650", + "metadata": {}, + "source": [ + "We set up a PDE for oxygen diffusion and consumption by cells, setting the rate of consumption to 0.1\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16a169b9", + "metadata": {}, + "outputs": [], + "source": [ + "pde = chaste.cell_based.CellwiseSourceEllipticPde2(cell_population, -0.5)" + ] + }, + { + "cell_type": "markdown", + "id": "be361fbf", + "metadata": {}, + "source": [ + "We set a constant amount of oxygen on the edge of the spheroid\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86bac00d", + "metadata": {}, + "outputs": [], + "source": [ + "bc = chaste.pde.ConstBoundaryCondition2(1.0)\n", + "is_neumann_bc = False" + ] + }, + { + "cell_type": "markdown", + "id": "56e57a8e", + "metadata": {}, + "source": [ + "Set up a pde modifier to solve the PDE at each simulation time step\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0938fd2", + "metadata": {}, + "outputs": [], + "source": [ + "#pde_modifier.SetDependentVariableName(\"oxygen\")\n", + "#simulator.AddSimulationModifier(pde_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "834cc15f", + "metadata": {}, + "source": [ + "As before, we set up a scene modifier for real-time visualization\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "846a01a5", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "scene.GetCellPopulationActorGenerator().SetColorByCellData(True)\n", + "scene.GetCellPopulationActorGenerator().SetDataLabel(\"oxygen\")\n", + "scene.GetCellPopulationActorGenerator().SetShowCellCentres(True)\n", + "scene.GetCellPopulationActorGenerator().SetShowVoronoiMeshEdges(False)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "d850618f", + "metadata": {}, + "source": [ + "Eventually remove apoptotic cells\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0557f3b9", + "metadata": {}, + "outputs": [], + "source": [ + "killer = chaste.cell_based.ApoptoticCellKiller2(cell_population)\n", + "simulator.AddCellKiller(killer)" + ] + }, + { + "cell_type": "markdown", + "id": "a126f1fc", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f8db77e", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "e20112d6", + "metadata": {}, + "source": [ + "Full results can be visualized in Paraview from the `file_handler.GetOutputDirectoryFullPath()` directory.\n", + "\n" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestTensileTestTutorial.ipynb b/doc/tutorials/TestTensileTestTutorial.ipynb index db569757..535d17a3 100644 --- a/doc/tutorials/TestTensileTestTutorial.ipynb +++ b/doc/tutorials/TestTensileTestTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "58e6d7e5", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestTensileTestTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestTensileTestTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "6997f647", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "9b512385", "metadata": {}, "source": [ "\n", @@ -39,6 +42,7 @@ { "cell_type": "code", "execution_count": null, + "id": "56881166", "metadata": {}, "outputs": [], "source": [ @@ -52,6 +56,7 @@ }, { "cell_type": "markdown", + "id": "fdbae083", "metadata": {}, "source": [ "## Test 1 - A 2d test\n", @@ -61,6 +66,7 @@ { "cell_type": "code", "execution_count": null, + "id": "24523789", "metadata": {}, "outputs": [], "source": [ @@ -70,6 +76,7 @@ }, { "cell_type": "markdown", + "id": "781d5a0f", "metadata": {}, "source": [ "First, we generate a vertex mesh using a HoneycombVertexMeshGenerator.\n", @@ -79,6 +86,7 @@ { "cell_type": "code", "execution_count": null, + "id": "21cdd368", "metadata": {}, "outputs": [], "source": [ @@ -88,6 +96,7 @@ }, { "cell_type": "markdown", + "id": "9e70f317", "metadata": {}, "source": [ "Now set up the cells, again we want to avoid proliferation.\n", @@ -97,17 +106,18 @@ { "cell_type": "code", "execution_count": null, + "id": "e68edf48", "metadata": {}, "outputs": [], "source": [ "differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType()\n", "cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()\n", - "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(),\n", - " differentiated_type)" + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), differentiated_type)" ] }, { "cell_type": "markdown", + "id": "12bf2d05", "metadata": {}, "source": [ "Next, create the cell population\n", @@ -117,6 +127,7 @@ { "cell_type": "code", "execution_count": null, + "id": "17215522", "metadata": {}, "outputs": [], "source": [ @@ -126,6 +137,7 @@ }, { "cell_type": "markdown", + "id": "52887441", "metadata": {}, "source": [ "Pass the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", @@ -135,6 +147,7 @@ { "cell_type": "code", "execution_count": null, + "id": "771fe9fb", "metadata": {}, "outputs": [], "source": [ @@ -146,6 +159,7 @@ }, { "cell_type": "markdown", + "id": "9d8f01d1", "metadata": {}, "source": [ "Now create a force law\n", @@ -155,6 +169,7 @@ { "cell_type": "code", "execution_count": null, + "id": "a46fcaf0", "metadata": {}, "outputs": [], "source": [ @@ -164,6 +179,7 @@ }, { "cell_type": "markdown", + "id": "d8653f57", "metadata": {}, "source": [ "A `NagaiHondaForce` assumes that each cell has a target area. The target areas of cells are used to determine\n", @@ -176,6 +192,7 @@ { "cell_type": "code", "execution_count": null, + "id": "2bda9089", "metadata": {}, "outputs": [], "source": [ @@ -185,6 +202,7 @@ }, { "cell_type": "markdown", + "id": "018cc1c1", "metadata": {}, "source": [ "For our tensile test we will fix the bottom of the sheet and subject the top to an applied displacement. We neglect\n", @@ -195,6 +213,7 @@ { "cell_type": "code", "execution_count": null, + "id": "e4515294", "metadata": {}, "outputs": [], "source": [ @@ -204,14 +223,13 @@ "simulator.AddCellPopulationBoundaryCondition(bc)\n", "point = np.array([0.0, 15.5])\n", "normal = np.array([0.0, -1.0])\n", - "bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population,\n", - " point,\n", - " normal)\n", + "bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, point, normal)\n", "simulator.AddCellPopulationBoundaryCondition(bc2)" ] }, { "cell_type": "markdown", + "id": "9d5263fb", "metadata": {}, "source": [ "We want to displace our top boundary over time. We could write a custom boundary condition class to do this.\n", @@ -223,6 +241,7 @@ { "cell_type": "code", "execution_count": null, + "id": "6424820f", "metadata": {}, "outputs": [], "source": [ @@ -251,6 +270,7 @@ }, { "cell_type": "markdown", + "id": "05a43849", "metadata": {}, "source": [ "PyChaste can do simple 3D rendering with VTK. We set up a `VtkScene` so that we can see the population\n", @@ -261,6 +281,7 @@ { "cell_type": "code", "execution_count": null, + "id": "814afac4", "metadata": {}, "outputs": [], "source": [ @@ -275,6 +296,7 @@ }, { "cell_type": "markdown", + "id": "4be588e8", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`.\n", @@ -284,6 +306,7 @@ { "cell_type": "code", "execution_count": null, + "id": "e22ba1a4", "metadata": {}, "outputs": [], "source": [ @@ -296,5 +319,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestTensileTestTutorial.md b/doc/tutorials/TestTensileTestTutorial.md index db67497d..cd17c550 100644 --- a/doc/tutorials/TestTensileTestTutorial.md +++ b/doc/tutorials/TestTensileTestTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Tensile Test Tutorial +title : "Test Tensile Test Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestTensileTestTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestTensileTestTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestTensileTestTutorial.py . Note that the code is given in full at the bottom of the page. @@ -49,8 +54,7 @@ Now set up the cells, again we want to avoid proliferation. ```python differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), - differentiated_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), differentiated_type) ``` Next, create the cell population @@ -96,9 +100,7 @@ fixing lateral degress of freedom for simplicity, since we are using an over-dam simulator.AddCellPopulationBoundaryCondition(bc) point = np.array([0.0, 15.5]) normal = np.array([0.0, -1.0]) - bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, - point, - normal) + bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, point, normal) simulator.AddCellPopulationBoundaryCondition(bc2) ``` @@ -193,8 +195,7 @@ class TestTensileTestTutorial(chaste.cell_based.AbstractCellBasedTestSuite): differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), - differentiated_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), differentiated_type) cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells) @@ -216,9 +217,7 @@ class TestTensileTestTutorial(chaste.cell_based.AbstractCellBasedTestSuite): simulator.AddCellPopulationBoundaryCondition(bc) point = np.array([0.0, 15.5]) normal = np.array([0.0, -1.0]) - bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, - point, - normal) + bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, point, normal) simulator.AddCellPopulationBoundaryCondition(bc2) class BoundaryConditionModifier(chaste.cell_based.PythonSimulationModifier2): diff --git a/doc/tutorials/TestTensileTestTutorial.nbconvert.ipynb b/doc/tutorials/TestTensileTestTutorial.nbconvert.ipynb new file mode 100644 index 00000000..535d17a3 --- /dev/null +++ b/doc/tutorials/TestTensileTestTutorial.nbconvert.ipynb @@ -0,0 +1,323 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "58e6d7e5", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestTensileTestTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6997f647", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "9b512385", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "In this tutorial we will demonstrate a simulated tensile test on an epithelial sheet. This test\n", + "demonstrates:\n", + " * Working with vertex based off lattice populations\n", + " * Applying boundary conditions\n", + " * Working with forces\n", + " \n", + "## The Test\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56881166", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.visualization # Visualization tools\n", + "chaste.init() # Set up MPI" + ] + }, + { + "cell_type": "markdown", + "id": "fdbae083", + "metadata": {}, + "source": [ + "## Test 1 - A 2d test\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24523789", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "781d5a0f", + "metadata": {}, + "source": [ + "First, we generate a vertex mesh using a HoneycombVertexMeshGenerator.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21cdd368", + "metadata": {}, + "outputs": [], + "source": [ + "generator = chaste.mesh.HoneycombVertexMeshGenerator(5, 15)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "9e70f317", + "metadata": {}, + "source": [ + "Now set up the cells, again we want to avoid proliferation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e68edf48", + "metadata": {}, + "outputs": [], + "source": [ + "differentiated_type = chaste.cell_based.DifferentiatedCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), differentiated_type)" + ] + }, + { + "cell_type": "markdown", + "id": "12bf2d05", + "metadata": {}, + "source": [ + "Next, create the cell population\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17215522", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh,\n", + " cells)" + ] + }, + { + "cell_type": "markdown", + "id": "52887441", + "metadata": {}, + "source": [ + "Pass the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "771fe9fb", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestTensileTest\")\n", + "simulator.SetEndTime(1.0)\n", + "simulator.SetSamplingTimestepMultiple(1000)" + ] + }, + { + "cell_type": "markdown", + "id": "9d8f01d1", + "metadata": {}, + "source": [ + "Now create a force law\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a46fcaf0", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.NagaiHondaForce2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "d8653f57", + "metadata": {}, + "source": [ + "A `NagaiHondaForce` assumes that each cell has a target area. The target areas of cells are used to determine\n", + "pressure forces on each vertex and eventually determine the size of each cell in the simulation.\n", + "In order to assign target areas to cells and update them in each time step we add a `SimpleTargetAreaModifier`\n", + "to the simulation, which inherits from `AbstractTargetAreaModifier`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2bda9089", + "metadata": {}, + "outputs": [], + "source": [ + "growth_modifier = chaste.cell_based.SimpleTargetAreaModifier2()\n", + "simulator.AddSimulationModifier(growth_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "018cc1c1", + "metadata": {}, + "source": [ + "For our tensile test we will fix the bottom of the sheet and subject the top to an applied displacement. We neglect\n", + "fixing lateral degress of freedom for simplicity, since we are using an over-damped mechanical model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4515294", + "metadata": {}, + "outputs": [], + "source": [ + "my_point = np.array([0.0, 0.0])\n", + "normal = np.array([0.0, -1.0])\n", + "bc = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, my_point, normal)\n", + "simulator.AddCellPopulationBoundaryCondition(bc)\n", + "point = np.array([0.0, 15.5])\n", + "normal = np.array([0.0, -1.0])\n", + "bc2 = chaste.cell_based.AttractingPlaneBoundaryCondition2_2(cell_population, point, normal)\n", + "simulator.AddCellPopulationBoundaryCondition(bc2)" + ] + }, + { + "cell_type": "markdown", + "id": "9d5263fb", + "metadata": {}, + "source": [ + "We want to displace our top boundary over time. We could write a custom boundary condition class to do this.\n", + "A more simple alternative is to modify the the position of the point describing our boundary plane in `bc2`\n", + "as the simulation progresses. As per earlier tutorials we make a new `SimulationModifier` class to do this.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6424820f", + "metadata": {}, + "outputs": [], + "source": [ + "class BoundaryConditionModifier(chaste.cell_based.PythonSimulationModifier2):\n", + " \"\"\" Class for time varying boundary conditions\n", + " \"\"\"\n", + " def __init__(self, boundary_condition):\n", + " self.boundary_condition = boundary_condition\n", + " self.original_location = boundary_condition.rGetPointOnPlane()\n", + " self.velocity = 0.5 # cell lengths per time\n", + " super(BoundaryConditionModifier, self).__init__()\n", + " def UpdateAtEndOfTimeStep(self, cell_population):\n", + " \"\"\" Move the boundary upwards at the specified velocity\n", + " \"\"\"\n", + " total_time = chaste.cell_based.SimulationTime.Instance().GetTime()\n", + " new_location = [self.original_location[0],\n", + " self.original_location[1] + self.velocity*total_time]\n", + " self.boundary_condition.SetPointOnPlane(np.array(new_location))\n", + " def SetupSolve(self, cell_population, output_directory):\n", + " \"\"\" Make sure the cell population is in the correct state at the start of the simulation\n", + " \"\"\"\n", + " cell_population.Update()\n", + "bc_modifier = BoundaryConditionModifier(bc2)\n", + "simulator.AddSimulationModifier(bc_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "05a43849", + "metadata": {}, + "source": [ + "PyChaste can do simple 3D rendering with VTK. We set up a `VtkScene` so that we can see the population\n", + "evovle in real time.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "814afac4", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(1000)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "4be588e8", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e22ba1a4", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.ipynb b/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.ipynb index 3bc310b3..f048dc5c 100644 --- a/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.ipynb +++ b/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.ipynb @@ -2,15 +2,17 @@ "cells": [ { "cell_type": "markdown", + "id": "ce381363", "metadata": {}, "source": [ - "This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestVertexBasedCellSimulationsPythonTutorial.py.\n", + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestVertexBasedCellSimulationsPythonTutorial.py.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "7ac165c0", "metadata": {}, "outputs": [], "source": [ @@ -22,6 +24,7 @@ }, { "cell_type": "markdown", + "id": "f797ee03", "metadata": {}, "source": [ "\n", @@ -37,6 +40,7 @@ { "cell_type": "code", "execution_count": null, + "id": "fdd5942d", "metadata": {}, "outputs": [], "source": [ @@ -51,6 +55,7 @@ }, { "cell_type": "markdown", + "id": "05adc24b", "metadata": {}, "source": [ "## Test 1 - A basic vertex-based simulation\n", @@ -62,6 +67,7 @@ { "cell_type": "code", "execution_count": null, + "id": "6aed13ce", "metadata": {}, "outputs": [], "source": [ @@ -71,6 +77,7 @@ }, { "cell_type": "markdown", + "id": "776ac8f8", "metadata": {}, "source": [ "First, we generate a vertex mesh. To create a MutableVertexMesh, we can use the HoneycombVertexMeshGenerator.\n", @@ -82,6 +89,7 @@ { "cell_type": "code", "execution_count": null, + "id": "41535320", "metadata": {}, "outputs": [], "source": [ @@ -92,6 +100,7 @@ }, { "cell_type": "markdown", + "id": "facdbabe", "metadata": {}, "source": [ "Having created a mesh, we now create a std::vector of CellPtrs. To do this, we use the CellsGenerator helper class,\n", @@ -105,17 +114,18 @@ { "cell_type": "code", "execution_count": null, + "id": "c04d0a3f", "metadata": {}, "outputs": [], "source": [ "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", "cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()\n", - "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(),\n", - " transit_type)" + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type)" ] }, { "cell_type": "markdown", + "id": "a0740e83", "metadata": {}, "source": [ "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", @@ -127,15 +137,16 @@ { "cell_type": "code", "execution_count": null, + "id": "1b603f65", "metadata": {}, "outputs": [], "source": [ - "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh,\n", - " cells)" + "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells)" ] }, { "cell_type": "markdown", + "id": "412e6f6c", "metadata": {}, "source": [ "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", @@ -145,6 +156,7 @@ { "cell_type": "code", "execution_count": null, + "id": "40c7e03a", "metadata": {}, "outputs": [], "source": [ @@ -156,6 +168,7 @@ }, { "cell_type": "markdown", + "id": "d8d4b9c2", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", @@ -165,6 +178,7 @@ { "cell_type": "code", "execution_count": null, + "id": "a0d75bbb", "metadata": {}, "outputs": [], "source": [ @@ -175,6 +189,7 @@ }, { "cell_type": "markdown", + "id": "6b9c2009", "metadata": {}, "source": [ "For longer simulations, we may not want to output the results every time step.\n", @@ -187,6 +202,7 @@ { "cell_type": "code", "execution_count": null, + "id": "2940206f", "metadata": {}, "outputs": [], "source": [ @@ -195,6 +211,7 @@ }, { "cell_type": "markdown", + "id": "7966a7f4", "metadata": {}, "source": [ "We must now create one or more force laws, which determine the mechanics of the vertices of each cell in a cell population.\n", @@ -208,6 +225,7 @@ { "cell_type": "code", "execution_count": null, + "id": "26e4644a", "metadata": {}, "outputs": [], "source": [ @@ -217,6 +235,7 @@ }, { "cell_type": "markdown", + "id": "00582593", "metadata": {}, "source": [ "A NagaiHondaForce assumes that each cell has a target area. The target areas of cells are used to determine\n", @@ -229,6 +248,7 @@ { "cell_type": "code", "execution_count": null, + "id": "fda8f3af", "metadata": {}, "outputs": [], "source": [ @@ -238,6 +258,7 @@ }, { "cell_type": "markdown", + "id": "05290bcb", "metadata": {}, "source": [ "Save snapshot images of the population during the simulation\n", @@ -247,6 +268,7 @@ { "cell_type": "code", "execution_count": null, + "id": "88684fe0", "metadata": {}, "outputs": [], "source": [ @@ -258,6 +280,7 @@ }, { "cell_type": "markdown", + "id": "39dd07cd", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", @@ -267,6 +290,7 @@ { "cell_type": "code", "execution_count": null, + "id": "4c1b7bcd", "metadata": {}, "outputs": [], "source": [ @@ -277,6 +301,7 @@ }, { "cell_type": "markdown", + "id": "5f4a930e", "metadata": {}, "source": [ "The next two lines are for test purposes only and are not part of this tutorial.\n", @@ -287,16 +312,17 @@ { "cell_type": "code", "execution_count": null, + "id": "94f90cd2", "metadata": {}, "outputs": [], "source": [ - " 5.0, 6)\n", "# Tear down the test \n", "chaste.cell_based.TearDownNotebookTest()" ] }, { "cell_type": "markdown", + "id": "77383ca3", "metadata": {}, "source": [ "## Test 2 - introducing periodicity, boundaries and cell killers\n", @@ -309,6 +335,7 @@ { "cell_type": "code", "execution_count": null, + "id": "41cef549", "metadata": {}, "outputs": [], "source": [ @@ -318,6 +345,7 @@ }, { "cell_type": "markdown", + "id": "fc605cc4", "metadata": {}, "source": [ "First, we generate a periodic vertex mesh. To create a Cylindrical2dVertexMesh, we can use the CylindricalHoneycombVertexMeshGenerator.\n", @@ -330,6 +358,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3efea02c", "metadata": {}, "outputs": [], "source": [ @@ -339,6 +368,7 @@ }, { "cell_type": "markdown", + "id": "af27d734", "metadata": {}, "source": [ "Having created a mesh, we now create a VectorSharedPtrCells. This is exactly the same as the above test.\n", @@ -348,17 +378,18 @@ { "cell_type": "code", "execution_count": null, + "id": "3caf01b6", "metadata": {}, "outputs": [], "source": [ "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", "cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()\n", - "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(),\n", - " transit_type)" + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type)" ] }, { "cell_type": "markdown", + "id": "9b6ecbd5", "metadata": {}, "source": [ "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.\n", @@ -368,15 +399,16 @@ { "cell_type": "code", "execution_count": null, + "id": "35beacb5", "metadata": {}, "outputs": [], "source": [ - "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh,\n", - " cells)" + "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells)" ] }, { "cell_type": "markdown", + "id": "15c0a487", "metadata": {}, "source": [ "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", @@ -386,6 +418,7 @@ { "cell_type": "code", "execution_count": null, + "id": "447ff9df", "metadata": {}, "outputs": [], "source": [ @@ -397,6 +430,7 @@ }, { "cell_type": "markdown", + "id": "9b7db67d", "metadata": {}, "source": [ "We now make a pointer to an appropriate force and pass it to the OffLatticeSimulation.\n", @@ -406,6 +440,7 @@ { "cell_type": "code", "execution_count": null, + "id": "2ad5f991", "metadata": {}, "outputs": [], "source": [ @@ -415,6 +450,7 @@ }, { "cell_type": "markdown", + "id": "a4989fa0", "metadata": {}, "source": [ "We also make a pointer to the target area modifier and add it to the simulator.\n", @@ -424,6 +460,7 @@ { "cell_type": "code", "execution_count": null, + "id": "31eab391", "metadata": {}, "outputs": [], "source": [ @@ -433,6 +470,7 @@ }, { "cell_type": "markdown", + "id": "f4e62725", "metadata": {}, "source": [ "We now create one or more CellPopulationBoundaryConditions, which determine any conditions which each cell in a cell population must satisfy.\n", @@ -447,6 +485,7 @@ { "cell_type": "code", "execution_count": null, + "id": "b98ee25b", "metadata": {}, "outputs": [], "source": [ @@ -456,25 +495,26 @@ }, { "cell_type": "markdown", + "id": "b45c6346", "metadata": {}, "source": [ "We can now make a PlaneBoundaryCondition (passing the point and normal to the plane) and pass it to the OffLatticeSimulation.\n", - "bc = chaste.cell_based.PlaneBoundaryCondition2_2(cell_population,\n" + "bc = chaste.cell_based.PlaneBoundaryCondition2_2(cell_population, point, normal)\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "0ff6476a", "metadata": {}, "outputs": [], "source": [ - " point,\n", - " normal)\n", "simulator.AddCellPopulationBoundaryCondition(bc)" ] }, { "cell_type": "markdown", + "id": "1c562b7d", "metadata": {}, "source": [ "We now create one or more CellKillers, which determine how cells are removed from the simulation.\n", @@ -487,6 +527,7 @@ { "cell_type": "code", "execution_count": null, + "id": "5f9c419c", "metadata": {}, "outputs": [], "source": [ @@ -496,45 +537,31 @@ }, { "cell_type": "markdown", + "id": "ab554989", "metadata": {}, "source": [ "Finally we now make a PlaneBasedCellKiller (passing the point and normal to the plane) and pass it to the OffLatticeSimulation.\n", - "\n" + "killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population, point, normal)\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "d2747096", "metadata": {}, "outputs": [], "source": [ - "killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population,\n", - " point,\n", - " normal)\n", "simulator.AddCellKiller(killer)" ] }, { "cell_type": "markdown", + "id": "7bd62315", "metadata": {}, "source": [ "To run the simulation, we call `Solve()`.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "simulator.Solve()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ + "simulator.Solve()\n", + "\n", "The next two lines are for test purposes only and are not part of this tutorial.\n", "If different simulation input parameters are being explored the lines should be removed.\n", "\n" @@ -543,10 +570,10 @@ { "cell_type": "code", "execution_count": null, + "id": "5c194b6b", "metadata": {}, "outputs": [], "source": [ - " 1.0, 6)\n", "# Tear down the test \n", "chaste.cell_based.TearDownNotebookTest()" ] @@ -554,5 +581,5 @@ ], "metadata": {}, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 5 } diff --git a/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.md b/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.md index d1e43d30..69459502 100644 --- a/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.md +++ b/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.md @@ -1,9 +1,14 @@ + --- -layout: page-full-width -title: Test Vertex Based Cell Simulations Python Tutorial +title : "Test Vertex Based Cell Simulations Python Tutorial" +summary: "" +draft: false +images: [] +toc: true +layout: "single" --- -This tutorial is automatically generated from the file test/python/cell_based/tutorials/TestVertexBasedCellSimulationsPythonTutorial.py. -[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/TestVertexBasedCellSimulationsPythonTutorial_nb.html) + +This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestVertexBasedCellSimulationsPythonTutorial.py . Note that the code is given in full at the bottom of the page. @@ -56,8 +61,7 @@ the third argument specifies the proliferative type of the cell. ```python transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type) ``` Now we have a mesh and a set of cells to go with it, we can create a CellPopulation. @@ -65,8 +69,7 @@ In general, this class associates a collection of cells with a mesh. For this te we use a particular type of cell population called a VertexBasedCellPopulation. ```python - cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, - cells) + 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. @@ -138,8 +141,7 @@ If different simulation input parameters are being explored the lines should be ```python self.assertEqual(cell_population.GetNumRealCells(), 7) - self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), - 5.0, 6) + self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), 5.0, 6) # JUPYTER_TEARDOWN @@ -170,15 +172,13 @@ Having created a mesh, we now create a VectorSharedPtrCells. This is exactly the ```python transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), - transit_type) + cells = cell_generator.GenerateBasicRandom(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. ```python - cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, - cells) + 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 @@ -217,10 +217,8 @@ The first step is to define a point on the plane boundary and a normal to the pl ``` We can now make a PlaneBoundaryCondition (passing the point and normal to the plane) and pass it to the OffLatticeSimulation. -bc = chaste.cell_based.PlaneBoundaryCondition2_2(cell_population, +bc = chaste.cell_based.PlaneBoundaryCondition2_2(cell_population, point, normal) ```python - point, - normal) simulator.AddCellPopulationBoundaryCondition(bc) ``` @@ -235,27 +233,20 @@ The first step is to define a point on the plane boundary and a normal to the pl ``` Finally we now make a PlaneBasedCellKiller (passing the point and normal to the plane) and pass it to the OffLatticeSimulation. - +killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population, point, normal) ```python - killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population, - point, - normal) simulator.AddCellKiller(killer) ``` To run the simulation, we call `Solve()`. +simulator.Solve() -```python - 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. ```python self.assertEqual(cell_population.GetNumRealCells(), 12) - self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), - 1.0, 6) + self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), 1.0, 6) # JUPYTER_TEARDOWN @@ -292,11 +283,9 @@ class TestRunningVertexBasedSimulationsTutorial(chaste.cell_based.AbstractCellBa transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type) - cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, - cells) + cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells) scene = chaste.visualization.VtkScene2() scene.SetCellPopulation(cell_population) @@ -325,8 +314,7 @@ class TestRunningVertexBasedSimulationsTutorial(chaste.cell_based.AbstractCellBa scene.End() self.assertEqual(cell_population.GetNumRealCells(), 7) - self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), - 5.0, 6) + self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), 5.0, 6) # JUPYTER_TEARDOWN @@ -339,11 +327,9 @@ class TestRunningVertexBasedSimulationsTutorial(chaste.cell_based.AbstractCellBa transit_type = chaste.cell_based.TransitCellProliferativeType() cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2() - cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), - transit_type) + cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type) - cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, - cells) + cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells) simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population) simulator.SetOutputDirectory("Python/TestPeriodicVertexBasedCellPopulation") @@ -359,23 +345,15 @@ class TestRunningVertexBasedSimulationsTutorial(chaste.cell_based.AbstractCellBa point = np.array([0.0, 0.0]) normal = np.array([0.0, -1.0]) - point, - normal) simulator.AddCellPopulationBoundaryCondition(bc) point = np.array([0.0, 3.0]) normal = np.array([0.0, 1.0]) - killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population, - point, - normal) simulator.AddCellKiller(killer) - simulator.Solve() - self.assertEqual(cell_population.GetNumRealCells(), 12) - self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), - 1.0, 6) + self.assertAlmostEqual(chaste.cell_based.SimulationTime.Instance().GetTime(), 1.0, 6) # JUPYTER_TEARDOWN diff --git a/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.nbconvert.ipynb b/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.nbconvert.ipynb new file mode 100644 index 00000000..f048dc5c --- /dev/null +++ b/doc/tutorials/TestVertexBasedCellSimulationsPythonTutorial.nbconvert.ipynb @@ -0,0 +1,585 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ce381363", + "metadata": {}, + "source": [ + "This tutorial is automatically generated from the file ../test/python/cell_based/tutorials/TestVertexBasedCellSimulationsPythonTutorial.py.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ac165c0", + "metadata": {}, + "outputs": [], + "source": [ + "# Jupyter notebook specific imports \n", + "import matplotlib as mpl \n", + "from IPython import display \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "f797ee03", + "metadata": {}, + "source": [ + "\n", + "# Introduction\n", + "In this tutorial we show how Chaste can be used to create, run and visualize vertex-based simulations.\n", + "Full details of the mechanical model proposed by T. Nagai and H. Honda (\"A dynamic cell model for the formation of epithelial tissues\",\n", + "Philosophical Magazine Part B 81:699-719).\n", + "\n", + "## The Test\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fdd5942d", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt # Plotting\n", + "import numpy as np # Matrix tools\n", + "import chaste # The PyChaste module\n", + "import chaste.cell_based # Contains cell populations\n", + "import chaste.mesh # Contains meshes\n", + "import chaste.visualization # Visualization tools\n", + "chaste.init() # Set up MPI" + ] + }, + { + "cell_type": "markdown", + "id": "05adc24b", + "metadata": {}, + "source": [ + "## Test 1 - A basic vertex-based simulation\n", + "In the first test, we run a simple vertex-based simulation, in which we create a monolayer of cells,\n", + "using a mutable vertex mesh. Each cell is assigned a stochastic cell-cycle model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6aed13ce", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "776ac8f8", + "metadata": {}, + "source": [ + "First, we generate a vertex mesh. To create a MutableVertexMesh, we can use the HoneycombVertexMeshGenerator.\n", + "This generates a honeycomb-shaped mesh, in which all nodes are equidistant. Here the first and second arguments\n", + "define the size of the mesh - we have chosen a mesh that is 2 elements (i.e. cells) wide, and 2 elements high.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41535320", + "metadata": {}, + "outputs": [], + "source": [ + "chaste.core.OutputFileHandler(\"Python/TestVertexBasedCellSimulationsTutorial\")\n", + "generator = chaste.mesh.HoneycombVertexMeshGenerator(2, 2)\n", + "mesh = generator.GetMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "facdbabe", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a std::vector of CellPtrs. To do this, we use the CellsGenerator helper class,\n", + "which is templated over the type of cell model required\n", + "and the dimension. We create an empty vector of cells and pass this into the method along with the mesh.\n", + "The second argument represents the size of that the vector cells should become - one cell for each element,\n", + "the third argument specifies the proliferative type of the cell.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c04d0a3f", + "metadata": {}, + "outputs": [], + "source": [ + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type)" + ] + }, + { + "cell_type": "markdown", + "id": "a0740e83", + "metadata": {}, + "source": [ + "Now we have a mesh and a set of cells to go with it, we can create a CellPopulation.\n", + "In general, this class associates a collection of cells with a mesh. For this test, because we have a MutableVertexMesh,\n", + "we use a particular type of cell population called a VertexBasedCellPopulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b603f65", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "412e6f6c", + "metadata": {}, + "source": [ + "We can set up a `VtkScene` to do a quick visualization of the population before running the analysis.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40c7e03a", + "metadata": {}, + "outputs": [], + "source": [ + "scene = chaste.visualization.VtkScene2()\n", + "scene.SetCellPopulation(cell_population)\n", + "nb_manager = chaste.visualization.JupyterNotebookManager()\n", + "nb_manager.vtk_show(scene, height=600)" + ] + }, + { + "cell_type": "markdown", + "id": "d8d4b9c2", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0d75bbb", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestVertexBasedCellSimulationsTutorial\")\n", + "simulator.SetEndTime(5.0)" + ] + }, + { + "cell_type": "markdown", + "id": "6b9c2009", + "metadata": {}, + "source": [ + "For longer simulations, we may not want to output the results every time step.\n", + "In this case we can use the following method, to print results every 50 time steps instead.\n", + "As the default time step used by the simulator (for vertex based simulations), is 0.02 hours, this method\n", + "will cause the simulator to print results every 6 minutes (i.e. 0.1 hours).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2940206f", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.SetSamplingTimestepMultiple(50)" + ] + }, + { + "cell_type": "markdown", + "id": "7966a7f4", + "metadata": {}, + "source": [ + "We must now create one or more force laws, which determine the mechanics of the vertices of each cell in a cell population.\n", + "For this test, we use one force law, based on the Nagai-Honda mechanics, and pass it to the OffLatticeSimulation.\n", + "For a list of possible forces see subclasses of AbstractForce.\n", + "Note that some of these forces are not compatible with vertex-based simulations see the specific class documentation for details,\n", + "if you try to use an incompatible class then you will receive a warning.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26e4644a", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.NagaiHondaForce2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "00582593", + "metadata": {}, + "source": [ + "A NagaiHondaForce assumes that each cell has a target area. The target areas of cells are used to determine\n", + "pressure forces on each vertex and eventually determine the size of each cell in the simulation.\n", + "In order to assign target areas to cells and update them in each time step we add a SimpleTargetAreaModifier\n", + "to the simulation, which inherits from AbstractTargetAreaModifier.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fda8f3af", + "metadata": {}, + "outputs": [], + "source": [ + "growth_modifier = chaste.cell_based.SimpleTargetAreaModifier2()\n", + "simulator.AddSimulationModifier(growth_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "05290bcb", + "metadata": {}, + "source": [ + "Save snapshot images of the population during the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88684fe0", + "metadata": {}, + "outputs": [], + "source": [ + "scene_modifier = chaste.visualization.JupyterSceneModifier2(nb_manager)\n", + "scene_modifier.SetVtkScene(scene)\n", + "scene_modifier.SetUpdateFrequency(100)\n", + "simulator.AddSimulationModifier(scene_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "39dd07cd", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`. We can again do a quick rendering of the population at the end of the simulation\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c1b7bcd", + "metadata": {}, + "outputs": [], + "source": [ + "scene.Start()\n", + "simulator.Solve()\n", + "scene.End()" + ] + }, + { + "cell_type": "markdown", + "id": "5f4a930e", + "metadata": {}, + "source": [ + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94f90cd2", + "metadata": {}, + "outputs": [], + "source": [ + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "77383ca3", + "metadata": {}, + "source": [ + "## Test 2 - introducing periodicity, boundaries and cell killers\n", + "In the second test, we run a simple vertex-based simulation, in which we create a monolayer of cells in a periodic geometry,\n", + "using a cylindrical vertex mesh. We also include a fixed boundary which cells can't pass through and a cell killer which removes\n", + "cells once they leave a region. As before each cell is assigned a stochastic cell-cycle model.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41cef549", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the test \n", + "chaste.cell_based.SetupNotebookTest()" + ] + }, + { + "cell_type": "markdown", + "id": "fc605cc4", + "metadata": {}, + "source": [ + "First, we generate a periodic vertex mesh. To create a Cylindrical2dVertexMesh, we can use the CylindricalHoneycombVertexMeshGenerator.\n", + "This generates a honeycomb-shaped mesh, in which all nodes are equidistant and the right hand side is associated with the left hand side.\n", + "Here the first and second arguments define the size of the mesh - we have chosen a mesh that is\n", + "4 elements (i.e. cells) wide, and 4 elements high.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3efea02c", + "metadata": {}, + "outputs": [], + "source": [ + "generator = chaste.mesh.CylindricalHoneycombVertexMeshGenerator(4, 4)\n", + "mesh = generator.GetCylindricalMesh()" + ] + }, + { + "cell_type": "markdown", + "id": "af27d734", + "metadata": {}, + "source": [ + "Having created a mesh, we now create a VectorSharedPtrCells. This is exactly the same as the above test.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3caf01b6", + "metadata": {}, + "outputs": [], + "source": [ + "transit_type = chaste.cell_based.TransitCellProliferativeType()\n", + "cell_generator = chaste.cell_based.CellsGeneratorUniformG1GenerationalCellCycleModel_2()\n", + "cells = cell_generator.GenerateBasicRandom(mesh.GetNumElements(), transit_type)" + ] + }, + { + "cell_type": "markdown", + "id": "9b6ecbd5", + "metadata": {}, + "source": [ + "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.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35beacb5", + "metadata": {}, + "outputs": [], + "source": [ + "cell_population = chaste.cell_based.VertexBasedCellPopulation2(mesh, cells)" + ] + }, + { + "cell_type": "markdown", + "id": "15c0a487", + "metadata": {}, + "source": [ + "We then pass in the cell population into an `OffLatticeSimulation`, and set the output directory, output multiple and end time\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "447ff9df", + "metadata": {}, + "outputs": [], + "source": [ + "simulator = chaste.cell_based.OffLatticeSimulation2_2(cell_population)\n", + "simulator.SetOutputDirectory(\"Python/TestPeriodicVertexBasedCellPopulation\")\n", + "simulator.SetEndTime(1.0)\n", + "simulator.SetSamplingTimestepMultiple(50)" + ] + }, + { + "cell_type": "markdown", + "id": "9b7db67d", + "metadata": {}, + "source": [ + "We now make a pointer to an appropriate force and pass it to the OffLatticeSimulation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ad5f991", + "metadata": {}, + "outputs": [], + "source": [ + "force = chaste.cell_based.NagaiHondaForce2()\n", + "simulator.AddForce(force)" + ] + }, + { + "cell_type": "markdown", + "id": "a4989fa0", + "metadata": {}, + "source": [ + "We also make a pointer to the target area modifier and add it to the simulator.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31eab391", + "metadata": {}, + "outputs": [], + "source": [ + "growth_modifier = chaste.cell_based.SimpleTargetAreaModifier2()\n", + "simulator.AddSimulationModifier(growth_modifier)" + ] + }, + { + "cell_type": "markdown", + "id": "f4e62725", + "metadata": {}, + "source": [ + "We now create one or more CellPopulationBoundaryConditions, which determine any conditions which each cell in a cell population must satisfy.\n", + "For this test, we use a PlaneBoundaryCondition, and pass it to the OffLatticeSimulation. For a list of possible boundary condition\n", + "see subclasses of AbstractCellPopulationBoundaryCondition.\n", + "Note that some of these boundary conditions are not compatible with vertex-based simulations see the specific class documentation\n", + "for details, if you try to use an incompatible class then you will receive a warning.\n", + "The first step is to define a point on the plane boundary and a normal to the plane.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b98ee25b", + "metadata": {}, + "outputs": [], + "source": [ + "point = np.array([0.0, 0.0])\n", + "normal = np.array([0.0, -1.0])" + ] + }, + { + "cell_type": "markdown", + "id": "b45c6346", + "metadata": {}, + "source": [ + "We can now make a PlaneBoundaryCondition (passing the point and normal to the plane) and pass it to the OffLatticeSimulation.\n", + "bc = chaste.cell_based.PlaneBoundaryCondition2_2(cell_population, point, normal)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ff6476a", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.AddCellPopulationBoundaryCondition(bc)" + ] + }, + { + "cell_type": "markdown", + "id": "1c562b7d", + "metadata": {}, + "source": [ + "We now create one or more CellKillers, which determine how cells are removed from the simulation.\n", + "For this test, we use a PlaneBasedCellKiller, and pass it to the OffLatticeSimulation.\n", + "For a list of possible cell killers see subclasses of AbstractCellKiller.\n", + "The first step is to define a point on the plane boundary and a normal to the plane.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f9c419c", + "metadata": {}, + "outputs": [], + "source": [ + "point = np.array([0.0, 3.0])\n", + "normal = np.array([0.0, 1.0])" + ] + }, + { + "cell_type": "markdown", + "id": "ab554989", + "metadata": {}, + "source": [ + "Finally we now make a PlaneBasedCellKiller (passing the point and normal to the plane) and pass it to the OffLatticeSimulation.\n", + "killer = chaste.cell_based.PlaneBasedCellKiller2(cell_population, point, normal)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2747096", + "metadata": {}, + "outputs": [], + "source": [ + "simulator.AddCellKiller(killer)" + ] + }, + { + "cell_type": "markdown", + "id": "7bd62315", + "metadata": {}, + "source": [ + "To run the simulation, we call `Solve()`.\n", + "simulator.Solve()\n", + "\n", + "The next two lines are for test purposes only and are not part of this tutorial.\n", + "If different simulation input parameters are being explored the lines should be removed.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c194b6b", + "metadata": {}, + "outputs": [], + "source": [ + "# Tear down the test \n", + "chaste.cell_based.TearDownNotebookTest()" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/infra/CreateJupyterNotebookTutorial.py b/infra/CreateJupyterNotebookTutorial.py index 1a691acc..35f89143 100755 --- a/infra/CreateJupyterNotebookTutorial.py +++ b/infra/CreateJupyterNotebookTutorial.py @@ -244,7 +244,6 @@ def ConvertTutorialToJupyterNotebook(test_file_path, test_file, other_files, rev """ if revision: revision = ' at revision r' + str(revision) - nb = nbf.v4.new_notebook() nb['cells'] = [] @@ -307,7 +306,6 @@ def ParseOptions(): ## Some logging print ("Generating:" + out_file_name) - with open(out_file_name, 'w') as f: nbf.write(nb, f) diff --git a/infra/CreateMarkdownTutorial.py b/infra/CreateMarkdownTutorial.py index 085962a8..2565bb16 100755 --- a/infra/CreateMarkdownTutorial.py +++ b/infra/CreateMarkdownTutorial.py @@ -210,14 +210,27 @@ def ConvertTutorialToMarkdownText(test_file_path, test_file, other_files, revisi revision = ' at revision r' + str(revision) output = [] # Header - regex = re.compile(ur'(?!^)(?=[A-Z])', re.MULTILINE) + regex = re.compile(r'(?!^)(?=[A-Z])', re.MULTILINE) ugly_file_name = os.path.splitext(os.path.basename(test_file_path))[0] nice_file_name = re.sub(regex, " ", ugly_file_name) + + page_header = f""" +--- +title : "{nice_file_name}" +summary: "" +draft: false +images: [] +toc: true +layout: "single" +--- + +This tutorial is automatically generated from the file {test_file_path} {revision}. +Note that the code is given in full at the bottom of the page. + + +""" - output.append('---\nlayout: page-full-width \ntitle: ' + nice_file_name + '\n---\n') - output.append('This tutorial is automatically generated from the file ' + test_file_path + revision + '.\n') - output.append('[Go to the Jupyter Notebook version.]({{ site.baseurl}}/documentation/md_tutorials/'+ ugly_file_name + '_nb.html)\n') - output.append('Note that the code is given in full at the bottom of the page.\n\n\n') + output.append(page_header) # Convert each file in turn test_output, test_code = ConvertFileToMarkdownText(test_file, test_file_path) @@ -233,7 +246,7 @@ def ConvertTutorialToMarkdownText(test_file_path, test_file, other_files, revisi # Now output the C++ code for all files output.append('\n\n# Code \nThe full code is given below\n') AddCodeOutput(os.path.basename(test_file_path), test_code, output) - for filename, code in other_code.iteritems(): + for filename, code in other_code.items(): AddCodeOutput(filename, code, output) return ''.join(output) diff --git a/infra/GenerateWikiPages.py b/infra/GenerateWikiPages.py index 3c3086b4..ec2ca546 100755 --- a/infra/GenerateWikiPages.py +++ b/infra/GenerateWikiPages.py @@ -37,41 +37,59 @@ This script converts Python tutorials to markdown and jupyter notebook formats for use on the PyChaste website. """ +import argparse import fnmatch -import os -import sys import ntpath +import os import subprocess -if __name__ == '__main__': +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog="GenerateWikiPages") + parser.add_argument( + "--format", + type=str, + choices=["markdown", "jupyter"], + default="markdown", + const="all", + nargs="?", + help="output format", + ) + args = parser.parse_args() # Find all the tutorial files. tutorial_files = [] - for root, dirs, files in os.walk('test'): + for root, dirs, files in os.walk("../test"): for file in files: - if fnmatch.fnmatch(file, 'Test*LiteratePaper*') or fnmatch.fnmatch(file, 'Test*Tutorial*'): - if not fnmatch.fnmatch(file, '*.pyc'): + if fnmatch.fnmatch(file, "Test*LiteratePaper*") or fnmatch.fnmatch( + file, "Test*Tutorial*" + ): + if not fnmatch.fnmatch(file, "*.pyc"): tutorial_files.append([root, file]) - - output_format = "jupyter" - - if output_format == "markdown": - + + if args.format == "markdown": # Generate the markdown for each for eachFile in tutorial_files: - outfile = " doc/tutorials/" + os.path.splitext(ntpath.basename(eachFile[1]))[0] +".md" + outfile = ( + "../doc/tutorials/" + + os.path.splitext(ntpath.basename(eachFile[1]))[0] + + ".md" + ) inputfile = eachFile[0] + "/" + eachFile[1] - launch_string = "infra/CreateMarkdownTutorial.py " + inputfile + outfile + launch_string = f"../infra/CreateMarkdownTutorial.py {inputfile} {outfile}" os.system(launch_string) - - elif output_format == "jupyter": - + + elif args.format == "jupyter": # Generate the jupyter notebooks for each for eachFile in tutorial_files: - outfile = " doc/tutorials/" + os.path.splitext(ntpath.basename(eachFile[1]))[0] +".ipynb" + outfile = ( + "../doc/tutorials/" + + os.path.splitext(ntpath.basename(eachFile[1]))[0] + + ".ipynb" + ) inputfile = eachFile[0] + "/" + eachFile[1] - launch_string = "infra/CreateJupyterNotebookTutorial.py " + inputfile + outfile + launch_string = ( + f"../infra/CreateJupyterNotebookTutorial.py {inputfile} {outfile}" + ) os.system(launch_string) - - subprocess.call("jupyter nbconvert " + outfile, shell=True) + subprocess.call(f"jupyter nbconvert --to notebook {outfile}", shell=True)