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 #include "NodeBasedCellPopulation.hpp"
00030 #include "CellwiseData.hpp"
00031 #include "VtkMeshWriter.hpp"
00032
00033 template<unsigned DIM>
00034 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh,
00035 std::vector<CellPtr>& rCells,
00036 const std::vector<unsigned> locationIndices,
00037 bool deleteMesh)
00038 : AbstractCentreBasedCellPopulation<DIM>(rCells, locationIndices),
00039 mrMesh(rMesh),
00040 mpBoxCollection(NULL),
00041 mDeleteMesh(deleteMesh),
00042 mMechanicsCutOffLength(DBL_MAX)
00043 {
00044 Validate();
00045 }
00046
00047 template<unsigned DIM>
00048 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh)
00049 : AbstractCentreBasedCellPopulation<DIM>(),
00050 mrMesh(rMesh),
00051 mpBoxCollection(NULL),
00052 mDeleteMesh(true),
00053 mMechanicsCutOffLength(DBL_MAX)
00054 {
00055
00056 }
00057
00058 template<unsigned DIM>
00059 NodeBasedCellPopulation<DIM>::~NodeBasedCellPopulation()
00060 {
00061 Clear();
00062 if (mDeleteMesh)
00063 {
00064 delete &mrMesh;
00065 }
00066 }
00067
00068 template<unsigned DIM>
00069 NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh()
00070 {
00071 return mrMesh;
00072 }
00073
00074 template<unsigned DIM>
00075 const NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh() const
00076 {
00077 return mrMesh;
00078 }
00079
00080 template<unsigned DIM>
00081 void NodeBasedCellPopulation<DIM>::Clear()
00082 {
00083 delete mpBoxCollection;
00084 mpBoxCollection = NULL;
00085 mNodePairs.clear();
00086 }
00087
00088 template<unsigned DIM>
00089 void NodeBasedCellPopulation<DIM>::Validate()
00090 {
00091 std::vector<bool> validated_node(GetNumNodes());
00092 for (unsigned i=0; i<validated_node.size(); i++)
00093 {
00094 validated_node[i] = false;
00095 }
00096
00097 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
00098 {
00099 unsigned node_index = this->mCellLocationMap[(*cell_iter).get()];
00100 validated_node[node_index] = true;
00101 }
00102
00103 for (unsigned i=0; i<validated_node.size(); i++)
00104 {
00105 if (!validated_node[i])
00106 {
00107 EXCEPTION("Node " << i << " does not appear to have a cell associated with it");
00108 }
00109 }
00110 }
00111
00112 template<unsigned DIM>
00113 void NodeBasedCellPopulation<DIM>::SplitUpIntoBoxes(double cutOffLength, c_vector<double, 2*DIM> domainSize)
00114 {
00115 mpBoxCollection = new BoxCollection<DIM>(cutOffLength, domainSize);
00116 mpBoxCollection->SetupLocalBoxesHalfOnly();
00117
00118 for (unsigned i=0; i<mrMesh.GetNumNodes(); i++)
00119 {
00120 unsigned box_index = mpBoxCollection->CalculateContainingBox(this->GetNode(i));
00121 mpBoxCollection->rGetBox(box_index).AddNode(this->GetNode(i));
00122 }
00123 }
00124
00125 template<unsigned DIM>
00126 void NodeBasedCellPopulation<DIM>::FindMaxAndMin()
00127 {
00128 c_vector<double, DIM> min_posn;
00129 c_vector<double, DIM> max_posn;
00130 for (unsigned i=0; i<DIM; i++)
00131 {
00132 min_posn(i) = DBL_MAX;
00133 max_posn(i) = -DBL_MAX;
00134 }
00135
00136 for (unsigned i=0; i<mrMesh.GetNumNodes(); i++)
00137 {
00138 c_vector<double, DIM> posn = this->GetNode(i)->rGetLocation();
00139
00140 for (unsigned j=0; j<DIM; j++)
00141 {
00142 if (posn(j) > max_posn(j))
00143 {
00144 max_posn(j) = posn(j);
00145 }
00146 if (posn(j) < min_posn(j))
00147 {
00148 min_posn(j) = posn(j);
00149 }
00150 }
00151 }
00152
00153 for (unsigned i=0; i<DIM; i++)
00154 {
00155 assert(min_posn(i) != DBL_MAX);
00156 mMinSpatialPositions(i) = min_posn(i);
00157
00158 assert(max_posn(i) != -DBL_MAX);
00159 mMaxSpatialPositions(i) = max_posn(i);
00160 }
00161 }
00162
00163 template<unsigned DIM>
00164 Node<DIM>* NodeBasedCellPopulation<DIM>::GetNode(unsigned index)
00165 {
00166 return mrMesh.GetNode(index);
00167 }
00168
00169 template<unsigned DIM>
00170 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
00171 {
00172 mrMesh.GetNode(nodeIndex)->SetPoint(rNewLocation);
00173 }
00174
00175 template<unsigned DIM>
00176 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00177 {
00178 NodeMap map(mrMesh.GetNumAllNodes());
00179 mrMesh.ReMesh(map);
00180
00181 if (!map.IsIdentityMap())
00182 {
00183
00184 std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
00185
00186
00187 this->mLocationCellMap.clear();
00188 this->mCellLocationMap.clear();
00189
00190 for (std::list<CellPtr>::iterator it = this->mCells.begin();
00191 it != this->mCells.end();
00192 ++it)
00193 {
00194 unsigned old_node_index = old_map[(*it).get()];
00195
00196
00197 assert(!map.IsDeleted(old_node_index));
00198
00199 unsigned new_node_index = map.GetNewIndex(old_node_index);
00200 this->mLocationCellMap[new_node_index] = *it;
00201 this->mCellLocationMap[(*it).get()] = new_node_index;
00202 }
00203
00204 this->Validate();
00205 }
00206
00207 mrMesh.SetMeshHasChangedSinceLoading();
00208
00209 if (mpBoxCollection != NULL)
00210 {
00211 delete mpBoxCollection;
00212 }
00213
00214 FindMaxAndMin();
00215
00216
00217 c_vector<double, 2*DIM> domain_size;
00218 for (unsigned i=0; i<DIM; i++)
00219 {
00220 domain_size(2*i) = mMinSpatialPositions(i);
00221 domain_size(2*i+1) = mMaxSpatialPositions(i);
00222 }
00223
00224 if (mMechanicsCutOffLength == DBL_MAX)
00225 {
00226 std::string error = std::string("NodeBasedCellPopulation cannot create boxes if the cut-off length has not been set - ")
00227 + std::string("Call SetMechanicsCutOffLength on the CellPopulation ensuring it is larger than GetCutOffLength() on the force law");
00228 EXCEPTION(error);
00229 }
00230
00231
00232
00233
00234
00235
00236 SplitUpIntoBoxes(mMechanicsCutOffLength, domain_size);
00237
00238 std::vector<Node<DIM>*> nodes;
00239 for (unsigned index=0; index<mrMesh.GetNumNodes(); index++)
00240 {
00241 Node<DIM>* p_node = mrMesh.GetNode(index);
00242 nodes.push_back(p_node);
00243 }
00244 mpBoxCollection->CalculateNodePairs(nodes, mNodePairs);
00245 }
00246
00247 template<unsigned DIM>
00248 unsigned NodeBasedCellPopulation<DIM>::RemoveDeadCells()
00249 {
00250 unsigned num_removed = 0;
00251 for (std::list<CellPtr>::iterator it = this->mCells.begin();
00252 it != this->mCells.end();
00253 ++it)
00254 {
00255 if ((*it)->IsDead())
00256 {
00257
00258 num_removed++;
00259 mrMesh.DeleteNodePriorToReMesh(this->mCellLocationMap[(*it).get()]);
00260
00261
00262 unsigned location_index_of_removed_node = this->mCellLocationMap[(*it).get()];
00263 this->mCellLocationMap.erase((*it).get());
00264 this->mLocationCellMap.erase(location_index_of_removed_node);
00265
00266
00267 it = this->mCells.erase(it);
00268 --it;
00269 }
00270 }
00271
00272 return num_removed;
00273 }
00274
00275 template<unsigned DIM>
00276 unsigned NodeBasedCellPopulation<DIM>::AddNode(Node<DIM>* pNewNode)
00277 {
00278 return mrMesh.AddNode(pNewNode);
00279 }
00280
00281 template<unsigned DIM>
00282 unsigned NodeBasedCellPopulation<DIM>::GetNumNodes()
00283 {
00284 return mrMesh.GetNumAllNodes();
00285 }
00286
00287 template<unsigned DIM>
00288 BoxCollection<DIM>* NodeBasedCellPopulation<DIM>::GetBoxCollection()
00289 {
00290 return mpBoxCollection;
00291 }
00292
00293 template<unsigned DIM>
00294 std::set< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
00295 {
00296 if (mNodePairs.empty())
00297 {
00298 EXCEPTION("No node pairs set up, rGetNodePairs probably called before Update");
00299 }
00300 return mNodePairs;
00301 }
00302
00303 template<unsigned DIM>
00304 void NodeBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00305 {
00306 *rParamsFile << "\t\t<MechanicsCutOffLength>" << mMechanicsCutOffLength << "</MechanicsCutOffLength>\n";
00307
00308
00309 AbstractCentreBasedCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00310 }
00311
00312 template<unsigned DIM>
00313 void NodeBasedCellPopulation<DIM>::SetMechanicsCutOffLength(double mechanicsCutOffLength)
00314 {
00315 assert(mechanicsCutOffLength > 0.0);
00316 mMechanicsCutOffLength = mechanicsCutOffLength;
00317 }
00318
00319 template<unsigned DIM>
00320 double NodeBasedCellPopulation<DIM>::GetMechanicsCutOffLength()
00321 {
00322 return mMechanicsCutOffLength;
00323 }
00324
00325 template<unsigned DIM>
00326 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00327 {
00328
00329 FindMaxAndMin();
00330
00331
00332 double width = mMaxSpatialPositions(rDimension) - mMinSpatialPositions(rDimension);
00333
00334 return width;
00335 }
00336
00337 template<unsigned DIM>
00338 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00339 {
00340
00341 c_vector<double, DIM> node_i_location = this->GetNode(index)->rGetLocation();
00342
00343
00344 double radius_of_cell_i = mrMesh.GetCellRadius(index);
00345
00346
00347 std::set<unsigned> neighbouring_node_indices;
00348 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00349 cell_iter != this->End();
00350 ++cell_iter)
00351 {
00352
00353 unsigned node_j_index = this->GetLocationIndexUsingCell(*cell_iter);
00354
00355
00356 if (node_j_index != index)
00357 {
00358
00359 c_vector<double, DIM> node_j_location = this->GetNode(node_j_index)->rGetLocation();
00360
00361
00362 c_vector<double, DIM> unit_vector = node_i_location - node_j_location;
00363
00364
00365 double distance_between_nodes = norm_2(unit_vector);
00366
00367
00368 double radius_of_cell_j = mrMesh.GetCellRadius(node_j_index);
00369
00370
00371 double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
00372 if (distance_between_nodes < max_interaction_distance)
00373 {
00374
00375 neighbouring_node_indices.insert(node_j_index);
00376 }
00377 }
00378 }
00379 return neighbouring_node_indices;
00380 }
00381
00382 template<unsigned DIM>
00383 void NodeBasedCellPopulation<DIM>::WriteCellVolumeResultsToFile()
00384 {
00385 assert(DIM==2 || DIM==3);
00386
00387
00388 *(this->mpCellVolumesFile) << SimulationTime::Instance()->GetTime() << " ";
00389
00390
00391 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin();
00392 cell_iter!=this->End(); ++cell_iter)
00393 {
00394
00395 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00396
00397
00398 *(this->mpCellVolumesFile) << node_index << " ";
00399
00400
00401 *(this->mpCellVolumesFile) << cell_iter->GetCellId() << " ";
00402
00403
00404 c_vector<double, DIM> node_location = this->GetNode(node_index)->rGetLocation();
00405 for (unsigned i=0; i<DIM; i++)
00406 {
00407 *(this->mpCellVolumesFile) << node_location[i] << " ";
00408 }
00409
00410
00411 double cell_radius = mrMesh.GetCellRadius(node_index);
00412
00413
00414 double cell_volume = 0.0;
00415
00416 if (DIM == 2)
00417 {
00418 cell_volume = M_PI*cell_radius*cell_radius;
00419 }
00420 else if (DIM == 3)
00421 {
00422 cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
00423 }
00424
00425 *(this->mpCellVolumesFile) << cell_volume << " ";
00426 }
00427 *(this->mpCellVolumesFile) << "\n";
00428 }
00429
00430 template<unsigned DIM>
00431 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile()
00432 {
00433 #ifdef CHASTE_VTK
00434 std::stringstream time;
00435 time << SimulationTime::Instance()->GetTimeStepsElapsed();
00436 VtkMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results_"+time.str(), false);
00437
00438 unsigned num_nodes = GetNumNodes();
00439 std::vector<double> cell_types(num_nodes);
00440 std::vector<double> cell_ancestors(num_nodes);
00441 std::vector<double> cell_mutation_states(num_nodes);
00442 std::vector<double> cell_ages(num_nodes);
00443 std::vector<double> cell_cycle_phases(num_nodes);
00444 std::vector<double> cell_radii(num_nodes);
00445 std::vector<std::vector<double> > cellwise_data;
00446
00447 if (CellwiseData<DIM>::Instance()->IsSetUp())
00448 {
00449 CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00450 unsigned num_variables = p_data->GetNumVariables();
00451 for (unsigned var=0; var<num_variables; var++)
00452 {
00453 std::vector<double> cellwise_data_var(num_nodes);
00454 cellwise_data.push_back(cellwise_data_var);
00455 }
00456 }
00457
00458
00459 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00460 cell_iter != this->End();
00461 ++cell_iter)
00462 {
00463
00464 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00465
00466 if (this->mOutputCellAncestors)
00467 {
00468 double ancestor_index = (cell_iter->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_iter->GetAncestor();
00469 cell_ancestors[node_index] = ancestor_index;
00470 }
00471 if (this->mOutputCellProliferativeTypes)
00472 {
00473 double cell_type = cell_iter->GetCellCycleModel()->GetCellProliferativeType();
00474 cell_types[node_index] = cell_type;
00475 }
00476 if (this->mOutputCellMutationStates)
00477 {
00478 double mutation_state = cell_iter->GetMutationState()->GetColour();
00479 cell_mutation_states[node_index] = mutation_state;
00480 }
00481 if (this->mOutputCellAges)
00482 {
00483 double age = cell_iter->GetAge();
00484 cell_ages[node_index] = age;
00485 }
00486 if (this->mOutputCellCyclePhases)
00487 {
00488 double cycle_phase = cell_iter->GetCellCycleModel()->GetCurrentCellCyclePhase();
00489 cell_cycle_phases[node_index] = cycle_phase;
00490 }
00491 if (this->mOutputCellVolumes)
00492 {
00493 double cell_radius = mrMesh.GetCellRadius(node_index);
00494 cell_radii[node_index] = cell_radius;
00495 }
00496 if (CellwiseData<DIM>::Instance()->IsSetUp())
00497 {
00498 CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00499 unsigned num_variables = p_data->GetNumVariables();
00500 for (unsigned var=0; var<num_variables; var++)
00501 {
00502 cellwise_data[var][node_index] = p_data->GetValue(*cell_iter, var);
00503 }
00504 }
00505 }
00506
00507 if (this->mOutputCellProliferativeTypes)
00508 {
00509 mesh_writer.AddPointData("Cell types", cell_types);
00510 }
00511 if (this->mOutputCellAncestors)
00512 {
00513 mesh_writer.AddPointData("Ancestors", cell_ancestors);
00514 }
00515 if (this->mOutputCellMutationStates)
00516 {
00517 mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00518 }
00519 if (this->mOutputCellAges)
00520 {
00521 mesh_writer.AddPointData("Ages", cell_ages);
00522 }
00523 if (this->mOutputCellCyclePhases)
00524 {
00525 mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00526 }
00527 if (this->mOutputCellVolumes)
00528 {
00529 mesh_writer.AddPointData("Cell radii", cell_radii);
00530 }
00531 if (CellwiseData<DIM>::Instance()->IsSetUp())
00532 {
00533 for (unsigned var=0; var<cellwise_data.size(); var++)
00534 {
00535 std::stringstream data_name;
00536 data_name << "Cellwise data " << var;
00537 std::vector<double> cellwise_data_var = cellwise_data[var];
00538 mesh_writer.AddPointData(data_name.str(), cellwise_data_var);
00539 }
00540 }
00541
00542 mesh_writer.WriteFilesUsingMesh(mrMesh);
00543
00544 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
00545 *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00546 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00547 *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00548 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00549 #endif //CHASTE_VTK
00550 }
00551
00552 template<unsigned DIM>
00553 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00554 {
00555 assert(pNewCell);
00556
00557
00558 CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00559 assert(p_created_cell == pNewCell);
00560
00561
00563 unsigned node_index = this->GetLocationIndexUsingCell(p_created_cell);
00564 mrMesh.SetCellRadius(node_index, 1.0);
00565
00566
00567 return p_created_cell;
00568 }
00569
00571
00573
00574 template class NodeBasedCellPopulation<1>;
00575 template class NodeBasedCellPopulation<2>;
00576 template class NodeBasedCellPopulation<3>;
00577
00578
00579 #include "SerializationExportWrapperForCpp.hpp"
00580 EXPORT_TEMPLATE_CLASS_SAME_DIMS(NodeBasedCellPopulation)