Chaste  Release::3.4
NodeBasedCellPopulation.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "NodeBasedCellPopulation.hpp"
37 #include "MathsCustomFunctions.hpp"
38 #include "VtkMeshWriter.hpp"
39 
40 // Cell writers
41 #include "CellAgesWriter.hpp"
42 #include "CellAncestorWriter.hpp"
43 #include "CellProliferativePhasesWriter.hpp"
44 #include "CellProliferativeTypesWriter.hpp"
45 #include "CellVolumesWriter.hpp"
46 #include "CellMutationStatesWriter.hpp"
47 
48 template<unsigned DIM>
50  std::vector<CellPtr>& rCells,
51  const std::vector<unsigned> locationIndices,
52  bool deleteMesh,
53  bool validate)
54  : AbstractCentreBasedCellPopulation<DIM>(rMesh, rCells, locationIndices),
55  mDeleteMesh(deleteMesh),
56  mUseVariableRadii(false),
57  mLoadBalanceMesh(false),
58  mLoadBalanceFrequency(100)
59 {
60  mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
61 
62  if (validate)
63  {
64  Validate();
65  }
66 }
67 
68 template<unsigned DIM>
71  mDeleteMesh(true),
72  mUseVariableRadii(false), // will be set by serialize() method
73  mLoadBalanceMesh(false),
74  mLoadBalanceFrequency(100)
75 {
76  mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
77 }
78 
79 template<unsigned DIM>
81 {
82  Clear();
83  if (mDeleteMesh)
84  {
85  delete &this->mrMesh;
86  }
87 }
88 
89 template<unsigned DIM>
91 {
92  return *mpNodesOnlyMesh;
93 }
94 
95 template<unsigned DIM>
97 {
98  return *mpNodesOnlyMesh;
99 }
100 
101 template<unsigned DIM>
103 {
104  mNodePairs.clear();
105 }
106 
107 template<unsigned DIM>
109 {
110  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
111  node_iter != this->mrMesh.GetNodeIteratorEnd();
112  ++node_iter)
113  {
114  try
115  {
116  this->GetCellUsingLocationIndex(node_iter->GetIndex());
117  }
118  catch (Exception&)
119  {
120  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Node " << node_iter->GetIndex() << " does not appear to have a cell associated with it");
121  }
122  }
123 }
124 
125 template<unsigned DIM>
127 {
128  return mpNodesOnlyMesh->GetNodeOrHaloNode(index);
129 }
130 
131 template<unsigned DIM>
132 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
133 {
134  mpNodesOnlyMesh->SetNode(nodeIndex, rNewLocation, false);
135 }
136 
137 template<unsigned DIM>
138 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
139 {
140  UpdateCellProcessLocation();
141 
142  mpNodesOnlyMesh->UpdateBoxCollection();
143 
144  if (mLoadBalanceMesh)
145  {
146  if ((SimulationTime::Instance()->GetTimeStepsElapsed() % mLoadBalanceFrequency) == 0)
147  {
148  mpNodesOnlyMesh->LoadBalanceMesh();
149 
150  UpdateCellProcessLocation();
151 
152  mpNodesOnlyMesh->UpdateBoxCollection();
153  }
154  }
155 
156  RefreshHaloCells();
157 
158  mpNodesOnlyMesh->CalculateInteriorNodePairs(mNodePairs, mNodeNeighbours);
159 
160  AddReceivedHaloCells();
161 
162  mpNodesOnlyMesh->CalculateBoundaryNodePairs(mNodePairs, mNodeNeighbours);
163 
164  /*
165  * Update cell radii based on CellData
166  */
167  if (mUseVariableRadii)
168  {
169  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
170  cell_iter != this->End();
171  ++cell_iter)
172  {
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);
176  }
177  }
178 
179  // Make sure that everyone exits update together so that all asynchronous communications are complete.
180  PetscTools::Barrier("Update");
181 }
182 
183 template<unsigned DIM>
185 {
186  if (!map.IsIdentityMap())
187  {
188  UpdateParticlesAfterReMesh(map);
189 
190  // Update the mappings between cells and location indices
192  std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
193 
194  // Remove any dead pointers from the maps (needed to avoid archiving errors)
195  this->mLocationCellMap.clear();
196  this->mCellLocationMap.clear();
197 
198  for (std::list<CellPtr>::iterator it = this->mCells.begin();
199  it != this->mCells.end();
200  ++it)
201  {
202  unsigned old_node_index = old_map[(*it).get()];
203 
204  // This shouldn't ever happen, as the cell vector only contains living cells
205  assert(!map.IsDeleted(old_node_index));
206 
207  unsigned new_node_index = map.GetNewIndex(old_node_index);
208  this->SetCellUsingLocationIndex(new_node_index,*it);
209  }
210 
211  this->Validate();
212  }
213 }
214 
215 template<unsigned DIM>
217 {
218  unsigned num_removed = 0;
219  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
220  cell_iter != this->mCells.end();
221  )
222  {
223  if ((*cell_iter)->IsDead())
224  {
225  // Remove the node from the mesh
226  num_removed++;
227  unsigned location_index = mpNodesOnlyMesh->SolveNodeMapping(this->GetLocationIndexUsingCell((*cell_iter)));
228  mpNodesOnlyMesh->DeleteNodePriorToReMesh(location_index);
229 
230  // Update mappings between cells and location indices
231  unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*cell_iter));
232  this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*cell_iter));
233 
234  // Update vector of cells
235  cell_iter = this->mCells.erase(cell_iter);
236  }
237  else
238  {
239  ++cell_iter;
240  }
241  }
242 
243  return num_removed;
244 }
245 
246 template<unsigned DIM>
248 {
249  return mpNodesOnlyMesh->AddNode(pNewNode);
250 }
251 
252 template<unsigned DIM>
254 {
255  return mpNodesOnlyMesh->GetNumNodes();
256 }
257 
258 template<unsigned DIM>
260 {
261  std::map<unsigned, CellPtr>::iterator iter = mLocationHaloCellMap.find(index);
262  if (iter != mLocationHaloCellMap.end())
263  {
264  return iter->second;
265  }
266  else
267  {
269  }
270 }
271 
272 template<unsigned DIM>
274 {
275 }
276 
277 template<unsigned DIM>
278 std::vector< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
279 {
280  return mNodePairs;
281 }
282 
283 template<unsigned DIM>
285 {
286  *rParamsFile << "\t\t<MechanicsCutOffLength>" << mpNodesOnlyMesh->GetMaximumInteractionDistance() << "</MechanicsCutOffLength>\n";
287  *rParamsFile << "\t\t<UseVariableRadii>" << mUseVariableRadii <<
288 "</UseVariableRadii>\n";
289 
290  // Call method on direct parent class
292 }
293 
294 template<unsigned DIM>
296 {
297  pPopulationWriter->Visit(this);
298 }
299 
300 template<unsigned DIM>
302 {
303  pPopulationCountWriter->Visit(this);
304 }
305 
306 template<unsigned DIM>
307 void NodeBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
308 {
309  pCellWriter->VisitCell(pCell, this);
310 }
311 
312 template<unsigned DIM>
314 {
315  return mpNodesOnlyMesh->GetMaximumInteractionDistance();
316 }
317 
318 template<unsigned DIM>
320 {
321  return mUseVariableRadii;
322 }
323 
324 template<unsigned DIM>
326 {
327  mUseVariableRadii = useVariableRadii;
328 }
329 
330 template<unsigned DIM>
332 {
333  mLoadBalanceMesh = loadBalanceMesh;
334 }
335 
336 template<unsigned DIM>
337 void NodeBasedCellPopulation<DIM>::SetLoadBalanceFrequency(unsigned loadBalanceFrequency)
338 {
339  mLoadBalanceFrequency = loadBalanceFrequency;
340 }
341 
342 template<unsigned DIM>
343 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
344 {
345  return mpNodesOnlyMesh->GetWidth(rDimension);
346 }
347 
348 template<unsigned DIM>
350 {
351  c_vector<double, DIM> local_size = AbstractCellPopulation<DIM, DIM>::GetSizeOfCellPopulation();
352  c_vector<double, DIM> global_size;
353 
354  for (unsigned i=0; i<DIM; i++)
355  {
356  MPI_Allreduce(&local_size[i], &global_size[i], 1, MPI_DOUBLE, MPI_MAX, PetscTools::GetWorld());
357  }
358 
359  return global_size;
360 }
361 
362 template<unsigned DIM>
363 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNodesWithinNeighbourhoodRadius(unsigned index, double neighbourhoodRadius)
364 {
365  // Check neighbourhoodRadius is less than the interaction radius. If not you wont return all the correct nodes
366  if (neighbourhoodRadius > mpNodesOnlyMesh->GetMaximumInteractionDistance())
367  {
368  EXCEPTION("neighbourhoodRadius should be less than or equal to the the maximum interaction radius defined on the NodesOnlyMesh");
369  }
370 
371 
372  // Check the mNodeNeighbours has been set up correctly
373  if (mNodeNeighbours.empty())
374  {
375  EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNodesWithinNeighbourhoodRadius()");
376  }
377 
378  std::set<unsigned> neighbouring_node_indices;
379 
380  // Get location
381  Node<DIM>* p_node_i = this->GetNode(index);
382  c_vector<double, DIM> node_i_location = p_node_i->rGetLocation();
383 
384  // Get set of 'candidate' neighbours.
385  std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
386 
387  // Find which ones are actually close
388  for (std::set<unsigned>::iterator iter = near_nodes.begin();
389  iter != near_nodes.end();
390  ++iter)
391  {
392  // Be sure not to return the index itself.
393  if ((*iter) != index)
394  {
395  Node<DIM>* p_node_j = this->GetNode((*iter));
396 
397  // Get the location of this node
398  c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
399 
400  // Get the vector the two nodes (using GetVectorFromAtoB to catch periodicities etc.)
401  c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location);
402 
403  // Calculate the distance between the two nodes
404  double distance_between_nodes = norm_2(node_to_node_vector);
405 
406  // If the cell j is within the neighbourhood of radius neighbourhoodRadius
407  // of cell i
408  if (distance_between_nodes <= neighbourhoodRadius)// + DBL_EPSILSON)
409  {
410  // ...then add this node index to the set of neighbouring node indices
411  neighbouring_node_indices.insert((*iter));
412  }
413  }
414  }
415 
416  return neighbouring_node_indices;
417 }
418 
419 template<unsigned DIM>
421 {
422  // Check the mNodeNeighbours has been set up correctly
423  if (mNodeNeighbours.empty())
424  {
425  EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNeighbouringNodeIndices()");
426  }
427 
428  std::set<unsigned> neighbouring_node_indices;
429 
430  // Get location and radius of node
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();
434 
435  // Make sure that the max_interaction distance is smaller than or equal to the box collection size
436  if (!(radius_of_cell_i * 2.0 <= mpNodesOnlyMesh->GetMaximumInteractionDistance()))
437  {
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.");
439  }
440 
441  // Get set of 'candidate' neighbours
442  std::set<unsigned> near_nodes = mNodeNeighbours.find(index)->second;
443 
444  // Find which ones are actually close
445  for (std::set<unsigned>::iterator iter = near_nodes.begin();
446  iter != near_nodes.end();
447  ++iter)
448  {
449  // Be sure not to return the index itself
450  if ((*iter) != index)
451  {
452  Node<DIM>* p_node_j = this->GetNode((*iter));
453 
454  // Get the location of this node
455  c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
456 
457  // Get the vector the two nodes (using GetVectorFromAtoB to catch periodicities etc.)
458  c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location);
459 
460  // Calculate the distance between the two nodes
461  double distance_between_nodes = norm_2(node_to_node_vector);
462 
463  // Get the radius of the cell corresponding to this node
464  double radius_of_cell_j = p_node_j->GetRadius();
465 
466  // If the cells are close enough to exert a force on each other...
467  double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
468 
469  // Make sure that the max_interaction distance is smaller than or equal to the box collection size
470  if (!(max_interaction_distance <= mpNodesOnlyMesh->GetMaximumInteractionDistance()))
471  {
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.");
473  }
474  if (distance_between_nodes <= max_interaction_distance)// + DBL_EPSILSON) //Assumes that max_interaction_distance is of order 1
475  {
476  // ...then add this node index to the set of neighbouring node indices
477  neighbouring_node_indices.insert((*iter));
478  }
479  }
480  }
481 
482  return neighbouring_node_indices;
483 }
484 
485 template<unsigned DIM>
487 {
488  // Not implemented or tested in 1D
489  assert(DIM==2 ||DIM==3);
490 
491  // Get node index corresponding to this cell
492  unsigned node_index = this->GetLocationIndexUsingCell(pCell);
493  Node<DIM>* p_node = this->GetNode(node_index);
494 
495  // Get cell radius
496  double cell_radius = p_node->GetRadius();
497 
498  // Begin code to approximate cell volume
499  double averaged_cell_radius = 0.0;
500  unsigned num_cells = 0;
501 
502  // Get the location of this node
503  c_vector<double, DIM> node_i_location = GetNode(node_index)->rGetLocation();
504 
505  // Get the set of node indices corresponding to this cell's neighbours
506  std::set<unsigned> neighbouring_node_indices = GetNeighbouringNodeIndices(node_index);
507 
508  // THe number of neighbours in equilibrium configuration, from sphere packing problem
509  unsigned num_neighbours_equil;
510  if (DIM==2)
511  {
512  num_neighbours_equil = 6;
513  }
514  else
515  {
516  assert(DIM==3);
517  num_neighbours_equil = 12;
518  }
519 
520  // Loop over this set
521  for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
522  iter != neighbouring_node_indices.end();
523  ++iter)
524  {
525  Node<DIM>* p_node_j = this->GetNode(*iter);
526 
527  // Get the location of the neighbouring node
528  c_vector<double, DIM> node_j_location = p_node_j->rGetLocation();
529 
530  double neighbouring_cell_radius = p_node_j->GetRadius();
531 
532  // If this throws then you may not be considering all cell interactions use a larger cut off length
533  assert(cell_radius+neighbouring_cell_radius<mpNodesOnlyMesh->GetMaximumInteractionDistance());
534 
535  // Calculate the distance between the two nodes and add to cell radius
536  double separation = norm_2(mpNodesOnlyMesh->GetVectorFromAtoB(node_j_location,node_i_location));
537 
538  if (separation < cell_radius+neighbouring_cell_radius)
539  {
540  // The effective radius is the mid point of the overlap
541  averaged_cell_radius = averaged_cell_radius + cell_radius - (cell_radius+neighbouring_cell_radius-separation)/2.0;
542  num_cells++;
543  }
544  }
545  if (num_cells < num_neighbours_equil)
546  {
547  averaged_cell_radius += (num_neighbours_equil-num_cells)*cell_radius;
548 
549  averaged_cell_radius /= num_neighbours_equil;
550  }
551  else
552  {
553  averaged_cell_radius /= num_cells;
554  }
555  assert(averaged_cell_radius < mpNodesOnlyMesh->GetMaximumInteractionDistance()/2.0);
556 
557  cell_radius = averaged_cell_radius;
558 
559  // End code to approximate cell volume
560 
561  // Calculate cell volume from radius of cell
562  double cell_volume = 0.0;
563  if (DIM == 2)
564  {
565  cell_volume = M_PI*cell_radius*cell_radius;
566  }
567  else if (DIM == 3)
568  {
569  cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
570  }
571 
572  return cell_volume;
573 }
574 
575 template<unsigned DIM>
576 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
577 {
578 #ifdef CHASTE_VTK
579  // Store the present time as a string
580  std::stringstream time;
582 
583  // Make sure the nodes are ordered contiguously in memory
584  NodeMap map(1 + this->mpNodesOnlyMesh->GetMaximumNodeIndex());
585  this->mpNodesOnlyMesh->ReMesh(map);
586 
587  // Store the number of cells for which to output data to VTK
588  unsigned num_nodes = GetNumNodes();
589  std::vector<double> rank(num_nodes);
590 
591  unsigned num_cell_data_items = 0;
592  std::vector<std::string> cell_data_names;
593 
594  // We assume that the first cell is representative of all cells
595  if (num_nodes > 0)
596  {
597  num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
598  cell_data_names = this->Begin()->GetCellData()->GetKeys();
599  }
600 
601  std::vector<std::vector<double> > cell_data;
602  for (unsigned var=0; var<num_cell_data_items; var++)
603  {
604  std::vector<double> cell_data_var(num_nodes);
605  cell_data.push_back(cell_data_var);
606  }
607 
608  // Create mesh writer for VTK output
609  VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
610  mesh_writer.SetParallelFiles(*mpNodesOnlyMesh);
611 
612  // Iterate over any cell writers that are present
613  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
614  cell_writer_iter != this->mCellWriters.end();
615  ++cell_writer_iter)
616  {
617  // Create vector to store VTK cell data
618  std::vector<double> vtk_cell_data(num_nodes);
619 
620  // Loop over cells
621  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
622  cell_iter != this->End();
623  ++cell_iter)
624  {
625  // Get the node index corresponding to this cell
626  unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
627  unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
628 
629  // Populate the vector of VTK cell data
630  vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
631  }
632 
633  mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
634  }
635 
636  // Loop over cells
637  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
638  cell_iter != this->End();
639  ++cell_iter)
640  {
641  // Get the node index corresponding to this cell
642  unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
643  unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
644 
645  for (unsigned var=0; var<num_cell_data_items; var++)
646  {
647  cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
648  }
649 
650  rank[node_index] = (PetscTools::GetMyRank());
651  }
652 
653  mesh_writer.AddPointData("Process rank", rank);
654 
655  if (num_cell_data_items > 0)
656  {
657  for (unsigned var=0; var<cell_data.size(); var++)
658  {
659  mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
660  }
661  }
662 
663  mesh_writer.WriteFilesUsingMesh(*mpNodesOnlyMesh);
664 
665  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
666  *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
667  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
668  *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
670  {
671  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
672  }
673  else
674  {
675  // Parallel vtu files .vtu -> .pvtu
676  *(this->mpVtkMetaFile) << ".pvtu\"/>\n";
677  }
678 #endif //CHASTE_VTK
679 }
680 
681 template<unsigned DIM>
682 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
683 {
684  assert(pNewCell);
685 
686  // Add new cell to cell population
687  CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
688  assert(p_created_cell == pNewCell);
689 
690  // Then set the new cell radius in the NodesOnlyMesh
691  unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
692  Node<DIM>* p_parent_node = this->GetNode(parent_node_index);
693 
694  unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
695  Node<DIM>* p_new_node = this->GetNode(new_node_index);
696 
697  p_new_node->SetRadius(p_parent_node->GetRadius());
698 
699  // Return pointer to new cell
700  return p_created_cell;
701 }
702 
703 template<unsigned DIM>
704 void NodeBasedCellPopulation<DIM>::AddMovedCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
705 {
706  // Create a new node
707  mpNodesOnlyMesh->AddMovedNode(pNode);
708 
709  // Update cells vector
710  this->mCells.push_back(pCell);
711 
712  // Update mappings between cells and location indices
713  this->AddCellUsingLocationIndex(pNode->GetIndex(), pCell);
714 }
715 
716 template<unsigned DIM>
718 {
719  mpNodesOnlyMesh->DeleteMovedNode(index);
720 
721  // Update vector of cells
722  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
723  cell_iter != this->mCells.end();
724  ++cell_iter)
725  {
726  if (this->GetLocationIndexUsingCell(*cell_iter) == index)
727  {
728  // Update mappings between cells and location indices
729  this->RemoveCellUsingLocationIndex(index, (*cell_iter));
730  cell_iter = this->mCells.erase(cell_iter);
731 
732  break;
733  }
734  }
735 }
736 
743 struct null_deleter
744 {
748  void operator()(void const *) const
749  {
750  }
751 };
752 
753 template<unsigned DIM>
755 {
756 #if BOOST_VERSION < 103700
757  EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
758 #else // BOOST_VERSION >= 103700
759  MPI_Status status;
760 
761  if (!PetscTools::AmTopMost())
762  {
763  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
764  mpCellsRecvRight = mRightCommunicator.SendRecvObject(p_cells_right, PetscTools::GetMyRank() + 1, mCellCommunicationTag, PetscTools::GetMyRank() + 1, mCellCommunicationTag, status);
765  }
766  if (!PetscTools::AmMaster())
767  {
768  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
769  mpCellsRecvLeft = mLeftCommunicator.SendRecvObject(p_cells_left, PetscTools::GetMyRank() - 1, mCellCommunicationTag, PetscTools::GetMyRank() - 1, mCellCommunicationTag, status);
770  }
771 #endif
772 }
773 
774 template<unsigned DIM>
776 {
777 #if BOOST_VERSION < 103700
778  EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
779 #else // BOOST_VERSION >= 103700
780 
781  if (!PetscTools::AmTopMost())
782  {
783  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
784  int tag = SmallPow(2u, 1+ PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() + 1);
785  mRightCommunicator.ISendObject(p_cells_right, PetscTools::GetMyRank() + 1, tag);
786  }
787  if (!PetscTools::AmMaster())
788  {
789  int tag = SmallPow (2u, 1 + PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() - 1);
790  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
791  mLeftCommunicator.ISendObject(p_cells_left, PetscTools::GetMyRank() - 1, tag);
792  }
793  // Now post receives to start receiving data before returning.
794  if (!PetscTools::AmTopMost())
795  {
796  int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() + 1);
797  mRightCommunicator.IRecvObject(PetscTools::GetMyRank() + 1, tag);
798  }
799  if (!PetscTools::AmMaster())
800  {
801  int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() - 1);
802  mLeftCommunicator.IRecvObject(PetscTools::GetMyRank() - 1, tag);
803  }
804 #endif
805 }
806 
807 template<unsigned DIM>
809 {
810 #if BOOST_VERSION < 103700
811  EXCEPTION("Parallel cell-based Chaste requires Boost >= 1.37");
812 #else // BOOST_VERSION >= 103700
813 
814  if (!PetscTools::AmTopMost())
815  {
816  mpCellsRecvRight = mRightCommunicator.GetRecvObject();
817  }
818  if (!PetscTools::AmMaster())
819  {
820  mpCellsRecvLeft = mLeftCommunicator.GetRecvObject();
821  }
822 #endif
823 }
824 template<unsigned DIM>
825 std::pair<CellPtr, Node<DIM>* > NodeBasedCellPopulation<DIM>::GetCellNodePair(unsigned nodeIndex)
826 {
827  Node<DIM>* p_node = this->GetNode(nodeIndex);
828 
829  CellPtr p_cell = this->GetCellUsingLocationIndex(nodeIndex);
830 
831  std::pair<CellPtr, Node<DIM>* > new_pair(p_cell, p_node);
832 
833  return new_pair;
834 }
835 
836 template<unsigned DIM>
838 {
839  std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
840 
841  mCellsToSendRight.push_back(pair);
842 }
843 
844 template<unsigned DIM>
846 {
847  std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
848 
849  mCellsToSendLeft.push_back(pair);
850 }
851 
852 template<unsigned DIM>
854 {
855  if (!PetscTools::AmMaster())
856  {
857  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
858  iter != mpCellsRecvLeft->end();
859  ++iter)
860  {
861  // Make a shared pointer to the node to make sure it is correctly deleted.
862  boost::shared_ptr<Node<DIM> > p_node(iter->second);
863  AddMovedCell(iter->first, p_node);
864  }
865  }
866  if (!PetscTools::AmTopMost())
867  {
868  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
869  iter != mpCellsRecvRight->end();
870  ++iter)
871  {
872  boost::shared_ptr<Node<DIM> > p_node(iter->second);
873  AddMovedCell(iter->first, p_node);
874  }
875  }
876 }
877 
878 template<unsigned DIM>
880 {
881  mpNodesOnlyMesh->ResizeBoxCollection();
882 
883  mpNodesOnlyMesh->CalculateNodesOutsideLocalDomain();
884 
885  std::vector<unsigned> nodes_to_send_right = mpNodesOnlyMesh->rGetNodesToSendRight();
886  AddCellsToSendRight(nodes_to_send_right);
887 
888  std::vector<unsigned> nodes_to_send_left = mpNodesOnlyMesh->rGetNodesToSendLeft();
889  AddCellsToSendLeft(nodes_to_send_left);
890 
891  // Post non-blocking send / receives so communication on both sides can start.
892  SendCellsToNeighbourProcesses();
893 
894  // Post blocking receive calls that wait until communication complete.
895  //GetReceivedCells();
896 
897  for (std::vector<unsigned>::iterator iter = nodes_to_send_right.begin();
898  iter != nodes_to_send_right.end();
899  ++iter)
900  {
901  DeleteMovedCell(*iter);
902  }
903 
904  for (std::vector<unsigned>::iterator iter = nodes_to_send_left.begin();
905  iter != nodes_to_send_left.end();
906  ++iter)
907  {
908  DeleteMovedCell(*iter);
909  }
910 
911  AddReceivedCells();
912 
913  NodeMap map(1 + mpNodesOnlyMesh->GetMaximumNodeIndex());
914  mpNodesOnlyMesh->ReMesh(map);
915  UpdateMapsAfterRemesh(map);
916 }
917 
918 template<unsigned DIM>
920 {
921  mpNodesOnlyMesh->ClearHaloNodes();
922 
923  mHaloCells.clear();
924  mHaloCellLocationMap.clear();
925  mLocationHaloCellMap.clear();
926 
927  std::vector<unsigned> halos_to_send_right = mpNodesOnlyMesh->rGetHaloNodesToSendRight();
928  AddCellsToSendRight(halos_to_send_right);
929 
930  std::vector<unsigned> halos_to_send_left = mpNodesOnlyMesh->rGetHaloNodesToSendLeft();
931  AddCellsToSendLeft(halos_to_send_left);
932 
933  NonBlockingSendCellsToNeighbourProcesses();
934 }
935 
936 template<unsigned DIM>
937 void NodeBasedCellPopulation<DIM>::AddCellsToSendRight(std::vector<unsigned>& cellLocationIndices)
938 {
939  mCellsToSendRight.clear();
940 
941  for (unsigned i=0; i < cellLocationIndices.size(); i++)
942  {
943  AddNodeAndCellToSendRight(cellLocationIndices[i]);
944  }
945 }
946 
947 template<unsigned DIM>
948 void NodeBasedCellPopulation<DIM>::AddCellsToSendLeft(std::vector<unsigned>& cellLocationIndices)
949 {
950  mCellsToSendLeft.clear();
951 
952  for (unsigned i=0; i < cellLocationIndices.size(); i++)
953  {
954  AddNodeAndCellToSendLeft(cellLocationIndices[i]);
955  }
956 }
957 
958 template<unsigned DIM>
960 {
961  GetReceivedCells();
962 
963  if (!PetscTools::AmMaster())
964  {
965  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
966  iter != mpCellsRecvLeft->end();
967  ++iter)
968  {
969  boost::shared_ptr<Node<DIM> > p_node(iter->second);
970  AddHaloCell(iter->first, p_node);
971 
972  }
973  }
974  if (!PetscTools::AmTopMost())
975  {
976  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
977  iter != mpCellsRecvRight->end();
978  ++iter)
979  {
980  boost::shared_ptr<Node<DIM> > p_node(iter->second);
981  AddHaloCell(iter->first, p_node);
982  }
983  }
984 
985  mpNodesOnlyMesh->AddHaloNodesToBoxes();
986 }
987 
988 template<unsigned DIM>
989 void NodeBasedCellPopulation<DIM>::AddHaloCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
990 {
991  mHaloCells.push_back(pCell);
992 
993  mpNodesOnlyMesh->AddHaloNode(pNode);
994 
995  mHaloCellLocationMap[pCell] = pNode->GetIndex();
996 
997  mLocationHaloCellMap[pNode->GetIndex()] = pCell;
998 }
999 
1000 // Explicit instantiation
1001 template class NodeBasedCellPopulation<1>;
1002 template class NodeBasedCellPopulation<2>;
1003 template class NodeBasedCellPopulation<3>;
1004 
1005 // Serialization for Boost >= 1.36
void AddCellsToSendRight(std::vector< unsigned > &cellLocationIndices)
void OutputCellPopulationParameters(out_stream &rParamsFile)
std::set< unsigned > GetNodesWithinNeighbourhoodRadius(unsigned index, double neighbourhoodRadius)
NodesOnlyMesh< DIM > & rGetMesh()
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)
Definition: Node.hpp:58
static void Barrier(const std::string callerId="")
Definition: PetscTools.cpp:134
double SmallPow(double x, unsigned exponent)
c_vector< double, DIM > GetSizeOfCellPopulation()
void SetRadius(double radius)
Definition: Node.cpp:257
#define EXCEPTION(message)
Definition: Exception.hpp:143
Node< DIM > * GetNode(unsigned index)
void AddCellsToSendLeft(std::vector< unsigned > &cellLocationIndices)
static SimulationTime * Instance()
void SetParallelFiles(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
static bool AmMaster()
Definition: PetscTools.cpp:120
void SetNode(unsigned nodeIndex, ChastePoint< DIM > &rNewLocation)
void SetUseVariableRadii(bool useVariableRadii=true)
static MPI_Comm GetWorld()
Definition: PetscTools.cpp:174
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)
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()
static bool IsSequential()
Definition: PetscTools.cpp:91
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
void UpdateMapsAfterRemesh(NodeMap &map)
void SetLoadBalanceMesh(bool loadBalanceMesh)
bool IsIdentityMap()
Definition: NodeMap.cpp:99
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
Definition: Node.cpp:140
bool IsDeleted(unsigned index)
Definition: NodeMap.cpp:81
unsigned GetNewIndex(unsigned oldIndex) const
Definition: NodeMap.cpp:86
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())
static bool AmTopMost()
Definition: PetscTools.cpp:126
static unsigned GetMyRank()
Definition: PetscTools.cpp:114
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)
double GetRadius()
Definition: Node.cpp:249
void AddNodeAndCellToSendRight(unsigned nodeIndex)
virtual void UpdateParticlesAfterReMesh(NodeMap &rMap)
virtual CellPtr AddCell(CellPtr pNewCell, const c_vector< double, DIM > &rCellDivisionVector, CellPtr pParentCell)