36 #include "NodeBasedCellPopulation.hpp"
38 #include "VtkMeshWriter.hpp"
41 #include "CellAgesWriter.hpp"
42 #include "CellAncestorWriter.hpp"
43 #include "CellProliferativePhasesWriter.hpp"
44 #include "CellProliferativeTypesWriter.hpp"
45 #include "CellVolumesWriter.hpp"
46 #include "CellMutationStatesWriter.hpp"
48 template<
unsigned DIM>
50 std::vector<CellPtr>& rCells,
51 const std::vector<unsigned> locationIndices,
55 mDeleteMesh(deleteMesh),
56 mUseVariableRadii(false),
57 mLoadBalanceMesh(false),
58 mLoadBalanceFrequency(100)
68 template<
unsigned DIM>
72 mUseVariableRadii(false),
73 mLoadBalanceMesh(false),
74 mLoadBalanceFrequency(100)
79 template<
unsigned DIM>
89 template<
unsigned DIM>
92 return *mpNodesOnlyMesh;
95 template<
unsigned DIM>
98 return *mpNodesOnlyMesh;
101 template<
unsigned DIM>
107 template<
unsigned DIM>
111 node_iter != this->mrMesh.GetNodeIteratorEnd();
116 this->GetCellUsingLocationIndex(node_iter->GetIndex());
125 template<
unsigned DIM>
128 return mpNodesOnlyMesh->GetNodeOrHaloNode(index);
131 template<
unsigned DIM>
134 mpNodesOnlyMesh->SetNode(nodeIndex, rNewLocation,
false);
137 template<
unsigned DIM>
140 UpdateCellProcessLocation();
142 mpNodesOnlyMesh->UpdateBoxCollection();
144 if (mLoadBalanceMesh)
148 mpNodesOnlyMesh->LoadBalanceMesh();
150 UpdateCellProcessLocation();
152 mpNodesOnlyMesh->UpdateBoxCollection();
158 mpNodesOnlyMesh->CalculateInteriorNodePairs(mNodePairs, mNodeNeighbours);
160 AddReceivedHaloCells();
162 mpNodesOnlyMesh->CalculateBoundaryNodePairs(mNodePairs, mNodeNeighbours);
167 if (mUseVariableRadii)
170 cell_iter != this->End();
173 double cell_radius = cell_iter->GetCellData()->GetItem(
"Radius");
174 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
175 this->GetNode(node_index)->SetRadius(cell_radius);
183 template<
unsigned DIM>
188 UpdateParticlesAfterReMesh(map);
192 std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
195 this->mLocationCellMap.clear();
196 this->mCellLocationMap.clear();
198 for (std::list<CellPtr>::iterator it = this->mCells.begin();
199 it != this->mCells.end();
202 unsigned old_node_index = old_map[(*it).get()];
207 unsigned new_node_index = map.
GetNewIndex(old_node_index);
208 this->SetCellUsingLocationIndex(new_node_index,*it);
215 template<
unsigned DIM>
218 unsigned num_removed = 0;
219 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
220 cell_iter != this->mCells.end();
223 if ((*cell_iter)->IsDead())
227 unsigned location_index = mpNodesOnlyMesh->SolveNodeMapping(this->GetLocationIndexUsingCell((*cell_iter)));
228 mpNodesOnlyMesh->DeleteNodePriorToReMesh(location_index);
231 unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*cell_iter));
232 this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*cell_iter));
235 cell_iter = this->mCells.erase(cell_iter);
246 template<
unsigned DIM>
249 return mpNodesOnlyMesh->AddNode(pNewNode);
252 template<
unsigned DIM>
255 return mpNodesOnlyMesh->GetNumNodes();
258 template<
unsigned DIM>
261 std::map<unsigned, CellPtr>::iterator iter = mLocationHaloCellMap.find(index);
262 if (iter != mLocationHaloCellMap.end())
272 template<
unsigned DIM>
277 template<
unsigned DIM>
283 template<
unsigned DIM>
286 *rParamsFile <<
"\t\t<MechanicsCutOffLength>" << mpNodesOnlyMesh->GetMaximumInteractionDistance() <<
"</MechanicsCutOffLength>\n";
287 *rParamsFile <<
"\t\t<UseVariableRadii>" << mUseVariableRadii <<
288 "</UseVariableRadii>\n";
294 template<
unsigned DIM>
297 pPopulationWriter->Visit(
this);
300 template<
unsigned DIM>
303 pPopulationCountWriter->Visit(
this);
306 template<
unsigned DIM>
309 pCellWriter->VisitCell(pCell,
this);
312 template<
unsigned DIM>
315 return mpNodesOnlyMesh->GetMaximumInteractionDistance();
318 template<
unsigned DIM>
321 return mUseVariableRadii;
324 template<
unsigned DIM>
327 mUseVariableRadii = useVariableRadii;
330 template<
unsigned DIM>
333 mLoadBalanceMesh = loadBalanceMesh;
336 template<
unsigned DIM>
339 mLoadBalanceFrequency = loadBalanceFrequency;
342 template<
unsigned DIM>
345 return mpNodesOnlyMesh->GetWidth(rDimension);
348 template<
unsigned DIM>
352 c_vector<double, DIM> global_size;
354 for (
unsigned i=0; i<DIM; i++)
362 template<
unsigned DIM>
366 if (neighbourhoodRadius > mpNodesOnlyMesh->GetMaximumInteractionDistance())
368 EXCEPTION(
"neighbourhoodRadius should be less than or equal to the the maximum interaction radius defined on the NodesOnlyMesh");
373 if (mNodeNeighbours.empty())
375 EXCEPTION(
"mNodeNeighbours not set up. Call Update() before GetNodesWithinNeighbourhoodRadius()");
378 std::set<unsigned> neighbouring_node_indices;
381 Node<DIM>* p_node_i = this->GetNode(index);
382 c_vector<double, DIM> node_i_location = p_node_i->
rGetLocation();
385 std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
388 for (std::set<unsigned>::iterator iter = near_nodes.begin();
389 iter != near_nodes.end();
393 if ((*iter) != index)
395 Node<DIM>* p_node_j = this->GetNode((*iter));
398 c_vector<double, DIM> node_j_location = p_node_j->
rGetLocation();
401 c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location);
404 double distance_between_nodes = norm_2(node_to_node_vector);
408 if (distance_between_nodes <= neighbourhoodRadius)
411 neighbouring_node_indices.insert((*iter));
416 return neighbouring_node_indices;
419 template<
unsigned DIM>
423 if (mNodeNeighbours.empty())
425 EXCEPTION(
"mNodeNeighbours not set up. Call Update() before GetNeighbouringNodeIndices()");
428 std::set<unsigned> neighbouring_node_indices;
431 Node<DIM>* p_node_i = this->GetNode(index);
432 c_vector<double, DIM> node_i_location = p_node_i->
rGetLocation();
433 double radius_of_cell_i = p_node_i->
GetRadius();
436 if (!(radius_of_cell_i * 2.0 <= mpNodesOnlyMesh->GetMaximumInteractionDistance()))
438 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.");
442 std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
445 for (std::set<unsigned>::iterator iter = near_nodes.begin();
446 iter != near_nodes.end();
450 if ((*iter) != index)
452 Node<DIM>* p_node_j = this->GetNode((*iter));
455 c_vector<double, DIM> node_j_location = p_node_j->
rGetLocation();
458 c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location);
461 double distance_between_nodes = norm_2(node_to_node_vector);
464 double radius_of_cell_j = p_node_j->
GetRadius();
467 double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
470 if (!(max_interaction_distance <= mpNodesOnlyMesh->GetMaximumInteractionDistance()))
472 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.");
474 if (distance_between_nodes <= max_interaction_distance)
477 neighbouring_node_indices.insert((*iter));
482 return neighbouring_node_indices;
485 template<
unsigned DIM>
489 assert(DIM==2 ||DIM==3);
492 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
493 Node<DIM>* p_node = this->GetNode(node_index);
496 double cell_radius = p_node->
GetRadius();
499 double averaged_cell_radius = 0.0;
500 unsigned num_cells = 0;
503 c_vector<double, DIM> node_i_location = GetNode(node_index)->rGetLocation();
506 std::set<unsigned> neighbouring_node_indices = GetNeighbouringNodeIndices(node_index);
509 unsigned num_neighbours_equil;
512 num_neighbours_equil = 6;
517 num_neighbours_equil = 12;
521 for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
522 iter != neighbouring_node_indices.end();
525 Node<DIM>* p_node_j = this->GetNode(*iter);
528 c_vector<double, DIM> node_j_location = p_node_j->
rGetLocation();
530 double neighbouring_cell_radius = p_node_j->
GetRadius();
533 assert(cell_radius+neighbouring_cell_radius<mpNodesOnlyMesh->GetMaximumInteractionDistance());
536 double separation = norm_2(mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location));
538 if (separation < cell_radius+neighbouring_cell_radius)
541 averaged_cell_radius = averaged_cell_radius + cell_radius - (cell_radius+neighbouring_cell_radius-separation)/2.0;
545 if (num_cells < num_neighbours_equil)
547 averaged_cell_radius += (num_neighbours_equil-num_cells)*cell_radius;
549 averaged_cell_radius /= num_neighbours_equil;
553 averaged_cell_radius /= num_cells;
555 assert(averaged_cell_radius < mpNodesOnlyMesh->GetMaximumInteractionDistance()/2.0);
557 cell_radius = averaged_cell_radius;
562 double cell_volume = 0.0;
565 cell_volume = M_PI*cell_radius*cell_radius;
569 cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
575 template<
unsigned DIM>
580 std::stringstream time;
584 NodeMap map(1 + this->mpNodesOnlyMesh->GetMaximumNodeIndex());
585 this->mpNodesOnlyMesh->ReMesh(map);
588 unsigned num_nodes = GetNumNodes();
589 std::vector<double> rank(num_nodes);
591 unsigned num_cell_data_items = 0;
592 std::vector<std::string> cell_data_names;
597 num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
598 cell_data_names = this->Begin()->GetCellData()->GetKeys();
601 std::vector<std::vector<double> > cell_data;
602 for (
unsigned var=0; var<num_cell_data_items; var++)
604 std::vector<double> cell_data_var(num_nodes);
605 cell_data.push_back(cell_data_var);
614 cell_writer_iter != this->mCellWriters.end();
618 std::vector<double> vtk_cell_data(num_nodes);
622 cell_iter != this->End();
626 unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
627 unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
630 vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter,
this);
633 mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
638 cell_iter != this->End();
642 unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
643 unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
645 for (
unsigned var=0; var<num_cell_data_items; var++)
647 cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
653 mesh_writer.AddPointData(
"Process rank", rank);
655 if (num_cell_data_items > 0)
657 for (
unsigned var=0; var<cell_data.size(); var++)
659 mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
663 mesh_writer.WriteFilesUsingMesh(*mpNodesOnlyMesh);
665 *(this->mpVtkMetaFile) <<
" <DataSet timestep=\"";
667 *(this->mpVtkMetaFile) <<
"\" group=\"\" part=\"0\" file=\"results_";
671 *(this->mpVtkMetaFile) <<
".vtu\"/>\n";
676 *(this->mpVtkMetaFile) <<
".pvtu\"/>\n";
681 template<
unsigned DIM>
688 assert(p_created_cell == pNewCell);
691 unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
692 Node<DIM>* p_parent_node = this->GetNode(parent_node_index);
694 unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
695 Node<DIM>* p_new_node = this->GetNode(new_node_index);
700 return p_created_cell;
703 template<
unsigned DIM>
707 mpNodesOnlyMesh->AddMovedNode(pNode);
710 this->mCells.push_back(pCell);
713 this->AddCellUsingLocationIndex(pNode->GetIndex(), pCell);
716 template<
unsigned DIM>
719 mpNodesOnlyMesh->DeleteMovedNode(index);
722 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
723 cell_iter != this->mCells.end();
726 if (this->GetLocationIndexUsingCell(*cell_iter) == index)
729 this->RemoveCellUsingLocationIndex(index, (*cell_iter));
730 cell_iter = this->mCells.erase(cell_iter);
753 template<
unsigned DIM>
756 #if BOOST_VERSION < 103700
757 EXCEPTION(
"Parallel cell-based Chaste requires Boost >= 1.37");
758 #else // BOOST_VERSION >= 103700
763 boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight,
null_deleter());
768 boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft,
null_deleter());
774 template<
unsigned DIM>
777 #if BOOST_VERSION < 103700
778 EXCEPTION(
"Parallel cell-based Chaste requires Boost >= 1.37");
779 #else // BOOST_VERSION >= 103700
783 boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight,
null_deleter());
790 boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft,
null_deleter());
807 template<
unsigned DIM>
810 #if BOOST_VERSION < 103700
811 EXCEPTION(
"Parallel cell-based Chaste requires Boost >= 1.37");
812 #else // BOOST_VERSION >= 103700
816 mpCellsRecvRight = mRightCommunicator.GetRecvObject();
820 mpCellsRecvLeft = mLeftCommunicator.GetRecvObject();
824 template<
unsigned DIM>
827 Node<DIM>* p_node = this->GetNode(nodeIndex);
829 CellPtr p_cell = this->GetCellUsingLocationIndex(nodeIndex);
831 std::pair<CellPtr, Node<DIM>* > new_pair(p_cell, p_node);
836 template<
unsigned DIM>
839 std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
841 mCellsToSendRight.push_back(pair);
844 template<
unsigned DIM>
847 std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
849 mCellsToSendLeft.push_back(pair);
852 template<
unsigned DIM>
857 for (
typename std::vector<std::pair<CellPtr,
Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
858 iter != mpCellsRecvLeft->end();
862 boost::shared_ptr<Node<DIM> > p_node(iter->second);
863 AddMovedCell(iter->first, p_node);
868 for (
typename std::vector<std::pair<CellPtr,
Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
869 iter != mpCellsRecvRight->end();
872 boost::shared_ptr<Node<DIM> > p_node(iter->second);
873 AddMovedCell(iter->first, p_node);
878 template<
unsigned DIM>
881 mpNodesOnlyMesh->ResizeBoxCollection();
883 mpNodesOnlyMesh->CalculateNodesOutsideLocalDomain();
885 std::vector<unsigned> nodes_to_send_right = mpNodesOnlyMesh->rGetNodesToSendRight();
886 AddCellsToSendRight(nodes_to_send_right);
888 std::vector<unsigned> nodes_to_send_left = mpNodesOnlyMesh->rGetNodesToSendLeft();
889 AddCellsToSendLeft(nodes_to_send_left);
892 SendCellsToNeighbourProcesses();
897 for (std::vector<unsigned>::iterator iter = nodes_to_send_right.begin();
898 iter != nodes_to_send_right.end();
901 DeleteMovedCell(*iter);
904 for (std::vector<unsigned>::iterator iter = nodes_to_send_left.begin();
905 iter != nodes_to_send_left.end();
908 DeleteMovedCell(*iter);
913 NodeMap map(1 + mpNodesOnlyMesh->GetMaximumNodeIndex());
914 mpNodesOnlyMesh->ReMesh(map);
915 UpdateMapsAfterRemesh(map);
918 template<
unsigned DIM>
921 mpNodesOnlyMesh->ClearHaloNodes();
924 mHaloCellLocationMap.clear();
925 mLocationHaloCellMap.clear();
927 std::vector<unsigned> halos_to_send_right = mpNodesOnlyMesh->rGetHaloNodesToSendRight();
928 AddCellsToSendRight(halos_to_send_right);
930 std::vector<unsigned> halos_to_send_left = mpNodesOnlyMesh->rGetHaloNodesToSendLeft();
931 AddCellsToSendLeft(halos_to_send_left);
933 NonBlockingSendCellsToNeighbourProcesses();
936 template<
unsigned DIM>
939 mCellsToSendRight.clear();
941 for (
unsigned i=0; i < cellLocationIndices.size(); i++)
943 AddNodeAndCellToSendRight(cellLocationIndices[i]);
947 template<
unsigned DIM>
950 mCellsToSendLeft.clear();
952 for (
unsigned i=0; i < cellLocationIndices.size(); i++)
954 AddNodeAndCellToSendLeft(cellLocationIndices[i]);
958 template<
unsigned DIM>
965 for (
typename std::vector<std::pair<CellPtr,
Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
966 iter != mpCellsRecvLeft->end();
969 boost::shared_ptr<Node<DIM> > p_node(iter->second);
970 AddHaloCell(iter->first, p_node);
976 for (
typename std::vector<std::pair<CellPtr,
Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
977 iter != mpCellsRecvRight->end();
980 boost::shared_ptr<Node<DIM> > p_node(iter->second);
981 AddHaloCell(iter->first, p_node);
985 mpNodesOnlyMesh->AddHaloNodesToBoxes();
988 template<
unsigned DIM>
991 mHaloCells.push_back(pCell);
993 mpNodesOnlyMesh->AddHaloNode(pNode);
995 mHaloCellLocationMap[pCell] = pNode->GetIndex();
997 mLocationHaloCellMap[pNode->GetIndex()] = pCell;
void AddCellsToSendRight(std::vector< unsigned > &cellLocationIndices)
double GetMechanicsCutOffLength()
void OutputCellPopulationParameters(out_stream &rParamsFile)
std::set< unsigned > GetNodesWithinNeighbourhoodRadius(unsigned index, double neighbourhoodRadius)
NodesOnlyMesh< DIM > & rGetMesh()
bool GetUseVariableRadii()
virtual ~NodeBasedCellPopulation()
NodeBasedCellPopulation(NodesOnlyMesh< DIM > &rMesh, std::vector< CellPtr > &rCells, const std::vector< unsigned > locationIndices=std::vector< unsigned >(), bool deleteMesh=false, bool validate=true)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
double SmallPow(double x, unsigned exponent)
c_vector< double, DIM > GetSizeOfCellPopulation()
void SetRadius(double radius)
unsigned RemoveDeadCells()
#define EXCEPTION(message)
Node< DIM > * GetNode(unsigned index)
void AddCellsToSendLeft(std::vector< unsigned > &cellLocationIndices)
static SimulationTime * Instance()
void SetParallelFiles(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
void SetNode(unsigned nodeIndex, ChastePoint< DIM > &rNewLocation)
void SetUseVariableRadii(bool useVariableRadii=true)
unsigned GetTimeStepsElapsed() const
void operator()(void const *) const
void AddMovedCell(CellPtr pCell, boost::shared_ptr< Node< DIM > > pNode)
std::pair< CellPtr, Node< DIM > * > GetCellNodePair(unsigned nodeIndex)
void NonBlockingSendCellsToNeighbourProcesses()
double GetVolumeOfCell(CellPtr pCell)
virtual void AcceptPopulationWriter(boost::shared_ptr< AbstractCellPopulationWriter< DIM, DIM > > pPopulationWriter)
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
c_vector< double, SPACE_DIM > GetSizeOfCellPopulation()
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
void SendCellsToNeighbourProcesses()
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
void UpdateMapsAfterRemesh(NodeMap &map)
void SetLoadBalanceMesh(bool loadBalanceMesh)
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
virtual void AcceptCellWriter(boost::shared_ptr< AbstractCellWriter< DIM, DIM > > pCellWriter, CellPtr pCell)
void AddHaloCell(CellPtr pCell, boost::shared_ptr< Node< DIM > > pNode)
double GetWidth(const unsigned &rDimension)
unsigned AddNode(Node< DIM > *pNewNode)
const c_vector< double, SPACE_DIM > & rGetLocation() const
bool IsDeleted(unsigned index)
unsigned GetNewIndex(unsigned oldIndex) const
std::vector< std::pair< Node< DIM > *, Node< DIM > * > > & rGetNodePairs()
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
NodesOnlyMesh< DIM > * mpNodesOnlyMesh
CellPtr AddCell(CellPtr pNewCell, const c_vector< double, SPACE_DIM > &rCellDivisionVector, CellPtr pParentCell=CellPtr())
virtual void UpdateCellProcessLocation()
void DeleteMovedCell(unsigned index)
void Update(bool hasHadBirthsOrDeaths=true)
AbstractMesh< ELEMENT_DIM, SPACE_DIM > & mrMesh
virtual void AcceptPopulationCountWriter(boost::shared_ptr< AbstractCellPopulationCountWriter< DIM, DIM > > pPopulationCountWriter)
void SetLoadBalanceFrequency(unsigned loadBalanceFrequency)
void AddNodeAndCellToSendLeft(unsigned nodeIndex)
void AddReceivedHaloCells()
void AddNodeAndCellToSendRight(unsigned nodeIndex)
virtual void UpdateParticlesAfterReMesh(NodeMap &rMap)
virtual CellPtr AddCell(CellPtr pNewCell, const c_vector< double, DIM > &rCellDivisionVector, CellPtr pParentCell)