NodeBasedCellPopulation.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 "NodeBasedCellPopulation.hpp"
00030 #include "CellwiseData.hpp"
00031 #include "VtkMeshWriter.hpp"
00032 
00033 template<unsigned DIM>
00034 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh,
00035                                       std::vector<CellPtr>& rCells,
00036                                       const std::vector<unsigned> locationIndices,
00037                                       bool deleteMesh)
00038     : AbstractCentreBasedCellPopulation<DIM>(rCells, locationIndices),
00039       mrMesh(rMesh),
00040       mpBoxCollection(NULL),
00041       mDeleteMesh(deleteMesh),
00042       mMechanicsCutOffLength(DBL_MAX)
00043 {
00044     Validate();
00045 }
00046 
00047 template<unsigned DIM>
00048 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh)
00049     : AbstractCentreBasedCellPopulation<DIM>(),
00050       mrMesh(rMesh),
00051       mpBoxCollection(NULL),
00052       mDeleteMesh(true),
00053       mMechanicsCutOffLength(DBL_MAX) // will be set by serialize() method
00054 {
00055     // No Validate() because the cells are not associated with the cell population yet in archiving
00056 }
00057 
00058 template<unsigned DIM>
00059 NodeBasedCellPopulation<DIM>::~NodeBasedCellPopulation()
00060 {
00061     Clear();
00062     if (mDeleteMesh)
00063     {
00064         delete &mrMesh;
00065     }
00066 }
00067 
00068 template<unsigned DIM>
00069 NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh()
00070 {
00071     return mrMesh;
00072 }
00073 
00074 template<unsigned DIM>
00075 const NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh() const
00076 {
00077     return mrMesh;
00078 }
00079 
00080 template<unsigned DIM>
00081 void NodeBasedCellPopulation<DIM>::Clear()
00082 {
00083     delete mpBoxCollection;
00084     mpBoxCollection = NULL;
00085     mNodePairs.clear();
00086 }
00087 
00088 template<unsigned DIM>
00089 void NodeBasedCellPopulation<DIM>::Validate()
00090 {
00091     std::vector<bool> validated_node(GetNumNodes());
00092     for (unsigned i=0; i<validated_node.size(); i++)
00093     {
00094         validated_node[i] = false;
00095     }
00096 
00097     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
00098     {
00099         unsigned node_index = this->mCellLocationMap[(*cell_iter).get()];
00100         validated_node[node_index] = true;
00101     }
00102 
00103     for (unsigned i=0; i<validated_node.size(); i++)
00104     {
00105         if (!validated_node[i])
00106         {
00107             EXCEPTION("Node " << i << " does not appear to have a cell associated with it");
00108         }
00109     }
00110 }
00111 
00112 template<unsigned DIM>
00113 void NodeBasedCellPopulation<DIM>::SplitUpIntoBoxes(double cutOffLength, c_vector<double, 2*DIM> domainSize)
00114 {
00115     mpBoxCollection = new BoxCollection<DIM>(cutOffLength, domainSize);
00116     mpBoxCollection->SetupLocalBoxesHalfOnly();
00117 
00118     for (unsigned i=0; i<mrMesh.GetNumNodes(); i++)
00119     {
00120         unsigned box_index = mpBoxCollection->CalculateContainingBox(this->GetNode(i));
00121         mpBoxCollection->rGetBox(box_index).AddNode(this->GetNode(i));
00122     }
00123 }
00124 
00125 template<unsigned DIM>
00126 void NodeBasedCellPopulation<DIM>::FindMaxAndMin()
00127 {
00128     c_vector<double, DIM> min_posn;
00129     c_vector<double, DIM> max_posn;
00130     for (unsigned i=0; i<DIM; i++)
00131     {
00132         min_posn(i) = DBL_MAX;
00133         max_posn(i) = -DBL_MAX;
00134     }
00135 
00136     for (unsigned i=0; i<mrMesh.GetNumNodes(); i++)
00137     {
00138         c_vector<double, DIM> posn = this->GetNode(i)->rGetLocation();
00139 
00140         for (unsigned j=0; j<DIM; j++)
00141         {
00142             if (posn(j) > max_posn(j))
00143             {
00144                 max_posn(j) = posn(j);
00145             }
00146             if (posn(j) < min_posn(j))
00147             {
00148                 min_posn(j) = posn(j);
00149             }
00150         }
00151     }
00152 
00153     for (unsigned i=0; i<DIM; i++)
00154     {
00155         assert(min_posn(i) != DBL_MAX);
00156         mMinSpatialPositions(i) = min_posn(i);
00157 
00158         assert(max_posn(i) != -DBL_MAX);
00159         mMaxSpatialPositions(i) = max_posn(i);
00160     }
00161 }
00162 
00163 template<unsigned DIM>
00164 Node<DIM>* NodeBasedCellPopulation<DIM>::GetNode(unsigned index)
00165 {
00166     return mrMesh.GetNode(index);
00167 }
00168 
00169 template<unsigned DIM>
00170 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
00171 {
00172     mrMesh.GetNode(nodeIndex)->SetPoint(rNewLocation);
00173 }
00174 
00175 template<unsigned DIM>
00176 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00177 {
00178     NodeMap map(mrMesh.GetNumAllNodes());
00179     mrMesh.ReMesh(map);
00180 
00181     if (!map.IsIdentityMap())
00182     {
00183         // Update the mappings between cells and location indices
00184         std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
00185 
00186         // Remove any dead pointers from the maps (needed to avoid archiving errors)
00187         this->mLocationCellMap.clear();
00188         this->mCellLocationMap.clear();
00189 
00190         for (std::list<CellPtr>::iterator it = this->mCells.begin();
00191              it != this->mCells.end();
00192              ++it)
00193         {
00194             unsigned old_node_index = old_map[(*it).get()];
00195 
00196             // This shouldn't ever happen, as the cell vector only contains living cells
00197             assert(!map.IsDeleted(old_node_index));
00198 
00199             unsigned new_node_index = map.GetNewIndex(old_node_index);
00200             this->mLocationCellMap[new_node_index] = *it;
00201             this->mCellLocationMap[(*it).get()] = new_node_index;
00202         }
00203 
00204         this->Validate();
00205     }
00206 
00207     mrMesh.SetMeshHasChangedSinceLoading();
00208 
00209     if (mpBoxCollection != NULL)
00210     {
00211         delete mpBoxCollection;
00212     }
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     SplitUpIntoBoxes(mMechanicsCutOffLength, domain_size);
00237 
00238     std::vector<Node<DIM>*> nodes;
00239     for (unsigned index=0; index<mrMesh.GetNumNodes(); index++)
00240     {
00241         Node<DIM>* p_node = mrMesh.GetNode(index);
00242         nodes.push_back(p_node);
00243     }
00244     mpBoxCollection->CalculateNodePairs(nodes, mNodePairs);
00245 }
00246 
00247 template<unsigned DIM>
00248 unsigned NodeBasedCellPopulation<DIM>::RemoveDeadCells()
00249 {
00250     unsigned num_removed = 0;
00251     for (std::list<CellPtr>::iterator it = this->mCells.begin();
00252          it != this->mCells.end();
00253          ++it)
00254     {
00255         if ((*it)->IsDead())
00256         {
00257             // Remove the node from the mesh
00258             num_removed++;
00259             mrMesh.DeleteNodePriorToReMesh(this->mCellLocationMap[(*it).get()]);
00260 
00261             // Update mappings between cells and location indices
00262             unsigned location_index_of_removed_node = this->mCellLocationMap[(*it).get()];
00263             this->mCellLocationMap.erase((*it).get());
00264             this->mLocationCellMap.erase(location_index_of_removed_node);
00265 
00266             // Update vector of cells
00267             it = this->mCells.erase(it);
00268             --it;
00269         }
00270     }
00271 
00272     return num_removed;
00273 }
00274 
00275 template<unsigned DIM>
00276 unsigned NodeBasedCellPopulation<DIM>::AddNode(Node<DIM>* pNewNode)
00277 {
00278     return mrMesh.AddNode(pNewNode);
00279 }
00280 
00281 template<unsigned DIM>
00282 unsigned NodeBasedCellPopulation<DIM>::GetNumNodes()
00283 {
00284     return mrMesh.GetNumAllNodes();
00285 }
00286 
00287 template<unsigned DIM>
00288 BoxCollection<DIM>* NodeBasedCellPopulation<DIM>::GetBoxCollection()
00289 {
00290     return mpBoxCollection;
00291 }
00292 
00293 template<unsigned DIM>
00294 std::set< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
00295 {
00296     if (mNodePairs.empty())
00297     {
00298         EXCEPTION("No node pairs set up, rGetNodePairs probably called before Update");
00299     }
00300     return mNodePairs;
00301 }
00302 
00303 template<unsigned DIM>
00304 void NodeBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00305 {
00306     *rParamsFile << "\t\t<MechanicsCutOffLength>" << mMechanicsCutOffLength << "</MechanicsCutOffLength>\n";
00307 
00308     // Call method on direct parent class
00309     AbstractCentreBasedCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00310 }
00311 
00312 template<unsigned DIM>
00313 void NodeBasedCellPopulation<DIM>::SetMechanicsCutOffLength(double mechanicsCutOffLength)
00314 {
00315     assert(mechanicsCutOffLength > 0.0);
00316     mMechanicsCutOffLength = mechanicsCutOffLength;
00317 }
00318 
00319 template<unsigned DIM>
00320 double NodeBasedCellPopulation<DIM>::GetMechanicsCutOffLength()
00321 {
00322     return mMechanicsCutOffLength;
00323 }
00324 
00325 template<unsigned DIM>
00326 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00327 {
00328     // Update the member variables mMinSpatialPositions and mMaxSpatialPositions
00329     FindMaxAndMin();
00330 
00331     // Compute the maximum distance between any nodes in this dimension
00332     double width = mMaxSpatialPositions(rDimension) - mMinSpatialPositions(rDimension);
00333 
00334     return width;
00335 }
00336 
00337 template<unsigned DIM>
00338 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00339 {
00340     // Get the location of this node
00341     c_vector<double, DIM> node_i_location = this->GetNode(index)->rGetLocation();
00342 
00343     // Get the radius of the cell corresponding to this node
00344     double radius_of_cell_i = mrMesh.GetCellRadius(index);
00345 
00346     // Loop over cells in the population
00347     std::set<unsigned> neighbouring_node_indices;
00348     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00349          cell_iter != this->End();
00350          ++cell_iter)
00351     {
00352         // Get the node index corresponding to this cell
00353         unsigned node_j_index = this->GetLocationIndexUsingCell(*cell_iter);
00354 
00355         // Only return the neighbours, not the original node
00356         if (node_j_index != index)
00357         {
00358             // Get the location of this node
00359             c_vector<double, DIM> node_j_location = this->GetNode(node_j_index)->rGetLocation();
00360 
00361             // Get the unit vector parallel to the line joining the two nodes (assuming no periodicities etc.)
00362             c_vector<double, DIM> unit_vector = node_i_location - node_j_location;
00363 
00364             // Calculate the distance between the two nodes
00365             double distance_between_nodes = norm_2(unit_vector);
00366 
00367             // Get the radius of the cell corresponding to this node
00368             double radius_of_cell_j = mrMesh.GetCellRadius(node_j_index);
00369 
00370             // If the cells are close enough to exert a force on each other...
00371             double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
00372             if (distance_between_nodes < max_interaction_distance)
00373             {
00374                 // ...then add this node index to the set of neighbouring node indices
00375                 neighbouring_node_indices.insert(node_j_index);
00376             }
00377         }
00378     }
00379     return neighbouring_node_indices;
00380 }
00381 
00382 template<unsigned DIM>
00383 void NodeBasedCellPopulation<DIM>::WriteCellVolumeResultsToFile()
00384 {
00385     assert(DIM==2 || DIM==3);
00386 
00387     // Write time to file
00388     *(this->mpCellVolumesFile) << SimulationTime::Instance()->GetTime() << " ";
00389 
00390     // Loop over cells
00391     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin();
00392          cell_iter!=this->End(); ++cell_iter)
00393     {
00394         // Get the index of the corresponding node in mrMesh
00395         unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00396 
00397         // Write node index to file
00398         *(this->mpCellVolumesFile) << node_index << " ";
00399 
00400         // Write cell ID to file
00401         *(this->mpCellVolumesFile) << cell_iter->GetCellId() << " ";
00402 
00403         // Write node location to file
00404         c_vector<double, DIM> node_location = this->GetNode(node_index)->rGetLocation();
00405         for (unsigned i=0; i<DIM; i++)
00406         {
00407             *(this->mpCellVolumesFile) << node_location[i] << " ";
00408         }
00409 
00410         // Get cell radius
00411         double cell_radius = mrMesh.GetCellRadius(node_index);
00412 
00413         // Get cell volume from radius
00414         double cell_volume = 0.0;
00415 
00416         if (DIM == 2)
00417         {
00418             cell_volume = M_PI*cell_radius*cell_radius;
00419         }
00420         else if (DIM == 3)
00421         {
00422             cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
00423         }
00424         // Write cell volume (in 3D) or area (in 2D) to file
00425         *(this->mpCellVolumesFile) << cell_volume << " ";
00426     }
00427     *(this->mpCellVolumesFile) << "\n";
00428 }
00429 
00430 template<unsigned DIM>
00431 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile()
00432 {
00433 #ifdef CHASTE_VTK
00434     std::stringstream time;
00435     time << SimulationTime::Instance()->GetTimeStepsElapsed();
00436     VtkMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results_"+time.str(), false);
00437 
00438     unsigned num_nodes = GetNumNodes();
00439     std::vector<double> cell_types(num_nodes);
00440     std::vector<double> cell_ancestors(num_nodes);
00441     std::vector<double> cell_mutation_states(num_nodes);
00442     std::vector<double> cell_ages(num_nodes);
00443     std::vector<double> cell_cycle_phases(num_nodes);
00444     std::vector<double> cell_radii(num_nodes);
00445     std::vector<std::vector<double> > cellwise_data;
00446 
00447     if (CellwiseData<DIM>::Instance()->IsSetUp())
00448     {
00449         CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00450         unsigned num_variables = p_data->GetNumVariables();
00451         for (unsigned var=0; var<num_variables; var++)
00452         {
00453             std::vector<double> cellwise_data_var(num_nodes);
00454             cellwise_data.push_back(cellwise_data_var);
00455         }
00456     }
00457 
00458     // Loop over cells
00459     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00460          cell_iter != this->End();
00461          ++cell_iter)
00462     {
00463         // Get the node index corresponding to this cell
00464         unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00465 
00466         if (this->mOutputCellAncestors)
00467         {
00468             double ancestor_index = (cell_iter->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_iter->GetAncestor();
00469             cell_ancestors[node_index] = ancestor_index;
00470         }
00471         if (this->mOutputCellProliferativeTypes)
00472         {
00473             double cell_type = cell_iter->GetCellCycleModel()->GetCellProliferativeType();
00474             cell_types[node_index] = cell_type;
00475         }
00476         if (this->mOutputCellMutationStates)
00477         {
00478             double mutation_state = cell_iter->GetMutationState()->GetColour();
00479             cell_mutation_states[node_index] = mutation_state;
00480         }
00481         if (this->mOutputCellAges)
00482         {
00483             double age = cell_iter->GetAge();
00484             cell_ages[node_index] = age;
00485         }
00486         if (this->mOutputCellCyclePhases)
00487         {
00488             double cycle_phase = cell_iter->GetCellCycleModel()->GetCurrentCellCyclePhase();
00489             cell_cycle_phases[node_index] = cycle_phase;
00490         }
00491         if (this->mOutputCellVolumes)
00492         {
00493             double cell_radius = mrMesh.GetCellRadius(node_index);
00494             cell_radii[node_index] = cell_radius;
00495         }
00496         if (CellwiseData<DIM>::Instance()->IsSetUp())
00497         {
00498             CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00499             unsigned num_variables = p_data->GetNumVariables();
00500             for (unsigned var=0; var<num_variables; var++)
00501             {
00502                 cellwise_data[var][node_index] = p_data->GetValue(*cell_iter, var);
00503             }
00504         }
00505     }
00506 
00507     if (this->mOutputCellProliferativeTypes)
00508     {
00509         mesh_writer.AddPointData("Cell types", cell_types);
00510     }
00511     if (this->mOutputCellAncestors)
00512     {
00513         mesh_writer.AddPointData("Ancestors", cell_ancestors);
00514     }
00515     if (this->mOutputCellMutationStates)
00516     {
00517         mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00518     }
00519     if (this->mOutputCellAges)
00520     {
00521         mesh_writer.AddPointData("Ages", cell_ages);
00522     }
00523     if (this->mOutputCellCyclePhases)
00524     {
00525         mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00526     }
00527     if (this->mOutputCellVolumes)
00528     {
00529         mesh_writer.AddPointData("Cell radii", cell_radii);
00530     }
00531     if (CellwiseData<DIM>::Instance()->IsSetUp())
00532     {
00533         for (unsigned var=0; var<cellwise_data.size(); var++)
00534         {
00535             std::stringstream data_name;
00536             data_name << "Cellwise data " << var;
00537             std::vector<double> cellwise_data_var = cellwise_data[var];
00538             mesh_writer.AddPointData(data_name.str(), cellwise_data_var);
00539         }
00540     }
00541 
00542     mesh_writer.WriteFilesUsingMesh(mrMesh);
00543 
00544     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00545     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00546     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00547     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00548     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00549 #endif //CHASTE_VTK
00550 }
00551 
00552 template<unsigned DIM>
00553 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00554 {
00555     assert(pNewCell);
00556 
00557     // Add new cell to cell population
00558     CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00559     assert(p_created_cell == pNewCell);
00560 
00561     // Then set the new cell radius in the NodesOnlyMesh
00563     unsigned node_index = this->GetLocationIndexUsingCell(p_created_cell);
00564     mrMesh.SetCellRadius(node_index, 1.0);
00565 
00566     // Return pointer to new cell
00567     return p_created_cell;
00568 }
00569 
00571 // Explicit instantiation
00573 
00574 template class NodeBasedCellPopulation<1>;
00575 template class NodeBasedCellPopulation<2>;
00576 template class NodeBasedCellPopulation<3>;
00577 
00578 // Serialization for Boost >= 1.36
00579 #include "SerializationExportWrapperForCpp.hpp"
00580 EXPORT_TEMPLATE_CLASS_SAME_DIMS(NodeBasedCellPopulation)
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3