CaBasedCellPopulation.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 "CaBasedCellPopulation.hpp"
00037 
00038 #include <boost/scoped_array.hpp>
00039 
00040 #include "RandomNumberGenerator.hpp"
00041 #include "Warnings.hpp"
00042 
00043 // Needed to convert mesh in order to write nodes to VTK (visualize as glyphs)
00044 #include "VtkMeshWriter.hpp"
00045 
00046 // Cell writers
00047 #include "CellAgesWriter.hpp"
00048 #include "CellAncestorWriter.hpp"
00049 #include "CellLocationWriter.hpp"
00050 #include "CellProliferativePhasesWriter.hpp"
00051 #include "CellProliferativeTypesWriter.hpp"
00052 
00053 // Cell population writers
00054 #include "CellMutationStatesWriter.hpp"
00055 
00056 #include "NodesOnlyMesh.hpp"
00057 #include "Exception.hpp"
00058 
00059 template<unsigned DIM>
00060 void CaBasedCellPopulation<DIM>::Validate()
00061 {
00062     NEVER_REACHED;
00063 }
00064 
00065 template<unsigned DIM>
00066 CaBasedCellPopulation<DIM>::CaBasedCellPopulation(PottsMesh<DIM>& rMesh,
00067                                                         std::vector<CellPtr>& rCells,
00068                                                         const std::vector<unsigned> locationIndices,
00069                                                         unsigned latticeCarryingCapacity,
00070                                                         bool deleteMesh,
00071                                                         bool validate)
00072     : AbstractOnLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh),
00073       mLatticeCarryingCapacity(latticeCarryingCapacity)
00074 {
00075     mAvailableSpaces = std::vector<unsigned>(this->GetNumNodes(), latticeCarryingCapacity);
00076 
00077     // This must always be true
00078     assert(this->mCells.size() <= this->mrMesh.GetNumNodes()*latticeCarryingCapacity);
00079 
00080     if (locationIndices.empty())
00081     {
00082         EXCEPTION("No location indices being passed. Specify where cells lie before creating the cell population.");
00083     }
00084     else
00085     {
00086         // Create a set of node indices corresponding to empty sites.
00087         // Note iterating over mCells is OK as it has the same order as location indices at this point (its just coppied from rCells)
00088         std::list<CellPtr>::iterator it = this->mCells.begin();
00089         for (unsigned i=0; it != this->mCells.end(); ++it, ++i)
00090         {
00091             assert(i<locationIndices.size());
00092             if (!IsSiteAvailable(locationIndices[i],*it))
00093             {
00094                 EXCEPTION("One of the lattice sites has more cells than the carrying capacity. Check the initial cell locations.");
00095             }
00096             mAvailableSpaces[locationIndices[i]]--;
00097         }
00098     }
00099     if (validate)
00100     {
00101         EXCEPTION("There is no validation for CaBasedCellPopulation.");
00102     }
00103 }
00104 
00105 template<unsigned DIM>
00106 CaBasedCellPopulation<DIM>::CaBasedCellPopulation(PottsMesh<DIM>& rMesh)
00107     : AbstractOnLatticeCellPopulation<DIM>(rMesh)
00108 {
00109 }
00110 
00111 template<unsigned DIM>
00112 CaBasedCellPopulation<DIM>::~CaBasedCellPopulation()
00113 {
00114     if (this->mDeleteMesh)
00115     {
00116         delete &this->mrMesh;
00117     }
00118 }
00119 
00120 template<unsigned DIM>
00121 std::vector<unsigned>& CaBasedCellPopulation<DIM>::rGetAvailableSpaces()
00122 {
00123     return mAvailableSpaces;
00124 }
00125 
00126 template<unsigned DIM>
00127 bool CaBasedCellPopulation<DIM>::IsSiteAvailable(unsigned index, CellPtr pCell)
00128 {
00130     return (mAvailableSpaces[index] != 0);
00131 }
00132 
00133 template<unsigned DIM>
00134 PottsMesh<DIM>& CaBasedCellPopulation<DIM>::rGetMesh()
00135 {
00136     return static_cast<PottsMesh<DIM>& >((this->mrMesh));
00137 }
00138 
00139 template<unsigned DIM>
00140 const PottsMesh<DIM>& CaBasedCellPopulation<DIM>::rGetMesh() const
00141 {
00142     return static_cast<PottsMesh<DIM>& >((this->mrMesh));
00143 }
00144 
00145 template<unsigned DIM>
00146 Node<DIM>* CaBasedCellPopulation<DIM>::GetNode(unsigned index)
00147 {
00148     return this->mrMesh.GetNode(index);
00149 }
00150 
00151 template<unsigned DIM>
00152 unsigned CaBasedCellPopulation<DIM>::GetNumNodes()
00153 {
00154     return this->mrMesh.GetNumNodes();
00155 }
00156 
00157 template<unsigned DIM>
00158 c_vector<double, DIM> CaBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell)
00159 {
00160     return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell))->rGetLocation();
00161 }
00162 
00163 template<unsigned DIM>
00164 Node<DIM>* CaBasedCellPopulation<DIM>::GetNodeCorrespondingToCell(CellPtr pCell)
00165 {
00166     return this->mrMesh.GetNode(this->GetLocationIndexUsingCell(pCell));
00167 }
00168 
00169 template<unsigned DIM>
00170 void CaBasedCellPopulation<DIM>::AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
00171 {
00172     if (!IsSiteAvailable(index, pCell))
00173     {
00174         EXCEPTION("No available spaces at location index " << index << ".");
00175     }
00176 
00177     mAvailableSpaces[index]--;
00178     AbstractCellPopulation<DIM,DIM>::AddCellUsingLocationIndex(index, pCell);
00179 }
00180 
00181 template<unsigned DIM>
00182 void CaBasedCellPopulation<DIM>::RemoveCellUsingLocationIndex(unsigned index, CellPtr pCell)
00183 {
00184     AbstractCellPopulation<DIM,DIM>::RemoveCellUsingLocationIndex(index, pCell);
00185 
00186     mAvailableSpaces[index]++;
00187 
00188     assert(mAvailableSpaces[index] <= mLatticeCarryingCapacity);
00189 }
00190 
00191 template<unsigned DIM>
00192 bool CaBasedCellPopulation<DIM>::IsRoomToDivide(CellPtr pCell)
00193 {
00194     bool is_room = false;
00195 
00196     // Get node index corresponding to this cell
00197     unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00198 
00199     // Get the set of neighbouring node indices
00200     std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
00201 
00202     // Iterate through the neighbours to see if there are any available sites
00203     for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00204          neighbour_iter != neighbouring_node_indices.end();
00205          ++neighbour_iter)
00206     {
00207         if (IsSiteAvailable(*neighbour_iter, pCell))
00208         {
00209             is_room = true;
00210             break;
00211         }
00212     }
00213 
00214     return is_room;
00215 }
00216 
00217 template<unsigned DIM>
00218 CellPtr CaBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00219 {
00220     // Get node index corresponding to the parent cell
00221     unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
00222 
00223     // Get the set of neighbouring node indices
00224     std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(parent_node_index);
00225     unsigned num_neighbours = neighbouring_node_indices.size();
00226 
00227     // Each node must have at least one neighbour
00228     assert(!neighbouring_node_indices.empty());
00229 
00230     std::vector<double> neighbouring_node_propensities;
00231     std::vector<unsigned> neighbouring_node_indices_vector;
00232 
00233     double total_propensity = 0.0;
00234 
00235     for (std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin();
00236             neighbour_iter != neighbouring_node_indices.end();
00237          ++neighbour_iter)
00238     {
00239         neighbouring_node_indices_vector.push_back(*neighbour_iter);
00240 
00241         double propensity_dividing_into_neighbour = EvaluateDivisionPropensity(parent_node_index,*neighbour_iter,pParentCell);
00242 
00243         if (!IsSiteAvailable(*neighbour_iter, pParentCell))
00244         {
00245             propensity_dividing_into_neighbour = 0.0;
00246         }
00247         neighbouring_node_propensities.push_back(propensity_dividing_into_neighbour);
00248         total_propensity += propensity_dividing_into_neighbour;
00249     }
00250 
00251     assert(total_propensity>0); // if this trips the cell cant divided so need to include this in the IsSiteAvailable method
00252 
00253     for (unsigned i=0; i<num_neighbours; i++)
00254     {
00255         neighbouring_node_propensities[i] /= total_propensity;
00256     }
00257 
00258      // Sample random number to specify which move to make
00259     RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00260     double random_number = p_gen->ranf();
00261 
00262     double total_probability = 0.0;
00263     unsigned daughter_node_index = UNSIGNED_UNSET;
00264 
00265     unsigned counter;
00266     for (counter=0; counter < num_neighbours; counter++)
00267     {
00268         total_probability += neighbouring_node_propensities[counter];
00269         if (total_probability >= random_number)
00270         {
00271             // Divide the parent cell to this neighbour location
00272             daughter_node_index = neighbouring_node_indices_vector[counter];
00273             break;
00274         }
00275     }
00276     // This loop should always break as sum(neighbouring_node_propensities) = 1
00277 
00278     assert(daughter_node_index != UNSIGNED_UNSET);
00279     assert(daughter_node_index < this->mrMesh.GetNumNodes());
00280 
00281     // Associate the new cell with the element
00282     this->mCells.push_back(pNewCell);
00283 
00284     // Update location cell map
00285     CellPtr p_created_cell = this->mCells.back();
00286     AddCellUsingLocationIndex(daughter_node_index,p_created_cell);
00287 
00288     return p_created_cell;
00289 }
00290 
00291 template<unsigned DIM>
00292 double CaBasedCellPopulation<DIM>:: EvaluateDivisionPropensity(unsigned currentNodeIndex,
00293                                                                        unsigned targetNodeIndex,
00294                                                                        CellPtr pCell)
00295 {
00296     return 1.0;
00297 }
00298 
00299 template<unsigned DIM>
00300 unsigned CaBasedCellPopulation<DIM>::RemoveDeadCells()
00301 {
00302     unsigned num_removed = 0;
00303 
00304     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00305          cell_iter != this->mCells.end();
00306          )
00307     {
00308         if ((*cell_iter)->IsDead())
00309         {
00310             // Get the index of the node corresponding to this cell
00311             unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00312 
00313             RemoveCellUsingLocationIndex(node_index, (*cell_iter));
00314 
00315             // Erase cell and update counter
00316             num_removed++;
00317             cell_iter = this->mCells.erase(cell_iter);
00318         }
00319         else
00320         {
00321             ++cell_iter;
00322         }
00323     }
00324     return num_removed;
00325 }
00326 
00327 template<unsigned DIM>
00328 void CaBasedCellPopulation<DIM>::UpdateCellLocations(double dt)
00329 {
00330     // Iterate over cells
00332     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00333          cell_iter != this->mCells.end();
00334          ++cell_iter)
00335     {
00336         // Loop over neighbours and calculate probability of moving (make sure all probabilities are <1)
00337         unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00338 
00339         // Find a random available neighbouring node to overwrite current site
00340         std::set<unsigned> neighbouring_node_indices = static_cast<PottsMesh<DIM>& >((this->mrMesh)).GetMooreNeighbouringNodeIndices(node_index);
00341         std::vector<double> neighbouring_node_propensities;
00342         std::vector<unsigned> neighbouring_node_indices_vector;
00343 
00344         if (!neighbouring_node_indices.empty())
00345         {
00346             unsigned num_neighbours = neighbouring_node_indices.size();
00347             double probability_of_not_moving = 1.0;
00348 
00349             for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00350                  iter != neighbouring_node_indices.end();
00351                  ++iter)
00352             {
00353                 double probability_of_moving = 0.0;
00354 
00355                 neighbouring_node_indices_vector.push_back(*iter);
00356 
00357                 if (IsSiteAvailable(*iter, *cell_iter))
00358                 {
00359                     // Iterating over the update rule
00360                     for (typename std::vector<boost::shared_ptr<AbstractCaUpdateRule<DIM> > >::iterator iterRule = mUpdateRuleCollection.begin();
00361                          iterRule != mUpdateRuleCollection.end();
00362                          ++iterRule)
00363                     {
00364                         probability_of_moving += (*iterRule)->EvaluateProbability(node_index, *iter, *this, dt, 1, *cell_iter);
00365                         if (probability_of_moving < 0)
00366                         {
00367                             EXCEPTION("The probability of cellular movement is smaller than zero. In order to prevent it from happening you should change your time step and parameters");
00368                         }
00369 
00370                         if (probability_of_moving > 1)
00371                         {
00372                             EXCEPTION("The probability of the cellular movement is bigger than one. In order to prevent it from happening you should change your time step and parameters");
00373                         }
00374                     }
00375 
00376                     probability_of_not_moving -= probability_of_moving;
00377                     neighbouring_node_propensities.push_back(probability_of_moving);
00378                 }
00379                 else
00380                 {
00381                     neighbouring_node_propensities.push_back(0.0);
00382                 }
00383             }
00384             if (probability_of_not_moving < 0)
00385             {
00386                 EXCEPTION("The probability of the cell not moving is smaller than zero. In order to prevent it from happening you should change your time step and parameters");
00387             }
00388 
00389             // Sample random number to specify which move to make
00390             RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00391             double random_number = p_gen->ranf();
00392 
00393             double total_probability = 0.0;
00394             for (unsigned counter=0; counter<num_neighbours; counter++)
00395             {
00396                 total_probability += neighbouring_node_propensities[counter];
00397                 if (total_probability >= random_number)
00398                 {
00399                     //Move the cell to this neighbour location
00400                     unsigned chosen_neighbour_location_index = neighbouring_node_indices_vector[counter];
00401                     this->MoveCellInLocationMap((*cell_iter), node_index, chosen_neighbour_location_index);
00402                     break;
00403                 }
00404             }
00405             // If loop completes with total_probability < random_number then stay in the same location
00406         }
00407         else
00408         {
00409             // Each node in the mesh must have at least one neighbour
00410             NEVER_REACHED;
00411         }
00412     }
00413 }
00414 
00415 template<unsigned DIM>
00416 bool CaBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell)
00417 {
00418     return false;
00419 }
00420 
00421 template<unsigned DIM>
00422 void CaBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00423 {
00424 }
00425 
00426 template<unsigned DIM>
00427 void CaBasedCellPopulation<DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<DIM, DIM> > pPopulationWriter)
00428 {
00429     pPopulationWriter->Visit(this);
00430 }
00431 
00432 template<unsigned DIM>
00433 void CaBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00434 {
00435     pCellWriter->VisitCell(pCell, this);
00436 }
00437 
00438 template<unsigned DIM>
00439 void CaBasedCellPopulation<DIM>::OpenWritersFiles(const std::string& rDirectory)
00440 {
00441     if (this->mOutputResultsForChasteVisualizer)
00442     {
00443         if (!this-> template HasWriter<CellLocationWriter>())
00444         {
00445             this-> template AddCellWriter<CellLocationWriter>();
00446         }
00447     }
00448 
00449     AbstractCellPopulation<DIM>::OpenWritersFiles(rDirectory);
00450 }
00451 
00452 template<unsigned DIM>
00453 double CaBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00454 {
00455     double cell_volume = 1.0;
00456     return cell_volume;
00457 }
00458 
00459 template<unsigned DIM>
00460 double CaBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00461 {
00462     double width = this->mrMesh.GetWidth(rDimension);
00463     return width;
00464 }
00465 
00466 template<unsigned DIM>
00467 void CaBasedCellPopulation<DIM>::AddUpdateRule(boost::shared_ptr<AbstractCaUpdateRule<DIM> > pUpdateRule)
00468 {
00469     mUpdateRuleCollection.push_back(pUpdateRule);
00470 }
00471 
00472 template<unsigned DIM>
00473 void CaBasedCellPopulation<DIM>::RemoveAllUpdateRules()
00474 {
00475     mUpdateRuleCollection.clear();
00476 }
00477 
00478 template<unsigned DIM>
00479 const std::vector<boost::shared_ptr<AbstractCaUpdateRule<DIM> > >& CaBasedCellPopulation<DIM>::rGetUpdateRuleCollection() const
00480 {
00481     return mUpdateRuleCollection;
00482 }
00483 
00484 template<unsigned DIM>
00485 void CaBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00486 {
00487     // Call method on direct parent class
00488     AbstractOnLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00489 }
00490 
00491 template<unsigned DIM>
00492 void CaBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00493 {
00494 #ifdef CHASTE_VTK
00495     unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
00496     std::stringstream time;
00497     time << num_timesteps;
00498 
00499     VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
00500 
00501     unsigned num_cells = this->GetNumRealCells();
00502     std::vector<double> cell_types(num_cells, -1.0);
00503     std::vector<double> cell_mutation_states(num_cells, -1.0);
00504     std::vector<double> cell_ids(num_cells, -1.0);
00505     std::vector<double> cell_ancestors(num_cells, -1.0);
00506     std::vector<double> cell_ages(num_cells, -1.0);
00507     std::vector<double> cell_cycle_phases(num_cells, -1.0);
00508     std::vector<Node<DIM>*> nodes;
00509 
00510     // When outputting any CellData, we assume that the first cell is representative of all cells
00511     unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00512     std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
00513 
00514     std::vector<std::vector<double> > cell_data;
00515     for (unsigned var=0; var<num_cell_data_items; var++)
00516     {
00517         std::vector<double> cell_data_var(num_cells);
00518         cell_data.push_back(cell_data_var);
00519     }
00520 
00521     unsigned cell = 0;
00522 
00523     // Counter to keep track of how many cells are at a lattice site
00524     unsigned num_sites = this->mrMesh.GetNumNodes();
00525     boost::scoped_array<unsigned> number_of_cells_at_site(new unsigned[num_sites]);
00526     for (unsigned i=0; i<num_sites; i++)
00527     {
00528         number_of_cells_at_site[i] = 0;
00529     }
00530 
00531     for (std::list<CellPtr>::iterator iter = this->mCells.begin();
00532          iter != this->mCells.end();
00533          ++iter)
00534     {
00535         CellPtr cell_ptr = *iter;
00536         cell_ids[cell] = cell_ptr->GetCellId();
00537 
00538         unsigned location_index = this->GetLocationIndexUsingCell(*iter);
00539 
00540         number_of_cells_at_site[location_index]++;
00541         assert(number_of_cells_at_site[location_index]<=mLatticeCarryingCapacity);
00542 
00543         // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
00544         c_vector<double, DIM> coords;
00545         coords = this->mrMesh.GetNode(location_index)->rGetLocation();
00546 
00547         // Move the coordinate slightly so that we can visualise all cells in a lattice site if there is more than one per site
00548         if (mLatticeCarryingCapacity > 1)
00549         {
00550             c_vector<double, DIM> offset;
00551 
00552             if (DIM == 2)
00553             {
00554                 double angle = (double)number_of_cells_at_site[location_index]*2.0*M_PI/(double)mLatticeCarryingCapacity;
00555                 offset[0] = 0.2*sin(angle);
00556                 offset[1] = 0.2*cos(angle);
00557             }
00558             else
00559             {
00560                 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00561 
00562                 for (unsigned i=0; i<DIM; i++)
00563                 {
00564                     offset[i] = p_gen->ranf(); // This assumes that all sites are 1 apart
00565                 }
00566             }
00567 
00568             for (unsigned i=0; i<DIM; i++)
00569             {
00570                 coords[i] += offset[i];
00571             }
00572         }
00573 
00574         nodes.push_back(new Node<DIM>(cell, coords, false));
00575 
00576         if (this-> template HasWriter<CellAncestorWriter>())
00577         {
00578             double ancestor_index = (cell_ptr->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_ptr->GetAncestor();
00579             cell_ancestors[cell] = ancestor_index;
00580         }
00581         if (this-> template HasWriter<CellProliferativeTypesWriter>())
00582         {
00583             cell_types[cell] = cell_ptr->GetCellProliferativeType()->GetColour();
00584         }
00585         if (this-> template HasWriter<CellMutationStatesWriter>())
00586         {
00587             cell_mutation_states[cell] = cell_ptr->GetMutationState()->GetColour();
00588 
00590             CellPropertyCollection collection = cell_ptr->rGetCellPropertyCollection();
00591             CellPropertyCollection label_collection = collection.GetProperties<CellLabel>();
00592 
00593             if (label_collection.GetSize() == 1)
00594             {
00595                 boost::shared_ptr<CellLabel> p_label = boost::static_pointer_cast<CellLabel>(label_collection.GetProperty());
00596                 cell_mutation_states[cell] = p_label->GetColour();
00597             }
00598 
00599         }
00600         if (this-> template HasWriter<CellAgesWriter>())
00601         {
00602             cell_ages[cell] = cell_ptr->GetAge();
00603         }
00604         if (this-> template HasWriter<CellProliferativePhasesWriter>())
00605         {
00606             cell_cycle_phases[cell] = cell_ptr->GetCellCycleModel()->GetCurrentCellCyclePhase();
00607         }
00608         for (unsigned var=0; var<num_cell_data_items; var++)
00609         {
00610             cell_data[var][cell] = cell_ptr->GetCellData()->GetItem(cell_data_names[var]);
00611         }
00612 
00613         cell ++;
00614     }
00615 
00616     // Cell IDs can be used to threshold out the empty lattice sites (which have ID=-1)
00617     mesh_writer.AddPointData("Cell ids", cell_ids);
00618 
00619     if (this-> template HasWriter<CellProliferativeTypesWriter>())
00620     {
00621         mesh_writer.AddPointData("Cell types", cell_types);
00622     }
00623     if (this-> template HasWriter<CellMutationStatesWriter>())
00624     {
00625         mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00626     }
00627     if (this-> template HasWriter<CellAncestorWriter>())
00628     {
00629         mesh_writer.AddPointData("Ancestors", cell_ancestors);
00630     }
00631     if (this-> template HasWriter<CellAgesWriter>())
00632     {
00633         mesh_writer.AddPointData("Ages", cell_ages);
00634     }
00635     if (this-> template HasWriter<CellProliferativePhasesWriter>())
00636     {
00637         mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00638     }
00639     if (num_cell_data_items > 0)
00640     {
00641         for (unsigned var=0; var<cell_data.size(); var++)
00642         {
00643             mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
00644         }
00645     }
00646 
00647     /*
00648      * The current VTK writer can only write things which inherit from AbstractTetrahedralMeshWriter.
00649      * For now, we do an explicit conversion to NodesOnlyMesh. This can be written to VTK then visualized as glyphs.
00650      */
00651     NodesOnlyMesh<DIM> temp_mesh;
00652     temp_mesh.ConstructNodesWithoutMesh(nodes, 1.5);  // Arbitrary cut off as connectivity not used.
00653     mesh_writer.WriteFilesUsingMesh(temp_mesh);
00654 
00655     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00656     *(this->mpVtkMetaFile) << num_timesteps;
00657     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00658     *(this->mpVtkMetaFile) << num_timesteps;
00659     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00660 
00661     // Tidy up
00662     for (unsigned i=0; i<nodes.size(); i++)
00663     {
00664         delete nodes[i];
00665     }
00666 #endif //CHASTE_VTK
00667 }
00668 
00669 // Explicit instantiation
00670 template class CaBasedCellPopulation<1>;
00671 template class CaBasedCellPopulation<2>;
00672 template class CaBasedCellPopulation<3>;
00673 
00674 // Serialization for Boost >= 1.36
00675 #include "SerializationExportWrapperForCpp.hpp"
00676 EXPORT_TEMPLATE_CLASS_SAME_DIMS(CaBasedCellPopulation)

Generated by  doxygen 1.6.2