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 "CellLocationIndexWriter.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 std::set<unsigned> CaBasedCellPopulation<DIM>::GetNeighbouringLocationIndices(CellPtr pCell)
00159 {
00160 unsigned index = this->GetLocationIndexUsingCell(pCell);
00161 std::set<unsigned> candidates = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(index);
00162
00163 std::set<unsigned> neighbour_indices;
00164 for (std::set<unsigned>::iterator iter = candidates.begin();
00165 iter != candidates.end();
00166 ++iter)
00167 {
00168 if (!IsSiteAvailable(*iter, pCell))
00169 {
00170 neighbour_indices.insert(*iter);
00171 }
00172 }
00173
00174 return neighbour_indices;
00175 }
00176
00177 template<unsigned DIM>
00178 c_vector<double, DIM> CaBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
00179 {
00180 return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell))->rGetLocation();
00181 }
00182
00183 template<unsigned DIM>
00184 Node<DIM>* CaBasedCellPopulation<DIM>::GetNodeCorrespondingToCell(CellPtr pCell)
00185 {
00186 return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell));
00187 }
00188
00189 template<unsigned DIM>
00190 void CaBasedCellPopulation<DIM>::AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
00191 {
00192 if (!IsSiteAvailable(index, pCell))
00193 {
00194 EXCEPTION("No available spaces at location index " << index << ".");
00195 }
00196
00197 mAvailableSpaces[index]--;
00198 AbstractCellPopulation<DIM,DIM>::AddCellUsingLocationIndex(index, pCell);
00199 }
00200
00201 template<unsigned DIM>
00202 void CaBasedCellPopulation<DIM>::RemoveCellUsingLocationIndex(unsigned index, CellPtr pCell)
00203 {
00204 AbstractCellPopulation<DIM,DIM>::RemoveCellUsingLocationIndex(index, pCell);
00205
00206 mAvailableSpaces[index]++;
00207
00208 assert(mAvailableSpaces[index] <= mLatticeCarryingCapacity);
00209 }
00210
00211 template<unsigned DIM>
00212 bool CaBasedCellPopulation<DIM>::IsRoomToDivide(CellPtr pCell)
00213 {
00214 bool is_room = false;
00215
00216
00217 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00218
00219
00220 std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
00221
00222
00223 for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00224 neighbour_iter != neighbouring_node_indices.end();
00225 ++neighbour_iter)
00226 {
00227 if (IsSiteAvailable(*neighbour_iter, pCell))
00228 {
00229 is_room = true;
00230 break;
00231 }
00232 }
00233
00234 return is_room;
00235 }
00236
00237 template<unsigned DIM>
00238 CellPtr CaBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00239 {
00240
00241 unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
00242
00243
00244 std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(parent_node_index);
00245 unsigned num_neighbours = neighbouring_node_indices.size();
00246
00247
00248 assert(!neighbouring_node_indices.empty());
00249
00250 std::vector<double> neighbouring_node_propensities;
00251 std::vector<unsigned> neighbouring_node_indices_vector;
00252
00253 double total_propensity = 0.0;
00254
00255 for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00256 neighbour_iter != neighbouring_node_indices.end();
00257 ++neighbour_iter)
00258 {
00259 neighbouring_node_indices_vector.push_back(*neighbour_iter);
00260
00261 double propensity_dividing_into_neighbour = EvaluateDivisionPropensity(parent_node_index,*neighbour_iter,pParentCell);
00262
00263 if (!IsSiteAvailable(*neighbour_iter, pParentCell))
00264 {
00265 propensity_dividing_into_neighbour = 0.0;
00266 }
00267 neighbouring_node_propensities.push_back(propensity_dividing_into_neighbour);
00268 total_propensity += propensity_dividing_into_neighbour;
00269 }
00270
00271 assert(total_propensity>0);
00272
00273 for (unsigned i=0; i<num_neighbours; i++)
00274 {
00275 neighbouring_node_propensities[i] /= total_propensity;
00276 }
00277
00278
00279 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00280 double random_number = p_gen->ranf();
00281
00282 double total_probability = 0.0;
00283 unsigned daughter_node_index = UNSIGNED_UNSET;
00284
00285 unsigned counter;
00286 for (counter=0; counter < num_neighbours; counter++)
00287 {
00288 total_probability += neighbouring_node_propensities[counter];
00289 if (total_probability >= random_number)
00290 {
00291
00292 daughter_node_index = neighbouring_node_indices_vector[counter];
00293 break;
00294 }
00295 }
00296
00297
00298 assert(daughter_node_index != UNSIGNED_UNSET);
00299 assert(daughter_node_index < this->mrMesh.GetNumNodes());
00300
00301
00302 this->mCells.push_back(pNewCell);
00303
00304
00305 CellPtr p_created_cell = this->mCells.back();
00306 AddCellUsingLocationIndex(daughter_node_index,p_created_cell);
00307
00308 return p_created_cell;
00309 }
00310
00311 template<unsigned DIM>
00312 double CaBasedCellPopulation<DIM>:: EvaluateDivisionPropensity(unsigned currentNodeIndex,
00313 unsigned targetNodeIndex,
00314 CellPtr pCell)
00315 {
00316 return 1.0;
00317 }
00318
00319 template<unsigned DIM>
00320 unsigned CaBasedCellPopulation<DIM>::RemoveDeadCells()
00321 {
00322 unsigned num_removed = 0;
00323
00324 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00325 cell_iter != this->mCells.end();
00326 )
00327 {
00328 if ((*cell_iter)->IsDead())
00329 {
00330
00331 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00332
00333 RemoveCellUsingLocationIndex(node_index, (*cell_iter));
00334
00335
00336 num_removed++;
00337 cell_iter = this->mCells.erase(cell_iter);
00338 }
00339 else
00340 {
00341 ++cell_iter;
00342 }
00343 }
00344 return num_removed;
00345 }
00346
00347 template<unsigned DIM>
00348 void CaBasedCellPopulation<DIM>::UpdateCellLocations(double dt)
00349 {
00350
00352 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00353 cell_iter != this->mCells.end();
00354 ++cell_iter)
00355 {
00356
00357 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00358
00359
00360 std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
00361 std::vector<double> neighbouring_node_propensities;
00362 std::vector<unsigned> neighbouring_node_indices_vector;
00363
00364 if (!neighbouring_node_indices.empty())
00365 {
00366 unsigned num_neighbours = neighbouring_node_indices.size();
00367 double probability_of_not_moving = 1.0;
00368
00369 for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00370 iter != neighbouring_node_indices.end();
00371 ++iter)
00372 {
00373 double probability_of_moving = 0.0;
00374
00375 neighbouring_node_indices_vector.push_back(*iter);
00376
00377 if (IsSiteAvailable(*iter, *cell_iter))
00378 {
00379
00380 for (typename std::vector<boost::shared_ptr<AbstractCaUpdateRule<DIM> > >::iterator iterRule = mUpdateRuleCollection.begin();
00381 iterRule != mUpdateRuleCollection.end();
00382 ++iterRule)
00383 {
00384 probability_of_moving += (*iterRule)->EvaluateProbability(node_index, *iter, *this, dt, 1, *cell_iter);
00385 if (probability_of_moving < 0)
00386 {
00387 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");
00388 }
00389
00390 if (probability_of_moving > 1)
00391 {
00392 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");
00393 }
00394 }
00395
00396 probability_of_not_moving -= probability_of_moving;
00397 neighbouring_node_propensities.push_back(probability_of_moving);
00398 }
00399 else
00400 {
00401 neighbouring_node_propensities.push_back(0.0);
00402 }
00403 }
00404 if (probability_of_not_moving < 0)
00405 {
00406 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");
00407 }
00408
00409
00410 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00411 double random_number = p_gen->ranf();
00412
00413 double total_probability = 0.0;
00414 for (unsigned counter=0; counter<num_neighbours; counter++)
00415 {
00416 total_probability += neighbouring_node_propensities[counter];
00417 if (total_probability >= random_number)
00418 {
00419
00420 unsigned chosen_neighbour_location_index = neighbouring_node_indices_vector[counter];
00421 this->MoveCellInLocationMap((*cell_iter), node_index, chosen_neighbour_location_index);
00422 break;
00423 }
00424 }
00425
00426 }
00427 else
00428 {
00429
00430 NEVER_REACHED;
00431 }
00432 }
00433 }
00434
00435 template<unsigned DIM>
00436 bool CaBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell)
00437 {
00438 return false;
00439 }
00440
00441 template<unsigned DIM>
00442 void CaBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00443 {
00444 }
00445
00446 template<unsigned DIM>
00447 void CaBasedCellPopulation<DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<DIM, DIM> > pPopulationWriter)
00448 {
00449 pPopulationWriter->Visit(this);
00450 }
00451
00452 template<unsigned DIM>
00453 void CaBasedCellPopulation<DIM>::AcceptPopulationCountWriter(boost::shared_ptr<AbstractCellPopulationCountWriter<DIM, DIM> > pPopulationCountWriter)
00454 {
00455 pPopulationCountWriter->Visit(this);
00456 }
00457
00458 template<unsigned DIM>
00459 void CaBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00460 {
00461 pCellWriter->VisitCell(pCell, this);
00462 }
00463
00464 template<unsigned DIM>
00465 void CaBasedCellPopulation<DIM>::OpenWritersFiles(OutputFileHandler& rOutputFileHandler)
00466 {
00467 if (this->mOutputResultsForChasteVisualizer)
00468 {
00469 if (!this-> template HasWriter<CellLocationIndexWriter>())
00470 {
00471 this-> template AddCellWriter<CellLocationIndexWriter>();
00472 }
00473 }
00474
00475 AbstractCellPopulation<DIM>::OpenWritersFiles(rOutputFileHandler);
00476 }
00477
00478 template<unsigned DIM>
00479 double CaBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00480 {
00481 double cell_volume = 1.0;
00482 return cell_volume;
00483 }
00484
00485 template<unsigned DIM>
00486 double CaBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00487 {
00488 double width = this->mrMesh.GetWidth(rDimension);
00489 return width;
00490 }
00491
00492 template<unsigned DIM>
00493 void CaBasedCellPopulation<DIM>::AddUpdateRule(boost::shared_ptr<AbstractCaUpdateRule<DIM> > pUpdateRule)
00494 {
00495 mUpdateRuleCollection.push_back(pUpdateRule);
00496 }
00497
00498 template<unsigned DIM>
00499 void CaBasedCellPopulation<DIM>::RemoveAllUpdateRules()
00500 {
00501 mUpdateRuleCollection.clear();
00502 }
00503
00504 template<unsigned DIM>
00505 const std::vector<boost::shared_ptr<AbstractCaUpdateRule<DIM> > >& CaBasedCellPopulation<DIM>::rGetUpdateRuleCollection() const
00506 {
00507 return mUpdateRuleCollection;
00508 }
00509
00510 template<unsigned DIM>
00511 void CaBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00512 {
00513
00514 AbstractOnLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00515 }
00516
00517 template<unsigned DIM>
00518 void CaBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00519 {
00520 #ifdef CHASTE_VTK
00521
00522 unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
00523 std::stringstream time;
00524 time << num_timesteps;
00525
00526
00527 unsigned num_cells = this->GetNumRealCells();
00528
00529
00530 unsigned num_cell_data_items = 0u;
00531 if (num_cells > 0u)
00532 {
00533 num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00534
00535 }
00536 std::vector<std::vector<double> > cell_data;
00537 for (unsigned var=0; var<num_cell_data_items; var++)
00538 {
00539 std::vector<double> cell_data_var(num_cells);
00540 cell_data.push_back(cell_data_var);
00541 }
00542
00543
00544 VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
00545
00546
00547 unsigned num_sites = this->mrMesh.GetNumNodes();
00548 boost::scoped_array<unsigned> number_of_cells_at_site(new unsigned[num_sites]);
00549 for (unsigned i=0; i<num_sites; i++)
00550 {
00551 number_of_cells_at_site[i] = 0;
00552 }
00553
00554
00555 std::vector<Node<DIM>*> nodes;
00556 unsigned node_index = 0;
00557 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00558 cell_iter != this->mCells.end();
00559 ++cell_iter)
00560 {
00561
00562 unsigned location_index = this->GetLocationIndexUsingCell(*cell_iter);
00563 number_of_cells_at_site[location_index]++;
00564 assert(number_of_cells_at_site[location_index] <= mLatticeCarryingCapacity);
00565
00566
00567 c_vector<double, DIM> coords;
00568 coords = this->mrMesh.GetNode(location_index)->rGetLocation();
00569
00570
00571 if (mLatticeCarryingCapacity > 1)
00572 {
00573 c_vector<double, DIM> offset;
00574
00575 if (DIM == 2)
00576 {
00577 double angle = (double)number_of_cells_at_site[location_index]*2.0*M_PI/(double)mLatticeCarryingCapacity;
00578 offset[0] = 0.2*sin(angle);
00579 offset[1] = 0.2*cos(angle);
00580 }
00581 else
00582 {
00583 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00584 for (unsigned i=0; i<DIM; i++)
00585 {
00586 offset[i] = p_gen->ranf();
00587 }
00588 }
00589
00590 for (unsigned i=0; i<DIM; i++)
00591 {
00592 coords[i] += offset[i];
00593 }
00594 }
00595
00596 nodes.push_back(new Node<DIM>(node_index, coords, false));
00597 node_index++;
00598 }
00599
00600
00601 for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
00602 cell_writer_iter != this->mCellWriters.end();
00603 ++cell_writer_iter)
00604 {
00605
00606
00607 std::vector<double> vtk_cell_data(num_cells, -1.0);
00608
00609
00610 unsigned cell_index = 0;
00611 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00612 cell_iter != this->mCells.end();
00613 ++cell_iter)
00614 {
00615
00616 vtk_cell_data[cell_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
00617 cell_index++;
00618 }
00619
00620 mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
00621 }
00622
00623
00624
00625
00626
00627
00628 NodesOnlyMesh<DIM> temp_mesh;
00629 temp_mesh.ConstructNodesWithoutMesh(nodes, 1.5);
00630 mesh_writer.WriteFilesUsingMesh(temp_mesh);
00631
00632 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
00633 *(this->mpVtkMetaFile) << num_timesteps;
00634 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00635 *(this->mpVtkMetaFile) << num_timesteps;
00636 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00637
00638
00639 for (unsigned i=0; i<nodes.size(); i++)
00640 {
00641 delete nodes[i];
00642 }
00643 #endif //CHASTE_VTK
00644 }
00645
00646
00647 template class CaBasedCellPopulation<1>;
00648 template class CaBasedCellPopulation<2>;
00649 template class CaBasedCellPopulation<3>;
00650
00651
00652 #include "SerializationExportWrapperForCpp.hpp"
00653 EXPORT_TEMPLATE_CLASS_SAME_DIMS(CaBasedCellPopulation)