00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "CaBasedCellPopulation.hpp"
00037
00038 #include <boost/scoped_array.hpp>
00039
00040 #include "RandomNumberGenerator.hpp"
00041 #include "Warnings.hpp"
00042
00043
00044 #include "VtkMeshWriter.hpp"
00045
00046
00047 #include "CellAgesWriter.hpp"
00048 #include "CellAncestorWriter.hpp"
00049 #include "CellLocationWriter.hpp"
00050 #include "CellProliferativePhasesWriter.hpp"
00051 #include "CellProliferativeTypesWriter.hpp"
00052
00053
00054 #include "CellMutationStatesWriter.hpp"
00055
00056 #include "NodesOnlyMesh.hpp"
00057 #include "Exception.hpp"
00058
00059 template<unsigned DIM>
00060 void CaBasedCellPopulation<DIM>::Validate()
00061 {
00062 NEVER_REACHED;
00063 }
00064
00065 template<unsigned DIM>
00066 CaBasedCellPopulation<DIM>::CaBasedCellPopulation(PottsMesh<DIM>& rMesh,
00067 std::vector<CellPtr>& rCells,
00068 const std::vector<unsigned> locationIndices,
00069 unsigned latticeCarryingCapacity,
00070 bool deleteMesh,
00071 bool validate)
00072 : AbstractOnLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh),
00073 mLatticeCarryingCapacity(latticeCarryingCapacity)
00074 {
00075 mAvailableSpaces = std::vector<unsigned>(this->GetNumNodes(), latticeCarryingCapacity);
00076
00077
00078 assert(this->mCells.size() <= this->mrMesh.GetNumNodes()*latticeCarryingCapacity);
00079
00080 if (locationIndices.empty())
00081 {
00082 EXCEPTION("No location indices being passed. Specify where cells lie before creating the cell population.");
00083 }
00084 else
00085 {
00086
00087
00088 std::list<CellPtr>::iterator it = this->mCells.begin();
00089 for (unsigned i=0; it != this->mCells.end(); ++it, ++i)
00090 {
00091 assert(i<locationIndices.size());
00092 if (!IsSiteAvailable(locationIndices[i],*it))
00093 {
00094 EXCEPTION("One of the lattice sites has more cells than the carrying capacity. Check the initial cell locations.");
00095 }
00096 mAvailableSpaces[locationIndices[i]]--;
00097 }
00098 }
00099 if (validate)
00100 {
00101 EXCEPTION("There is no validation for CaBasedCellPopulation.");
00102 }
00103 }
00104
00105 template<unsigned DIM>
00106 CaBasedCellPopulation<DIM>::CaBasedCellPopulation(PottsMesh<DIM>& rMesh)
00107 : AbstractOnLatticeCellPopulation<DIM>(rMesh)
00108 {
00109 }
00110
00111 template<unsigned DIM>
00112 CaBasedCellPopulation<DIM>::~CaBasedCellPopulation()
00113 {
00114 if (this->mDeleteMesh)
00115 {
00116 delete &this->mrMesh;
00117 }
00118 }
00119
00120 template<unsigned DIM>
00121 std::vector<unsigned>& CaBasedCellPopulation<DIM>::rGetAvailableSpaces()
00122 {
00123 return mAvailableSpaces;
00124 }
00125
00126 template<unsigned DIM>
00127 bool CaBasedCellPopulation<DIM>::IsSiteAvailable(unsigned index, CellPtr pCell)
00128 {
00130 return (mAvailableSpaces[index] != 0);
00131 }
00132
00133 template<unsigned DIM>
00134 PottsMesh<DIM>& CaBasedCellPopulation<DIM>::rGetMesh()
00135 {
00136 return static_cast<PottsMesh<DIM>& >((this->mrMesh));
00137 }
00138
00139 template<unsigned DIM>
00140 const PottsMesh<DIM>& CaBasedCellPopulation<DIM>::rGetMesh() const
00141 {
00142 return static_cast<PottsMesh<DIM>& >((this->mrMesh));
00143 }
00144
00145 template<unsigned DIM>
00146 Node<DIM>* CaBasedCellPopulation<DIM>::GetNode(unsigned index)
00147 {
00148 return this->mrMesh.GetNode(index);
00149 }
00150
00151 template<unsigned DIM>
00152 unsigned CaBasedCellPopulation<DIM>::GetNumNodes()
00153 {
00154 return this->mrMesh.GetNumNodes();
00155 }
00156
00157 template<unsigned DIM>
00158 c_vector<double, DIM> CaBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
00159 {
00160 return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell))->rGetLocation();
00161 }
00162
00163 template<unsigned DIM>
00164 Node<DIM>* CaBasedCellPopulation<DIM>::GetNodeCorrespondingToCell(CellPtr pCell)
00165 {
00166 return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell));
00167 }
00168
00169 template<unsigned DIM>
00170 void CaBasedCellPopulation<DIM>::AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
00171 {
00172 if (!IsSiteAvailable(index, pCell))
00173 {
00174 EXCEPTION("No available spaces at location index " << index << ".");
00175 }
00176
00177 mAvailableSpaces[index]--;
00178 AbstractCellPopulation<DIM,DIM>::AddCellUsingLocationIndex(index, pCell);
00179 }
00180
00181 template<unsigned DIM>
00182 void CaBasedCellPopulation<DIM>::RemoveCellUsingLocationIndex(unsigned index, CellPtr pCell)
00183 {
00184 AbstractCellPopulation<DIM,DIM>::RemoveCellUsingLocationIndex(index, pCell);
00185
00186 mAvailableSpaces[index]++;
00187
00188 assert(mAvailableSpaces[index] <= mLatticeCarryingCapacity);
00189 }
00190
00191 template<unsigned DIM>
00192 bool CaBasedCellPopulation<DIM>::IsRoomToDivide(CellPtr pCell)
00193 {
00194 bool is_room = false;
00195
00196
00197 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00198
00199
00200 std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
00201
00202
00203 for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00204 neighbour_iter != neighbouring_node_indices.end();
00205 ++neighbour_iter)
00206 {
00207 if (IsSiteAvailable(*neighbour_iter, pCell))
00208 {
00209 is_room = true;
00210 break;
00211 }
00212 }
00213
00214 return is_room;
00215 }
00216
00217 template<unsigned DIM>
00218 CellPtr CaBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00219 {
00220
00221 unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
00222
00223
00224 std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(parent_node_index);
00225 unsigned num_neighbours = neighbouring_node_indices.size();
00226
00227
00228 assert(!neighbouring_node_indices.empty());
00229
00230 std::vector<double> neighbouring_node_propensities;
00231 std::vector<unsigned> neighbouring_node_indices_vector;
00232
00233 double total_propensity = 0.0;
00234
00235 for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00236 neighbour_iter != neighbouring_node_indices.end();
00237 ++neighbour_iter)
00238 {
00239 neighbouring_node_indices_vector.push_back(*neighbour_iter);
00240
00241 double propensity_dividing_into_neighbour = EvaluateDivisionPropensity(parent_node_index,*neighbour_iter,pParentCell);
00242
00243 if (!IsSiteAvailable(*neighbour_iter, pParentCell))
00244 {
00245 propensity_dividing_into_neighbour = 0.0;
00246 }
00247 neighbouring_node_propensities.push_back(propensity_dividing_into_neighbour);
00248 total_propensity += propensity_dividing_into_neighbour;
00249 }
00250
00251 assert(total_propensity>0);
00252
00253 for (unsigned i=0; i<num_neighbours; i++)
00254 {
00255 neighbouring_node_propensities[i] /= total_propensity;
00256 }
00257
00258
00259 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00260 double random_number = p_gen->ranf();
00261
00262 double total_probability = 0.0;
00263 unsigned daughter_node_index = UNSIGNED_UNSET;
00264
00265 unsigned counter;
00266 for (counter=0; counter < num_neighbours; counter++)
00267 {
00268 total_probability += neighbouring_node_propensities[counter];
00269 if (total_probability >= random_number)
00270 {
00271
00272 daughter_node_index = neighbouring_node_indices_vector[counter];
00273 break;
00274 }
00275 }
00276
00277
00278 assert(daughter_node_index != UNSIGNED_UNSET);
00279 assert(daughter_node_index < this->mrMesh.GetNumNodes());
00280
00281
00282 this->mCells.push_back(pNewCell);
00283
00284
00285 CellPtr p_created_cell = this->mCells.back();
00286 AddCellUsingLocationIndex(daughter_node_index,p_created_cell);
00287
00288 return p_created_cell;
00289 }
00290
00291 template<unsigned DIM>
00292 double CaBasedCellPopulation<DIM>:: EvaluateDivisionPropensity(unsigned currentNodeIndex,
00293 unsigned targetNodeIndex,
00294 CellPtr pCell)
00295 {
00296 return 1.0;
00297 }
00298
00299 template<unsigned DIM>
00300 unsigned CaBasedCellPopulation<DIM>::RemoveDeadCells()
00301 {
00302 unsigned num_removed = 0;
00303
00304 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00305 cell_iter != this->mCells.end();
00306 )
00307 {
00308 if ((*cell_iter)->IsDead())
00309 {
00310
00311 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00312
00313 RemoveCellUsingLocationIndex(node_index, (*cell_iter));
00314
00315
00316 num_removed++;
00317 cell_iter = this->mCells.erase(cell_iter);
00318 }
00319 else
00320 {
00321 ++cell_iter;
00322 }
00323 }
00324 return num_removed;
00325 }
00326
00327 template<unsigned DIM>
00328 void CaBasedCellPopulation<DIM>::UpdateCellLocations(double dt)
00329 {
00330
00332 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00333 cell_iter != this->mCells.end();
00334 ++cell_iter)
00335 {
00336
00337 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00338
00339
00340 std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
00341 std::vector<double> neighbouring_node_propensities;
00342 std::vector<unsigned> neighbouring_node_indices_vector;
00343
00344 if (!neighbouring_node_indices.empty())
00345 {
00346 unsigned num_neighbours = neighbouring_node_indices.size();
00347 double probability_of_not_moving = 1.0;
00348
00349 for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00350 iter != neighbouring_node_indices.end();
00351 ++iter)
00352 {
00353 double probability_of_moving = 0.0;
00354
00355 neighbouring_node_indices_vector.push_back(*iter);
00356
00357 if (IsSiteAvailable(*iter, *cell_iter))
00358 {
00359
00360 for (typename std::vector<boost::shared_ptr<AbstractCaUpdateRule<DIM> > >::iterator iterRule = mUpdateRuleCollection.begin();
00361 iterRule != mUpdateRuleCollection.end();
00362 ++iterRule)
00363 {
00364 probability_of_moving += (*iterRule)->EvaluateProbability(node_index, *iter, *this, dt, 1, *cell_iter);
00365 if (probability_of_moving < 0)
00366 {
00367 EXCEPTION("The probability of cellular movement is smaller than zero. In order to prevent it from happening you should change your time step and parameters");
00368 }
00369
00370 if (probability_of_moving > 1)
00371 {
00372 EXCEPTION("The probability of the cellular movement is bigger than one. In order to prevent it from happening you should change your time step and parameters");
00373 }
00374 }
00375
00376 probability_of_not_moving -= probability_of_moving;
00377 neighbouring_node_propensities.push_back(probability_of_moving);
00378 }
00379 else
00380 {
00381 neighbouring_node_propensities.push_back(0.0);
00382 }
00383 }
00384 if (probability_of_not_moving < 0)
00385 {
00386 EXCEPTION("The probability of the cell not moving is smaller than zero. In order to prevent it from happening you should change your time step and parameters");
00387 }
00388
00389
00390 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00391 double random_number = p_gen->ranf();
00392
00393 double total_probability = 0.0;
00394 for (unsigned counter=0; counter<num_neighbours; counter++)
00395 {
00396 total_probability += neighbouring_node_propensities[counter];
00397 if (total_probability >= random_number)
00398 {
00399
00400 unsigned chosen_neighbour_location_index = neighbouring_node_indices_vector[counter];
00401 this->MoveCellInLocationMap((*cell_iter), node_index, chosen_neighbour_location_index);
00402 break;
00403 }
00404 }
00405
00406 }
00407 else
00408 {
00409
00410 NEVER_REACHED;
00411 }
00412 }
00413 }
00414
00415 template<unsigned DIM>
00416 bool CaBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell)
00417 {
00418 return false;
00419 }
00420
00421 template<unsigned DIM>
00422 void CaBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00423 {
00424 }
00425
00426 template<unsigned DIM>
00427 void CaBasedCellPopulation<DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<DIM, DIM> > pPopulationWriter)
00428 {
00429 pPopulationWriter->Visit(this);
00430 }
00431
00432 template<unsigned DIM>
00433 void CaBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00434 {
00435 pCellWriter->VisitCell(pCell, this);
00436 }
00437
00438 template<unsigned DIM>
00439 void CaBasedCellPopulation<DIM>::OpenWritersFiles(const std::string& rDirectory)
00440 {
00441 if (this->mOutputResultsForChasteVisualizer)
00442 {
00443 if (!this-> template HasWriter<CellLocationWriter>())
00444 {
00445 this-> template AddCellWriter<CellLocationWriter>();
00446 }
00447 }
00448
00449 AbstractCellPopulation<DIM>::OpenWritersFiles(rDirectory);
00450 }
00451
00452 template<unsigned DIM>
00453 double CaBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00454 {
00455 double cell_volume = 1.0;
00456 return cell_volume;
00457 }
00458
00459 template<unsigned DIM>
00460 double CaBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00461 {
00462 double width = this->mrMesh.GetWidth(rDimension);
00463 return width;
00464 }
00465
00466 template<unsigned DIM>
00467 void CaBasedCellPopulation<DIM>::AddUpdateRule(boost::shared_ptr<AbstractCaUpdateRule<DIM> > pUpdateRule)
00468 {
00469 mUpdateRuleCollection.push_back(pUpdateRule);
00470 }
00471
00472 template<unsigned DIM>
00473 void CaBasedCellPopulation<DIM>::RemoveAllUpdateRules()
00474 {
00475 mUpdateRuleCollection.clear();
00476 }
00477
00478 template<unsigned DIM>
00479 const std::vector<boost::shared_ptr<AbstractCaUpdateRule<DIM> > >& CaBasedCellPopulation<DIM>::rGetUpdateRuleCollection() const
00480 {
00481 return mUpdateRuleCollection;
00482 }
00483
00484 template<unsigned DIM>
00485 void CaBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00486 {
00487
00488 AbstractOnLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00489 }
00490
00491 template<unsigned DIM>
00492 void CaBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00493 {
00494 #ifdef CHASTE_VTK
00495 unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
00496 std::stringstream time;
00497 time << num_timesteps;
00498
00499 VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
00500
00501 unsigned num_cells = this->GetNumRealCells();
00502 std::vector<double> cell_types(num_cells, -1.0);
00503 std::vector<double> cell_mutation_states(num_cells, -1.0);
00504 std::vector<double> cell_ids(num_cells, -1.0);
00505 std::vector<double> cell_ancestors(num_cells, -1.0);
00506 std::vector<double> cell_ages(num_cells, -1.0);
00507 std::vector<double> cell_cycle_phases(num_cells, -1.0);
00508 std::vector<Node<DIM>*> nodes;
00509
00510
00511 unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00512 std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
00513
00514 std::vector<std::vector<double> > cell_data;
00515 for (unsigned var=0; var<num_cell_data_items; var++)
00516 {
00517 std::vector<double> cell_data_var(num_cells);
00518 cell_data.push_back(cell_data_var);
00519 }
00520
00521 unsigned cell = 0;
00522
00523
00524 unsigned num_sites = this->mrMesh.GetNumNodes();
00525 boost::scoped_array<unsigned> number_of_cells_at_site(new unsigned[num_sites]);
00526 for (unsigned i=0; i<num_sites; i++)
00527 {
00528 number_of_cells_at_site[i] = 0;
00529 }
00530
00531 for (std::list<CellPtr>::iterator iter = this->mCells.begin();
00532 iter != this->mCells.end();
00533 ++iter)
00534 {
00535 CellPtr cell_ptr = *iter;
00536 cell_ids[cell] = cell_ptr->GetCellId();
00537
00538 unsigned location_index = this->GetLocationIndexUsingCell(*iter);
00539
00540 number_of_cells_at_site[location_index]++;
00541 assert(number_of_cells_at_site[location_index]<=mLatticeCarryingCapacity);
00542
00543
00544 c_vector<double, DIM> coords;
00545 coords = this->mrMesh.GetNode(location_index)->rGetLocation();
00546
00547
00548 if (mLatticeCarryingCapacity > 1)
00549 {
00550 c_vector<double, DIM> offset;
00551
00552 if (DIM == 2)
00553 {
00554 double angle = (double)number_of_cells_at_site[location_index]*2.0*M_PI/(double)mLatticeCarryingCapacity;
00555 offset[0] = 0.2*sin(angle);
00556 offset[1] = 0.2*cos(angle);
00557 }
00558 else
00559 {
00560 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00561
00562 for (unsigned i=0; i<DIM; i++)
00563 {
00564 offset[i] = p_gen->ranf();
00565 }
00566 }
00567
00568 for (unsigned i=0; i<DIM; i++)
00569 {
00570 coords[i] += offset[i];
00571 }
00572 }
00573
00574 nodes.push_back(new Node<DIM>(cell, coords, false));
00575
00576 if (this-> template HasWriter<CellAncestorWriter>())
00577 {
00578 double ancestor_index = (cell_ptr->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_ptr->GetAncestor();
00579 cell_ancestors[cell] = ancestor_index;
00580 }
00581 if (this-> template HasWriter<CellProliferativeTypesWriter>())
00582 {
00583 cell_types[cell] = cell_ptr->GetCellProliferativeType()->GetColour();
00584 }
00585 if (this-> template HasWriter<CellMutationStatesWriter>())
00586 {
00587 cell_mutation_states[cell] = cell_ptr->GetMutationState()->GetColour();
00588
00590 CellPropertyCollection collection = cell_ptr->rGetCellPropertyCollection();
00591 CellPropertyCollection label_collection = collection.GetProperties<CellLabel>();
00592
00593 if (label_collection.GetSize() == 1)
00594 {
00595 boost::shared_ptr<CellLabel> p_label = boost::static_pointer_cast<CellLabel>(label_collection.GetProperty());
00596 cell_mutation_states[cell] = p_label->GetColour();
00597 }
00598
00599 }
00600 if (this-> template HasWriter<CellAgesWriter>())
00601 {
00602 cell_ages[cell] = cell_ptr->GetAge();
00603 }
00604 if (this-> template HasWriter<CellProliferativePhasesWriter>())
00605 {
00606 cell_cycle_phases[cell] = cell_ptr->GetCellCycleModel()->GetCurrentCellCyclePhase();
00607 }
00608 for (unsigned var=0; var<num_cell_data_items; var++)
00609 {
00610 cell_data[var][cell] = cell_ptr->GetCellData()->GetItem(cell_data_names[var]);
00611 }
00612
00613 cell ++;
00614 }
00615
00616
00617 mesh_writer.AddPointData("Cell ids", cell_ids);
00618
00619 if (this-> template HasWriter<CellProliferativeTypesWriter>())
00620 {
00621 mesh_writer.AddPointData("Cell types", cell_types);
00622 }
00623 if (this-> template HasWriter<CellMutationStatesWriter>())
00624 {
00625 mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00626 }
00627 if (this-> template HasWriter<CellAncestorWriter>())
00628 {
00629 mesh_writer.AddPointData("Ancestors", cell_ancestors);
00630 }
00631 if (this-> template HasWriter<CellAgesWriter>())
00632 {
00633 mesh_writer.AddPointData("Ages", cell_ages);
00634 }
00635 if (this-> template HasWriter<CellProliferativePhasesWriter>())
00636 {
00637 mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00638 }
00639 if (num_cell_data_items > 0)
00640 {
00641 for (unsigned var=0; var<cell_data.size(); var++)
00642 {
00643 mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
00644 }
00645 }
00646
00647
00648
00649
00650
00651 NodesOnlyMesh<DIM> temp_mesh;
00652 temp_mesh.ConstructNodesWithoutMesh(nodes, 1.5);
00653 mesh_writer.WriteFilesUsingMesh(temp_mesh);
00654
00655 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
00656 *(this->mpVtkMetaFile) << num_timesteps;
00657 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00658 *(this->mpVtkMetaFile) << num_timesteps;
00659 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00660
00661
00662 for (unsigned i=0; i<nodes.size(); i++)
00663 {
00664 delete nodes[i];
00665 }
00666 #endif //CHASTE_VTK
00667 }
00668
00669
00670 template class CaBasedCellPopulation<1>;
00671 template class CaBasedCellPopulation<2>;
00672 template class CaBasedCellPopulation<3>;
00673
00674
00675 #include "SerializationExportWrapperForCpp.hpp"
00676 EXPORT_TEMPLATE_CLASS_SAME_DIMS(CaBasedCellPopulation)