Chaste  Release::2018.1
VertexMesh.cpp
1 /*
2 
3 Copyright (c) 2005-2018, 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 "VertexMesh.hpp"
37 #include "RandomNumberGenerator.hpp"
38 #include "UblasCustomFunctions.hpp"
39 
40 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
42  std::vector<VertexElement<ELEMENT_DIM, SPACE_DIM>*> vertexElements)
43  : mpDelaunayMesh(nullptr)
44 {
45 
46  // Reset member variables and clear mNodes and mElements
47  Clear();
48 
49  // Populate mNodes and mElements
50  for (unsigned node_index = 0; node_index < nodes.size(); node_index++)
51  {
52  Node<SPACE_DIM>* p_temp_node = nodes[node_index];
53  this->mNodes.push_back(p_temp_node);
54  }
55  for (unsigned elem_index = 0; elem_index < vertexElements.size(); elem_index++)
56  {
57  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_temp_vertex_element = vertexElements[elem_index];
58  mElements.push_back(p_temp_vertex_element);
59  }
60 
61  // In 3D, populate mFaces
62  if (SPACE_DIM == 3)
63  {
64  // Use a std::set to keep track of which faces have been added to mFaces
65  std::set<unsigned> faces_counted;
66 
67  // Loop over mElements
68  for (unsigned elem_index = 0; elem_index < mElements.size(); elem_index++)
69  {
70  // Loop over faces of this element
71  for (unsigned face_index = 0; face_index < mElements[elem_index]->GetNumFaces(); face_index++)
72  {
73  VertexElement<ELEMENT_DIM - 1, SPACE_DIM>* p_face = mElements[elem_index]->GetFace(face_index);
74  unsigned global_index = p_face->GetIndex();
75 
76  // If this face is not already contained in mFaces, add it, and update faces_counted
77  if (faces_counted.find(global_index) == faces_counted.end())
78  {
79  mFaces.push_back(p_face);
80  faces_counted.insert(global_index);
81  }
82  }
83  }
84  }
85 
86  // Register elements with nodes
87  for (unsigned index = 0; index < mElements.size(); index++)
88  {
90 
91  unsigned element_index = p_element->GetIndex();
92  unsigned num_nodes_in_element = p_element->GetNumNodes();
93 
94  for (unsigned node_index = 0; node_index < num_nodes_in_element; node_index++)
95  {
96  p_element->GetNode(node_index)->AddElement(element_index);
97  }
98  }
99 
100  this->mMeshChangesDuringSimulation = false;
101 }
102 
103 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
105  std::vector<VertexElement<ELEMENT_DIM - 1, SPACE_DIM>*> faces,
106  std::vector<VertexElement<ELEMENT_DIM, SPACE_DIM>*> vertexElements)
107  : mpDelaunayMesh(nullptr)
108 {
109  // Reset member variables and clear mNodes, mFaces and mElements
110  Clear();
111 
112  // Populate mNodes mFaces and mElements
113  for (unsigned node_index = 0; node_index < nodes.size(); node_index++)
114  {
115  Node<SPACE_DIM>* p_temp_node = nodes[node_index];
116  this->mNodes.push_back(p_temp_node);
117  }
118 
119  for (unsigned face_index = 0; face_index < faces.size(); face_index++)
120  {
121  VertexElement<ELEMENT_DIM - 1, SPACE_DIM>* p_temp_face = faces[face_index];
122  mFaces.push_back(p_temp_face);
123  }
124 
125  for (unsigned elem_index = 0; elem_index < vertexElements.size(); elem_index++)
126  {
127  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_temp_vertex_element = vertexElements[elem_index];
128  mElements.push_back(p_temp_vertex_element);
129  }
130 
131  // Register elements with nodes
132  for (unsigned index = 0; index < mElements.size(); index++)
133  {
134  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_temp_vertex_element = mElements[index];
135  for (unsigned node_index = 0; node_index < p_temp_vertex_element->GetNumNodes(); node_index++)
136  {
137  Node<SPACE_DIM>* p_temp_node = p_temp_vertex_element->GetNode(node_index);
138  p_temp_node->AddElement(p_temp_vertex_element->GetIndex());
139  }
140  }
141 
142  this->mMeshChangesDuringSimulation = false;
143 }
144 
149 template <>
151  : mpDelaunayMesh(&rMesh)
152 {
153  //Note !isPeriodic is not used except through polymorphic calls in rMesh
154 
155  // Reset member variables and clear mNodes, mFaces and mElements
156  Clear();
157 
158  unsigned num_elements = mpDelaunayMesh->GetNumAllNodes();
159  unsigned num_nodes = mpDelaunayMesh->GetNumAllElements();
160 
161  // Allocate memory for mNodes and mElements
162  this->mNodes.reserve(num_nodes);
163 
164  // Create as many elements as there are nodes in the mesh
165  mElements.reserve(num_elements);
166  for (unsigned elem_index = 0; elem_index < num_elements; elem_index++)
167  {
168  VertexElement<2, 2>* p_element = new VertexElement<2, 2>(elem_index);
169  mElements.push_back(p_element);
170  }
171 
172  // Populate mNodes
174 
175  // Loop over elements of the Delaunay mesh (which are nodes/vertices of this mesh)
176  for (unsigned i = 0; i < num_nodes; i++)
177  {
178  // Loop over nodes owned by this triangular element in the Delaunay mesh
179  // Add this node/vertex to each of the 3 vertex elements
180  for (unsigned local_index = 0; local_index < 3; local_index++)
181  {
182  unsigned elem_index = mpDelaunayMesh->GetElement(i)->GetNodeGlobalIndex(local_index);
183  unsigned num_nodes_in_elem = mElements[elem_index]->GetNumNodes();
184  unsigned end_index = num_nodes_in_elem > 0 ? num_nodes_in_elem - 1 : 0;
185 
186  mElements[elem_index]->AddNode(this->mNodes[i], end_index);
187  }
188  }
189 
190  // Reorder mNodes anticlockwise
191  for (unsigned elem_index = 0; elem_index < mElements.size(); elem_index++)
192  {
198  std::vector<std::pair<double, unsigned> > index_angle_list;
199  for (unsigned local_index = 0; local_index < mElements[elem_index]->GetNumNodes(); local_index++)
200  {
201  c_vector<double, 2> vectorA = mpDelaunayMesh->GetNode(elem_index)->rGetLocation();
202  c_vector<double, 2> vectorB = mElements[elem_index]->GetNodeLocation(local_index);
203  c_vector<double, 2> centre_to_vertex = mpDelaunayMesh->GetVectorFromAtoB(vectorA, vectorB);
204 
205  double angle = atan2(centre_to_vertex(1), centre_to_vertex(0));
206  unsigned global_index = mElements[elem_index]->GetNodeGlobalIndex(local_index);
207 
208  std::pair<double, unsigned> pair(angle, global_index);
209  index_angle_list.push_back(pair);
210  }
211 
212  // Sort the list in order of increasing angle
213  sort(index_angle_list.begin(), index_angle_list.end());
214 
215  // Create a new Voronoi element and pass in the appropriate Nodes, ordered anticlockwise
216  VertexElement<2, 2>* p_new_element = new VertexElement<2, 2>(elem_index);
217  for (unsigned count = 0; count < index_angle_list.size(); count++)
218  {
219  unsigned local_index = count > 1 ? count - 1 : 0;
220  p_new_element->AddNode(mNodes[index_angle_list[count].second], local_index);
221  }
222 
223  // Replace the relevant member of mElements with this Voronoi element
224  delete mElements[elem_index];
225  mElements[elem_index] = p_new_element;
226  }
227 
228  this->mMeshChangesDuringSimulation = false;
229 }
239 template <>
241  : mpDelaunayMesh(&rMesh)
242 {
243  // Reset member variables and clear mNodes, mFaces and mElements
244  Clear();
245 
246  unsigned num_nodes = mpDelaunayMesh->GetNumAllElements();
247 
248  // Allocate memory for mNodes
249  this->mNodes.reserve(num_nodes);
250 
251  // Populate mNodes
253 
254  std::map<unsigned, VertexElement<3, 3>*> index_element_map;
255  unsigned face_index = 0;
256  unsigned element_index = 0;
257 
258  // Loop over each edge of the Delaunay mesh and populate mFaces and mElements
259  for (TetrahedralMesh<3, 3>::EdgeIterator edge_iterator = mpDelaunayMesh->EdgesBegin();
260  edge_iterator != mpDelaunayMesh->EdgesEnd();
261  ++edge_iterator)
262  {
263  Node<3>* p_node_a = edge_iterator.GetNodeA();
264  Node<3>* p_node_b = edge_iterator.GetNodeB();
265 
266  if (!(p_node_a->IsBoundaryNode() && p_node_b->IsBoundaryNode()))
267  {
268  std::set<unsigned>& node_a_element_indices = p_node_a->rGetContainingElementIndices();
269  std::set<unsigned>& node_b_element_indices = p_node_b->rGetContainingElementIndices();
270  std::set<unsigned> edge_element_indices;
271 
272  std::set_intersection(node_a_element_indices.begin(),
273  node_a_element_indices.end(),
274  node_b_element_indices.begin(),
275  node_b_element_indices.end(),
276  std::inserter(edge_element_indices, edge_element_indices.begin()));
277 
278  c_vector<double, 3> edge_vector;
279  edge_vector = p_node_b->rGetLocation() - p_node_a->rGetLocation();
280 
281  c_vector<double, 3> mid_edge;
282  mid_edge = edge_vector * 0.5 + p_node_a->rGetLocation();
283 
284  unsigned element0_index = *(edge_element_indices.begin());
285 
286  c_vector<double, 3> basis_vector1;
287  basis_vector1 = mNodes[element0_index]->rGetLocation() - mid_edge;
288 
289  c_vector<double, 3> basis_vector2;
290  basis_vector2 = VectorProduct(edge_vector, basis_vector1);
291 
297  std::vector<std::pair<double, unsigned> > index_angle_list;
298 
299  // Loop over each element containing this edge (i.e. those containing both nodes of the edge)
300  for (std::set<unsigned>::iterator index_iter = edge_element_indices.begin();
301  index_iter != edge_element_indices.end();
302  ++index_iter)
303  {
304  // Calculate angle
305  c_vector<double, 3> vertex_vector = mNodes[*index_iter]->rGetLocation() - mid_edge;
306 
307  double local_vertex_dot_basis_vector1 = inner_prod(vertex_vector, basis_vector1);
308  double local_vertex_dot_basis_vector2 = inner_prod(vertex_vector, basis_vector2);
309 
310  double angle = atan2(local_vertex_dot_basis_vector2, local_vertex_dot_basis_vector1);
311 
312  std::pair<double, unsigned> pair(angle, *index_iter);
313  index_angle_list.push_back(pair);
314  }
315 
316  // Sort the list in order of increasing angle
317  sort(index_angle_list.begin(), index_angle_list.end());
318 
319  // Create face
320  VertexElement<2, 3>* p_face = new VertexElement<2, 3>(face_index);
321  face_index++;
322  for (unsigned count = 0; count < index_angle_list.size(); count++)
323  {
324  unsigned local_index = count > 1 ? count - 1 : 0;
325  p_face->AddNode(mNodes[index_angle_list[count].second], local_index);
326  }
327 
328  // Add face to list of faces
329  mFaces.push_back(p_face);
330 
331  // Add face to appropriate elements
332  if (!p_node_a->IsBoundaryNode())
333  {
334  unsigned node_a_index = p_node_a->GetIndex();
335  if (index_element_map[node_a_index])
336  {
337  // If there is already an element with this index, add the face to it...
338  index_element_map[node_a_index]->AddFace(p_face);
339  }
340  else
341  {
342  // ...otherwise create an element, add the face to it, and add to the map
343  mVoronoiElementIndexMap[node_a_index] = element_index;
344  VertexElement<3, 3>* p_element = new VertexElement<3, 3>(element_index);
345  element_index++;
346  p_element->AddFace(p_face);
347  index_element_map[node_a_index] = p_element;
348  }
349  }
350  if (!p_node_b->IsBoundaryNode())
351  {
352  unsigned node_b_index = p_node_b->GetIndex();
353  if (index_element_map[node_b_index])
354  {
355  // If there is already an element with this index, add the face to it...
356  index_element_map[node_b_index]->AddFace(p_face);
357  }
358  else
359  {
360  // ...otherwise create an element, add the face to it, and add to the map
361  mVoronoiElementIndexMap[node_b_index] = element_index;
362  VertexElement<3, 3>* p_element = new VertexElement<3, 3>(element_index);
363  element_index++;
364  p_element->AddFace(p_face);
365  index_element_map[node_b_index] = p_element;
366  }
367  }
368  }
369  }
370 
371  // Populate mElements
372  unsigned elem_count = 0;
373  for (std::map<unsigned, VertexElement<3, 3>*>::iterator element_iter = index_element_map.begin();
374  element_iter != index_element_map.end();
375  ++element_iter)
376  {
377  mElements.push_back(element_iter->second);
378  mVoronoiElementIndexMap[element_iter->first] = elem_count;
379  elem_count++;
380  }
381 
382  this->mMeshChangesDuringSimulation = false;
383 }
389 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
391 {
392  c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
393  c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
394  double jacobian_det;
395 
396  // Loop over elements of the Delaunay mesh and populate mNodes
397  for (unsigned i = 0; i < rMesh.GetNumElements(); i++)
398  {
399  // Calculate the circumcentre of this element in the Delaunay mesh
400  rMesh.GetInverseJacobianForElement(i, jacobian, jacobian_det, inverse_jacobian);
401  c_vector<double, SPACE_DIM + 1> circumsphere = rMesh.GetElement(i)->CalculateCircumsphere(jacobian, inverse_jacobian);
402 
403  c_vector<double, SPACE_DIM> circumcentre;
404  for (unsigned j = 0; j < SPACE_DIM; j++)
405  {
406  circumcentre(j) = circumsphere(j);
407  }
408 
409  // Create a node in the Voronoi mesh at the location of this circumcentre
410  this->mNodes.push_back(new Node<SPACE_DIM>(i, circumcentre));
411  }
412 }
413 
414 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
415 double VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetEdgeLength(unsigned elementIndex1, unsigned elementIndex2)
416 {
417  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
418 
419  std::set<unsigned> node_indices_1;
420  for (unsigned i = 0; i < mElements[elementIndex1]->GetNumNodes(); i++)
421  {
422  node_indices_1.insert(mElements[elementIndex1]->GetNodeGlobalIndex(i));
423  }
424  std::set<unsigned> node_indices_2;
425  for (unsigned i = 0; i < mElements[elementIndex2]->GetNumNodes(); i++)
426  {
427  node_indices_2.insert(mElements[elementIndex2]->GetNodeGlobalIndex(i));
428  }
429 
430  std::set<unsigned> shared_nodes;
431  std::set_intersection(node_indices_1.begin(), node_indices_1.end(),
432  node_indices_2.begin(), node_indices_2.end(),
433  std::inserter(shared_nodes, shared_nodes.begin()));
434 
435  if (shared_nodes.size() == 1)
436  {
437  // It's possible that these two elements are actually infinite but are on the edge of the domain
438  EXCEPTION("Elements " << elementIndex1 << " and " << elementIndex2 << " share only one node.");
439  }
440  assert(shared_nodes.size() == 2);
441 
442  unsigned index1 = *(shared_nodes.begin());
443  unsigned index2 = *(++(shared_nodes.begin()));
444 
445  double edge_length = this->GetDistanceBetweenNodes(index1, index2);
446  return edge_length;
447 }
448 
449 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
451 {
452  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
453 
454  c_vector<double, 3> moments = CalculateMomentsOfElement(index);
455 
456  double discriminant = sqrt((moments(0) - moments(1)) * (moments(0) - moments(1)) + 4.0 * moments(2) * moments(2));
457 
458  // Note that as the matrix of second moments of area is symmetric, both its eigenvalues are real
459  double largest_eigenvalue = (moments(0) + moments(1) + discriminant) * 0.5;
460  double smallest_eigenvalue = (moments(0) + moments(1) - discriminant) * 0.5;
461 
462  double elongation_shape_factor = sqrt(largest_eigenvalue / smallest_eigenvalue);
463  return elongation_shape_factor;
464 }
465 
466 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
468 {
469  mpDelaunayMesh = nullptr;
470  this->mMeshChangesDuringSimulation = false;
471  Clear();
472 }
473 
474 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
476 {
477  Clear();
478 }
479 
480 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
482 {
483  assert(index < this->mNodes.size());
484  return index;
485 }
486 
487 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
489 {
490  assert(index < this->mElements.size());
491  return index;
492 }
493 
494 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
496 {
498  // assert(index < this->mBoundaryElements.size() );
499  return index;
500 }
501 
502 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
504 {
505  unsigned node_index = UNSIGNED_UNSET;
506 
507  if (mVoronoiElementIndexMap.empty())
508  {
509  node_index = elementIndex;
510  }
511  else
512  {
513  for (std::map<unsigned, unsigned>::iterator iter = mVoronoiElementIndexMap.begin();
514  iter != mVoronoiElementIndexMap.end();
515  ++iter)
516  {
517  if (iter->second == elementIndex)
518  {
519  node_index = iter->first;
520  break;
521  }
522  }
523  }
524  assert(node_index != UNSIGNED_UNSET);
525  return node_index;
526 }
527 
528 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
530 {
531  unsigned element_index = UNSIGNED_UNSET;
532 
533  if (mVoronoiElementIndexMap.empty())
534  {
535  element_index = nodeIndex;
536  }
537  else
538  {
539  std::map<unsigned, unsigned>::iterator iter = mVoronoiElementIndexMap.find(nodeIndex);
540 
541  if (iter == mVoronoiElementIndexMap.end())
542  {
543  EXCEPTION("This index does not correspond to a VertexElement");
544  }
545  else
546  {
547  element_index = iter->second;
548  }
549  }
550  assert(element_index != UNSIGNED_UNSET);
551  return element_index;
552 }
553 
554 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
556 {
557  assert(SPACE_DIM == 2 || SPACE_DIM == 3); // LCOV_EXCL_LINE - code will be removed at compile time
558 
559  // Get pointer to this element
560  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
561 
562  // Loop over nodes in the current element and find which is contained in the most elements
563  unsigned rosette_rank = 0;
564  for (unsigned node_idx = 0; node_idx < p_element->GetNumNodes(); node_idx++)
565  {
566  unsigned num_elems_this_node = p_element->GetNode(node_idx)->rGetContainingElementIndices().size();
567 
568  if (num_elems_this_node > rosette_rank)
569  {
570  rosette_rank = num_elems_this_node;
571  }
572  }
573 
574  // Return the rosette rank
575  return rosette_rank;
576 }
577 
578 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
580 {
581  // Delete elements
582  for (unsigned i = 0; i < mElements.size(); i++)
583  {
584  delete mElements[i];
585  }
586  mElements.clear();
587 
588  // Delete faces
589  for (unsigned i = 0; i < mFaces.size(); i++)
590  {
591  delete mFaces[i];
592  }
593  mFaces.clear();
594 
595  // Delete nodes
596  for (unsigned i = 0; i < this->mNodes.size(); i++)
597  {
598  delete this->mNodes[i];
599  }
600  this->mNodes.clear();
601 }
602 
603 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
605 {
606  return this->mNodes.size();
607 }
608 
609 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
611 {
612  return mElements.size();
613 }
614 
615 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
617 {
618  return mElements.size();
619 }
620 
621 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
623 {
624  return mFaces.size();
625 }
626 
627 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
629 {
630  assert(index < mElements.size());
631  return mElements[index];
632 }
633 
634 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
635 VertexElement<ELEMENT_DIM - 1, SPACE_DIM>* VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetFace(unsigned index) const
636 {
637  assert(index < mFaces.size());
638  return mFaces[index];
639 }
640 
641 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
642 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetCentroidOfElement(unsigned index)
643 {
644  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
645  unsigned num_nodes = p_element->GetNumNodes();
646 
647  c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM);
648 
649  switch (SPACE_DIM)
650  {
651  case 1:
652  {
653  centroid = 0.5 * (p_element->GetNodeLocation(0) + p_element->GetNodeLocation(1));
654  }
655  break;
656  case 2:
657  {
658  double centroid_x = 0;
659  double centroid_y = 0;
660 
661  // Note that we cannot use GetVolumeOfElement() below as it returns the absolute, rather than signed, area
662  double element_signed_area = 0.0;
663 
664  // Map the first vertex to the origin and employ GetVectorFromAtoB() to allow for periodicity
665  c_vector<double, SPACE_DIM> first_node_location = p_element->GetNodeLocation(0);
666  c_vector<double, SPACE_DIM> pos_1 = zero_vector<double>(SPACE_DIM);
667 
668  // Loop over vertices
669  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
670  {
671  c_vector<double, SPACE_DIM> next_node_location = p_element->GetNodeLocation((local_index + 1) % num_nodes);
672  c_vector<double, SPACE_DIM> pos_2 = GetVectorFromAtoB(first_node_location, next_node_location);
673 
674  double this_x = pos_1[0];
675  double this_y = pos_1[1];
676  double next_x = pos_2[0];
677  double next_y = pos_2[1];
678 
679  double signed_area_term = this_x * next_y - this_y * next_x;
680 
681  centroid_x += (this_x + next_x) * signed_area_term;
682  centroid_y += (this_y + next_y) * signed_area_term;
683  element_signed_area += 0.5 * signed_area_term;
684 
685  pos_1 = pos_2;
686  }
687 
688  assert(element_signed_area != 0.0);
689 
690  // Finally, map back and employ GetVectorFromAtoB() to allow for periodicity
691  centroid = first_node_location;
692  centroid(0) += centroid_x / (6.0 * element_signed_area);
693  centroid(1) += centroid_y / (6.0 * element_signed_area);
694  }
695  break;
696  case 3:
697  {
699  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
700  {
701  centroid += p_element->GetNodeLocation(local_index);
702  }
703  centroid /= ((double)num_nodes);
704  }
705  break;
706  default:
708  }
709  return centroid;
710 }
711 
712 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
714 {
715  // Create a set of neighbouring node indices
716  std::set<unsigned> neighbouring_node_indices;
717 
718  // Find the indices of the elements owned by this node
719  std::set<unsigned> containing_elem_indices = this->GetNode(nodeIndex)->rGetContainingElementIndices();
720 
721  // Iterate over these elements
722  for (std::set<unsigned>::iterator elem_iter = containing_elem_indices.begin();
723  elem_iter != containing_elem_indices.end();
724  ++elem_iter)
725  {
726  // Find the local index of this node in this element
727  unsigned local_index = GetElement(*elem_iter)->GetNodeLocalIndex(nodeIndex);
728 
729  // Find the global indices of the preceding and successive nodes in this element
730  unsigned num_nodes = GetElement(*elem_iter)->GetNumNodes();
731  unsigned previous_local_index = (local_index + num_nodes - 1) % num_nodes;
732  unsigned next_local_index = (local_index + 1) % num_nodes;
733 
734  // Add the global indices of these two nodes to the set of neighbouring node indices
735  neighbouring_node_indices.insert(GetElement(*elem_iter)->GetNodeGlobalIndex(previous_local_index));
736  neighbouring_node_indices.insert(GetElement(*elem_iter)->GetNodeGlobalIndex(next_local_index));
737  }
738 
739  return neighbouring_node_indices;
740 }
741 
742 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
743 std::set<unsigned> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNeighbouringNodeNotAlsoInElement(unsigned nodeIndex, unsigned elemIndex)
744 {
745  // Get a pointer to this element
746  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elemIndex);
747 
748  // Get the indices of the nodes contained in this element
749  std::set<unsigned> node_indices_in_this_element;
750  for (unsigned local_index = 0; local_index < p_element->GetNumNodes(); local_index++)
751  {
752  unsigned global_index = p_element->GetNodeGlobalIndex(local_index);
753  node_indices_in_this_element.insert(global_index);
754  }
755 
756  // Check that the node is in fact contained in the element
757  if (node_indices_in_this_element.find(nodeIndex) == node_indices_in_this_element.end())
758  {
759  EXCEPTION("The given node is not contained in the given element.");
760  }
761 
762  // Create a set of neighbouring node indices
763  std::set<unsigned> neighbouring_node_indices_not_in_this_element;
764 
765  // Get the indices of this node's neighbours
766  std::set<unsigned> node_neighbours = GetNeighbouringNodeIndices(nodeIndex);
767 
768  // Check if each neighbour is also in this element; if not, add it to the set
769  for (std::set<unsigned>::iterator iter = node_neighbours.begin();
770  iter != node_neighbours.end();
771  ++iter)
772  {
773  if (node_indices_in_this_element.find(*iter) == node_indices_in_this_element.end())
774  {
775  neighbouring_node_indices_not_in_this_element.insert(*iter);
776  }
777  }
778 
779  return neighbouring_node_indices_not_in_this_element;
780 }
781 
782 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
784 {
785  // Get a pointer to this element
786  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elementIndex);
787 
788  // Create a set of neighbouring element indices
789  std::set<unsigned> neighbouring_element_indices;
790 
791  // Loop over nodes owned by this element
792  for (unsigned local_index = 0; local_index < p_element->GetNumNodes(); local_index++)
793  {
794  // Get a pointer to this node
795  Node<SPACE_DIM>* p_node = p_element->GetNode(local_index);
796 
797  // Find the indices of the elements owned by this node
798  std::set<unsigned> containing_elem_indices = p_node->rGetContainingElementIndices();
799 
800  // Form the union of this set with the current set of neighbouring element indices
801  std::set<unsigned> all_elements;
802  std::set_union(neighbouring_element_indices.begin(), neighbouring_element_indices.end(),
803  containing_elem_indices.begin(), containing_elem_indices.end(),
804  std::inserter(all_elements, all_elements.begin()));
805 
806  // Update the set of neighbouring element indices
807  neighbouring_element_indices = all_elements;
808  }
809 
810  // Lastly remove this element's index from the set of neighbouring element indices
811  neighbouring_element_indices.erase(elementIndex);
812 
813  return neighbouring_element_indices;
814 }
815 
816 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
818 {
819  return this;
820 }
821 
823 template <>
826 {
827  EXCEPTION("VertexMesh<1,1>::ConstructFromMeshReader() is not implemented");
828 }
829 
831 template <>
834 {
835  EXCEPTION("VertexMesh<1,2>::ConstructFromMeshReader() is not implemented");
836 }
837 
839 template <>
842 {
843  EXCEPTION("VertexMesh<1,3>::ConstructFromMeshReader() is not implemented");
844 }
845 
847 template <>
850 {
851  EXCEPTION("VertexMesh<2,3>::ConstructFromMeshReader() is not implemented");
852 }
853 
855 template <>
858 {
859  assert(rMeshReader.HasNodePermutation() == false);
860  // Store numbers of nodes and elements
861  unsigned num_nodes = rMeshReader.GetNumNodes();
862  unsigned num_elements = rMeshReader.GetNumElements();
863 
864  // Reserve memory for nodes
865  this->mNodes.reserve(num_nodes);
866 
867  rMeshReader.Reset();
868 
869  // Add nodes
870  std::vector<double> node_data;
871  for (unsigned i = 0; i < num_nodes; i++)
872  {
873  node_data = rMeshReader.GetNextNode();
874  unsigned is_boundary_node = (bool)node_data[2];
875  node_data.pop_back();
876  this->mNodes.push_back(new Node<2>(i, node_data, is_boundary_node));
877  }
878 
879  rMeshReader.Reset();
880 
881  // Reserve memory for elements
882  mElements.reserve(rMeshReader.GetNumElements());
883 
884  // Add elements
885  for (unsigned elem_index = 0; elem_index < num_elements; elem_index++)
886  {
887  // Get the data for this element
888  ElementData element_data = rMeshReader.GetNextElementData();
889 
890  // Get the nodes owned by this element
891  std::vector<Node<2>*> nodes;
892  unsigned num_nodes_in_element = element_data.NodeIndices.size();
893  for (unsigned j = 0; j < num_nodes_in_element; j++)
894  {
895  assert(element_data.NodeIndices[j] < this->mNodes.size());
896  nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
897  }
898 
899  // Use nodes and index to construct this element
900  VertexElement<2, 2>* p_element = new VertexElement<2, 2>(elem_index, nodes);
901  mElements.push_back(p_element);
902 
903  if (rMeshReader.GetNumElementAttributes() > 0)
904  {
905  assert(rMeshReader.GetNumElementAttributes() == 1);
906  unsigned attribute_value = (unsigned)element_data.AttributeValue;
907  p_element->SetAttribute(attribute_value);
908  }
909  }
910 }
911 
913 template <>
916 {
917  assert(rMeshReader.HasNodePermutation() == false);
918 
919  // Store numbers of nodes and elements
920  unsigned num_nodes = rMeshReader.GetNumNodes();
921  unsigned num_elements = rMeshReader.GetNumElements();
922 
923  // Reserve memory for nodes
924  this->mNodes.reserve(num_nodes);
925 
926  rMeshReader.Reset();
927 
928  // Add nodes
929  std::vector<double> node_data;
930  for (unsigned i = 0; i < num_nodes; i++)
931  {
932  node_data = rMeshReader.GetNextNode();
933  unsigned is_boundary_node = (bool)node_data[3];
934  node_data.pop_back();
935  this->mNodes.push_back(new Node<3>(i, node_data, is_boundary_node));
936  }
937 
938  rMeshReader.Reset();
939 
940  // Reserve memory for nodes
941  mElements.reserve(rMeshReader.GetNumElements());
942 
943  // Use a std::set to keep track of which faces have been added to mFaces
944  std::set<unsigned> faces_counted;
945 
946  // Add elements
947  for (unsigned elem_index = 0; elem_index < num_elements; elem_index++)
948  {
950  typedef VertexMeshReader<3, 3> VERTEX_MESH_READER;
951  assert(dynamic_cast<VERTEX_MESH_READER*>(&rMeshReader) != nullptr);
952 
953  // Get the data for this element
954  VertexElementData element_data = static_cast<VERTEX_MESH_READER*>(&rMeshReader)->GetNextElementDataWithFaces();
955 
956  // Get the nodes owned by this element
957  std::vector<Node<3>*> nodes;
958  unsigned num_nodes_in_element = element_data.NodeIndices.size();
959  for (unsigned j = 0; j < num_nodes_in_element; j++)
960  {
961  assert(element_data.NodeIndices[j] < this->mNodes.size());
962  nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
963  }
964 
965  // Get the faces owned by this element
966  std::vector<VertexElement<2, 3>*> faces;
967  unsigned num_faces_in_element = element_data.Faces.size();
968  for (unsigned i = 0; i < num_faces_in_element; i++)
969  {
970  // Get the data for this face
971  ElementData face_data = element_data.Faces[i];
972 
973  // Get the face index
974  unsigned face_index = (unsigned)face_data.AttributeValue;
975 
976  // Get the nodes owned by this face
977  std::vector<Node<3>*> nodes_in_face;
978  unsigned num_nodes_in_face = face_data.NodeIndices.size();
979  for (unsigned j = 0; j < num_nodes_in_face; j++)
980  {
981  assert(face_data.NodeIndices[j] < this->mNodes.size());
982  nodes_in_face.push_back(this->mNodes[face_data.NodeIndices[j]]);
983  }
984 
985  // If this face index is not already encountered, create a new face and update faces_counted...
986  if (faces_counted.find(face_index) == faces_counted.end())
987  {
988  // Use nodes and index to construct this face
989  VertexElement<2, 3>* p_face = new VertexElement<2, 3>(face_index, nodes_in_face);
990  mFaces.push_back(p_face);
991  faces_counted.insert(face_index);
992  faces.push_back(p_face);
993  }
994  else
995  {
996  // ... otherwise use the member of mFaces with this index
997  bool face_added = false;
998  for (unsigned k = 0; k < mFaces.size(); k++)
999  {
1000  if (mFaces[k]->GetIndex() == face_index)
1001  {
1002  faces.push_back(mFaces[k]);
1003  face_added = true;
1004  break;
1005  }
1006  }
1007  UNUSED_OPT(face_added);
1008  assert(face_added == true);
1009  }
1010  }
1011 
1013  std::vector<bool> orientations = std::vector<bool>(num_faces_in_element, true);
1014 
1015  // Use faces and index to construct this element
1016  VertexElement<3, 3>* p_element = new VertexElement<3, 3>(elem_index, faces, orientations, nodes);
1017  mElements.push_back(p_element);
1018 
1019  if (rMeshReader.GetNumElementAttributes() > 0)
1020  {
1021  assert(rMeshReader.GetNumElementAttributes() == 1);
1022  unsigned attribute_value = element_data.AttributeValue;
1023  p_element->SetAttribute(attribute_value);
1024  }
1025  }
1026 }
1027 
1028 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1030  const c_vector<double, SPACE_DIM>& rLocationA, const c_vector<double, SPACE_DIM>& rLocationB)
1031 {
1032  c_vector<double, SPACE_DIM> vector;
1033  if (mpDelaunayMesh)
1034  {
1035  vector = mpDelaunayMesh->GetVectorFromAtoB(rLocationA, rLocationB);
1036  }
1037  else
1038  {
1039  vector = AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetVectorFromAtoB(rLocationA, rLocationB);
1040  }
1041  return vector;
1042 }
1043 
1044 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1046 {
1047  assert(SPACE_DIM == 2 || SPACE_DIM == 3); // LCOV_EXCL_LINE - code will be removed at compile time
1048 
1049  // Get pointer to this element
1050  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
1051 
1052  double element_volume = 0.0;
1053  if (SPACE_DIM == 2)
1054  {
1055  // We map the first vertex to the origin and employ GetVectorFromAtoB() to allow for periodicity
1056  c_vector<double, SPACE_DIM> first_node_location = p_element->GetNodeLocation(0);
1057  c_vector<double, SPACE_DIM> pos_1 = zero_vector<double>(SPACE_DIM);
1058 
1059  unsigned num_nodes = p_element->GetNumNodes();
1060  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
1061  {
1062  c_vector<double, SPACE_DIM> next_node_location = p_element->GetNodeLocation((local_index + 1) % num_nodes);
1063  c_vector<double, SPACE_DIM> pos_2 = GetVectorFromAtoB(first_node_location, next_node_location);
1064 
1065  double this_x = pos_1[0];
1066  double this_y = pos_1[1];
1067  double next_x = pos_2[0];
1068  double next_y = pos_2[1];
1069 
1070  element_volume += 0.5 * (this_x * next_y - next_x * this_y);
1071 
1072  pos_1 = pos_2;
1073  }
1074  }
1075  else
1076  {
1077  // Loop over faces and add up pyramid volumes
1078  c_vector<double, SPACE_DIM> pyramid_apex = p_element->GetNodeLocation(0);
1079  for (unsigned face_index = 0; face_index < p_element->GetNumFaces(); face_index++)
1080  {
1081  // Get pointer to face
1082  VertexElement<ELEMENT_DIM - 1, SPACE_DIM>* p_face = p_element->GetFace(face_index);
1083 
1084  // Calculate the area of the face and get unit normal to this face
1085  c_vector<double, SPACE_DIM> unit_normal;
1086  double face_area = CalculateUnitNormalToFaceWithArea(p_face, unit_normal);
1087 
1088  // Calculate the perpendicular distance from the plane of the face to the chosen apex
1089  c_vector<double, SPACE_DIM> base_to_apex = GetVectorFromAtoB(p_face->GetNodeLocation(0), pyramid_apex);
1090  double perpendicular_distance = fabs(inner_prod(base_to_apex, unit_normal));
1091 
1092  // Use these to calculate the volume of the pyramid formed by the face and the point pyramid_apex
1093  element_volume += face_area * perpendicular_distance / 3;
1094  }
1095  }
1096 
1097  // We take the absolute value just in case the nodes were really oriented clockwise
1098  return fabs(element_volume);
1099 }
1100 
1101 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1103 {
1104  assert(SPACE_DIM == 2 || SPACE_DIM == 3); // LCOV_EXCL_LINE - code will be removed at compile time
1105 
1106  // Get pointer to this element
1107  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
1108 
1109  double surface_area = 0.0;
1110  if (SPACE_DIM == 2)
1111  {
1112  unsigned num_nodes = p_element->GetNumNodes();
1113  unsigned this_node_index = p_element->GetNodeGlobalIndex(0);
1114  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
1115  {
1116  unsigned next_node_index = p_element->GetNodeGlobalIndex((local_index + 1) % num_nodes);
1117 
1118  surface_area += this->GetDistanceBetweenNodes(this_node_index, next_node_index);
1119  this_node_index = next_node_index;
1120  }
1121  }
1122  else
1123  {
1124  // Loop over faces and add up areas
1125  for (unsigned face_index = 0; face_index < p_element->GetNumFaces(); face_index++)
1126  {
1127  surface_area += CalculateAreaOfFace(p_element->GetFace(face_index));
1128  }
1129  }
1130  return surface_area;
1131 }
1132 
1134 // 2D-specific methods //
1136 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1137 bool VertexMesh<ELEMENT_DIM, SPACE_DIM>::ElementIncludesPoint(const c_vector<double, SPACE_DIM>& rTestPoint, unsigned elementIndex)
1138 {
1139  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1140  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE - code will be removed at compile time
1141 
1142  // Get the element
1143  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(elementIndex);
1144  unsigned num_nodes = p_element->GetNumNodes();
1145 
1146  // Initialise boolean
1147  bool element_includes_point = false;
1148 
1150  // // Initialise boolean
1151  // bool element_includes_point = true;
1152  //
1153  // unsigned winding_number = 0;
1154  //
1155  // c_vector<double, SPACE_DIM> first_node_location = p_element->GetNodeLocation(0);
1156  // c_vector<double, SPACE_DIM> test_point = this->GetVectorFromAtoB(first_node_location, rTestPoint);
1157  // c_vector<double, SPACE_DIM> this_node_location = zero_vector<double>(SPACE_DIM);
1158  //
1159  // // Loop over edges of the element
1160  // for (unsigned local_index=0; local_index<num_nodes; local_index++)
1161  // {
1162  // c_vector<double, SPACE_DIM> untransformed_vector = p_element->GetNodeLocation((local_index+1)%num_nodes);
1163  // c_vector<double, SPACE_DIM> next_node_location = this->GetVectorFromAtoB(first_node_location, untransformed_vector);
1164  //
1165  // // If this edge is crossing upward...
1166  // if (this_node_location[1] <= test_point[1])
1167  // {
1168  // if (next_node_location[1] > test_point[1])
1169  // {
1170  // double is_left = (next_node_location[0] - this_node_location[0])*(test_point[1] - this_node_location[1])
1171  // - (test_point[0] - this_node_location[0])*(next_node_location[1] - this_node_location[1]);
1172  //
1173  // // ...and the test point is to the left of the edge...
1174  // if (is_left > DBL_EPSILON)
1175  // {
1176  // // ...then there is a valid upward edge-ray intersection to the right of the test point
1177  // winding_number++;
1178  // }
1179  // }
1180  // }
1181  // else
1182  // {
1183  // // ...otherwise, if the edge is crossing downward
1184  // if (next_node_location[1] <= test_point[1])
1185  // {
1186  // double is_left = (next_node_location[0] - this_node_location[0])*(test_point[1] - this_node_location[1])
1187  // - (test_point[0] - this_node_location[0])*(next_node_location[1] - this_node_location[1]);
1188  //
1189  // // ...and the test point is to the right of the edge...
1190  // if (is_left < -DBL_EPSILON)
1191  // {
1192  // // ...then there is a valid downward edge-ray intersection to the right of the test point
1193  // winding_number--;
1194  // }
1195  // }
1196  // }
1197  // this_node_location = next_node_location;
1198  // }
1199  //
1200  // if (winding_number == 0)
1201  // {
1202  // element_includes_point = false;
1203  // }
1205 
1206  // Remap the origin to the first vertex to allow alternative distance metrics to be used in subclasses
1207  c_vector<double, SPACE_DIM> first_vertex = p_element->GetNodeLocation(0);
1208  c_vector<double, SPACE_DIM> test_point = GetVectorFromAtoB(first_vertex, rTestPoint);
1209 
1210  // Loop over edges of the element
1211  c_vector<double, SPACE_DIM> vertexA = zero_vector<double>(SPACE_DIM);
1212  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
1213  {
1214  // Check if this edge crosses the ray running out horizontally (increasing x, fixed y) from the test point
1215  c_vector<double, SPACE_DIM> vector_a_to_point = GetVectorFromAtoB(vertexA, test_point);
1216 
1217  // Pathological case - test point coincides with vertexA
1218  // (we will check vertexB next time we go through the for loop)
1219  if (norm_2(vector_a_to_point) < DBL_EPSILON)
1220  {
1221  return false;
1222  }
1223 
1224  c_vector<double, SPACE_DIM> vertexB = GetVectorFromAtoB(first_vertex, p_element->GetNodeLocation((local_index + 1) % num_nodes));
1225  c_vector<double, SPACE_DIM> vector_b_to_point = GetVectorFromAtoB(vertexB, test_point);
1226  c_vector<double, SPACE_DIM> vector_a_to_b = GetVectorFromAtoB(vertexA, vertexB);
1227 
1228  // Pathological case - ray coincides with horizontal edge
1229  if ((fabs(vector_a_to_b[1]) < DBL_EPSILON) && (fabs(vector_a_to_point[1]) < DBL_EPSILON) && (fabs(vector_b_to_point[1]) < DBL_EPSILON))
1230  {
1231  if ((vector_a_to_point[0] > 0) != (vector_b_to_point[0] > 0))
1232  {
1233  return false;
1234  }
1235  }
1236 
1237  // Non-pathological case
1238  // A and B on different sides of the line y = test_point[1]
1239  if ((vertexA[1] > test_point[1]) != (vertexB[1] > test_point[1]))
1240  {
1241  // Intersection of y=test_point[1] and vector_a_to_b is on the right of test_point
1242  if (test_point[0] < vertexA[0] + vector_a_to_b[0] * vector_a_to_point[1] / vector_a_to_b[1])
1243  {
1244  element_includes_point = !element_includes_point;
1245  }
1246  }
1247 
1248  vertexA = vertexB;
1249  }
1250  return element_includes_point;
1251 }
1252 
1253 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1254 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetLocalIndexForElementEdgeClosestToPoint(const c_vector<double, SPACE_DIM>& rTestPoint, unsigned elementIndex)
1255 {
1256  // Make sure that we are in the correct dimension - this code will be eliminated at compile time
1257  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1258  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE - code will be removed at compile time
1259 
1260  // Get the element
1261  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(elementIndex);
1262  unsigned num_nodes = p_element->GetNumNodes();
1263 
1264  double min_squared_normal_distance = DBL_MAX;
1265  unsigned min_distance_edge_index = UINT_MAX;
1266 
1267  // Loop over edges of the element
1268  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
1269  {
1270  // Get the end points of this edge
1271  c_vector<double, SPACE_DIM> vertexA = p_element->GetNodeLocation(local_index);
1272  c_vector<double, SPACE_DIM> vertexB = p_element->GetNodeLocation((local_index + 1) % num_nodes);
1273 
1274  c_vector<double, SPACE_DIM> vector_a_to_point = this->GetVectorFromAtoB(vertexA, rTestPoint);
1275  c_vector<double, SPACE_DIM> vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB);
1276  double distance_a_to_b = norm_2(vector_a_to_b);
1277 
1278  c_vector<double, SPACE_DIM> edge_ab_unit_vector = vector_a_to_b / norm_2(vector_a_to_b);
1279  double distance_parallel_to_edge = inner_prod(vector_a_to_point, edge_ab_unit_vector);
1280 
1281  double squared_distance_normal_to_edge = SmallPow(norm_2(vector_a_to_point), 2) - SmallPow(distance_parallel_to_edge, 2);
1282 
1283  /*
1284  * If the point lies almost bang on the supporting line of the edge, then snap to the line.
1285  * This allows us to do floating point tie-breaks when line is exactly at a node.
1286  * We adopt a similar approach if the point is at the same position as a point in the
1287  * element.
1288  */
1289  if (squared_distance_normal_to_edge < DBL_EPSILON)
1290  {
1291  squared_distance_normal_to_edge = 0.0;
1292  }
1293 
1294  if (fabs(distance_parallel_to_edge) < DBL_EPSILON)
1295  {
1296  distance_parallel_to_edge = 0.0;
1297  }
1298  else if (fabs(distance_parallel_to_edge - distance_a_to_b) < DBL_EPSILON)
1299  {
1300  distance_parallel_to_edge = distance_a_to_b;
1301  }
1302 
1303  // Make sure node is within the confines of the edge and is the nearest edge to the node \this breaks for convex elements
1304  if (squared_distance_normal_to_edge < min_squared_normal_distance && distance_parallel_to_edge >= 0 && distance_parallel_to_edge <= distance_a_to_b)
1305  {
1306  min_squared_normal_distance = squared_distance_normal_to_edge;
1307  min_distance_edge_index = local_index;
1308  }
1309  }
1310 
1311  assert(min_distance_edge_index < num_nodes);
1312  return min_distance_edge_index;
1313 }
1314 
1315 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1317 {
1318  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1319 
1320  // Define helper variables
1321  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
1322  unsigned num_nodes = p_element->GetNumNodes();
1323  c_vector<double, 3> moments = zero_vector<double>(3);
1324 
1325  // Since we compute I_xx, I_yy and I_xy about the centroid, we must shift each vertex accordingly
1326  c_vector<double, SPACE_DIM> centroid = GetCentroidOfElement(index);
1327 
1328  c_vector<double, SPACE_DIM> this_node_location = p_element->GetNodeLocation(0);
1329  c_vector<double, SPACE_DIM> pos_1 = this->GetVectorFromAtoB(centroid, this_node_location);
1330 
1331  for (unsigned local_index = 0; local_index < num_nodes; local_index++)
1332  {
1333  unsigned next_index = (local_index + 1) % num_nodes;
1334  c_vector<double, SPACE_DIM> next_node_location = p_element->GetNodeLocation(next_index);
1335  c_vector<double, SPACE_DIM> pos_2 = this->GetVectorFromAtoB(centroid, next_node_location);
1336 
1337  double signed_area_term = pos_1(0) * pos_2(1) - pos_2(0) * pos_1(1);
1338  // Ixx
1339  moments(0) += (pos_1(1) * pos_1(1) + pos_1(1) * pos_2(1) + pos_2(1) * pos_2(1)) * signed_area_term;
1340 
1341  // Iyy
1342  moments(1) += (pos_1(0) * pos_1(0) + pos_1(0) * pos_2(0) + pos_2(0) * pos_2(0)) * signed_area_term;
1343 
1344  // Ixy
1345  moments(2) += (pos_1(0) * pos_2(1) + 2 * pos_1(0) * pos_1(1) + 2 * pos_2(0) * pos_2(1) + pos_2(0) * pos_1(1)) * signed_area_term;
1346 
1347  pos_1 = pos_2;
1348  }
1349 
1350  moments(0) /= 12;
1351  moments(1) /= 12;
1352  moments(2) /= 24;
1353 
1354  /*
1355  * If the nodes owned by the element were supplied in a clockwise rather
1356  * than anticlockwise manner, or if this arose as a result of enforcing
1357  * periodicity, then our computed quantities will be the wrong sign, so
1358  * we need to fix this.
1359  */
1360  if (moments(0) < 0.0)
1361  {
1362  moments(0) = -moments(0);
1363  moments(1) = -moments(1);
1364  moments(2) = -moments(2);
1365  }
1366  return moments;
1367 }
1368 
1369 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1370 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetShortAxisOfElement(unsigned index)
1371 {
1372  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1373 
1374  c_vector<double, SPACE_DIM> short_axis = zero_vector<double>(SPACE_DIM);
1375 
1376  // Calculate the moments of the element about its centroid (recall that I_xx and I_yy must be non-negative)
1377  c_vector<double, 3> moments = CalculateMomentsOfElement(index);
1378 
1379  // Normalise the moments vector to remove problem of a very small discriminant (see #2874)
1380  moments /= norm_2(moments);
1381 
1382  // If the principal moments are equal...
1383  double discriminant = (moments(0) - moments(1)) * (moments(0) - moments(1)) + 4.0 * moments(2) * moments(2);
1384  if (fabs(discriminant) < DBL_EPSILON)
1385  {
1386  // ...then every axis through the centroid is a principal axis, so return a random unit vector
1387  short_axis(0) = RandomNumberGenerator::Instance()->ranf();
1388  short_axis(1) = sqrt(1.0 - short_axis(0) * short_axis(0));
1389  }
1390  else
1391  {
1392  // If the product of inertia is zero, then the coordinate axes are the principal axes
1393  if (fabs(moments(2)) < DBL_EPSILON)
1394  {
1395  if (moments(0) < moments(1))
1396  {
1397  short_axis(0) = 0.0;
1398  short_axis(1) = 1.0;
1399  }
1400  else
1401  {
1402  short_axis(0) = 1.0;
1403  short_axis(1) = 0.0;
1404  }
1405  }
1406  else
1407  {
1408  // Otherwise we find the eigenvector of the inertia matrix corresponding to the largest eigenvalue
1409  double lambda = 0.5 * (moments(0) + moments(1) + sqrt(discriminant));
1410 
1411  short_axis(0) = 1.0;
1412  short_axis(1) = (moments(0) - lambda) / moments(2);
1413 
1414  // Normalise the short axis before returning it
1415  short_axis /= norm_2(short_axis);
1416  }
1417  }
1418 
1419  return short_axis;
1420 }
1421 
1422 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1424 {
1425  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1426 
1427  unsigned num_nodes_in_element = pElement->GetNumNodes();
1428  unsigned next_local_index = (localIndex + 1) % num_nodes_in_element;
1429 
1430  // We add an extra num_nodes_in_element in the line below as otherwise this term can be negative, which breaks the % operator
1431  unsigned previous_local_index = (num_nodes_in_element + localIndex - 1) % num_nodes_in_element;
1432 
1433  c_vector<double, SPACE_DIM> previous_node_location = pElement->GetNodeLocation(previous_local_index);
1434  c_vector<double, SPACE_DIM> next_node_location = pElement->GetNodeLocation(next_local_index);
1435  c_vector<double, SPACE_DIM> difference_vector = this->GetVectorFromAtoB(previous_node_location, next_node_location);
1436 
1437  c_vector<double, SPACE_DIM> area_gradient;
1438 
1439  area_gradient[0] = 0.5 * difference_vector[1];
1440  area_gradient[1] = -0.5 * difference_vector[0];
1441 
1442  return area_gradient;
1443 }
1444 
1445 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1447 {
1448  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1449 
1450  unsigned num_nodes_in_element = pElement->GetNumNodes();
1451 
1452  // We add an extra num_nodes_in_element-1 in the line below as otherwise this term can be negative, which breaks the % operator
1453  unsigned previous_local_index = (num_nodes_in_element + localIndex - 1) % num_nodes_in_element;
1454 
1455  unsigned this_global_index = pElement->GetNodeGlobalIndex(localIndex);
1456  unsigned previous_global_index = pElement->GetNodeGlobalIndex(previous_local_index);
1457 
1458  double previous_edge_length = this->GetDistanceBetweenNodes(this_global_index, previous_global_index);
1459  assert(previous_edge_length > DBL_EPSILON);
1460 
1461  c_vector<double, SPACE_DIM> previous_edge_gradient = this->GetVectorFromAtoB(pElement->GetNodeLocation(previous_local_index), pElement->GetNodeLocation(localIndex)) / previous_edge_length;
1462 
1463  return previous_edge_gradient;
1464 }
1465 
1466 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1468 {
1469  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
1470 
1471  unsigned next_local_index = (localIndex + 1) % (pElement->GetNumNodes());
1472 
1473  unsigned this_global_index = pElement->GetNodeGlobalIndex(localIndex);
1474  unsigned next_global_index = pElement->GetNodeGlobalIndex(next_local_index);
1475 
1476  double next_edge_length = this->GetDistanceBetweenNodes(this_global_index, next_global_index);
1477  assert(next_edge_length > DBL_EPSILON);
1478 
1479  c_vector<double, SPACE_DIM> next_edge_gradient = this->GetVectorFromAtoB(pElement->GetNodeLocation(next_local_index), pElement->GetNodeLocation(localIndex)) / next_edge_length;
1480 
1481  return next_edge_gradient;
1482 }
1483 
1484 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1486 {
1487  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
1488 
1489  c_vector<double, SPACE_DIM> previous_edge_gradient = GetPreviousEdgeGradientOfElementAtNode(pElement, localIndex);
1490  c_vector<double, SPACE_DIM> next_edge_gradient = GetNextEdgeGradientOfElementAtNode(pElement, localIndex);
1491 
1492  return previous_edge_gradient + next_edge_gradient;
1493 }
1494 
1496 // 3D-specific methods //
1498 
1499 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1501 {
1502  assert(SPACE_DIM == 3); // LCOV_EXCL_LINE - code will be removed at compile time
1503 
1504  // As we are in 3D, the face must have at least three vertices
1505  assert(pFace->GetNumNodes() >= 3u);
1506 
1507  // Reset the answer
1508  rNormal = zero_vector<double>(SPACE_DIM);
1509 
1510  c_vector<double, SPACE_DIM> v_minus_v0 = this->GetVectorFromAtoB(pFace->GetNode(0)->rGetLocation(), pFace->GetNode(1)->rGetLocation());
1511  for (unsigned local_index = 2; local_index < pFace->GetNumNodes(); local_index++)
1512  {
1513  c_vector<double, SPACE_DIM> vnext_minus_v0 = this->GetVectorFromAtoB(pFace->GetNode(0)->rGetLocation(), pFace->GetNode(local_index)->rGetLocation());
1514  rNormal += VectorProduct(v_minus_v0, vnext_minus_v0);
1515  v_minus_v0 = vnext_minus_v0;
1516  }
1517  double magnitude = norm_2(rNormal);
1518  if (magnitude != 0.0)
1519  {
1520  // Normalize the normal vector
1521  rNormal /= magnitude;
1522  // If all points are co-located, then magnitude==0.0 and there is potential for a floating point exception
1523  // here if we divide by zero, so we'll move on.
1524  }
1525  return magnitude / 2.0;
1526 }
1527 
1528 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1530 {
1531  assert(SPACE_DIM == 3); // LCOV_EXCL_LINE - code will be removed at compile time
1532 
1533  // Get the unit normal to the plane of this face
1534  c_vector<double, SPACE_DIM> unit_normal;
1535  return CalculateUnitNormalToFaceWithArea(pFace, unit_normal);
1536 }
1537 
1539 #if defined(__xlC__)
1540 template <>
1542 {
1543  NEVER_REACHED;
1544 }
1545 #endif
1546 
1547 // Explicit instantiation
1548 template class VertexMesh<1, 1>;
1549 template class VertexMesh<1, 2>;
1550 template class VertexMesh<1, 3>;
1551 template class VertexMesh<2, 2>;
1552 template class VertexMesh<2, 3>;
1553 template class VertexMesh<3, 3>;
1554 
1555 // Serialization for Boost >= 1.36
virtual c_vector< double, 3 > CalculateMomentsOfElement(unsigned index)
void ConstructFromMeshReader(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader)
virtual void Clear()
Definition: VertexMesh.cpp:579
void SetAttribute(double attribute)
VertexElement< ELEMENT_DIM-1, SPACE_DIM > * GetFace(unsigned index) const
Definition: VertexMesh.cpp:635
unsigned GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(unsigned elementIndex)
Definition: VertexMesh.cpp:503
virtual unsigned GetNumFaces() const
Definition: VertexMesh.cpp:622
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
virtual ElementData GetNextElementData()=0
std::set< unsigned > GetNeighbouringNodeIndices(unsigned nodeIndex)
Definition: VertexMesh.cpp:713
Definition: Node.hpp:58
virtual unsigned GetNumElements() const
Definition: VertexMesh.cpp:610
double SmallPow(double x, unsigned exponent)
unsigned GetNodeGlobalIndex(unsigned localIndex) const
unsigned GetNumAllElements() const
Definition: VertexMesh.cpp:616
bool IsBoundaryNode() const
Definition: Node.cpp:164
virtual unsigned GetNumElements() const
virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, double &rJacobianDeterminant, c_matrix< double, ELEMENT_DIM, SPACE_DIM > &rInverseJacobian) const
std::vector< VertexElement< ELEMENT_DIM-1, SPACE_DIM > * > mFaces
Definition: VertexMesh.hpp:83
#define EXCEPTION(message)
Definition: Exception.hpp:143
virtual unsigned GetNumNodes() const
Definition: VertexMesh.cpp:604
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
c_vector< T, 1 > VectorProduct(const c_vector< T, 1 > &rA, const c_vector< T, 1 > &rB)
void GenerateVerticesFromElementCircumcentres(TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
Definition: VertexMesh.cpp:390
std::set< unsigned > & rGetContainingElementIndices()
Definition: Node.cpp:300
c_vector< double, SPACE_DIM > GetNextEdgeGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
std::set< unsigned > GetNeighbouringNodeNotAlsoInElement(unsigned nodeIndex, unsigned elemIndex)
Definition: VertexMesh.cpp:743
VertexElement< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
Definition: VertexMesh.cpp:628
#define NEVER_REACHED
Definition: Exception.hpp:206
c_vector< double, SPACE_DIM > GetPreviousEdgeGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
unsigned GetNumFaces() const
std::vector< ElementData > Faces
std::vector< unsigned > NodeIndices
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
virtual bool HasNodePermutation()
VertexElement< ELEMENT_DIM-1, SPACE_DIM > * GetFace(unsigned index) const
bool mMeshChangesDuringSimulation
void AddNode(Node< SPACE_DIM > *pNode, const unsigned &rIndex)
std::vector< Node< SPACE_DIM > * > mNodes
double CalculateUnitNormalToFaceWithArea(VertexElement< ELEMENT_DIM-1, SPACE_DIM > *pFace, c_vector< double, SPACE_DIM > &rNormal)
virtual unsigned GetNumElements() const =0
virtual double CalculateAreaOfFace(VertexElement< ELEMENT_DIM-1, SPACE_DIM > *pFace)
virtual void Reset()=0
unsigned GetNumNodes() const
const unsigned UNSIGNED_UNSET
Definition: Exception.hpp:52
virtual ~VertexMesh()
Definition: VertexMesh.cpp:475
double GetElongationShapeFactorOfElement(unsigned elementIndex)
Definition: VertexMesh.cpp:450
void AddFace(VertexElement< ELEMENT_DIM-1, SPACE_DIM > *pFace)
static RandomNumberGenerator * Instance()
virtual double GetVolumeOfElement(unsigned index)
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
virtual unsigned GetNumElementAttributes() const
std::vector< VertexElement< ELEMENT_DIM, SPACE_DIM > * > mElements
Definition: VertexMesh.hpp:80
unsigned SolveNodeMapping(unsigned index) const
Definition: VertexMesh.cpp:481
c_vector< double, SPACE_DIM > GetPerimeterGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:139
void AddElement(unsigned index)
Definition: Node.cpp:268
#define UNUSED_OPT(var)
Definition: Exception.hpp:216
unsigned GetIndex() const
unsigned SolveBoundaryElementMapping(unsigned index) const
Definition: VertexMesh.cpp:495
virtual c_vector< double, SPACE_DIM > GetCentroidOfElement(unsigned index)
Definition: VertexMesh.cpp:642
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
std::set< unsigned > GetNeighbouringElementIndices(unsigned elementIndex)
Definition: VertexMesh.cpp:783
double GetNodeLocation(unsigned localIndex, unsigned dimension) const
virtual std::vector< double > GetNextNode()=0
c_vector< double, SPACE_DIM > GetAreaGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
unsigned GetIndex() const
Definition: Node.cpp:158
virtual VertexMesh< ELEMENT_DIM, SPACE_DIM > * GetMeshForVtk()
Definition: VertexMesh.cpp:817
double GetEdgeLength(unsigned elementIndex1, unsigned elementIndex2)
Definition: VertexMesh.cpp:415
unsigned GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(unsigned nodeIndex)
Definition: VertexMesh.cpp:529
virtual double GetSurfaceAreaOfElement(unsigned index)
std::vector< unsigned > NodeIndices
unsigned SolveElementMapping(unsigned index) const
Definition: VertexMesh.cpp:488
virtual unsigned GetNumNodes() const =0
bool ElementIncludesPoint(const c_vector< double, SPACE_DIM > &rTestPoint, unsigned elementIndex)
unsigned GetLocalIndexForElementEdgeClosestToPoint(const c_vector< double, SPACE_DIM > &rTestPoint, unsigned elementIndex)
c_vector< double, SPACE_DIM > GetShortAxisOfElement(unsigned index)
TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpDelaunayMesh
Definition: VertexMesh.hpp:101
std::map< unsigned, unsigned > mVoronoiElementIndexMap
Definition: VertexMesh.hpp:92
unsigned GetRosetteRankOfElement(unsigned index)
Definition: VertexMesh.cpp:555