PottsBasedCellPopulation.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "PottsBasedCellPopulation.hpp"
00030 #include "RandomNumberGenerator.hpp"
00031 #include "Warnings.hpp"
00032 
00033 // Needed to convert mesh in order to write nodes to VTK (visualize as glyphs)
00034 #include "VtkMeshWriter.hpp"
00035 #include "NodesOnlyMesh.hpp"
00036 #include "Exception.hpp"
00037 
00038 template<unsigned DIM>
00039 void PottsBasedCellPopulation<DIM>::Validate()
00040 {
00041     // Check each element has only one cell associated with it
00042     std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0);
00043 
00044     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00045          cell_iter != this->End();
00046          ++cell_iter)
00047     {
00048         unsigned elem_index = GetLocationIndexUsingCell(*cell_iter);
00049         validated_element[elem_index]++;
00050     }
00051 
00052     for (unsigned i=0; i<validated_element.size(); i++)
00053     {
00054         if (validated_element[i] == 0)
00055         {
00056             EXCEPTION("Element " << i << " does not appear to have a cell associated with it");
00057         }
00058 
00059         if (validated_element[i] > 1)
00060         {
00061             EXCEPTION("Element " << i << " appears to have " << validated_element[i] << " cells associated with it");
00062         }
00063     }
00064 }
00065 
00066 template<unsigned DIM>
00067 PottsBasedCellPopulation<DIM>::PottsBasedCellPopulation(PottsMesh<DIM>& rMesh,
00068                                                         std::vector<CellPtr>& rCells,
00069                                                         bool deleteMesh,
00070                                                         bool validate,
00071                                                         const std::vector<unsigned> locationIndices)
00072     : AbstractOnLatticeCellPopulation<DIM>(rCells, locationIndices, deleteMesh),
00073       mrMesh(rMesh),
00074       mpElementTessellation(NULL),
00075       mTemperature(0.1),
00076       mNumSweepsPerTimestep(1)
00077 {
00078     // Check each element has only one cell associated with it
00079     if (validate)
00080     {
00081         Validate();
00082     }
00083 }
00084 
00085 template<unsigned DIM>
00086 PottsBasedCellPopulation<DIM>::PottsBasedCellPopulation(PottsMesh<DIM>& rMesh)
00087     : AbstractOnLatticeCellPopulation<DIM>(),
00088       mrMesh(rMesh),
00089       mpElementTessellation(NULL),
00090       mTemperature(0.1),
00091       mNumSweepsPerTimestep(1)
00092 {
00093 }
00094 
00095 template<unsigned DIM>
00096 PottsBasedCellPopulation<DIM>::~PottsBasedCellPopulation()
00097 {
00098     delete mpElementTessellation;
00099 
00100     if (this->mDeleteMesh)
00101     {
00102         delete &mrMesh;
00103     }
00104 }
00105 
00106 template<unsigned DIM>
00107 PottsMesh<DIM>& PottsBasedCellPopulation<DIM>::rGetMesh()
00108 {
00109     return mrMesh;
00110 }
00111 
00112 template<unsigned DIM>
00113 const PottsMesh<DIM>& PottsBasedCellPopulation<DIM>::rGetMesh() const
00114 {
00115     return mrMesh;
00116 }
00117 
00118 template<unsigned DIM>
00119 PottsElement<DIM>* PottsBasedCellPopulation<DIM>::GetElement(unsigned elementIndex)
00120 {
00121     return mrMesh.GetElement(elementIndex);
00122 }
00123 
00124 template<unsigned DIM>
00125 unsigned PottsBasedCellPopulation<DIM>::GetNumElements()
00126 {
00127     return mrMesh.GetNumElements();
00128 }
00129 
00130 template<unsigned DIM>
00131 Node<DIM>* PottsBasedCellPopulation<DIM>::GetNode(unsigned index)
00132 {
00133     return mrMesh.GetNode(index);
00134 }
00135 
00136 template<unsigned DIM>
00137 unsigned PottsBasedCellPopulation<DIM>::GetNumNodes()
00138 {
00139     return mrMesh.GetNumNodes();
00140 }
00141 
00142 template<unsigned DIM>
00143 c_vector<double, DIM> PottsBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
00144 {
00145     return mrMesh.GetCentroidOfElement(this->mCellLocationMap[pCell.get()]);
00146 }
00147 
00148 template<unsigned DIM>
00149 PottsElement<DIM>* PottsBasedCellPopulation<DIM>::GetElementCorrespondingToCell(CellPtr pCell)
00150 {
00151     return mrMesh.GetElement(this->mCellLocationMap[pCell.get()]);
00152 }
00153 
00154 template<unsigned DIM>
00155 CellPtr PottsBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00156 {
00157     // Get the element associated with this cell
00158     PottsElement<DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
00159 
00160     // Divide the element
00161     unsigned new_element_index = mrMesh.DivideElement(p_element, true); // new element will be below the existing element
00162 
00163     // Associate the new cell with the element
00164     this->mCells.push_back(pNewCell);
00165 
00166     // Update location cell map
00167     CellPtr p_created_cell = this->mCells.back();
00168     this->mLocationCellMap[new_element_index] = p_created_cell;
00169     this->mCellLocationMap[p_created_cell.get()] = new_element_index;
00170     return p_created_cell;
00171 }
00172 
00173 template<unsigned DIM>
00174 unsigned PottsBasedCellPopulation<DIM>::RemoveDeadCells()
00175 {
00176     unsigned num_removed = 0;
00177 
00178     for (std::list<CellPtr>::iterator it = this->mCells.begin();
00179          it != this->mCells.end();
00180          ++it)
00181     {
00182         if ((*it)->IsDead())
00183         {
00184             // Remove the element from the mesh
00185             num_removed++;
00186             mrMesh.DeleteElement(this->mCellLocationMap[(*it).get()]);
00187             it = this->mCells.erase(it);
00188             --it;
00189         }
00190     }
00191     return num_removed;
00192 }
00193 template<unsigned DIM>
00194 void PottsBasedCellPopulation<DIM>::UpdateCellLocations(double dt)
00195 {
00196     /*
00197      * This method implements a Monte Carlo method to update the cell population.
00198      * We sample randomly from all nodes in the mesh. Once we have selected a target
00199      * node we randomly select a neighbour. The Hamiltonian is evaluated in the
00200      * current configuration (H_0) and with the target node added to the same
00201      * element as the neighbour (H_1). Based on the vale of deltaH = H_1 - H_0,
00202      * the switch is either made or not.
00203      *
00204      * For each time step (i.e. each time this method is called) we sample
00205      * mrMesh.GetNumNodes() nodes. This is known as a Monte Carlo Step (MCS).
00206      */
00207 
00208     RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00209     unsigned num_nodes = mrMesh.GetNumNodes();
00210 
00211     // Randomly permute mUpdateRuleCollection if specified
00212     if (this->mIterateRandomlyOverUpdateRuleCollection)
00213     {
00215         std::random_shuffle(mUpdateRuleCollection.begin(), mUpdateRuleCollection.end());
00216     }
00217 
00218     for (unsigned i=0; i<num_nodes*mNumSweepsPerTimestep; i++)
00219     {
00220         unsigned node_index;
00221 
00222         if (this->mUpdateNodesInRandomOrder)
00223         {
00224             node_index = p_gen->randMod(num_nodes);
00225         }
00226         else
00227         {
00228             // Loop over nodes in index order.
00229             node_index = i%num_nodes;
00230         }
00231 
00232         Node<DIM>* p_node = mrMesh.GetNode(node_index);
00233 
00234         // Each node in the mesh must be in at most one element
00235         assert(p_node->GetNumContainingElements() <= 1);
00236 
00237         // Find a random available neighbouring node to overwrite current site
00238         std::set<unsigned> neighbouring_node_indices = mrMesh.GetMooreNeighbouringNodeIndices(node_index);
00239         unsigned neighbour_location_index;
00240 
00241         if (!neighbouring_node_indices.empty())
00242         {
00243             unsigned num_neighbours = neighbouring_node_indices.size();
00244             unsigned chosen_neighbour = p_gen->randMod(num_neighbours);
00245 
00246             std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00247             for (unsigned i=0; i<chosen_neighbour; i++)
00248             {
00249                 neighbour_iter++;
00250             }
00251 
00252             neighbour_location_index = *neighbour_iter;
00253         }
00254         else
00255         {
00256             // Each node in the mesh must have at least one neighbour
00257             NEVER_REACHED;
00258         }
00259 
00260         std::set<unsigned> containing_elements = p_node->rGetContainingElementIndices();
00261         std::set<unsigned> neighbour_containing_elements = GetNode(neighbour_location_index)->rGetContainingElementIndices();
00262         // Only calculate Hamiltonian and update elements if the nodes are from different elements, or one is from the medium
00263         if (  (  *containing_elements.begin() != *neighbour_containing_elements.begin() && !containing_elements.empty() && !neighbour_containing_elements.empty() )
00264                 || ( !containing_elements.empty() && neighbour_containing_elements.empty() )
00265                 || ( containing_elements.empty() && !neighbour_containing_elements.empty() ) )
00266         {
00267             double delta_H = 0.0; // This is H_1-H_0.
00268 
00269             // Now add contributions to the Hamiltonian from each AbstractPottsUpdateRule
00270             for (typename std::vector<boost::shared_ptr<AbstractPottsUpdateRule<DIM> > >::iterator iter = mUpdateRuleCollection.begin();
00271                  iter != mUpdateRuleCollection.end();
00272                  ++iter)
00273             {
00274                 delta_H += (*iter)->EvaluateHamiltonianContribution(neighbour_location_index, p_node->GetIndex(), *this);
00275             }
00276 
00277             // Generate a uniform random number to do the random motion
00278             double random_number = p_gen->ranf();
00279             double p = exp(-delta_H/mTemperature);
00280             if (delta_H <= 0 || random_number < p)
00281             {
00282                 // Do swap
00283 
00284                 // Remove the current node from any elements containing it (there should be at most one such element)
00285                 for (std::set<unsigned>::iterator iter = containing_elements.begin();
00286                      iter != containing_elements.end();
00287                      ++iter)
00288                 {
00289                     GetElement(*iter)->DeleteNode(GetElement(*iter)->GetNodeLocalIndex(node_index));
00290 
00292                 }
00293 
00294                 // Next add the current node to any elements containing the neighbouring node (there should be at most one such element)
00295                 for (std::set<unsigned>::iterator iter = neighbour_containing_elements.begin();
00296                      iter != neighbour_containing_elements.end();
00297                      ++iter)
00298                 {
00299                     GetElement(*iter)->AddNode(mrMesh.GetNode(node_index));
00300                 }
00301             }
00302         }
00303     }
00304 }
00305 
00306 template<unsigned DIM>
00307 bool PottsBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell)
00308 {
00309     return GetElementCorrespondingToCell(pCell)->IsDeleted();
00310 }
00311 
00312 template<unsigned DIM>
00313 void PottsBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00314 {
00315 }
00316 
00317 template<unsigned DIM>
00318 void PottsBasedCellPopulation<DIM>::CreateOutputFiles(const std::string& rDirectory, bool cleanOutputDirectory)
00319 {
00320     AbstractCellPopulation<DIM>::CreateOutputFiles(rDirectory, cleanOutputDirectory);
00321 
00322     OutputFileHandler output_file_handler(rDirectory, cleanOutputDirectory);
00323     mpVizElementsFile = output_file_handler.OpenOutputFile("results.vizelements");
00324 }
00325 
00326 template<unsigned DIM>
00327 void PottsBasedCellPopulation<DIM>::CloseOutputFiles()
00328 {
00329     AbstractCellPopulation<DIM>::CloseOutputFiles();
00330     mpVizElementsFile->close();
00331 }
00332 
00333 template<unsigned DIM>
00334 void PottsBasedCellPopulation<DIM>::WriteResultsToFiles()
00335 {
00336     AbstractCellPopulation<DIM>::WriteResultsToFiles();
00337 
00338     CreateElementTessellation(); // To be used to output to the visualiser
00339 
00340     SimulationTime* p_time = SimulationTime::Instance();
00341 
00342     // Write element data to file
00343     *mpVizElementsFile << p_time->GetTime() << "\t";
00344 
00345     // Loop over cells and find associated elements so in the same order as the cells in output files
00346     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00347          cell_iter != this->mCells.end();
00348          ++cell_iter)
00349     {
00350         unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
00351 
00352         // Hack that covers the case where the element is associated with a cell that has just been killed (#11DIM9)
00353         bool elem_corresponds_to_dead_cell = false;
00354 
00355         if (this->mLocationCellMap[elem_index])
00356         {
00357             elem_corresponds_to_dead_cell = this->mLocationCellMap[elem_index]->IsDead();
00358         }
00359 
00360         // Write node data to file
00361         if (!(GetElement(elem_index)->IsDeleted()) && !elem_corresponds_to_dead_cell)
00362         {
00363             PottsElement<DIM>* p_element = mrMesh.GetElement(elem_index);
00364 
00365             unsigned num_nodes_in_element = p_element->GetNumNodes();
00366 
00367             // First write the number of Nodes belonging to this PottsElement
00368             *mpVizElementsFile << num_nodes_in_element << " ";
00369 
00370             // Then write the global index of each Node in this element
00371             for (unsigned i=0; i<num_nodes_in_element; i++)
00372             {
00373                 *mpVizElementsFile << p_element->GetNodeGlobalIndex(i) << " ";
00374             }
00375         }
00376     }
00377     *mpVizElementsFile << "\n";
00378 }
00379 
00380 template<unsigned DIM>
00381 void PottsBasedCellPopulation<DIM>::WriteCellVolumeResultsToFile()
00382 {
00383     // Write time to file
00384     *(this->mpCellVolumesFile) << SimulationTime::Instance()->GetTime() << " ";
00385 
00386     // Loop over cells and find associated elements so in the same order as the cells in output files
00387      for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00388          cell_iter != this->End();
00389          ++cell_iter)
00390     {
00391         unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
00392 
00393         // Hack that covers the case where the element is associated with a cell that has just been killed (#1129)
00394         bool elem_corresponds_to_dead_cell = false;
00395 
00396         if (this->mLocationCellMap[elem_index])
00397         {
00398             elem_corresponds_to_dead_cell = this->mLocationCellMap[elem_index]->IsDead();
00399         }
00400 
00401         // Write node data to file
00402         if (!(GetElement(elem_index)->IsDeleted()) && !elem_corresponds_to_dead_cell)
00403         {
00404            // Write element index to file
00405             *(this->mpCellVolumesFile) << elem_index << " ";
00406 
00407             // Write cell ID to file
00408             unsigned cell_index = cell_iter->GetCellId();
00409             *(this->mpCellVolumesFile) << cell_index << " ";
00410 
00411             // Write centroid location to file
00412             c_vector<double, DIM> centroid_location = mrMesh.GetCentroidOfElement(elem_index);
00413 
00414             *(this->mpCellVolumesFile) << centroid_location[0] << " ";
00415             *(this->mpCellVolumesFile) << centroid_location[1] << " ";
00416 
00417             // Write cell volume (in 3D) or area (in 2D) to file
00418             double cell_volume = mrMesh.GetVolumeOfElement(elem_index);
00419             *(this->mpCellVolumesFile) << cell_volume << " ";
00420         }
00421     }
00422     *(this->mpCellVolumesFile) << "\n";
00423 }
00424 
00425 template<unsigned DIM>
00426 void PottsBasedCellPopulation<DIM>::GenerateCellResultsAndWriteToFiles()
00427 {
00428     // Set up cell type counter
00429     unsigned num_cell_types = this->mCellProliferativeTypeCount.size();
00430     std::vector<unsigned> cell_type_counter(num_cell_types);
00431     for (unsigned i=0; i<num_cell_types; i++)
00432     {
00433         cell_type_counter[i] = 0;
00434     }
00435 
00436     // Set up cell cycle phase counter
00437     unsigned num_cell_cycle_phases = this->mCellCyclePhaseCount.size();
00438     std::vector<unsigned> cell_cycle_phase_counter(num_cell_cycle_phases);
00439     for (unsigned i=0; i<num_cell_cycle_phases; i++)
00440     {
00441         cell_cycle_phase_counter[i] = 0;
00442     }
00443 
00444     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00445          cell_iter != this->End();
00446          ++cell_iter)
00447     {
00448         this->GenerateCellResults(this->GetLocationIndexUsingCell(*cell_iter), cell_type_counter, cell_cycle_phase_counter);
00449     }
00450 
00451     this->WriteCellResultsToFiles(cell_type_counter, cell_cycle_phase_counter);
00452 }
00453 
00454 template<unsigned DIM>
00455 double PottsBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00456 {
00457     // Call GetWidth() on the mesh
00458     double width = mrMesh.GetWidth(rDimension);
00459 
00460     return width;
00461 }
00462 
00463 template<unsigned DIM>
00464 void PottsBasedCellPopulation<DIM>::AddUpdateRule(boost::shared_ptr<AbstractPottsUpdateRule<DIM> > pUpdateRule)
00465 {
00466     mUpdateRuleCollection.push_back(pUpdateRule);
00467 }
00468 
00469 template<unsigned DIM>
00470 const std::vector<boost::shared_ptr<AbstractPottsUpdateRule<DIM> > >& PottsBasedCellPopulation<DIM>::rGetUpdateRuleCollection() const
00471 {
00472     return mUpdateRuleCollection;
00473 }
00474 
00475 template<unsigned DIM>
00476 void PottsBasedCellPopulation<DIM>::CreateElementTessellation()
00477 {
00479 //  delete mpElementTessellation;
00480 //
00481 //    ///\todo this code would need to be extended if the domain were required to be periodic
00482 //
00483 //  std::vector<Node<2>*> nodes;
00484 //  for (unsigned node_index=0; node_index<mrMesh.GetNumNodes(); node_index++)
00485 //  {
00486 //      Node<2>* p_temp_node = mrMesh.GetNode(node_index);
00487 //      nodes.push_back(p_temp_node);
00488 //  }
00489 //  MutableMesh<2,2> mesh(nodes);
00490 //    mpElementTessellation = new VertexMesh<2,2>(mesh);
00491 }
00492 
00493 template<unsigned DIM>
00494 VertexMesh<DIM,DIM>* PottsBasedCellPopulation<DIM>::GetElementTessellation()
00495 {
00496 //    assert(mpElementTessellation != NULL);
00497     return mpElementTessellation;
00498 }
00499 
00500 template<unsigned DIM>
00501 void PottsBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00502 {
00503     *rParamsFile << "\t\t<Temperature>" << mTemperature << "</Temperature>\n";
00504     *rParamsFile << "\t\t<NumSweepsPerTimestep>" << mNumSweepsPerTimestep << "</NumSweepsPerTimestep>\n";
00505 
00506     // Call method on direct parent class
00507     AbstractOnLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00508 }
00509 
00510 template<unsigned DIM>
00511 std::set<unsigned> PottsBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00512 {
00513     EXCEPTION("Cannot call GetNeighbouringNodeIndices() on a PottsBasedCellPopulation, need to go through the PottsMesh instead");
00514     std::set<unsigned> neighbouring_node_indices;
00515     return neighbouring_node_indices;
00516 }
00517 
00518 template<unsigned DIM>
00519 void PottsBasedCellPopulation<DIM>::SetTemperature(double temperature)
00520 {
00521     mTemperature = temperature;
00522 }
00523 
00524 template<unsigned DIM>
00525 double PottsBasedCellPopulation<DIM>::GetTemperature()
00526 {
00527     return mTemperature;
00528 }
00529 
00530 template<unsigned DIM>
00531 void PottsBasedCellPopulation<DIM>::SetNumSweepsPerTimestep(unsigned numSweepsPerTimestep)
00532 {
00533     mNumSweepsPerTimestep = numSweepsPerTimestep;
00534 }
00535 
00536 template<unsigned DIM>
00537 unsigned PottsBasedCellPopulation<DIM>::GetNumSweepsPerTimestep()
00538 {
00539     return mNumSweepsPerTimestep;
00540 }
00541 
00542 template<unsigned DIM>
00543 void PottsBasedCellPopulation<DIM>::WriteVtkResultsToFile()
00544 {
00545 #ifdef CHASTE_VTK
00546     std::stringstream time;
00547     time << SimulationTime::Instance()->GetTimeStepsElapsed();
00548     VtkMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results_"+time.str(), false);
00549 
00550     unsigned num_nodes = GetNumNodes();
00551     std::vector<double> cell_types;
00552     std::vector<double> cell_mutation_states;
00553     std::vector<double> cell_labels;
00554     std::vector<double> elem_ids;
00555     cell_types.reserve(num_nodes);
00556     cell_mutation_states.reserve(num_nodes);
00557     cell_labels.reserve(num_nodes);
00558     elem_ids.reserve(num_nodes);
00559 
00560     for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mrMesh.GetNodeIteratorBegin();
00561          iter != mrMesh.GetNodeIteratorEnd();
00562          ++iter)
00563     {
00564         std::set<unsigned> element_indices = iter->rGetContainingElementIndices();
00565 
00566         if (element_indices.empty())
00567         {
00568             // No elements associated with this gridpoint
00569             cell_types.push_back(-1.0);
00570             elem_ids.push_back(-1.0);
00571             if (this->mOutputCellMutationStates)
00572             {
00573                 cell_mutation_states.push_back(-1.0);
00574                 cell_labels.push_back(-1.0);
00575             }
00576         }
00577         else
00578         {
00579             // The number of elements should be zero or one
00580             assert(element_indices.size() == 1);
00581 
00582             unsigned element_index = *(element_indices.begin());
00583             elem_ids.push_back((double)element_index);
00584 
00585             CellPtr p_cell = this->mLocationCellMap[element_index];
00586             double cell_type = p_cell->GetCellCycleModel()->GetCellProliferativeType();
00587             cell_types.push_back(cell_type);
00588 
00589             if (this->mOutputCellMutationStates)
00590             {
00591                 double cell_mutation_state = p_cell->GetMutationState()->GetColour();
00592                 cell_mutation_states.push_back(cell_mutation_state);
00593 
00594                 double cell_label = 0.0;
00595                 if (p_cell->HasCellProperty<CellLabel>())
00596                 {
00597                     CellPropertyCollection collection = p_cell->rGetCellPropertyCollection().GetProperties<CellLabel>();
00598                     boost::shared_ptr<CellLabel> p_label = boost::static_pointer_cast<CellLabel>(collection.GetProperty());
00599                     cell_label = p_label->GetColour();
00600                 }
00601                 cell_labels.push_back(cell_label);
00602             }
00603         }
00604     }
00605 
00606     assert(cell_types.size() == num_nodes);
00607     assert(elem_ids.size() == num_nodes);
00608 
00609     mesh_writer.AddPointData("Element index", elem_ids);
00610     mesh_writer.AddPointData("Cell types", cell_types);
00611 
00612     if (this->mOutputCellMutationStates)
00613     {
00614         assert(cell_mutation_states.size() == num_nodes);
00615         mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00616         assert(cell_labels.size() == num_nodes);
00617         mesh_writer.AddPointData("Cell labels", cell_labels);
00618     }
00619 
00620     /*
00621      * The current VTK writer can only write things which inherit from AbstractTetrahedralMeshWriter.
00622      * For now, we do an explicit conversion to NodesOnlyMesh. This can be written to VTK then visualized as glyphs.
00623      */
00624     NodesOnlyMesh<DIM> temp_mesh;
00625     temp_mesh.ConstructNodesWithoutMesh(mrMesh);
00626     mesh_writer.WriteFilesUsingMesh(temp_mesh);
00627 
00628     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00629     *(this->mpVtkMetaFile) << time.str();
00630     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00631     *(this->mpVtkMetaFile) << time.str();
00632     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00633 #endif //CHASTE_VTK
00634 }
00635 
00637 // Explicit instantiation
00639 
00640 template class PottsBasedCellPopulation<1>;
00641 template class PottsBasedCellPopulation<2>;
00642 template class PottsBasedCellPopulation<3>;
00643 
00644 // Serialization for Boost >= 1.36
00645 #include "SerializationExportWrapperForCpp.hpp"
00646 EXPORT_TEMPLATE_CLASS_SAME_DIMS(PottsBasedCellPopulation)
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3