VertexBasedCellPopulation.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2014, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 // Cell writers
00045 #include "CellAgesWriter.hpp"
00046 #include "CellAncestorWriter.hpp"
00047 #include "CellProliferativePhasesWriter.hpp"
00048 #include "CellProliferativeTypesWriter.hpp"
00049 #include "CellVolumesWriter.hpp"
00050 
00051 // Cell population writers
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     // If no location indices are specified, associate with elements from the mesh (assumed to be sequentially ordered).
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]; // assume that the ordering matches
00076         AbstractCellPopulation<DIM, DIM>::AddCellUsingLocationIndex(index,*it);
00077     }
00078 
00079     // Check each element has only one cell attached
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     // Take the average of the cells containing this vertex
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     // Get the element associated with this cell
00200     VertexElement<DIM, DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
00201 
00202     // Divide the element
00203     unsigned new_element_index = mpMutableVertexMesh->DivideElementAlongGivenAxis(p_element,
00204                                                                                   rCellDivisionVector,
00205                                                                                   true);
00206     // Associate the new cell with the element
00207     this->mCells.push_back(pNewCell);
00208 
00209     // Update location cell map
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             // Count the cell as dead
00228             num_removed++;
00229 
00230             // Remove the element from the mesh if it is not deleted yet
00232             if (!(this->GetElement(this->GetLocationIndexUsingCell((*it)))->IsDeleted()))
00233             {
00234                 // This warning relies on the fact that there is only one other possibility for
00235                 // vertex elements to be marked as deleted: a T2 swap
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             // Delete the cell
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     // Iterate over all nodes associated with real cells to update their positions
00255     for (unsigned node_index=0; node_index<GetNumNodes(); node_index++)
00256     {
00257         // Get the damping constant for this node
00258         double damping_const = this->GetDampingConstant(node_index);
00259 
00260         // Compute the displacement of this node
00261         c_vector<double, DIM> displacement = dt*this->GetNode(node_index)->rGetAppliedForce()/damping_const;
00262 
00263         /*
00264          * If the displacement of this node is greater than half the cell rearrangement threshold,
00265          * this could result in nodes moving into the interior of other elements, which should not
00266          * be possible. Therefore in this case we restrict the displacement of the node to the cell
00267          * rearrangement threshold and warn the user that a smaller timestep should be used. This
00268          * restriction ensures that vertex elements remain well defined (see #1376).
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         // Get new node location
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         // Create ChastePoint for new node location
00285         ChastePoint<DIM> new_point(new_node_location);
00286 
00287         // Move the node
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         // Fix up the mappings between CellPtrs and VertexElements
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             // The cell vector should only ever contain living cells
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         // Check that each VertexElement has only one CellPtr associated with it in the updated cell population
00327         Validate();
00328     }
00329 
00330     element_map.ResetToIdentity();
00331 }
00332 
00333 template<unsigned DIM>
00334 void VertexBasedCellPopulation<DIM>::Validate()
00335 {
00336     // Check each element has only one cell attached
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             // This should never be reached as you can only set one cell per element index
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     // Get the vertex element index corresponding to this cell
00377     unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
00378 
00379     // Get the cell's volume from the vertex mesh
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     // Create mesh writer for VTK output
00391     VertexMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results", false);
00392 
00393     // Iterate over any cell writers that are present
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         // Create vector to store VTK cell data
00400         std::vector<double> vtk_cell_data(num_cells);
00401 
00402         // Iterate over vertex elements ///\todo #2441 - replace with loop over cells
00403         for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
00404              elem_iter != mpMutableVertexMesh->GetElementIteratorEnd();
00405              ++elem_iter)
00406         {
00407             // Get index of this element in the vertex mesh
00408             unsigned elem_index = elem_iter->GetIndex();
00409 
00410             // Get the cell corresponding to this element
00411             CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
00412             assert(p_cell);
00413 
00414             // Populate the vector of VTK cell data
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     // When outputting any CellData, we assume that the first cell is representative of all cells
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     // Loop over vertex elements ///\todo #2441 - replace with loop over cells
00433     for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
00434          elem_iter != mpMutableVertexMesh->GetElementIteratorEnd();
00435          ++elem_iter)
00436     {
00437         // Get index of this element in the vertex mesh
00438         unsigned elem_index = elem_iter->GetIndex();
00439 
00440         // Get the cell corresponding to this element
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     // Add the division rule parameters
00518     *rParamsFile << "\t\t<VertexBasedDivisionRule>\n";
00519     mpVertexBasedDivisionRule->OutputCellVertexBasedDivisionRuleInfo(rParamsFile);
00520     *rParamsFile << "\t\t</VertexBasedDivisionRule>\n";
00521 
00522     // Call method on direct parent class
00523     AbstractOffLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00524 }
00525 
00526 template<unsigned DIM>
00527 double VertexBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00528 {
00529     // Call GetWidth() on the mesh
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     // This method only works in 2D sequential
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     // Get a unique temporary foldername
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     // Compute the number of nodes in the TetrahedralMesh
00572     unsigned num_tetrahedral_nodes = num_vertex_nodes + num_vertex_elements;
00573 
00574     // Write node file
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     // Begin by writing each node in the VertexMesh
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     // Now write an additional node at each VertexElement's centroid
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         // Any node located at a VertexElement's centroid will not be a boundary node
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         // Also keep track of how many tetrahedral elements there will be
00608         num_tetrahedral_elements += mpMutableVertexMesh->GetElement(vertex_elem_index)->GetNumNodes();
00609     }
00610     p_node_file->close();
00611 
00612     // Write element file
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         // Iterate over nodes owned by this VertexElement
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             // Add edges to the set if they are not already present
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     // Write edge file
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         // To be a boundary edge both nodes need to be boundary nodes.
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     // Having written the mesh to file, now construct it using TrianglesMeshReader
00673     TetrahedralMesh<DIM, DIM>* p_mesh = new TetrahedralMesh<DIM, DIM>;
00674     // Nested scope so reader is destroyed before we remove the temporary files.
00675     {
00676         TrianglesMeshReader<DIM, DIM> mesh_reader(output_dir + mesh_file_name);
00677         p_mesh->ConstructFromMeshReader(mesh_reader);
00678     }
00679 
00680     // Delete the temporary files
00681     output_file_handler.FindFile("").Remove();
00682 
00683     // The original files have been deleted, it is better if the mesh object forgets about them
00684     p_mesh->SetMeshHasChangedSinceLoading();
00685 
00686     return p_mesh;
00687 }
00688 
00689 // Explicit instantiation
00690 template class VertexBasedCellPopulation<1>;
00691 template class VertexBasedCellPopulation<2>;
00692 template class VertexBasedCellPopulation<3>;
00693 
00694 // Serialization for Boost >= 1.36
00695 #include "SerializationExportWrapperForCpp.hpp"
00696 EXPORT_TEMPLATE_CLASS_SAME_DIMS(VertexBasedCellPopulation)

Generated by  doxygen 1.6.2