Chaste  Release::2024.1
VertexBasedCellPopulation.cpp
1 /*
2 
3 Copyright (c) 2005-2021, 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 "VertexBasedCellPopulation.hpp"
37 #include "Warnings.hpp"
38 #include "ShortAxisVertexBasedDivisionRule.hpp"
39 #include "StepSizeException.hpp"
40 #include "WildTypeCellMutationState.hpp"
41 #include "Cylindrical2dVertexMesh.hpp"
42 #include "SmartPointers.hpp"
43 #include "T2SwapCellKiller.hpp"
44 #include "ApoptoticCellProperty.hpp"
45 #include "CellPopulationElementWriter.hpp"
46 #include "VertexT1SwapLocationsWriter.hpp"
47 #include "VertexT2SwapLocationsWriter.hpp"
48 #include "VertexT3SwapLocationsWriter.hpp"
49 #include "VertexIntersectionSwapLocationsWriter.hpp"
50 #include "AbstractCellBasedSimulation.hpp"
51 
52 template<unsigned DIM>
54  std::vector<CellPtr>& rCells,
55  bool deleteMesh,
56  bool validate,
57  const std::vector<unsigned> locationIndices)
58  : AbstractOffLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices),
59  mDeleteMesh(deleteMesh),
60  mOutputCellRearrangementLocations(true),
61  mRestrictVertexMovement(true)
62 {
63  mpMutableVertexMesh = static_cast<MutableVertexMesh<DIM, DIM>* >(&(this->mrMesh));
65 
66  // If no location indices are specified, associate with elements from the mesh (assumed to be sequentially ordered).
67  std::list<CellPtr>::iterator it = this->mCells.begin();
68  for (unsigned i=0; it != this->mCells.end(); ++it, ++i)
69  {
70  unsigned index = locationIndices.empty() ? i : locationIndices[i]; // assume that the ordering matches
72  }
73 
74  // Check each element has only one cell attached
75  if (validate)
76  {
77  Validate();
78  }
79 }
80 
81 template<unsigned DIM>
84  mDeleteMesh(true),
87 {
88  mpMutableVertexMesh = static_cast<MutableVertexMesh<DIM, DIM>* >(&(this->mrMesh));
89 }
90 
91 template<unsigned DIM>
93 {
94  if (mDeleteMesh)
95  {
96  delete &this->mrMesh;
97  }
98 }
99 
100 template<unsigned DIM>
102 {
103  // Take the average of the cells containing this vertex
104  double average_damping_constant = 0.0;
105 
106  std::set<unsigned> containing_elements = GetNode(nodeIndex)->rGetContainingElementIndices();
107 
108  unsigned num_containing_elements = containing_elements.size();
109  if (num_containing_elements == 0)
110  {
111  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Node " << nodeIndex << " is not contained in any elements, so GetDampingConstant() returns zero");
112  }
113 
114  double temp = 1.0/((double) num_containing_elements);
115  for (std::set<unsigned>::iterator iter = containing_elements.begin();
116  iter != containing_elements.end();
117  ++iter)
118  {
119  CellPtr p_cell = this->GetCellUsingLocationIndex(*iter);
120  bool cell_is_wild_type = p_cell->GetMutationState()->IsType<WildTypeCellMutationState>();
121 
122  if (cell_is_wild_type)
123  {
124  average_damping_constant += this->GetDampingConstantNormal()*temp;
125  }
126  else
127  {
128  average_damping_constant += this->GetDampingConstantMutant()*temp;
129  }
130  }
131 
132  return average_damping_constant;
133 }
134 
135 template<unsigned DIM>
137 {
138  return *mpMutableVertexMesh;
139 }
140 
141 template<unsigned DIM>
143 {
144  return *mpMutableVertexMesh;
145 }
146 
147 template<unsigned DIM>
149 {
150  return mpMutableVertexMesh->GetElement(elementIndex);
151 }
152 
153 template<unsigned DIM>
155 {
156  return this->mrMesh.GetNumNodes();
157 }
158 
159 template<unsigned DIM>
161 {
162  return mpMutableVertexMesh->GetCentroidOfElement(this->mCellLocationMap[pCell.get()]);
163 }
164 
165 template<unsigned DIM>
167 {
168  return this->mrMesh.GetNode(index);
169 }
170 
171 template<unsigned DIM>
173 {
174  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
175  return this->rGetMesh().GetNeighbouringElementIndices(elem_index);
176 }
177 
178 template<unsigned DIM>
180 {
181  return mpMutableVertexMesh->AddNode(pNewNode);
182 }
183 
184 template<unsigned DIM>
185 void VertexBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
186 {
187  mpMutableVertexMesh->SetNode(nodeIndex, rNewLocation);
188 }
189 
190 template<unsigned DIM>
192 {
194 }
195 
196 template<unsigned DIM>
198 {
200 }
201 
202 template<unsigned DIM>
203 CellPtr VertexBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, CellPtr pParentCell)
204 {
205  // Get the element associated with this cell
206  VertexElement<DIM, DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
207 
208  // Get the orientation of division
209  c_vector<double, DIM> division_vector = mpVertexBasedDivisionRule->CalculateCellDivisionVector(pParentCell, *this);
210 
211  // Divide the element
212  unsigned new_element_index = mpMutableVertexMesh->DivideElementAlongGivenAxis(p_element, division_vector, true);
213 
214  // Associate the new cell with the element
215  this->mCells.push_back(pNewCell);
216 
217  // Update location cell map
218  CellPtr p_created_cell = this->mCells.back();
219  this->SetCellUsingLocationIndex(new_element_index,p_created_cell);
220  this->mCellLocationMap[p_created_cell.get()] = new_element_index;
221 
222  return p_created_cell;
223 }
224 
225 template<unsigned DIM>
227 {
228  unsigned num_removed = 0;
229 
230  for (std::list<CellPtr>::iterator it = this->mCells.begin();
231  it != this->mCells.end();
232  )
233  {
234  if ((*it)->IsDead())
235  {
236  // Count the cell as dead
237  num_removed++;
238 
239  // Remove the element from the mesh if it is not deleted yet
241  if (!(this->GetElement(this->GetLocationIndexUsingCell((*it)))->IsDeleted()))
242  {
243  // This warning relies on the fact that there is only one other possibility for
244  // vertex elements to be marked as deleted: a T2 swap
245  WARN_ONCE_ONLY("A Cell is removed without performing a T2 swap. This could leave a void in the mesh.");
247  }
248 
249  // Delete the cell
250  it = this->mCells.erase(it);
251  }
252  else
253  {
254  ++it;
255  }
256  }
257  return num_removed;
258 }
259 
260 template<unsigned DIM>
261 void VertexBasedCellPopulation<DIM>::CheckForStepSizeException(unsigned nodeIndex, c_vector<double,DIM>& rDisplacement, double dt)
262 {
263  double length = norm_2(rDisplacement);
264 
266  {
268  {
269  rDisplacement *= 0.5*mpMutableVertexMesh->GetCellRearrangementThreshold()/length;
270 
271  std::ostringstream message;
272  message << "Vertices are moving more than half the CellRearrangementThreshold. This could cause elements to become inverted ";
273  message << "so the motion has been restricted. Use a smaller timestep to avoid these warnings.";
274 
275  double suggested_step = 0.95*dt*((0.5*mpMutableVertexMesh->GetCellRearrangementThreshold())/length);
276 
277  // The first time we see this behaviour, throw a StepSizeException, but not more than once
279  {
280  mThrowStepSizeException = false;
281  throw StepSizeException(suggested_step, message.str(), false);
282  }
283  }
284  }
285 }
286 
287 template<unsigned DIM>
289 {
290  return GetElementCorrespondingToCell(pCell)->IsDeleted();
291 }
292 
293 template<unsigned DIM>
294 void VertexBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
295 {
297  mpMutableVertexMesh->ReMesh(element_map);
298 
299  if (!element_map.IsIdentityMap())
300  {
301  // Fix up the mappings between CellPtrs and VertexElements
303  std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
304 
305  this->mCellLocationMap.clear();
306  this->mLocationCellMap.clear();
307 
308  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
309  cell_iter != this->mCells.end();
310  ++cell_iter)
311  {
312  // The cell vector should only ever contain living cells
313  unsigned old_elem_index = old_map[(*cell_iter).get()];
314  assert(!element_map.IsDeleted(old_elem_index));
315 
316  unsigned new_elem_index = element_map.GetNewIndex(old_elem_index);
317  this->SetCellUsingLocationIndex(new_elem_index, *cell_iter);
318  }
319 
320  // Check that each VertexElement has only one CellPtr associated with it in the updated cell population
321  Validate();
322  }
323 
324  element_map.ResetToIdentity();
325 }
326 
327 template<unsigned DIM>
329 {
330  // Check each element has only one cell attached
331  std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0);
332  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
333  cell_iter != this->End();
334  ++cell_iter)
335  {
336  unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
337  validated_element[elem_index]++;
338  }
339 
340  for (unsigned i=0; i<validated_element.size(); i++)
341  {
342  if (validated_element[i] == 0)
343  {
344  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() <<", Element " << i << " does not appear to have a cell associated with it");
345  }
346 
347  if (validated_element[i] > 1)
348  {
349  // This should never be reached as you can only set one cell per element index
350  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() <<", Element " << i << " appears to have " << validated_element[i] << " cells associated with it");
351  }
352  }
353 }
354 
355 template<unsigned DIM>
357 {
358  pPopulationWriter->Visit(this);
359 }
360 
361 template<unsigned DIM>
363 {
364  pPopulationCountWriter->Visit(this);
365 }
366 
367 template<unsigned DIM>
368 void VertexBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
369 {
370  pCellWriter->VisitCell(pCell, this);
371 }
372 
373 template<unsigned DIM>
375 {
376  // Get the vertex element index corresponding to this cell
377  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
378 
379  // Get the element rosette rank from the vertex mesh
380  unsigned rosette_rank = mpMutableVertexMesh->GetRosetteRankOfElement(elem_index);
381 
382  return rosette_rank;
383 }
384 
385 template<unsigned DIM>
387 {
388  // Get the vertex element index corresponding to this cell
389  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
390 
391  // Get the cell's volume from the vertex mesh
392  double cell_volume = mpMutableVertexMesh->GetVolumeOfElement(elem_index);
393 
394  return cell_volume;
395 }
396 
397 template<unsigned DIM>
398 void VertexBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
399 {
400 #ifdef CHASTE_VTK
401 
402  // Create mesh writer for VTK output
403  VertexMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results", false);
404 
405  // We avoid writing out CellData if the population is empty (i.e. no cells).
406  unsigned num_cells = this->GetNumAllCells();
407  if (num_cells > 0)
408  {
409  // Iterate over any cell writers that are present
410  for (auto cell_writer_iter = this->mCellWriters.begin();
411  cell_writer_iter != this->mCellWriters.end();
412  ++cell_writer_iter)
413  {
414  // Create vector to store VTK cell data
415  std::vector<double> vtk_cell_data(num_cells);
416 
417  // Iterate over vertex elements ///\todo #2512 - replace with loop over cells
418  for (auto elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
420  ++elem_iter)
421  {
422  // Get index of this element in the vertex mesh
423  unsigned elem_index = elem_iter->GetIndex();
424 
425  // Get the cell corresponding to this element
426  CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
427  assert(p_cell);
428 
429  // Populate the vector of VTK cell data
430  vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
431  }
432 
433  mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
434  }
435 
436  // When outputting any CellData, we assume that the first cell is representative of all cells
437  unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
438  std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
439 
440  std::vector<std::vector<double> > cell_data;
441  for (unsigned var=0; var<num_cell_data_items; var++)
442  {
443  std::vector<double> cell_data_var(num_cells);
444  cell_data.push_back(cell_data_var);
445  }
446 
447  // Loop over vertex elements ///\todo #2512 - replace with loop over cells
448  for (auto elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
450  ++elem_iter)
451  {
452  // Get index of this element in the vertex mesh
453  unsigned elem_index = elem_iter->GetIndex();
454 
455  // Get the cell corresponding to this element
456  CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
457  assert(p_cell);
458 
459  for (unsigned var=0; var<num_cell_data_items; var++)
460  {
461  cell_data[var][elem_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
462  }
463  }
464  for (unsigned var=0; var<num_cell_data_items; var++)
465  {
466  mesh_writer.AddCellData(cell_data_names[var], cell_data[var]);
467  }
468  }
469 
470  unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
471  std::stringstream time;
472  time << num_timesteps;
473 
474  mesh_writer.WriteVtkUsingMesh(*mpMutableVertexMesh, time.str());
475 
476  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
477  *(this->mpVtkMetaFile) << num_timesteps;
478  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
479  *(this->mpVtkMetaFile) << num_timesteps;
480  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
481 #endif //CHASTE_VTK
482 }
483 
484 template<unsigned DIM>
486 {
488  {
489  if (!this-> template HasWriter<CellPopulationElementWriter>())
490  {
491  this-> template AddPopulationWriter<CellPopulationElementWriter>();
492  }
493  }
494 
496  {
497  if (!this-> template HasWriter<VertexT1SwapLocationsWriter>())
498  {
499  this-> template AddPopulationWriter<VertexT1SwapLocationsWriter>();
500  }
501  if (!this-> template HasWriter<VertexT2SwapLocationsWriter>())
502  {
503  this-> template AddPopulationWriter<VertexT2SwapLocationsWriter>();
504  }
505  if (!this-> template HasWriter<VertexT3SwapLocationsWriter>())
506  {
507  this-> template AddPopulationWriter<VertexT3SwapLocationsWriter>();
508  }
509  if (!this-> template HasWriter<VertexIntersectionSwapLocationsWriter>())
510  {
511  this-> template AddPopulationWriter<VertexIntersectionSwapLocationsWriter>();
512  }
513  }
514 
516 }
517 
518 template<unsigned DIM>
520 {
522 }
523 
524 template<unsigned DIM>
526 {
527  mOutputCellRearrangementLocations = outputCellRearrangementLocations;
528 }
529 
530 template<unsigned DIM>
532 {
533  *rParamsFile << "\t\t<CellRearrangementThreshold>" << mpMutableVertexMesh->GetCellRearrangementThreshold() << "</CellRearrangementThreshold>\n";
534  *rParamsFile << "\t\t<T2Threshold>" << mpMutableVertexMesh->GetT2Threshold() << "</T2Threshold>\n";
535  *rParamsFile << "\t\t<CellRearrangementRatio>" << mpMutableVertexMesh->GetCellRearrangementRatio() << "</CellRearrangementRatio>\n";
536  *rParamsFile << "\t\t<OutputCellRearrangementLocations>" << mOutputCellRearrangementLocations << "</OutputCellRearrangementLocations>\n";
537 
538  // Add the division rule parameters
539  *rParamsFile << "\t\t<VertexBasedDivisionRule>\n";
540  mpVertexBasedDivisionRule->OutputCellVertexBasedDivisionRuleInfo(rParamsFile);
541  *rParamsFile << "\t\t</VertexBasedDivisionRule>\n";
542 
543  // Call method on direct parent class
545 }
546 
547 template<unsigned DIM>
548 double VertexBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
549 {
550  // Call GetWidth() on the mesh
551  double width = this->mrMesh.GetWidth(rDimension);
552 
553  return width;
554 }
555 
556 template<unsigned DIM>
558 {
560 }
561 
562 template<unsigned DIM>
563 boost::shared_ptr<AbstractVertexBasedDivisionRule<DIM> > VertexBasedCellPopulation<DIM>::GetVertexBasedDivisionRule()
564 {
566 }
567 
568 template<unsigned DIM>
570 {
571  mpVertexBasedDivisionRule = pVertexBasedDivisionRule;
572 }
573 
574 template<unsigned DIM>
575 std::vector< c_vector< double, DIM > > VertexBasedCellPopulation<DIM>::GetLocationsOfT2Swaps()
576 {
577  return mLocationsOfT2Swaps;
578 }
579 
580 template<unsigned DIM>
582 {
583  return mCellIdsOfT2Swaps;
584 }
585 
586 template<unsigned DIM>
587 void VertexBasedCellPopulation<DIM>::AddLocationOfT2Swap(c_vector< double, DIM> locationOfT2Swap)
588 {
589  mLocationsOfT2Swaps.push_back(locationOfT2Swap);
590 }
591 
592 template<unsigned DIM>
594 {
595  mCellIdsOfT2Swaps.push_back(idOfT2Swap);
596 }
597 
598 template<unsigned DIM>
600 {
601  mCellIdsOfT2Swaps.clear();
602  mLocationsOfT2Swaps.clear();
603 }
604 
605 template<unsigned DIM>
607 {
608  // This method only works in 2D sequential
609  assert(DIM == 2); // LCOV_EXCL_LINE - disappears at compile time.
610  assert(PetscTools::IsSequential());
611 
612  unsigned num_vertex_nodes = mpMutableVertexMesh->GetNumNodes();
613  unsigned num_vertex_elements = mpMutableVertexMesh->GetNumElements();
614 
615  std::string mesh_file_name = "mesh";
616 
617  // Get a unique temporary foldername
618  std::stringstream pid;
619  pid << getpid();
620  OutputFileHandler output_file_handler("2D_temporary_tetrahedral_mesh_" + pid.str());
621  std::string output_dir = output_file_handler.GetOutputDirectoryFullPath();
622 
623  // Compute the number of nodes in the TetrahedralMesh
624  unsigned num_tetrahedral_nodes = num_vertex_nodes + num_vertex_elements;
625 
626  // Write node file
627  out_stream p_node_file = output_file_handler.OpenOutputFile(mesh_file_name+".node");
628  (*p_node_file) << std::scientific;
629  (*p_node_file) << std::setprecision(20);
630  (*p_node_file) << num_tetrahedral_nodes << "\t2\t0\t1" << std::endl;
631 
632  // Begin by writing each node in the VertexMesh
633  for (unsigned node_index=0; node_index<num_vertex_nodes; node_index++)
634  {
635  Node<DIM>* p_node = mpMutableVertexMesh->GetNode(node_index);
636 
638  unsigned index = p_node->GetIndex();
639  const c_vector<double, DIM>& r_location = p_node->rGetLocation();
640  unsigned is_boundary_node = p_node->IsBoundaryNode() ? 1 : 0;
641 
642  (*p_node_file) << index << "\t" << r_location[0] << "\t" << r_location[1] << "\t" << is_boundary_node << std::endl;
643  }
644 
645  // Now write an additional node at each VertexElement's centroid
646  unsigned num_tetrahedral_elements = 0;
647  for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++)
648  {
649  unsigned index = num_vertex_nodes + vertex_elem_index;
650 
651  c_vector<double, DIM> location = mpMutableVertexMesh->GetCentroidOfElement(vertex_elem_index);
652 
653  // Any node located at a VertexElement's centroid will not be a boundary node
654  unsigned is_boundary_node = 0;
655  (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl;
656 
657  // Also keep track of how many tetrahedral elements there will be
658  num_tetrahedral_elements += mpMutableVertexMesh->GetElement(vertex_elem_index)->GetNumNodes();
659  }
660  p_node_file->close();
661 
662  // Write element file
663  out_stream p_elem_file = output_file_handler.OpenOutputFile(mesh_file_name+".ele");
664  (*p_elem_file) << std::scientific;
665  (*p_elem_file) << num_tetrahedral_elements << "\t3\t0" << std::endl;
666 
667  std::set<std::pair<unsigned, unsigned> > tetrahedral_edges;
668 
669  unsigned tetrahedral_elem_index = 0;
670  for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++)
671  {
672  VertexElement<DIM, DIM>* p_vertex_element = mpMutableVertexMesh->GetElement(vertex_elem_index);
673 
674  // Iterate over nodes owned by this VertexElement
675  unsigned num_nodes_in_vertex_element = p_vertex_element->GetNumNodes();
676  for (unsigned local_index=0; local_index<num_nodes_in_vertex_element; local_index++)
677  {
678  unsigned node_0_index = p_vertex_element->GetNodeGlobalIndex(local_index);
679  unsigned node_1_index = p_vertex_element->GetNodeGlobalIndex((local_index+1)%num_nodes_in_vertex_element);
680  unsigned node_2_index = num_vertex_nodes + vertex_elem_index;
681 
682  (*p_elem_file) << tetrahedral_elem_index++ << "\t" << node_0_index << "\t" << node_1_index << "\t" << node_2_index << std::endl;
683 
684  // Add edges to the set if they are not already present
685  std::pair<unsigned, unsigned> edge_0 = this->CreateOrderedPair(node_0_index, node_1_index);
686  std::pair<unsigned, unsigned> edge_1 = this->CreateOrderedPair(node_1_index, node_2_index);
687  std::pair<unsigned, unsigned> edge_2 = this->CreateOrderedPair(node_2_index, node_0_index);
688 
689  tetrahedral_edges.insert(edge_0);
690  tetrahedral_edges.insert(edge_1);
691  tetrahedral_edges.insert(edge_2);
692  }
693  }
694  p_elem_file->close();
695 
696  // Write edge file
697  out_stream p_edge_file = output_file_handler.OpenOutputFile(mesh_file_name+".edge");
698  (*p_edge_file) << std::scientific;
699  (*p_edge_file) << tetrahedral_edges.size() << "\t1" << std::endl;
700 
701  unsigned edge_index = 0;
702  for (std::set<std::pair<unsigned, unsigned> >::iterator edge_iter = tetrahedral_edges.begin();
703  edge_iter != tetrahedral_edges.end();
704  ++edge_iter)
705  {
706  std::pair<unsigned, unsigned> this_edge = *edge_iter;
707 
708  // To be a boundary edge both nodes need to be boundary nodes.
709  bool is_boundary_edge = false;
710  if (this_edge.first < mpMutableVertexMesh->GetNumNodes() &&
711  this_edge.second < mpMutableVertexMesh->GetNumNodes())
712  {
713  is_boundary_edge = (mpMutableVertexMesh->GetNode(this_edge.first)->IsBoundaryNode() &&
714  mpMutableVertexMesh->GetNode(this_edge.second)->IsBoundaryNode() );
715  }
716  unsigned is_boundary_edge_unsigned = is_boundary_edge ? 1 : 0;
717 
718  (*p_edge_file) << edge_index++ << "\t" << this_edge.first << "\t" << this_edge.second << "\t" << is_boundary_edge_unsigned << std::endl;
719  }
720  p_edge_file->close();
721 
722  // Having written the mesh to file, now construct it using TrianglesMeshReader
724 
725  // Nested scope so reader is destroyed before we remove the temporary files
726  {
727  TrianglesMeshReader<DIM, DIM> mesh_reader(output_dir + mesh_file_name);
728  p_mesh->ConstructFromMeshReader(mesh_reader);
729  }
730 
731  // Delete the temporary files
732  output_file_handler.FindFile("").Remove();
733 
734  // The original files have been deleted, it is better if the mesh object forgets about them
736 
737  return p_mesh;
738 }
739 
740 template<unsigned DIM>
742 {
743  bool non_apoptotic_cell_present = true;
744 
745  if (pdeNodeIndex < this->GetNumNodes())
746  {
747  std::set<unsigned> containing_element_indices = this->GetNode(pdeNodeIndex)->rGetContainingElementIndices();
748 
749  for (std::set<unsigned>::iterator iter = containing_element_indices.begin();
750  iter != containing_element_indices.end();
751  iter++)
752  {
753  if (this->GetCellUsingLocationIndex(*iter)->template HasCellProperty<ApoptoticCellProperty>() )
754  {
755  non_apoptotic_cell_present = false;
756  break;
757  }
758  }
759  }
760  else
761  {
762  /*
763  * This node of the tetrahedral finite element mesh is in the centre of the element of the
764  * vertex-based cell population, so we can use an offset to compute which cell to interrogate.
765  */
766  non_apoptotic_cell_present = !(this->GetCellUsingLocationIndex(pdeNodeIndex - this->GetNumNodes())->template HasCellProperty<ApoptoticCellProperty>());
767  }
768 
769  return non_apoptotic_cell_present;
770 }
771 
772 template<unsigned DIM>
774  unsigned pdeNodeIndex,
775  std::string& rVariableName,
776  bool dirichletBoundaryConditionApplies,
777  double dirichletBoundaryValue)
778 {
779  unsigned num_nodes = this->GetNumNodes();
780  double value = 0.0;
781 
782  // Cells correspond to nodes in the centre of the vertex element; nodes on vertices have averaged values from containing cells
783 
784  if (pdeNodeIndex >= num_nodes)
785  {
786  // Offset to relate elements in vertex mesh to nodes in tetrahedral mesh
787  assert(pdeNodeIndex-num_nodes < num_nodes);
788 
789  CellPtr p_cell = this->GetCellUsingLocationIndex(pdeNodeIndex - num_nodes);
790  value = p_cell->GetCellData()->GetItem(rVariableName);
791  }
792  else
793  {
795  if (dirichletBoundaryConditionApplies)
796  {
797  // We need to impose the Dirichlet boundaries again here as not represented in cell data
798  value = dirichletBoundaryValue;
799  }
800  else
801  {
802  assert(pdeNodeIndex < num_nodes);
803  Node<DIM>* p_node = this->GetNode(pdeNodeIndex);
804 
805  // Average over data from containing elements (cells)
806  std::set<unsigned> containing_elements = p_node->rGetContainingElementIndices();
807  for (std::set<unsigned>::iterator index_iter = containing_elements.begin();
808  index_iter != containing_elements.end();
809  ++index_iter)
810  {
811  assert(*index_iter < num_nodes);
812  CellPtr p_cell = this->GetCellUsingLocationIndex(*index_iter);
813  value += p_cell->GetCellData()->GetItem(rVariableName);
814  }
815  value /= containing_elements.size();
816  }
817  }
818 
819  return value;
820 }
821 
822 template<unsigned DIM>
824 {
825  return 0.002;
826 }
827 
828 template<unsigned DIM>
830 {
831  if (bool(dynamic_cast<Cylindrical2dVertexMesh*>(&(this->mrMesh))))
832  {
833  *pVizSetupFile << "MeshWidth\t" << this->GetWidth(0) << "\n";
834  }
835 }
836 
837 template<unsigned DIM>
839 {
840  MAKE_PTR_ARGS(T2SwapCellKiller<DIM>, p_t2_swap_cell_killer, (this));
841  pSimulation->AddCellKiller(p_t2_swap_cell_killer);
842 }
843 
844 
845 template<unsigned DIM>
847 {
849 }
850 
851 template<unsigned DIM>
853 {
854  mRestrictVertexMovement = restrictMovement;
855 }
856 
857 // Explicit instantiation
858 template class VertexBasedCellPopulation<1>;
859 template class VertexBasedCellPopulation<2>;
860 template class VertexBasedCellPopulation<3>;
861 
862 // Serialization for Boost >= 1.36
void SetOutputCellRearrangementLocations(bool outputCellRearrangementLocations)
void AddCellData(std::string dataName, std::vector< double > dataPayload)
std::vector< c_vector< double, DIM > > GetLocationsOfT2Swaps()
unsigned GetNumAllElements() const
Definition: VertexMesh.cpp:616
std::vector< unsigned > mCellIdsOfT2Swaps
std::string GetOutputDirectoryFullPath() const
double GetCellRearrangementRatio() const
void AddCellKiller(boost::shared_ptr< AbstractCellKiller< SPACE_DIM > > pCellKiller)
virtual void AcceptPopulationCountWriter(boost::shared_ptr< AbstractCellPopulationCountWriter< DIM, DIM > > pPopulationCountWriter)
unsigned DivideElementAlongGivenAxis(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, c_vector< double, SPACE_DIM > axisOfDivision, bool placeOriginalElementBelow=false)
std::set< unsigned > GetNeighbouringNodeIndices(unsigned nodeIndex)
Definition: VertexMesh.cpp:713
Definition: Node.hpp:58
std::vector< boost::shared_ptr< AbstractCellWriter< ELEMENT_DIM, SPACE_DIM > > > mCellWriters
std::vector< c_vector< double, DIM > > mLocationsOfT2Swaps
virtual void SimulationSetupHook(AbstractCellBasedSimulation< DIM, DIM > *pSimulation)
#define EXCEPTION(message)
Definition: Exception.hpp:143
boost::shared_ptr< AbstractVertexBasedDivisionRule< DIM > > mpVertexBasedDivisionRule
MutableVertexMesh< DIM, DIM > * mpMutableVertexMesh
static SimulationTime * Instance()
VertexElement< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
Definition: VertexMesh.cpp:628
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
void ConstructFromMeshReader(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader)
virtual void AcceptCellWriter(boost::shared_ptr< AbstractCellWriter< DIM, DIM > > pCellWriter, CellPtr pCell)
void SetVertexBasedDivisionRule(boost::shared_ptr< AbstractVertexBasedDivisionRule< DIM > > pVertexBasedDivisionRule)
std::vector< unsigned > GetCellIdsOfT2Swaps()
virtual bool IsPdeNodeAssociatedWithNonApoptoticCell(unsigned pdeNodeIndex)
std::set< unsigned > & rGetContainingElementIndices()
Definition: Node.cpp:300
unsigned GetIndex() const
Definition: Node.cpp:158
virtual void WriteDataToVisualizerSetupFile(out_stream &pVizSetupFile)
unsigned GetNumNodes() const
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
unsigned GetNumElements() const
Node< SPACE_DIM > * GetNode(unsigned index) const
boost::shared_ptr< AbstractVertexBasedDivisionRule< DIM > > GetVertexBasedDivisionRule()
bool IsCellAssociatedWithADeletedLocation(CellPtr pCell)
double GetDampingConstant(unsigned nodeIndex)
void SetRestrictVertexMovementBoolean(bool restrictVertexMovement)
std::set< unsigned > GetNeighbouringLocationIndices(CellPtr pCell)
unsigned GetRosetteRankOfCell(CellPtr pCell)
MutableVertexMesh< DIM, DIM > & rGetMesh()
unsigned GetNodeGlobalIndex(unsigned localIndex) const
static bool IsSequential()
Definition: PetscTools.cpp:91
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:139
std::pair< unsigned, unsigned > CreateOrderedPair(unsigned index1, unsigned index2)
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:679
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
virtual void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > point)
std::map< unsigned, std::set< CellPtr > > mLocationCellMap
void SetCellUsingLocationIndex(unsigned index, CellPtr pCell)
virtual void AcceptPopulationWriter(boost::shared_ptr< AbstractCellPopulationWriter< DIM, DIM > > pPopulationWriter)
void Update(bool hasHadBirthsOrDeaths=true)
void AddLocationOfT2Swap(c_vector< double, DIM > locationOfT2Swap)
VertexBasedCellPopulation(MutableVertexMesh< DIM, DIM > &rMesh, std::vector< CellPtr > &rCells, bool deleteMesh=false, bool validate=true, const std::vector< unsigned > locationIndices=std::vector< unsigned >())
Node< DIM > * GetNode(unsigned index)
double GetT2Threshold() const
virtual TetrahedralMesh< DIM, DIM > * GetTetrahedralMeshForPdeModifier()
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
double GetCellRearrangementThreshold() const
virtual double GetVolumeOfElement(unsigned index)
virtual void CheckForStepSizeException(unsigned nodeIndex, c_vector< double, DIM > &rDisplacement, double dt)
void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
virtual void ReMesh(VertexElementMap &rElementMap)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
void SetMeshHasChangedSinceLoading()
void SetNode(unsigned index, ChastePoint< DIM > &rNewLocation)
void DeleteElementPriorToReMesh(unsigned index)
void AddCellIdOfT2Swap(unsigned idOfT2Swap)
double GetWidth(const unsigned &rDimension)
c_vector< double, DIM > GetLocationOfCellCentre(CellPtr pCell)
virtual c_vector< double, SPACE_DIM > GetCentroidOfElement(unsigned index)
Definition: VertexMesh.cpp:642
unsigned AddNode(Node< DIM > *pNewNode)
std::set< unsigned > GetNeighbouringElementIndices(unsigned elementIndex)
Definition: VertexMesh.cpp:783
CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell=CellPtr())
unsigned GetNumNodes() const
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
virtual double GetCellDataItemAtPdeNode(unsigned pdeNodeIndex, std::string &rVariableName, bool dirichletBoundaryConditionApplies=false, double dirichletBoundaryValue=0.0)
VertexElementIterator GetElementIteratorEnd()
Definition: VertexMesh.hpp:686
virtual void AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
AbstractMesh< ELEMENT_DIM, SPACE_DIM > & mrMesh
bool IsBoundaryNode() const
Definition: Node.cpp:164
VertexElement< DIM, DIM > * GetElement(unsigned elementIndex)
unsigned GetTimeStepsElapsed() const
#define MAKE_PTR_ARGS(TYPE, NAME, ARGS)
VertexElement< DIM, DIM > * GetElementCorrespondingToCell(CellPtr pCell)
unsigned GetRosetteRankOfElement(unsigned index)
Definition: VertexMesh.cpp:555