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 "VertexBasedCellPopulation.hpp"
00037 #include <boost/foreach.hpp>
00038 #include "VertexMeshWriter.hpp"
00039 #include "Warnings.hpp"
00040 #include "ChasteSyscalls.hpp"
00041 #include "IsNan.hpp"
00042 #include "ShortAxisVertexBasedDivisionRule.hpp"
00043
00044
00045 #include "CellAgesWriter.hpp"
00046 #include "CellAncestorWriter.hpp"
00047 #include "CellProliferativePhasesWriter.hpp"
00048 #include "CellProliferativeTypesWriter.hpp"
00049 #include "CellVolumesWriter.hpp"
00050
00051
00052 #include "CellMutationStatesCountWriter.hpp"
00053 #include "CellPopulationElementWriter.hpp"
00054 #include "VertexT1SwapLocationsWriter.hpp"
00055 #include "VertexT2SwapLocationsWriter.hpp"
00056 #include "VertexT3SwapLocationsWriter.hpp"
00057
00058 template<unsigned DIM>
00059 VertexBasedCellPopulation<DIM>::VertexBasedCellPopulation(MutableVertexMesh<DIM, DIM>& rMesh,
00060 std::vector<CellPtr>& rCells,
00061 bool deleteMesh,
00062 bool validate,
00063 const std::vector<unsigned> locationIndices)
00064 : AbstractOffLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices),
00065 mDeleteMesh(deleteMesh),
00066 mOutputCellRearrangementLocations(true)
00067 {
00068 mpMutableVertexMesh = static_cast<MutableVertexMesh<DIM, DIM>* >(&(this->mrMesh));
00069 mpVertexBasedDivisionRule.reset(new ShortAxisVertexBasedDivisionRule<DIM>());
00070
00071
00072 std::list<CellPtr>::iterator it = this->mCells.begin();
00073 for (unsigned i=0; it != this->mCells.end(); ++it, ++i)
00074 {
00075 unsigned index = locationIndices.empty() ? i : locationIndices[i];
00076 AbstractCellPopulation<DIM, DIM>::AddCellUsingLocationIndex(index,*it);
00077 }
00078
00079
00080 if (validate)
00081 {
00082 Validate();
00083 }
00084 }
00085
00086 template<unsigned DIM>
00087 VertexBasedCellPopulation<DIM>::VertexBasedCellPopulation(MutableVertexMesh<DIM, DIM>& rMesh)
00088 : AbstractOffLatticeCellPopulation<DIM>(rMesh),
00089 mDeleteMesh(true),
00090 mOutputCellRearrangementLocations(true)
00091 {
00092 mpMutableVertexMesh = static_cast<MutableVertexMesh<DIM, DIM>* >(&(this->mrMesh));
00093 }
00094
00095 template<unsigned DIM>
00096 VertexBasedCellPopulation<DIM>::~VertexBasedCellPopulation()
00097 {
00098 if (mDeleteMesh)
00099 {
00100 delete &this->mrMesh;
00101 }
00102 }
00103
00104 template<unsigned DIM>
00105 double VertexBasedCellPopulation<DIM>::GetDampingConstant(unsigned nodeIndex)
00106 {
00107
00108 double average_damping_constant = 0.0;
00109
00110 std::set<unsigned> containing_elements = GetNode(nodeIndex)->rGetContainingElementIndices();
00111 double temp = 1.0/((double) containing_elements.size());
00112
00113 for (std::set<unsigned>::iterator iter = containing_elements.begin();
00114 iter != containing_elements.end();
00115 ++iter)
00116 {
00117 CellPtr p_cell = this->GetCellUsingLocationIndex(*iter);
00118 bool cell_is_wild_type = p_cell->GetMutationState()->IsType<WildTypeCellMutationState>();
00119 bool cell_is_labelled = p_cell->HasCellProperty<CellLabel>();
00120
00121 if (cell_is_wild_type && !cell_is_labelled)
00122 {
00123 average_damping_constant += this->GetDampingConstantNormal()*temp;
00124 }
00125 else
00126 {
00127 average_damping_constant += this->GetDampingConstantMutant()*temp;
00128 }
00129 }
00130
00131 return average_damping_constant;
00132 }
00133
00134 template<unsigned DIM>
00135 MutableVertexMesh<DIM, DIM>& VertexBasedCellPopulation<DIM>::rGetMesh()
00136 {
00137 return *mpMutableVertexMesh;
00138 }
00139
00140 template<unsigned DIM>
00141 const MutableVertexMesh<DIM, DIM>& VertexBasedCellPopulation<DIM>::rGetMesh() const
00142 {
00143 return *mpMutableVertexMesh;
00144 }
00145
00146 template<unsigned DIM>
00147 VertexElement<DIM, DIM>* VertexBasedCellPopulation<DIM>::GetElement(unsigned elementIndex)
00148 {
00149 return mpMutableVertexMesh->GetElement(elementIndex);
00150 }
00151
00152 template<unsigned DIM>
00153 unsigned VertexBasedCellPopulation<DIM>::GetNumNodes()
00154 {
00155 return this->mrMesh.GetNumNodes();
00156 }
00157
00158 template<unsigned DIM>
00159 c_vector<double, DIM> VertexBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
00160 {
00161 return mpMutableVertexMesh->GetCentroidOfElement(this->mCellLocationMap[pCell.get()]);
00162 }
00163
00164 template<unsigned DIM>
00165 Node<DIM>* VertexBasedCellPopulation<DIM>::GetNode(unsigned index)
00166 {
00167 return this->mrMesh.GetNode(index);
00168 }
00169
00170 template<unsigned DIM>
00171 unsigned VertexBasedCellPopulation<DIM>::AddNode(Node<DIM>* pNewNode)
00172 {
00173 return mpMutableVertexMesh->AddNode(pNewNode);
00174 }
00175
00176 template<unsigned DIM>
00177 void VertexBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
00178 {
00179 mpMutableVertexMesh->SetNode(nodeIndex, rNewLocation);
00180 }
00181
00182 template<unsigned DIM>
00183 VertexElement<DIM, DIM>* VertexBasedCellPopulation<DIM>::GetElementCorrespondingToCell(CellPtr pCell)
00184 {
00185 return mpMutableVertexMesh->GetElement(this->GetLocationIndexUsingCell(pCell));
00186 }
00187
00188 template<unsigned DIM>
00189 unsigned VertexBasedCellPopulation<DIM>::GetNumElements()
00190 {
00191 return mpMutableVertexMesh->GetNumElements();
00192 }
00193
00194 template<unsigned DIM>
00195 CellPtr VertexBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell,
00196 const c_vector<double,DIM>& rCellDivisionVector,
00197 CellPtr pParentCell)
00198 {
00199
00200 VertexElement<DIM, DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
00201
00202
00203 unsigned new_element_index = mpMutableVertexMesh->DivideElementAlongGivenAxis(p_element,
00204 rCellDivisionVector,
00205 true);
00206
00207 this->mCells.push_back(pNewCell);
00208
00209
00210 CellPtr p_created_cell = this->mCells.back();
00211 this->SetCellUsingLocationIndex(new_element_index,p_created_cell);
00212 this->mCellLocationMap[p_created_cell.get()] = new_element_index;
00213 return p_created_cell;
00214 }
00215
00216 template<unsigned DIM>
00217 unsigned VertexBasedCellPopulation<DIM>::RemoveDeadCells()
00218 {
00219 unsigned num_removed = 0;
00220
00221 for (std::list<CellPtr>::iterator it = this->mCells.begin();
00222 it != this->mCells.end();
00223 )
00224 {
00225 if ((*it)->IsDead())
00226 {
00227
00228 num_removed++;
00229
00230
00232 if (!(this->GetElement(this->GetLocationIndexUsingCell((*it)))->IsDeleted()))
00233 {
00234
00235
00236 WARN_ONCE_ONLY("A Cell is removed without performing a T2 swap. This could leave a void in the mesh.");
00237 mpMutableVertexMesh->DeleteElementPriorToReMesh(this->GetLocationIndexUsingCell((*it)));
00238 }
00239
00240
00241 it = this->mCells.erase(it);
00242 }
00243 else
00244 {
00245 ++it;
00246 }
00247 }
00248 return num_removed;
00249 }
00250
00251 template<unsigned DIM>
00252 void VertexBasedCellPopulation<DIM>::UpdateNodeLocations(double dt)
00253 {
00254
00255 for (unsigned node_index=0; node_index<GetNumNodes(); node_index++)
00256 {
00257
00258 double damping_const = this->GetDampingConstant(node_index);
00259
00260
00261 c_vector<double, DIM> displacement = dt*this->GetNode(node_index)->rGetAppliedForce()/damping_const;
00262
00263
00264
00265
00266
00267
00268
00269
00270 if (norm_2(displacement) > 0.5*mpMutableVertexMesh->GetCellRearrangementThreshold())
00271 {
00272 WARN_ONCE_ONLY("Vertices are moving more than half the CellRearrangementThreshold. This could cause elements to become inverted so the motion has been restricted. Use a smaller timestep to avoid these warnings.");
00273 displacement *= 0.5*mpMutableVertexMesh->GetCellRearrangementThreshold()/norm_2(displacement);
00274 }
00275
00276
00277 c_vector<double, DIM> new_node_location = this->GetNode(node_index)->rGetLocation() + displacement;
00278
00279 for (unsigned i=0; i<DIM; i++)
00280 {
00281 assert(!std::isnan(new_node_location(i)));
00282 }
00283
00284
00285 ChastePoint<DIM> new_point(new_node_location);
00286
00287
00288 this->SetNode(node_index, new_point);
00289 }
00290 }
00291
00292 template<unsigned DIM>
00293 bool VertexBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell)
00294 {
00295 return GetElementCorrespondingToCell(pCell)->IsDeleted();;
00296 }
00297
00298 template<unsigned DIM>
00299 void VertexBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00300 {
00301 VertexElementMap element_map(mpMutableVertexMesh->GetNumAllElements());
00302
00303 mpMutableVertexMesh->ReMesh(element_map);
00304
00305 if (!element_map.IsIdentityMap())
00306 {
00307
00309 std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
00310
00311 this->mCellLocationMap.clear();
00312 this->mLocationCellMap.clear();
00313
00314 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00315 cell_iter != this->mCells.end();
00316 ++cell_iter)
00317 {
00318
00319 unsigned old_elem_index = old_map[(*cell_iter).get()];
00320 assert(!element_map.IsDeleted(old_elem_index));
00321
00322 unsigned new_elem_index = element_map.GetNewIndex(old_elem_index);
00323 this->SetCellUsingLocationIndex(new_elem_index, *cell_iter);
00324 }
00325
00326
00327 Validate();
00328 }
00329
00330 element_map.ResetToIdentity();
00331 }
00332
00333 template<unsigned DIM>
00334 void VertexBasedCellPopulation<DIM>::Validate()
00335 {
00336
00337 std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0);
00338 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00339 cell_iter != this->End();
00340 ++cell_iter)
00341 {
00342 unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
00343 validated_element[elem_index]++;
00344 }
00345
00346 for (unsigned i=0; i<validated_element.size(); i++)
00347 {
00348 if (validated_element[i] == 0)
00349 {
00350 EXCEPTION("Element " << i << " does not appear to have a cell associated with it");
00351 }
00352
00353 if (validated_element[i] > 1)
00354 {
00355
00356 EXCEPTION("Element " << i << " appears to have " << validated_element[i] << " cells associated with it");
00357 }
00358 }
00359 }
00360
00361 template<unsigned DIM>
00362 void VertexBasedCellPopulation<DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<DIM, DIM> > pPopulationWriter)
00363 {
00364 pPopulationWriter->Visit(this);
00365 }
00366
00367 template<unsigned DIM>
00368 void VertexBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00369 {
00370 pCellWriter->VisitCell(pCell, this);
00371 }
00372
00373 template<unsigned DIM>
00374 double VertexBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00375 {
00376
00377 unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
00378
00379
00380 double cell_volume = mpMutableVertexMesh->GetVolumeOfElement(elem_index);
00381
00382 return cell_volume;
00383 }
00384
00385 template<unsigned DIM>
00386 void VertexBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00387 {
00388 #ifdef CHASTE_VTK
00389
00390
00391 VertexMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results", false);
00392
00393
00394 unsigned num_cells = this->GetNumAllCells();
00395 for (typename std::set<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
00396 cell_writer_iter != this->mCellWriters.end();
00397 ++cell_writer_iter)
00398 {
00399
00400 std::vector<double> vtk_cell_data(num_cells);
00401
00402
00403 for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
00404 elem_iter != mpMutableVertexMesh->GetElementIteratorEnd();
00405 ++elem_iter)
00406 {
00407
00408 unsigned elem_index = elem_iter->GetIndex();
00409
00410
00411 CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
00412 assert(p_cell);
00413
00414
00415 vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
00416 }
00417
00418 mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
00419 }
00420
00421
00422 unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00423 std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
00424
00425 std::vector<std::vector<double> > cell_data;
00426 for (unsigned var=0; var<num_cell_data_items; var++)
00427 {
00428 std::vector<double> cell_data_var(num_cells);
00429 cell_data.push_back(cell_data_var);
00430 }
00431
00432
00433 for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
00434 elem_iter != mpMutableVertexMesh->GetElementIteratorEnd();
00435 ++elem_iter)
00436 {
00437
00438 unsigned elem_index = elem_iter->GetIndex();
00439
00440
00441 CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
00442 assert(p_cell);
00443
00444 for (unsigned var=0; var<num_cell_data_items; var++)
00445 {
00446 cell_data[var][elem_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
00447 }
00448 }
00449 for (unsigned var=0; var<num_cell_data_items; var++)
00450 {
00451 mesh_writer.AddCellData(cell_data_names[var], cell_data[var]);
00452 }
00453
00454 unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
00455 std::stringstream time;
00456 time << num_timesteps;
00457
00458 mesh_writer.WriteVtkUsingMesh(*mpMutableVertexMesh, time.str());
00459 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
00460 *(this->mpVtkMetaFile) << num_timesteps;
00461 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00462 *(this->mpVtkMetaFile) << num_timesteps;
00463 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00464 #endif //CHASTE_VTK
00465 }
00466
00467 template<unsigned DIM>
00468 void VertexBasedCellPopulation<DIM>::OpenWritersFiles(const std::string& rDirectory)
00469 {
00470 if (this->mOutputResultsForChasteVisualizer)
00471 {
00472 if (!this-> template HasWriter<CellPopulationElementWriter>())
00473 {
00474 this-> template AddPopulationWriter<CellPopulationElementWriter>();
00475 }
00476 }
00477
00478 if (mOutputCellRearrangementLocations)
00479 {
00480 if (!this-> template HasWriter<VertexT1SwapLocationsWriter>())
00481 {
00482 this-> template AddPopulationWriter<VertexT1SwapLocationsWriter>();
00483 }
00484 if (!this-> template HasWriter<VertexT2SwapLocationsWriter>())
00485 {
00486 this-> template AddPopulationWriter<VertexT2SwapLocationsWriter>();
00487 }
00488 if (!this-> template HasWriter<VertexT3SwapLocationsWriter>())
00489 {
00490 this-> template AddPopulationWriter<VertexT3SwapLocationsWriter>();
00491 }
00492 }
00493
00494 AbstractCellPopulation<DIM>::OpenWritersFiles(rDirectory);
00495 }
00496
00497 template<unsigned DIM>
00498 bool VertexBasedCellPopulation<DIM>::GetOutputCellRearrangementLocations()
00499 {
00500 return mOutputCellRearrangementLocations;
00501 }
00502
00503 template<unsigned DIM>
00504 void VertexBasedCellPopulation<DIM>::SetOutputCellRearrangementLocations(bool outputCellRearrangementLocations)
00505 {
00506 mOutputCellRearrangementLocations = outputCellRearrangementLocations;
00507 }
00508
00509 template<unsigned DIM>
00510 void VertexBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00511 {
00512 *rParamsFile << "\t\t<CellRearrangementThreshold>" << mpMutableVertexMesh->GetCellRearrangementThreshold() << "</CellRearrangementThreshold>\n";
00513 *rParamsFile << "\t\t<T2Threshold>" << mpMutableVertexMesh->GetT2Threshold() << "</T2Threshold>\n";
00514 *rParamsFile << "\t\t<CellRearrangementRatio>" << mpMutableVertexMesh->GetCellRearrangementRatio() << "</CellRearrangementRatio>\n";
00515 *rParamsFile << "\t\t<OutputCellRearrangementLocations>" << mOutputCellRearrangementLocations << "</OutputCellRearrangementLocations>\n";
00516
00517
00518 *rParamsFile << "\t\t<VertexBasedDivisionRule>\n";
00519 mpVertexBasedDivisionRule->OutputCellVertexBasedDivisionRuleInfo(rParamsFile);
00520 *rParamsFile << "\t\t</VertexBasedDivisionRule>\n";
00521
00522
00523 AbstractOffLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00524 }
00525
00526 template<unsigned DIM>
00527 double VertexBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00528 {
00529
00530 double width = this->mrMesh.GetWidth(rDimension);
00531
00532 return width;
00533 }
00534
00535 template<unsigned DIM>
00536 std::set<unsigned> VertexBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00537 {
00538 return mpMutableVertexMesh->GetNeighbouringNodeIndices(index);
00539 }
00540
00541 template<unsigned DIM>
00542 boost::shared_ptr<AbstractVertexBasedDivisionRule<DIM> > VertexBasedCellPopulation<DIM>::GetVertexBasedDivisionRule()
00543 {
00544 return mpVertexBasedDivisionRule;
00545 }
00546
00547 template<unsigned DIM>
00548 void VertexBasedCellPopulation<DIM>::SetVertexBasedDivisionRule(boost::shared_ptr<AbstractVertexBasedDivisionRule<DIM> > pVertexBasedDivisionRule)
00549 {
00550 mpVertexBasedDivisionRule = pVertexBasedDivisionRule;
00551 }
00552
00553 template<unsigned DIM>
00554 TetrahedralMesh<DIM, DIM>* VertexBasedCellPopulation<DIM>::GetTetrahedralMeshUsingVertexMesh()
00555 {
00556
00557 assert(DIM == 2);
00558 assert(PetscTools::IsSequential());
00559
00560 unsigned num_vertex_nodes = mpMutableVertexMesh->GetNumNodes();
00561 unsigned num_vertex_elements = mpMutableVertexMesh->GetNumElements();
00562
00563 std::string mesh_file_name = "mesh";
00564
00565
00566 std::stringstream pid;
00567 pid << getpid();
00568 OutputFileHandler output_file_handler("2D_temporary_tetrahedral_mesh_" + pid.str());
00569 std::string output_dir = output_file_handler.GetOutputDirectoryFullPath();
00570
00571
00572 unsigned num_tetrahedral_nodes = num_vertex_nodes + num_vertex_elements;
00573
00574
00575 out_stream p_node_file = output_file_handler.OpenOutputFile(mesh_file_name+".node");
00576 (*p_node_file) << std::scientific;
00577 (*p_node_file) << std::setprecision(20);
00578 (*p_node_file) << num_tetrahedral_nodes << "\t2\t0\t1" << std::endl;
00579
00580
00581 for (unsigned node_index=0; node_index<num_vertex_nodes; node_index++)
00582 {
00583 Node<DIM>* p_node = mpMutableVertexMesh->GetNode(node_index);
00584
00586 unsigned index = p_node->GetIndex();
00587
00588 c_vector<double, DIM> location = p_node->rGetLocation();
00589
00590 unsigned is_boundary_node = p_node->IsBoundaryNode() ? 1 : 0;
00591
00592 (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl;
00593 }
00594
00595
00596 unsigned num_tetrahedral_elements = 0;
00597 for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++)
00598 {
00599 unsigned index = num_vertex_nodes + vertex_elem_index;
00600
00601 c_vector<double, DIM> location = mpMutableVertexMesh->GetCentroidOfElement(vertex_elem_index);
00602
00603
00604 unsigned is_boundary_node = 0;
00605 (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl;
00606
00607
00608 num_tetrahedral_elements += mpMutableVertexMesh->GetElement(vertex_elem_index)->GetNumNodes();
00609 }
00610 p_node_file->close();
00611
00612
00613 out_stream p_elem_file = output_file_handler.OpenOutputFile(mesh_file_name+".ele");
00614 (*p_elem_file) << std::scientific;
00615 (*p_elem_file) << num_tetrahedral_elements << "\t3\t0" << std::endl;
00616
00617 std::set<std::pair<unsigned, unsigned> > tetrahedral_edges;
00618
00619 unsigned tetrahedral_elem_index = 0;
00620 for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++)
00621 {
00622 VertexElement<DIM, DIM>* p_vertex_element = mpMutableVertexMesh->GetElement(vertex_elem_index);
00623
00624
00625 unsigned num_nodes_in_vertex_element = p_vertex_element->GetNumNodes();
00626 for (unsigned local_index=0; local_index<num_nodes_in_vertex_element; local_index++)
00627 {
00628 unsigned node_0_index = p_vertex_element->GetNodeGlobalIndex(local_index);
00629 unsigned node_1_index = p_vertex_element->GetNodeGlobalIndex((local_index+1)%num_nodes_in_vertex_element);
00630 unsigned node_2_index = num_vertex_nodes + vertex_elem_index;
00631
00632 (*p_elem_file) << tetrahedral_elem_index++ << "\t" << node_0_index << "\t" << node_1_index << "\t" << node_2_index << std::endl;
00633
00634
00635 std::pair<unsigned, unsigned> edge_0 = this->CreateOrderedPair(node_0_index, node_1_index);
00636 std::pair<unsigned, unsigned> edge_1 = this->CreateOrderedPair(node_1_index, node_2_index);
00637 std::pair<unsigned, unsigned> edge_2 = this->CreateOrderedPair(node_2_index, node_0_index);
00638
00639 tetrahedral_edges.insert(edge_0);
00640 tetrahedral_edges.insert(edge_1);
00641 tetrahedral_edges.insert(edge_2);
00642 }
00643 }
00644 p_elem_file->close();
00645
00646
00647 out_stream p_edge_file = output_file_handler.OpenOutputFile(mesh_file_name+".edge");
00648 (*p_edge_file) << std::scientific;
00649 (*p_edge_file) << tetrahedral_edges.size() << "\t1" << std::endl;
00650
00651 unsigned edge_index = 0;
00652 for (std::set<std::pair<unsigned, unsigned> >::iterator edge_iter = tetrahedral_edges.begin();
00653 edge_iter != tetrahedral_edges.end();
00654 ++edge_iter)
00655 {
00656 std::pair<unsigned, unsigned> this_edge = *edge_iter;
00657
00658
00659 bool is_boundary_edge = false;
00660 if (this_edge.first < mpMutableVertexMesh->GetNumNodes() &&
00661 this_edge.second < mpMutableVertexMesh->GetNumNodes())
00662 {
00663 is_boundary_edge = (mpMutableVertexMesh->GetNode(this_edge.first)->IsBoundaryNode() &&
00664 mpMutableVertexMesh->GetNode(this_edge.second)->IsBoundaryNode() );
00665 }
00666 unsigned is_boundary_edge_unsigned = is_boundary_edge ? 1 : 0;
00667
00668 (*p_edge_file) << edge_index++ << "\t" << this_edge.first << "\t" << this_edge.second << "\t" << is_boundary_edge_unsigned << std::endl;
00669 }
00670 p_edge_file->close();
00671
00672
00673 TetrahedralMesh<DIM, DIM>* p_mesh = new TetrahedralMesh<DIM, DIM>;
00674
00675 {
00676 TrianglesMeshReader<DIM, DIM> mesh_reader(output_dir + mesh_file_name);
00677 p_mesh->ConstructFromMeshReader(mesh_reader);
00678 }
00679
00680
00681 output_file_handler.FindFile("").Remove();
00682
00683
00684 p_mesh->SetMeshHasChangedSinceLoading();
00685
00686 return p_mesh;
00687 }
00688
00689
00690 template class VertexBasedCellPopulation<1>;
00691 template class VertexBasedCellPopulation<2>;
00692 template class VertexBasedCellPopulation<3>;
00693
00694
00695 #include "SerializationExportWrapperForCpp.hpp"
00696 EXPORT_TEMPLATE_CLASS_SAME_DIMS(VertexBasedCellPopulation)