Chaste  Release::3.4
VertexBasedCellPopulation.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 "VertexBasedCellPopulation.hpp"
37 #include <boost/foreach.hpp>
38 #include "VertexMeshWriter.hpp"
39 #include "Warnings.hpp"
40 #include "ChasteSyscalls.hpp"
41 #include "IsNan.hpp"
42 #include "ShortAxisVertexBasedDivisionRule.hpp"
43 
44 // Cell writers
45 #include "CellAgesWriter.hpp"
46 #include "CellAncestorWriter.hpp"
47 #include "CellProliferativePhasesWriter.hpp"
48 #include "CellProliferativeTypesWriter.hpp"
49 #include "CellVolumesWriter.hpp"
50 
51 // Cell population writers
52 #include "CellMutationStatesCountWriter.hpp"
53 #include "CellPopulationElementWriter.hpp"
54 #include "VertexT1SwapLocationsWriter.hpp"
55 #include "VertexT2SwapLocationsWriter.hpp"
56 #include "VertexT3SwapLocationsWriter.hpp"
57 
58 template<unsigned DIM>
60  std::vector<CellPtr>& rCells,
61  bool deleteMesh,
62  bool validate,
63  const std::vector<unsigned> locationIndices)
64  : AbstractOffLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices),
65  mDeleteMesh(deleteMesh),
66  mOutputCellRearrangementLocations(true)
67 {
68  mpMutableVertexMesh = static_cast<MutableVertexMesh<DIM, DIM>* >(&(this->mrMesh));
70 
71  // If no location indices are specified, associate with elements from the mesh (assumed to be sequentially ordered).
72  std::list<CellPtr>::iterator it = this->mCells.begin();
73  for (unsigned i=0; it != this->mCells.end(); ++it, ++i)
74  {
75  unsigned index = locationIndices.empty() ? i : locationIndices[i]; // assume that the ordering matches
77  }
78 
79  // Check each element has only one cell attached
80  if (validate)
81  {
82  Validate();
83  }
84 }
85 
86 template<unsigned DIM>
89  mDeleteMesh(true),
90  mOutputCellRearrangementLocations(true)
91 {
92  mpMutableVertexMesh = static_cast<MutableVertexMesh<DIM, DIM>* >(&(this->mrMesh));
93 }
94 
95 template<unsigned DIM>
97 {
98  if (mDeleteMesh)
99  {
100  delete &this->mrMesh;
101  }
102 }
103 
104 template<unsigned DIM>
106 {
107  // Take the average of the cells containing this vertex
108  double average_damping_constant = 0.0;
109 
110  std::set<unsigned> containing_elements = GetNode(nodeIndex)->rGetContainingElementIndices();
111 
112  unsigned num_containing_elements = containing_elements.size();
113  if (num_containing_elements == 0)
114  {
115  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Node " << nodeIndex << " is not contained in any elements, so GetDampingConstant() returns zero");
116  }
117 
118  double temp = 1.0/((double) num_containing_elements);
119  for (std::set<unsigned>::iterator iter = containing_elements.begin();
120  iter != containing_elements.end();
121  ++iter)
122  {
123  CellPtr p_cell = this->GetCellUsingLocationIndex(*iter);
124  bool cell_is_wild_type = p_cell->GetMutationState()->IsType<WildTypeCellMutationState>();
125  bool cell_is_labelled = p_cell->HasCellProperty<CellLabel>();
126 
127  if (cell_is_wild_type && !cell_is_labelled)
128  {
129  average_damping_constant += this->GetDampingConstantNormal()*temp;
130  }
131  else
132  {
133  average_damping_constant += this->GetDampingConstantMutant()*temp;
134  }
135  }
136 
137  return average_damping_constant;
138 }
139 
140 template<unsigned DIM>
142 {
143  return *mpMutableVertexMesh;
144 }
145 
146 template<unsigned DIM>
148 {
149  return *mpMutableVertexMesh;
150 }
151 
152 template<unsigned DIM>
154 {
155  return mpMutableVertexMesh->GetElement(elementIndex);
156 }
157 
158 template<unsigned DIM>
160 {
161  return this->mrMesh.GetNumNodes();
162 }
163 
164 template<unsigned DIM>
166 {
167  return mpMutableVertexMesh->GetCentroidOfElement(this->mCellLocationMap[pCell.get()]);
168 }
169 
170 template<unsigned DIM>
172 {
173  return this->mrMesh.GetNode(index);
174 }
175 
176 template<unsigned DIM>
178 {
179  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
180  return this->rGetMesh().GetNeighbouringElementIndices(elem_index);
181 }
182 
183 template<unsigned DIM>
185 {
186  return mpMutableVertexMesh->AddNode(pNewNode);
187 }
188 
189 template<unsigned DIM>
190 void VertexBasedCellPopulation<DIM>::SetNode(unsigned nodeIndex, ChastePoint<DIM>& rNewLocation)
191 {
192  mpMutableVertexMesh->SetNode(nodeIndex, rNewLocation);
193 }
194 
195 template<unsigned DIM>
197 {
198  return mpMutableVertexMesh->GetElement(this->GetLocationIndexUsingCell(pCell));
199 }
200 
201 template<unsigned DIM>
203 {
204  return mpMutableVertexMesh->GetNumElements();
205 }
206 
207 template<unsigned DIM>
209  const c_vector<double,DIM>& rCellDivisionVector,
210  CellPtr pParentCell)
211 {
212  // Get the element associated with this cell
213  VertexElement<DIM, DIM>* p_element = GetElementCorrespondingToCell(pParentCell);
214 
215  // Divide the element
216  unsigned new_element_index = mpMutableVertexMesh->DivideElementAlongGivenAxis(p_element,
217  rCellDivisionVector,
218  true);
219  // Associate the new cell with the element
220  this->mCells.push_back(pNewCell);
221 
222  // Update location cell map
223  CellPtr p_created_cell = this->mCells.back();
224  this->SetCellUsingLocationIndex(new_element_index,p_created_cell);
225  this->mCellLocationMap[p_created_cell.get()] = new_element_index;
226  return p_created_cell;
227 }
228 
229 template<unsigned DIM>
231 {
232  unsigned num_removed = 0;
233 
234  for (std::list<CellPtr>::iterator it = this->mCells.begin();
235  it != this->mCells.end();
236  )
237  {
238  if ((*it)->IsDead())
239  {
240  // Count the cell as dead
241  num_removed++;
242 
243  // Remove the element from the mesh if it is not deleted yet
245  if (!(this->GetElement(this->GetLocationIndexUsingCell((*it)))->IsDeleted()))
246  {
247  // This warning relies on the fact that there is only one other possibility for
248  // vertex elements to be marked as deleted: a T2 swap
249  WARN_ONCE_ONLY("A Cell is removed without performing a T2 swap. This could leave a void in the mesh.");
250  mpMutableVertexMesh->DeleteElementPriorToReMesh(this->GetLocationIndexUsingCell((*it)));
251  }
252 
253  // Delete the cell
254  it = this->mCells.erase(it);
255  }
256  else
257  {
258  ++it;
259  }
260  }
261  return num_removed;
262 }
263 
264 template<unsigned DIM>
266 {
267  // Iterate over all nodes associated with real cells to update their positions
268  for (unsigned node_index=0; node_index<GetNumNodes(); node_index++)
269  {
270  // Get the damping constant for this node
271  double damping_const = this->GetDampingConstant(node_index);
272 
273  // Compute the displacement of this node
274  c_vector<double, DIM> displacement = dt*this->GetNode(node_index)->rGetAppliedForce()/damping_const;
275 
276  /*
277  * If the displacement of this node is greater than half the cell rearrangement threshold,
278  * this could result in nodes moving into the interior of other elements, which should not
279  * be possible. Therefore in this case we restrict the displacement of the node to the cell
280  * rearrangement threshold and warn the user that a smaller timestep should be used. This
281  * restriction ensures that vertex elements remain well defined (see #1376).
282  */
283  if (norm_2(displacement) > 0.5*mpMutableVertexMesh->GetCellRearrangementThreshold())
284  {
285  WARN_ONCE_ONLY("Vertices are moving more than half the CellRearrangementThreshold. This could cause elements to become inverted so the motion has been restricted. Use a smaller timestep to avoid these warnings.");
286  displacement *= 0.5*mpMutableVertexMesh->GetCellRearrangementThreshold()/norm_2(displacement);
287  }
288 
289  // Get new node location
290  c_vector<double, DIM> new_node_location = this->GetNode(node_index)->rGetLocation() + displacement;
291 
292  for (unsigned i=0; i<DIM; i++)
293  {
294  assert(!std::isnan(new_node_location(i)));
295  }
296 
297  // Create ChastePoint for new node location
298  ChastePoint<DIM> new_point(new_node_location);
299 
300  // Move the node
301  this->SetNode(node_index, new_point);
302  }
303 }
304 
305 template<unsigned DIM>
307 {
308  return GetElementCorrespondingToCell(pCell)->IsDeleted();;
309 }
310 
311 template<unsigned DIM>
312 void VertexBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths)
313 {
314  VertexElementMap element_map(mpMutableVertexMesh->GetNumAllElements());
315  mpMutableVertexMesh->ReMesh(element_map);
316 
317  if (!element_map.IsIdentityMap())
318  {
319  // Fix up the mappings between CellPtrs and VertexElements
321  std::map<Cell*, unsigned> old_map = this->mCellLocationMap;
322 
323  this->mCellLocationMap.clear();
324  this->mLocationCellMap.clear();
325 
326  for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin();
327  cell_iter != this->mCells.end();
328  ++cell_iter)
329  {
330  // The cell vector should only ever contain living cells
331  unsigned old_elem_index = old_map[(*cell_iter).get()];
332  assert(!element_map.IsDeleted(old_elem_index));
333 
334  unsigned new_elem_index = element_map.GetNewIndex(old_elem_index);
335  this->SetCellUsingLocationIndex(new_elem_index, *cell_iter);
336  }
337 
338  // Check that each VertexElement has only one CellPtr associated with it in the updated cell population
339  Validate();
340  }
341 
342  element_map.ResetToIdentity();
343 }
344 
345 template<unsigned DIM>
347 {
348  // Check each element has only one cell attached
349  std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0);
350  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
351  cell_iter != this->End();
352  ++cell_iter)
353  {
354  unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter);
355  validated_element[elem_index]++;
356  }
357 
358  for (unsigned i=0; i<validated_element.size(); i++)
359  {
360  if (validated_element[i] == 0)
361  {
362  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() <<", Element " << i << " does not appear to have a cell associated with it");
363  }
364 
365  if (validated_element[i] > 1)
366  {
367  // This should never be reached as you can only set one cell per element index
368  EXCEPTION("At time " << SimulationTime::Instance()->GetTime() <<", Element " << i << " appears to have " << validated_element[i] << " cells associated with it");
369  }
370  }
371 }
372 
373 template<unsigned DIM>
375 {
376  pPopulationWriter->Visit(this);
377 }
378 
379 template<unsigned DIM>
381 {
382  pPopulationCountWriter->Visit(this);
383 }
384 
385 template<unsigned DIM>
386 void VertexBasedCellPopulation<DIM>::AcceptCellWriter(boost::shared_ptr<AbstractCellWriter<DIM, DIM> > pCellWriter, CellPtr pCell)
387 {
388  pCellWriter->VisitCell(pCell, this);
389 }
390 
391 template<unsigned DIM>
393 {
394  // Get the vertex element index corresponding to this cell
395  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
396 
397  // Get the element rosette rank from the vertex mesh
398  unsigned rosette_rank = mpMutableVertexMesh->GetRosetteRankOfElement(elem_index);
399 
400  return rosette_rank;
401 }
402 
403 template<unsigned DIM>
405 {
406  // Get the vertex element index corresponding to this cell
407  unsigned elem_index = this->GetLocationIndexUsingCell(pCell);
408 
409  // Get the cell's volume from the vertex mesh
410  double cell_volume = mpMutableVertexMesh->GetVolumeOfElement(elem_index);
411 
412  return cell_volume;
413 }
414 
415 template<unsigned DIM>
416 void VertexBasedCellPopulation<DIM>::WriteVtkResultsToFile(const std::string& rDirectory)
417 {
418 #ifdef CHASTE_VTK
419 
420  // Create mesh writer for VTK output
421  VertexMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results", false);
422 
423  // Iterate over any cell writers that are present
424  unsigned num_cells = this->GetNumAllCells();
425  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
426  cell_writer_iter != this->mCellWriters.end();
427  ++cell_writer_iter)
428  {
429  // Create vector to store VTK cell data
430  std::vector<double> vtk_cell_data(num_cells);
431 
432  // Iterate over vertex elements ///\todo #2512 - replace with loop over cells
433  for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
434  elem_iter != mpMutableVertexMesh->GetElementIteratorEnd();
435  ++elem_iter)
436  {
437  // Get index of this element in the vertex mesh
438  unsigned elem_index = elem_iter->GetIndex();
439 
440  // Get the cell corresponding to this element
441  CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
442  assert(p_cell);
443 
444  // Populate the vector of VTK cell data
445  vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
446  }
447 
448  mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
449  }
450 
451  // When outputting any CellData, we assume that the first cell is representative of all cells
452  unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
453  std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
454 
455  std::vector<std::vector<double> > cell_data;
456  for (unsigned var=0; var<num_cell_data_items; var++)
457  {
458  std::vector<double> cell_data_var(num_cells);
459  cell_data.push_back(cell_data_var);
460  }
461 
462  // Loop over vertex elements ///\todo #2512 - replace with loop over cells
463  for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = mpMutableVertexMesh->GetElementIteratorBegin();
464  elem_iter != mpMutableVertexMesh->GetElementIteratorEnd();
465  ++elem_iter)
466  {
467  // Get index of this element in the vertex mesh
468  unsigned elem_index = elem_iter->GetIndex();
469 
470  // Get the cell corresponding to this element
471  CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
472  assert(p_cell);
473 
474  for (unsigned var=0; var<num_cell_data_items; var++)
475  {
476  cell_data[var][elem_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
477  }
478  }
479  for (unsigned var=0; var<num_cell_data_items; var++)
480  {
481  mesh_writer.AddCellData(cell_data_names[var], cell_data[var]);
482  }
483 
484  unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
485  std::stringstream time;
486  time << num_timesteps;
487 
488  mesh_writer.WriteVtkUsingMesh(*mpMutableVertexMesh, time.str());
489 
490  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
491  *(this->mpVtkMetaFile) << num_timesteps;
492  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
493  *(this->mpVtkMetaFile) << num_timesteps;
494  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
495 #endif //CHASTE_VTK
496 }
497 
498 template<unsigned DIM>
500 {
501  if (this->mOutputResultsForChasteVisualizer)
502  {
503  if (!this-> template HasWriter<CellPopulationElementWriter>())
504  {
505  this-> template AddPopulationWriter<CellPopulationElementWriter>();
506  }
507  }
508 
509  if (mOutputCellRearrangementLocations)
510  {
511  if (!this-> template HasWriter<VertexT1SwapLocationsWriter>())
512  {
513  this-> template AddPopulationWriter<VertexT1SwapLocationsWriter>();
514  }
515  if (!this-> template HasWriter<VertexT2SwapLocationsWriter>())
516  {
517  this-> template AddPopulationWriter<VertexT2SwapLocationsWriter>();
518  }
519  if (!this-> template HasWriter<VertexT3SwapLocationsWriter>())
520  {
521  this-> template AddPopulationWriter<VertexT3SwapLocationsWriter>();
522  }
523  }
524 
526 }
527 
528 template<unsigned DIM>
530 {
531  return mOutputCellRearrangementLocations;
532 }
533 
534 template<unsigned DIM>
536 {
537  mOutputCellRearrangementLocations = outputCellRearrangementLocations;
538 }
539 
540 template<unsigned DIM>
542 {
543  *rParamsFile << "\t\t<CellRearrangementThreshold>" << mpMutableVertexMesh->GetCellRearrangementThreshold() << "</CellRearrangementThreshold>\n";
544  *rParamsFile << "\t\t<T2Threshold>" << mpMutableVertexMesh->GetT2Threshold() << "</T2Threshold>\n";
545  *rParamsFile << "\t\t<CellRearrangementRatio>" << mpMutableVertexMesh->GetCellRearrangementRatio() << "</CellRearrangementRatio>\n";
546  *rParamsFile << "\t\t<OutputCellRearrangementLocations>" << mOutputCellRearrangementLocations << "</OutputCellRearrangementLocations>\n";
547 
548  // Add the division rule parameters
549  *rParamsFile << "\t\t<VertexBasedDivisionRule>\n";
550  mpVertexBasedDivisionRule->OutputCellVertexBasedDivisionRuleInfo(rParamsFile);
551  *rParamsFile << "\t\t</VertexBasedDivisionRule>\n";
552 
553  // Call method on direct parent class
555 }
556 
557 template<unsigned DIM>
558 double VertexBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension)
559 {
560  // Call GetWidth() on the mesh
561  double width = this->mrMesh.GetWidth(rDimension);
562 
563  return width;
564 }
565 
566 template<unsigned DIM>
568 {
569  return mpMutableVertexMesh->GetNeighbouringNodeIndices(index);
570 }
571 
572 template<unsigned DIM>
573 boost::shared_ptr<AbstractVertexBasedDivisionRule<DIM> > VertexBasedCellPopulation<DIM>::GetVertexBasedDivisionRule()
574 {
575  return mpVertexBasedDivisionRule;
576 }
577 
578 template<unsigned DIM>
580 {
581  mpVertexBasedDivisionRule = pVertexBasedDivisionRule;
582 }
583 
584 template<unsigned DIM>
585 std::vector< c_vector< double, DIM > > VertexBasedCellPopulation<DIM>::GetLocationsOfT2Swaps()
586 {
587  return mLocationsOfT2Swaps;
588 }
589 
590 template<unsigned DIM>
592 {
593  return mCellIdsOfT2Swaps;
594 }
595 
596 template<unsigned DIM>
597 void VertexBasedCellPopulation<DIM>::AddLocationOfT2Swap(c_vector< double, DIM> locationOfT2Swap)
598 {
599  mLocationsOfT2Swaps.push_back(locationOfT2Swap);
600 }
601 
602 template<unsigned DIM>
604 {
605  mCellIdsOfT2Swaps.push_back(idOfT2Swap);
606 }
607 
608 template<unsigned DIM>
610 {
611  mCellIdsOfT2Swaps.clear();
612  mLocationsOfT2Swaps.clear();
613 }
614 
615 template<unsigned DIM>
617 {
618  // This method only works in 2D sequential
619  assert(DIM == 2);
620  assert(PetscTools::IsSequential());
621 
622  unsigned num_vertex_nodes = mpMutableVertexMesh->GetNumNodes();
623  unsigned num_vertex_elements = mpMutableVertexMesh->GetNumElements();
624 
625  std::string mesh_file_name = "mesh";
626 
627  // Get a unique temporary foldername
628  std::stringstream pid;
629  pid << getpid();
630  OutputFileHandler output_file_handler("2D_temporary_tetrahedral_mesh_" + pid.str());
631  std::string output_dir = output_file_handler.GetOutputDirectoryFullPath();
632 
633  // Compute the number of nodes in the TetrahedralMesh
634  unsigned num_tetrahedral_nodes = num_vertex_nodes + num_vertex_elements;
635 
636  // Write node file
637  out_stream p_node_file = output_file_handler.OpenOutputFile(mesh_file_name+".node");
638  (*p_node_file) << std::scientific;
639  (*p_node_file) << std::setprecision(20);
640  (*p_node_file) << num_tetrahedral_nodes << "\t2\t0\t1" << std::endl;
641 
642  // Begin by writing each node in the VertexMesh
643  for (unsigned node_index=0; node_index<num_vertex_nodes; node_index++)
644  {
645  Node<DIM>* p_node = mpMutableVertexMesh->GetNode(node_index);
646 
648  unsigned index = p_node->GetIndex();
649 
650  c_vector<double, DIM> location = p_node->rGetLocation();
651 
652  unsigned is_boundary_node = p_node->IsBoundaryNode() ? 1 : 0;
653 
654  (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl;
655  }
656 
657  // Now write an additional node at each VertexElement's centroid
658  unsigned num_tetrahedral_elements = 0;
659  for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++)
660  {
661  unsigned index = num_vertex_nodes + vertex_elem_index;
662 
663  c_vector<double, DIM> location = mpMutableVertexMesh->GetCentroidOfElement(vertex_elem_index);
664 
665  // Any node located at a VertexElement's centroid will not be a boundary node
666  unsigned is_boundary_node = 0;
667  (*p_node_file) << index << "\t" << location[0] << "\t" << location[1] << "\t" << is_boundary_node << std::endl;
668 
669  // Also keep track of how many tetrahedral elements there will be
670  num_tetrahedral_elements += mpMutableVertexMesh->GetElement(vertex_elem_index)->GetNumNodes();
671  }
672  p_node_file->close();
673 
674  // Write element file
675  out_stream p_elem_file = output_file_handler.OpenOutputFile(mesh_file_name+".ele");
676  (*p_elem_file) << std::scientific;
677  (*p_elem_file) << num_tetrahedral_elements << "\t3\t0" << std::endl;
678 
679  std::set<std::pair<unsigned, unsigned> > tetrahedral_edges;
680 
681  unsigned tetrahedral_elem_index = 0;
682  for (unsigned vertex_elem_index=0; vertex_elem_index<num_vertex_elements; vertex_elem_index++)
683  {
684  VertexElement<DIM, DIM>* p_vertex_element = mpMutableVertexMesh->GetElement(vertex_elem_index);
685 
686  // Iterate over nodes owned by this VertexElement
687  unsigned num_nodes_in_vertex_element = p_vertex_element->GetNumNodes();
688  for (unsigned local_index=0; local_index<num_nodes_in_vertex_element; local_index++)
689  {
690  unsigned node_0_index = p_vertex_element->GetNodeGlobalIndex(local_index);
691  unsigned node_1_index = p_vertex_element->GetNodeGlobalIndex((local_index+1)%num_nodes_in_vertex_element);
692  unsigned node_2_index = num_vertex_nodes + vertex_elem_index;
693 
694  (*p_elem_file) << tetrahedral_elem_index++ << "\t" << node_0_index << "\t" << node_1_index << "\t" << node_2_index << std::endl;
695 
696  // Add edges to the set if they are not already present
697  std::pair<unsigned, unsigned> edge_0 = this->CreateOrderedPair(node_0_index, node_1_index);
698  std::pair<unsigned, unsigned> edge_1 = this->CreateOrderedPair(node_1_index, node_2_index);
699  std::pair<unsigned, unsigned> edge_2 = this->CreateOrderedPair(node_2_index, node_0_index);
700 
701  tetrahedral_edges.insert(edge_0);
702  tetrahedral_edges.insert(edge_1);
703  tetrahedral_edges.insert(edge_2);
704  }
705  }
706  p_elem_file->close();
707 
708  // Write edge file
709  out_stream p_edge_file = output_file_handler.OpenOutputFile(mesh_file_name+".edge");
710  (*p_edge_file) << std::scientific;
711  (*p_edge_file) << tetrahedral_edges.size() << "\t1" << std::endl;
712 
713  unsigned edge_index = 0;
714  for (std::set<std::pair<unsigned, unsigned> >::iterator edge_iter = tetrahedral_edges.begin();
715  edge_iter != tetrahedral_edges.end();
716  ++edge_iter)
717  {
718  std::pair<unsigned, unsigned> this_edge = *edge_iter;
719 
720  // To be a boundary edge both nodes need to be boundary nodes.
721  bool is_boundary_edge = false;
722  if (this_edge.first < mpMutableVertexMesh->GetNumNodes() &&
723  this_edge.second < mpMutableVertexMesh->GetNumNodes())
724  {
725  is_boundary_edge = (mpMutableVertexMesh->GetNode(this_edge.first)->IsBoundaryNode() &&
726  mpMutableVertexMesh->GetNode(this_edge.second)->IsBoundaryNode() );
727  }
728  unsigned is_boundary_edge_unsigned = is_boundary_edge ? 1 : 0;
729 
730  (*p_edge_file) << edge_index++ << "\t" << this_edge.first << "\t" << this_edge.second << "\t" << is_boundary_edge_unsigned << std::endl;
731  }
732  p_edge_file->close();
733 
734  // Having written the mesh to file, now construct it using TrianglesMeshReader
736  // Nested scope so reader is destroyed before we remove the temporary files.
737  {
738  TrianglesMeshReader<DIM, DIM> mesh_reader(output_dir + mesh_file_name);
739  p_mesh->ConstructFromMeshReader(mesh_reader);
740  }
741 
742  // Delete the temporary files
743  output_file_handler.FindFile("").Remove();
744 
745  // The original files have been deleted, it is better if the mesh object forgets about them
747 
748  return p_mesh;
749 }
750 
751 // Explicit instantiation
752 template class VertexBasedCellPopulation<1>;
753 template class VertexBasedCellPopulation<2>;
754 template class VertexBasedCellPopulation<3>;
755 
756 // 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()
virtual void AcceptPopulationCountWriter(boost::shared_ptr< AbstractCellPopulationCountWriter< DIM, DIM > > pPopulationCountWriter)
Definition: Node.hpp:58
unsigned GetNodeGlobalIndex(unsigned localIndex) const
bool IsBoundaryNode() const
Definition: Node.cpp:165
#define EXCEPTION(message)
Definition: Exception.hpp:143
static SimulationTime * Instance()
boost::shared_ptr< AbstractVertexBasedDivisionRule< DIM > > mpVertexBasedDivisionRule
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()
unsigned GetTimeStepsElapsed() const
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
std::string GetOutputDirectoryFullPath() const
boost::shared_ptr< AbstractVertexBasedDivisionRule< DIM > > GetVertexBasedDivisionRule()
bool IsCellAssociatedWithADeletedLocation(CellPtr pCell)
double GetDampingConstant(unsigned nodeIndex)
std::set< unsigned > GetNeighbouringLocationIndices(CellPtr pCell)
unsigned GetRosetteRankOfCell(CellPtr pCell)
MutableVertexMesh< DIM, DIM > & rGetMesh()
static bool IsSequential()
Definition: PetscTools.cpp:91
TetrahedralMesh< DIM, DIM > * GetTetrahedralMeshUsingVertexMesh()
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:668
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
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)
unsigned GetNumNodes() const
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
unsigned GetNewIndex(unsigned oldIndex) const
void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
void SetMeshHasChangedSinceLoading()
void SetNode(unsigned index, ChastePoint< DIM > &rNewLocation)
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:140
void AddCellIdOfT2Swap(unsigned idOfT2Swap)
double GetWidth(const unsigned &rDimension)
c_vector< double, DIM > GetLocationOfCellCentre(CellPtr pCell)
unsigned AddNode(Node< DIM > *pNewNode)
MutableVertexMesh< DIM, DIM > * mpMutableVertexMesh
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
unsigned GetIndex() const
Definition: Node.cpp:159
virtual void AddCellUsingLocationIndex(unsigned index, CellPtr pCell)
CellPtr AddCell(CellPtr pNewCell, const c_vector< double, DIM > &rCellDivisionVector, CellPtr pParentCell=CellPtr())
AbstractMesh< ELEMENT_DIM, SPACE_DIM > & mrMesh
VertexElement< DIM, DIM > * GetElement(unsigned elementIndex)
VertexElement< DIM, DIM > * GetElementCorrespondingToCell(CellPtr pCell)