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