On this page This tutorial was generated from the file projects/CryptFissionPlos2016/test/TestCryptFissionLiteratePaper.hpp at revision r26908.
Note that the code is given in full at the bottom of the page.
Simulation of fission in epithelial layer# Introduction# In this test we show how Chaste can be used to simulate a buckling layer of epithelial cells.
Details of the computational model can be found in
Langlands et al (2016) “Paneth cell-rich regions separated by a cluster of Lgr5+ cells initiate
fission in the intestinal stem cell niche”.
We begin by including the necessary header files. The first ones are common to all cell_based Chaste simulations
#include <cxxtest/TestSuite.h> //Needed for all test files
#include "CellBasedSimulationArchiver.hpp" //Needed if we would like to save/load simulations
#include "AbstractCellBasedTestSuite.hpp" //Needed for cell-based tests: times simulations, generates random numbers and has cell properties
#include "CheckpointArchiveTypes.hpp" //Needed if we use GetIdentifier() method (which we do)
#include "SmartPointers.hpp" //Enables macros to save typing
The next set of classes are needed specifically for the simulation, which can be found in the core code.
#include "HoneycombMeshGenerator.hpp" //Generates mesh
#include "OffLatticeSimulation.hpp" //Simulates the evolution of the population
#include "MeshBasedCellPopulationWithGhostNodes.hpp"
#include "VoronoiDataWriter.hpp" //Allows us to visualise output in Paraview
#include "DifferentiatedCellProliferativeType.hpp" //Stops cells from proliferating
#include "TransitCellProliferativeType.hpp"
#include "FakePetscSetup.hpp" //Forbids tests running in parallel
This set of classes are not part of the core code and were made for this model.
#include "StochasticTargetProportionBasedCellCycleModel.hpp" //Asymmetric-division-based cell cycle model
#include "PanethCellMutationState.hpp" //Mutation class that defines Paneth cells
#include "EpithelialLayerLinearSpringForce.hpp" //Spring force law to account for different cell type pairs
#include "EpithelialLayerBasementMembraneForce.hpp" //Basement membrane force, as defined in Dunn et al. (2012)
#include "EpithelialLayerAnoikisCellKiller.hpp" //Cell killer to remove proliferative cells that have fallen into the lumen
#include "EpithelialLayerDataTrackingModifier.hpp" //Modifier for all the necessary data
#include "FixedRegionPlaneBoundaryCondition.hpp" //Boundary condition that fixes cells past a given plane
Define the Chaste simulation as a test class. This is how all simulations
in Chaste are defined.
class TestCryptFissionLiteratePaper : public AbstractCellBasedTestSuite
{
public :
void TestEpithelialLayerUndergoingFission () throw ( Exception )
{
We first set all the simulation parameters.
//Simulation time parameters
double dt = 0.005 ; //Set dt
double end_time = 100.0 ; //Set end time
double sampling_timestep = 0.5 / dt ; //Set sampling timestep
//Set all the spring stiffness variables
double epithelial_epithelial_stiffness = 15.0 ; //Epithelial-epithelial spring connections
double epithelial_nonepithelial_stiffness = 15.0 ; //Epithelial-non-epithelial spring connections
double nonepithelial_nonepithelial_stiffness = 15.0 ; //Non-epithelial-non-epithelial spring connections
//Set the stiffness ratio for Paneth cells to stem cells. This is the
double stiffness_ratio = 4.5 ;
Set the target proportion for stem cells. Note that the target proportion and
the actual proportion of stem cells will be different, due to cell death and
mechanical heterogeneities.
double target_proportion = 0.3 ; //This corresponds to the 20% stem cell (80% Paneth cell) case
// double target_proportion = 0.8; //This corresponds to the 60% stem cell (40% Paneth cell) case.
//Set the BM force parameters
double bm_force = 10.0 ; //Set the basement membrane stiffness
double target_curvature = 0.2 ; //Set the target curvature, i.e. how circular the layer wants to be
Set the domain of the model.
unsigned cells_across = 24 ; //Desired width + a few more layers, to avoid the box collapsing
unsigned cells_up = 27 ; //Since height of each cell is 0.5*sqrt(3), we need to specify the no. of cells such that #cells*0.5*sqrt(3) = desired height
unsigned ghosts = 4 ; //Define a sufficient layer of ghost nodes to avoid infinite tessellations and hence excessively large forces
//Translate mesh 1.5 units left and 1.5 units down, so that we have a sufficient layer of fixed cells around the boundary.
c_vector < double , 2 > translate_left = zero_vector < double > ( 2 );
translate_left ( 0 ) = - 1.5 ;
c_vector < double , 2 > translate_down = zero_vector < double > ( 2 );
translate_down ( 1 ) = - 1.5 ;
Define the initially circular lumen by centre and radius
c_vector < double , 2 > circle_centre ;
circle_centre ( 0 ) = 10.5 ;
circle_centre ( 1 ) = 10.0 ;
double circle_radius = 2.5 ; //Size of hole
assert ( circle_radius > 0 ); //Just in case someone does something crazy.
double ring_radius = circle_radius + 2.0 ; //Radius of the ring of cells. This isn't the actual radius, just has to be large enough for later
assert (( ring_radius <= cells_across ) && ( ring_radius <= cells_up )); //Again, just in case.
Generate the initial mesh of cells.
HoneycombMeshGenerator generator ( cells_across , cells_up , ghosts );
MutableMesh < 2 , 2 >* p_mesh = generator . GetMesh ();
//Translate mesh appropriately
p_mesh -> Translate ( translate_left );
p_mesh -> Translate ( translate_down );
Define the lumen as an inner region of ghost nodes.
std :: vector < unsigned > initial_real_indices = generator . GetCellLocationIndices (); //Obtain the locations of real nodes
std :: vector < unsigned > real_indices ; //Vector used to define the locations of non-ghost nodes
//Sweep over the initial real indices
for ( unsigned i = 0 ; i < initial_real_indices . size (); i ++ )
{
unsigned cell_index = initial_real_indices [ i ];
double x = p_mesh -> GetNode ( cell_index ) -> rGetLocation ()[ 0 ];
double y = p_mesh -> GetNode ( cell_index ) -> rGetLocation ()[ 1 ];
// If the location of the node falls inside the defined lumen region, then it becomes a ghost node.
if ( pow ( x - circle_centre [ 0 ], 2 ) + pow ( y - circle_centre [ 1 ], 2 ) > pow ( circle_radius , 2 ))
{
real_indices . push_back ( cell_index );
}
}
Define cell types: non-epithelial cells are differentiated, all proliferative epithelial cells
will be transit cells (to define cell cycle duration). In addition, stem cells are assigned a wildtype mutation state,
while Paneth cells are assigned a Paneth cell mutation state.
boost :: shared_ptr < AbstractCellProperty > p_diff_type = CellPropertyRegistry :: Instance () -> Get < DifferentiatedCellProliferativeType > ();
boost :: shared_ptr < AbstractCellProperty > p_stem_type = CellPropertyRegistry :: Instance () -> Get < TransitCellProliferativeType > ();
boost :: shared_ptr < AbstractCellProperty > p_paneth_state = CellPropertyRegistry :: Instance () -> Get < PanethCellMutationState > ();
boost :: shared_ptr < AbstractCellProperty > p_state = CellPropertyRegistry :: Instance () -> Get < WildTypeCellMutationState > ();
//Create vector of cells
std :: vector < CellPtr > cells ;
Create asymmetric-division-based cell cycle for each cell. However, we initially set all cells
to be non-epithelial cells before defining our layer of epithelial cells.
for ( unsigned i = 0 ; i < real_indices . size (); i ++ )
{
//Set cell cycle
StochasticTargetProportionBasedCellCycleModel * p_cycle_model = new StochasticTargetProportionBasedCellCycleModel ();
p_cycle_model -> SetTargetProportion ( target_proportion ); //Set the division parameter
p_cycle_model -> SetDimension ( 2 );
//To avoid a 'pulsing' behaviour with birth events, we set each cell's initial age to be
// ~U(-12, 0) in the past, as each cell cycle duration is U(11, 13).
double birth_time = 12.0 * RandomNumberGenerator :: Instance () -> ranf ();
p_cycle_model -> SetBirthTime ( - birth_time );
CellPtr p_cell ( new Cell ( p_state , p_cycle_model ));
p_cell -> SetCellProliferativeType ( p_diff_type ); //Set the cell to be differentiated and hence non-epithelial
p_cell -> InitialiseCellCycleModel ();
cells . push_back ( p_cell );
}
//Create cell population
MeshBasedCellPopulationWithGhostNodes < 2 > cell_population ( * p_mesh , cells , real_indices );
//Create layer of proliferative cells
for ( unsigned i = 0 ; i < real_indices . size (); i ++ )
{
unsigned cell_index = real_indices [ i ];
CellPtr cell_iter = cell_population . GetCellUsingLocationIndex ( cell_index );
double x = cell_population . GetLocationOfCellCentre ( cell_iter )[ 0 ];
double y = cell_population . GetLocationOfCellCentre ( cell_iter )[ 1 ];
We ‘un-differentiate’ any cells adjacent to the lumen into epithelial cells.
We only consider cells within the pre-defined ring radius. Not only does this narrow down
our search, but it also means we won’t accidentally consider any cells on the outside and
turn them into epithelial cells.
if ( pow ( x - circle_centre [ 0 ], 2 ) + pow ( y - circle_centre [ 1 ], 2 ) <= pow ( ring_radius , 2 ))
{
Node < 2 >* p_node = cell_population . GetNodeCorrespondingToCell ( cell_iter );
unsigned node_index = p_node -> GetIndex ();
//Iterate over all possible neighbours of the node
for ( Node < 2 >:: ContainingElementIterator iter = p_node -> ContainingElementsBegin ();
iter != p_node -> ContainingElementsEnd ();
++ iter )
{
bool element_contains_ghost_nodes = false ;
// Get a pointer to the element
Element < 2 , 2 >* p_element = cell_population . rGetMesh (). GetElement ( * iter );
// Check whether it's triangulation contains a ghost node
for ( unsigned local_index = 0 ; local_index < 3 ; local_index ++ )
{
unsigned nodeGlobalIndex = p_element -> GetNodeGlobalIndex ( local_index );
if ( cell_population . IsGhostNode ( nodeGlobalIndex ) == true )
{
element_contains_ghost_nodes = true ;
break ; // This should break out of the inner for loop
}
}
//If a cell has a ghost node as a neighbour, we make it an epithelial cells.
if ( element_contains_ghost_nodes )
{
cell_iter -> SetCellProliferativeType ( p_stem_type );
}
}
}
}
Iterate again and check that proliferative cells are also attached to non-epithelial
cells. If they are not, remove them from the simulation.
for ( unsigned i = 0 ; i < real_indices . size (); i ++ )
{
unsigned cell_index = real_indices [ i ];
CellPtr cell_iter = cell_population . GetCellUsingLocationIndex ( cell_index );
double x = cell_population . GetLocationOfCellCentre ( cell_iter )[ 0 ];
double y = cell_population . GetLocationOfCellCentre ( cell_iter )[ 1 ];
//Only consider this inside the pre-defined ring to narrow down our search
if ( pow ( x - circle_centre [ 0 ], 2 ) + pow ( y - circle_centre [ 1 ], 2 ) <= pow ( ring_radius , 2 ))
{
Node < 2 >* p_node = cell_population . GetNodeCorrespondingToCell ( cell_iter );
unsigned node_index = p_node -> GetIndex ();
//Only iterate over the initial layer of transit cells
if ( cell_iter -> GetCellProliferativeType () -> IsType < DifferentiatedCellProliferativeType > () == false )
{
bool element_contains_gel_nodes = false ;
//Iterate over elements (triangles) containing the node
for ( Node < 2 >:: ContainingElementIterator iter = p_node -> ContainingElementsBegin ();
iter != p_node -> ContainingElementsEnd ();
++ iter )
{
// Get a pointer to the element (triangle)
Element < 2 , 2 >* p_element = cell_population . rGetMesh (). GetElement ( * iter );
// Check if its triangulation contains a gel node
for ( unsigned local_index = 0 ; local_index < 3 ; local_index ++ )
{
unsigned nodeGlobalIndex = p_element -> GetNodeGlobalIndex ( local_index );
bool is_ghost_node = cell_population . IsGhostNode ( nodeGlobalIndex );
if ( is_ghost_node == false ) //Make sure we're not dealing with ghost nodes (otherwise this stuff will fail)
{
CellPtr p_local_cell = cell_population . GetCellUsingLocationIndex ( nodeGlobalIndex );
if ( p_local_cell -> GetCellProliferativeType () -> IsType < DifferentiatedCellProliferativeType > () == true )
{
element_contains_gel_nodes = true ;
break ; // This should break out of the inner for loop
}
}
}
}
if ( element_contains_gel_nodes == false )
{
cell_iter -> Kill ();
}
}
}
}
Randomly assign cells in the layer to be Paneth cells.
std :: vector < unsigned > cells_in_layer ; //Initialise vector
//Obtain the proliferative cells
for ( AbstractCellPopulation < 2 >:: Iterator cell_iter = cell_population . Begin ();
cell_iter != cell_population . End ();
++ cell_iter )
{
unsigned node_index = cell_population . GetLocationIndexUsingCell ( * cell_iter );
//If the cell is an epithelial cell
if ( ! cell_iter -> GetCellProliferativeType () -> IsType < DifferentiatedCellProliferativeType > () )
{
cells_in_layer . push_back ( node_index ); //Add the angle and node index
}
}
For each cell in the ring, we draw a random number and assign cells to be stem cells with
a probability equal to the target proportion, as defined above.
for ( unsigned i = 0 ; i < cells_in_layer . size (); i ++ )
{
unsigned node_index = cells_in_layer [ i ];
CellPtr cell = cell_population . GetCellUsingLocationIndex ( node_index );
//Randomly generate number
double random_number = RandomNumberGenerator :: Instance () -> ranf ();
if ( random_number >= target_proportion ) //Assign cells to be Paneth with 1 - target_proportion
{
cell -> SetMutationState ( p_paneth_state );
}
}
//Allow output in Paraview, a program that can be used to visualise Chaste simulations
cell_population . AddPopulationWriter < VoronoiDataWriter > ();
Define the simulation class.
OffLatticeSimulation < 2 > simulator ( cell_population );
//Set output directory
simulator . SetOutputDirectory ( "CryptFissionLiteratePaper" );
simulator . SetDt ( dt ); //Set the timestep dt for force volution
simulator . SetSamplingTimestepMultiple ( sampling_timestep ); //Set the sampling timestep multiple for animations
simulator . SetEndTime ( end_time ); //Set the number of hours to run the simulation to
We add a modifier class to track relevant cell population numbers and shape measurements.
MAKE_PTR ( EpithelialLayerDataTrackingModifier < 2 > , p_data_tracking_modifier );
simulator . AddSimulationModifier ( p_data_tracking_modifier );
Add linear spring force which has different spring stiffness constants, depending
on the pair of cells it is connecting.
MAKE_PTR ( EpithelialLayerLinearSpringForce < 2 > , p_spring_force );
p_spring_force -> SetCutOffLength ( 1.5 );
//Set the spring stiffnesses
p_spring_force -> SetEpithelialEpithelialSpringStiffness ( epithelial_epithelial_stiffness );
p_spring_force -> SetEpithelialNonepithelialSpringStiffness ( epithelial_nonepithelial_stiffness );
p_spring_force -> SetNonepithelialNonepithelialSpringStiffness ( nonepithelial_nonepithelial_stiffness );
p_spring_force -> SetPanethCellStiffnessRatio ( stiffness_ratio );
simulator . AddForce ( p_spring_force );
Add the basement membrane force.
MAKE_PTR ( EpithelialLayerBasementMembraneForce , p_bm_force );
p_bm_force -> SetBasementMembraneParameter ( bm_force ); //Equivalent to beta in SJD's papers
p_bm_force -> SetTargetCurvature ( target_curvature ); //This is equivalent to 1/R in SJD's papers
simulator . AddForce ( p_bm_force );
Add an anoikis-based cell killer.
MAKE_PTR_ARGS ( EpithelialLayerAnoikisCellKiller , p_anoikis_killer , ( & cell_population ));
simulator . AddCellKiller ( p_anoikis_killer );
We fix all cells outside of the 20 x 20 box.
c_vector < double , 2 > point = zero_vector < double > ( 2 );
c_vector < double , 2 > normal = zero_vector < double > ( 2 );
//Fix cells in the region x < 0
normal ( 0 ) = - 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc1 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc1 );
//Fix cells in the region x > 20
point ( 0 ) = 20.0 ;
normal ( 0 ) = 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc2 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc2 );
//Fix cells in the region y < 0
point ( 0 ) = 0.0 ;
point ( 1 ) = 0.0 ;
normal ( 0 ) = 0.0 ;
normal ( 1 ) = - 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc3 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc3 );
//Fix cells in the region y > 20
point ( 1 ) = 20.0 ;
normal ( 1 ) = 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc4 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc4 );
Run the simulation.
To visualize the results, open a new terminal and
to the Chaste directory, then
to
. Then do:
java Visualize2dCentreCells /tmp/$USER/testoutput/CryptFissionLiteratePaper/results_from_time_0
.
You may have to do:
javac Visualize2dCentreCells.java
beforehand to create the java executable. You should also select the axes equal option.
Code# The full code is given below
File name TestCryptFissionLiteratePaper.hpp
# #include <cxxtest/TestSuite.h> //Needed for all test files
#include "CellBasedSimulationArchiver.hpp" //Needed if we would like to save/load simulations
#include "AbstractCellBasedTestSuite.hpp" //Needed for cell-based tests: times simulations, generates random numbers and has cell properties
#include "CheckpointArchiveTypes.hpp" //Needed if we use GetIdentifier() method (which we do)
#include "SmartPointers.hpp" //Enables macros to save typing
#include "HoneycombMeshGenerator.hpp" //Generates mesh
#include "OffLatticeSimulation.hpp" //Simulates the evolution of the population
#include "MeshBasedCellPopulationWithGhostNodes.hpp"
#include "VoronoiDataWriter.hpp" //Allows us to visualise output in Paraview
#include "DifferentiatedCellProliferativeType.hpp" //Stops cells from proliferating
#include "TransitCellProliferativeType.hpp"
#include "FakePetscSetup.hpp" //Forbids tests running in parallel
#include "StochasticTargetProportionBasedCellCycleModel.hpp" //Asymmetric-division-based cell cycle model
#include "PanethCellMutationState.hpp" //Mutation class that defines Paneth cells
#include "EpithelialLayerLinearSpringForce.hpp" //Spring force law to account for different cell type pairs
#include "EpithelialLayerBasementMembraneForce.hpp" //Basement membrane force, as defined in Dunn et al. (2012)
#include "EpithelialLayerAnoikisCellKiller.hpp" //Cell killer to remove proliferative cells that have fallen into the lumen
#include "EpithelialLayerDataTrackingModifier.hpp" //Modifier for all the necessary data
#include "FixedRegionPlaneBoundaryCondition.hpp" //Boundary condition that fixes cells past a given plane
class TestCryptFissionLiteratePaper : public AbstractCellBasedTestSuite
{
public :
void TestEpithelialLayerUndergoingFission () throw ( Exception )
{
//Simulation time parameters
double dt = 0.005 ; //Set dt
double end_time = 100.0 ; //Set end time
double sampling_timestep = 0.5 / dt ; //Set sampling timestep
//Set all the spring stiffness variables
double epithelial_epithelial_stiffness = 15.0 ; //Epithelial-epithelial spring connections
double epithelial_nonepithelial_stiffness = 15.0 ; //Epithelial-non-epithelial spring connections
double nonepithelial_nonepithelial_stiffness = 15.0 ; //Non-epithelial-non-epithelial spring connections
//Set the stiffness ratio for Paneth cells to stem cells. This is the
double stiffness_ratio = 4.5 ;
double target_proportion = 0.3 ; //This corresponds to the 20% stem cell (80% Paneth cell) case
// double target_proportion = 0.8; //This corresponds to the 60% stem cell (40% Paneth cell) case.
//Set the BM force parameters
double bm_force = 10.0 ; //Set the basement membrane stiffness
double target_curvature = 0.2 ; //Set the target curvature, i.e. how circular the layer wants to be
unsigned cells_across = 24 ; //Desired width + a few more layers, to avoid the box collapsing
unsigned cells_up = 27 ; //Since height of each cell is 0.5*sqrt(3), we need to specify the no. of cells such that #cells*0.5*sqrt(3) = desired height
unsigned ghosts = 4 ; //Define a sufficient layer of ghost nodes to avoid infinite tessellations and hence excessively large forces
//Translate mesh 1.5 units left and 1.5 units down, so that we have a sufficient layer of fixed cells around the boundary.
c_vector < double , 2 > translate_left = zero_vector < double > ( 2 );
translate_left ( 0 ) = - 1.5 ;
c_vector < double , 2 > translate_down = zero_vector < double > ( 2 );
translate_down ( 1 ) = - 1.5 ;
c_vector < double , 2 > circle_centre ;
circle_centre ( 0 ) = 10.5 ;
circle_centre ( 1 ) = 10.0 ;
double circle_radius = 2.5 ; //Size of hole
assert ( circle_radius > 0 ); //Just in case someone does something crazy.
double ring_radius = circle_radius + 2.0 ; //Radius of the ring of cells. This isn't the actual radius, just has to be large enough for later
assert (( ring_radius <= cells_across ) && ( ring_radius <= cells_up )); //Again, just in case.
HoneycombMeshGenerator generator ( cells_across , cells_up , ghosts );
MutableMesh < 2 , 2 >* p_mesh = generator . GetMesh ();
//Translate mesh appropriately
p_mesh -> Translate ( translate_left );
p_mesh -> Translate ( translate_down );
std :: vector < unsigned > initial_real_indices = generator . GetCellLocationIndices (); //Obtain the locations of real nodes
std :: vector < unsigned > real_indices ; //Vector used to define the locations of non-ghost nodes
//Sweep over the initial real indices
for ( unsigned i = 0 ; i < initial_real_indices . size (); i ++ )
{
unsigned cell_index = initial_real_indices [ i ];
double x = p_mesh -> GetNode ( cell_index ) -> rGetLocation ()[ 0 ];
double y = p_mesh -> GetNode ( cell_index ) -> rGetLocation ()[ 1 ];
// If the location of the node falls inside the defined lumen region, then it becomes a ghost node.
if ( pow ( x - circle_centre [ 0 ], 2 ) + pow ( y - circle_centre [ 1 ], 2 ) > pow ( circle_radius , 2 ))
{
real_indices . push_back ( cell_index );
}
}
boost :: shared_ptr < AbstractCellProperty > p_diff_type = CellPropertyRegistry :: Instance () -> Get < DifferentiatedCellProliferativeType > ();
boost :: shared_ptr < AbstractCellProperty > p_stem_type = CellPropertyRegistry :: Instance () -> Get < TransitCellProliferativeType > ();
boost :: shared_ptr < AbstractCellProperty > p_paneth_state = CellPropertyRegistry :: Instance () -> Get < PanethCellMutationState > ();
boost :: shared_ptr < AbstractCellProperty > p_state = CellPropertyRegistry :: Instance () -> Get < WildTypeCellMutationState > ();
//Create vector of cells
std :: vector < CellPtr > cells ;
for ( unsigned i = 0 ; i < real_indices . size (); i ++ )
{
//Set cell cycle
StochasticTargetProportionBasedCellCycleModel * p_cycle_model = new StochasticTargetProportionBasedCellCycleModel ();
p_cycle_model -> SetTargetProportion ( target_proportion ); //Set the division parameter
p_cycle_model -> SetDimension ( 2 );
//To avoid a 'pulsing' behaviour with birth events, we set each cell's initial age to be
// ~U(-12, 0) in the past, as each cell cycle duration is U(11, 13).
double birth_time = 12.0 * RandomNumberGenerator :: Instance () -> ranf ();
p_cycle_model -> SetBirthTime ( - birth_time );
CellPtr p_cell ( new Cell ( p_state , p_cycle_model ));
p_cell -> SetCellProliferativeType ( p_diff_type ); //Set the cell to be differentiated and hence non-epithelial
p_cell -> InitialiseCellCycleModel ();
cells . push_back ( p_cell );
}
//Create cell population
MeshBasedCellPopulationWithGhostNodes < 2 > cell_population ( * p_mesh , cells , real_indices );
//Create layer of proliferative cells
for ( unsigned i = 0 ; i < real_indices . size (); i ++ )
{
unsigned cell_index = real_indices [ i ];
CellPtr cell_iter = cell_population . GetCellUsingLocationIndex ( cell_index );
double x = cell_population . GetLocationOfCellCentre ( cell_iter )[ 0 ];
double y = cell_population . GetLocationOfCellCentre ( cell_iter )[ 1 ];
if ( pow ( x - circle_centre [ 0 ], 2 ) + pow ( y - circle_centre [ 1 ], 2 ) <= pow ( ring_radius , 2 ))
{
Node < 2 >* p_node = cell_population . GetNodeCorrespondingToCell ( cell_iter );
unsigned node_index = p_node -> GetIndex ();
//Iterate over all possible neighbours of the node
for ( Node < 2 >:: ContainingElementIterator iter = p_node -> ContainingElementsBegin ();
iter != p_node -> ContainingElementsEnd ();
++ iter )
{
bool element_contains_ghost_nodes = false ;
// Get a pointer to the element
Element < 2 , 2 >* p_element = cell_population . rGetMesh (). GetElement ( * iter );
// Check whether it's triangulation contains a ghost node
for ( unsigned local_index = 0 ; local_index < 3 ; local_index ++ )
{
unsigned nodeGlobalIndex = p_element -> GetNodeGlobalIndex ( local_index );
if ( cell_population . IsGhostNode ( nodeGlobalIndex ) == true )
{
element_contains_ghost_nodes = true ;
break ; // This should break out of the inner for loop
}
}
//If a cell has a ghost node as a neighbour, we make it an epithelial cells.
if ( element_contains_ghost_nodes )
{
cell_iter -> SetCellProliferativeType ( p_stem_type );
}
}
}
}
for ( unsigned i = 0 ; i < real_indices . size (); i ++ )
{
unsigned cell_index = real_indices [ i ];
CellPtr cell_iter = cell_population . GetCellUsingLocationIndex ( cell_index );
double x = cell_population . GetLocationOfCellCentre ( cell_iter )[ 0 ];
double y = cell_population . GetLocationOfCellCentre ( cell_iter )[ 1 ];
//Only consider this inside the pre-defined ring to narrow down our search
if ( pow ( x - circle_centre [ 0 ], 2 ) + pow ( y - circle_centre [ 1 ], 2 ) <= pow ( ring_radius , 2 ))
{
Node < 2 >* p_node = cell_population . GetNodeCorrespondingToCell ( cell_iter );
unsigned node_index = p_node -> GetIndex ();
//Only iterate over the initial layer of transit cells
if ( cell_iter -> GetCellProliferativeType () -> IsType < DifferentiatedCellProliferativeType > () == false )
{
bool element_contains_gel_nodes = false ;
//Iterate over elements (triangles) containing the node
for ( Node < 2 >:: ContainingElementIterator iter = p_node -> ContainingElementsBegin ();
iter != p_node -> ContainingElementsEnd ();
++ iter )
{
// Get a pointer to the element (triangle)
Element < 2 , 2 >* p_element = cell_population . rGetMesh (). GetElement ( * iter );
// Check if its triangulation contains a gel node
for ( unsigned local_index = 0 ; local_index < 3 ; local_index ++ )
{
unsigned nodeGlobalIndex = p_element -> GetNodeGlobalIndex ( local_index );
bool is_ghost_node = cell_population . IsGhostNode ( nodeGlobalIndex );
if ( is_ghost_node == false ) //Make sure we're not dealing with ghost nodes (otherwise this stuff will fail)
{
CellPtr p_local_cell = cell_population . GetCellUsingLocationIndex ( nodeGlobalIndex );
if ( p_local_cell -> GetCellProliferativeType () -> IsType < DifferentiatedCellProliferativeType > () == true )
{
element_contains_gel_nodes = true ;
break ; // This should break out of the inner for loop
}
}
}
}
if ( element_contains_gel_nodes == false )
{
cell_iter -> Kill ();
}
}
}
}
std :: vector < unsigned > cells_in_layer ; //Initialise vector
//Obtain the proliferative cells
for ( AbstractCellPopulation < 2 >:: Iterator cell_iter = cell_population . Begin ();
cell_iter != cell_population . End ();
++ cell_iter )
{
unsigned node_index = cell_population . GetLocationIndexUsingCell ( * cell_iter );
//If the cell is an epithelial cell
if ( ! cell_iter -> GetCellProliferativeType () -> IsType < DifferentiatedCellProliferativeType > () )
{
cells_in_layer . push_back ( node_index ); //Add the angle and node index
}
}
for ( unsigned i = 0 ; i < cells_in_layer . size (); i ++ )
{
unsigned node_index = cells_in_layer [ i ];
CellPtr cell = cell_population . GetCellUsingLocationIndex ( node_index );
//Randomly generate number
double random_number = RandomNumberGenerator :: Instance () -> ranf ();
if ( random_number >= target_proportion ) //Assign cells to be Paneth with 1 - target_proportion
{
cell -> SetMutationState ( p_paneth_state );
}
}
//Allow output in Paraview, a program that can be used to visualise Chaste simulations
cell_population . AddPopulationWriter < VoronoiDataWriter > ();
OffLatticeSimulation < 2 > simulator ( cell_population );
//Set output directory
simulator . SetOutputDirectory ( "CryptFissionLiteratePaper" );
simulator . SetDt ( dt ); //Set the timestep dt for force volution
simulator . SetSamplingTimestepMultiple ( sampling_timestep ); //Set the sampling timestep multiple for animations
simulator . SetEndTime ( end_time ); //Set the number of hours to run the simulation to
MAKE_PTR ( EpithelialLayerDataTrackingModifier < 2 > , p_data_tracking_modifier );
simulator . AddSimulationModifier ( p_data_tracking_modifier );
MAKE_PTR ( EpithelialLayerLinearSpringForce < 2 > , p_spring_force );
p_spring_force -> SetCutOffLength ( 1.5 );
//Set the spring stiffnesses
p_spring_force -> SetEpithelialEpithelialSpringStiffness ( epithelial_epithelial_stiffness );
p_spring_force -> SetEpithelialNonepithelialSpringStiffness ( epithelial_nonepithelial_stiffness );
p_spring_force -> SetNonepithelialNonepithelialSpringStiffness ( nonepithelial_nonepithelial_stiffness );
p_spring_force -> SetPanethCellStiffnessRatio ( stiffness_ratio );
simulator . AddForce ( p_spring_force );
MAKE_PTR ( EpithelialLayerBasementMembraneForce , p_bm_force );
p_bm_force -> SetBasementMembraneParameter ( bm_force ); //Equivalent to beta in SJD's papers
p_bm_force -> SetTargetCurvature ( target_curvature ); //This is equivalent to 1/R in SJD's papers
simulator . AddForce ( p_bm_force );
MAKE_PTR_ARGS ( EpithelialLayerAnoikisCellKiller , p_anoikis_killer , ( & cell_population ));
simulator . AddCellKiller ( p_anoikis_killer );
c_vector < double , 2 > point = zero_vector < double > ( 2 );
c_vector < double , 2 > normal = zero_vector < double > ( 2 );
//Fix cells in the region x < 0
normal ( 0 ) = - 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc1 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc1 );
//Fix cells in the region x > 20
point ( 0 ) = 20.0 ;
normal ( 0 ) = 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc2 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc2 );
//Fix cells in the region y < 0
point ( 0 ) = 0.0 ;
point ( 1 ) = 0.0 ;
normal ( 0 ) = 0.0 ;
normal ( 1 ) = - 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc3 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc3 );
//Fix cells in the region y > 20
point ( 1 ) = 20.0 ;
normal ( 1 ) = 1.0 ;
MAKE_PTR_ARGS ( FixedRegionPlaneBoundaryCondition < 2 > , p_bc4 , ( & cell_population , point , normal ));
simulator . AddCellPopulationBoundaryCondition ( p_bc4 );
simulator . Solve ();
}
};