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 "MeshBasedCellPopulation.hpp"
00037 #include "TrianglesMeshWriter.hpp"
00038 #include "VtkMeshWriter.hpp"
00039 #include "CellBasedEventHandler.hpp"
00040 #include "ApoptoticCellProperty.hpp"
00041 #include "Cylindrical2dMesh.hpp"
00042 #include "NodesOnlyMesh.hpp"
00043 #include "Exception.hpp"
00044
00045
00046 #include "CellAgesWriter.hpp"
00047 #include "CellAncestorWriter.hpp"
00048 #include "CellProliferativePhasesWriter.hpp"
00049 #include "CellProliferativeTypesWriter.hpp"
00050 #include "CellVolumesWriter.hpp"
00051
00052
00053 #include "CellMutationStatesCountWriter.hpp"
00054 #include "CellPopulationElementWriter.hpp"
00055 #include "VoronoiDataWriter.hpp"
00056 #include "NodeVelocityWriter.hpp"
00057 #include "CellPopulationAreaWriter.hpp"
00058
00059 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00060 MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::MeshBasedCellPopulation(MutableMesh<ELEMENT_DIM,SPACE_DIM>& rMesh,
00061 std::vector<CellPtr>& rCells,
00062 const std::vector<unsigned> locationIndices,
00063 bool deleteMesh,
00064 bool validate)
00065 : AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>(rMesh, rCells, locationIndices),
00066 mpVoronoiTessellation(NULL),
00067 mDeleteMesh(deleteMesh),
00068 mUseAreaBasedDampingConstant(false),
00069 mAreaBasedDampingConstantParameter(0.1),
00070 mWriteVtkAsPoints(false),
00071 mOutputMeshInVtk(false),
00072 mHasVariableRestLength(false)
00073 {
00074 mpMutableMesh = static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>* >(&(this->mrMesh));
00075
00076 assert(this->mCells.size() <= this->mrMesh.GetNumNodes());
00077
00078 if (validate)
00079 {
00080 Validate();
00081 }
00082
00083
00084 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->rGetMesh().GetNodeIteratorBegin();
00085 node_iter != this->rGetMesh().GetNodeIteratorEnd();
00086 ++node_iter)
00087 {
00088 node_iter->ClearAppliedForce();
00089 }
00090 }
00091
00092 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00093 MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::MeshBasedCellPopulation(MutableMesh<ELEMENT_DIM,SPACE_DIM>& rMesh)
00094 : AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>(rMesh)
00095 {
00096 mpMutableMesh = static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>* >(&(this->mrMesh));
00097 mpVoronoiTessellation = NULL;
00098 mDeleteMesh = true;
00099 }
00100
00101 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00102 MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::~MeshBasedCellPopulation()
00103 {
00104 delete mpVoronoiTessellation;
00105
00106 if (mDeleteMesh)
00107 {
00108 delete &this->mrMesh;
00109 }
00110 }
00111
00112 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00113 bool MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::UseAreaBasedDampingConstant()
00114 {
00115 return mUseAreaBasedDampingConstant;
00116 }
00117
00118 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00119 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetAreaBasedDampingConstant(bool useAreaBasedDampingConstant)
00120 {
00121 assert(SPACE_DIM==2);
00122 mUseAreaBasedDampingConstant = useAreaBasedDampingConstant;
00123 }
00124
00125 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00126 unsigned MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddNode(Node<SPACE_DIM>* pNewNode)
00127 {
00128 return mpMutableMesh->AddNode(pNewNode);
00129 }
00130
00131 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00132 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetNode(unsigned nodeIndex, ChastePoint<SPACE_DIM>& rNewLocation)
00133 {
00134 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).SetNode(nodeIndex, rNewLocation, false);
00135 }
00136
00137 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00138 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetDampingConstant(unsigned nodeIndex)
00139 {
00140 double damping_multiplier = AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetDampingConstant(nodeIndex);
00141
00142 if (mUseAreaBasedDampingConstant)
00143 {
00153 assert(SPACE_DIM==2);
00154
00155 double rest_length = 1.0;
00156 double d0 = mAreaBasedDampingConstantParameter;
00157
00163 double d1 = 2.0*(1.0 - d0)/(sqrt(3.0)*rest_length*rest_length);
00164
00165 double area_cell = GetVolumeOfVoronoiElement(nodeIndex);
00166
00172 assert(area_cell < 1000);
00173
00174 damping_multiplier = d0 + area_cell*d1;
00175 }
00176
00177 return damping_multiplier;
00178 }
00179
00180 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00181 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::Validate()
00182 {
00183 std::vector<bool> validated_node = std::vector<bool>(this->GetNumNodes(), false);
00184
00185 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
00186 {
00187 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00188 validated_node[node_index] = true;
00189 }
00190
00191 for (unsigned i=0; i<validated_node.size(); i++)
00192 {
00193 if (!validated_node[i])
00194 {
00195 EXCEPTION("Node " << i << " does not appear to have a cell associated with it");
00196 }
00197 }
00198 }
00199
00200 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00201 MutableMesh<ELEMENT_DIM,SPACE_DIM>& MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::rGetMesh()
00202 {
00203 return *mpMutableMesh;
00204 }
00205
00206 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00207 const MutableMesh<ELEMENT_DIM,SPACE_DIM>& MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::rGetMesh() const
00208 {
00209 return *mpMutableMesh;
00210 }
00211
00212 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00213 unsigned MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::RemoveDeadCells()
00214 {
00215 unsigned num_removed = 0;
00216 for (std::list<CellPtr>::iterator it = this->mCells.begin();
00217 it != this->mCells.end();
00218 )
00219 {
00220 if ((*it)->IsDead())
00221 {
00222
00223 std::vector<const std::pair<CellPtr,CellPtr>*> pairs_to_remove;
00224 for (std::set<std::pair<CellPtr,CellPtr> >::iterator it1 = this->mMarkedSprings.begin();
00225 it1 != this->mMarkedSprings.end();
00226 ++it1)
00227 {
00228 const std::pair<CellPtr,CellPtr>& r_pair = *it1;
00229
00230 for (unsigned i=0; i<2; i++)
00231 {
00232 CellPtr p_cell = (i==0 ? r_pair.first : r_pair.second);
00233
00234 if (p_cell == *it)
00235 {
00236
00237 pairs_to_remove.push_back(&r_pair);
00238 break;
00239 }
00240 }
00241 }
00242
00243
00244 for (std::vector<const std::pair<CellPtr,CellPtr>* >::iterator pair_it = pairs_to_remove.begin();
00245 pair_it != pairs_to_remove.end();
00246 ++pair_it)
00247 {
00248 this->mMarkedSprings.erase(**pair_it);
00249 }
00250
00251
00252 num_removed++;
00253 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).DeleteNodePriorToReMesh(this->GetLocationIndexUsingCell((*it)));
00254
00255
00256 unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*it));
00257 this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*it));
00258
00259
00260 it = this->mCells.erase(it);
00261 }
00262 else
00263 {
00264 ++it;
00265 }
00266 }
00267
00268 return num_removed;
00269 }
00270
00271 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00272 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::Update(bool hasHadBirthsOrDeaths)
00273 {
00275 bool output_node_velocities = (this-> template HasWriter<NodeVelocityWriter>());
00276
00277 std::map<unsigned, c_vector<double, SPACE_DIM> > old_node_applied_force_map;
00278 old_node_applied_force_map.clear();
00279 if (output_node_velocities)
00280 {
00281
00282
00283
00284
00285
00286 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
00287 node_iter != this->mrMesh.GetNodeIteratorEnd();
00288 ++node_iter)
00289 {
00290 unsigned node_index = node_iter->GetIndex();
00291 old_node_applied_force_map[node_index] = node_iter->rGetAppliedForce();
00292 }
00293 }
00294
00295 NodeMap node_map(this->mrMesh.GetNumAllNodes());
00296
00297
00298 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).ReMesh(node_map);
00299
00300 if (!node_map.IsIdentityMap())
00301 {
00302 UpdateGhostNodesAfterReMesh(node_map);
00303
00304
00305 std::map<Cell*, unsigned> old_cell_location_map = this->mCellLocationMap;
00306
00307
00308 this->mLocationCellMap.clear();
00309 this->mCellLocationMap.clear();
00310
00311 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
00312 {
00313 unsigned old_node_index = old_cell_location_map[(*it).get()];
00314
00315
00316 assert(!node_map.IsDeleted(old_node_index));
00317
00318 unsigned new_node_index = node_map.GetNewIndex(old_node_index);
00319 this->SetCellUsingLocationIndex(new_node_index,*it);
00320
00321 if (output_node_velocities)
00322 {
00323 this->GetNode(new_node_index)->AddAppliedForceContribution(old_node_applied_force_map[old_node_index]);
00324 }
00325 }
00326
00327 this->Validate();
00328 }
00329 else if (output_node_velocities)
00330 {
00331 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
00332 {
00333 unsigned node_index = this->mCellLocationMap[(*it).get()];
00334 this->GetNode(node_index)->AddAppliedForceContribution(old_node_applied_force_map[node_index]);
00335 }
00336 }
00337
00338
00339 std::vector<const std::pair<CellPtr,CellPtr>*> springs_to_remove;
00340 for (std::set<std::pair<CellPtr,CellPtr> >::iterator spring_it = this->mMarkedSprings.begin();
00341 spring_it != this->mMarkedSprings.end();
00342 ++spring_it)
00343 {
00344 CellPtr p_cell_1 = spring_it->first;
00345 CellPtr p_cell_2 = spring_it->second;
00346 Node<SPACE_DIM>* p_node_1 = this->GetNodeCorrespondingToCell(p_cell_1);
00347 Node<SPACE_DIM>* p_node_2 = this->GetNodeCorrespondingToCell(p_cell_2);
00348
00349 bool joined = false;
00350
00351
00352 std::set<unsigned> node2_elements = p_node_2->rGetContainingElementIndices();
00353 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node_1->ContainingElementsBegin();
00354 elem_iter != p_node_1->ContainingElementsEnd();
00355 ++elem_iter)
00356 {
00357 if (node2_elements.find(*elem_iter) != node2_elements.end())
00358 {
00359 joined = true;
00360 break;
00361 }
00362 }
00363
00364
00365 if (!joined)
00366 {
00367 springs_to_remove.push_back(&(*spring_it));
00368 }
00369 }
00370
00371
00372 for (std::vector<const std::pair<CellPtr,CellPtr>* >::iterator spring_it = springs_to_remove.begin();
00373 spring_it != springs_to_remove.end();
00374 ++spring_it)
00375 {
00376 this->mMarkedSprings.erase(**spring_it);
00377 }
00378
00379
00380 TessellateIfNeeded();
00381
00382 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).SetMeshHasChangedSinceLoading();
00383 }
00384
00385 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00386 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::TessellateIfNeeded()
00387 {
00388 if ((SPACE_DIM==2 || SPACE_DIM==3)&&(ELEMENT_DIM==SPACE_DIM))
00389 {
00390 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::TESSELLATION);
00391 if (mUseAreaBasedDampingConstant ||
00392 this-> template HasWriter<VoronoiDataWriter>() ||
00393 this-> template HasWriter<CellPopulationAreaWriter>() ||
00394 this-> template HasWriter<CellVolumesWriter>())
00395 {
00396 CreateVoronoiTessellation();
00397 }
00398 CellBasedEventHandler::EndEvent(CellBasedEventHandler::TESSELLATION);
00399 }
00400 }
00401
00402 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00403 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::DivideLongSprings(double springDivisionThreshold)
00404 {
00405
00406 assert(ELEMENT_DIM==2);
00407
00408 std::vector<c_vector<unsigned, 5> > new_nodes;
00409 new_nodes = rGetMesh().SplitLongEdges(springDivisionThreshold);
00410
00411
00412 for (unsigned index=0; index<new_nodes.size(); index++)
00413 {
00414
00415 unsigned new_node_index = new_nodes[index][0];
00416 unsigned node_a_index = new_nodes[index][1];
00417 unsigned node_b_index = new_nodes[index][2];
00418
00419 CellPtr p_neighbour_cell = this->GetCellUsingLocationIndex(node_a_index);
00420
00421
00422 CellPropertyCollection daughter_property_collection = p_neighbour_cell->rGetCellPropertyCollection();
00423
00424
00425 daughter_property_collection.RemoveProperty<CellId>();
00426
00427 CellPtr p_new_cell(new Cell(p_neighbour_cell->GetMutationState(),
00428 p_neighbour_cell->GetCellCycleModel()->CreateCellCycleModel(),
00429 false,
00430 daughter_property_collection));
00431
00432
00433 this->mCells.push_back(p_new_cell);
00434 this->AddCellUsingLocationIndex(new_node_index,p_new_cell);
00435
00436
00437
00438
00439 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(node_a_index, node_b_index);
00440 double old_rest_length = mSpringRestLengths[node_pair];
00441
00442 std::map<std::pair<unsigned,unsigned>, double>::iterator iter = mSpringRestLengths.find(node_pair);
00443 mSpringRestLengths.erase(iter);
00444
00445
00446 node_pair = this->CreateOrderedPair(node_a_index, new_node_index);
00447 mSpringRestLengths[node_pair] = 0.5*old_rest_length;
00448
00449 node_pair = this->CreateOrderedPair(node_b_index, new_node_index);
00450 mSpringRestLengths[node_pair] = 0.5*old_rest_length;
00451
00452
00453 for (unsigned pair_index=3; pair_index<5; pair_index++)
00454 {
00455 unsigned other_node_index = new_nodes[index][pair_index];
00456
00457 if (other_node_index != UNSIGNED_UNSET)
00458 {
00459 node_pair = this->CreateOrderedPair(other_node_index, new_node_index);
00460 double new_rest_length = rGetMesh().GetDistanceBetweenNodes(new_node_index, other_node_index);
00461 mSpringRestLengths[node_pair] = new_rest_length;
00462 }
00463 }
00464 }
00465 }
00466
00467 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00468 Node<SPACE_DIM>* MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetNode(unsigned index)
00469 {
00470 return this->mrMesh.GetNode(index);
00471 }
00472
00473 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00474 unsigned MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetNumNodes()
00475 {
00476 return this->mrMesh.GetNumAllNodes();
00477 }
00478
00479 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00480 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::UpdateGhostNodesAfterReMesh(NodeMap& rMap)
00481 {
00482 }
00483
00484 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00485 CellPtr MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddCell(CellPtr pNewCell, const c_vector<double,SPACE_DIM>& rCellDivisionVector, CellPtr pParentCell)
00486 {
00487 assert(pNewCell);
00488 assert(pParentCell);
00489
00490
00491 CellPtr p_created_cell = AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00492 assert(p_created_cell == pNewCell);
00493
00494
00495 std::pair<CellPtr,CellPtr> cell_pair = this->CreateCellPair(pParentCell, p_created_cell);
00496 this->MarkSpring(cell_pair);
00497
00498
00499 return p_created_cell;
00500 }
00501
00503
00505
00506 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00507 void MeshBasedCellPopulation<ELEMENT_DIM, SPACE_DIM>::OpenWritersFiles(const std::string& rDirectory)
00508 {
00509 if (this->mOutputResultsForChasteVisualizer)
00510 {
00511 if (!this-> template HasWriter<CellPopulationElementWriter>())
00512 {
00513 this-> template AddPopulationWriter<CellPopulationElementWriter>();
00514 }
00515 }
00516
00517 AbstractCentreBasedCellPopulation<ELEMENT_DIM, SPACE_DIM>::OpenWritersFiles(rDirectory);
00518 }
00519
00520 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00521 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::WriteResultsToFiles(const std::string& rDirectory)
00522 {
00523 if (SimulationTime::Instance()->GetTimeStepsElapsed() == 0 && this->mpVoronoiTessellation == NULL)
00524 {
00525 TessellateIfNeeded();
00526 }
00527
00528 AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::WriteResultsToFiles(rDirectory);
00529 }
00530
00531 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00532 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<ELEMENT_DIM, SPACE_DIM> > pPopulationWriter)
00533 {
00534 pPopulationWriter->Visit(this);
00535 }
00536
00537 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00538 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > pCellWriter, CellPtr pCell)
00539 {
00540 pCellWriter->VisitCell(pCell, this);
00541 }
00542
00543 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00544 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00545 {
00546 #ifdef CHASTE_VTK
00547 unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
00548 std::stringstream time;
00549 time << num_timesteps;
00550
00551 unsigned num_cells_from_mesh = GetNumNodes();
00552 if (!mWriteVtkAsPoints && (mpVoronoiTessellation != NULL))
00553 {
00554 num_cells_from_mesh = mpVoronoiTessellation->GetNumElements();
00555 }
00556
00557
00558 unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00559 std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
00560
00561 std::vector<std::vector<double> > cell_data;
00562 for (unsigned var=0; var<num_cell_data_items; var++)
00563 {
00564 std::vector<double> cell_data_var(num_cells_from_mesh);
00565 cell_data.push_back(cell_data_var);
00566 }
00567
00568 if (mOutputMeshInVtk)
00569 {
00570
00571 VtkMeshWriter<ELEMENT_DIM, SPACE_DIM> mesh_writer(rDirectory, "mesh_"+time.str(), false);
00572 mesh_writer.WriteFilesUsingMesh(rGetMesh());
00573 }
00574
00575 if (mWriteVtkAsPoints)
00576 {
00577
00578 VtkMeshWriter<SPACE_DIM, SPACE_DIM> cells_writer(rDirectory, "results_"+time.str(), false);
00579
00580
00581 unsigned num_cells = this->GetNumAllCells();
00582 for (typename std::set<boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
00583 cell_writer_iter != this->mCellWriters.end();
00584 ++cell_writer_iter)
00585 {
00586
00587 std::vector<double> vtk_cell_data(num_cells);
00588
00589
00590 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = this->Begin();
00591 cell_iter != this->End();
00592 ++cell_iter)
00593 {
00594
00595 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00596
00597
00598 vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
00599 }
00600
00601 cells_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
00602 }
00603
00604
00605 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = this->Begin();
00606 cell_iter != this->End();
00607 ++cell_iter)
00608 {
00609
00610 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00611
00612 for (unsigned var=0; var<num_cell_data_items; var++)
00613 {
00614 cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
00615 }
00616 }
00617 for (unsigned var=0; var<num_cell_data_items; var++)
00618 {
00619 cells_writer.AddPointData(cell_data_names[var], cell_data[var]);
00620 }
00621
00622
00623 {
00624 std::vector<Node<SPACE_DIM>* > nodes;
00625 for (unsigned index=0; index<this->mrMesh.GetNumNodes(); index++)
00626 {
00627 Node<SPACE_DIM>* p_node = this->mrMesh.GetNode(index);
00628 nodes.push_back(p_node);
00629 }
00630
00631 NodesOnlyMesh<SPACE_DIM> mesh;
00632 mesh.ConstructNodesWithoutMesh(nodes, 1.5);
00633 cells_writer.WriteFilesUsingMesh(mesh);
00634 }
00635
00636 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
00637 *(this->mpVtkMetaFile) << num_timesteps;
00638 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00639 *(this->mpVtkMetaFile) << num_timesteps;
00640 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00641 }
00642 else if (mpVoronoiTessellation != NULL)
00643 {
00644
00645 VertexMeshWriter<ELEMENT_DIM, SPACE_DIM> mesh_writer(rDirectory, "results", false);
00646 std::vector<double> cell_volumes(num_cells_from_mesh);
00647
00648
00649 unsigned num_cells = this->GetNumAllCells();
00650 for (typename std::set<boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
00651 cell_writer_iter != this->mCellWriters.end();
00652 ++cell_writer_iter)
00653 {
00654
00655 std::vector<double> vtk_cell_data(num_cells);
00656
00657
00658 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = mpVoronoiTessellation->GetElementIteratorBegin();
00659 elem_iter != mpVoronoiTessellation->GetElementIteratorEnd();
00660 ++elem_iter)
00661 {
00662
00663 unsigned elem_index = elem_iter->GetIndex();
00664
00665
00666 unsigned node_index = mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
00667 CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
00668
00669
00670 vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
00671 }
00672
00673 mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
00674 }
00675
00676
00677 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = mpVoronoiTessellation->GetElementIteratorBegin();
00678 elem_iter != mpVoronoiTessellation->GetElementIteratorEnd();
00679 ++elem_iter)
00680 {
00681
00682 unsigned elem_index = elem_iter->GetIndex();
00683
00684
00685 unsigned node_index = mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
00686 CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
00687
00688 for (unsigned var=0; var<num_cell_data_items; var++)
00689 {
00690 cell_data[var][elem_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
00691 }
00692 }
00693
00694 for (unsigned var=0; var<cell_data.size(); var++)
00695 {
00696 mesh_writer.AddCellData(cell_data_names[var], cell_data[var]);
00697 }
00698
00699 mesh_writer.WriteVtkUsingMesh(*mpVoronoiTessellation, time.str());
00700 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
00701 *(this->mpVtkMetaFile) << num_timesteps;
00702 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00703 *(this->mpVtkMetaFile) << num_timesteps;
00704 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00705 }
00706 #endif //CHASTE_VTK
00707 }
00708
00709 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00710 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetVolumeOfCell(CellPtr pCell)
00711 {
00712 double cell_volume = 0;
00713
00714 if (ELEMENT_DIM == SPACE_DIM)
00715 {
00716
00717 if (mpVoronoiTessellation == NULL)
00718 {
00719 CreateVoronoiTessellation();
00720 }
00721
00722
00723 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00724
00725
00726 try
00727 {
00728 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(node_index);
00729
00730
00731 cell_volume = mpVoronoiTessellation->GetVolumeOfElement(element_index);
00732 }
00733 catch (Exception&)
00734 {
00735
00736 cell_volume = DBL_MAX;
00737 }
00738 }
00739 else if (SPACE_DIM==3 && ELEMENT_DIM==2)
00740 {
00741 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00742
00743 Node<SPACE_DIM>* p_node = rGetMesh().GetNode(node_index);
00744
00745 assert(p_node->rGetContainingElementIndices().size()>0);
00746
00747 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node->ContainingElementsBegin();
00748 elem_iter != p_node->ContainingElementsEnd();
00749 ++elem_iter)
00750 {
00751 Element<ELEMENT_DIM,SPACE_DIM>* p_element = rGetMesh().GetElement(*elem_iter);
00752
00753 c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacob;
00754 double det;
00755
00756 p_element->CalculateJacobian(jacob, det);
00757
00758 cell_volume += fabs(p_element->GetVolume(det));
00759 }
00760
00761
00762 cell_volume /= 3.0;
00763 }
00764 else
00765 {
00766
00767 NEVER_REACHED;
00768 }
00769
00770 return cell_volume;
00771 }
00772
00773 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00774 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetWriteVtkAsPoints(bool writeVtkAsPoints)
00775 {
00776 mWriteVtkAsPoints = writeVtkAsPoints;
00777 }
00778
00779 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00780 bool MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetWriteVtkAsPoints()
00781 {
00782 return mWriteVtkAsPoints;
00783 }
00784
00785 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00786 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetOutputMeshInVtk(bool outputMeshInVtk)
00787 {
00788 mOutputMeshInVtk = outputMeshInVtk;
00789 }
00790
00791 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00792 bool MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetOutputMeshInVtk()
00793 {
00794 return mOutputMeshInVtk;
00795 }
00796
00798
00800
00801 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00802 Node<SPACE_DIM>* MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::GetNodeA()
00803 {
00804 return mEdgeIter.GetNodeA();
00805 }
00806
00807 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00808 Node<SPACE_DIM>* MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::GetNodeB()
00809 {
00810 return mEdgeIter.GetNodeB();
00811 }
00812
00813 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00814 CellPtr MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::GetCellA()
00815 {
00816 assert((*this) != mrCellPopulation.SpringsEnd());
00817 return mrCellPopulation.GetCellUsingLocationIndex(mEdgeIter.GetNodeA()->GetIndex());
00818 }
00819
00820 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00821 CellPtr MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::GetCellB()
00822 {
00823 assert((*this) != mrCellPopulation.SpringsEnd());
00824 return mrCellPopulation.GetCellUsingLocationIndex(mEdgeIter.GetNodeB()->GetIndex());
00825 }
00826
00827 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00828 bool MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::operator!=(const typename MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator& rOther)
00829 {
00830 return (mEdgeIter != rOther.mEdgeIter);
00831 }
00832
00833 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00834 typename MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator& MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::operator++()
00835 {
00836 bool edge_is_ghost = false;
00837
00838 do
00839 {
00840 ++mEdgeIter;
00841 if (*this != mrCellPopulation.SpringsEnd())
00842 {
00843 bool a_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeA()->GetIndex());
00844 bool b_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeB()->GetIndex());
00845
00846 edge_is_ghost = (a_is_ghost || b_is_ghost);
00847 }
00848 }
00849 while (*this!=mrCellPopulation.SpringsEnd() && edge_is_ghost);
00850
00851 return (*this);
00852 }
00853
00854 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00855 MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator::SpringIterator(
00856 MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation,
00857 typename MutableMesh<ELEMENT_DIM,SPACE_DIM>::EdgeIterator edgeIter)
00858 : mrCellPopulation(rCellPopulation),
00859 mEdgeIter(edgeIter)
00860 {
00861 if (mEdgeIter!=static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation.mrMesh))->EdgesEnd())
00862 {
00863 bool a_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeA()->GetIndex());
00864 bool b_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeB()->GetIndex());
00865
00866 if (a_is_ghost || b_is_ghost)
00867 {
00868 ++(*this);
00869 }
00870 }
00871 }
00872
00873 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00874 typename MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringsBegin()
00875 {
00876 return SpringIterator(*this, static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).EdgesBegin());
00877 }
00878
00879 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00880 typename MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringIterator MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SpringsEnd()
00881 {
00882 return SpringIterator(*this, static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).EdgesEnd());
00883 }
00884
00888 template<>
00889 void MeshBasedCellPopulation<2>::CreateVoronoiTessellation()
00890 {
00891 delete mpVoronoiTessellation;
00892
00893
00894 bool is_mesh_periodic = false;
00895 if (dynamic_cast<Cylindrical2dMesh*>(&mrMesh))
00896 {
00897 is_mesh_periodic = true;
00898 }
00899
00900 mpVoronoiTessellation = new VertexMesh<2, 2>(static_cast<MutableMesh<2, 2> &>((this->mrMesh)), is_mesh_periodic);
00901 }
00902
00906 template<>
00907 void MeshBasedCellPopulation<2,3>::CreateVoronoiTessellation()
00908 {
00909
00910 NEVER_REACHED;
00911 }
00912
00918 template<>
00919 void MeshBasedCellPopulation<3>::CreateVoronoiTessellation()
00920 {
00921 delete mpVoronoiTessellation;
00922 mpVoronoiTessellation = new VertexMesh<3, 3>(static_cast<MutableMesh<3, 3> &>((this->mrMesh)));
00923 }
00924
00929 template<>
00930 void MeshBasedCellPopulation<1, 1>::CreateVoronoiTessellation()
00931 {
00932
00933 NEVER_REACHED;
00934 }
00935
00940 template<>
00941 void MeshBasedCellPopulation<1, 2>::CreateVoronoiTessellation()
00942 {
00943
00944 NEVER_REACHED;
00945 }
00946
00951 template<>
00952 void MeshBasedCellPopulation<1, 3>::CreateVoronoiTessellation()
00953 {
00954
00955 NEVER_REACHED;
00956 }
00957
00958 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00959 VertexMesh<ELEMENT_DIM,SPACE_DIM>* MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetVoronoiTessellation()
00960 {
00961 assert(mpVoronoiTessellation!=NULL);
00962 return mpVoronoiTessellation;
00963 }
00964
00965 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00966 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetVolumeOfVoronoiElement(unsigned index)
00967 {
00968 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index);
00969 double volume = mpVoronoiTessellation->GetVolumeOfElement(element_index);
00970 return volume;
00971 }
00972
00973 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00974 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetSurfaceAreaOfVoronoiElement(unsigned index)
00975 {
00976 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index);
00977 double surface_area = mpVoronoiTessellation->GetSurfaceAreaOfElement(element_index);
00978 return surface_area;
00979 }
00980
00981 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00982 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetVoronoiEdgeLength(unsigned index1, unsigned index2)
00983 {
00984 unsigned element_index1 = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index1);
00985 unsigned element_index2 = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index2);
00986 try
00987 {
00988 double edge_length = mpVoronoiTessellation->GetEdgeLength(element_index1, element_index2);
00989 return edge_length;
00990 }
00991 catch (Exception&)
00992 {
00993
00994 EXCEPTION("Spring iterator tried to calculate interaction between degenerate cells on the boundary of the mesh. Have you set ghost layers correctly?");
00995 }
00996 }
00997
00998 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00999 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::CheckCellPointers()
01000 {
01001 bool res = true;
01002 for (std::list<CellPtr>::iterator it=this->mCells.begin();
01003 it!=this->mCells.end();
01004 ++it)
01005 {
01006 CellPtr p_cell = *it;
01007 assert(p_cell);
01008 AbstractCellCycleModel* p_model = p_cell->GetCellCycleModel();
01009 assert(p_model);
01010
01011
01012 unsigned node_index = this->GetLocationIndexUsingCell(p_cell);
01013 std::cout << "Cell at node " << node_index << " addr " << p_cell << std::endl << std::flush;
01014 CellPtr p_cell_in_cell_population = this->GetCellUsingLocationIndex(node_index);
01015 #define COVERAGE_IGNORE //Debugging code. Shouldn't fail under normal conditions
01016 if (p_cell_in_cell_population != p_cell)
01017 {
01018 std::cout << " Mismatch with cell population" << std::endl << std::flush;
01019 res = false;
01020 }
01021
01022
01023 if (p_model->GetCell() != p_cell)
01024 {
01025 std::cout << " Mismatch with cycle model" << std::endl << std::flush;
01026 res = false;
01027 }
01028 }
01029 UNUSED_OPT(res);
01030 assert(res);
01031 #undef COVERAGE_IGNORE
01032
01033 res = true;
01034 for (std::set<std::pair<CellPtr,CellPtr> >::iterator it1 = this->mMarkedSprings.begin();
01035 it1 != this->mMarkedSprings.end();
01036 ++it1)
01037 {
01038 const std::pair<CellPtr,CellPtr>& r_pair = *it1;
01039
01040 for (unsigned i=0; i<2; i++)
01041 {
01042 CellPtr p_cell = (i==0 ? r_pair.first : r_pair.second);
01043
01044 assert(p_cell);
01045 AbstractCellCycleModel* p_model = p_cell->GetCellCycleModel();
01046 assert(p_model);
01047 unsigned node_index = this->GetLocationIndexUsingCell(p_cell);
01048 std::cout << "Cell at node " << node_index << " addr " << p_cell << std::endl << std::flush;
01049
01050 #define COVERAGE_IGNORE //Debugging code. Shouldn't fail under normal conditions
01051
01052 if (p_cell->IsDead())
01053 {
01054 std::cout << " Cell is dead" << std::endl << std::flush;
01055 res = false;
01056 }
01057
01058
01059 CellPtr p_cell_in_cell_population = this->GetCellUsingLocationIndex(node_index);
01060 if (p_cell_in_cell_population != p_cell)
01061 {
01062 std::cout << " Mismatch with cell population" << std::endl << std::flush;
01063 res = false;
01064 }
01065
01066
01067 if (p_model->GetCell() != p_cell)
01068 {
01069 std::cout << " Mismatch with cycle model" << std::endl << std::flush;
01070 res = false;
01071 }
01072 }
01073 #undef COVERAGE_IGNORE
01074 }
01075 assert(res);
01076 }
01077
01078 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01079 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetAreaBasedDampingConstantParameter()
01080 {
01081 return mAreaBasedDampingConstantParameter;
01082 }
01083
01084 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01085 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetAreaBasedDampingConstantParameter(double areaBasedDampingConstantParameter)
01086 {
01087 assert(areaBasedDampingConstantParameter >= 0.0);
01088 mAreaBasedDampingConstantParameter = areaBasedDampingConstantParameter;
01089 }
01090
01091 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01092 std::vector< std::pair<Node<SPACE_DIM>*, Node<SPACE_DIM>* > >& MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::rGetNodePairs()
01093 {
01094
01095 NEVER_REACHED;
01096 return mNodePairs;
01097 }
01098
01099 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01100 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
01101 {
01102 *rParamsFile << "\t\t<UseAreaBasedDampingConstant>" << mUseAreaBasedDampingConstant << "</UseAreaBasedDampingConstant>\n";
01103 *rParamsFile << "\t\t<AreaBasedDampingConstantParameter>" << mAreaBasedDampingConstantParameter << "</AreaBasedDampingConstantParameter>\n";
01104 *rParamsFile << "\t\t<WriteVtkAsPoints>" << mWriteVtkAsPoints << "</WriteVtkAsPoints>\n";
01105 *rParamsFile << "\t\t<OutputMeshInVtk>" << mOutputMeshInVtk << "</OutputMeshInVtk>\n";
01106 *rParamsFile << "\t\t<HasVariableRestLength>" << mHasVariableRestLength << "</HasVariableRestLength>\n";
01107
01108
01109 AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::OutputCellPopulationParameters(rParamsFile);
01110 }
01111
01112 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01113 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetWidth(const unsigned& rDimension)
01114 {
01115
01116 double width = this->mrMesh.GetWidth(rDimension);
01117 return width;
01118 }
01119
01120 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01121 std::set<unsigned> MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetNeighbouringNodeIndices(unsigned index)
01122 {
01123
01124 Node<SPACE_DIM>* p_node = this->mrMesh.GetNode(index);
01125
01126
01127 std::set<unsigned> neighbouring_node_indices;
01128 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node->ContainingElementsBegin();
01129 elem_iter != p_node->ContainingElementsEnd();
01130 ++elem_iter)
01131 {
01132
01133 Element<ELEMENT_DIM,SPACE_DIM>* p_element = static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).GetElement(*elem_iter);
01134
01135
01136 for (unsigned i=0; i<p_element->GetNumNodes(); i++)
01137 {
01138
01139 unsigned node_index = p_element->GetNodeGlobalIndex(i);
01140 if (node_index != index)
01141 {
01142 neighbouring_node_indices.insert(node_index);
01143 }
01144 }
01145 }
01146 return neighbouring_node_indices;
01147 }
01148
01149 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01150 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::CalculateRestLengths()
01151 {
01152 mSpringRestLengths.clear();
01153
01154
01155 for (SpringIterator spring_iterator = SpringsBegin();
01156 spring_iterator != SpringsEnd();
01157 ++spring_iterator)
01158 {
01159
01160 Node<SPACE_DIM>* p_nodeA = spring_iterator.GetNodeA();
01161 Node<SPACE_DIM>* p_nodeB = spring_iterator.GetNodeB();
01162
01163 unsigned nodeA_global_index = p_nodeA->GetIndex();
01164 unsigned nodeB_global_index = p_nodeB->GetIndex();
01165
01166
01167 double separation = rGetMesh().GetDistanceBetweenNodes(nodeA_global_index, nodeB_global_index);
01168
01169
01170 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(nodeA_global_index, nodeB_global_index);
01171
01172 mSpringRestLengths[node_pair] = separation;
01173 }
01174 mHasVariableRestLength = true;
01175 }
01176
01177 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01178 double MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::GetRestLength(unsigned indexA, unsigned indexB)
01179 {
01180 if (mHasVariableRestLength)
01181 {
01182 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(indexA, indexB);
01183 std::map<std::pair<unsigned,unsigned>, double>::const_iterator iter = mSpringRestLengths.find(node_pair);
01184
01185 if (iter != mSpringRestLengths.end())
01186 {
01187
01188 return iter->second;
01189 }
01190 else
01191 {
01192 EXCEPTION("Tried to get a rest length of an edge that doesn't exist. You can only use variable rest lengths if SetUpdateCellPopulationRule is set on the simulation.");
01193 }
01194 }
01195 else
01196 {
01197 return 1.0;
01198 }
01199 }
01200
01201 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01202 void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetRestLength(unsigned indexA, unsigned indexB, double restLength)
01203 {
01204 if (mHasVariableRestLength)
01205 {
01206 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(indexA, indexB);
01207 std::map<std::pair<unsigned,unsigned>, double>::iterator iter = mSpringRestLengths.find(node_pair);
01208
01209 if (iter != mSpringRestLengths.end())
01210 {
01211
01212 iter->second = restLength;
01213 }
01214 else
01215 {
01216 EXCEPTION("Tried to set the rest length of an edge not in the mesh.");
01217 }
01218 }
01219 else
01220 {
01221 EXCEPTION("Tried to set a rest length in a simulation with fixed rest length. You can only use variable rest lengths if SetUpdateCellPopulationRule is set on the simulation.");
01222 }
01223 }
01224
01225
01226 template class MeshBasedCellPopulation<1,1>;
01227 template class MeshBasedCellPopulation<1,2>;
01228 template class MeshBasedCellPopulation<2,2>;
01229 template class MeshBasedCellPopulation<1,3>;
01230 template class MeshBasedCellPopulation<2,3>;
01231 template class MeshBasedCellPopulation<3,3>;
01232
01233
01234 #include "SerializationExportWrapperForCpp.hpp"
01235 EXPORT_TEMPLATE_CLASS_ALL_DIMS(MeshBasedCellPopulation)