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