PottsBasedCellPopulation.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 "PottsBasedCellPopulation.hpp"
00037 #include "RandomNumberGenerator.hpp"
00038 #include "Warnings.hpp"
00039 
00040 // Needed to convert mesh in order to write nodes to VTK (visualize as glyphs)
00041 #include "VtkMeshWriter.hpp"
00042 #include "NodesOnlyMesh.hpp"
00043 #include "Exception.hpp"
00044 
00045 // Cell writers
00046 #include "CellPopulationElementWriter.hpp"
00047 #include "CellIdWriter.hpp"
00048 
00049 template<unsigned DIM>
00050 void PottsBasedCellPopulation<DIM>::Validate()
00051 {
00052     // Check each element has only one cell associated with it
00053     std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0);
00054 
00055     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00056          cell_iter != this->End();
00057          ++cell_iter)
00058     {
00059         unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
00060         validated_element[elem_index]++;
00061     }
00062 
00063     for (unsigned i=0; i<validated_element.size(); i++)
00064     {
00065         if (validated_element[i] == 0)
00066         {
00067             EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Element " << i << " does not appear to have a cell associated with it");
00068         }
00069 
00070         if (validated_element[i] > 1)
00071         {
00072             EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Element " << i << " appears to have " << validated_element[i] << " cells associated with it");
00073         }
00074     }
00075 }
00076 
00077 template<unsigned DIM>
00078 PottsBasedCellPopulation<DIM>::PottsBasedCellPopulation(PottsMesh<DIM>& rMesh,
00079                                                         std::vector<CellPtr>& rCells,
00080                                                         bool deleteMesh,
00081                                                         bool validate,
00082                                                         const std::vector<unsigned> locationIndices)
00083     : AbstractOnLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh),
00084       mpElementTessellation(NULL),
00085       mpMutableMesh(NULL),
00086       mTemperature(0.1),
00087       mNumSweepsPerTimestep(1)
00088 {
00089     mpPottsMesh = static_cast<PottsMesh<DIM>* >(&(this->mrMesh));
00090     // Check each element has only one cell associated with it
00091     if (validate)
00092     {
00093         Validate();
00094     }
00095 }
00096 
00097 template<unsigned DIM>
00098 PottsBasedCellPopulation<DIM>::PottsBasedCellPopulation(PottsMesh<DIM>& rMesh)
00099     : AbstractOnLatticeCellPopulation<DIM>(rMesh),
00100       mpElementTessellation(NULL),
00101       mpMutableMesh(NULL),
00102       mTemperature(0.1),
00103       mNumSweepsPerTimestep(1)
00104 {
00105     mpPottsMesh = static_cast<PottsMesh<DIM>* >(&(this->mrMesh));
00106 }
00107 
00108 template<unsigned DIM>
00109 PottsBasedCellPopulation<DIM>::~PottsBasedCellPopulation()
00110 {
00111     delete mpElementTessellation;
00112 
00113     delete mpMutableMesh;
00114 
00115     if (this->mDeleteMesh)
00116     {
00117         delete &this->mrMesh;
00118     }
00119 }
00120 
00121 template<unsigned DIM>
00122 PottsMesh<DIM>& PottsBasedCellPopulation<DIM>::rGetMesh()
00123 {
00124     return *mpPottsMesh;
00125 }
00126 
00127 template<unsigned DIM>
00128 const PottsMesh<DIM>& PottsBasedCellPopulation<DIM>::rGetMesh() const
00129 {
00130     return *mpPottsMesh;
00131 }
00132 
00133 template<unsigned DIM>
00134 PottsElement<DIM>* PottsBasedCellPopulation<DIM>::GetElement(unsigned elementIndex)
00135 {
00136     return mpPottsMesh->GetElement(elementIndex);
00137 }
00138 
00139 template<unsigned DIM>
00140 unsigned PottsBasedCellPopulation<DIM>::GetNumElements()
00141 {
00142     return mpPottsMesh->GetNumElements();
00143 }
00144 
00145 template<unsigned DIM>
00146 Node<DIM>* PottsBasedCellPopulation<DIM>::GetNode(unsigned index)
00147 {
00148     return this->mrMesh.GetNode(index);
00149 }
00150 
00151 template<unsigned DIM>
00152 unsigned PottsBasedCellPopulation<DIM>::GetNumNodes()
00153 {
00154     return this->mrMesh.GetNumNodes();
00155 }
00156 
00157 template<unsigned DIM>
00158 std::set<unsigned> PottsBasedCellPopulation<DIM>::GetNeighbouringLocationIndices(CellPtr pCell)
00159 {
00160     unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
00161     return mpPottsMesh->GetNeighbouringElementIndices(elem_index);
00162 }
00163 
00164 template<unsigned DIM>
00165 c_vector<double, DIM> PottsBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
00166 {
00167     return mpPottsMesh->GetCentroidOfElement(this->GetLocationIndexUsingCell(pCell));
00168 }
00169 
00170 template<unsigned DIM>
00171 PottsElement<DIM>* PottsBasedCellPopulation<DIM>::GetElementCorrespondingToCell(CellPtr pCell)
00172 {
00173     return mpPottsMesh->GetElement(this->GetLocationIndexUsingCell(pCell));
00174 }
00175 
00176 template<unsigned DIM>
00177 CellPtr PottsBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00178 {
00179     // Get the element associated with this cell
00180     PottsElement<DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
00181 
00182     // Divide the element
00183     unsigned new_element_index = mpPottsMesh->DivideElement(p_element, true); // new element will be below the existing element
00184 
00185     // Associate the new cell with the element
00186     this->mCells.push_back(pNewCell);
00187 
00188     // Update location cell map
00189     CellPtr p_created_cell = this->mCells.back();
00190     this->SetCellUsingLocationIndex(new_element_index,p_created_cell);
00191     return p_created_cell;
00192 }
00193 
00194 template<unsigned DIM>
00195 unsigned PottsBasedCellPopulation<DIM>::RemoveDeadCells()
00196 {
00197     unsigned num_removed = 0;
00198 
00199     for (std::list<CellPtr>::iterator it = this->mCells.begin();
00200          it != this->mCells.end();
00201          )
00202     {
00203         if ((*it)->IsDead())
00204         {
00205             // Remove the element from the mesh
00206             num_removed++;
00207             mpPottsMesh->DeleteElement(this->GetLocationIndexUsingCell((*it)));
00208             it = this->mCells.erase(it);
00209         }
00210         else
00211         {
00212             ++it;
00213         }
00214     }
00215     return num_removed;
00216 }
00217 template<unsigned DIM>
00218 void PottsBasedCellPopulation<DIM>::UpdateCellLocations(double dt)
00219 {
00220     /*
00221      * This method implements a Monte Carlo method to update the cell population.
00222      * We sample randomly from all nodes in the mesh. Once we have selected a target
00223      * node we randomly select a neighbour. The Hamiltonian is evaluated in the
00224      * current configuration (H_0) and with the target node added to the same
00225      * element as the neighbour (H_1). Based on the vale of deltaH = H_1 - H_0,
00226      * the switch is either made or not.
00227      *
00228      * For each time step (i.e. each time this method is called) we sample
00229      * mrMesh.GetNumNodes() nodes. This is known as a Monte Carlo Step (MCS).
00230      */
00231 
00232     RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00233     unsigned num_nodes = this->mrMesh.GetNumNodes();
00234 
00235     // Randomly permute mUpdateRuleCollection if specified
00236     if (this->mIterateRandomlyOverUpdateRuleCollection)
00237     {
00238         // Randomly permute mUpdateRuleCollection
00239         p_gen->Shuffle(mUpdateRuleCollection);
00240     }
00241 
00242     for (unsigned i=0; i<num_nodes*mNumSweepsPerTimestep; i++)
00243     {
00244         unsigned node_index;
00245 
00246         if (this->mUpdateNodesInRandomOrder)
00247         {
00248             node_index = p_gen->randMod(num_nodes);
00249         }
00250         else
00251         {
00252             // Loop over nodes in index order.
00253             node_index = i%num_nodes;
00254         }
00255 
00256         Node<DIM>* p_node = this->mrMesh.GetNode(node_index);
00257 
00258         // Each node in the mesh must be in at most one element
00259         assert(p_node->GetNumContainingElements() <= 1);
00260 
00261         // Find a random available neighbouring node to overwrite current site
00262         std::set<unsigned> neighbouring_node_indices = mpPottsMesh->GetMooreNeighbouringNodeIndices(node_index);
00263         unsigned neighbour_location_index;
00264 
00265         if (!neighbouring_node_indices.empty())
00266         {
00267             unsigned num_neighbours = neighbouring_node_indices.size();
00268             unsigned chosen_neighbour = p_gen->randMod(num_neighbours);
00269 
00270             std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00271             for (unsigned j=0; j<chosen_neighbour; j++)
00272             {
00273                 neighbour_iter++;
00274             }
00275 
00276             neighbour_location_index = *neighbour_iter;
00277 
00278             std::set<unsigned> containing_elements = p_node->rGetContainingElementIndices();
00279             std::set<unsigned> neighbour_containing_elements = GetNode(neighbour_location_index)->rGetContainingElementIndices();
00280             // Only calculate Hamiltonian and update elements if the nodes are from different elements, or one is from the medium
00281             if (    ( !containing_elements.empty() && neighbour_containing_elements.empty() )
00282                  || ( containing_elements.empty() && !neighbour_containing_elements.empty() )
00283                  || ( !containing_elements.empty() && !neighbour_containing_elements.empty() && *containing_elements.begin() != *neighbour_containing_elements.begin() ) )
00284             {
00285                 double delta_H = 0.0; // This is H_1-H_0.
00286 
00287                 // Now add contributions to the Hamiltonian from each AbstractPottsUpdateRule
00288                 for (typename std::vector<boost::shared_ptr<AbstractPottsUpdateRule<DIM> > >::iterator iter = mUpdateRuleCollection.begin();
00289                      iter != mUpdateRuleCollection.end();
00290                      ++iter)
00291                 {
00292                     delta_H += (*iter)->EvaluateHamiltonianContribution(neighbour_location_index, p_node->GetIndex(), *this);
00293                 }
00294 
00295                 // Generate a uniform random number to do the random motion
00296                 double random_number = p_gen->ranf();
00297 
00298                 double p = exp(-delta_H/mTemperature);
00299                 if (delta_H <= 0 || random_number < p)
00300                 {
00301                     // Do swap
00302 
00303                     // Remove the current node from any elements containing it (there should be at most one such element)
00304                     for (std::set<unsigned>::iterator iter = containing_elements.begin();
00305                          iter != containing_elements.end();
00306                          ++iter)
00307                     {
00308                         GetElement(*iter)->DeleteNode(GetElement(*iter)->GetNodeLocalIndex(node_index));
00309 
00311                     }
00312 
00313                     // Next add the current node to any elements containing the neighbouring node (there should be at most one such element)
00314                     for (std::set<unsigned>::iterator iter = neighbour_containing_elements.begin();
00315                          iter != neighbour_containing_elements.end();
00316                          ++iter)
00317                     {
00318                         GetElement(*iter)->AddNode(this->mrMesh.GetNode(node_index));
00319                     }
00320                 }
00321             }
00322         }
00323     }
00324 }
00325 
00326 template<unsigned DIM>
00327 bool PottsBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell)
00328 {
00329     return GetElementCorrespondingToCell(pCell)->IsDeleted();
00330 }
00331 
00332 template<unsigned DIM>
00333 void PottsBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00334 {
00335 }
00336 
00337 template<unsigned DIM>
00338 void PottsBasedCellPopulation<DIM>::OpenWritersFiles(OutputFileHandler& rOutputFileHandler)
00339 {
00340     if (this->mOutputResultsForChasteVisualizer)
00341     {
00342         if (!this-> template HasWriter<CellPopulationElementWriter>())
00343         {
00344             this-> template AddPopulationWriter<CellPopulationElementWriter>();
00345         }
00346     }
00347     // Add a CellID writer so that a VTK file will contain IDs for visualisation.  (It will also dump a "loggedcell.dat" file as a side-effect.)
00348     this-> template AddCellWriter<CellIdWriter>();
00349 
00350     AbstractCellPopulation<DIM>::OpenWritersFiles(rOutputFileHandler);
00351 }
00352 
00353 template<unsigned DIM>
00354 void PottsBasedCellPopulation<DIM>::WriteResultsToFiles(const std::string& rDirectory)
00355 {
00356     CreateElementTessellation(); // To be used to output to the visualizer
00357 
00358     AbstractCellPopulation<DIM>::WriteResultsToFiles(rDirectory);
00359 }
00360 
00361 template<unsigned DIM>
00362 void PottsBasedCellPopulation<DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<DIM, DIM> > pPopulationWriter)
00363 {
00364     pPopulationWriter->Visit(this);
00365 }
00366 
00367 template<unsigned DIM>
00368 void PottsBasedCellPopulation<DIM>::AcceptPopulationCountWriter(boost::shared_ptr<AbstractCellPopulationCountWriter<DIM, DIM> > pPopulationCountWriter)
00369 {
00370     pPopulationCountWriter->Visit(this);
00371 }
00372 
00373 template<unsigned DIM>
00374 void PottsBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00375 {
00376     pCellWriter->VisitCell(pCell, this);
00377 }
00378 
00379 template<unsigned DIM>
00380 double PottsBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00381 {
00382     // Get element index corresponding to this cell
00383     unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
00384 
00385     // Get volume of this element in the Potts mesh
00386     double cell_volume = mpPottsMesh->GetVolumeOfElement(elem_index);
00387 
00388     return cell_volume;
00389 }
00390 
00391 template<unsigned DIM>
00392 double PottsBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00393 {
00394     // Call GetWidth() on the mesh
00395     double width = this->mrMesh.GetWidth(rDimension);
00396 
00397     return width;
00398 }
00399 
00400 template<unsigned DIM>
00401 void PottsBasedCellPopulation<DIM>::AddUpdateRule(boost::shared_ptr<AbstractPottsUpdateRule<DIM> > pUpdateRule)
00402 {
00403     mUpdateRuleCollection.push_back(pUpdateRule);
00404 }
00405 
00406 template<unsigned DIM>
00407 void PottsBasedCellPopulation<DIM>::RemoveAllUpdateRules()
00408 {
00409     mUpdateRuleCollection.clear();
00410 }
00411 
00412 template<unsigned DIM>
00413 const std::vector<boost::shared_ptr<AbstractPottsUpdateRule<DIM> > >& PottsBasedCellPopulation<DIM>::rGetUpdateRuleCollection() const
00414 {
00415     return mUpdateRuleCollection;
00416 }
00417 
00418 template<unsigned DIM>
00419 void PottsBasedCellPopulation<DIM>::CreateElementTessellation()
00420 {
00422 //  delete mpElementTessellation;
00423 //
00424 //    ///\todo this code would need to be extended if the domain were required to be periodic
00425 //
00426 //  std::vector<Node<2>*> nodes;
00427 //  for (unsigned node_index=0; node_index<mrMesh.GetNumNodes(); node_index++)
00428 //  {
00429 //      Node<2>* p_temp_node = mrMesh.GetNode(node_index);
00430 //      nodes.push_back(p_temp_node);
00431 //  }
00432 //  MutableMesh<2,2> mesh(nodes);
00433 //    mpElementTessellation = new VertexMesh<2,2>(mesh);
00434 }
00435 
00436 template<unsigned DIM>
00437 VertexMesh<DIM,DIM>* PottsBasedCellPopulation<DIM>::GetElementTessellation()
00438 {
00439 //    assert(mpElementTessellation != NULL);
00440     return mpElementTessellation;
00441 }
00442 
00443 template<unsigned DIM>
00444 void PottsBasedCellPopulation<DIM>::CreateMutableMesh()
00445 {
00446     delete mpMutableMesh;
00447 
00448     // Get the nodes of the PottsMesh
00449     std::vector<Node<DIM>*> nodes;
00450     for (unsigned node_index=0; node_index<this->mrMesh.GetNumNodes(); node_index++)
00451     {
00452       c_vector<double, DIM> location = this->mrMesh.GetNode(node_index)->rGetLocation();
00453       nodes.push_back(new Node<DIM>(node_index, location));
00454     }
00455 
00456     mpMutableMesh = new MutableMesh<DIM,DIM>(nodes);
00457 }
00458 
00459 template<unsigned DIM>
00460 MutableMesh<DIM,DIM>* PottsBasedCellPopulation<DIM>::GetMutableMesh()
00461 {
00462     assert(mpMutableMesh);
00463     return mpMutableMesh;
00464 }
00465 
00466 template<unsigned DIM>
00467 void PottsBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00468 {
00469     *rParamsFile << "\t\t<Temperature>" << mTemperature << "</Temperature>\n";
00470     *rParamsFile << "\t\t<NumSweepsPerTimestep>" << mNumSweepsPerTimestep << "</NumSweepsPerTimestep>\n";
00471 
00472     // Call method on direct parent class
00473     AbstractOnLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00474 }
00475 
00476 template<unsigned DIM>
00477 void PottsBasedCellPopulation<DIM>::SetTemperature(double temperature)
00478 {
00479     mTemperature = temperature;
00480 }
00481 
00482 template<unsigned DIM>
00483 double PottsBasedCellPopulation<DIM>::GetTemperature()
00484 {
00485     return mTemperature;
00486 }
00487 
00488 template<unsigned DIM>
00489 void PottsBasedCellPopulation<DIM>::SetNumSweepsPerTimestep(unsigned numSweepsPerTimestep)
00490 {
00491     mNumSweepsPerTimestep = numSweepsPerTimestep;
00492 }
00493 
00494 template<unsigned DIM>
00495 unsigned PottsBasedCellPopulation<DIM>::GetNumSweepsPerTimestep()
00496 {
00497     return mNumSweepsPerTimestep;
00498 }
00499 
00500 template<unsigned DIM>
00501 void PottsBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00502 {
00503 #ifdef CHASTE_VTK
00504     unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
00505     std::stringstream time;
00506     time << num_timesteps;
00507 
00508     // Create mesh writer for VTK output
00509     VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
00510 
00511     // Iterate over any cell writers that are present
00512     unsigned num_nodes = GetNumNodes();
00513     for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
00514          cell_writer_iter != this->mCellWriters.end();
00515          ++cell_writer_iter)
00516     {
00517         // Create vector to store VTK cell data
00518         std::vector<double> vtk_cell_data(num_nodes);
00519 
00520         // Iterate over nodes in the mesh
00521         for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mpPottsMesh->GetNodeIteratorBegin();
00522              iter != mpPottsMesh->GetNodeIteratorEnd();
00523              ++iter)
00524         {
00525             // Get the index of this node in the mesh and those elements (i.e. cells) that contain this node
00526             unsigned node_index = iter->GetIndex();
00527             std::set<unsigned> element_indices = iter->rGetContainingElementIndices();
00528 
00529             // If there are no elements associated with this node, then we set the value of any VTK cell data to be -1 at this node...
00530             if (element_indices.empty())
00531             {
00532                 // Populate the vector of VTK cell data
00533                 vtk_cell_data[node_index] = -1.0;
00534             }
00535             else
00536             {
00537                 // ... otherwise there should be exactly one element (i.e. cell) containing this node
00538                 assert(element_indices.size() == 1);
00539                 unsigned elem_index = *(element_indices.begin());
00540                 CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
00541 
00542                 // Populate the vector of VTK cell data
00543                 vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
00544             }
00545         }
00546 
00547         mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
00548     }
00549 
00550 
00551     // When outputting any CellData, we assume that the first cell is representative of all cells
00552     unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00553     std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
00554 
00555     std::vector<std::vector<double> > cell_data;
00556     for (unsigned var=0; var<num_cell_data_items; var++)
00557     {
00558         std::vector<double> cell_data_var(num_nodes);
00559         cell_data.push_back(cell_data_var);
00560     }
00561 
00562     for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mpPottsMesh->GetNodeIteratorBegin();
00563          iter != mpPottsMesh->GetNodeIteratorEnd();
00564          ++iter)
00565     {
00566         // Get the index of this node in the mesh and those elements (i.e. cells) that contain this node
00567         unsigned node_index = iter->GetIndex();
00568         std::set<unsigned> element_indices = iter->rGetContainingElementIndices();
00569 
00570         // If there are no elements associated with this node, then we set the value of any VTK cell data to be -1 at this node...
00571         if (element_indices.empty())
00572         {
00573             for (unsigned var=0; var<num_cell_data_items; var++)
00574             {
00575                 cell_data[var][node_index] = -1.0;
00576             }
00577         }
00578         else
00579         {
00580             // ... otherwise there should be exactly one element (i.e. cell) containing this node
00581             assert(element_indices.size() == 1);
00582             unsigned elem_index = *(element_indices.begin());
00583             CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
00584 
00585             for (unsigned var=0; var<num_cell_data_items; var++)
00586             {
00587                 cell_data[var][node_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
00588             }
00589         }
00590     }
00591     for (unsigned var=0; var<cell_data.size(); var++)
00592     {
00593         mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
00594     }
00595 
00596     /*
00597      * At present, the VTK writer can only write things which inherit from AbstractTetrahedralMeshWriter.
00598      * For now, we do an explicit conversion to NodesOnlyMesh. This can be written to VTK, then visualized
00599      * as glyphs in Paraview.
00600      */
00601     NodesOnlyMesh<DIM> temp_mesh;
00602     temp_mesh.ConstructNodesWithoutMesh(*mpPottsMesh, 1.5); // This cut-off is arbitrary, as node connectivity is not used here
00603     mesh_writer.WriteFilesUsingMesh(temp_mesh);
00604 
00605     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00606     *(this->mpVtkMetaFile) << num_timesteps;
00607     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00608     *(this->mpVtkMetaFile) << num_timesteps;
00609     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00610 #endif //CHASTE_VTK
00611 }
00612 
00613 // Explicit instantiation
00614 template class PottsBasedCellPopulation<1>;
00615 template class PottsBasedCellPopulation<2>;
00616 template class PottsBasedCellPopulation<3>;
00617 
00618 // Serialization for Boost >= 1.36
00619 #include "SerializationExportWrapperForCpp.hpp"
00620 EXPORT_TEMPLATE_CLASS_SAME_DIMS(PottsBasedCellPopulation)

Generated by  doxygen 1.6.2