This tutorial will be going through the steps to create a tumor clustering simulation using BioDynaMo. The full simulation can be found in the soma clustering demo on the biodynamo website and in the source code.
To create a new project folder, we first need to source the biodynamo code. This done by running the build→bin→thisbdm.sh script.
We then run bdm new project_name
to create our project folder. This folder contains some files that’s needed for biodynamo to run, but where we write the code for the simulation is in the src folder.
The file src→project_name.h contains the code for the simulation, this is where we can design our tumor simulation. When creating a new project, you a given a template simulation where a single cell is created.
Running the command bdm build
builds the simulation code so it’s ready to run. This command will also tell us if there are any errors in your code. Running the command bdm run
then runs the code for the number of timesteps we specified in the project file. In this case, it is just 1 timestep.
Once it has finished running, a new folder is created called output, which contains the visualisation files. Running the command bdm view
opens paraview and shows the results of the simulation.
We have now created a single cell but its not doing anything, so lets give it something to do.
BioDynaMo has many pre-made functions for cells called behaviours. Behaviours are a set of instructions that each cell completes in each timestep.
To add a behaviour, we initialise the cell and then add our behaviour to the list of behaviours. This is done before adding the cell to the simulation.
The behaviour being added is the Growth and Division function, where a cell grows in size by a given speed each timestep (in this case it adds 10 to its volume each timestep).
Once the cell reaches a certain size (in this case 2 units in diameter). The cell will divide equally into two daughter cells. This growth and division process then repeats to create a small collection of cells.
Now lets scale up the simulation to start with a few cells.
We now introduce a class into our code called the model initialiser. These set of functions allows us to create many cells in many different orientations at the start of the simulation.
The first we will look at is Grid3D, which initialises a uniform grid of cells. This function takes in 3 variables: the number of cells in the x, y and z direction, the distance between each cell, and then a construct function that defines the cell itself.
The constructor is made as a lambda function, which is simply a short, quick function that defines the cell itself in the same way as the previous two steps.
In this example, this creates a cube of cells with 5 cells in each direction (125 cells total) with each cell being spaced by 5 units.
As we gave all the cells the growth and division behaviour, every cell will begin creating daughter cells, rapidly increasing the number of cells in the simulation over time.
Lets take a look at another orientation.
The setup is the same as the previous step except we now use the CreateRandomAgents function in the model initialiser.
This function takes 4 variables: minimum x, y, z position, maximum x, y and z position, total number of cells to generate, and then the same constructor as the previous step.
In this example we will give the minimum and maximum position as 0 and 25, respectively. We will also set the total number of cells to 125. This is so the bounds and starting number of the cells is the same as the previous step, but now they are randomly placed instead of aligned in a grid pattern.
Similar to the previous example, all of this cells are given the growth and division behaviour, but now the random placement of cells is more representative of a biological system.
Now lets give the cells something else to do.
While BioDynaMo has many in-built behaviours, many biological systems have specific rules and governing equations. So to offer more flexibility to the user, BioDynaMo allows us to design our own behaviours.
To demonstrate this, the behaviour we will create is a random walk, where cells will slowly move around the simulation similar to brownian motion or turbulent flow.
The behaviour is created before everything else in the simulation, including the simulation space itself. Our behaviour is created as an extension of the general behaviour class (the in-built behaviours are made like this as well).
We start by retrieving the cell information, which contains its position, diameter, mass, etc. We then retrieve BioDynaMo’s random number generator so we can generate the direction the cell will walk in.
To generate this direction, we first define a speed at which it will walk (in this case 0.1 units per timestep). Then we create a vector in a random direction. Lastly, we update the cells position, which takes the cells position and adds our walk to it.
Once the behaviour is created, we can then add it to the cells list of behaviours in the same way we added the Growth and Division behaviour. Our random collection of cells now jiggle a little bit. The speed at which they move can be adjusted by changing the speed value in our new behaviour.
Cells are able to have many different behaviours at once. When we initialise the cell, we can add both the growth and division behaviour and our new random walk behaviour.
Both of these behaviours will be completed by every cell per time step.
It’s important to note that the cell will complete the random walk before it grows/divides, as the random walk behaviour is added first and the growth and division behaviour is added second.
Now our simulation is starting to look biological! Let’s up the complexity a bit more.
Cells are not the only element we can add to our simulation. BioDynaMo offers the ability to create a substance. This substance diffuses throughout the simulation space, and can be produced/consumed by cells.
We first start with the main code, where we use the model initialiser to define our substance. This function takes in the substance ID, substance name, diffusion coefficient, decay constant and resolution. Lets go through each of them:
- Substance ID is created just before the simulation is defined. This is simply to help BioDynaMo recall the substance information in the background whenever it is needed.
- Substance name is what we use to retrieve the substance information.
- The diffusion coefficient is the speed at which the substance moves through the simulation space.
- The decay constant is the rate of which the substance disappears over time.
- The resolution determines how many divisions the simulation space is split into. Higher resolution means more accurate substance movement, but a more computationally expensive simulation.
In this example, the simulation starts with zero substance concentration in the space. It also starts with a Dirichlet boundaries of 0, which means the concentration at the edges of simulation is 0 and cannot change. This simulates substances diffusing away from where our simulation takes place.
Now we need to do something with this substance.
We create a new behaviour called Secrete, where cells add to the substance concentration in the region they reside in.
In this behaviour, we start by retrieving the resource manager, which then lets us retrieve the substance information. Then we retrieve the cell information like the random walk behaviour.
We then retrieve the cell’s position, and increase the concentration by 10 at the cell’s position using the diffusion grid information.
This behaviour is then added to the cell’s list of behaviours like normal.
The simulation created now shows our cells secreting a substance into the surrounding space. This substance diffuses away from the cells and decays over time.
We’ve almost made our tumour clustering model. We now need to add one last behaviour.
The final behaviour we will create will give the cells the ability to move towards the substance that other cells create.
This can be introduced by modifying the random walk behaviour we created earlier.
We retrieve the cell and substance information, and the cells position.
Then we retrieve the substance gradient at the cells position. We define a speed and then update the cells position to move in the direction of the positive gradient.
This will cause the cell to migrate towards areas of highest substance concentration, which will be where cells are secreting the substance.
Add this behaviour and the secreting behaviour, and we now have a basic tumor clustering simulation!
This tutorial has shown the steps we take to create the soma clustering demo, which can be found in the list of demos that BioDynaMo offers.
This demo scales up the number of cells in the simulation compared to ours, while also having two types of cells creating two different substances.
This simulation begins with a large collection of agents assigned at random positions, then each cell type secretes its own substance type, while cells of the same type migrate to each other.