Mitosis
In developmental simulations, we often need to simulate cells that grow
and divide. We start with a single cell and grow it.
When a cell reaches a critical volume, it undergoes Mitosis.
We check if the cell has reached this volume threshold at
the end of every Monte Carlo Step (MCS). The folder containing this simulation is
CompuCellPythonTutorial/steppableBasedMitosis
Note
Tip: Be sure to turn off mitosis for dying cells. cell_death.rst`_`See how here.
How to Implement a Simple Mitosis Steppable
from cc3d.core.PySteppables import *
class MitosisSteppable(MitosisSteppableBase):
def __init__(self, frequency=1):
MitosisSteppableBase.__init__(self, frequency)
# Optional: Customize where to place the new cell.
# 0 - parent and child positions will be randomized between mitosis events
# negative integer - parent appears on the 'left' of the child
# positive integer - parent appears on the 'right' of the child
self.set_parent_child_position_flag(-1)
def step(self, mcs):
cells_to_divide = []
for cell in self.cell_list:
if cell.volume > 50: #the critical mass, chosen arbitrarily
cells_to_divide.append(cell)
for cell in cells_to_divide:
# To change mitosis mode, leave one of the below lines uncommented
self.divide_cell_random_orientation(cell)
# Other valid options
# self.divide_cell_orientation_vector_based(cell,1,1,0)
# self.divide_cell_along_major_axis(cell)
# self.divide_cell_along_minor_axis(cell)
def update_attributes(self):
# Reduce parent target volume BEFORE cloning
self.parent_cell.targetVolume /= 2.0
self.clone_parent_2_child()
# Make the cell type change every time the cell divides
if self.parent_cell.type == self.CONDENSING:
self.child_cell.type = self.NONCONDENSING
else:
self.child_cell.type = self.CONDENSING
- How does the
step(…)
function work? Check every cell to see if its volume is greater than 50.
All cells with this critical volume are placed into a list,
cells_to_divide
.Then, loop over all
cells_to_divide
to perform mitosis with a built-in function such asdivide_cell_random_orientation(cell)
.update_attributes()
is automatically called before each division. Use this to control the data of the parent and child cells.Here,
self.clone_parent_2_child()
copies over all data for you.
Note
It’s important to use two Python loops in step(…)
to avoid iterating
over a newly-created cell. If we keep dividing cells in this loop we are adding elements to the list over which we iterate over and this might have unwanted side effects.
The solution is to use use list of cells to divide as we did in the example.
We have a choice in step 3 to divide cells along a randomly-oriented plane
(line in 2D), along major, minor, or user-specified axis. When using a user
specified axis, you specify a vector which is perpendicular to the plane
(axis in 2D) along which you want to divide the cell. This vector does
not have to be normalized but it has to have length different than 0. The
update_attributes
function is called automatically each time you call any
of the functions which divide cells.
Note
The name of the function where we update attributes after mitosis has to be exactly update_attributes
. If it is differen, CC3D will not call it automatically.
The update_attributes
of the function is actually the heart of the
mitosis module and you implement parameter adjustments for parent and
child cells inside this function. It is, in general, a good practice to
make sure that you update attributes of both parent and child
cells. Notice that we reset target volume of the parent to 25:
self.parent_cell.targetVolume = 25.0
Had we forgotten to do that, the parent cell would keep the high target volume
from before the mitosis and its actual volume would be, roughly 25
pixels. As a result, after the mitosis, the parent cell would “explode”
to get its volume close to the target target volume. As a matter of fact,
if we keep increasing targetVolume
without resetting, the target volume
of parent cell would be higher for each consecutive mitosis event.
Therefore, you should always make sure that the attributes of parent and
child cells are adjusted properly in the update_attributes
function.
The next call in the update_attributes
function is
self.clone_parent_2_child()
. This function is a convenience function that
copies all parent cell’s attributes to the child cell. It is completely up to you to call this
function or do a manual copy of select attributes from parent to child
cell.
Deep-Copy a Cell (recommended)
clone_parent_2_child()
: Copies all attributes of the parent cell to the child cell, including cell.dict
.
Shallow-Copy a Cell
clone_attributes(source_cell, target_cell, no_clone_key_dict_list)
: Creates a shallow copy of a cell.
Parent attributes are copied, but dictionary elements, such as cell.dict
, are skipped.
Example:
self.clone_attributes(source_cell=self.parent_cell,
target_cell=self.child_cell,
no_clone_key_dict_list=["ATTRIB_1", "ATTRIB_2"])
The dictionary elements ATTRIB_1
and ATTRIB_2
no_clone_key_dict_list=["ATTRIB_1", "ATTRIB_2"]
are not copied. Remember that you can always ignore those convenience functions and assign parent and child cell attributes manually if this gives your code the behavior you want or makes code run faster.
For example, the implementation of the update_attributes
function where we
manually set parent
and child
properties could look like that:
def update_attributes(self):
self.child_cell.targetVolume = self.parent_cell.targetVolume
self.child_cell.lambdaVolume = self.parent_cell.lambdaVolume
if self.parent_cell.type == self.CONDENSING:
self.child_cell.type = self.NONCONDENSING
else:
self.child_cell.type = self.CONDENSING
Remember to Grow Your Cells
You can use either one of the two XML plugins to grow your cells to the target volume of 50. Let CC3D define this for you by clicking on CCDML -> Plugins -> Volume in Twedit++.
<Plugin Name="Volume">
<VolumeEnergyParameters CellType="Condensing" LambdaVolume="2.0" TargetVolume="50.0"/>
<VolumeEnergyParameters CellType="NonCondensing" LambdaVolume="2.0" TargetVolume="50.0"/>
</Plugin>
or
<Plugin Name="Volume">
<TargetVolume>50</TargetVolume>
<LambdaVolume>2.0</LambdaVolume>
</Plugin>
Directionality of mitosis - a source of possible simulation bias
When the mitosis module divides cells (and, for simplicity, let’s assume that division happens along a vertical line), then the parent cell will always remain on the same side of the line. For example, if you run have a “stem” cell that keeps dividing, all of its offspring will be created on the same side of the dividing line. What you may observe then is that, if you reassign the cell type of a child cell after mitosis, then, in certain simulations, the cell will appear to be biased to move in one direction of the lattice.
To avoid this bias, you need to call the
self.set_parent_child_position_flag
function from the Base
class of the Mitosis
steppable. When you call this function with argument 0, then the relative
position of parent and child cells after mitosis will be randomized (this
is the default behavior). When the argument is a negative integer, the child
cell will always appear on the right of the parent cell. Conversely, when the
argument is a positive integer, the child cell will appear always on the
left-hand side of the parent cell.
- Related Examples