NodeBasedCellPopulation.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 "NodeBasedCellPopulation.hpp"
00037 #include "MathsCustomFunctions.hpp"
00038 #include "VtkMeshWriter.hpp"
00039 
00040 // Cell writers
00041 #include "CellAgesWriter.hpp"
00042 #include "CellAncestorWriter.hpp"
00043 #include "CellProliferativePhasesWriter.hpp"
00044 #include "CellProliferativeTypesWriter.hpp"
00045 #include "CellVolumesWriter.hpp"
00046 #include "CellMutationStatesWriter.hpp"
00047 
00048 template<unsigned DIM>
00049 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh,
00050                                       std::vector<CellPtr>& rCells,
00051                                       const std::vector<unsigned> locationIndices,
00052                                       bool deleteMesh,
00053                                       bool validate)
00054     : AbstractCentreBasedCellPopulation<DIM>(rMesh, rCells, locationIndices),
00055       mDeleteMesh(deleteMesh),
00056       mUseVariableRadii(false),
00057       mLoadBalanceMesh(false),
00058       mLoadBalanceFrequency(100)
00059 {
00060     mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
00061 
00062     if (validate)
00063     {
00064         Validate();
00065     }
00066 }
00067 
00068 template<unsigned DIM>
00069 NodeBasedCellPopulation<DIM>::NodeBasedCellPopulation(NodesOnlyMesh<DIM>& rMesh)
00070     : AbstractCentreBasedCellPopulation<DIM>(rMesh),
00071       mDeleteMesh(true),
00072       mUseVariableRadii(false), // will be set by serialize() method
00073       mLoadBalanceMesh(false),
00074       mLoadBalanceFrequency(100)
00075 {
00076     mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
00077 }
00078 
00079 template<unsigned DIM>
00080 NodeBasedCellPopulation<DIM>::~NodeBasedCellPopulation()
00081 {
00082     Clear();
00083     if (mDeleteMesh)
00084     {
00085         delete &this->mrMesh;
00086     }
00087 }
00088 
00089 template<unsigned DIM>
00090 NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh()
00091 {
00092     return *mpNodesOnlyMesh;
00093 }
00094 
00095 template<unsigned DIM>
00096 const NodesOnlyMesh<DIM>& NodeBasedCellPopulation<DIM>::rGetMesh() const
00097 {
00098     return *mpNodesOnlyMesh;
00099 }
00100 
00101 template<unsigned DIM>
00102 void NodeBasedCellPopulation<DIM>::Clear()
00103 {
00104     mNodePairs.clear();
00105 }
00106 
00107 template<unsigned DIM>
00108 void NodeBasedCellPopulation<DIM>::Validate()
00109 {
00110     for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
00111          node_iter != this->mrMesh.GetNodeIteratorEnd();
00112          ++node_iter)
00113     {
00114         try
00115         {
00116             this->GetCellUsingLocationIndex(node_iter->GetIndex());
00117         }
00118         catch (Exception&)
00119         {
00120             EXCEPTION("Node " << node_iter->GetIndex() << " does not appear to have a cell associated with it");
00121         }
00122     }
00123 }
00124 
00125 template<unsigned DIM>
00126 Node<DIM>* NodeBasedCellPopulation<DIM>::GetNode(unsigned index)
00127 {
00128     return mpNodesOnlyMesh->GetNodeOrHaloNode(index);
00129 }
00130 
00131 template<unsigned DIM>
00132 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
00133 {
00134     mpNodesOnlyMesh->GetNode(nodeIndex)->SetPoint(rNewLocation);
00135 }
00136 
00137 template<unsigned DIM>
00138 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
00139 {
00140     UpdateCellProcessLocation();
00141 
00142     mpNodesOnlyMesh->UpdateBoxCollection();
00143 
00144     if (mLoadBalanceMesh)
00145     {
00146         if ((SimulationTime::Instance()->GetTimeStepsElapsed() % mLoadBalanceFrequency) == 0)
00147         {
00148             mpNodesOnlyMesh->LoadBalanceMesh();
00149 
00150             UpdateCellProcessLocation();
00151 
00152             mpNodesOnlyMesh->UpdateBoxCollection();
00153         }
00154     }
00155 
00156     RefreshHaloCells();
00157 
00158     mpNodesOnlyMesh->CalculateInteriorNodePairs(mNodePairs, mNodeNeighbours);
00159 
00160     AddReceivedHaloCells();
00161 
00162     mpNodesOnlyMesh->CalculateBoundaryNodePairs(mNodePairs, mNodeNeighbours);
00163 
00164     /*
00165      * Update cell radii based on CellData
00166      */
00167     if (mUseVariableRadii)
00168     {
00169         for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00170              cell_iter != this->End();
00171              ++cell_iter)
00172         {
00173             double cell_radius = cell_iter->GetCellData()->GetItem("Radius");
00174             unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
00175             this->GetNode(node_index)->SetRadius(cell_radius);
00176         }
00177     }
00178 
00179     // Make sure that everyone exits update together so that all asynchronous communications are complete.
00180     PetscTools::Barrier("Update");
00181 }
00182 
00183 template<unsigned DIM>
00184 void NodeBasedCellPopulation<DIM>::UpdateMapsAfterRemesh(NodeMap& map)
00185 {
00186     if (!map.IsIdentityMap())
00187     {
00188         UpdateParticlesAfterReMesh(map);
00189 
00190         // Update the mappings between cells and location indices
00192         std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
00193 
00194         // Remove any dead pointers from the maps (needed to avoid archiving errors)
00195         this->mLocationCellMap.clear();
00196         this->mCellLocationMap.clear();
00197 
00198         for (std::list<CellPtr>::iterator it = this->mCells.begin();
00199              it != this->mCells.end();
00200              ++it)
00201         {
00202             unsigned old_node_index = old_map[(*it).get()];
00203 
00204             // This shouldn't ever happen, as the cell vector only contains living cells
00205             assert(!map.IsDeleted(old_node_index));
00206 
00207             unsigned new_node_index = map.GetNewIndex(old_node_index);
00208             this->SetCellUsingLocationIndex(new_node_index,*it);
00209         }
00210 
00211         this->Validate();
00212     }
00213 }
00214 
00215 template<unsigned DIM>
00216 unsigned NodeBasedCellPopulation<DIM>::RemoveDeadCells()
00217 {
00218     unsigned num_removed = 0;
00219     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00220          cell_iter != this->mCells.end();
00221          )
00222     {
00223         if ((*cell_iter)->IsDead())
00224         {
00225             // Remove the node from the mesh
00226             num_removed++;
00227             unsigned location_index = mpNodesOnlyMesh->SolveNodeMapping(this->GetLocationIndexUsingCell((*cell_iter)));
00228             mpNodesOnlyMesh->DeleteNodePriorToReMesh(location_index);
00229 
00230             // Update mappings between cells and location indices
00231             unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*cell_iter));
00232             this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*cell_iter));
00233 
00234             // Update vector of cells
00235             cell_iter = this->mCells.erase(cell_iter);
00236         }
00237         else
00238         {
00239             ++cell_iter;
00240         }
00241     }
00242 
00243     return num_removed;
00244 }
00245 
00246 template<unsigned DIM>
00247 unsigned NodeBasedCellPopulation<DIM>::AddNode(Node<DIM>* pNewNode)
00248 {
00249     return mpNodesOnlyMesh->AddNode(pNewNode);
00250 }
00251 
00252 template<unsigned DIM>
00253 unsigned NodeBasedCellPopulation<DIM>::GetNumNodes()
00254 {
00255     return mpNodesOnlyMesh->GetNumNodes();
00256 }
00257 
00258 template<unsigned DIM>
00259 CellPtr NodeBasedCellPopulation<DIM>::GetCellUsingLocationIndex(unsigned index)
00260 {
00261     std::map<unsigned, CellPtr>::iterator iter = mLocationHaloCellMap.find(index);
00262     if (iter != mLocationHaloCellMap.end())
00263     {
00264         return iter->second;
00265     }
00266     else
00267     {
00268         return AbstractCellPopulation<DIM, DIM>::GetCellUsingLocationIndex(index);
00269     }
00270 }
00271 
00272 template<unsigned DIM>
00273 void NodeBasedCellPopulation<DIM>::UpdateParticlesAfterReMesh(NodeMap& rMap)
00274 {
00275 }
00276 
00277 template<unsigned DIM>
00278 std::vector< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
00279 {
00280     return mNodePairs;
00281 }
00282 
00283 template<unsigned DIM>
00284 void NodeBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00285 {
00286     *rParamsFile << "\t\t<MechanicsCutOffLength>" << mpNodesOnlyMesh->GetMaximumInteractionDistance() << "</MechanicsCutOffLength>\n";
00287     *rParamsFile << "\t\t<UseVariableRadii>" << mUseVariableRadii <<
00288 "</UseVariableRadii>\n";
00289 
00290     // Call method on direct parent class
00291     AbstractCentreBasedCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00292 }
00293 
00294 template<unsigned DIM>
00295 void NodeBasedCellPopulation<DIM>::AcceptPopulationWriter(boost::shared_ptr<AbstractCellPopulationWriter<DIM, DIM> > pPopulationWriter)
00296 {
00297     pPopulationWriter->Visit(this);
00298 }
00299 
00300 template<unsigned DIM>
00301 void NodeBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00302 {
00303     pCellWriter->VisitCell(pCell, this);
00304 }
00305 
00306 template<unsigned DIM>
00307 double NodeBasedCellPopulation<DIM>::GetMechanicsCutOffLength()
00308 {
00309     return mpNodesOnlyMesh->GetMaximumInteractionDistance();
00310 }
00311 
00312 template<unsigned DIM>
00313 bool NodeBasedCellPopulation<DIM>::GetUseVariableRadii()
00314 {
00315     return mUseVariableRadii;
00316 }
00317 
00318 template<unsigned DIM>
00319 void NodeBasedCellPopulation<DIM>::SetUseVariableRadii(bool useVariableRadii)
00320 {
00321     mUseVariableRadii = useVariableRadii;
00322 }
00323 
00324 template<unsigned DIM>
00325 void NodeBasedCellPopulation<DIM>::SetLoadBalanceMesh(bool loadBalanceMesh)
00326 {
00327     mLoadBalanceMesh = loadBalanceMesh;
00328 }
00329 
00330 template<unsigned DIM>
00331 void NodeBasedCellPopulation<DIM>::SetLoadBalanceFrequency(unsigned loadBalanceFrequency)
00332 {
00333     mLoadBalanceFrequency = loadBalanceFrequency;
00334 }
00335 
00336 template<unsigned DIM>
00337 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00338 {
00339     return mpNodesOnlyMesh->GetWidth(rDimension);
00340 }
00341 
00342 template<unsigned DIM>
00343 c_vector<double, DIM> NodeBasedCellPopulation<DIM>::GetSizeOfCellPopulation()
00344 {
00345     c_vector<double, DIM> local_size = AbstractCellPopulation<DIM, DIM>::GetSizeOfCellPopulation();
00346     c_vector<double, DIM> global_size;
00347 
00348     for (unsigned i=0; i<DIM; i++)
00349     {
00350         MPI_Allreduce(&local_size[i], &global_size[i], 1, MPI_DOUBLE, MPI_MAX, PetscTools::GetWorld());
00351     }
00352 
00353     return global_size;
00354 }
00355 
00356 template<unsigned DIM>
00357 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00358 {
00359     // Check the mNodeNeighbours has been set up correctly
00360     if (mNodeNeighbours.empty())
00361     {
00362         EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNeighbouringNodeIndices()");
00363     }
00364 
00365     std::set<unsigned> neighbouring_node_indices;
00366 
00367     // Get location and radius of node
00368     Node<DIM>* p_node_i = this->GetNode(index);
00369     c_vector<double, DIM> node_i_location = p_node_i->rGetLocation();
00370     double radius_of_cell_i = p_node_i->GetRadius();
00371 
00372     // Make sure that the max_interaction distance is smaller than the box collection size
00373     if (!(radius_of_cell_i * 2.0 < mpNodesOnlyMesh->GetMaximumInteractionDistance()))
00374     {
00375         EXCEPTION("mpNodesOnlyMesh::mMaxInteractionDistance 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.");
00376     }
00377 
00378 
00379     // Get set of 'candidate' neighbours.
00380     std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
00381 
00382     // Find which ones are actually close
00383     for (std::set<unsigned>::iterator iter = near_nodes.begin();
00384             iter != near_nodes.end();
00385             ++iter)
00386     {
00387         // Be sure not to return the index itself.
00388         if ((*iter) != index)
00389         {
00390             Node<DIM>* p_node_j = this->GetNode((*iter));
00391 
00392             // Get the location of this node
00393             c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
00394 
00395             // Get the vector the two nodes (using GetVectorFromAtoB to catch periodicities etc.)
00396             c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location);
00397 
00398             // Calculate the distance between the two nodes
00399             double distance_between_nodes = norm_2(node_to_node_vector);
00400 
00401             // Get the radius of the cell corresponding to this node
00402             double radius_of_cell_j = p_node_j->GetRadius();
00403 
00404             // If the cells are close enough to exert a force on each other...
00405             double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
00406 
00407             // Make sure that the max_interaction distance is smaller than the box collection size
00408             if (!(max_interaction_distance < mpNodesOnlyMesh->GetMaximumInteractionDistance()))
00409             {
00410                 EXCEPTION("mpNodesOnlyMesh::mMaxInteractionDistance 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.");
00411             }
00412             if (distance_between_nodes <= max_interaction_distance)// + DBL_EPSILSON) //Assumes that max_interaction_distance is of over 1
00413             {
00414                 // ...then add this node index to the set of neighbouring node indices
00415                 neighbouring_node_indices.insert((*iter));
00416             }
00417         }
00418     }
00419 
00420     return neighbouring_node_indices;
00421 }
00422 
00423 template<unsigned DIM>
00424 double NodeBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00425 {
00426     // Not implemented or tested in 1D
00427     assert(DIM==2 ||DIM==3);
00428 
00429     // Get node index corresponding to this cell
00430     unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00431     Node<DIM>* p_node = this->GetNode(node_index);
00432 
00433     // Get cell radius
00434     double cell_radius = p_node->GetRadius();
00435 
00436     // Begin code to approximate cell volume
00437     double averaged_cell_radius = 0.0;
00438     unsigned num_cells = 0;
00439 
00440     // Get the location of this node
00441     c_vector<double, DIM> node_i_location = GetNode(node_index)->rGetLocation();
00442 
00443     // Get the set of node indices corresponding to this cell's neighbours
00444     std::set<unsigned> neighbouring_node_indices = GetNeighbouringNodeIndices(node_index);
00445 
00446     // THe number of neighbours in equilibrium configuration, from sphere packing problem
00447     unsigned num_neighbours_equil;
00448     if (DIM==2)
00449     {
00450         num_neighbours_equil = 6;
00451     }
00452     else
00453     {
00454         assert(DIM==3);
00455         num_neighbours_equil = 12;
00456     }
00457 
00458     // Loop over this set
00459     for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00460          iter != neighbouring_node_indices.end();
00461          ++iter)
00462     {
00463         Node<DIM>* p_node_j = this->GetNode(*iter);
00464 
00465         // Get the location of the neighbouring node
00466         c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
00467 
00468         double neighbouring_cell_radius = p_node_j->GetRadius();
00469 
00470         // If this throws then you may not be considering all cell interactions use a larger cut off length
00471         assert(cell_radius+neighbouring_cell_radius<mpNodesOnlyMesh->GetMaximumInteractionDistance());
00472 
00473         // Calculate the distance between the two nodes and add to cell radius
00474         double separation = norm_2(mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location));
00475 
00476         if (separation < cell_radius+neighbouring_cell_radius)
00477         {
00478             // The effective radius is the mid point of the overlap
00479             averaged_cell_radius = averaged_cell_radius + cell_radius - (cell_radius+neighbouring_cell_radius-separation)/2.0;
00480             num_cells++;
00481         }
00482     }
00483     if (num_cells < num_neighbours_equil)
00484     {
00485         averaged_cell_radius += (num_neighbours_equil-num_cells)*cell_radius;
00486 
00487         averaged_cell_radius /=num_neighbours_equil;
00488     }
00489     else
00490     {
00491         averaged_cell_radius /= num_cells;
00492     }
00493     assert(averaged_cell_radius < mpNodesOnlyMesh->GetMaximumInteractionDistance()/2.0);
00494 
00495     cell_radius = averaged_cell_radius;
00496 
00497     // End code to approximate cell volume
00498 
00499     // Calculate cell volume from radius of cell
00500     double cell_volume = 0.0;
00501     if (DIM == 2)
00502     {
00503         cell_volume = M_PI*cell_radius*cell_radius;
00504     }
00505     else if (DIM == 3)
00506     {
00507         cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
00508     }
00509 
00510     return cell_volume;
00511 }
00512 
00513 template<unsigned DIM>
00514 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00515 {
00516 #ifdef CHASTE_VTK
00517     std::stringstream time;
00518     time << SimulationTime::Instance()->GetTimeStepsElapsed();
00519     VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
00520 
00521     // Make sure the nodes are ordered contiguously in memory.
00522     NodeMap map(1 + this->mpNodesOnlyMesh->GetMaximumNodeIndex());
00523     this->mpNodesOnlyMesh->ReMesh(map);
00524 
00525     mesh_writer.SetParallelFiles(*mpNodesOnlyMesh);
00526 
00527     unsigned num_nodes = GetNumNodes();
00528     std::vector<double> cell_types(num_nodes);
00529     std::vector<double> cell_ancestors(num_nodes);
00530     std::vector<double> cell_mutation_states(num_nodes);
00531     std::vector<double> cell_ages(num_nodes);
00532     std::vector<double> cell_cycle_phases(num_nodes);
00533     std::vector<double> cell_radii(num_nodes);
00534     std::vector<std::vector<double> > cellwise_data;
00535     std::vector<double> rank(num_nodes);
00536 
00537     unsigned num_cell_data_items = 0;
00538     std::vector<std::string> cell_data_names;
00539 
00540     // We assume that the first cell is representative of all cells
00541     if (num_nodes > 0)
00542     {
00543         num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00544         cell_data_names = this->Begin()->GetCellData()->GetKeys();
00545     }
00546 
00547     for (unsigned var=0; var<num_cell_data_items; var++)
00548     {
00549         std::vector<double> cellwise_data_var(num_nodes);
00550         cellwise_data.push_back(cellwise_data_var);
00551     }
00552 
00553     // Loop over cells
00554     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00555          cell_iter != this->End();
00556          ++cell_iter)
00557     {
00558         // Get the node index corresponding to this cell
00559         unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
00560 
00561         Node<DIM>* p_node = this->GetNode(global_index);
00562 
00563         unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
00564 
00565         if (this-> template HasWriter<CellAncestorWriter>())
00566         {
00567             double ancestor_index = (cell_iter->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)cell_iter->GetAncestor();
00568             cell_ancestors[node_index] = ancestor_index;
00569         }
00570         if (this-> template HasWriter<CellProliferativeTypesWriter>())
00571         {
00572             double cell_type = cell_iter->GetCellProliferativeType()->GetColour();
00573             cell_types[node_index] = cell_type;
00574         }
00575         if (this-> template HasWriter<CellMutationStatesWriter>())
00576         {
00577             double mutation_state = cell_iter->GetMutationState()->GetColour();
00578 
00580             CellPropertyCollection collection = cell_iter->rGetCellPropertyCollection();
00581             CellPropertyCollection label_collection = collection.GetProperties<CellLabel>();
00582 
00583             if (label_collection.GetSize() == 1)
00584             {
00585                 boost::shared_ptr<CellLabel> p_label = boost::static_pointer_cast<CellLabel>(label_collection.GetProperty());
00586                 mutation_state = p_label->GetColour();
00587             }
00588 
00589             cell_mutation_states[node_index] = mutation_state;
00590         }
00591         if (this-> template HasWriter<CellAgesWriter>())
00592         {
00593             double age = cell_iter->GetAge();
00594             cell_ages[node_index] = age;
00595         }
00596         if (this-> template HasWriter<CellProliferativePhasesWriter>())
00597         {
00598             double cycle_phase = cell_iter->GetCellCycleModel()->GetCurrentCellCyclePhase();
00599             cell_cycle_phases[node_index] = cycle_phase;
00600         }
00601         if (this-> template HasWriter<CellVolumesWriter>())
00602         {
00603             double cell_radius = p_node->GetRadius();
00604             cell_radii[node_index] = cell_radius;
00605         }
00606 
00607         for (unsigned var=0; var<num_cell_data_items; var++)
00608         {
00609             cellwise_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
00610         }
00611 
00612         rank[node_index] = (PetscTools::GetMyRank());
00613     }
00614 
00615     mesh_writer.AddPointData("Process rank", rank);
00616 
00617     if (this-> template HasWriter<CellProliferativeTypesWriter>())
00618     {
00619         mesh_writer.AddPointData("Cell types", cell_types);
00620     }
00621     if (this-> template HasWriter<CellAncestorWriter>())
00622     {
00623         mesh_writer.AddPointData("Ancestors", cell_ancestors);
00624     }
00625     if (this-> template HasWriter<CellMutationStatesWriter>())
00626     {
00627         mesh_writer.AddPointData("Mutation states", cell_mutation_states);
00628     }
00629     if (this-> template HasWriter<CellAgesWriter>())
00630     {
00631         mesh_writer.AddPointData("Ages", cell_ages);
00632     }
00633     if (this-> template HasWriter<CellProliferativePhasesWriter>())
00634     {
00635         mesh_writer.AddPointData("Cycle phases", cell_cycle_phases);
00636     }
00637     if (this-> template HasWriter<CellVolumesWriter>())
00638     {
00639         mesh_writer.AddPointData("Cell radii", cell_radii);
00640     }
00641     if (num_cell_data_items > 0)
00642     {
00643         for (unsigned var=0; var<cellwise_data.size(); var++)
00644         {
00645             mesh_writer.AddPointData(cell_data_names[var], cellwise_data[var]);
00646         }
00647     }
00648 
00649     mesh_writer.WriteFilesUsingMesh(*mpNodesOnlyMesh);
00650 
00651     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00652     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00653     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00654     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00655     *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00656 #endif //CHASTE_VTK
00657 }
00658 
00659 template<unsigned DIM>
00660 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00661 {
00662     assert(pNewCell);
00663 
00664     // Add new cell to cell population
00665     CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00666     assert(p_created_cell == pNewCell);
00667 
00668     // Then set the new cell radius in the NodesOnlyMesh
00669     unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
00670     Node<DIM>* p_parent_node = this->GetNode(parent_node_index);
00671 
00672     unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
00673     Node<DIM>* p_new_node = this->GetNode(new_node_index);
00674 
00675     p_new_node->SetRadius(p_parent_node->GetRadius());
00676 
00677     // Return pointer to new cell
00678     return p_created_cell;
00679 }
00680 
00681 template<unsigned DIM>
00682 void NodeBasedCellPopulation<DIM>::AddMovedCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
00683 {
00684     // Create a new node
00685     mpNodesOnlyMesh->AddMovedNode(pNode);
00686 
00687     // Update cells vector
00688     this->mCells.push_back(pCell);
00689 
00690     // Update mappings between cells and location indices
00691     this->AddCellUsingLocationIndex(pNode->GetIndex(), pCell);
00692 }
00693 
00694 template<unsigned DIM>
00695 void NodeBasedCellPopulation<DIM>::DeleteMovedCell(unsigned index)
00696 {
00697     mpNodesOnlyMesh->DeleteMovedNode(index);
00698 
00699     // Update vector of cells
00700     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00701          cell_iter != this->mCells.end();
00702          ++cell_iter)
00703     {
00704         if (this->GetLocationIndexUsingCell(*cell_iter) == index)
00705         {
00706             // Update mappings between cells and location indices
00707             this->RemoveCellUsingLocationIndex(index, (*cell_iter));
00708             cell_iter = this->mCells.erase(cell_iter);
00709 
00710             break;
00711         }
00712     }
00713 }
00714 
00721 struct null_deleter
00722 {
00726     void operator()(void const *) const
00727     {
00728     }
00729 };
00730 
00731 template<unsigned DIM>
00732 void NodeBasedCellPopulation<DIM>::SendCellsToNeighbourProcesses()
00733 {
00734 #if BOOST_VERSION < 103700
00735     EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
00736 #else // BOOST_VERSION >= 103700
00737     MPI_Status status;
00738 
00739     if (!PetscTools::AmTopMost())
00740     {
00741         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
00742         mpCellsRecvRight = mRightCommunicator.SendRecvObject(p_cells_right, PetscTools::GetMyRank() + 1, mCellCommunicationTag, PetscTools::GetMyRank() + 1, mCellCommunicationTag, status);
00743     }
00744     if (!PetscTools::AmMaster())
00745     {
00746         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
00747         mpCellsRecvLeft = mLeftCommunicator.SendRecvObject(p_cells_left, PetscTools::GetMyRank() - 1, mCellCommunicationTag, PetscTools::GetMyRank() - 1, mCellCommunicationTag, status);
00748     }
00749 #endif
00750 }
00751 
00752 template<unsigned DIM>
00753 void NodeBasedCellPopulation<DIM>::NonBlockingSendCellsToNeighbourProcesses()
00754 {
00755 #if BOOST_VERSION < 103700
00756     EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
00757 #else // BOOST_VERSION >= 103700
00758 
00759     if (!PetscTools::AmTopMost())
00760     {
00761         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
00762         int tag = SmallPow(2u, 1+ PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() + 1);
00763         mRightCommunicator.ISendObject(p_cells_right, PetscTools::GetMyRank() + 1, tag);
00764     }
00765     if (!PetscTools::AmMaster())
00766     {
00767         int tag = SmallPow (2u, 1 + PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() - 1);
00768         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
00769         mLeftCommunicator.ISendObject(p_cells_left, PetscTools::GetMyRank() - 1, tag);
00770     }
00771     // Now post receives to start receiving data before returning.
00772     if (!PetscTools::AmTopMost())
00773     {
00774         int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() + 1);
00775         mRightCommunicator.IRecvObject(PetscTools::GetMyRank() + 1, tag);
00776     }
00777     if (!PetscTools::AmMaster())
00778     {
00779         int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() - 1);
00780         mLeftCommunicator.IRecvObject(PetscTools::GetMyRank() - 1, tag);
00781     }
00782 #endif
00783 }
00784 
00785 template<unsigned DIM>
00786 void NodeBasedCellPopulation<DIM>::GetReceivedCells()
00787 {
00788 #if BOOST_VERSION < 103700
00789     EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
00790 #else // BOOST_VERSION >= 103700
00791 
00792     if (!PetscTools::AmTopMost())
00793     {
00794         mpCellsRecvRight = mRightCommunicator.GetRecvObject();
00795     }
00796     if (!PetscTools::AmMaster())
00797     {
00798         mpCellsRecvLeft = mLeftCommunicator.GetRecvObject();
00799     }
00800 #endif
00801 }
00802 template<unsigned DIM>
00803 std::pair<CellPtr, Node<DIM>* > NodeBasedCellPopulation<DIM>::GetCellNodePair(unsigned nodeIndex)
00804 {
00805     Node<DIM>* p_node = this->GetNode(nodeIndex);
00806 
00807     CellPtr p_cell = this->GetCellUsingLocationIndex(nodeIndex);
00808 
00809     std::pair<CellPtr, Node<DIM>* > new_pair(p_cell, p_node);
00810 
00811     return new_pair;
00812 }
00813 
00814 template<unsigned DIM>
00815 void NodeBasedCellPopulation<DIM>::AddNodeAndCellToSendRight(unsigned nodeIndex)
00816 {
00817     std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
00818 
00819     mCellsToSendRight.push_back(pair);
00820 }
00821 
00822 template<unsigned DIM>
00823 void NodeBasedCellPopulation<DIM>::AddNodeAndCellToSendLeft(unsigned nodeIndex)
00824 {
00825     std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
00826 
00827     mCellsToSendLeft.push_back(pair);
00828 }
00829 
00830 template<unsigned DIM>
00831 void NodeBasedCellPopulation<DIM>::AddReceivedCells()
00832 {
00833     if (!PetscTools::AmMaster())
00834     {
00835         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
00836              iter != mpCellsRecvLeft->end();
00837              ++iter)
00838         {
00839             // Make a shared pointer to the node to make sure it is correctly deleted.
00840             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00841             AddMovedCell(iter->first, p_node);
00842         }
00843     }
00844     if (!PetscTools::AmTopMost())
00845     {
00846         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
00847              iter != mpCellsRecvRight->end();
00848              ++iter)
00849         {
00850             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00851             AddMovedCell(iter->first, p_node);
00852         }
00853     }
00854 }
00855 
00856 template<unsigned DIM>
00857 void NodeBasedCellPopulation<DIM>::UpdateCellProcessLocation()
00858 {
00859     mpNodesOnlyMesh->ResizeBoxCollection();
00860 
00861     mpNodesOnlyMesh->CalculateNodesOutsideLocalDomain();
00862 
00863     std::vector<unsigned> nodes_to_send_right = mpNodesOnlyMesh->rGetNodesToSendRight();
00864     AddCellsToSendRight(nodes_to_send_right);
00865 
00866     std::vector<unsigned> nodes_to_send_left = mpNodesOnlyMesh->rGetNodesToSendLeft();
00867     AddCellsToSendLeft(nodes_to_send_left);
00868 
00869     // Post non-blocking send / receives so communication on both sides can start.
00870     SendCellsToNeighbourProcesses();
00871 
00872     // Post blocking receive calls that wait until communication complete.
00873     //GetReceivedCells();
00874 
00875     for (std::vector<unsigned>::iterator iter = nodes_to_send_right.begin();
00876          iter != nodes_to_send_right.end();
00877          ++iter)
00878     {
00879         DeleteMovedCell(*iter);
00880     }
00881 
00882     for (std::vector<unsigned>::iterator iter = nodes_to_send_left.begin();
00883          iter != nodes_to_send_left.end();
00884          ++iter)
00885     {
00886         DeleteMovedCell(*iter);
00887     }
00888 
00889     AddReceivedCells();
00890 
00891     NodeMap map(1 + mpNodesOnlyMesh->GetMaximumNodeIndex());
00892     mpNodesOnlyMesh->ReMesh(map);
00893     UpdateMapsAfterRemesh(map);
00894 }
00895 
00896 template<unsigned DIM>
00897 void NodeBasedCellPopulation<DIM>::RefreshHaloCells()
00898 {
00899     mpNodesOnlyMesh->ClearHaloNodes();
00900 
00901     mHaloCells.clear();
00902     mHaloCellLocationMap.clear();
00903     mLocationHaloCellMap.clear();
00904 
00905     std::vector<unsigned> halos_to_send_right = mpNodesOnlyMesh->rGetHaloNodesToSendRight();
00906     AddCellsToSendRight(halos_to_send_right);
00907 
00908     std::vector<unsigned> halos_to_send_left = mpNodesOnlyMesh->rGetHaloNodesToSendLeft();
00909     AddCellsToSendLeft(halos_to_send_left);
00910 
00911     NonBlockingSendCellsToNeighbourProcesses();
00912 }
00913 
00914 template<unsigned DIM>
00915 void NodeBasedCellPopulation<DIM>::AddCellsToSendRight(std::vector<unsigned>& cellLocationIndices)
00916 {
00917     mCellsToSendRight.clear();
00918 
00919     for (unsigned i=0; i < cellLocationIndices.size(); i++)
00920     {
00921         AddNodeAndCellToSendRight(cellLocationIndices[i]);
00922     }
00923 }
00924 
00925 template<unsigned DIM>
00926 void NodeBasedCellPopulation<DIM>::AddCellsToSendLeft(std::vector<unsigned>& cellLocationIndices)
00927 {
00928     mCellsToSendLeft.clear();
00929 
00930     for (unsigned i=0; i < cellLocationIndices.size(); i++)
00931     {
00932         AddNodeAndCellToSendLeft(cellLocationIndices[i]);
00933     }
00934 }
00935 
00936 template<unsigned DIM>
00937 void NodeBasedCellPopulation<DIM>::AddReceivedHaloCells()
00938 {
00939     GetReceivedCells();
00940 
00941     if (!PetscTools::AmMaster())
00942     {
00943         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
00944                 iter != mpCellsRecvLeft->end();
00945                 ++iter)
00946         {
00947             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00948             AddHaloCell(iter->first, p_node);
00949 
00950         }
00951     }
00952     if (!PetscTools::AmTopMost())
00953     {
00954         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
00955                 iter != mpCellsRecvRight->end();
00956                 ++iter)
00957         {
00958             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00959             AddHaloCell(iter->first, p_node);
00960         }
00961     }
00962 
00963     mpNodesOnlyMesh->AddHaloNodesToBoxes();
00964 }
00965 
00966 template<unsigned DIM>
00967 void NodeBasedCellPopulation<DIM>::AddHaloCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
00968 {
00969     mHaloCells.push_back(pCell);
00970 
00971     mpNodesOnlyMesh->AddHaloNode(pNode);
00972 
00973     mHaloCellLocationMap[pCell] = pNode->GetIndex();
00974 
00975     mLocationHaloCellMap[pNode->GetIndex()] = pCell;
00976 }
00977 
00978 // Explicit instantiation
00979 template class NodeBasedCellPopulation<1>;
00980 template class NodeBasedCellPopulation<2>;
00981 template class NodeBasedCellPopulation<3>;
00982 
00983 // Serialization for Boost >= 1.36
00984 #include "SerializationExportWrapperForCpp.hpp"
00985 EXPORT_TEMPLATE_CLASS_SAME_DIMS(NodeBasedCellPopulation)

Generated by  doxygen 1.6.2