NodeBasedCellPopulation.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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("At time " << SimulationTime::Instance()->GetTime() << ", 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>::AcceptPopulationCountWriter(boost::shared_ptr<AbstractCellPopulationCountWriter<DIM, DIM> > pPopulationCountWriter)
00302 {
00303     pPopulationCountWriter->Visit(this);
00304 }
00305 
00306 template<unsigned DIM>
00307 void NodeBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
00308 {
00309     pCellWriter->VisitCell(pCell, this);
00310 }
00311 
00312 template<unsigned DIM>
00313 double NodeBasedCellPopulation<DIM>::GetMechanicsCutOffLength()
00314 {
00315     return mpNodesOnlyMesh->GetMaximumInteractionDistance();
00316 }
00317 
00318 template<unsigned DIM>
00319 bool NodeBasedCellPopulation<DIM>::GetUseVariableRadii()
00320 {
00321     return mUseVariableRadii;
00322 }
00323 
00324 template<unsigned DIM>
00325 void NodeBasedCellPopulation<DIM>::SetUseVariableRadii(bool useVariableRadii)
00326 {
00327     mUseVariableRadii = useVariableRadii;
00328 }
00329 
00330 template<unsigned DIM>
00331 void NodeBasedCellPopulation<DIM>::SetLoadBalanceMesh(bool loadBalanceMesh)
00332 {
00333     mLoadBalanceMesh = loadBalanceMesh;
00334 }
00335 
00336 template<unsigned DIM>
00337 void NodeBasedCellPopulation<DIM>::SetLoadBalanceFrequency(unsigned loadBalanceFrequency)
00338 {
00339     mLoadBalanceFrequency = loadBalanceFrequency;
00340 }
00341 
00342 template<unsigned DIM>
00343 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
00344 {
00345     return mpNodesOnlyMesh->GetWidth(rDimension);
00346 }
00347 
00348 template<unsigned DIM>
00349 c_vector<double, DIM> NodeBasedCellPopulation<DIM>::GetSizeOfCellPopulation()
00350 {
00351     c_vector<double, DIM> local_size = AbstractCellPopulation<DIM, DIM>::GetSizeOfCellPopulation();
00352     c_vector<double, DIM> global_size;
00353 
00354     for (unsigned i=0; i<DIM; i++)
00355     {
00356         MPI_Allreduce(&local_size[i], &global_size[i], 1, MPI_DOUBLE, MPI_MAX, PetscTools::GetWorld());
00357     }
00358 
00359     return global_size;
00360 }
00361 
00362 template<unsigned DIM>
00363 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index)
00364 {
00365     // Check the mNodeNeighbours has been set up correctly
00366     if (mNodeNeighbours.empty())
00367     {
00368         EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNeighbouringNodeIndices()");
00369     }
00370 
00371     std::set<unsigned> neighbouring_node_indices;
00372 
00373     // Get location and radius of node
00374     Node<DIM>* p_node_i = this->GetNode(index);
00375     c_vector<double, DIM> node_i_location = p_node_i->rGetLocation();
00376     double radius_of_cell_i = p_node_i->GetRadius();
00377 
00378     // Make sure that the max_interaction distance is smaller than the box collection size
00379     if (!(radius_of_cell_i * 2.0 < mpNodesOnlyMesh->GetMaximumInteractionDistance()))
00380     {
00381         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.");
00382     }
00383 
00384     // Get set of 'candidate' neighbours
00385     std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
00386 
00387     // Find which ones are actually close
00388     for (std::set<unsigned>::iterator iter = near_nodes.begin();
00389          iter != near_nodes.end();
00390          ++iter)
00391     {
00392         // Be sure not to return the index itself
00393         if ((*iter) != index)
00394         {
00395             Node<DIM>* p_node_j = this->GetNode((*iter));
00396 
00397             // Get the location of this node
00398             c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
00399 
00400             // Get the vector the two nodes (using GetVectorFromAtoB to catch periodicities etc.)
00401             c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location);
00402 
00403             // Calculate the distance between the two nodes
00404             double distance_between_nodes = norm_2(node_to_node_vector);
00405 
00406             // Get the radius of the cell corresponding to this node
00407             double radius_of_cell_j = p_node_j->GetRadius();
00408 
00409             // If the cells are close enough to exert a force on each other...
00410             double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
00411 
00412             // Make sure that the max_interaction distance is smaller than the box collection size
00413             if (!(max_interaction_distance < mpNodesOnlyMesh->GetMaximumInteractionDistance()))
00414             {
00415                 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.");
00416             }
00417             if (distance_between_nodes <= max_interaction_distance)// + DBL_EPSILSON) //Assumes that max_interaction_distance is of order 1
00418             {
00419                 // ...then add this node index to the set of neighbouring node indices
00420                 neighbouring_node_indices.insert((*iter));
00421             }
00422         }
00423     }
00424 
00425     return neighbouring_node_indices;
00426 }
00427 
00428 template<unsigned DIM>
00429 double NodeBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell)
00430 {
00431     // Not implemented or tested in 1D
00432     assert(DIM==2 ||DIM==3);
00433 
00434     // Get node index corresponding to this cell
00435     unsigned node_index = this->GetLocationIndexUsingCell(pCell);
00436     Node<DIM>* p_node = this->GetNode(node_index);
00437 
00438     // Get cell radius
00439     double cell_radius = p_node->GetRadius();
00440 
00441     // Begin code to approximate cell volume
00442     double averaged_cell_radius = 0.0;
00443     unsigned num_cells = 0;
00444 
00445     // Get the location of this node
00446     c_vector<double, DIM> node_i_location = GetNode(node_index)->rGetLocation();
00447 
00448     // Get the set of node indices corresponding to this cell's neighbours
00449     std::set<unsigned> neighbouring_node_indices = GetNeighbouringNodeIndices(node_index);
00450 
00451     // THe number of neighbours in equilibrium configuration, from sphere packing problem
00452     unsigned num_neighbours_equil;
00453     if (DIM==2)
00454     {
00455         num_neighbours_equil = 6;
00456     }
00457     else
00458     {
00459         assert(DIM==3);
00460         num_neighbours_equil = 12;
00461     }
00462 
00463     // Loop over this set
00464     for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
00465          iter != neighbouring_node_indices.end();
00466          ++iter)
00467     {
00468         Node<DIM>* p_node_j = this->GetNode(*iter);
00469 
00470         // Get the location of the neighbouring node
00471         c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
00472 
00473         double neighbouring_cell_radius = p_node_j->GetRadius();
00474 
00475         // If this throws then you may not be considering all cell interactions use a larger cut off length
00476         assert(cell_radius+neighbouring_cell_radius<mpNodesOnlyMesh->GetMaximumInteractionDistance());
00477 
00478         // Calculate the distance between the two nodes and add to cell radius
00479         double separation = norm_2(mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location));
00480 
00481         if (separation < cell_radius+neighbouring_cell_radius)
00482         {
00483             // The effective radius is the mid point of the overlap
00484             averaged_cell_radius = averaged_cell_radius + cell_radius - (cell_radius+neighbouring_cell_radius-separation)/2.0;
00485             num_cells++;
00486         }
00487     }
00488     if (num_cells < num_neighbours_equil)
00489     {
00490         averaged_cell_radius += (num_neighbours_equil-num_cells)*cell_radius;
00491 
00492         averaged_cell_radius /= num_neighbours_equil;
00493     }
00494     else
00495     {
00496         averaged_cell_radius /= num_cells;
00497     }
00498     assert(averaged_cell_radius < mpNodesOnlyMesh->GetMaximumInteractionDistance()/2.0);
00499 
00500     cell_radius = averaged_cell_radius;
00501 
00502     // End code to approximate cell volume
00503 
00504     // Calculate cell volume from radius of cell
00505     double cell_volume = 0.0;
00506     if (DIM == 2)
00507     {
00508         cell_volume = M_PI*cell_radius*cell_radius;
00509     }
00510     else if (DIM == 3)
00511     {
00512         cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
00513     }
00514 
00515     return cell_volume;
00516 }
00517 
00518 template<unsigned DIM>
00519 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
00520 {
00521 #ifdef CHASTE_VTK
00522     // Store the present time as a string
00523     std::stringstream time;
00524     time << SimulationTime::Instance()->GetTimeStepsElapsed();
00525 
00526     // Make sure the nodes are ordered contiguously in memory
00527     NodeMap map(1 + this->mpNodesOnlyMesh->GetMaximumNodeIndex());
00528     this->mpNodesOnlyMesh->ReMesh(map);
00529 
00530     // Store the number of cells for which to output data to VTK
00531     unsigned num_nodes = GetNumNodes();
00532     std::vector<double> rank(num_nodes);
00533 
00534     unsigned num_cell_data_items = 0;
00535     std::vector<std::string> cell_data_names;
00536 
00537     // We assume that the first cell is representative of all cells
00538     if (num_nodes > 0)
00539     {
00540         num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
00541         cell_data_names = this->Begin()->GetCellData()->GetKeys();
00542     }
00543 
00544     std::vector<std::vector<double> > cell_data;
00545     for (unsigned var=0; var<num_cell_data_items; var++)
00546     {
00547         std::vector<double> cell_data_var(num_nodes);
00548         cell_data.push_back(cell_data_var);
00549     }
00550 
00551     // Create mesh writer for VTK output
00552     VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
00553     mesh_writer.SetParallelFiles(*mpNodesOnlyMesh);
00554 
00555     // Iterate over any cell writers that are present
00556     for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
00557          cell_writer_iter != this->mCellWriters.end();
00558          ++cell_writer_iter)
00559     {
00560         // Create vector to store VTK cell data
00561         std::vector<double> vtk_cell_data(num_nodes);
00562 
00563         // Loop over cells
00564         for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00565              cell_iter != this->End();
00566              ++cell_iter)
00567         {
00568             // Get the node index corresponding to this cell
00569             unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
00570             unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
00571 
00572             // Populate the vector of VTK cell data
00573             vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
00574         }
00575 
00576         mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
00577     }
00578 
00579     // Loop over cells
00580     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
00581          cell_iter != this->End();
00582          ++cell_iter)
00583     {
00584         // Get the node index corresponding to this cell
00585         unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
00586         unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
00587 
00588         for (unsigned var=0; var<num_cell_data_items; var++)
00589         {
00590             cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
00591         }
00592 
00593         rank[node_index] = (PetscTools::GetMyRank());
00594     }
00595 
00596     mesh_writer.AddPointData("Process rank", rank);
00597 
00598     if (num_cell_data_items > 0)
00599     {
00600         for (unsigned var=0; var<cell_data.size(); var++)
00601         {
00602             mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
00603         }
00604     }
00605 
00606     mesh_writer.WriteFilesUsingMesh(*mpNodesOnlyMesh);
00607 
00608     *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00609     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00610     *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00611     *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00612     if (PetscTools::IsSequential())
00613     {
00614         *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00615     }
00616     else
00617     {
00618         // Parallel vtu files  .vtu -> .pvtu
00619         *(this->mpVtkMetaFile) << ".pvtu\"/>\n";
00620     }
00621 #endif //CHASTE_VTK
00622 }
00623 
00624 template<unsigned DIM>
00625 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00626 {
00627     assert(pNewCell);
00628 
00629     // Add new cell to cell population
00630     CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00631     assert(p_created_cell == pNewCell);
00632 
00633     // Then set the new cell radius in the NodesOnlyMesh
00634     unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
00635     Node<DIM>* p_parent_node = this->GetNode(parent_node_index);
00636 
00637     unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
00638     Node<DIM>* p_new_node = this->GetNode(new_node_index);
00639 
00640     p_new_node->SetRadius(p_parent_node->GetRadius());
00641 
00642     // Return pointer to new cell
00643     return p_created_cell;
00644 }
00645 
00646 template<unsigned DIM>
00647 void NodeBasedCellPopulation<DIM>::AddMovedCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
00648 {
00649     // Create a new node
00650     mpNodesOnlyMesh->AddMovedNode(pNode);
00651 
00652     // Update cells vector
00653     this->mCells.push_back(pCell);
00654 
00655     // Update mappings between cells and location indices
00656     this->AddCellUsingLocationIndex(pNode->GetIndex(), pCell);
00657 }
00658 
00659 template<unsigned DIM>
00660 void NodeBasedCellPopulation<DIM>::DeleteMovedCell(unsigned index)
00661 {
00662     mpNodesOnlyMesh->DeleteMovedNode(index);
00663 
00664     // Update vector of cells
00665     for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
00666          cell_iter != this->mCells.end();
00667          ++cell_iter)
00668     {
00669         if (this->GetLocationIndexUsingCell(*cell_iter) == index)
00670         {
00671             // Update mappings between cells and location indices
00672             this->RemoveCellUsingLocationIndex(index, (*cell_iter));
00673             cell_iter = this->mCells.erase(cell_iter);
00674 
00675             break;
00676         }
00677     }
00678 }
00679 
00686 struct null_deleter
00687 {
00691     void operator()(void const *) const
00692     {
00693     }
00694 };
00695 
00696 template<unsigned DIM>
00697 void NodeBasedCellPopulation<DIM>::SendCellsToNeighbourProcesses()
00698 {
00699 #if BOOST_VERSION < 103700
00700     EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
00701 #else // BOOST_VERSION >= 103700
00702     MPI_Status status;
00703 
00704     if (!PetscTools::AmTopMost())
00705     {
00706         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
00707         mpCellsRecvRight = mRightCommunicator.SendRecvObject(p_cells_right, PetscTools::GetMyRank() + 1, mCellCommunicationTag, PetscTools::GetMyRank() + 1, mCellCommunicationTag, status);
00708     }
00709     if (!PetscTools::AmMaster())
00710     {
00711         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
00712         mpCellsRecvLeft = mLeftCommunicator.SendRecvObject(p_cells_left, PetscTools::GetMyRank() - 1, mCellCommunicationTag, PetscTools::GetMyRank() - 1, mCellCommunicationTag, status);
00713     }
00714 #endif
00715 }
00716 
00717 template<unsigned DIM>
00718 void NodeBasedCellPopulation<DIM>::NonBlockingSendCellsToNeighbourProcesses()
00719 {
00720 #if BOOST_VERSION < 103700
00721     EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
00722 #else // BOOST_VERSION >= 103700
00723 
00724     if (!PetscTools::AmTopMost())
00725     {
00726         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
00727         int tag = SmallPow(2u, 1+ PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() + 1);
00728         mRightCommunicator.ISendObject(p_cells_right, PetscTools::GetMyRank() + 1, tag);
00729     }
00730     if (!PetscTools::AmMaster())
00731     {
00732         int tag = SmallPow (2u, 1 + PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() - 1);
00733         boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
00734         mLeftCommunicator.ISendObject(p_cells_left, PetscTools::GetMyRank() - 1, tag);
00735     }
00736     // Now post receives to start receiving data before returning.
00737     if (!PetscTools::AmTopMost())
00738     {
00739         int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() + 1);
00740         mRightCommunicator.IRecvObject(PetscTools::GetMyRank() + 1, tag);
00741     }
00742     if (!PetscTools::AmMaster())
00743     {
00744         int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() - 1);
00745         mLeftCommunicator.IRecvObject(PetscTools::GetMyRank() - 1, tag);
00746     }
00747 #endif
00748 }
00749 
00750 template<unsigned DIM>
00751 void NodeBasedCellPopulation<DIM>::GetReceivedCells()
00752 {
00753 #if BOOST_VERSION < 103700
00754     EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
00755 #else // BOOST_VERSION >= 103700
00756 
00757     if (!PetscTools::AmTopMost())
00758     {
00759         mpCellsRecvRight = mRightCommunicator.GetRecvObject();
00760     }
00761     if (!PetscTools::AmMaster())
00762     {
00763         mpCellsRecvLeft = mLeftCommunicator.GetRecvObject();
00764     }
00765 #endif
00766 }
00767 template<unsigned DIM>
00768 std::pair<CellPtr, Node<DIM>* > NodeBasedCellPopulation<DIM>::GetCellNodePair(unsigned nodeIndex)
00769 {
00770     Node<DIM>* p_node = this->GetNode(nodeIndex);
00771 
00772     CellPtr p_cell = this->GetCellUsingLocationIndex(nodeIndex);
00773 
00774     std::pair<CellPtr, Node<DIM>* > new_pair(p_cell, p_node);
00775 
00776     return new_pair;
00777 }
00778 
00779 template<unsigned DIM>
00780 void NodeBasedCellPopulation<DIM>::AddNodeAndCellToSendRight(unsigned nodeIndex)
00781 {
00782     std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
00783 
00784     mCellsToSendRight.push_back(pair);
00785 }
00786 
00787 template<unsigned DIM>
00788 void NodeBasedCellPopulation<DIM>::AddNodeAndCellToSendLeft(unsigned nodeIndex)
00789 {
00790     std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
00791 
00792     mCellsToSendLeft.push_back(pair);
00793 }
00794 
00795 template<unsigned DIM>
00796 void NodeBasedCellPopulation<DIM>::AddReceivedCells()
00797 {
00798     if (!PetscTools::AmMaster())
00799     {
00800         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
00801              iter != mpCellsRecvLeft->end();
00802              ++iter)
00803         {
00804             // Make a shared pointer to the node to make sure it is correctly deleted.
00805             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00806             AddMovedCell(iter->first, p_node);
00807         }
00808     }
00809     if (!PetscTools::AmTopMost())
00810     {
00811         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
00812              iter != mpCellsRecvRight->end();
00813              ++iter)
00814         {
00815             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00816             AddMovedCell(iter->first, p_node);
00817         }
00818     }
00819 }
00820 
00821 template<unsigned DIM>
00822 void NodeBasedCellPopulation<DIM>::UpdateCellProcessLocation()
00823 {
00824     mpNodesOnlyMesh->ResizeBoxCollection();
00825 
00826     mpNodesOnlyMesh->CalculateNodesOutsideLocalDomain();
00827 
00828     std::vector<unsigned> nodes_to_send_right = mpNodesOnlyMesh->rGetNodesToSendRight();
00829     AddCellsToSendRight(nodes_to_send_right);
00830 
00831     std::vector<unsigned> nodes_to_send_left = mpNodesOnlyMesh->rGetNodesToSendLeft();
00832     AddCellsToSendLeft(nodes_to_send_left);
00833 
00834     // Post non-blocking send / receives so communication on both sides can start.
00835     SendCellsToNeighbourProcesses();
00836 
00837     // Post blocking receive calls that wait until communication complete.
00838     //GetReceivedCells();
00839 
00840     for (std::vector<unsigned>::iterator iter = nodes_to_send_right.begin();
00841          iter != nodes_to_send_right.end();
00842          ++iter)
00843     {
00844         DeleteMovedCell(*iter);
00845     }
00846 
00847     for (std::vector<unsigned>::iterator iter = nodes_to_send_left.begin();
00848          iter != nodes_to_send_left.end();
00849          ++iter)
00850     {
00851         DeleteMovedCell(*iter);
00852     }
00853 
00854     AddReceivedCells();
00855 
00856     NodeMap map(1 + mpNodesOnlyMesh->GetMaximumNodeIndex());
00857     mpNodesOnlyMesh->ReMesh(map);
00858     UpdateMapsAfterRemesh(map);
00859 }
00860 
00861 template<unsigned DIM>
00862 void NodeBasedCellPopulation<DIM>::RefreshHaloCells()
00863 {
00864     mpNodesOnlyMesh->ClearHaloNodes();
00865 
00866     mHaloCells.clear();
00867     mHaloCellLocationMap.clear();
00868     mLocationHaloCellMap.clear();
00869 
00870     std::vector<unsigned> halos_to_send_right = mpNodesOnlyMesh->rGetHaloNodesToSendRight();
00871     AddCellsToSendRight(halos_to_send_right);
00872 
00873     std::vector<unsigned> halos_to_send_left = mpNodesOnlyMesh->rGetHaloNodesToSendLeft();
00874     AddCellsToSendLeft(halos_to_send_left);
00875 
00876     NonBlockingSendCellsToNeighbourProcesses();
00877 }
00878 
00879 template<unsigned DIM>
00880 void NodeBasedCellPopulation<DIM>::AddCellsToSendRight(std::vector<unsigned>& cellLocationIndices)
00881 {
00882     mCellsToSendRight.clear();
00883 
00884     for (unsigned i=0; i < cellLocationIndices.size(); i++)
00885     {
00886         AddNodeAndCellToSendRight(cellLocationIndices[i]);
00887     }
00888 }
00889 
00890 template<unsigned DIM>
00891 void NodeBasedCellPopulation<DIM>::AddCellsToSendLeft(std::vector<unsigned>& cellLocationIndices)
00892 {
00893     mCellsToSendLeft.clear();
00894 
00895     for (unsigned i=0; i < cellLocationIndices.size(); i++)
00896     {
00897         AddNodeAndCellToSendLeft(cellLocationIndices[i]);
00898     }
00899 }
00900 
00901 template<unsigned DIM>
00902 void NodeBasedCellPopulation<DIM>::AddReceivedHaloCells()
00903 {
00904     GetReceivedCells();
00905 
00906     if (!PetscTools::AmMaster())
00907     {
00908         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
00909                 iter != mpCellsRecvLeft->end();
00910                 ++iter)
00911         {
00912             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00913             AddHaloCell(iter->first, p_node);
00914 
00915         }
00916     }
00917     if (!PetscTools::AmTopMost())
00918     {
00919         for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
00920                 iter != mpCellsRecvRight->end();
00921                 ++iter)
00922         {
00923             boost::shared_ptr<Node<DIM> > p_node(iter->second);
00924             AddHaloCell(iter->first, p_node);
00925         }
00926     }
00927 
00928     mpNodesOnlyMesh->AddHaloNodesToBoxes();
00929 }
00930 
00931 template<unsigned DIM>
00932 void NodeBasedCellPopulation<DIM>::AddHaloCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
00933 {
00934     mHaloCells.push_back(pCell);
00935 
00936     mpNodesOnlyMesh->AddHaloNode(pNode);
00937 
00938     mHaloCellLocationMap[pCell] = pNode->GetIndex();
00939 
00940     mLocationHaloCellMap[pNode->GetIndex()] = pCell;
00941 }
00942 
00943 // Explicit instantiation
00944 template class NodeBasedCellPopulation<1>;
00945 template class NodeBasedCellPopulation<2>;
00946 template class NodeBasedCellPopulation<3>;
00947 
00948 // Serialization for Boost >= 1.36
00949 #include "SerializationExportWrapperForCpp.hpp"
00950 EXPORT_TEMPLATE_CLASS_SAME_DIMS(NodeBasedCellPopulation)

Generated by  doxygen 1.6.2