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

Generated by  doxygen 1.6.2