Chaste Release::3.1
NodeBasedCellPopulation.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, 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 "NodeBasedCellPopulation.hpp"
00037 #include "VtkMeshWriter.hpp"
00038 
00039 template<unsigned DIM>
00040 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh,
00041                                       std::vector<CellPtr>& rCells,
00042                                       const std::vector<unsigned> locationIndices,
00043                                       bool deleteMesh,
00044                                       bool validate)
00045     : AbstractCentreBasedCellPopulation<DIM>(rMesh, rCells, locationIndices),
00046       mDeleteMesh(deleteMesh),
00047       mMechanicsCutOffLength(DBL_MAX),
00048       mUseVariableRadii(false)
00049 {
00050     mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
00051     if (validate)
00052     {
00053         Validate();
00054     }
00055 }
00056 
00057 template<unsigned DIM>
00058 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh)
00059     : AbstractCentreBasedCellPopulation<DIM>(rMesh),
00060       mDeleteMesh(true),
00061       mMechanicsCutOffLength(DBL_MAX), // will be set by serialize() method
00062       mUseVariableRadii(false) // will be set by serialize() method
00063 {
00064     mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
00065     // No Validate() because the cells are not associated with the cell population yet in archiving
00066 }
00067 
00068 template<unsigned DIM>
00069 NodeBasedCellPopulation<DIM>::~NodeBasedCellPopulation()
00070 {
00071     Clear();
00072     if (mDeleteMesh)
00073     {
00074         delete &this->mrMesh;
00075     }
00076 }
00077 
00078 template<unsigned DIM>
00079 NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh()
00080 {
00081     return *mpNodesOnlyMesh;
00082 }
00083 
00084 template<unsigned DIM>
00085 const NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh() const
00086 {
00087     return *mpNodesOnlyMesh;
00088 }
00089 
00090 template<unsigned DIM>
00091 void NodeBasedCellPopulation<DIM>::Clear()
00092 {
00093     mNodePairs.clear();
00094 }
00095 
00096 template<unsigned DIM>
00097 void NodeBasedCellPopulation<DIM>::Validate()
00098 {
00099     std::vector<bool> validated_node(GetNumNodes());
00100     for (unsigned i=0; i<validated_node.size(); i++)
00101     {
00102         validated_node[i] = false;
00103     }
00104 
00105     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
00106     {
00107         unsigned node_index = this->GetLocationIndexUsingCell((*cell_iter));
00108         validated_node[node_index] = true;
00109     }
00110 
00111     for (unsigned i=0; i<validated_node.size(); i++)
00112     {
00113         if (!validated_node[i])
00114         {
00115             EXCEPTION("Node " << i << " does not appear to have a cell associated with it");
00116         }
00117     }
00118 }
00119 
00120 template<unsigned DIM>
00121 void NodeBasedCellPopulation<DIM>::SplitUpIntoBoxes(double cutOffLength, c_vector<double, 2*DIM> domainSize)
00122 {
00123     mpNodesOnlyMesh->SetUpBoxCollection(cutOffLength, domainSize);
00124 }
00125 
00126 template<unsigned DIM>
00127 void NodeBasedCellPopulation<DIM>::FindMaxAndMin()
00128 {
00129     c_vector<double, DIM> min_posn;
00130     c_vector<double, DIM> max_posn;
00131     for (unsigned i=0; i<DIM; i++)
00132     {
00133         min_posn(i) = DBL_MAX;
00134         max_posn(i) = -DBL_MAX;
00135     }
00136 
00137     for (unsigned i=0; i<this->mrMesh.GetNumNodes(); i++)
00138     {
00139         c_vector<double, DIM> posn = this->GetNode(i)->rGetLocation();
00140 
00141         for (unsigned j=0; j<DIM; j++)
00142         {
00143             if (posn(j) > max_posn(j))
00144             {
00145                 max_posn(j) = posn(j);
00146             }
00147             if (posn(j) < min_posn(j))
00148             {
00149                 min_posn(j) = posn(j);
00150             }
00151         }
00152     }
00153 
00154     for (unsigned i=0; i<DIM; i++)
00155     {
00156         assert(min_posn(i) != DBL_MAX);
00157         mMinSpatialPositions(i) = min_posn(i);
00158 
00159         assert(max_posn(i) != -DBL_MAX);
00160         mMaxSpatialPositions(i) = max_posn(i);
00161     }
00162 }
00163 
00164 template<unsigned DIM>
00165 Node<DIM>* NodeBasedCellPopulation<DIM>::GetNode(unsigned index)
00166 {
00167     return this->mrMesh.GetNode(index);
00168 }
00169 
00170 template<unsigned DIM>
00171 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
00172 {
00173     mpNodesOnlyMesh->GetNode(nodeIndex)->SetPoint(rNewLocation);
00174 }
00175 
00176 template<unsigned DIM>
00177 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00178 {
00179     NodeMap map(this->mrMesh.GetNumAllNodes());
00180     mpNodesOnlyMesh->ReMesh(map);
00181 
00182     if (!map.IsIdentityMap())
00183     {
00184         UpdateParticlesAfterReMesh(map);
00185 
00186         // Update the mappings between cells and location indices
00188         std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
00189 
00190         // Remove any dead pointers from the maps (needed to avoid archiving errors)
00191         this->mLocationCellMap.clear();
00192         this->mCellLocationMap.clear();
00193 
00194         for (std::list<CellPtr>::iterator it = this->mCells.begin();
00195              it != this->mCells.end();
00196              ++it)
00197         {
00198             unsigned old_node_index = old_map[(*it).get()];
00199 
00200             // This shouldn't ever happen, as the cell vector only contains living cells
00201             assert(!map.IsDeleted(old_node_index));
00202 
00203             unsigned new_node_index = map.GetNewIndex(old_node_index);
00204             this->SetCellUsingLocationIndex(new_node_index,*it);
00205         }
00206 
00207         this->Validate();
00208     }
00209 
00210     mpNodesOnlyMesh->SetMeshHasChangedSinceLoading();
00211 
00212     mpNodesOnlyMesh->ClearBoxCollection();
00213 
00214     FindMaxAndMin();
00215 
00216     // Something here to set up the domain size (max and min of each node position dimension)
00217     c_vector<double, 2*DIM> domain_size;
00218     for (unsigned i=0; i<DIM; i++)
00219     {
00220         domain_size(2*i) = mMinSpatialPositions(i);
00221         domain_size(2*i+1) = mMaxSpatialPositions(i);
00222     }
00223 
00224     if (mMechanicsCutOffLength == DBL_MAX)
00225     {
00226         std::string error =  std::string("NodeBasedCellPopulation cannot create boxes if the cut-off length has not been set - ")
00227                            + std::string("Call SetMechanicsCutOffLength on the CellPopulation ensuring it is larger than GetCutOffLength() on the force law");
00228         EXCEPTION(error);
00229     }
00230 
00231     /*
00232      * Add this parameter and suggest that mechanics systems set it.
00233      * Allocates memory for mpBoxCollection and does the splitting
00234      * and putting nodes into boxes.
00235      */
00236 
00237     mpNodesOnlyMesh->SetUpBoxCollection(mMechanicsCutOffLength, domain_size);
00238 
00239     mpNodesOnlyMesh->CalculateNodePairs(mNodePairs, mNodeNeighbours);
00240 
00241     /*
00242      * Update cell radii based on CellData
00243      */
00244     if (mUseVariableRadii)
00245     {
00246         for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00247              cell_iter != this->End();
00248              ++cell_iter)
00249         {
00250             double cell_radius = cell_iter->GetCellData()->GetItem("Radius");
00251             unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00252             mpNodesOnlyMesh->SetCellRadius(node_index, cell_radius);
00253         }
00254     }
00255 }
00256 
00257 template<unsigned DIM>
00258 unsigned NodeBasedCellPopulation<DIM>::RemoveDeadCells()
00259 {
00260     unsigned num_removed = 0;
00261     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00262          cell_iter != this->mCells.end();
00263          ++cell_iter)
00264     {
00265         if ((*cell_iter)->IsDead())
00266         {
00267             // Remove the node from the mesh
00268             num_removed++;
00269             mpNodesOnlyMesh->DeleteNodePriorToReMesh(this->GetLocationIndexUsingCell((*cell_iter)));
00270 
00271             // Update mappings between cells and location indices
00272             unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*cell_iter));
00273             this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*cell_iter));
00274 
00275             // Update vector of cells
00276             cell_iter = this->mCells.erase(cell_iter);
00277             --cell_iter;
00278         }
00279     }
00280 
00281     return num_removed;
00282 }
00283 
00284 template<unsigned DIM>
00285 unsigned NodeBasedCellPopulation<DIM>::AddNode(Node<DIM>* pNewNode)
00286 {
00287     return mpNodesOnlyMesh->AddNode(pNewNode);
00288 }
00289 
00290 template<unsigned DIM>
00291 unsigned NodeBasedCellPopulation<DIM>::GetNumNodes()
00292 {
00293     return mpNodesOnlyMesh->GetNumAllNodes();
00294 }
00295 
00296 template<unsigned DIM>
00297 void NodeBasedCellPopulation<DIM>::UpdateParticlesAfterReMesh(NodeMap& rMap)
00298 {
00299 }
00300 
00301 template<unsigned DIM>
00302 BoxCollection<DIM>* NodeBasedCellPopulation<DIM>::GetBoxCollection()
00303 {
00304     return mpNodesOnlyMesh->GetBoxCollection();
00305 }
00306 
00307 template<unsigned DIM>
00308 std::set< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
00309 {
00310 //    if (mNodePairs.empty())
00311 //    {
00312 //        EXCEPTION("No node pairs set up, rGetNodePairs probably called before Update");
00313 //    }
00314     return mNodePairs;
00315 }
00316 
00317 template<unsigned DIM>
00318 void NodeBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00319 {
00320     *rParamsFile << "\t\t<MechanicsCutOffLength>" << mMechanicsCutOffLength << "</MechanicsCutOffLength>\n";
00321     *rParamsFile << "\t\t<UseVariableRadii>" << mUseVariableRadii <<
00322 "</UseVariableRadii>\n";
00323 
00324     // Call method on direct parent class
00325     AbstractCentreBasedCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00326 }
00327 
00328 template<unsigned DIM>
00329 void NodeBasedCellPopulation<DIM>::SetMechanicsCutOffLength(double mechanicsCutOffLength)
00330 {
00331     assert(mechanicsCutOffLength > 0.0);
00332     mMechanicsCutOffLength = mechanicsCutOffLength;
00333 }
00334 
00335 template<unsigned DIM>
00336 double NodeBasedCellPopulation<DIM>::GetMechanicsCutOffLength()
00337 {
00338     return mMechanicsCutOffLength;
00339 }
00340 
00341 template<unsigned DIM>
00342 bool NodeBasedCellPopulation<DIM>::GetUseVariableRadii()
00343 {
00344     return mUseVariableRadii;
00345 }
00346 
00347 template<unsigned DIM>
00348 void NodeBasedCellPopulation<DIM>::SetUseVariableRadii(bool useVariableRadii)
00349 {
00350     mUseVariableRadii = useVariableRadii;
00351 }
00352 
00353 template<unsigned DIM>
00354 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00355 {
00356     // Update the member variables mMinSpatialPositions and mMaxSpatialPositions
00357     FindMaxAndMin();
00358 
00359     // Compute the maximum distance between any nodes in this dimension
00360     double width = mMaxSpatialPositions(rDimension) - mMinSpatialPositions(rDimension);
00361 
00362     return width;
00363 }
00364 
00365 template<unsigned DIM>
00366 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00367 {
00368     // Check the mNodeNeighbours has been set up correctly
00369     if (mNodeNeighbours.empty())
00370     {
00371         EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNeighbouringNodeIndices()");
00372     }
00373 
00374     std::set<unsigned> neighbouring_node_indices;
00375 
00376     // Get location and radius of node
00377     c_vector<double, DIM> node_i_location = this->GetNode(index)->rGetLocation();
00378     double radius_of_cell_i = mpNodesOnlyMesh->GetCellRadius(index);
00379 
00380     // Make sure that the max_interaction distance is smaller than the box collection size
00381     if (!(radius_of_cell_i * 2.0 < mMechanicsCutOffLength))
00382     {
00383         EXCEPTION("mMechanicsCutOffLength is smaller than twice the radius of cell " << index << " (" << radius_of_cell_i << ") so interactions may be missed. Make the cut-off larger to avoid errors.");
00384     }
00385 
00386 
00387     // Get set of 'candidate' neighbours.
00388     std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
00389 
00390     // Find which ones are actually close
00391     for (std::set<unsigned>::iterator iter = near_nodes.begin();
00392             iter != near_nodes.end();
00393             ++iter)
00394     {
00395         // Be sure not to return the index itself.
00396         if ((*iter) != index)
00397         {
00398             // Get the location of this node
00399             c_vector<double, DIM> node_j_location = this->GetNode((*iter))->rGetLocation();
00400 
00401             // Get the vector the two nodes (assuming no periodicities etc.)
00402             c_vector<double, DIM> node_to_node_vector = node_i_location - node_j_location;
00403 
00404             // Calculate the distance between the two nodes
00405             double distance_between_nodes = norm_2(node_to_node_vector);
00406 
00407             // Get the radius of the cell corresponding to this node
00408             double radius_of_cell_j = mpNodesOnlyMesh->GetCellRadius((*iter));
00409 
00410             // If the cells are close enough to exert a force on each other...
00411             double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
00412 
00413             // Make sure that the max_interaction distance is smaller than the box collection size
00414             if (!(max_interaction_distance < mMechanicsCutOffLength))
00415             {
00416                 EXCEPTION("mMechanicsCutOffLength is smaller than the sum of radius of cell " << index << " (" << radius_of_cell_i << ") and cell " << (*iter) << " (" << radius_of_cell_j <<"). Make the cut-off larger to avoid errors.");
00417             }
00418             if (distance_between_nodes <= max_interaction_distance)// + DBL_EPSILSON) //Assumes that max_interaction_distance is of over 1
00419             {
00420                 // ...then add this node index to the set of neighbouring node indices
00421                 neighbouring_node_indices.insert((*iter));
00422             }
00423         }
00424     }
00425 
00426     return neighbouring_node_indices;
00427 }
00428 
00429 template<unsigned DIM>
00430 double NodeBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00431 {
00432     // Get node index corresponding to this cell
00433     unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00434 
00435     // Get cell radius
00436     double cell_radius = mpNodesOnlyMesh->GetCellRadius(node_index);
00437 
00438     // Begin code to approximate cell volume
00439     double averaged_cell_radius = 0.0;
00440     unsigned num_cells = 0;
00441 
00442     // Get the location of this node
00443     c_vector<double, DIM> node_i_location = GetNode(node_index)->rGetLocation();
00444 
00445     // Get the set of node indices corresponding to this cell's neighbours
00446     std::set<unsigned> neighbouring_node_indices = GetNeighbouringNodeIndices(node_index);
00447 
00448     // Loop over this set
00449     for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00450          iter != neighbouring_node_indices.end();
00451          ++iter)
00452     {
00453         // Get the location of the neighbouring node
00454         c_vector<double, DIM> node_j_location = GetNode(*iter)->rGetLocation();
00455 
00456         double neighbouring_cell_radius = mpNodesOnlyMesh->GetCellRadius( *iter);
00457 
00458         // If this throws then you may not be considering all cell interactions use a larger cut off length
00459         assert(cell_radius+neighbouring_cell_radius<mMechanicsCutOffLength);
00460 
00461         // Calculate the distance between the two nodes and add to cell radius
00462         double separation = norm_2(node_j_location - node_i_location);
00463 
00464         if (separation < cell_radius+neighbouring_cell_radius)
00465         {
00466             // The effective radius is the mid point of the overlap
00467             averaged_cell_radius = averaged_cell_radius + cell_radius - (cell_radius+neighbouring_cell_radius-separation)/2.0;
00468             num_cells++;
00469         }
00470     }
00471     if (num_cells == 0)
00472     {
00473         averaged_cell_radius =  cell_radius;
00474     }
00475     else
00476     {
00477         averaged_cell_radius /= num_cells;
00478     }
00479     assert(averaged_cell_radius<mMechanicsCutOffLength/2.0);
00480 
00481     cell_radius = averaged_cell_radius;
00482 
00483     // End code to approximate cell volume
00484 
00485     // Calculate cell volume from radius of cell
00486     double cell_volume = 0.0;
00487     if (DIM == 2)
00488     {
00489         cell_volume = M_PI*cell_radius*cell_radius;
00490     }
00491     else if (DIM == 3)
00492     {
00493         cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
00494     }
00495 
00496     return cell_volume;
00497 }
00498 
00499 template<unsigned DIM>
00500 void NodeBasedCellPopulation<DIM>::WriteCellVolumeResultsToFile()
00501 {
00502     assert(DIM==2 || DIM==3);
00503 
00504     // Write time to file
00505     *(this->mpCellVolumesFile) << SimulationTime::Instance()->GetTime() << " ";
00506 
00507     // Loop over cells
00508     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00509          cell_iter != this->End();
00510          ++cell_iter)
00511     {
00512         // Get the index of the corresponding node in mrMesh
00513         unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00514 
00515         // Write node index to file
00516         *(this->mpCellVolumesFile) << node_index << " ";
00517 
00518         // Write cell ID to file
00519         *(this->mpCellVolumesFile) << cell_iter->GetCellId() << " ";
00520 
00521         // Write node location to file
00522         c_vector<double, DIM> node_location = this->GetNode(node_index)->rGetLocation();
00523         for (unsigned i=0; i<DIM; i++)
00524         {
00525             *(this->mpCellVolumesFile) << node_location[i] << " ";
00526         }
00527 
00528         // Write cell volume (in 3D) or area (in 2D) to file
00529         double cell_volume = this->GetVolumeOfCell(*cell_iter);
00530         *(this->mpCellVolumesFile) << cell_volume << " ";
00531     }
00532 
00533     *(this->mpCellVolumesFile) << "\n";
00534 }
00535 
00536 template<unsigned DIM>
00537 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile()
00538 {
00539 #ifdef CHASTE_VTK
00540     std::stringstream time;
00541     time << SimulationTime::Instance()->GetTimeStepsElapsed();
00542     VtkMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results_"+time.str(), false);
00543 
00544     unsigned num_nodes = GetNumNodes();
00545     std::vector<double> cell_types(num_nodes);
00546     std::vector<double> cell_ancestors(num_nodes);
00547     std::vector<double> cell_mutation_states(num_nodes);
00548     std::vector<double> cell_ages(num_nodes);
00549     std::vector<double> cell_cycle_phases(num_nodes);
00550     std::vector<double> cell_radii(num_nodes);
00551     std::vector<std::vector<double> > cellwise_data;
00552 
00553     unsigned num_cell_data_items = 0;
00554     std::vector<std::string> cell_data_names;
00555     //We assume that the first cell is representative of all cells
00556     num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00557     cell_data_names = this->Begin()->GetCellData()->GetKeys();
00558 
00559     for (unsigned var=0; var<num_cell_data_items; var++)
00560     {
00561         std::vector<double> cellwise_data_var(num_nodes);
00562         cellwise_data.push_back(cellwise_data_var);
00563     }
00564 
00565 
00566     // Loop over cells
00567     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00568          cell_iter != this->End();
00569          ++cell_iter)
00570     {
00571         // Get the node index corresponding to this cell
00572         unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00573 
00574         if (this->mOutputCellAncestors)
00575         {
00576             double ancestor_index = (cell_iter->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_iter->GetAncestor();
00577             cell_ancestors[node_index] = ancestor_index;
00578         }
00579         if (this->mOutputCellProliferativeTypes)
00580         {
00581             double cell_type = cell_iter->GetCellProliferativeType();
00582             cell_types[node_index] = cell_type;
00583         }
00584         if (this->mOutputCellMutationStates)
00585         {
00586             double mutation_state = cell_iter->GetMutationState()->GetColour();
00587 
00588             CellPropertyCollection collection = cell_iter->rGetCellPropertyCollection();
00589            CellPropertyCollection label_collection = collection.GetProperties<CellLabel>();
00590 
00591            if (label_collection.GetSize()==1 )
00592             {
00593                 boost::shared_ptr<CellLabel> p_label = boost::static_pointer_cast<CellLabel>(label_collection.GetProperty());
00594                 mutation_state = p_label->GetColour();
00595             }
00596 
00597             cell_mutation_states[node_index] = mutation_state;
00598         }
00599         if (this->mOutputCellAges)
00600         {
00601             double age = cell_iter->GetAge();
00602             cell_ages[node_index] = age;
00603         }
00604         if (this->mOutputCellCyclePhases)
00605         {
00606             double cycle_phase = cell_iter->GetCellCycleModel()->GetCurrentCellCyclePhase();
00607             cell_cycle_phases[node_index] = cycle_phase;
00608         }
00609         if (this->mOutputCellVolumes)
00610         {
00611             double cell_radius = mpNodesOnlyMesh->GetCellRadius(node_index);
00612             cell_radii[node_index] = cell_radius;
00613         }
00614 
00615         for (unsigned var=0; var<num_cell_data_items; var++)
00616         {
00617             cellwise_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
00618         }
00619     }
00620 
00621     if (this->mOutputCellProliferativeTypes)
00622     {
00623         mesh_writer.AddPointData("Cell types", cell_types);
00624     }
00625     if (this->mOutputCellAncestors)
00626     {
00627         mesh_writer.AddPointData("Ancestors", cell_ancestors);
00628     }
00629     if (this->mOutputCellMutationStates)
00630     {
00631         mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00632     }
00633     if (this->mOutputCellAges)
00634     {
00635         mesh_writer.AddPointData("Ages", cell_ages);
00636     }
00637     if (this->mOutputCellCyclePhases)
00638     {
00639         mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00640     }
00641     if (this->mOutputCellVolumes)
00642     {
00643         mesh_writer.AddPointData("Cell radii", cell_radii);
00644     }
00645     if (num_cell_data_items > 0)
00646     {
00647         for (unsigned var=0; var<cellwise_data.size(); var++)
00648         {
00649             mesh_writer.AddPointData(cell_data_names[var], cellwise_data[var]);
00650         }
00651     }
00652 
00653     mesh_writer.WriteFilesUsingMesh(*mpNodesOnlyMesh);
00654 
00655     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00656     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00657     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00658     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00659     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00660 #endif //CHASTE_VTK
00661 }
00662 
00663 template<unsigned DIM>
00664 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00665 {
00666     assert(pNewCell);
00667 
00668     // Add new cell to cell population
00669     CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00670     assert(p_created_cell == pNewCell);
00671 
00672     // Then set the new cell radius in the NodesOnlyMesh
00673     unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
00674     unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
00675     mpNodesOnlyMesh->SetCellRadius(new_node_index, mpNodesOnlyMesh->GetCellRadius(parent_node_index));
00676 
00677     // Return pointer to new cell
00678     return p_created_cell;
00679 }
00680 
00682 // Explicit instantiation
00684 
00685 template class NodeBasedCellPopulation<1>;
00686 template class NodeBasedCellPopulation<2>;
00687 template class NodeBasedCellPopulation<3>;
00688 
00689 // Serialization for Boost >= 1.36
00690 #include "SerializationExportWrapperForCpp.hpp"
00691 EXPORT_TEMPLATE_CLASS_SAME_DIMS(NodeBasedCellPopulation)