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 #include "NodeBasedCellPopulation.hpp"
00029 #include "CellwiseData.hpp"
00030 #include "VtkMeshWriter.hpp"
00031 
00032 template<unsigned DIM>
00033 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(const std::vector<Node<DIM>* > nodes,
00034                                       std::vector<CellPtr>& rCells,
00035                                       const std::vector<unsigned> locationIndices,
00036                                       bool deleteNodes)
00037     : AbstractCentreBasedCellPopulation<DIM>(rCells, locationIndices),
00038       mNodes(nodes.begin(), nodes.end()),
00039       mAddedNodes(true),
00040       mpBoxCollection(NULL),
00041       mDeleteNodes(deleteNodes),
00042       mMechanicsCutOffLength(DBL_MAX)
00043 {
00044     Validate();
00045 }
00046 
00047 // archiving constructor
00048 template<unsigned DIM>
00049 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(const std::vector<Node<DIM>* > nodes, double mechanicsCutOffLength, bool deleteNodes)
00050     : AbstractCentreBasedCellPopulation<DIM>(),
00051       mNodes(nodes.begin(), nodes.end()),
00052       mAddedNodes(true),
00053       mpBoxCollection(NULL),
00054       mDeleteNodes(deleteNodes),
00055       mMechanicsCutOffLength(mechanicsCutOffLength)
00056 {
00057     // No Validate() because the cells are not associated with the cell population yet in archiving
00058 }
00059 
00060 template<unsigned DIM>
00061 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(const AbstractMesh<DIM,DIM>& rMesh,
00062                                       std::vector<CellPtr>& rCells)
00063     : AbstractCentreBasedCellPopulation<DIM>(rCells),
00064       mAddedNodes(false),
00065       mpBoxCollection(NULL),
00066       mDeleteNodes(true),
00067       mMechanicsCutOffLength(DBL_MAX)
00068 {
00069     unsigned num_nodes = rMesh.GetNumNodes();
00070 
00071     mNodes.reserve(num_nodes);
00072     // Copy the actual node objects from mesh to this (mesh-less) cell population.
00073     for (unsigned i=0; i<num_nodes; i++)
00074     {
00075         Node<DIM>* p_node = new Node<DIM>(*(rMesh.GetNode(i)));
00076         mNodes.push_back(p_node);
00077     }
00078     mAddedNodes = true;
00079     Validate();
00080 }
00081 
00082 template<unsigned DIM>
00083 NodeBasedCellPopulation<DIM>::~NodeBasedCellPopulation()
00084 {
00085     Clear();
00086 
00087     // Free node memory
00088     if (mDeleteNodes)
00089     {
00090         for (unsigned i=0; i<mNodes.size(); i++)
00091         {
00092             delete mNodes[i];
00093         }
00094     }
00095 }
00096 
00097 template<unsigned DIM>
00098 void NodeBasedCellPopulation<DIM>::Clear()
00099 {
00100     delete mpBoxCollection;
00101     mpBoxCollection = NULL;
00102     mNodePairs.clear();
00103     mDeletedNodeIndices.clear();
00104     mAddedNodes = false;
00105 }
00106 
00107 template<unsigned DIM>
00108 void NodeBasedCellPopulation<DIM>::Validate()
00109 {
00110     std::vector<bool> validated_node(GetNumNodes());
00111     for (unsigned i=0; i<validated_node.size(); i++)
00112     {
00113         validated_node[i] = false;
00114     }
00115 
00116     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
00117     {
00118         unsigned node_index = this->mCellLocationMap[(*cell_iter).get()];
00119         validated_node[node_index] = true;
00120     }
00121 
00122     for (unsigned i=0; i<validated_node.size(); i++)
00123     {
00124         if (!validated_node[i])
00125         {
00126             std::stringstream ss;
00127             ss << "Node " << i << " does not appear to have a cell associated with it";
00128             EXCEPTION(ss.str());
00129         }
00130     }
00131 }
00132 
00133 template<unsigned DIM>
00134 std::vector<Node<DIM>* >& NodeBasedCellPopulation<DIM>::rGetNodes()
00135 {
00136     return mNodes;
00137 }
00138 
00139 template<unsigned DIM>
00140 const std::vector<Node<DIM>* >& NodeBasedCellPopulation<DIM>::rGetNodes() const
00141 {
00142     return mNodes;
00143 }
00144 
00145 template<unsigned DIM>
00146 void NodeBasedCellPopulation<DIM>::SplitUpIntoBoxes(double cutOffLength, c_vector<double, 2*DIM> domainSize)
00147 {
00148     mpBoxCollection = new BoxCollection<DIM>(cutOffLength, domainSize);
00149     mpBoxCollection->SetupLocalBoxesHalfOnly();
00150 
00151     for (unsigned i=0; i<mNodes.size(); i++)
00152     {
00153         unsigned box_index = mpBoxCollection->CalculateContainingBox(mNodes[i]);
00154         mpBoxCollection->rGetBox(box_index).AddNode(mNodes[i]);
00155     }
00156 }
00157 
00158 template<unsigned DIM>
00159 void NodeBasedCellPopulation<DIM>::FindMaxAndMin()
00160 {
00161     c_vector<double, DIM> min_posn;
00162     c_vector<double, DIM> max_posn;
00163     for (unsigned i=0; i<DIM; i++)
00164     {
00165         min_posn(i) = DBL_MAX;
00166         max_posn(i) = -DBL_MAX;
00167     }
00168 
00169     for (unsigned i=0; i<mNodes.size(); i++)
00170     {
00171         c_vector<double, DIM> posn = this->GetNode(i)->rGetLocation();
00172 
00173         for (unsigned j=0; j<DIM; j++)
00174         {
00175             if (posn(j) > max_posn(j))
00176             {
00177                 max_posn(j) = posn(j);
00178             }
00179             if (posn(j) < min_posn(j))
00180             {
00181                 min_posn(j) = posn(j);
00182             }
00183         }
00184     }
00185 
00186     for (unsigned i=0; i<DIM; i++)
00187     {
00188         assert(min_posn(i) != DBL_MAX);
00189         mMinSpatialPositions(i) = min_posn(i);
00190 
00191         assert(max_posn(i) != -DBL_MAX);
00192         mMaxSpatialPositions(i) = max_posn(i);
00193     }
00194 }
00195 
00196 template<unsigned DIM>
00197 Node<DIM>* NodeBasedCellPopulation<DIM>::GetNode(unsigned index)
00198 {
00199     return mNodes[index];
00200 }
00201 
00202 template<unsigned DIM>
00203 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
00204 {
00205     mNodes[nodeIndex]->SetPoint(rNewLocation);
00206 }
00207 
00208 template<unsigned DIM>
00209 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00210 {
00211     if (hasHadBirthsOrDeaths)
00212     {
00213         // Create and reserve space for a temporary vector
00214         std::vector<Node<DIM>*> old_nodes;
00215         old_nodes.reserve(mNodes.size());
00216 
00217         // Store all non-deleted nodes in the temporary vector
00218         for (unsigned i=0; i<mNodes.size(); i++)
00219         {
00220             if (!mNodes[i]->IsDeleted())
00221             {
00222                 old_nodes.push_back(mNodes[i]);
00223             }
00224             else
00225             {
00226                 // Free node memory
00227                 delete mNodes[i];
00228             }
00229         }
00230 
00231         std::map<unsigned,CellPtr> old_map = this->mLocationCellMap;
00232         mNodes.clear();
00233 
00234         // Clear maps
00235         this->mLocationCellMap.clear();
00236         this->mCellLocationMap.clear();
00237 
00238         // Update mNodes to new indices which go from 0 to NumNodes-1
00239         for (unsigned i=0; i<old_nodes.size(); i++)
00240         {
00241             // Get the living cell associated with the old node
00242             CellPtr p_live_cell = old_map[old_nodes[i]->GetIndex()];
00243 
00244             // Set the node up
00245             mNodes.push_back(old_nodes[i]);
00246             mNodes[i]->SetIndex(i);
00247 
00248             // Set the maps up
00249             this->mLocationCellMap[i] = p_live_cell;
00250             this->mCellLocationMap[p_live_cell.get()] = i;
00251         }
00252 
00253         // Remove current dead indices data
00254         Clear();
00255 
00256         Validate();
00257     }
00258 
00259     if (mpBoxCollection!=NULL)
00260     {
00261         delete mpBoxCollection;
00262     }
00263 
00264     FindMaxAndMin();
00265 
00266     // Something here to set up the domain size (max and min of each node position dimension)
00267     c_vector<double, 2*DIM> domain_size;
00268 
00269     for (unsigned i=0; i<DIM; i++)
00270     {
00271         domain_size(2*i) = mMinSpatialPositions(i);
00272         domain_size(2*i+1) = mMaxSpatialPositions(i);
00273     }
00274 
00275     if (mMechanicsCutOffLength == DBL_MAX)
00276     {
00277         std::string error =  std::string("NodeBasedCellPopulation cannot create boxes if the cut-off length has not been set - ")
00278                            + std::string("Call SetMechanicsCutOffLength on the CellPopulation ensuring it is larger than GetCutOffLength() on the force law");
00279         EXCEPTION(error);
00280     }
00281 
00282     // Add this parameter and suggest that mechanics systems set it.
00283     // Allocates memory for mpBoxCollection and does the splitting and putting nodes into boxes
00284     SplitUpIntoBoxes(mMechanicsCutOffLength, domain_size);
00285 
00286     mpBoxCollection->CalculateNodePairs(mNodes, mNodePairs);
00287 }
00288 
00289 template<unsigned DIM>
00290 unsigned NodeBasedCellPopulation<DIM>::RemoveDeadCells()
00291 {
00292     unsigned num_removed = 0;
00293 
00294     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00295          cell_iter != this->mCells.end();
00296          ++cell_iter)
00297     {
00298         if ((*cell_iter)->IsDead())
00299         {
00300             // Remove the node
00301             num_removed++;
00302             this->GetNodeCorrespondingToCell(*cell_iter)->MarkAsDeleted();
00303             mDeletedNodeIndices.push_back(this->mCellLocationMap[(*cell_iter).get()]);
00304             cell_iter = this->mCells.erase(cell_iter);
00305             --cell_iter;
00306         }
00307     }
00308     return num_removed;
00309 }
00310 
00311 template<unsigned DIM>
00312 unsigned NodeBasedCellPopulation<DIM>::AddNode(Node<DIM>* pNewNode)
00313 {
00314     if (mDeletedNodeIndices.empty())
00315     {
00316         pNewNode->SetIndex(mNodes.size());
00317         mNodes.push_back(pNewNode);
00318     }
00319     else
00320     {
00321         unsigned index = mDeletedNodeIndices.back();
00322         pNewNode->SetIndex(index);
00323         mDeletedNodeIndices.pop_back();
00324         delete mNodes[index];
00325         mNodes[index] = pNewNode;
00326     }
00327     mAddedNodes = true;
00328     return pNewNode->GetIndex();
00329 }
00330 
00331 template<unsigned DIM>
00332 unsigned NodeBasedCellPopulation<DIM>::GetNumNodes()
00333 {
00334     return mNodes.size() - mDeletedNodeIndices.size();
00335 }
00336 
00337 template<unsigned DIM>
00338 BoxCollection<DIM>* NodeBasedCellPopulation<DIM>::GetBoxCollection()
00339 {
00340     return mpBoxCollection;
00341 }
00342 
00343 template<unsigned DIM>
00344 std::set< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
00345 {
00346     if (mNodePairs.empty())
00347     {
00348         EXCEPTION("No node pairs set up, rGetNodePairs probably called before Update");
00349     }
00350     return mNodePairs;
00351 }
00352 
00353 template<unsigned DIM>
00354 void NodeBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00355 {
00356     *rParamsFile << "\t\t<MechanicsCutOffLength>" << mMechanicsCutOffLength << "</MechanicsCutOffLength>\n";
00357 
00358     // Currently no specific parameters to output all come from parent classes
00359 
00360     // Call method on direct parent class
00361     AbstractCentreBasedCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00362 }
00363 
00364 template<unsigned DIM>
00365 void NodeBasedCellPopulation<DIM>::SetMechanicsCutOffLength(double mechanicsCutOffLength)
00366 {
00367     assert(mechanicsCutOffLength > 0.0);
00368     mMechanicsCutOffLength = mechanicsCutOffLength;
00369 }
00370 
00371 template<unsigned DIM>
00372 double NodeBasedCellPopulation<DIM>::GetMechanicsCutOffLength()
00373 {
00374     return mMechanicsCutOffLength;
00375 }
00376 
00377 template<unsigned DIM>
00378 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00379 {
00380     // Update the member variables mMinSpatialPositions and mMaxSpatialPositions
00381     FindMaxAndMin();
00382 
00383     // Compute the maximum distance between any nodes in this dimension
00384     double width = mMaxSpatialPositions(rDimension) - mMinSpatialPositions(rDimension);
00385 
00386     return width;
00387 }
00388 
00389 template<unsigned DIM>
00390 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile()
00391 {
00392 #ifdef CHASTE_VTK
00393     std::stringstream time;
00394     time << SimulationTime::Instance()->GetTimeStepsElapsed();
00395     VtkMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results_"+time.str(), false);
00396 
00397     unsigned num_nodes = GetNumNodes();
00398     std::vector<double> cell_types(num_nodes);
00399     std::vector<double> cell_ancestors(num_nodes);
00400     std::vector<double> cell_mutation_states(num_nodes);
00401     std::vector<double> cell_ages(num_nodes);
00402     std::vector<double> cell_cycle_phases(num_nodes);
00403     std::vector<std::vector<double> > cellwise_data;
00404 
00405     if (CellwiseData<DIM>::Instance()->IsSetUp())
00406     {
00407         CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00408         unsigned num_variables = p_data->GetNumVariables();
00409         for (unsigned var=0; var<num_variables; var++)
00410         {
00411             std::vector<double> cellwise_data_var(num_nodes);
00412             cellwise_data.push_back(cellwise_data_var);
00413         }
00414     }
00415 
00416     // Loop over cells
00417     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00418          cell_iter != this->End();
00419          ++cell_iter)
00420     {
00421         // Get the node index corresponding to this cell
00422         unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00423 
00424         if (this->mOutputCellAncestors)
00425         {
00426             double ancestor_index = (cell_iter->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_iter->GetAncestor();
00427             cell_ancestors[node_index] = ancestor_index;
00428         }
00429         if (this->mOutputCellProliferativeTypes)
00430         {
00431             double cell_type = cell_iter->GetCellCycleModel()->GetCellProliferativeType();
00432             cell_types[node_index] = cell_type;
00433         }
00434         if (this->mOutputCellMutationStates)
00435         {
00436             double mutation_state = cell_iter->GetMutationState()->GetColour();
00437             cell_mutation_states[node_index] = mutation_state;
00438         }
00439         if (this->mOutputCellAges)
00440         {
00441             double age = cell_iter->GetAge();
00442             cell_ages[node_index] = age;
00443         }
00444         if (this->mOutputCellCyclePhases)
00445         {
00446             double cycle_phase = cell_iter->GetCellCycleModel()->GetCurrentCellCyclePhase();
00447             cell_cycle_phases[node_index] = cycle_phase;
00448         }
00449         if (CellwiseData<DIM>::Instance()->IsSetUp())
00450         {
00451             CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00452             unsigned num_variables = p_data->GetNumVariables();
00453             for (unsigned var=0; var<num_variables; var++)
00454             {
00455                 cellwise_data[var][node_index] = p_data->GetValue(*cell_iter, var);
00456             }
00457         }
00458     }
00459 
00460     if (this->mOutputCellProliferativeTypes)
00461     {
00462         mesh_writer.AddPointData("Cell types", cell_types);
00463     }
00464     if (this->mOutputCellAncestors)
00465     {
00466         mesh_writer.AddPointData("Ancestors", cell_ancestors);
00467     }
00468     if (this->mOutputCellMutationStates)
00469     {
00470         mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00471     }
00472     if (this->mOutputCellAges)
00473     {
00474         mesh_writer.AddPointData("Ages", cell_ages);
00475     }
00476     if (this->mOutputCellCyclePhases)
00477     {
00478         mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00479     }
00480     if (CellwiseData<DIM>::Instance()->IsSetUp())
00481     {
00482         for (unsigned var=0; var<cellwise_data.size(); var++)
00483         {
00484             std::stringstream data_name;
00485             data_name << "Cellwise data " << var;
00486             std::vector<double> cellwise_data_var = cellwise_data[var];
00487             mesh_writer.AddPointData(data_name.str(), cellwise_data_var);
00488         }
00489     }
00490     
00491     {
00492         // Make a copy of the nodes in a disposable mesh for writing...
00493         TetrahedralMesh<DIM,DIM> mesh;
00494         mesh.ConstructNodesWithoutMesh(mNodes);
00495         mesh_writer.WriteFilesUsingMesh(mesh);
00496     }
00497     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00498     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00499     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00500     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00501     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00502 #endif //CHASTE_VTK
00503 }
00504 
00505 template<unsigned DIM>
00506 void NodeBasedCellPopulation<DIM>::SetOutputCellVolumes(bool outputCellVolumes)
00507 {
00508     if (outputCellVolumes)
00509     {
00510         EXCEPTION("This method currently not implemented for a NodeBasedCellPopulation");
00511     }
00512 }
00513 
00515 // Explicit instantiation
00517 
00518 template class NodeBasedCellPopulation<1>;
00519 template class NodeBasedCellPopulation<2>;
00520 template class NodeBasedCellPopulation<3>;
00521 
00522 // Serialization for Boost >= 1.36
00523 #include "SerializationExportWrapperForCpp.hpp"
00524 EXPORT_TEMPLATE_CLASS_SAME_DIMS(NodeBasedCellPopulation)

Generated on Mon Apr 18 11:35:27 2011 for Chaste by  doxygen 1.5.5