Chaste  Release::2017.1
NodeBasedCellPopulation.cpp
1 /*
2 
3 Copyright (c) 2005-2017, 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 template<unsigned DIM>
42  std::vector<CellPtr>& rCells,
43  const std::vector<unsigned> locationIndices,
44  bool deleteMesh,
45  bool validate)
46  : AbstractCentreBasedCellPopulation<DIM>(rMesh, rCells, locationIndices),
47  mDeleteMesh(deleteMesh),
48  mUseVariableRadii(false),
49  mLoadBalanceMesh(false),
50  mLoadBalanceFrequency(100)
51 {
52  mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
53 
54  if (validate)
55  {
56  Validate();
57  }
58 }
59 
60 template<unsigned DIM>
63  mDeleteMesh(true),
64  mUseVariableRadii(false), // will be set by serialize() method
65  mLoadBalanceMesh(false),
67 {
68  mpNodesOnlyMesh = static_cast<NodesOnlyMesh<DIM>* >(&(this->mrMesh));
69 }
70 
71 template<unsigned DIM>
73 {
74  Clear();
75  if (mDeleteMesh)
76  {
77  delete &this->mrMesh;
78  }
79 }
80 
81 template<unsigned DIM>
83 {
84  return *mpNodesOnlyMesh;
85 }
86 
87 template<unsigned DIM>
89 {
90  return *mpNodesOnlyMesh;
91 }
92 
93 template<unsigned DIM>
95 {
96  // Note that this code does not yet work in parallel.
97  assert(PetscTools::IsSequential());
98 
99  std::vector<Node<DIM>*> temp_nodes;
100 
101  // Get the nodes of mpNodesOnlyMesh
103  node_iter != mpNodesOnlyMesh->GetNodeIteratorEnd();
104  ++node_iter)
105  {
106  temp_nodes.push_back(new Node<DIM>(node_iter->GetIndex(), node_iter->rGetLocation(), node_iter->IsBoundaryNode()));
107  }
108 
109  return new MutableMesh<DIM,DIM>(temp_nodes);
110 }
111 
112 template<unsigned DIM>
114 {
115  mNodePairs.clear();
116 }
117 
118 template<unsigned DIM>
120 {
121  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
122  node_iter != this->mrMesh.GetNodeIteratorEnd();
123  ++node_iter)
124  {
125  try
126  {
127  this->GetCellUsingLocationIndex(node_iter->GetIndex());
128  }
129  catch (Exception&)
130  {
131  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Node " << node_iter->GetIndex() << " does not appear to have a cell associated with it");
132  }
133  }
134 }
135 
136 template<unsigned DIM>
138 {
139  return mpNodesOnlyMesh->GetNodeOrHaloNode(index);
140 }
141 
142 template<unsigned DIM>
143 void NodeBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
144 {
145  mpNodesOnlyMesh->SetNode(nodeIndex, rNewLocation, false);
146 }
147 
148 template<unsigned DIM>
149 void NodeBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
150 {
152 
154 
155  if (mLoadBalanceMesh)
156  {
157  if ((SimulationTime::Instance()->GetTimeStepsElapsed() % mLoadBalanceFrequency) == 0)
158  {
160 
162 
164  }
165  }
166 
168 
170 
172 
174 
175  /*
176  * Update cell radii based on CellData
177  */
178  if (mUseVariableRadii)
179  {
180  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
181  cell_iter != this->End();
182  ++cell_iter)
183  {
184  double cell_radius = cell_iter->GetCellData()->GetItem("Radius");
185  unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
186  this->GetNode(node_index)->SetRadius(cell_radius);
187  }
188  }
189 
190  // Make sure that everyone exits update together so that all asynchronous communications are complete.
191  PetscTools::Barrier("Update");
192 }
193 
194 template<unsigned DIM>
196 {
197  if (!map.IsIdentityMap())
198  {
200 
201  // Update the mappings between cells and location indices
203  std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
204 
205  // Remove any dead pointers from the maps (needed to avoid archiving errors)
206  this->mLocationCellMap.clear();
207  this->mCellLocationMap.clear();
208 
209  for (std::list<CellPtr>::iterator it = this->mCells.begin();
210  it != this->mCells.end();
211  ++it)
212  {
213  unsigned old_node_index = old_map[(*it).get()];
214 
215  // This shouldn't ever happen, as the cell vector only contains living cells
216  assert(!map.IsDeleted(old_node_index));
217 
218  unsigned new_node_index = map.GetNewIndex(old_node_index);
219  this->SetCellUsingLocationIndex(new_node_index,*it);
220  }
221 
222  this->Validate();
223  }
224 }
225 
226 template<unsigned DIM>
228 {
229  unsigned num_removed = 0;
230  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
231  cell_iter != this->mCells.end();
232  )
233  {
234  if ((*cell_iter)->IsDead())
235  {
236  // Remove the node from the mesh
237  num_removed++;
238  unsigned location_index = mpNodesOnlyMesh->SolveNodeMapping(this->GetLocationIndexUsingCell((*cell_iter)));
239  mpNodesOnlyMesh->DeleteNodePriorToReMesh(location_index);
240 
241  // Update mappings between cells and location indices
242  unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*cell_iter));
243  this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*cell_iter));
244 
245  // Update vector of cells
246  cell_iter = this->mCells.erase(cell_iter);
247  }
248  else
249  {
250  ++cell_iter;
251  }
252  }
253 
254  return num_removed;
255 }
256 
257 template<unsigned DIM>
259 {
260  return mpNodesOnlyMesh->AddNode(pNewNode);
261 }
262 
263 template<unsigned DIM>
265 {
266  return mpNodesOnlyMesh->GetNumNodes();
267 }
268 
269 template<unsigned DIM>
271 {
272  std::map<unsigned, CellPtr>::iterator iter = mLocationHaloCellMap.find(index);
273  if (iter != mLocationHaloCellMap.end())
274  {
275  return iter->second;
276  }
277  else
278  {
280  }
281 }
282 
283 template<unsigned DIM>
285 {
286 }
287 
288 template<unsigned DIM>
289 std::vector< std::pair<Node<DIM>*, Node<DIM>* > >& NodeBasedCellPopulation<DIM>::rGetNodePairs()
290 {
291  return mNodePairs;
292 }
293 
294 template<unsigned DIM>
296 {
297  *rParamsFile << "\t\t<MechanicsCutOffLength>" << mpNodesOnlyMesh->GetMaximumInteractionDistance() << "</MechanicsCutOffLength>\n";
298  *rParamsFile << "\t\t<UseVariableRadii>" << mUseVariableRadii << "</UseVariableRadii>\n";
299 
300  // Call method on direct parent class
302 }
303 
304 template<unsigned DIM>
306 {
307  pPopulationWriter->Visit(this);
308 }
309 
310 template<unsigned DIM>
312 {
313  pPopulationCountWriter->Visit(this);
314 }
315 
316 template<unsigned DIM>
317 void NodeBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
318 {
319  pCellWriter->VisitCell(pCell, this);
320 }
321 
322 template<unsigned DIM>
324 {
326 }
327 
328 template<unsigned DIM>
330 {
331  return mUseVariableRadii;
332 }
333 
334 template<unsigned DIM>
336 {
337  mUseVariableRadii = useVariableRadii;
338 }
339 
340 template<unsigned DIM>
342 {
343  mLoadBalanceMesh = loadBalanceMesh;
344 }
345 
346 template<unsigned DIM>
347 void NodeBasedCellPopulation<DIM>::SetLoadBalanceFrequency(unsigned loadBalanceFrequency)
348 {
349  mLoadBalanceFrequency = loadBalanceFrequency;
350 }
351 
352 template<unsigned DIM>
353 double NodeBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
354 {
355  return mpNodesOnlyMesh->GetWidth(rDimension);
356 }
357 
358 template<unsigned DIM>
360 {
361  c_vector<double, DIM> local_size = AbstractCellPopulation<DIM, DIM>::GetSizeOfCellPopulation();
362  c_vector<double, DIM> global_size;
363 
364  for (unsigned i=0; i<DIM; i++)
365  {
366  MPI_Allreduce(&local_size[i], &global_size[i], 1, MPI_DOUBLE, MPI_MAX, PetscTools::GetWorld());
367  }
368 
369  return global_size;
370 }
371 
372 template<unsigned DIM>
373 std::set<unsigned> NodeBasedCellPopulation<DIM>::GetNodesWithinNeighbourhoodRadius(unsigned index, double neighbourhoodRadius)
374 {
375  // Check neighbourhoodRadius is less than the interaction radius. If not you wont return all the correct nodes
376  if (neighbourhoodRadius > mpNodesOnlyMesh->GetMaximumInteractionDistance())
377  {
378  EXCEPTION("neighbourhoodRadius should be less than or equal to the the maximum interaction radius defined on the NodesOnlyMesh");
379  }
380 
381  std::set<unsigned> neighbouring_node_indices;
382 
383  // Get location
384  Node<DIM>* p_node_i = this->GetNode(index);
385  const c_vector<double, DIM>& r_node_i_location = p_node_i->rGetLocation();
386 
387  // Check the mNodeNeighbours has been set up correctly
388  if (!(p_node_i->GetNeighboursSetUp()))
389  {
390  EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNodesWithinNeighbourhoodRadius()");
391  }
392 
393  // Get set of 'candidate' neighbours.
394  std::vector<unsigned>& near_nodes = p_node_i->rGetNeighbours();
395 
396  // Find which ones are actually close
397  for (std::vector<unsigned>::iterator iter = near_nodes.begin();
398  iter != near_nodes.end();
399  ++iter)
400  {
401  // Be sure not to return the index itself.
402  if ((*iter) != index)
403  {
404  Node<DIM>* p_node_j = this->GetNode((*iter));
405 
406  // Get the location of this node
407  const c_vector<double, DIM>& r_node_j_location = p_node_j->rGetLocation();
408 
409  // Get the vector the two nodes (using GetVectorFromAtoB to catch periodicities etc.)
410  c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(r_node_j_location, r_node_i_location);
411 
412  // Calculate the distance between the two nodes
413  double distance_between_nodes = norm_2(node_to_node_vector);
414 
415  // If the cell j is within the neighbourhood of radius neighbourhoodRadius
416  // of cell i
417  if (distance_between_nodes <= neighbourhoodRadius)// + DBL_EPSILSON)
418  {
419  // ...then add this node index to the set of neighbouring node indices
420  neighbouring_node_indices.insert((*iter));
421  }
422  }
423  }
424 
425  return neighbouring_node_indices;
426 }
427 
428 template<unsigned DIM>
430 {
431  std::set<unsigned> neighbouring_node_indices;
432 
433  // Get location and radius of node
434  Node<DIM>* p_node_i = this->GetNode(index);
435  const c_vector<double, DIM>& r_node_i_location = p_node_i->rGetLocation();
436  double radius_of_cell_i = p_node_i->GetRadius();
437 
438  // Check the mNodeNeighbours has been set up correctly
439  if (!(p_node_i->GetNeighboursSetUp()))
440  {
441  EXCEPTION("mNodeNeighbours not set up. Call Update() before GetNeighbouringNodeIndices()");
442  }
443 
444  // Make sure that the max_interaction distance is smaller than or equal to the box collection size
445  if (!(radius_of_cell_i * 2.0 <= mpNodesOnlyMesh->GetMaximumInteractionDistance()))
446  {
447  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.");
448  }
449 
450  // Get set of 'candidate' neighbours
451  std::vector<unsigned>& near_nodes = p_node_i->rGetNeighbours();
452 
453  // Find which ones are actually close
454  for (std::vector<unsigned>::iterator iter = near_nodes.begin();
455  iter != near_nodes.end();
456  ++iter)
457  {
458  // Be sure not to return the index itself
459  if ((*iter) != index)
460  {
461  Node<DIM>* p_node_j = this->GetNode((*iter));
462 
463  // Get the location of this node
464  const c_vector<double, DIM>& r_node_j_location = p_node_j->rGetLocation();
465 
466  // Get the vector the two nodes (using GetVectorFromAtoB to catch periodicities etc.)
467  c_vector<double, DIM> node_to_node_vector = mpNodesOnlyMesh->GetVectorFromAtoB(r_node_j_location, r_node_i_location);
468 
469  // Calculate the distance between the two nodes
470  double distance_between_nodes = norm_2(node_to_node_vector);
471 
472  // Get the radius of the cell corresponding to this node
473  double radius_of_cell_j = p_node_j->GetRadius();
474 
475  // If the cells are close enough to exert a force on each other...
476  double max_interaction_distance = radius_of_cell_i + radius_of_cell_j;
477 
478  // Make sure that the max_interaction distance is smaller than or equal to the box collection size
479  if (!(max_interaction_distance <= mpNodesOnlyMesh->GetMaximumInteractionDistance()))
480  {
481  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.");
482  }
483  if (distance_between_nodes <= max_interaction_distance)// + DBL_EPSILSON) //Assumes that max_interaction_distance is of order 1
484  {
485  // ...then add this node index to the set of neighbouring node indices
486  neighbouring_node_indices.insert((*iter));
487  }
488  }
489  }
490 
491  return neighbouring_node_indices;
492 }
493 
494 template<unsigned DIM>
496 {
497  // Not implemented or tested in 1D
498  assert(DIM==2 ||DIM==3); // LCOV_EXCL_LINE
499 
500  // Get node index corresponding to this cell
501  unsigned node_index = this->GetLocationIndexUsingCell(pCell);
502  Node<DIM>* p_node = this->GetNode(node_index);
503 
504  // Get cell radius
505  double cell_radius = p_node->GetRadius();
506 
507  // Begin code to approximate cell volume
508  double averaged_cell_radius = 0.0;
509  unsigned num_cells = 0;
510 
511  // Get the location of this node
512  const c_vector<double, DIM>& r_node_i_location = GetNode(node_index)->rGetLocation();
513 
514  // Get the set of node indices corresponding to this cell's neighbours
515  std::set<unsigned> neighbouring_node_indices = GetNeighbouringNodeIndices(node_index);
516 
517  // THe number of neighbours in equilibrium configuration, from sphere packing problem
518  unsigned num_neighbours_equil;
519  if (DIM==2)
520  {
521  num_neighbours_equil = 6;
522  }
523  else
524  {
525  assert(DIM==3);
526  num_neighbours_equil = 12;
527  }
528 
529  // Loop over this set
530  for (std::set<unsigned>::iterator iter = neighbouring_node_indices.begin();
531  iter != neighbouring_node_indices.end();
532  ++iter)
533  {
534  Node<DIM>* p_node_j = this->GetNode(*iter);
535 
536  // Get the location of the neighbouring node
537  const c_vector<double, DIM>& r_node_j_location = p_node_j->rGetLocation();
538 
539  double neighbouring_cell_radius = p_node_j->GetRadius();
540 
541  // If this throws then you may not be considering all cell interactions use a larger cut off length
542  assert(cell_radius+neighbouring_cell_radius<mpNodesOnlyMesh->GetMaximumInteractionDistance());
543 
544  // Calculate the distance between the two nodes and add to cell radius
545  double separation = norm_2(mpNodesOnlyMesh->GetVectorFromAtoB(r_node_j_location, r_node_i_location));
546 
547  if (separation < cell_radius+neighbouring_cell_radius)
548  {
549  // The effective radius is the mid point of the overlap
550  averaged_cell_radius = averaged_cell_radius + cell_radius - (cell_radius+neighbouring_cell_radius-separation)/2.0;
551  num_cells++;
552  }
553  }
554  if (num_cells < num_neighbours_equil)
555  {
556  averaged_cell_radius += (num_neighbours_equil-num_cells)*cell_radius;
557 
558  averaged_cell_radius /= num_neighbours_equil;
559  }
560  else
561  {
562  averaged_cell_radius /= num_cells;
563  }
564  assert(averaged_cell_radius < mpNodesOnlyMesh->GetMaximumInteractionDistance()/2.0);
565 
566  cell_radius = averaged_cell_radius;
567 
568  // End code to approximate cell volume
569 
570  // Calculate cell volume from radius of cell
571  double cell_volume = 0.0;
572  if (DIM == 2)
573  {
574  cell_volume = M_PI*cell_radius*cell_radius;
575  }
576  else if (DIM == 3)
577  {
578  cell_volume = (4.0/3.0)*M_PI*cell_radius*cell_radius*cell_radius;
579  }
580 
581  return cell_volume;
582 }
583 
584 template<unsigned DIM>
585 void NodeBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
586 {
587 #ifdef CHASTE_VTK
588  // Store the present time as a string
589  std::stringstream time;
591 
592  // Make sure the nodes are ordered contiguously in memory
593  NodeMap map(1 + this->mpNodesOnlyMesh->GetMaximumNodeIndex());
594  this->mpNodesOnlyMesh->ReMesh(map);
595 
596  // Create mesh writer for VTK output
597  VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
598  mesh_writer.SetParallelFiles(*mpNodesOnlyMesh);
599 
600  auto num_nodes = GetNumNodes();
601 
602  // For each cell that this process owns, find the corresponding node index, which we only want to calculate once
603  std::vector<unsigned> node_indices_in_cell_order;
604  for (auto cell_iter = this->Begin(); cell_iter != this->End(); ++cell_iter)
605  {
606  // Get the node index corresponding to this cell
607  unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
608  unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
609 
610  node_indices_in_cell_order.emplace_back(node_index);
611  }
612 
613  // Iterate over any cell writers that are present. This is in a separate loop to below, because the writer loop
614  // needs to the the outer loop.
615  for (auto&& p_cell_writer : this->mCellWriters)
616  {
617  // Add any scalar data
618  if (p_cell_writer->GetOutputScalarData())
619  {
620  std::vector<double> vtk_cell_data(num_nodes);
621 
622  unsigned loop_it = 0;
623  for (auto cell_iter = this->Begin(); cell_iter != this->End(); ++cell_iter, ++loop_it)
624  {
625  unsigned node_idx = node_indices_in_cell_order[loop_it];
626  vtk_cell_data[node_idx] = p_cell_writer->GetCellDataForVtkOutput(*cell_iter, this);
627  }
628 
629  mesh_writer.AddPointData(p_cell_writer->GetVtkCellDataName(), vtk_cell_data);
630  }
631 
632  // Add any vector data
633  if (p_cell_writer->GetOutputVectorData())
634  {
635  std::vector<c_vector<double, DIM>> vtk_cell_data(num_nodes);
636 
637  unsigned loop_it = 0;
638  for (auto cell_iter = this->Begin(); cell_iter != this->End(); ++cell_iter, ++loop_it)
639  {
640  unsigned node_idx = node_indices_in_cell_order[loop_it];
641  vtk_cell_data[node_idx] = p_cell_writer->GetVectorCellDataForVtkOutput(*cell_iter, this);
642  }
643 
644  mesh_writer.AddPointData(p_cell_writer->GetVtkVectorCellDataName(), vtk_cell_data);
645  }
646  }
647 
648  // Process rank and cell data can be collected on a cell-by-cell basis, and both occur in the following loop
649  // We assume the first cell is representative of all cells
650  if (this->Begin() != this->End()) // some processes may own no cells, so can't do this->Begin()->GetCellData()
651  {
652  auto num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
653  std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
654  std::vector<std::vector<double>> cell_data(num_cell_data_items, std::vector<double>(num_nodes));
655 
656  std::vector<double> rank(num_nodes);
657 
658  unsigned loop_it = 0;
659  for (auto cell_iter = this->Begin(); cell_iter != this->End(); ++cell_iter, ++loop_it)
660  {
661  unsigned node_idx = node_indices_in_cell_order[loop_it];
662 
663  for (unsigned cell_data_idx = 0; cell_data_idx < num_cell_data_items; ++cell_data_idx)
664  {
665  cell_data[cell_data_idx][node_idx] = cell_iter->GetCellData()->GetItem(cell_data_names[cell_data_idx]);
666  }
667 
668  rank[node_idx] = (PetscTools::GetMyRank());
669  }
670 
671  // Add point data to writers
672  mesh_writer.AddPointData("Process rank", rank);
673  for (unsigned cell_data_idx = 0; cell_data_idx < num_cell_data_items; ++cell_data_idx)
674  {
675  mesh_writer.AddPointData(cell_data_names[cell_data_idx], cell_data[cell_data_idx]);
676  }
677  }
678 
679  mesh_writer.WriteFilesUsingMesh(*mpNodesOnlyMesh);
680 
681  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
683  *(this->mpVtkMetaFile) << R"(" group="" part="0" file="results_)";
686  {
687  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
688  }
689  else
690  {
691  // Parallel vtu files .vtu -> .pvtu
692  *(this->mpVtkMetaFile) << ".pvtu\"/>\n";
693  }
694 #endif //CHASTE_VTK
695 }
696 
697 template<unsigned DIM>
698 CellPtr NodeBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, CellPtr pParentCell)
699 {
700  assert(pNewCell);
701 
702  // Add new cell to population
703  CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, pParentCell);
704  assert(p_created_cell == pNewCell);
705 
706  // Then set the new cell radius in the NodesOnlyMesh
707  unsigned parent_node_index = this->GetLocationIndexUsingCell(pParentCell);
708  Node<DIM>* p_parent_node = this->GetNode(parent_node_index);
709 
710  unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
711  Node<DIM>* p_new_node = this->GetNode(new_node_index);
712 
713  p_new_node->SetRadius(p_parent_node->GetRadius());
714 
715  // Return pointer to new cell
716  return p_created_cell;
717 }
718 
719 template<unsigned DIM>
720 void NodeBasedCellPopulation<DIM>::AddMovedCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
721 {
722  // Create a new node
724 
725  // Update cells vector
726  this->mCells.push_back(pCell);
727 
728  // Update mappings between cells and location indices
729  this->AddCellUsingLocationIndex(pNode->GetIndex(), pCell);
730 }
731 
732 template<unsigned DIM>
734 {
736 
737  // Update vector of cells
738  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
739  cell_iter != this->mCells.end();
740  ++cell_iter)
741  {
742  if (this->GetLocationIndexUsingCell(*cell_iter) == index)
743  {
744  // Update mappings between cells and location indices
745  this->RemoveCellUsingLocationIndex(index, (*cell_iter));
746  cell_iter = this->mCells.erase(cell_iter);
747 
748  break;
749  }
750  }
751 }
752 
753 template<unsigned DIM>
755 {
756  MPI_Status status;
757 
758  if (!PetscTools::AmTopMost())
759  {
760  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
762  }
763  if (!PetscTools::AmMaster())
764  {
765  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
767  }
768 }
769 
770 template<unsigned DIM>
772 {
773  if (!PetscTools::AmTopMost())
774  {
775  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_right(&mCellsToSendRight, null_deleter());
776  int tag = SmallPow(2u, 1+ PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() + 1);
777  mRightCommunicator.ISendObject(p_cells_right, PetscTools::GetMyRank() + 1, tag);
778  }
779  if (!PetscTools::AmMaster())
780  {
781  int tag = SmallPow (2u, 1 + PetscTools::GetMyRank() ) * SmallPow (3u, 1 + PetscTools::GetMyRank() - 1);
782  boost::shared_ptr<std::vector<std::pair<CellPtr, Node<DIM>* > > > p_cells_left(&mCellsToSendLeft, null_deleter());
783  mLeftCommunicator.ISendObject(p_cells_left, PetscTools::GetMyRank() - 1, tag);
784  }
785  // Now post receives to start receiving data before returning.
786  if (!PetscTools::AmTopMost())
787  {
788  int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() + 1);
790  }
791  if (!PetscTools::AmMaster())
792  {
793  int tag = SmallPow (3u, 1 + PetscTools::GetMyRank() ) * SmallPow (2u, 1+ PetscTools::GetMyRank() - 1);
795  }
796 }
797 
798 template<unsigned DIM>
800 {
801  if (!PetscTools::AmTopMost())
802  {
804  }
805  if (!PetscTools::AmMaster())
806  {
808  }
809 }
810 
811 template<unsigned DIM>
812 std::pair<CellPtr, Node<DIM>* > NodeBasedCellPopulation<DIM>::GetCellNodePair(unsigned nodeIndex)
813 {
814  Node<DIM>* p_node = this->GetNode(nodeIndex);
815 
816  CellPtr p_cell = this->GetCellUsingLocationIndex(nodeIndex);
817 
818  std::pair<CellPtr, Node<DIM>* > new_pair(p_cell, p_node);
819 
820  return new_pair;
821 }
822 
823 template<unsigned DIM>
825 {
826  std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
827 
828  mCellsToSendRight.push_back(pair);
829 }
830 
831 template<unsigned DIM>
833 {
834  std::pair<CellPtr, Node<DIM>* > pair = GetCellNodePair(nodeIndex);
835 
836  mCellsToSendLeft.push_back(pair);
837 }
838 
839 template<unsigned DIM>
841 {
842  if (!PetscTools::AmMaster())
843  {
844  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
845  iter != mpCellsRecvLeft->end();
846  ++iter)
847  {
848  // Make a shared pointer to the node to make sure it is correctly deleted.
849  boost::shared_ptr<Node<DIM> > p_node(iter->second);
850  AddMovedCell(iter->first, p_node);
851  }
852  }
853  if (!PetscTools::AmTopMost())
854  {
855  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
856  iter != mpCellsRecvRight->end();
857  ++iter)
858  {
859  boost::shared_ptr<Node<DIM> > p_node(iter->second);
860  AddMovedCell(iter->first, p_node);
861  }
862  }
863 }
864 
865 template<unsigned DIM>
867 {
869 
871 
872  std::vector<unsigned> nodes_to_send_right = mpNodesOnlyMesh->rGetNodesToSendRight();
873  AddCellsToSendRight(nodes_to_send_right);
874 
875  std::vector<unsigned> nodes_to_send_left = mpNodesOnlyMesh->rGetNodesToSendLeft();
876  AddCellsToSendLeft(nodes_to_send_left);
877 
878  // Post non-blocking send / receives so communication on both sides can start.
880 
881  // Post blocking receive calls that wait until communication complete.
882  //GetReceivedCells();
883 
884  for (std::vector<unsigned>::iterator iter = nodes_to_send_right.begin();
885  iter != nodes_to_send_right.end();
886  ++iter)
887  {
888  DeleteMovedCell(*iter);
889  }
890 
891  for (std::vector<unsigned>::iterator iter = nodes_to_send_left.begin();
892  iter != nodes_to_send_left.end();
893  ++iter)
894  {
895  DeleteMovedCell(*iter);
896  }
897 
899 
901  mpNodesOnlyMesh->ReMesh(map);
903 }
904 
905 template<unsigned DIM>
907 {
909 
910  mHaloCells.clear();
911  mHaloCellLocationMap.clear();
912  mLocationHaloCellMap.clear();
913 
914  std::vector<unsigned> halos_to_send_right = mpNodesOnlyMesh->rGetHaloNodesToSendRight();
915  AddCellsToSendRight(halos_to_send_right);
916 
917  std::vector<unsigned> halos_to_send_left = mpNodesOnlyMesh->rGetHaloNodesToSendLeft();
918  AddCellsToSendLeft(halos_to_send_left);
919 
921 }
922 
923 template<unsigned DIM>
924 void NodeBasedCellPopulation<DIM>::AddCellsToSendRight(std::vector<unsigned>& cellLocationIndices)
925 {
926  mCellsToSendRight.clear();
927 
928  for (unsigned i=0; i < cellLocationIndices.size(); i++)
929  {
930  AddNodeAndCellToSendRight(cellLocationIndices[i]);
931  }
932 }
933 
934 template<unsigned DIM>
935 void NodeBasedCellPopulation<DIM>::AddCellsToSendLeft(std::vector<unsigned>& cellLocationIndices)
936 {
937  mCellsToSendLeft.clear();
938 
939  for (unsigned i=0; i < cellLocationIndices.size(); i++)
940  {
941  AddNodeAndCellToSendLeft(cellLocationIndices[i]);
942  }
943 }
944 
945 template<unsigned DIM>
947 {
949 
950  if (!PetscTools::AmMaster())
951  {
952  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvLeft->begin();
953  iter != mpCellsRecvLeft->end();
954  ++iter)
955  {
956  boost::shared_ptr<Node<DIM> > p_node(iter->second);
957  AddHaloCell(iter->first, p_node);
958 
959  }
960  }
961  if (!PetscTools::AmTopMost())
962  {
963  for (typename std::vector<std::pair<CellPtr, Node<DIM>* > >::iterator iter = mpCellsRecvRight->begin();
964  iter != mpCellsRecvRight->end();
965  ++iter)
966  {
967  boost::shared_ptr<Node<DIM> > p_node(iter->second);
968  AddHaloCell(iter->first, p_node);
969  }
970  }
971 
973 }
974 
975 template<unsigned DIM>
976 void NodeBasedCellPopulation<DIM>::AddHaloCell(CellPtr pCell, boost::shared_ptr<Node<DIM> > pNode)
977 {
978  mHaloCells.push_back(pCell);
979 
981 
982  mHaloCellLocationMap[pCell] = pNode->GetIndex();
983 
984  mLocationHaloCellMap[pNode->GetIndex()] = pCell;
985 }
986 
987 // Explicit instantiation
988 template class NodeBasedCellPopulation<1>;
989 template class NodeBasedCellPopulation<2>;
990 template class NodeBasedCellPopulation<3>;
991 
992 // Serialization for Boost >= 1.36
void AddCellsToSendRight(std::vector< unsigned > &cellLocationIndices)
void OutputCellPopulationParameters(out_stream &rParamsFile)
std::set< unsigned > GetNodesWithinNeighbourhoodRadius(unsigned index, double neighbourhoodRadius)
std::vector< unsigned > & rGetNodesToSendLeft()
NodesOnlyMesh< DIM > & rGetMesh()
virtual unsigned GetMaximumNodeIndex()
std::vector< unsigned > & rGetHaloNodesToSendLeft()
void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > point, bool concreteMove=false)
boost::shared_ptr< std::vector< std::pair< CellPtr, Node< DIM > * > > > mpCellsRecvLeft
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
unsigned GetLocationIndexUsingCell(CellPtr pCell)
static void Barrier(const std::string callerId="")
Definition: PetscTools.cpp:134
std::vector< boost::shared_ptr< AbstractCellWriter< ELEMENT_DIM, SPACE_DIM > > > mCellWriters
virtual TetrahedralMesh< DIM, DIM > * GetTetrahedralMeshForPdeModifier()
double SmallPow(double x, unsigned exponent)
c_vector< double, DIM > GetSizeOfCellPopulation()
void LoadBalanceMesh()
void DeleteNodePriorToReMesh(unsigned index)
virtual void RemoveCellUsingLocationIndex(unsigned index, CellPtr pCell)
void SetRadius(double radius)
Definition: Node.cpp:256
boost::shared_ptr< CLASS > SendRecvObject(boost::shared_ptr< CLASS > const pSendObject, unsigned destinationProcess, unsigned sendTag, unsigned sourceProcess, unsigned sourceTag, MPI_Status &status)
#define EXCEPTION(message)
Definition: Exception.hpp:143
Node< DIM > * GetNode(unsigned index)
Node< SPACE_DIM > * GetNodeOrHaloNode(unsigned index) const
void AddCellsToSendLeft(std::vector< unsigned > &cellLocationIndices)
static const unsigned mCellCommunicationTag
static SimulationTime * Instance()
void SetParallelFiles(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
static bool AmMaster()
Definition: PetscTools.cpp:120
std::map< CellPtr, unsigned > mHaloCellLocationMap
ObjectCommunicator< std::vector< std::pair< CellPtr, Node< DIM > * > > > mRightCommunicator
NodeIterator GetNodeIteratorEnd()
void SetNode(unsigned nodeIndex, ChastePoint< DIM > &rNewLocation)
std::vector< std::pair< Node< DIM > *, Node< DIM > * > > mNodePairs
void SetUseVariableRadii(bool useVariableRadii=true)
static MPI_Comm GetWorld()
Definition: PetscTools.cpp:174
ObjectCommunicator< std::vector< std::pair< CellPtr, Node< DIM > * > > > mLeftCommunicator
unsigned GetTimeStepsElapsed() const
void ReMesh(NodeMap &rMap)
std::vector< CellPtr > mHaloCells
boost::shared_ptr< std::vector< std::pair< CellPtr, Node< DIM > * > > > mpCellsRecvRight
void AddMovedCell(CellPtr pCell, boost::shared_ptr< Node< DIM > > pNode)
void IRecvObject(unsigned sourceProcess, unsigned tag)
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 CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell)
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
std::vector< unsigned > & rGetHaloNodesToSendRight()
c_vector< double, SPACE_DIM > GetSizeOfCellPopulation()
static bool IsSequential()
Definition: PetscTools.cpp:91
void AddHaloNodesToBoxes()
std::vector< std::pair< CellPtr, Node< DIM > * > > mCellsToSendRight
void CalculateInteriorNodePairs(std::vector< std::pair< Node< SPACE_DIM > *, Node< SPACE_DIM > * > > &rNodePairs)
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
std::map< unsigned, std::set< CellPtr > > mLocationCellMap
double GetWidth(const unsigned &rDimension) const
void SetCellUsingLocationIndex(unsigned index, CellPtr pCell)
void UpdateMapsAfterRemesh(NodeMap &map)
std::map< Cell *, unsigned > mCellLocationMap
double GetMaximumInteractionDistance()
void DeleteMovedNode(unsigned index)
boost::shared_ptr< CLASS > GetRecvObject()
void SetLoadBalanceMesh(bool loadBalanceMesh)
void ResizeBoxCollection()
bool IsIdentityMap()
Definition: NodeMap.cpp:100
unsigned SolveNodeMapping(unsigned index) const
CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell=CellPtr())
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
virtual void AcceptCellWriter(boost::shared_ptr< AbstractCellWriter< DIM, DIM > > pCellWriter, CellPtr pCell)
void UpdateBoxCollection()
void AddHaloNode(boost::shared_ptr< Node< SPACE_DIM > > pNewNode)
void CalculateNodesOutsideLocalDomain()
void AddHaloCell(CellPtr pCell, boost::shared_ptr< Node< DIM > > pNode)
double GetWidth(const unsigned &rDimension)
std::vector< unsigned > & rGetNeighbours()
Definition: Node.cpp:376
unsigned AddNode(Node< DIM > *pNewNode)
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:139
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
std::vector< unsigned > & rGetNodesToSendRight()
bool IsDeleted(unsigned index)
Definition: NodeMap.cpp:82
unsigned GetNewIndex(unsigned oldIndex) const
Definition: NodeMap.cpp:87
bool GetNeighboursSetUp()
Definition: Node.cpp:368
std::vector< std::pair< Node< DIM > *, Node< DIM > * > > & rGetNodePairs()
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
void ISendObject(boost::shared_ptr< CLASS > const pObject, unsigned destinationProcess, unsigned tag)
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
void CalculateBoundaryNodePairs(std::vector< std::pair< Node< SPACE_DIM > *, Node< SPACE_DIM > * > > &rNodePairs)
NodesOnlyMesh< DIM > * mpNodesOnlyMesh
std::map< unsigned, CellPtr > mLocationHaloCellMap
static bool AmTopMost()
Definition: PetscTools.cpp:126
std::vector< std::pair< CellPtr, Node< DIM > * > > mCellsToSendLeft
static unsigned GetMyRank()
Definition: PetscTools.cpp:114
void AddMovedNode(boost::shared_ptr< Node< SPACE_DIM > > pMovedNode)
void DeleteMovedCell(unsigned index)
void Update(bool hasHadBirthsOrDeaths=true)
virtual void AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
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:248
unsigned GetNumNodes() const
void AddNodeAndCellToSendRight(unsigned nodeIndex)
virtual void UpdateParticlesAfterReMesh(NodeMap &rMap)