Chaste  Release::2024.1
MutableVertexMesh.cpp
1 /*
2 
3 Copyright (c) 2005-2021, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "MutableVertexMesh.hpp"
37 
38 #include "LogFile.hpp"
39 #include "UblasCustomFunctions.hpp"
40 #include "Warnings.hpp"
41 
42 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
44  std::vector<VertexElement<ELEMENT_DIM,SPACE_DIM>*> vertexElements,
45  double cellRearrangementThreshold,
46  double t2Threshold,
47  double cellRearrangementRatio,
48  double protorosetteFormationProbability,
49  double protorosetteResolutionProbabilityPerTimestep,
50  double rosetteResolutionProbabilityPerTimestep)
51  : mCellRearrangementThreshold(cellRearrangementThreshold),
52  mCellRearrangementRatio(cellRearrangementRatio),
53  mT2Threshold(t2Threshold),
54  mProtorosetteFormationProbability(protorosetteFormationProbability),
55  mProtorosetteResolutionProbabilityPerTimestep(protorosetteResolutionProbabilityPerTimestep),
56  mRosetteResolutionProbabilityPerTimestep(rosetteResolutionProbabilityPerTimestep),
57  mCheckForInternalIntersections(false),
58  mDistanceForT3SwapChecking(5.0)
59 {
60  // Threshold parameters must be strictly positive
61  assert(cellRearrangementThreshold > 0.0);
62  assert(t2Threshold > 0.0);
63  assert(protorosetteFormationProbability >= 0.0);
64  assert(protorosetteFormationProbability <= 1.0);
65  assert(protorosetteResolutionProbabilityPerTimestep >= 0.0);
66  assert(protorosetteResolutionProbabilityPerTimestep <= 1.0);
67  assert(rosetteResolutionProbabilityPerTimestep >= 0.0);
68  assert(rosetteResolutionProbabilityPerTimestep <= 1.0);
69 
70  // Reset member variables and clear mNodes and mElements
71  Clear();
72 
73  // Populate mNodes and mElements
74  for (unsigned node_index=0; node_index<nodes.size(); node_index++)
75  {
76  Node<SPACE_DIM>* p_temp_node = nodes[node_index];
77  this->mNodes.push_back(p_temp_node);
78  }
79  for (unsigned elem_index=0; elem_index<vertexElements.size(); elem_index++)
80  {
81  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_temp_vertex_element = vertexElements[elem_index];
82  this->mElements.push_back(p_temp_vertex_element);
83  }
84 
85  // If in 3D, then also populate mFaces
86  if (SPACE_DIM == 3)
87  {
88  // Use a std::set to keep track of which faces have been added to mFaces
89  std::set<unsigned> faces_counted;
90 
91  // Loop over mElements
92  for (unsigned elem_index=0; elem_index<this->mElements.size(); elem_index++)
93  {
94  // Loop over faces of this element
95  for (unsigned face_index=0; face_index<this->mElements[elem_index]->GetNumFaces(); face_index++)
96  {
97  VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_face = this->mElements[elem_index]->GetFace(face_index);
98 
99  // If this face is not already contained in mFaces, then add it and update faces_counted
100  if (faces_counted.find(p_face->GetIndex()) == faces_counted.end())
101  {
102  this->mFaces.push_back(p_face);
103  faces_counted.insert(p_face->GetIndex());
104  }
105  }
106  }
107  }
108 
109  // Register elements with nodes
110  for (unsigned index=0; index<this->mElements.size(); index++)
111  {
112  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_temp_vertex_element = this->mElements[index];
113  for (unsigned node_index=0; node_index<p_temp_vertex_element->GetNumNodes(); node_index++)
114  {
115  Node<SPACE_DIM>* p_temp_node = p_temp_vertex_element->GetNode(node_index);
116  p_temp_node->AddElement(p_temp_vertex_element->GetIndex());
117  }
118  }
119 
120  this->mMeshChangesDuringSimulation = true;
121 }
122 
123 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
127  mT2Threshold(0.001),
133 {
134  // Note that the member variables initialised above will be overwritten as soon as archiving is complete
135  this->mMeshChangesDuringSimulation = true;
136  Clear();
137 }
138 
139 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
141 {
142  Clear();
143 }
144 
145 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
147 {
149 }
150 
151 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
153 {
154  return mT2Threshold;
155 }
156 
157 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
159 {
161 }
162 
163 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
165 {
167 }
168 
169 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
171 {
173 }
174 
175 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
177 {
179 }
180 
181 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
183 {
184  mDistanceForT3SwapChecking = distanceForT3SwapChecking;
185 }
186 
187 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
189 {
191 }
192 
193 
194 
195 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
197 {
199 }
200 
201 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
203 {
204  mCellRearrangementThreshold = cellRearrangementThreshold;
205 }
206 
207 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
209 {
210  mT2Threshold = t2Threshold;
211 }
212 
213 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
215 {
216  mCellRearrangementRatio = cellRearrangementRatio;
217 }
218 
219 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
221 {
222  // Check that the new value is in [0,1]
223  if (protorosetteFormationProbability < 0.0)
224  {
225  EXCEPTION("Attempting to assign a negative probability.");
226  }
227  if (protorosetteFormationProbability > 1.0)
228  {
229  EXCEPTION("Attempting to assign a probability greater than one.");
230  }
231 
232  // Assign the new value
233  mProtorosetteFormationProbability = protorosetteFormationProbability;
234 }
235 
236 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
238 {
239  // Check that the new value is in [0,1]
240  if (protorosetteResolutionProbabilityPerTimestep < 0.0)
241  {
242  EXCEPTION("Attempting to assign a negative probability.");
243  }
244  if (protorosetteResolutionProbabilityPerTimestep > 1.0)
245  {
246  EXCEPTION("Attempting to assign a probability greater than one.");
247  }
248 
249  // Assign the new value
250  mProtorosetteResolutionProbabilityPerTimestep = protorosetteResolutionProbabilityPerTimestep;
251 }
252 
253 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
255 {
256  // Check that the new value is in [0,1]
257  if (rosetteResolutionProbabilityPerTimestep < 0.0)
258  {
259  EXCEPTION("Attempting to assign a negative probability.");
260  }
261  if (rosetteResolutionProbabilityPerTimestep > 1.0)
262  {
263  EXCEPTION("Attempting to assign a probability greater than one.");
264  }
265 
266  // Assign the new value
267  mRosetteResolutionProbabilityPerTimestep = rosetteResolutionProbabilityPerTimestep;
268 }
269 
270 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
272 {
273  mCheckForInternalIntersections = checkForInternalIntersections;
274 }
275 
276 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
278 {
279  mDeletedNodeIndices.clear();
280  mDeletedElementIndices.clear();
281 
283 }
284 
285 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
287 {
288  return this->mNodes.size() - mDeletedNodeIndices.size();
289 }
290 
291 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
293 {
294  return this->mElements.size() - mDeletedElementIndices.size();
295 }
296 
297 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
298 std::vector< c_vector<double, SPACE_DIM> > MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetLocationsOfT1Swaps()
299 {
300  return mLocationsOfT1Swaps;
301 }
302 
303 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
305 {
306  return mLastT2SwapLocation;
307 }
308 
309 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
310 std::vector< c_vector<double, SPACE_DIM> > MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetLocationsOfT3Swaps()
311 {
312  return mLocationsOfT3Swaps;
313 }
314 
315 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
317 {
319 }
320 
321 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
323 {
324  mLocationsOfT1Swaps.clear();
325 }
326 
327 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
329 {
330  mLocationsOfT3Swaps.clear();
331 }
332 
333 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
335 {
337 }
338 
339 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
341 {
342  if (mDeletedNodeIndices.empty())
343  {
344  pNewNode->SetIndex(this->mNodes.size());
345  this->mNodes.push_back(pNewNode);
346  }
347  else
348  {
349  unsigned index = mDeletedNodeIndices.back();
350  pNewNode->SetIndex(index);
351  mDeletedNodeIndices.pop_back();
352  delete this->mNodes[index];
353  this->mNodes[index] = pNewNode;
354  }
355  return pNewNode->GetIndex();
356 }
357 
358 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
360 {
361  unsigned new_element_index = pNewElement->GetIndex();
362 
363  if (new_element_index == this->mElements.size())
364  {
365  this->mElements.push_back(pNewElement);
366  }
367  else
368  {
369  this->mElements[new_element_index] = pNewElement;
370  }
371  pNewElement->RegisterWithNodes();
372  return pNewElement->GetIndex();
373 }
374 
375 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
377 {
378  this->mNodes[nodeIndex]->SetPoint(point);
379 }
380 
381 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
383  c_vector<double, SPACE_DIM> axisOfDivision,
384  bool placeOriginalElementBelow)
385 {
386  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
387  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE
388 
389  // Get the centroid of the element
390  c_vector<double, SPACE_DIM> centroid = this->GetCentroidOfElement(pElement->GetIndex());
391 
392  // Create a vector perpendicular to the axis of division
393  c_vector<double, SPACE_DIM> perp_axis;
394  perp_axis(0) = -axisOfDivision(1);
395  perp_axis(1) = axisOfDivision(0);
396 
397  /*
398  * Find which edges the axis of division crosses by finding any node
399  * that lies on the opposite side of the axis of division to its next
400  * neighbour.
401  */
402  unsigned num_nodes = pElement->GetNumNodes();
403  std::vector<unsigned> intersecting_nodes;
404  bool is_current_node_on_left = (inner_prod(this->GetVectorFromAtoB(pElement->GetNodeLocation(0), centroid), perp_axis) >= 0);
405  for (unsigned i=0; i<num_nodes; i++)
406  {
407  bool is_next_node_on_left = (inner_prod(this->GetVectorFromAtoB(pElement->GetNodeLocation((i+1)%num_nodes), centroid), perp_axis) >= 0);
408  if (is_current_node_on_left != is_next_node_on_left)
409  {
410  intersecting_nodes.push_back(i);
411  }
412  is_current_node_on_left = is_next_node_on_left;
413  }
414 
415  // If the axis of division does not cross two edges then we cannot proceed
416  if (intersecting_nodes.size() != 2)
417  {
418  EXCEPTION("Cannot proceed with element division: the given axis of division does not cross two edges of the element");
419  }
420 
421  std::vector<unsigned> division_node_global_indices;
422  unsigned nodes_added = 0;
423 
424  // Find the intersections between the axis of division and the element edges
425  for (unsigned i=0; i<intersecting_nodes.size(); i++)
426  {
427  /*
428  * Get pointers to the nodes forming the edge into which one new node will be inserted.
429  *
430  * Note that when we use the first entry of intersecting_nodes to add a node,
431  * we change the local index of the second entry of intersecting_nodes in
432  * pElement, so must account for this by moving one entry further on.
433  */
434  Node<SPACE_DIM>* p_node_A = pElement->GetNode((intersecting_nodes[i]+nodes_added)%pElement->GetNumNodes());
435  Node<SPACE_DIM>* p_node_B = pElement->GetNode((intersecting_nodes[i]+nodes_added+1)%pElement->GetNumNodes());
436 
437  // Find the indices of the elements owned by each node on the edge into which one new node will be inserted
438  std::set<unsigned> elems_containing_node_A = p_node_A->rGetContainingElementIndices();
439  std::set<unsigned> elems_containing_node_B = p_node_B->rGetContainingElementIndices();
440 
441  c_vector<double, SPACE_DIM> position_a = p_node_A->rGetLocation();
442  c_vector<double, SPACE_DIM> position_b = p_node_B->rGetLocation();
443  c_vector<double, SPACE_DIM> a_to_b = this->GetVectorFromAtoB(position_a, position_b);
444 
445  c_vector<double, SPACE_DIM> intersection;
446 
447  if (norm_2(a_to_b) < 2.0*mCellRearrangementRatio*mCellRearrangementThreshold)
448  {
449  WARNING("Edge is too small for normal division; putting node in the middle of a and b. There may be T1 swaps straight away.");
451  intersection = position_a + 0.5*a_to_b;
452  }
453  else
454  {
455  // Find the location of the intersection
456  double determinant = a_to_b[0]*axisOfDivision[1] - a_to_b[1]*axisOfDivision[0];
457 
458  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
459  c_vector<double, SPACE_DIM> moved_centroid;
460  moved_centroid = position_a + this->GetVectorFromAtoB(position_a, centroid);
461 
462  double alpha = (moved_centroid[0]*a_to_b[1] - position_a[0]*a_to_b[1]
463  -moved_centroid[1]*a_to_b[0] + position_a[1]*a_to_b[0])/determinant;
464 
465  intersection = moved_centroid + alpha*axisOfDivision;
466 
467  /*
468  * If then new node is too close to one of the edge nodes, then reposition it
469  * a distance mCellRearrangementRatio*mCellRearrangementThreshold further along the edge.
470  */
471  c_vector<double, SPACE_DIM> a_to_intersection = this->GetVectorFromAtoB(position_a, intersection);
472  if (norm_2(a_to_intersection) < mCellRearrangementThreshold)
473  {
474  intersection = position_a + mCellRearrangementRatio*mCellRearrangementThreshold*a_to_b/norm_2(a_to_b);
475  }
476 
477  c_vector<double, SPACE_DIM> b_to_intersection = this->GetVectorFromAtoB(position_b, intersection);
478  if (norm_2(b_to_intersection) < mCellRearrangementThreshold)
479  {
480  assert(norm_2(a_to_intersection) > mCellRearrangementThreshold); // to prevent moving intersection back to original position
481 
482  intersection = position_b - mCellRearrangementRatio*mCellRearrangementThreshold*a_to_b/norm_2(a_to_b);
483  }
484  }
485 
486  /*
487  * The new node is boundary node if the 2 nodes are boundary nodes and the elements don't look like
488  * ___A___
489  * | | |
490  * |___|___|
491  * B
492  */
493  bool is_boundary = false;
494  if (p_node_A->IsBoundaryNode() && p_node_B->IsBoundaryNode())
495  {
496  if (elems_containing_node_A.size() != 2 ||
497  elems_containing_node_B.size() != 2 ||
498  elems_containing_node_A != elems_containing_node_B)
499  {
500  is_boundary = true;
501  }
502  }
503 
504  // Add a new node to the mesh at the location of the intersection
505  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, is_boundary, intersection[0], intersection[1]));
506  nodes_added++;
507 
508  // Now make sure the new node is added to all neighbouring elements
509 
510  // Find common elements
511  std::set<unsigned> shared_elements;
512  std::set_intersection(elems_containing_node_A.begin(),
513  elems_containing_node_A.end(),
514  elems_containing_node_B.begin(),
515  elems_containing_node_B.end(),
516  std::inserter(shared_elements, shared_elements.begin()));
517 
518  // Iterate over common elements
519  unsigned node_A_index = p_node_A->GetIndex();
520  unsigned node_B_index = p_node_B->GetIndex();
521  for (std::set<unsigned>::iterator iter = shared_elements.begin();
522  iter != shared_elements.end();
523  ++iter)
524  {
525  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(*iter);
526 
527  // Find which node has the lower local index in this element
528  unsigned local_indexA = p_element->GetNodeLocalIndex(node_A_index);
529  unsigned local_indexB = p_element->GetNodeLocalIndex(node_B_index);
530 
531  unsigned index = local_indexB;
532 
533  // If node B has a higher index then use node A's index...
534  if (local_indexB > local_indexA)
535  {
536  index = local_indexA;
537 
538  // ...unless nodes A and B share the element's last edge
539  if ((local_indexA == 0) && (local_indexB == p_element->GetNumNodes()-1))
540  {
541  index = local_indexB;
542  }
543  }
544  else if ((local_indexB == 0) && (local_indexA == p_element->GetNumNodes()-1))
545  {
546  // ...otherwise use node B's index, unless nodes A and B share the element's last edge
547  index = local_indexA;
548  }
549 
550  // Add new node to this element
551  this->GetElement(*iter)->AddNode(this->GetNode(new_node_global_index), index);
552  }
553 
554  // Store index of new node
555  division_node_global_indices.push_back(new_node_global_index);
556  }
557 
558  // Now call DivideElement() to divide the element using the new nodes
559  unsigned new_element_index = DivideElement(pElement,
560  pElement->GetNodeLocalIndex(division_node_global_indices[0]),
561  pElement->GetNodeLocalIndex(division_node_global_indices[1]),
562  placeOriginalElementBelow);
563 
564  return new_element_index;
565 }
566 
567 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
569  bool placeOriginalElementBelow)
570 {
571  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
572  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE
573 
574  c_vector<double, SPACE_DIM> short_axis = this->GetShortAxisOfElement(pElement->GetIndex());
575 
576  unsigned new_element_index = DivideElementAlongGivenAxis(pElement, short_axis, placeOriginalElementBelow);
577  return new_element_index;
578 }
579 
580 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
582  unsigned nodeAIndex,
583  unsigned nodeBIndex,
584  bool placeOriginalElementBelow)
585 {
586  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
587  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE
588 
589  // Sort nodeA and nodeB such that nodeBIndex > nodeAindex
590  assert(nodeBIndex != nodeAIndex);
591  unsigned node1_index = (nodeAIndex < nodeBIndex) ? nodeAIndex : nodeBIndex; // low index
592  unsigned node2_index = (nodeAIndex < nodeBIndex) ? nodeBIndex : nodeAIndex; // high index
593 
594  // Store the number of nodes in the element (this changes when nodes are deleted from the element)
595  unsigned num_nodes = pElement->GetNumNodes();
596 
597  // Copy the nodes in this element
598  std::vector<Node<SPACE_DIM>*> nodes_elem;
599  for (unsigned i=0; i<num_nodes; i++)
600  {
601  nodes_elem.push_back(pElement->GetNode(i));
602  }
603 
604  // Get the index of the new element
605  unsigned new_element_index;
606  if (mDeletedElementIndices.empty())
607  {
608  new_element_index = this->mElements.size();
609  }
610  else
611  {
612  new_element_index = mDeletedElementIndices.back();
613  mDeletedElementIndices.pop_back();
614  delete this->mElements[new_element_index];
615  }
616 
617  // Add the new element to the mesh
618  AddElement(new VertexElement<ELEMENT_DIM,SPACE_DIM>(new_element_index, nodes_elem));
619 
626  // Find lowest element
628  double height_midpoint_1 = 0.0;
629  double height_midpoint_2 = 0.0;
630  unsigned counter_1 = 0;
631  unsigned counter_2 = 0;
632 
633  for (unsigned i=0; i<num_nodes; i++)
634  {
635  if (i>=node1_index && i<=node2_index)
636  {
637  height_midpoint_1 += pElement->GetNode(i)->rGetLocation()[1];
638  counter_1++;
639  }
640  if (i<=node1_index || i>=node2_index)
641  {
642  height_midpoint_2 += pElement->GetNode(i)->rGetLocation()[1];
643  counter_2++;
644  }
645  }
646  height_midpoint_1 /= (double)counter_1;
647  height_midpoint_2 /= (double)counter_2;
648 
649  for (unsigned i=num_nodes; i>0; i--)
650  {
651  if (i-1 < node1_index || i-1 > node2_index)
652  {
653  if (height_midpoint_1 < height_midpoint_2)
654  {
655  if (placeOriginalElementBelow)
656  {
657  pElement->DeleteNode(i-1);
658  }
659  else
660  {
661  this->mElements[new_element_index]->DeleteNode(i-1);
662  }
663  }
664  else
665  {
666  if (placeOriginalElementBelow)
667  {
668  this->mElements[new_element_index]->DeleteNode(i-1);
669  }
670  else
671  {
672  pElement->DeleteNode(i-1);
673  }
674  }
675  }
676  else if (i-1 > node1_index && i-1 < node2_index)
677  {
678  if (height_midpoint_1 < height_midpoint_2)
679  {
680  if (placeOriginalElementBelow)
681  {
682  this->mElements[new_element_index]->DeleteNode(i-1);
683  }
684  else
685  {
686  pElement->DeleteNode(i-1);
687  }
688  }
689  else
690  {
691  if (placeOriginalElementBelow)
692  {
693  pElement->DeleteNode(i-1);
694  }
695  else
696  {
697  this->mElements[new_element_index]->DeleteNode(i-1);
698  }
699  }
700  }
701  }
702 
703  return new_element_index;
704 }
705 
706 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
708 {
709  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
710 
711  // Mark any nodes that are contained only in this element as deleted
712  for (unsigned i=0; i<this->mElements[index]->GetNumNodes(); i++)
713  {
714  Node<SPACE_DIM>* p_node = this->mElements[index]->GetNode(i);
715 
716  if (p_node->rGetContainingElementIndices().size() == 1)
717  {
719  }
720 
721  // Mark all the nodes contained in the removed element as boundary nodes
722  p_node->SetAsBoundaryNode(true);
723  }
724 
725  // Mark this element as deleted
726  this->mElements[index]->MarkAsDeleted();
727  mDeletedElementIndices.push_back(index);
728 }
729 
730 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
732 {
733  this->mNodes[index]->MarkAsDeleted();
734  mDeletedNodeIndices.push_back(index);
735 }
736 
737 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
739 {
740  // Find the indices of the elements owned by each node
741  std::set<unsigned> elements_containing_nodeA = pNodeA->rGetContainingElementIndices();
742  std::set<unsigned> elements_containing_nodeB = pNodeB->rGetContainingElementIndices();
743 
744  // Find common elements
745  std::set<unsigned> shared_elements;
746  std::set_intersection(elements_containing_nodeA.begin(),
747  elements_containing_nodeA.end(),
748  elements_containing_nodeB.begin(),
749  elements_containing_nodeB.end(),
750  std::inserter(shared_elements, shared_elements.begin()));
751 
752  // Check that the nodes have a common edge and not more than 2
753  assert(!shared_elements.empty());
754  assert(shared_elements.size()<=2u);
755 
756  // Specify if it's a boundary node
757  bool is_boundary_node = false;
758  if (shared_elements.size()==1u)
759  {
760  // If only one shared element then must be on the boundary.
761  assert((pNodeA->IsBoundaryNode()) && (pNodeB->IsBoundaryNode()));
762  is_boundary_node = true;
763  }
764 
765  // Create a new node (position is not important as it will be changed)
766  Node<SPACE_DIM>* p_new_node = new Node<SPACE_DIM>(GetNumNodes(), is_boundary_node, 0.0, 0.0);
767 
768  // Update the node location
769  c_vector<double, SPACE_DIM> new_node_position = pNodeA->rGetLocation() + 0.5*this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeB->rGetLocation());
770  ChastePoint<SPACE_DIM> point(new_node_position);
771  p_new_node->SetPoint(new_node_position);
772 
773  // Add node to mesh
774  this->mNodes.push_back(p_new_node);
775 
776  // Iterate over common elements
777  unsigned node_A_index = pNodeA->GetIndex();
778  unsigned node_B_index = pNodeB->GetIndex();
779  for (std::set<unsigned>::iterator iter = shared_elements.begin();
780  iter != shared_elements.end();
781  ++iter)
782  {
783  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(*iter);
784 
785  // Find which node has the lower local index in this element
786  unsigned local_indexA = p_element->GetNodeLocalIndex(node_A_index);
787  unsigned local_indexB = p_element->GetNodeLocalIndex(node_B_index);
788 
789  unsigned index = local_indexB;
790 
791  // If node B has a higher index then use node A's index...
792  if (local_indexB > local_indexA)
793  {
794  index = local_indexA;
795 
796  // ...unless nodes A and B share the element's last edge
797  if ((local_indexA == 0) && (local_indexB == p_element->GetNumNodes()-1))
798  {
799  index = local_indexB;
800  }
801  }
802  else if ((local_indexB == 0) && (local_indexA == p_element->GetNumNodes()-1))
803  {
804  // ...otherwise use node B's index, unless nodes A and B share the element's last edge
805  index = local_indexA;
806  }
807 
808  // Add new node to this element
809  this->GetElement(*iter)->AddNode(p_new_node, index);
810  }
811 }
812 
813 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
815 {
816  // Make sure the map is big enough. Each entry will be set in the loop below.
817  rElementMap.Resize(this->GetNumAllElements());
818 
819  // Remove any elements that have been marked for deletion and store all other elements in a temporary structure
820  std::vector<VertexElement<ELEMENT_DIM, SPACE_DIM>*> live_elements;
821  for (unsigned i=0; i<this->mElements.size(); i++)
822  {
823  if (this->mElements[i]->IsDeleted())
824  {
825  delete this->mElements[i];
826  rElementMap.SetDeleted(i);
827  }
828  else
829  {
830  live_elements.push_back(this->mElements[i]);
831  rElementMap.SetNewIndex(i, (unsigned)(live_elements.size()-1));
832  }
833  }
834 
835  // Sanity check
836  assert(mDeletedElementIndices.size() == this->mElements.size() - live_elements.size());
837 
838  // Repopulate the elements vector and reset the list of deleted element indices
839  mDeletedElementIndices.clear();
840  this->mElements = live_elements;
841 
842  // Finally, reset the element indices to run from zero
843  for (unsigned i=0; i<this->mElements.size(); i++)
844  {
845  this->mElements[i]->ResetIndex(i);
846  }
847 
848  // Remove deleted nodes
850 }
851 
852 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
854 {
855  // Remove any nodes that have been marked for deletion and store all other nodes in a temporary structure
856  std::vector<Node<SPACE_DIM>*> live_nodes;
857  for (unsigned i=0; i<this->mNodes.size(); i++)
858  {
859  if (this->mNodes[i]->IsDeleted())
860  {
861  delete this->mNodes[i];
862  }
863  else
864  {
865  live_nodes.push_back(this->mNodes[i]);
866  }
867  }
868 
869  // Sanity check
870  assert(mDeletedNodeIndices.size() == this->mNodes.size() - live_nodes.size());
871 
872  // Repopulate the nodes vector and reset the list of deleted node indices
873  this->mNodes = live_nodes;
874  mDeletedNodeIndices.clear();
875 
876  // Finally, reset the node indices to run from zero
877  for (unsigned i=0; i<this->mNodes.size(); i++)
878  {
879  this->mNodes[i]->SetIndex(i);
880  }
881 }
882 
883 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
885 {
886  // Make sure that we are in the correct dimension - this code will be eliminated at compile time
887  assert(SPACE_DIM==2 || SPACE_DIM==3); // LCOV_EXCL_LINE
888  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE
889 
890 
891  if (SPACE_DIM == 2)
892  {
893  // Make sure the map is big enough
894  rElementMap.Resize(this->GetNumAllElements());
895 
896  /*
897  * To begin the remeshing process, we do not need to call Clear() and remove all current data,
898  * since cell birth, rearrangement and death result only in local remeshing of a vertex-based
899  * mesh. Instead, we just remove any deleted elements and nodes.
900  */
901  RemoveDeletedNodesAndElements(rElementMap);
902  bool recheck_mesh = true;
903  while (recheck_mesh == true)
904  {
905  // We check for any short edges and perform swaps if necessary and possible.
906  recheck_mesh = CheckForSwapsFromShortEdges();
907  }
908 
909  // Check for element intersections
910  recheck_mesh = true;
911  while (recheck_mesh == true)
912  {
913  // Check mesh for intersections, and perform T3 swaps where required
914  recheck_mesh = CheckForIntersections();
915  }
916 
918 
919  /*
920  * This is handled in a separate method to allow child classes to implement additional ReMeshing functionality
921  * (see #2664).
922  */
923  this->CheckForRosettes();
924  }
925  else // 3D
926  {
927 // LCOV_EXCL_START
928  EXCEPTION("Remeshing has not been implemented in 3D (see #827 and #860)\n");
929 // LCOV_EXCL_STOP
931  }
932 }
933 
934 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
936 {
938  ReMesh(map);
939 }
940 
941 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
943 {
944  // Loop over elements to check for T1 swaps
946  elem_iter != this->GetElementIteratorEnd();
947  ++elem_iter)
948  {
950 
951  unsigned num_nodes = elem_iter->GetNumNodes();
952  assert(num_nodes > 0);
953 
954  // Loop over the nodes contained in this element
955  for (unsigned local_index=0; local_index<num_nodes; local_index++)
956  {
957  // Find locations of the current node and anticlockwise node
958  Node<SPACE_DIM>* p_current_node = elem_iter->GetNode(local_index);
959  unsigned local_index_plus_one = (local_index+1)%num_nodes;
960  Node<SPACE_DIM>* p_anticlockwise_node = elem_iter->GetNode(local_index_plus_one);
961 
962  // Find distance between nodes
963  double distance_between_nodes = this->GetDistanceBetweenNodes(p_current_node->GetIndex(), p_anticlockwise_node->GetIndex());
964 
965  // If the nodes are too close together...
966  if (distance_between_nodes < mCellRearrangementThreshold)
967  {
968  // ...then check if any triangular elements are shared by these nodes...
969  std::set<unsigned> elements_of_node_a = p_current_node->rGetContainingElementIndices();
970  std::set<unsigned> elements_of_node_b = p_anticlockwise_node->rGetContainingElementIndices();
971 
972  std::set<unsigned> shared_elements;
973  std::set_intersection(elements_of_node_a.begin(), elements_of_node_a.end(),
974  elements_of_node_b.begin(), elements_of_node_b.end(),
975  std::inserter(shared_elements, shared_elements.begin()));
976 
977  bool both_nodes_share_triangular_element = false;
978  for (std::set<unsigned>::const_iterator it = shared_elements.begin();
979  it != shared_elements.end();
980  ++it)
981  {
982  if (this->GetElement(*it)->GetNumNodes() <= 3)
983  {
984  both_nodes_share_triangular_element = true;
985  break;
986  }
987  }
988 
989  // ...and if none are, then perform the required type of swap and halt the search, returning true
990  if (!both_nodes_share_triangular_element)
991  {
992  IdentifySwapType(p_current_node, p_anticlockwise_node);
993  return true;
994  }
995  }
996  }
997  }
998 
999  return false;
1000 }
1001 
1002 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1004 {
1005  // Loop over elements to check for T2 swaps
1007  elem_iter != this->GetElementIteratorEnd();
1008  ++elem_iter)
1009  {
1010  // If this element is triangular...
1011  if (elem_iter->GetNumNodes() == 3)
1012  {
1013  // ...and smaller than the threshold area...
1014  if (this->GetVolumeOfElement(elem_iter->GetIndex()) < GetT2Threshold())
1015  {
1016  // ...then perform a T2 swap and break out of the loop
1017  PerformT2Swap(*elem_iter);
1019  rElementMap.SetDeleted(elem_iter->GetIndex());
1020  return true;
1021  }
1022  }
1023  }
1024  return false;
1025 }
1026 
1027 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1029 {
1030  // If checking for internal intersections as well as on the boundary, then check that no nodes have overlapped any elements...
1032  {
1033  // First neighbours are elements that contain the node. Second
1034  // neighbours are elements that share a cell-cell boundary with first
1035  // neighbours, but do not contain the node. Nodes can only intersect
1036  // second neighbours.
1037  for (auto node_iter = this->GetNodeIteratorBegin();
1038  node_iter != this->GetNodeIteratorEnd();
1039  ++node_iter)
1040  {
1041  assert(!(node_iter->IsDeleted()));
1042 
1043  // Get all nodes of first neighbours
1044  std::set<unsigned> first_neighbour_node_indices;
1045 
1046  auto first_neighbour_indices = node_iter->rGetContainingElementIndices();
1047 
1048  for (auto elem_iter = first_neighbour_indices.begin();
1049  elem_iter != first_neighbour_indices.end();
1050  ++elem_iter)
1051  {
1052  auto p_element = this->GetElement(*elem_iter);
1053 
1054  for (auto local_node_index = 0u;
1055  local_node_index < p_element->GetNumNodes();
1056  ++local_node_index)
1057  {
1058  first_neighbour_node_indices.insert(p_element->GetNodeGlobalIndex(local_node_index));
1059  }
1060  }
1061 
1062  // Get all first and second neighbours
1063  std::set<unsigned> all_neighbours;
1064 
1065  for (auto second_node_iter = first_neighbour_node_indices.begin();
1066  second_node_iter != first_neighbour_node_indices.end();
1067  ++second_node_iter)
1068  {
1069  auto containing_element_indices =
1070  this->GetNode(*second_node_iter)->rGetContainingElementIndices();
1071  all_neighbours.insert(containing_element_indices.begin(),
1072  containing_element_indices.end());
1073  }
1074 
1075  // Second neighbours are the difference between all neighbours and
1076  // first neighbours
1077  std::set<unsigned> second_neighbour_indices;
1078  std::set_difference(
1079  all_neighbours.begin(), all_neighbours.end(),
1080  first_neighbour_indices.begin(), first_neighbour_indices.end(),
1081  std::inserter(second_neighbour_indices, second_neighbour_indices.begin()));
1082 
1083  // Loop over second neighbours only
1084  for (auto elem_iter = second_neighbour_indices.begin();
1085  elem_iter != second_neighbour_indices.end();
1086  ++elem_iter)
1087  {
1088  unsigned elem_index = *elem_iter;
1089 
1090  // Node should not be part of this element
1091  assert(node_iter->rGetContainingElementIndices().count(elem_index) == 0);
1092 
1093  if (this->ElementIncludesPoint(node_iter->rGetLocation(), elem_index))
1094  {
1095  PerformIntersectionSwap(&(*node_iter), elem_index);
1096  return true;
1097  }
1098  }
1099  }
1100  }
1101  else
1102  {
1103  // ...otherwise, just check that no boundary nodes have overlapped any boundary elements
1104  // First: find all boundary element and calculate their centroid only once
1105  std::vector<unsigned> boundary_element_indices;
1106  std::vector< c_vector<double, SPACE_DIM> > boundary_element_centroids;
1108  elem_iter != this->GetElementIteratorEnd();
1109  ++elem_iter)
1110  {
1111  if (elem_iter->IsElementOnBoundary())
1112  {
1113  unsigned element_index = elem_iter->GetIndex();
1114  boundary_element_indices.push_back(element_index);
1115  // should be a map but I am too lazy to look up the syntax
1116  boundary_element_centroids.push_back(this->GetCentroidOfElement(element_index));
1117  }
1118  }
1119 
1120  // Second: Check intersections only for those nodes and elements within
1121  // mDistanceForT3SwapChecking within each other (node<-->element centroid)
1123  node_iter != this->GetNodeIteratorEnd();
1124  ++node_iter)
1125  {
1126  if (node_iter->IsBoundaryNode())
1127  {
1128  assert(!(node_iter->IsDeleted()));
1129 
1130  // index in boundary_element_centroids and boundary_element_indices
1131  unsigned boundary_element_index = 0;
1132  for (std::vector<unsigned>::iterator elem_iter = boundary_element_indices.begin();
1133  elem_iter != boundary_element_indices.end();
1134  ++elem_iter)
1135  {
1136  // Check that the node is not part of this element
1137  if (node_iter->rGetContainingElementIndices().count(*elem_iter) == 0)
1138  {
1139  c_vector<double, SPACE_DIM> node_location = node_iter->rGetLocation();
1140  c_vector<double, SPACE_DIM> element_centroid = boundary_element_centroids[boundary_element_index];
1141  double node_element_distance = norm_2(this->GetVectorFromAtoB(node_location, element_centroid));
1142 
1143  if ( node_element_distance < mDistanceForT3SwapChecking )
1144  {
1145  if (this->ElementIncludesPoint(node_iter->rGetLocation(), *elem_iter))
1146  {
1147  this->PerformT3Swap(&(*node_iter), *elem_iter);
1148  return true;
1149  }
1150  }
1151  }
1152  // increment the boundary element index
1153  boundary_element_index +=1u;
1154  }
1155  }
1156  }
1157 
1158  }
1159  return false;
1160 }
1161 
1162 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1164 {
1165  // Find the sets of elements containing nodes A and B
1166  std::set<unsigned> nodeA_elem_indices = pNodeA->rGetContainingElementIndices();
1167  std::set<unsigned> nodeB_elem_indices = pNodeB->rGetContainingElementIndices();
1168 
1169  // Form the set union
1170  std::set<unsigned> all_indices, temp_union_set;
1171  std::set_union(nodeA_elem_indices.begin(), nodeA_elem_indices.end(),
1172  nodeB_elem_indices.begin(), nodeB_elem_indices.end(),
1173  std::inserter(temp_union_set, temp_union_set.begin()));
1174  all_indices.swap(temp_union_set); // temp_set will be deleted, all_indices now contains all the indices of elements
1175  // that touch the potentially swapping nodes
1176 
1177  if ((nodeA_elem_indices.size()>3) || (nodeB_elem_indices.size()>3))
1178  {
1179  /*
1180  * Looks like
1181  *
1182  * \
1183  * \ A B
1184  * ---o---o---
1185  * /
1186  * /
1187  *
1188  */
1189 
1190  /*
1191  * This case is handled in a separate method to allow child classes to implement different
1192  * functionality for high-order-junction remodelling events (see #2664).
1193  */
1194  this->HandleHighOrderJunctions(pNodeA, pNodeB);
1195  }
1196  else // each node is contained in at most three elements
1197  {
1198  switch (all_indices.size())
1199  {
1200  case 1:
1201  {
1202  /*
1203  * Each node is contained in a single element, so the nodes must lie on the boundary
1204  * of the mesh, as shown below. In this case, we merge the nodes and tidy up node
1205  * indices through calls to PerformNodeMerge() and RemoveDeletedNodes().
1206  *
1207  * A B
1208  * ---o---o---
1209  */
1210  assert(pNodeA->IsBoundaryNode());
1211  assert(pNodeB->IsBoundaryNode());
1212 
1213  PerformNodeMerge(pNodeA, pNodeB);
1215  break;
1216  }
1217  case 2:
1218  {
1219  if (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==2)
1220  {
1221  if (pNodeA->IsBoundaryNode() && pNodeB->IsBoundaryNode())
1222  {
1223  /*
1224  * The node configuration is as shown below, with voids on either side. In this case
1225  * we perform a T1 swap, which separates the elements.
1226  *
1227  * \ /
1228  * \ / Node A
1229  * (1) | (2) (element number in brackets)
1230  * / \ Node B
1231  * / \
1232  */
1233  PerformT1Swap(pNodeA, pNodeB,all_indices);
1234  }
1235  else if (pNodeA->IsBoundaryNode() || pNodeB->IsBoundaryNode())
1236  {
1237  /*
1238  * The node configuration is as shown below, with a void on one side. We should not
1239  * be able to reach this case at present, since we allow only for three-way junctions
1240  * or boundaries, so we throw an exception.
1241  *
1242  * \ /
1243  * \ / Node A
1244  * (1) | (2) (element number in brackets)
1245  * x Node B
1246  * |
1247  */
1248  EXCEPTION("There is a non-boundary node contained only in two elements; something has gone wrong.");
1249  }
1250  else
1251  {
1252  /*
1253  * Each node is contained in two elements, so the nodes lie on an internal edge, as shown below.
1254  * We should not be able to reach this case at present, since we allow only for three-way junctions
1255  * or boundaries, so we throw an exception.
1256  *
1257  * A B
1258  * ---o---o---
1259  */
1260  EXCEPTION("There are non-boundary nodes contained only in two elements; something has gone wrong.");
1261  }
1262  }// from [if (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==2)]
1263  else
1264  {
1265  /*
1266  * The node configuration looks like that shown below. In this case, we merge the nodes
1267  * and tidy up node indices through calls to PerformNodeMerge() and RemoveDeletedNodes().
1268  *
1269  * Outside
1270  * /
1271  * --o--o (2)
1272  * (1) \
1273  *
1274  * ///\todo this should be a T1 swap (see #1263 and #2401)
1275  * Referring to the todo: this should probably stay a node-merge. If this is a T1 swap then
1276  * the single boundary node will travel from element 1 to element 2, but still remain a single node.
1277  * I.e. we would not reduce the total number of nodes in this situation.
1278  */
1279  PerformNodeMerge(pNodeA, pNodeB);
1281  }
1282  break;
1283  }
1284  case 3:
1285  {
1286  if (nodeA_elem_indices.size()==1 || nodeB_elem_indices.size()==1)
1287  {
1288  /*
1289  * One node is contained in one element and the other node is contained in three elements.
1290  * We should not be able to reach this case at present, since we allow each boundary node
1291  * to be contained in at most two elements, so we throw an exception.
1292  *
1293  * A B
1294  *
1295  * empty /
1296  * / (3)
1297  * ---o---o----- (element number in brackets)
1298  * (1) \ (2)
1299  * \
1300  */
1301  assert(pNodeA->IsBoundaryNode());
1302  assert(pNodeB->IsBoundaryNode());
1303 
1304  EXCEPTION("There is a boundary node contained in three elements something has gone wrong.");
1305  }
1306  else if (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==2)
1307  {
1308  // The short edge must be at the boundary. We need to check whether this edge is
1309  // adjacent to a triangular void before we swap. If it is a triangular void, we perform a T2-type swap.
1310  // If not, then we perform a normal T1 swap. I.e. in detail we need to check whether the
1311  // element in nodeA_elem_indices which is not in nodeB_elem_indices contains a shared node
1312  // with the element in nodeB_elem_indices which is not in nodeA_elem_indices.
1313 
1314  std::set<unsigned> element_A_not_B, temp_set;
1315  std::set_difference(all_indices.begin(), all_indices.end(), nodeB_elem_indices.begin(),
1316  nodeB_elem_indices.end(), std::inserter(temp_set, temp_set.begin()));
1317  element_A_not_B.swap(temp_set);
1318 
1319  // There must be only one such element
1320  assert(element_A_not_B.size() == 1);
1321 
1322  std::set<unsigned> element_B_not_A;
1323  std::set_difference(all_indices.begin(), all_indices.end(), nodeA_elem_indices.begin(),
1324  nodeA_elem_indices.end(), std::inserter(temp_set, temp_set.begin()));
1325  element_B_not_A.swap(temp_set);
1326 
1327  // There must be only one such element
1328  assert(element_B_not_A.size() == 1);
1329 
1330  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_A_not_B = this->mElements[*element_A_not_B.begin()];
1331  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_B_not_A = this->mElements[*element_B_not_A.begin()];
1332 
1333  unsigned local_index_1 = p_element_A_not_B->GetNodeLocalIndex(pNodeA->GetIndex());
1334  unsigned next_node_1 = p_element_A_not_B->GetNodeGlobalIndex((local_index_1 + 1)%(p_element_A_not_B->GetNumNodes()));
1335  unsigned previous_node_1 = p_element_A_not_B->GetNodeGlobalIndex(
1336  (local_index_1 + p_element_A_not_B->GetNumNodes() - 1)%(p_element_A_not_B->GetNumNodes()));
1337  unsigned local_index_2 = p_element_B_not_A->GetNodeLocalIndex(pNodeB->GetIndex());
1338  unsigned next_node_2 = p_element_B_not_A->GetNodeGlobalIndex(
1339  (local_index_2 + 1)%(p_element_B_not_A->GetNumNodes()));
1340  unsigned previous_node_2 = p_element_B_not_A->GetNodeGlobalIndex(
1341  (local_index_2 + p_element_B_not_A->GetNumNodes() - 1)%(p_element_B_not_A->GetNumNodes()));
1342 
1343  if (next_node_1 == previous_node_2 || next_node_2 == previous_node_1)
1344  {
1345  /*
1346  * The node configuration looks like that shown below, and both nodes must be on the boundary.
1347  * In this case we remove the void through a call to PerformVoidRemoval().
1348  *
1349  * A C B A B
1350  * /\ \ /
1351  * /v \ \ (1) /
1352  * (3)o----o (1) or (2) o----o (3) (element number in brackets, v is a void)
1353  * / (2) \ \v /
1354  * / \ \/
1355  * C
1356  */
1357  assert(pNodeA->IsBoundaryNode());
1358  assert(pNodeB->IsBoundaryNode());
1359 
1360  // Get the third node in the triangular void
1361 
1362  unsigned nodeC_index;
1363  if (next_node_1 == previous_node_2 && next_node_2 != previous_node_1)
1364  {
1365  nodeC_index = next_node_1;
1366  }
1367  else if (next_node_2 == previous_node_1 && next_node_1 != previous_node_2)
1368  {
1369  nodeC_index = next_node_2;
1370  }
1371  else
1372  {
1373  assert(next_node_1 == previous_node_2 && next_node_2 == previous_node_1);
1381  EXCEPTION("Triangular element next to triangular void, not implemented yet.");
1382  }
1383 
1384  if (p_element_A_not_B->GetNumNodes() == 3u || p_element_B_not_A->GetNumNodes() == 3u)
1385  {
1393  EXCEPTION("Triangular element next to triangular void, not implemented yet.");
1394  }
1395 
1396  PerformVoidRemoval(pNodeA, pNodeB, this->mNodes[nodeC_index]);
1397  }
1398  else
1399  {
1400  /*
1401  * The node configuration looks like that below, and both nodes must lie on the boundary.
1402  * In this case we perform a T1 swap.
1403  *
1404  * A B A B
1405  * \ empty/ \ /
1406  * \ / \(1) /
1407  * (3) o--o (1) or (2) o--o (3) (element number in brackets)
1408  * / (2)\ / \
1409  * / \ /empty \
1410  */
1411  assert(pNodeA->IsBoundaryNode());
1412  assert(pNodeB->IsBoundaryNode());
1413 
1414  PerformT1Swap(pNodeA, pNodeB, all_indices);
1415  }
1416  } // from else if (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==2)
1417  else
1418  {
1419  // In this case, one node must be contained in two elements and the other in three elements.
1420  assert ( (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==3)
1421  || (nodeA_elem_indices.size()==3 && nodeB_elem_indices.size()==2) );
1422 
1423  // They can't both be boundary nodes
1424  assert(!(pNodeA->IsBoundaryNode() && pNodeB->IsBoundaryNode()));
1425 
1426  if (pNodeA->IsBoundaryNode() || pNodeB->IsBoundaryNode())
1427  {
1428  /*
1429  * The node configuration looks like that shown below. We perform a T1 swap in this case.
1430  *
1431  * A B A B
1432  * \ / \ /
1433  * \ (1)/ \(1) /
1434  * (3) o--o (empty) or (empty) o--o (3) (element number in brackets)
1435  * / (2)\ /(2) \
1436  * / \ / \
1437  */
1438  PerformT1Swap(pNodeA, pNodeB, all_indices);
1439  }
1440  else
1441  {
1442  /*
1443  * The node configuration looks like that shown below. We should not be able to reach this case
1444  * at present, since we allow only for three-way junctions or boundaries, so we throw an exception.
1445  *
1446  * A B A B
1447  * \ /
1448  * \ (1) (1) /
1449  * (3) o--o--- or ---o--o (3) (element number in brackets)
1450  * / (2) (2) \
1451  * / \
1452  */
1453  EXCEPTION("There are non-boundary nodes contained only in two elements; something has gone wrong.");
1454  }
1455  }
1456  break;
1457  }
1458  case 4:
1459  {
1460  /*
1461  * The node configuration looks like that shown below. We perform a T1 swap in this case.
1462  *
1463  * \(1)/
1464  * \ / Node A
1465  * (2) | (4) (element number in brackets)
1466  * / \ Node B
1467  * /(3)\
1468  */
1469 
1470  /*
1471  * This case is handled in a separate method to allow child classes to implement different
1472  * functionality for junction remodelling events (see #2664).
1473  */
1475  {
1476  this->PerformNodeMerge(pNodeA, pNodeB);
1477  this->RemoveDeletedNodes();
1478  }
1479  else
1480  {
1481  this->PerformT1Swap(pNodeA, pNodeB, all_indices);
1482  }
1483  break;
1484  }
1485  default:
1486  // This can't happen
1487  NEVER_REACHED;
1488  }
1489  }
1490 }
1491 
1492 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1494 {
1495  // Find the sets of elements containing each of the nodes, sorted by index
1496  std::set<unsigned> nodeA_elem_indices = pNodeA->rGetContainingElementIndices();
1497  std::set<unsigned> nodeB_elem_indices = pNodeB->rGetContainingElementIndices();
1498 
1499  // Move node A to the mid-point
1500  pNodeA->rGetModifiableLocation() += 0.5 * this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeB->rGetLocation());
1501 
1502  // Update the elements previously containing node B to contain node A
1503  unsigned node_B_index = pNodeB->GetIndex();
1504  for (std::set<unsigned>::const_iterator it = nodeB_elem_indices.begin(); it != nodeB_elem_indices.end(); ++it)
1505  {
1506  // Find the local index of node B in this element
1507  unsigned node_B_local_index = this->mElements[*it]->GetNodeLocalIndex(node_B_index);
1508  assert(node_B_local_index < UINT_MAX); // this element contains node B
1509 
1510  /*
1511  * If this element already contains node A, then just remove node B.
1512  * Otherwise replace it with node A in the element and remove it from mNodes.
1513  */
1514  if (nodeA_elem_indices.count(*it) != 0)
1515  {
1516  this->mElements[*it]->DeleteNode(node_B_local_index);
1517  }
1518  else
1519  {
1520  // Replace node B with node A in this element
1521  this->mElements[*it]->UpdateNode(node_B_local_index, pNodeA);
1522  }
1523  }
1524 
1525  assert(!(this->mNodes[node_B_index]->IsDeleted()));
1526  this->mNodes[node_B_index]->MarkAsDeleted();
1527  mDeletedNodeIndices.push_back(node_B_index);
1528 }
1529 
1530 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1532  Node<SPACE_DIM>* pNodeB,
1533  std::set<unsigned>& rElementsContainingNodes)
1534 {
1535  // First compute and store the location of the T1 swap, which is at the midpoint of nodes A and B
1536  double distance_between_nodes_CD = mCellRearrangementRatio*mCellRearrangementThreshold;
1537 
1538  c_vector<double, SPACE_DIM> nodeA_location = pNodeA->rGetLocation();
1539  c_vector<double, SPACE_DIM> nodeB_location = pNodeB->rGetLocation();
1540  c_vector<double, SPACE_DIM> vector_AB = this->GetVectorFromAtoB(nodeA_location, nodeB_location);
1541  mLocationsOfT1Swaps.push_back(nodeA_location + 0.5*vector_AB);
1542 
1543  double distance_AB = norm_2(vector_AB);
1544  if (distance_AB < 1e-10)
1545  {
1546  EXCEPTION("Nodes are too close together, this shouldn't happen");
1547  }
1548 
1549  /*
1550  * Compute the locations of two new nodes C, D, placed on either side of the
1551  * edge E_old formed by nodes A and B, such that the edge E_new formed by the
1552  * new nodes is the perpendicular bisector of E_old, with |E_new| 'just larger'
1553  * (mCellRearrangementRatio) than mThresholdDistance.
1554  *
1555  * We implement the following changes to the mesh:
1556  *
1557  * The element whose index was in nodeA_elem_indices but not nodeB_elem_indices,
1558  * and the element whose index was in nodeB_elem_indices but not nodeA_elem_indices,
1559  * should now both contain nodes A and B.
1560  *
1561  * The element whose index was in nodeA_elem_indices and nodeB_elem_indices, and which
1562  * node C lies inside, should now only contain node A.
1563  *
1564  * The element whose index was in nodeA_elem_indices and nodeB_elem_indices, and which
1565  * node D lies inside, should now only contain node B.
1566  *
1567  * Iterate over all elements involved and identify which element they are
1568  * in the diagram then update the nodes as necessary.
1569  *
1570  * \(1)/
1571  * \ / Node A
1572  * (2) | (4) elements in brackets
1573  * / \ Node B
1574  * /(3)\
1575  */
1576 
1577  // Move nodes A and B to C and D respectively
1578  c_vector<double, SPACE_DIM> vector_CD;
1579  vector_CD(0) = -vector_AB(1) * distance_between_nodes_CD / distance_AB;
1580  vector_CD(1) = vector_AB(0) * distance_between_nodes_CD / distance_AB;
1581 
1582  c_vector<double, SPACE_DIM> nodeC_location = nodeA_location + 0.5*vector_AB - 0.5*vector_CD;
1583  c_vector<double, SPACE_DIM> nodeD_location = nodeC_location + vector_CD;
1584 
1585  pNodeA->rGetModifiableLocation() = nodeC_location;
1586  pNodeB->rGetModifiableLocation() = nodeD_location;
1587 
1588  // Find the sets of elements containing nodes A and B
1589  std::set<unsigned> nodeA_elem_indices = pNodeA->rGetContainingElementIndices();
1590  std::set<unsigned> nodeB_elem_indices = pNodeB->rGetContainingElementIndices();
1591 
1592  for (std::set<unsigned>::const_iterator it = rElementsContainingNodes.begin();
1593  it != rElementsContainingNodes.end();
1594  ++it)
1595  {
1596  // If, as in element 3 above, this element does not contain node A (now C)...
1597  if (nodeA_elem_indices.find(*it) == nodeA_elem_indices.end())
1598  {
1599  // ...then add it to the element just after node B (now D), going anticlockwise
1600  unsigned nodeB_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeB->GetIndex());
1601  assert(nodeB_local_index < UINT_MAX);
1602 
1603  this->mElements[*it]->AddNode(pNodeA, nodeB_local_index);
1604  }
1605  else if (nodeB_elem_indices.find(*it) == nodeB_elem_indices.end())
1606  {
1607  // Do similarly if the element does not contain node B (now D), as in element 4 above
1608  unsigned nodeA_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeA->GetIndex());
1609  assert(nodeA_local_index < UINT_MAX);
1610 
1611  this->mElements[*it]->AddNode(pNodeB, nodeA_local_index);
1612  }
1613  else
1614  {
1615  // If the element contains both nodes A and B (now C and D respectively)...
1616  unsigned nodeA_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeA->GetIndex());
1617  unsigned nodeB_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeB->GetIndex());
1618 
1619  assert(nodeA_local_index < UINT_MAX);
1620  assert(nodeB_local_index < UINT_MAX);
1621 
1622  /*
1623  * Locate local index of nodeA and nodeB and use the ordering to
1624  * identify the element, if nodeB_index > nodeA_index then element 4
1625  * and if nodeA_index > nodeB_index then element 2
1626  */
1627  unsigned nodeB_local_index_plus_one = (nodeB_local_index + 1)%(this->mElements[*it]->GetNumNodes());
1628 
1629  if (nodeA_local_index == nodeB_local_index_plus_one)
1630  {
1631  /*
1632  * In this case the local index of nodeA is the local index of
1633  * nodeB plus one so we are in element 2 so we remove nodeB
1634  */
1635  this->mElements[*it]->DeleteNode(nodeB_local_index);
1636  }
1637  else
1638  {
1639  assert(nodeB_local_index == (nodeA_local_index + 1)%(this->mElements[*it]->GetNumNodes())); // as A and B are next to each other
1640  /*
1641  * In this case the local index of nodeA is the local index of
1642  * nodeB minus one so we are in element 4 so we remove nodeA
1643  */
1644  this->mElements[*it]->DeleteNode(nodeA_local_index);
1645  }
1646  }
1647  }
1648 
1649  // Sort out boundary nodes
1650  if (pNodeA->IsBoundaryNode() || pNodeB->IsBoundaryNode())
1651  {
1652  if (pNodeA->GetNumContainingElements() == 3)
1653  {
1654  pNodeA->SetAsBoundaryNode(false);
1655  }
1656  else
1657  {
1658  pNodeA->SetAsBoundaryNode(true);
1659  }
1660  if (pNodeB->GetNumContainingElements() == 3)
1661  {
1662  pNodeB->SetAsBoundaryNode(false);
1663  }
1664  else
1665  {
1666  pNodeB->SetAsBoundaryNode(true);
1667  }
1668  }
1669 }
1670 
1671 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1673 {
1674  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
1675  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE
1676 
1677 
1678  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elementIndex);
1679  unsigned num_nodes = p_element->GetNumNodes();
1680 
1681  std::set<unsigned> elements_containing_intersecting_node;
1682 
1683  for (unsigned node_local_index=0; node_local_index<num_nodes; node_local_index++)
1684  {
1685  unsigned node_global_index = p_element->GetNodeGlobalIndex(node_local_index);
1686 
1687  std::set<unsigned> node_elem_indices = this->GetNode(node_global_index)->rGetContainingElementIndices();
1688 
1689  for (std::set<unsigned>::const_iterator elem_iter = node_elem_indices.begin();
1690  elem_iter != node_elem_indices.end();
1691  ++elem_iter)
1692  {
1693  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_neighbouring_element = this->GetElement(*elem_iter);
1694  unsigned num_nodes_in_neighbouring_element = p_neighbouring_element->GetNumNodes();
1695 
1696  // Check if element contains the intersecting node
1697  for (unsigned node_index_2 = 0; node_index_2 < num_nodes_in_neighbouring_element; node_index_2++)
1698  {
1699  if (p_neighbouring_element->GetNodeGlobalIndex(node_index_2) == pNode->GetIndex())
1700  {
1701  elements_containing_intersecting_node.insert(p_neighbouring_element->GetIndex());
1702  }
1703  }
1704  }
1705  }
1706 
1707  std::set<unsigned> all_elements_containing_intersecting_node = pNode->rGetContainingElementIndices();
1708 
1709  assert(elements_containing_intersecting_node.size() >= 1);
1710  assert(all_elements_containing_intersecting_node.size() >= 1);
1711 
1712  /*
1713  * Identify nodes and elements to perform switch on
1714  * Intersecting node is node A
1715  * Other node is node B
1716  *
1717  * Element 1 only contains node A
1718  * Element 2 has nodes B and A (in that order)
1719  * Element 3 only contains node B
1720  * Element 4 has nodes A and B (in that order)
1721  *
1722  * If node A is a boundary node, then elements 1, 2, or 4 can be missing.
1723  */
1724  unsigned node_A_index = pNode->GetIndex();
1725  unsigned node_B_index = UINT_MAX;
1726 
1727  unsigned element_1_index = UINT_MAX;
1728  unsigned element_2_index = UINT_MAX;
1729  unsigned element_3_index = elementIndex;
1730  unsigned element_4_index = UINT_MAX;
1731 
1732  // Get element 1
1733  std::set<unsigned> intersecting_element;
1734 
1735  std::set_difference(all_elements_containing_intersecting_node.begin(), all_elements_containing_intersecting_node.end(),
1736  elements_containing_intersecting_node.begin(), elements_containing_intersecting_node.end(),
1737  std::inserter(intersecting_element, intersecting_element.begin()));
1738 
1739  if (intersecting_element.size() == 1)
1740  {
1741  element_1_index = *(intersecting_element.begin());
1742  }
1743 
1744  // Get element A
1745  std::set<unsigned>::iterator iter = elements_containing_intersecting_node.begin();
1746  unsigned element_a_index = *(iter);
1747  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_a = this->GetElement(element_a_index);
1748 
1749  // Get element B
1750  unsigned element_b_index = UINT_MAX;
1751  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_b = nullptr;
1752  if (elements_containing_intersecting_node.size() == 2)
1753  {
1754  iter++;
1755  element_b_index = *(iter);
1756  p_element_b = this->GetElement(element_b_index);
1757  }
1758 
1759  // T1 swaps can sometimes result in a concave triangular element (#3067)
1760  if ((p_element_a->GetNumNodes() == 3) || ((p_element_b != nullptr) && p_element_b->GetNumNodes() == 3))
1761  {
1762  EXCEPTION("A triangular element has become concave. "
1763  "You need to rerun the simulation with a smaller time step to prevent this.");
1764  }
1765 
1766  // Get node B index
1767  unsigned node_A_local_index_in_a = p_element_a->GetNodeLocalIndex(node_A_index);
1768 
1769  unsigned node_before_A_in_a = (node_A_local_index_in_a + p_element_a->GetNumNodes() - 1) % p_element_a->GetNumNodes();
1770  unsigned node_after_A_in_a = (node_A_local_index_in_a + 1) % p_element_a->GetNumNodes();
1771 
1772  unsigned global_node_before_A_in_a = p_element_a->GetNodeGlobalIndex(node_before_A_in_a);
1773  unsigned global_node_after_A_in_a = p_element_a->GetNodeGlobalIndex(node_after_A_in_a);
1774 
1775  for (unsigned node_index = 0; node_index < num_nodes; ++node_index)
1776  {
1777  if (p_element->GetNodeGlobalIndex(node_index) == global_node_before_A_in_a)
1778  {
1779  node_B_index = global_node_before_A_in_a;
1780  break;
1781  }
1782  else if (p_element->GetNodeGlobalIndex(node_index) == global_node_after_A_in_a)
1783  {
1784  node_B_index = global_node_after_A_in_a;
1785  break;
1786  }
1787  }
1788  /*
1789  * If node B cannot be found then there are no nodes before or after node A
1790  * in element a that are contained in the intersected element, and there is
1791  * no way to fix it unless you want to make two new elements.
1792  */
1793  if (node_B_index == UINT_MAX)
1794  {
1795  EXCEPTION("Intersection cannot be resolved without splitting the element into two new elements.");
1796  }
1797 
1798  // Store location of intersection swap, which is at midpoint of nodes A and B
1799  c_vector<double, SPACE_DIM> nodeA_location = pNode->rGetLocation();
1800  c_vector<double, SPACE_DIM> nodeB_location = this->GetNode(node_B_index)->rGetLocation();
1801  c_vector<double, SPACE_DIM> vector_AB = this->GetVectorFromAtoB(nodeA_location, nodeB_location);
1802  mLocationsOfIntersectionSwaps.push_back(nodeA_location + 0.5*vector_AB);
1803 
1804  // Now identify elements 2 and 4
1805  unsigned node_B_local_index_in_a = p_element_a->GetNodeLocalIndex(node_B_index);
1806 
1807  if ((node_B_local_index_in_a+1)%p_element_a->GetNumNodes() == node_A_local_index_in_a)
1808  {
1809 #ifndef NDEBUG
1810  if (element_b_index != UINT_MAX)
1811  {
1812  assert(p_element_b != nullptr);
1813  assert((p_element_b->GetNodeLocalIndex(node_A_index)+1)%p_element_b->GetNumNodes()
1814  == p_element_b->GetNodeLocalIndex(node_B_index));
1815  }
1816 #endif
1817 
1818  // Element 2 is element a, element 4 is element b
1819  element_2_index = element_a_index;
1820  element_4_index = element_b_index;
1821  }
1822  else
1823  {
1824 #ifndef NDEBUG
1825  if (element_b_index != UINT_MAX)
1826  {
1827  assert(p_element_b != nullptr);
1828  assert((p_element_b->GetNodeLocalIndex(node_B_index)+1)%p_element_b->GetNumNodes()
1829  == p_element_b->GetNodeLocalIndex(node_A_index));
1830  }
1831 #endif
1832 
1833  // Element 2 is element b, element 4 is element a
1834  element_2_index = element_b_index;
1835  element_4_index = element_a_index;
1836  }
1837 
1838  // Get local indices
1839  unsigned intersected_edge = this->GetLocalIndexForElementEdgeClosestToPoint(pNode->rGetLocation(), elementIndex);
1840 
1841  unsigned node_A_local_index_in_1 = UINT_MAX;
1842  if (element_1_index != UINT_MAX)
1843  {
1844  node_A_local_index_in_1 = this->GetElement(element_1_index)->GetNodeLocalIndex(node_A_index);
1845  }
1846 
1847  unsigned node_A_local_index_in_2 = UINT_MAX;
1848  unsigned node_B_local_index_in_2 = UINT_MAX;
1849 
1850  if (element_2_index != UINT_MAX)
1851  {
1852  node_A_local_index_in_2 = this->GetElement(element_2_index)->GetNodeLocalIndex(node_A_index);
1853  node_B_local_index_in_2 = this->GetElement(element_2_index)->GetNodeLocalIndex(node_B_index);
1854  }
1855 
1856  unsigned node_B_local_index_in_3 = this->GetElement(elementIndex)->GetNodeLocalIndex(node_B_index);
1857 
1858  unsigned node_A_local_index_in_4 = UINT_MAX;
1859  unsigned node_B_local_index_in_4 = UINT_MAX;
1860 
1861  if (element_4_index != UINT_MAX)
1862  {
1863  node_A_local_index_in_4 = this->GetElement(element_4_index)->GetNodeLocalIndex(node_A_index);
1864  node_B_local_index_in_4 = this->GetElement(element_4_index)->GetNodeLocalIndex(node_B_index);
1865  }
1866 
1867  // Switch nodes
1868  if (intersected_edge==node_B_local_index_in_3)
1869  {
1870  /*
1871  * Add node B to element 1 after node A
1872  * Add node A to element 3 after node B
1873  *
1874  * Remove node B from element 2
1875  * Remove node A from element 4
1876  */
1877  if (element_1_index != UINT_MAX)
1878  {
1879  assert(node_A_local_index_in_1 != UINT_MAX);
1880  this->mElements[element_1_index]->AddNode(this->mNodes[node_B_index], node_A_local_index_in_1);
1881  }
1882  this->mElements[element_3_index]->AddNode(this->mNodes[node_A_index], node_B_local_index_in_3);
1883 
1884  if (element_2_index != UINT_MAX)
1885  {
1886  assert(node_B_local_index_in_2 != UINT_MAX);
1887  this->mElements[element_2_index]->DeleteNode(node_B_local_index_in_2);
1888  }
1889  if (element_4_index != UINT_MAX)
1890  {
1891  assert(node_A_local_index_in_4 != UINT_MAX);
1892  this->mElements[element_4_index]->DeleteNode(node_A_local_index_in_4);
1893  }
1894  }
1895  else
1896  {
1897  assert((intersected_edge+1)%num_nodes==node_B_local_index_in_3);
1898 
1899  // Add node B to element 1 before node A and add node A to element 3 before node B
1900  if (element_1_index != UINT_MAX)
1901  {
1902  assert(node_A_local_index_in_1 != UINT_MAX);
1903  unsigned node_before_A_in_1 = (node_A_local_index_in_1 + this->GetElement(element_1_index)->GetNumNodes() - 1)%this->GetElement(element_1_index)->GetNumNodes();
1904  this->mElements[element_1_index]->AddNode(this->mNodes[node_B_index], node_before_A_in_1);
1905  }
1906 
1907  unsigned node_before_B_in_3 = (node_B_local_index_in_3 + this->GetElement(element_3_index)->GetNumNodes() - 1)%this->GetElement(element_3_index)->GetNumNodes();
1908  this->mElements[element_3_index]->AddNode(this->mNodes[node_A_index], node_before_B_in_3);
1909 
1910  // Remove node A from element 2 and remove node B from element 4
1911  if (element_2_index != UINT_MAX)
1912  {
1913  assert(node_A_local_index_in_2 != UINT_MAX);
1914  this->mElements[element_2_index]->DeleteNode(node_A_local_index_in_2);
1915  }
1916  if (element_4_index != UINT_MAX)
1917  {
1918  assert(node_B_local_index_in_4 != UINT_MAX);
1919  this->mElements[element_4_index]->DeleteNode(node_B_local_index_in_4);
1920  }
1921  }
1922 
1923  // Set as boundary nodes if intersecting node is a boundary node
1924  if (all_elements_containing_intersecting_node.size() == 2)
1925  {
1926  // Case 1: element 1 is missing
1927  if (elements_containing_intersecting_node.size() == 2)
1928  {
1929  assert(this->mNodes[node_A_index]->IsBoundaryNode() == true);
1930  assert(this->mNodes[node_B_index]->IsBoundaryNode() == false);
1931  this->mNodes[node_B_index]->SetAsBoundaryNode(true);
1932  }
1933  else if (elements_containing_intersecting_node.size() == 1)
1934  {
1935  assert(this->mNodes[node_A_index]->IsBoundaryNode() == true);
1936  assert(this->mNodes[node_B_index]->IsBoundaryNode() == true);
1937  // Case 2: element 2 is missing
1938  if (element_2_index == UINT_MAX)
1939  {
1940  if (intersected_edge==node_B_local_index_in_3)
1941  {
1942  this->mNodes[node_B_index]->SetAsBoundaryNode(false);
1943  }
1944  else
1945  {
1946  this->mNodes[node_A_index]->SetAsBoundaryNode(false);
1947  }
1948  }
1949  // Case 3: element 4 is missing
1950  if (element_4_index == UINT_MAX)
1951  {
1952  if (intersected_edge==node_B_local_index_in_3)
1953  {
1954  this->mNodes[node_A_index]->SetAsBoundaryNode(false);
1955  }
1956  else
1957  {
1958  this->mNodes[node_B_index]->SetAsBoundaryNode(false);
1959  }
1960  }
1961  }
1962  else
1963  {
1964  NEVER_REACHED;
1965  }
1966  }
1967 #ifndef NDEBUG
1968  // Case 4: elements 1 and 2 are missing
1969  // Case 5: elements 1 and 4 are missing
1970  else if (all_elements_containing_intersecting_node.size() == 1)
1971  {
1972  if (elements_containing_intersecting_node.size() == 1)
1973  {
1974  assert(this->mNodes[node_A_index]->IsBoundaryNode() == true);
1975  assert(this->mNodes[node_B_index]->IsBoundaryNode() == true);
1976  }
1977  else
1978  {
1979  NEVER_REACHED;
1980  }
1981  }
1982  // Node A is not a boundary node
1983  else
1984  {
1985  assert(this->mNodes[node_A_index]->IsBoundaryNode() == false);
1986  assert(this->mNodes[node_B_index]->IsBoundaryNode() == false);
1987  }
1988 #endif
1989 }
1990 
1991 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1993 {
1994  // The given element must be triangular for us to be able to perform a T2 swap on it
1995  assert(rElement.GetNumNodes() == 3);
1996 
1997  // Note that we define this vector before setting it, as otherwise the profiling build will break (see #2367)
1998  c_vector<double, SPACE_DIM> new_node_location;
1999  new_node_location = this->GetCentroidOfElement(rElement.GetIndex());
2000  mLastT2SwapLocation = new_node_location;
2001 
2002  // If this element has no neighbours, delete the element, its nodes and exit function
2003  if (this->GetNeighbouringElementIndices(rElement.GetIndex()).size() == 0)
2004  {
2005  mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(0));
2006  mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(1));
2007  mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(2));
2008 
2009  rElement.GetNode(0)->MarkAsDeleted();
2010  rElement.GetNode(1)->MarkAsDeleted();
2011  rElement.GetNode(2)->MarkAsDeleted();
2012 
2013  mDeletedElementIndices.push_back(rElement.GetIndex());
2014  rElement.MarkAsDeleted();
2015 
2016  return;
2017  }
2018 
2019  // Create a new node at the element's centroid; this will be a boundary node if any existing nodes were on the boundary
2020  bool is_node_on_boundary = false;
2021  for (unsigned i=0; i<3; i++)
2022  {
2023  if (rElement.GetNode(i)->IsBoundaryNode())
2024  {
2025  is_node_on_boundary = true;
2026  break;
2027  }
2028  }
2029  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(GetNumNodes(), new_node_location, is_node_on_boundary));
2030  Node<SPACE_DIM>* p_new_node = this->GetNode(new_node_global_index);
2031 
2032  // Loop over each of the three nodes contained in rElement
2033  for (unsigned i=0; i<3; i++)
2034  {
2035  // For each node, find the set of other elements containing it
2036  Node<SPACE_DIM>* p_node = rElement.GetNode(i);
2037  std::set<unsigned> containing_elements = p_node->rGetContainingElementIndices();
2038  containing_elements.erase(rElement.GetIndex());
2039 
2040  // For each of these elements...
2041  for (std::set<unsigned>::iterator elem_iter = containing_elements.begin(); elem_iter != containing_elements.end(); ++elem_iter)
2042  {
2043  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_this_elem = this->GetElement(*elem_iter);
2044 
2045  // ...throw an exception if the element is triangular...
2046  if (p_this_elem->GetNumNodes() < 4)
2047  {
2048  EXCEPTION("One of the neighbours of a small triangular element is also a triangle - dealing with this has not been implemented yet");
2049  }
2050 
2051  // ...otherwise, replace p_node with p_new_node unless this has already happened (in which case, delete p_node from the element)
2052  if (p_this_elem->GetNodeLocalIndex(new_node_global_index) == UINT_MAX)
2053  {
2054  p_this_elem->ReplaceNode(p_node, p_new_node);
2055  }
2056  else
2057  {
2058  p_this_elem->DeleteNode(p_this_elem->GetNodeLocalIndex(p_node->GetIndex()));
2059  }
2060  }
2061  }
2062 
2063  // We also have to mark pElement, pElement->GetNode(0), pElement->GetNode(1), and pElement->GetNode(2) as deleted
2064  mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(0));
2065  mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(1));
2066  mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(2));
2067 
2068  rElement.GetNode(0)->MarkAsDeleted();
2069  rElement.GetNode(1)->MarkAsDeleted();
2070  rElement.GetNode(2)->MarkAsDeleted();
2071 
2072  mDeletedElementIndices.push_back(rElement.GetIndex());
2073  rElement.MarkAsDeleted();
2074 }
2075 
2076 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
2078 {
2079  assert(SPACE_DIM == 2); // LCOV_EXCL_LINE - code will be removed at compile time
2080  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE - code will be removed at compile time
2081 
2082  assert(pNode->IsBoundaryNode());
2083 
2084  // Store the index of the elements containing the intersecting node
2085  std::set<unsigned> elements_containing_intersecting_node = pNode->rGetContainingElementIndices();
2086 
2087  // Get the local index of the node in the intersected element after which the new node is to be added
2088  unsigned node_A_local_index = this->GetLocalIndexForElementEdgeClosestToPoint(pNode->rGetLocation(), elementIndex);
2089 
2090  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
2091  c_vector<double, SPACE_DIM> node_location;
2092  node_location = pNode->rGetModifiableLocation();
2093 
2094  // Get element
2095  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elementIndex);
2096  unsigned num_nodes = p_element->GetNumNodes();
2097 
2098  // Get the nodes at either end of the edge to be divided
2099  unsigned vertexA_index = p_element->GetNodeGlobalIndex(node_A_local_index);
2100  unsigned vertexB_index = p_element->GetNodeGlobalIndex((node_A_local_index+1)%num_nodes);
2101 
2102  // Check these nodes are also boundary nodes if this fails then the elements have become concave and you need a smaller timestep
2103  if (!this->mNodes[vertexA_index]->IsBoundaryNode() || !this->mNodes[vertexB_index]->IsBoundaryNode())
2104  {
2105  EXCEPTION("A boundary node has intersected a non-boundary edge; this is because the boundary element has become concave. You need to rerun the simulation with a smaller time step to prevent this.");
2106  }
2107 
2108  // Get the nodes at either end of the edge to be divided and calculate intersection
2109  c_vector<double, SPACE_DIM> vertexA = p_element->GetNodeLocation(node_A_local_index);
2110  c_vector<double, SPACE_DIM> vertexB = p_element->GetNodeLocation((node_A_local_index+1)%num_nodes);
2111  c_vector<double, SPACE_DIM> vector_a_to_point = this->GetVectorFromAtoB(vertexA, node_location);
2112 
2113  c_vector<double, SPACE_DIM> vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB);
2114 
2115  c_vector<double, SPACE_DIM> edge_ab_unit_vector = vector_a_to_b/norm_2(vector_a_to_b);
2116  c_vector<double, SPACE_DIM> intersection = vertexA + edge_ab_unit_vector*inner_prod(vector_a_to_point, edge_ab_unit_vector);
2117 
2118  // Store the location of the T3 swap, the location of the intersection with the edge
2120  // is called (see #2401) - we should correct this in these cases!
2121 
2122  mLocationsOfT3Swaps.push_back(intersection);
2123 
2124  if (pNode->GetNumContainingElements() == 1)
2125  {
2126  // Get the index of the element containing the intersecting node
2127  unsigned intersecting_element_index = *elements_containing_intersecting_node.begin();
2128 
2129  // Get element
2130  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_intersecting_element = this->GetElement(intersecting_element_index);
2131 
2132  unsigned local_index = p_intersecting_element->GetNodeLocalIndex(pNode->GetIndex());
2133  unsigned next_node = p_intersecting_element->GetNodeGlobalIndex((local_index + 1)%(p_intersecting_element->GetNumNodes()));
2134  unsigned previous_node = p_intersecting_element->GetNodeGlobalIndex((local_index + p_intersecting_element->GetNumNodes() - 1)%(p_intersecting_element->GetNumNodes()));
2135 
2136  // Check to see if the nodes adjacent to the intersecting node are contained in the intersected element between vertices A and B
2137  if (next_node == vertexA_index || previous_node == vertexA_index || next_node == vertexB_index || previous_node == vertexB_index)
2138  {
2139  unsigned common_vertex_index;
2140 
2141  if (next_node == vertexA_index || previous_node == vertexA_index)
2142  {
2143  common_vertex_index = vertexA_index;
2144  }
2145  else
2146  {
2147  common_vertex_index = vertexB_index;
2148  }
2149 
2150  assert(this->mNodes[common_vertex_index]->GetNumContainingElements()>1);
2151 
2152  std::set<unsigned> elements_containing_common_vertex = this->mNodes[common_vertex_index]->rGetContainingElementIndices();
2153  std::set<unsigned>::const_iterator it = elements_containing_common_vertex.begin();
2154  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_1 = this->GetElement(*it);
2155  it++;
2156  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_2 = this->GetElement(*it);
2157 
2158  // Find the number and indices of common vertices between element_1 and element_2
2159  unsigned num_common_vertices = 0;
2160  std::vector<unsigned> common_vertex_indices;
2161  for (unsigned i=0; i<p_element_common_1->GetNumNodes(); i++)
2162  {
2163  for (unsigned j=0; j<p_element_common_2->GetNumNodes(); j++)
2164  {
2165  if (p_element_common_1->GetNodeGlobalIndex(i)==p_element_common_2->GetNodeGlobalIndex(j))
2166  {
2167  num_common_vertices++;
2168  common_vertex_indices.push_back(p_element_common_1->GetNodeGlobalIndex(i));
2169  }
2170  }
2171  }
2172 
2173  if (num_common_vertices == 1 || this->mNodes[common_vertex_index]->GetNumContainingElements() > 2)
2174  {
2175  /*
2176  * This is the situation here.
2177  *
2178  * From To
2179  * _ _
2180  * | <--- |
2181  * | /\ |\
2182  * | / \ | \
2183  * _|/____\ _|__\
2184  *
2185  * The edge goes from vertexA--vertexB to vertexA--pNode--vertexB
2186  */
2187 
2188  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2189  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2190 
2191  // Move original node
2192  pNode->rGetModifiableLocation() = intersection;
2193 
2194  // Add the moved nodes to the element (this also updates the node)
2195  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2196 
2197  // Check the nodes are updated correctly
2198  assert(pNode->GetNumContainingElements() == 2);
2199  }
2200  else if (num_common_vertices == 2)
2201  {
2202  // The two elements must have an edge in common. Find whether the common edge is the same as the
2203  // edge that is merged onto.
2204 
2205  if ((common_vertex_indices[0]==vertexA_index && common_vertex_indices[1]==vertexB_index) ||
2206  (common_vertex_indices[1]==vertexA_index && common_vertex_indices[0]==vertexB_index))
2207  {
2208  /*
2209  * Due to a previous T3 swap the situation looks like this.
2210  *
2211  * pNode
2212  * \ |\ /
2213  * \ | \ /
2214  * \_______|__\/
2215  * /A | B
2216  * / \
2217  *
2218  * A T3 Swap would merge pNode onto an edge of its own element.
2219  * We prevent this by just removing pNode. By doing this we also avoid the
2220  * intersecting element to be concave.
2221  */
2222 
2223  // Delete pNode in the intersecting element
2224  unsigned p_node_local_index = this->
2225  GetElement(intersecting_element_index)->GetNodeLocalIndex(pNode->GetIndex());
2226  this->GetElement(intersecting_element_index)->DeleteNode(p_node_local_index);
2227 
2228  // Mark all three nodes as deleted
2229  pNode->MarkAsDeleted();
2230  mDeletedNodeIndices.push_back(pNode->GetIndex());
2231  }
2232  else
2233  {
2234  /*
2235  * This is the situation here.
2236  *
2237  * C is common_vertex D is the other one.
2238  *
2239  * From To
2240  * _ D _
2241  * | <--- |
2242  * | /\ |\
2243  * C|/ \ | \
2244  * _|____\ _|__\
2245  *
2246  * The edge goes from vertexC--vertexB to vertexC--pNode--vertexD
2247  * then vertex B is removed as it is no longer needed.
2248  */
2249 
2250  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2251  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2252 
2253  // Move original node
2254  pNode->rGetModifiableLocation() = intersection;
2255 
2256  // Replace common_vertex with the the moved node (this also updates the nodes)
2257  this->GetElement(elementIndex)->ReplaceNode(this->mNodes[common_vertex_index], pNode);
2258 
2259  // Remove common_vertex
2260  unsigned common_vertex_local_index = this->GetElement(intersecting_element_index)->GetNodeLocalIndex(common_vertex_index);
2261  this->GetElement(intersecting_element_index)->DeleteNode(common_vertex_local_index);
2262  assert(this->mNodes[common_vertex_index]->GetNumContainingElements() == 0);
2263 
2264  this->mNodes[common_vertex_index]->MarkAsDeleted();
2265  mDeletedNodeIndices.push_back(common_vertex_index);
2266 
2267  // Check the nodes are updated correctly
2268  assert(pNode->GetNumContainingElements() == 2);
2269  }
2270  }
2271  else if (num_common_vertices == 4)
2272  {
2273  /*
2274  * The two elements share edges CA and BD due to previous swaps but not the edge AB
2275  *
2276  * From To
2277  * D___ D___
2278  * | |
2279  * B|\ |
2280  * | \ |
2281  * | / |
2282  * A|/ |
2283  * C_|__ C_|__
2284  *
2285  * We just remove the intersecting node as well as vertices A and B.
2286  */
2287 
2288  // Delete node A and B in the intersected element
2289  this->GetElement(elementIndex)->DeleteNode(node_A_local_index);
2290  unsigned node_B_local_index = this->
2291  GetElement(elementIndex)->GetNodeLocalIndex(vertexB_index);
2292  this->GetElement(elementIndex)->DeleteNode(node_B_local_index);
2293 
2294  // Delete nodes A and B in the intersecting element
2295  unsigned node_A_local_index_intersecting_element = this->
2296  GetElement(intersecting_element_index)->GetNodeLocalIndex(vertexA_index);
2297  this->GetElement(intersecting_element_index)->DeleteNode(node_A_local_index_intersecting_element);
2298  unsigned node_B_local_index_intersecting_element = this->
2299  GetElement(intersecting_element_index)->GetNodeLocalIndex(vertexB_index);
2300  this->GetElement(intersecting_element_index)->DeleteNode(node_B_local_index_intersecting_element);
2301 
2302  // Delete pNode in the intersecting element
2303  unsigned p_node_local_index = this->
2304  GetElement(intersecting_element_index)->GetNodeLocalIndex(pNode->GetIndex());
2305  this->GetElement(intersecting_element_index)->DeleteNode(p_node_local_index);
2306 
2307  // Mark all three nodes as deleted
2308  pNode->MarkAsDeleted();
2309  mDeletedNodeIndices.push_back(pNode->GetIndex());
2310  this->mNodes[vertexA_index]->MarkAsDeleted();
2311  mDeletedNodeIndices.push_back(vertexA_index);
2312  this->mNodes[vertexB_index]->MarkAsDeleted();
2313  mDeletedNodeIndices.push_back(vertexB_index);
2314  }
2315  else
2316  {
2317  // This can't happen as nodes can't be on the internal edge of 2 elements.
2318  NEVER_REACHED;
2319  }
2320  }
2321  else
2322  {
2323  /*
2324  * From To
2325  * ____ _______
2326  * / \
2327  * /\ ^ / \
2328  * / \ |
2329  *
2330  * The edge goes from vertexA--vertexB to vertexA--new_node--pNode--vertexB
2331  */
2332 
2333  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2334  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2335  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2336 
2337  // Move original node
2338  pNode->rGetModifiableLocation() = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2339 
2340  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
2341  c_vector<double, SPACE_DIM> new_node_location;
2342  new_node_location = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2343 
2344  // Add new node which will always be a boundary node
2345  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1]));
2346 
2347  // Add the moved and new nodes to the element (this also updates the node)
2348  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2349  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index);
2350 
2351  // Add the new node to the original element containing pNode (this also updates the node)
2352  this->GetElement(intersecting_element_index)->AddNode(this->mNodes[new_node_global_index], this->GetElement(intersecting_element_index)->GetNodeLocalIndex(pNode->GetIndex()));
2353 
2354  // The nodes must have been updated correctly
2355  assert(pNode->GetNumContainingElements() == 2);
2356  assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2);
2357  }
2358  }
2359  else if (pNode->GetNumContainingElements() == 2)
2360  {
2361  // Find the nodes contained in elements containing the intersecting node
2362  std::set<unsigned>::const_iterator it = elements_containing_intersecting_node.begin();
2363 
2364  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_1 = this->GetElement(*it);
2365  unsigned num_nodes_elem_1 = p_element_1->GetNumNodes();
2366  it++;
2367 
2368  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_2 = this->GetElement(*it);
2369  unsigned num_nodes_elem_2 = p_element_2->GetNumNodes();
2370 
2371  unsigned node_global_index = pNode->GetIndex();
2372 
2373  unsigned local_index_1 = p_element_1->GetNodeLocalIndex(node_global_index);
2374  unsigned next_node_1 = p_element_1->GetNodeGlobalIndex((local_index_1 + 1)%num_nodes_elem_1);
2375  unsigned previous_node_1 = p_element_1->GetNodeGlobalIndex((local_index_1 + num_nodes_elem_1 - 1)%num_nodes_elem_1);
2376 
2377  unsigned local_index_2 = p_element_2->GetNodeLocalIndex(node_global_index);
2378  unsigned next_node_2 = p_element_2->GetNodeGlobalIndex((local_index_2 + 1)%num_nodes_elem_2);
2379  unsigned previous_node_2 = p_element_2->GetNodeGlobalIndex((local_index_2 + num_nodes_elem_2 - 1)%num_nodes_elem_2);
2380 
2381  // Check to see if the nodes adjacent to the intersecting node are contained in the intersected element between vertices A and B
2382  if ((next_node_1 == vertexA_index || previous_node_1 == vertexA_index || next_node_2 == vertexA_index || previous_node_2 == vertexA_index) &&
2383  (next_node_1 == vertexB_index || previous_node_1 == vertexB_index || next_node_2 == vertexB_index || previous_node_2 == vertexB_index))
2384  {
2385  /*
2386  * Here we have
2387  * __
2388  * /| /
2389  * __ / | --> ___/
2390  * \ | \
2391  * \|__ \
2392  *
2393  * Where the node on the left has overlapped the edge A B
2394  *
2395  * Move p_node to the intersection on A B and merge AB and p_node
2396  */
2397 
2398  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2399  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2400  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2401 
2402  // Check they are all boundary nodes
2403  assert(pNode->IsBoundaryNode());
2404  assert(this->mNodes[vertexA_index]->IsBoundaryNode());
2405  assert(this->mNodes[vertexB_index]->IsBoundaryNode());
2406 
2407  // Move p_node to the intersection with the edge AB
2408  pNode->rGetModifiableLocation() = intersection;
2409  pNode->SetAsBoundaryNode(false);
2410 
2411  // Add pNode to the intersected element
2412  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2413 
2414  // Remove vertex A from elements
2415  std::set<unsigned> elements_containing_vertex_A = this->mNodes[vertexA_index]->rGetContainingElementIndices();
2416  for (std::set<unsigned>::const_iterator iter = elements_containing_vertex_A.begin();
2417  iter != elements_containing_vertex_A.end();
2418  iter++)
2419  {
2420  this->GetElement(*iter)->DeleteNode(this->GetElement(*iter)->GetNodeLocalIndex(vertexA_index));
2421  }
2422 
2423  // Remove vertex A from the mesh
2424  assert(this->mNodes[vertexA_index]->GetNumContainingElements() == 0);
2425  this->mNodes[vertexA_index]->MarkAsDeleted();
2426  mDeletedNodeIndices.push_back(vertexA_index);
2427 
2428  // Remove vertex B from elements
2429  std::set<unsigned> elements_containing_vertex_B = this->mNodes[vertexB_index]->rGetContainingElementIndices();
2430  for (std::set<unsigned>::const_iterator iter = elements_containing_vertex_B.begin();
2431  iter != elements_containing_vertex_B.end();
2432  iter++)
2433  {
2434  this->GetElement(*iter)->DeleteNode(this->GetElement(*iter)->GetNodeLocalIndex(vertexB_index));
2435  }
2436 
2437  // Remove vertex B from the mesh
2438  assert(this->mNodes[vertexB_index]->GetNumContainingElements()==0);
2439  this->mNodes[vertexB_index]->MarkAsDeleted();
2440  mDeletedNodeIndices.push_back(vertexB_index);
2441  }
2442  else
2443  {
2444  if (next_node_1 == vertexA_index || previous_node_1 == vertexA_index || next_node_2 == vertexA_index || previous_node_2 == vertexA_index)
2445  {
2446  // Get elements containing vertexA_index (the common vertex)
2447 
2448  assert(this->mNodes[vertexA_index]->GetNumContainingElements() > 1);
2449 
2450  std::set<unsigned> elements_containing_vertex_A = this->mNodes[vertexA_index]->rGetContainingElementIndices();
2451  std::set<unsigned>::const_iterator iter = elements_containing_vertex_A.begin();
2452  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_1 = this->GetElement(*iter);
2453  iter++;
2454  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_2 = this->GetElement(*iter);
2455 
2456  // Calculate the number of common vertices between element_1 and element_2
2457  unsigned num_common_vertices = 0;
2458  for (unsigned i=0; i<p_element_common_1->GetNumNodes(); i++)
2459  {
2460  for (unsigned j=0; j<p_element_common_2->GetNumNodes(); j++)
2461  {
2462  if (p_element_common_1->GetNodeGlobalIndex(i) == p_element_common_2->GetNodeGlobalIndex(j))
2463  {
2464  num_common_vertices++;
2465  }
2466  }
2467  }
2468 
2469  if (num_common_vertices == 1 || this->mNodes[vertexA_index]->GetNumContainingElements() > 2)
2470  {
2471  /*
2472  * From To
2473  * _ B _ B
2474  * | <--- |
2475  * | /|\ |\
2476  * | / | \ | \
2477  * | / | \ |\ \
2478  * _|/___|___\ _|_\_\
2479  * A A
2480  *
2481  * The edge goes from vertexA--vertexB to vertexA--pNode--new_node--vertexB
2482  */
2483 
2484  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2485  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2486  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2487 
2488  // Move original node and change to non-boundary node
2489  pNode->rGetModifiableLocation() = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2490  pNode->SetAsBoundaryNode(false);
2491 
2492  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
2493  c_vector<double, SPACE_DIM> new_node_location;
2494  new_node_location = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2495 
2496  // Add new node, which will always be a boundary node
2497  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1]));
2498 
2499  // Add the moved nodes to the element (this also updates the node)
2500  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index);
2501  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2502 
2503  // Add the new nodes to the original elements containing pNode (this also updates the node)
2504  if (next_node_1 == previous_node_2)
2505  {
2506  p_element_1->AddNode(this->mNodes[new_node_global_index], (local_index_1 + p_element_1->GetNumNodes() - 1)%(p_element_1->GetNumNodes()));
2507  }
2508  else
2509  {
2510  assert(next_node_2 == previous_node_1);
2511 
2512  p_element_2->AddNode(this->mNodes[new_node_global_index], (local_index_2 + p_element_2->GetNumNodes() - 1)%(p_element_2->GetNumNodes()));
2513  }
2514 
2515  // Check the nodes are updated correctly
2516  assert(pNode->GetNumContainingElements() == 3);
2517  assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2);
2518  }
2519  else if (num_common_vertices == 2)
2520  {
2521  /*
2522  * From To
2523  * _ B _ B
2524  * |<--- |
2525  * | /|\ |\
2526  * |/ | \ | \
2527  * | | \ |\ \
2528  * _|__|___\ _|_\_\
2529  * A A
2530  *
2531  * The edge goes from vertexA--vertexB to vertexA--pNode--new_node--vertexB
2532  * then vertexA is removed
2533  */
2534 
2535  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2536  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2537  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2538 
2539  // Move original node and change to non-boundary node
2540  pNode->rGetModifiableLocation() = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2541  pNode->SetAsBoundaryNode(false);
2542 
2543  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
2544  c_vector<double, SPACE_DIM> new_node_location;
2545  new_node_location = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2546 
2547  // Add new node, which will always be a boundary node
2548  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1]));
2549 
2550  // Add the moved nodes to the element (this also updates the node)
2551  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index);
2552  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2553 
2554  // Add the new nodes to the original elements containing pNode (this also updates the node)
2555  if (next_node_1 == previous_node_2)
2556  {
2557  p_element_1->AddNode(this->mNodes[new_node_global_index], (local_index_1 + p_element_1->GetNumNodes() - 1)%(p_element_1->GetNumNodes()));
2558  }
2559  else
2560  {
2561  assert(next_node_2 == previous_node_1);
2562  p_element_2->AddNode(this->mNodes[new_node_global_index], (local_index_2 + p_element_2->GetNumNodes() - 1)%(p_element_2->GetNumNodes()));
2563  }
2564 
2565  // Remove vertex A from the mesh
2566  p_element_common_1->DeleteNode(p_element_common_1->GetNodeLocalIndex(vertexA_index));
2567  p_element_common_2->DeleteNode(p_element_common_2->GetNodeLocalIndex(vertexA_index));
2568 
2569  assert(this->mNodes[vertexA_index]->GetNumContainingElements()==0);
2570 
2571  this->mNodes[vertexA_index]->MarkAsDeleted();
2572  mDeletedNodeIndices.push_back(vertexA_index);
2573 
2574  // Check the nodes are updated correctly
2575  assert(pNode->GetNumContainingElements() == 3);
2576  assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2);
2577  }
2578  else
2579  {
2580  // This can't happen as nodes can't be on the internal edge of two elements
2581  NEVER_REACHED;
2582  }
2583  }
2584  else if (next_node_1 == vertexB_index || previous_node_1 == vertexB_index || next_node_2 == vertexB_index || previous_node_2 == vertexB_index)
2585  {
2586  // Get elements containing vertexB_index (the common vertex)
2587 
2588  assert(this->mNodes[vertexB_index]->GetNumContainingElements()>1);
2589 
2590  std::set<unsigned> elements_containing_vertex_B = this->mNodes[vertexB_index]->rGetContainingElementIndices();
2591  std::set<unsigned>::const_iterator iter = elements_containing_vertex_B.begin();
2592  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_1 = this->GetElement(*iter);
2593  iter++;
2594  VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_2 = this->GetElement(*iter);
2595 
2596  // Calculate the number of common vertices between element_1 and element_2
2597  unsigned num_common_vertices = 0;
2598  for (unsigned i=0; i<p_element_common_1->GetNumNodes(); i++)
2599  {
2600  for (unsigned j=0; j<p_element_common_2->GetNumNodes(); j++)
2601  {
2602  if (p_element_common_1->GetNodeGlobalIndex(i) == p_element_common_2->GetNodeGlobalIndex(j))
2603  {
2604  num_common_vertices++;
2605  }
2606  }
2607  }
2608 
2609  if (num_common_vertices == 1 || this->mNodes[vertexB_index]->GetNumContainingElements() > 2)
2610  {
2611  /*
2612  * From To
2613  * _B_________ _B____
2614  * |\ | / | / /
2615  * | \ | / |/ /
2616  * | \ | / | /
2617  * | \|/ |/
2618  * _| <--- _|
2619  * A
2620  *
2621  * The edge goes from vertexA--vertexB to vertexA--new_node--pNode--vertexB
2622  */
2623 
2624  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2625  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2626  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2627 
2628  // Move original node and change to non-boundary node
2629  pNode->rGetModifiableLocation() = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2630  pNode->SetAsBoundaryNode(false);
2631 
2632  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
2633  c_vector<double, SPACE_DIM> new_node_location;
2634  new_node_location = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2635 
2636  // Add new node which will always be a boundary node
2637  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1]));
2638 
2639  // Add the moved nodes to the element (this also updates the node)
2640  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2641  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index);
2642 
2643  // Add the new nodes to the original elements containing pNode (this also updates the node)
2644  if (next_node_1 == previous_node_2)
2645  {
2646  p_element_2->AddNode(this->mNodes[new_node_global_index], local_index_2);
2647  }
2648  else
2649  {
2650  assert(next_node_2 == previous_node_1);
2651  p_element_1->AddNode(this->mNodes[new_node_global_index], local_index_1);
2652  }
2653 
2654  // Check the nodes are updated correctly
2655  assert(pNode->GetNumContainingElements() == 3);
2656  assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2);
2657  }
2658  else if (num_common_vertices == 2)
2659  {
2660  /*
2661  * From To
2662  * _B_______ _B____
2663  * | | / | / /
2664  * | | / |/ /
2665  * |\ | / | /
2666  * | \|/ |/
2667  * _| <--- _|
2668  * A
2669  *
2670  * The edge goes from vertexA--vertexB to vertexA--new_node--pNode--vertexB
2671  * then vertexB is removed
2672  */
2673 
2674  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2675  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2676  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2677 
2678  // Move original node and change to non-boundary node
2679  pNode->rGetModifiableLocation() = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2680  pNode->SetAsBoundaryNode(false);
2681 
2682  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
2683  c_vector<double, SPACE_DIM> new_node_location;
2684  new_node_location = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2685 
2686  // Add new node which will always be a boundary node
2687  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1]));
2688 
2689  // Add the moved nodes to the element (this also updates the node)
2690  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2691  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index);
2692 
2693  // Add the new nodes to the original elements containing pNode (this also updates the node)
2694  if (next_node_1 == previous_node_2)
2695  {
2696  p_element_2->AddNode(this->mNodes[new_node_global_index], local_index_2);
2697  }
2698  else
2699  {
2700  assert(next_node_2 == previous_node_1);
2701  p_element_1->AddNode(this->mNodes[new_node_global_index], local_index_1);
2702  }
2703 
2704  // Remove vertex B from the mesh
2705  p_element_common_1->DeleteNode(p_element_common_1->GetNodeLocalIndex(vertexB_index));
2706  p_element_common_2->DeleteNode(p_element_common_2->GetNodeLocalIndex(vertexB_index));
2707 
2708  assert(this->mNodes[vertexB_index]->GetNumContainingElements()==0);
2709 
2710  this->mNodes[vertexB_index]->MarkAsDeleted();
2711  mDeletedNodeIndices.push_back(vertexB_index);
2712 
2713  // Check the nodes are updated correctly
2714  assert(pNode->GetNumContainingElements() == 3);
2715  assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2);
2716  }
2717  else
2718  {
2719  // This can't happen as nodes can't be on the internal edge of two elements
2720  NEVER_REACHED;
2721  }
2722  }
2723  else
2724  {
2725  /*
2726  * From To
2727  * _____ _______
2728  * / | \
2729  * /|\ ^ / | \
2730  * / | \ |
2731  *
2732  * The edge goes from vertexA--vertexB to vertexA--new_node_1--pNode--new_node_2--vertexB
2733  */
2734 
2735  // Check whether the intersection location fits into the edge and update distances and vertex positions afterwards.
2736  intersection = this->WidenEdgeOrCorrectIntersectionLocationIfNecessary(vertexA_index, vertexB_index, intersection);
2737  edge_ab_unit_vector = this->GetPreviousEdgeGradientOfElementAtNode(p_element, (node_A_local_index+1)%num_nodes);
2738 
2739  // Move original node and change to non-boundary node
2740  pNode->rGetModifiableLocation() = intersection;
2741  pNode->SetAsBoundaryNode(false);
2742 
2743  c_vector<double, SPACE_DIM> new_node_1_location;
2744  new_node_1_location = intersection - mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2745  c_vector<double, SPACE_DIM> new_node_2_location;
2746  new_node_2_location = intersection + mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
2747 
2748  // Add new nodes which will always be boundary nodes
2749  unsigned new_node_1_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_1_location[0], new_node_1_location[1]));
2750  unsigned new_node_2_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_2_location[0], new_node_2_location[1]));
2751 
2752  // Add the moved and new nodes to the element (this also updates the node)
2753  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_2_global_index], node_A_local_index);
2754  this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index);
2755  this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_1_global_index], node_A_local_index);
2756 
2757  // Add the new nodes to the original elements containing pNode (this also updates the node)
2758  if (next_node_1 == previous_node_2)
2759  {
2760  p_element_1->AddNode(this->mNodes[new_node_2_global_index], (local_index_1 + p_element_1->GetNumNodes() - 1)%(p_element_1->GetNumNodes()));
2761  p_element_2->AddNode(this->mNodes[new_node_1_global_index], local_index_2);
2762  }
2763  else
2764  {
2765  assert(next_node_2 == previous_node_1);
2766 
2767  p_element_1->AddNode(this->mNodes[new_node_1_global_index], local_index_1);
2768  p_element_2->AddNode(this->mNodes[new_node_2_global_index], (local_index_2 + p_element_2->GetNumNodes() - 1)%(p_element_2->GetNumNodes()));
2769  }
2770 
2771  // Check the nodes are updated correctly
2772  assert(pNode->GetNumContainingElements() == 3);
2773  assert(this->mNodes[new_node_1_global_index]->GetNumContainingElements() == 2);
2774  assert(this->mNodes[new_node_2_global_index]->GetNumContainingElements() == 2);
2775  }
2776  }
2777  }
2778  else
2779  {
2780  EXCEPTION("Trying to merge a node, contained in more than 2 elements, into another element, this is not possible with the vertex mesh.");
2781  }
2782 }
2783 
2784 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
2786 {
2787  // Calculate void centroid
2788  c_vector<double, SPACE_DIM> nodes_midpoint = pNodeA->rGetLocation()
2789  + this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeB->rGetLocation()) / 3.0
2790  + this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeC->rGetLocation()) / 3.0;
2791 
2792  /*
2793  * In two steps, merge nodes A, B and C into a single node. This is implemented in such a way that
2794  * the ordering of their indices does not matter.
2795  */
2796 
2797  PerformNodeMerge(pNodeA, pNodeB);
2798 
2799  Node<SPACE_DIM>* p_merged_node = pNodeB;
2800 
2801  if (pNodeB->IsDeleted())
2802  {
2803  p_merged_node = pNodeA;
2804  }
2805 
2806  PerformNodeMerge(pNodeC, p_merged_node);
2807 
2808  if (p_merged_node->IsDeleted())
2809  {
2810  p_merged_node = pNodeC;
2811  }
2812 
2813  p_merged_node->rGetModifiableLocation() = nodes_midpoint;
2814 
2815  // Tag remaining node as non-boundary
2816  p_merged_node->SetAsBoundaryNode(false);
2817 
2818  // Remove the deleted nodes and re-index
2820 }
2821 
2822 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
2824 {
2825  unsigned node_a_rank = pNodeA->rGetContainingElementIndices().size();
2826  unsigned node_b_rank = pNodeB->rGetContainingElementIndices().size();
2827 
2828  if ((node_a_rank > 3) && (node_b_rank > 3))
2829  {
2830  // The code can't handle this case
2831  EXCEPTION("Both nodes involved in a swap event are contained in more than three elements");
2832  }
2833  else // the rosette degree should increase in this case
2834  {
2835  assert(node_a_rank > 3 || node_b_rank > 3);
2836  this->PerformRosetteRankIncrease(pNodeA, pNodeB);
2837  this->RemoveDeletedNodes();
2838  }
2839 }
2840 
2841 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
2843 {
2844  /*
2845  * One of the nodes will have 3 containing element indices, the other
2846  * will have at least four. We first identify which node is which.
2847  */
2848 
2849  unsigned node_a_index = pNodeA->GetIndex();
2850  unsigned node_b_index = pNodeB->GetIndex();
2851 
2852  unsigned node_a_rank = pNodeA->rGetContainingElementIndices().size();
2853  unsigned node_b_rank = pNodeB->rGetContainingElementIndices().size();
2854 
2855  unsigned lo_rank_index = (node_a_rank < node_b_rank) ? node_a_index : node_b_index;
2856  unsigned hi_rank_index = (node_a_rank < node_b_rank) ? node_b_index : node_a_index;
2857 
2858  // Get pointers to the nodes, sorted by index
2859  Node<SPACE_DIM>* p_lo_rank_node = this->GetNode(lo_rank_index);
2860  Node<SPACE_DIM>* p_hi_rank_node = this->GetNode(hi_rank_index);
2861 
2862  // Find the sets of elements containing each of the nodes, sorted by index
2863  std::set<unsigned> lo_rank_elem_indices = p_lo_rank_node->rGetContainingElementIndices();
2864  std::set<unsigned> hi_rank_elem_indices = p_hi_rank_node->rGetContainingElementIndices();
2865 
2892  for (std::set<unsigned>::const_iterator it = lo_rank_elem_indices.begin();
2893  it != lo_rank_elem_indices.end();
2894  ++it)
2895  {
2896  // Find the local index of lo_rank_node in this element
2897  unsigned lo_rank_local_index = this->mElements[*it]->GetNodeLocalIndex(lo_rank_index);
2898  assert(lo_rank_local_index < UINT_MAX); // double check this element contains lo_rank_node
2899 
2900  /*
2901  * If this element already contains the hi_rank_node, we are in the situation of elements
2902  * C and D above, so we just remove lo_rank_node.
2903  *
2904  * Otherwise, we are in element E, so we must replace lo_rank_node with high-rank node,
2905  * and remove it from mNodes.
2906  *
2907  * We can check whether hi_rank_node is in this element using the set::count() method.
2908  */
2909 
2910  if (hi_rank_elem_indices.count(*it) > 0)
2911  {
2912  // Delete lo_rank_node from current element
2913  this->mElements[*it]->DeleteNode(lo_rank_local_index);
2914  }
2915  else
2916  {
2917  // Update lo_rank_node with all information (including index and location) of hi_rank_node
2918  this->mElements[*it]->UpdateNode(lo_rank_local_index, p_hi_rank_node);
2919  }
2920  }
2921 
2922  // Tidy up the mesh by ensuring the global instance of lo_rank_node is deleted
2923  assert(!(this->mNodes[lo_rank_index]->IsDeleted()));
2924  this->mNodes[lo_rank_index]->MarkAsDeleted();
2925  this->mDeletedNodeIndices.push_back(lo_rank_index);
2926 }
2927 
2928 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
2930 {
2931  // Double check we are dealing with a protorosette
2932  assert(pProtorosetteNode->rGetContainingElementIndices().size() == 4);
2933 
2934  // Get random number (0, 1, 2 or 3), as the resolution axis is assumed to be random
2935  unsigned random_elem_increment = RandomNumberGenerator::Instance()->randMod(4);
2936 
2937  // Find global indices of elements around the protorosette node
2938  std::set<unsigned> protorosette_node_containing_elem_indices = pProtorosetteNode->rGetContainingElementIndices();
2939 
2940  // Select random element by advancing iterator a random number times
2941  std::set<unsigned>::const_iterator elem_index_iter(protorosette_node_containing_elem_indices.begin());
2942  advance(elem_index_iter, random_elem_increment);
2943 
2971  /*
2972  * We need to find the global indices of elements B, C and D. We do this with set intersections.
2973  */
2974 
2975  unsigned elem_a_idx = *elem_index_iter;
2976  unsigned elem_b_idx = UINT_MAX;
2977  unsigned elem_c_idx = UINT_MAX;
2978  unsigned elem_d_idx = UINT_MAX;
2979 
2980  // Get pointer to element we've chosen at random (element A)
2981  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_a = this->GetElement(elem_a_idx);
2982 
2983  // Get all necessary info about element A and the protorosette node
2984  unsigned num_nodes_elem_a = p_elem_a->GetNumNodes();
2985  unsigned protorosette_node_global_idx = pProtorosetteNode->GetIndex();
2986  unsigned protorosette_node_local_idx = p_elem_a->GetNodeLocalIndex(protorosette_node_global_idx);
2987 
2988  // Find global indices of previous (cw) and next (ccw) nodes, locally, from the protorosette node, in element A
2989  unsigned prev_node_global_idx = p_elem_a->GetNodeGlobalIndex((protorosette_node_local_idx + num_nodes_elem_a - 1) % num_nodes_elem_a);
2990  unsigned next_node_global_idx = p_elem_a->GetNodeGlobalIndex((protorosette_node_local_idx + 1) % num_nodes_elem_a);
2991 
2992  // Get the set of elements the previous and next nodes are contained in
2993  Node<SPACE_DIM>* p_prev_node = this->GetNode(prev_node_global_idx);
2994  Node<SPACE_DIM>* p_next_node = this->GetNode(next_node_global_idx);
2995  std::set<unsigned> prev_node_elem_indices = p_prev_node->rGetContainingElementIndices();
2996  std::set<unsigned> next_node_elem_indices = p_next_node->rGetContainingElementIndices();
2997 
2998  // Perform set intersections with the set of element indices which the protorosette node is contained in
2999  std::set<unsigned> intersection_with_prev;
3000  std::set<unsigned> intersection_with_next;
3001 
3002  // This intersection should contain just global indices for elements A and B
3003  std::set_intersection(protorosette_node_containing_elem_indices.begin(),
3004  protorosette_node_containing_elem_indices.end(),
3005  prev_node_elem_indices.begin(),
3006  prev_node_elem_indices.end(),
3007  std::inserter(intersection_with_prev, intersection_with_prev.begin()));
3008 
3009  // This intersection should contain just global indices for elements A and D
3010  std::set_intersection(protorosette_node_containing_elem_indices.begin(),
3011  protorosette_node_containing_elem_indices.end(),
3012  next_node_elem_indices.begin(),
3013  next_node_elem_indices.end(),
3014  std::inserter(intersection_with_next, intersection_with_next.begin()));
3015 
3016  assert(intersection_with_prev.size() == 2);
3017  assert(intersection_with_next.size() == 2);
3018 
3019  // Get global index of element B
3020  if (*intersection_with_prev.begin() != elem_a_idx)
3021  {
3022  elem_b_idx = *(intersection_with_prev.begin());
3023  }
3024  else
3025  {
3026  elem_b_idx = *(++(intersection_with_prev.begin()));
3027  }
3028  assert(elem_b_idx < UINT_MAX);
3029 
3030  // Get global index of element D
3031  if (*intersection_with_next.begin() != elem_a_idx)
3032  {
3033  elem_d_idx = *(intersection_with_next.begin());
3034  }
3035  else
3036  {
3037  elem_d_idx = *(++(intersection_with_next.begin()));
3038  }
3039  assert(elem_d_idx < UINT_MAX);
3040 
3041  // By elimination, the remaining unassigned index in the original set must be global index of element C
3042  for (elem_index_iter = protorosette_node_containing_elem_indices.begin();
3043  elem_index_iter != protorosette_node_containing_elem_indices.end();
3044  ++elem_index_iter)
3045  {
3046  if ((*elem_index_iter != elem_a_idx) && (*elem_index_iter != elem_b_idx) && (*elem_index_iter != elem_d_idx))
3047  {
3048  elem_c_idx = *elem_index_iter;
3049  }
3050  }
3051  assert(elem_c_idx < UINT_MAX);
3052 
3067  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_b = this->GetElement(elem_b_idx);
3068  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_c = this->GetElement(elem_c_idx);
3069  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_d = this->GetElement(elem_d_idx);
3070 
3071  double swap_distance = (this->mCellRearrangementRatio) * (this->mCellRearrangementThreshold);
3072 
3073  // Get normalized vectors to centre of elements A and B from protorosette node
3074  c_vector<double, SPACE_DIM> node_to_elem_a_centre = this->GetCentroidOfElement(elem_a_idx) - pProtorosetteNode->rGetLocation();
3075  node_to_elem_a_centre /= norm_2(node_to_elem_a_centre);
3076 
3077  c_vector<double, SPACE_DIM> node_to_elem_c_centre = this->GetCentroidOfElement(elem_c_idx) - pProtorosetteNode->rGetLocation();
3078  node_to_elem_c_centre /= norm_2(node_to_elem_c_centre);
3079 
3080  // Calculate new node locations
3081  c_vector<double, SPACE_DIM> new_location_of_protorosette_node = pProtorosetteNode->rGetLocation() + (0.5 * swap_distance) * node_to_elem_a_centre;
3082  c_vector<double, SPACE_DIM> location_of_new_node = pProtorosetteNode->rGetLocation() + (0.5 * swap_distance) * node_to_elem_c_centre;
3083 
3084  // Move protorosette node to new location
3085  pProtorosetteNode->rGetModifiableLocation() = new_location_of_protorosette_node;
3086 
3087  // Create new node in correct location
3088  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(this->GetNumNodes(), location_of_new_node, false));
3089  Node<SPACE_DIM>* p_new_node = this->GetNode(new_node_global_index);
3090 
3101  unsigned local_idx_elem_b = p_elem_b->GetNodeLocalIndex(protorosette_node_global_idx);
3102  local_idx_elem_b = (local_idx_elem_b + p_elem_b->GetNumNodes() - 1) % p_elem_b->GetNumNodes();
3103  unsigned local_idx_elem_c = p_elem_c->GetNodeLocalIndex(protorosette_node_global_idx);
3104  unsigned local_idx_elem_d = p_elem_d->GetNodeLocalIndex(protorosette_node_global_idx);
3105 
3106  p_elem_b->AddNode(p_new_node, local_idx_elem_b);
3107  p_elem_c->AddNode(p_new_node, local_idx_elem_c);
3108  p_elem_d->AddNode(p_new_node, local_idx_elem_d);
3109 
3110  // All that is left is to remove the original protorosette node from element C
3111  p_elem_c->DeleteNode(p_elem_c->GetNodeLocalIndex(protorosette_node_global_idx));
3112 }
3113 
3114 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
3116 {
3117  unsigned rosette_rank = pRosetteNode->rGetContainingElementIndices().size();
3118 
3119  // Double check we're dealing with a rosette
3120  assert(rosette_rank > 4);
3121 
3122  // Get random number in [0, 1, ..., n) where n is rank of rosette, as the resolution axis is assumed to be random
3123  unsigned random_elem_increment = RandomNumberGenerator::Instance()->randMod(rosette_rank);
3124 
3125  // Find global indices of elements around the protorosette node
3126  std::set<unsigned> rosette_node_containing_elem_indices = pRosetteNode->rGetContainingElementIndices();
3127 
3128  // Select random element by advancing iterator a random number times
3129  std::set<unsigned>::const_iterator elem_index_iter(rosette_node_containing_elem_indices.begin());
3130  advance(elem_index_iter, random_elem_increment);
3131 
3170  /*
3171  * We need to find the global indices of elements N and P. We do this with set intersections.
3172  */
3173 
3174  // Get the vertex element S (which we randomly selected)
3175  unsigned elem_s_idx = *elem_index_iter;
3176  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_s = this->GetElement(elem_s_idx);
3177 
3178  unsigned elem_n_idx = UINT_MAX;
3179  unsigned elem_p_idx = UINT_MAX;
3180 
3181  // Get all necessary info about element S and the rosette node
3182  unsigned num_nodes_elem_s = p_elem_s->GetNumNodes();
3183  unsigned rosette_node_global_idx = pRosetteNode->GetIndex();
3184  unsigned rosette_node_local_idx = p_elem_s->GetNodeLocalIndex(rosette_node_global_idx);
3185 
3186  // Find global indices of previous (cw) and next (ccw) nodes, locally, from the rosette node, in element S
3187  unsigned prev_node_global_idx = p_elem_s->GetNodeGlobalIndex((rosette_node_local_idx + num_nodes_elem_s - 1) % num_nodes_elem_s);
3188  unsigned next_node_global_idx = p_elem_s->GetNodeGlobalIndex((rosette_node_local_idx + 1) % num_nodes_elem_s);
3189 
3190  // Get the set of elements that the previous and next nodes are contained in
3191  Node<SPACE_DIM>* p_prev_node = this->GetNode(prev_node_global_idx);
3192  Node<SPACE_DIM>* p_next_node = this->GetNode(next_node_global_idx);
3193  std::set<unsigned> prev_node_elem_indices = p_prev_node->rGetContainingElementIndices();
3194  std::set<unsigned> next_node_elem_indices = p_next_node->rGetContainingElementIndices();
3195 
3196  // Perform set intersections with the set of element indices that the rosette node is contained in
3197  std::set<unsigned> intersection_with_prev;
3198  std::set<unsigned> intersection_with_next;
3199 
3200  // This intersection should contain just global indices for elements S and N
3201  std::set_intersection(rosette_node_containing_elem_indices.begin(),
3202  rosette_node_containing_elem_indices.end(),
3203  prev_node_elem_indices.begin(),
3204  prev_node_elem_indices.end(),
3205  std::inserter(intersection_with_prev, intersection_with_prev.begin()));
3206 
3207  // This intersection should contain just global indices for elements S and P
3208  std::set_intersection(rosette_node_containing_elem_indices.begin(),
3209  rosette_node_containing_elem_indices.end(),
3210  next_node_elem_indices.begin(),
3211  next_node_elem_indices.end(),
3212  std::inserter(intersection_with_next, intersection_with_next.begin()));
3213 
3214  assert(intersection_with_prev.size() == 2);
3215  assert(intersection_with_next.size() == 2);
3216 
3217  // Get global index of element N
3218  if (*intersection_with_prev.begin() != elem_s_idx)
3219  {
3220  elem_n_idx = *intersection_with_prev.begin();
3221  }
3222  else
3223  {
3224  elem_n_idx = *(++(intersection_with_prev.begin()));
3225  }
3226  assert(elem_n_idx < UINT_MAX);
3227 
3228  // Get global index of element P
3229  if (*intersection_with_next.begin() != elem_s_idx)
3230  {
3231  elem_p_idx = *intersection_with_next.begin();
3232  }
3233  else
3234  {
3235  elem_p_idx = *(++(intersection_with_next.begin()));
3236  }
3237  assert(elem_p_idx < UINT_MAX);
3238 
3249  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_n = this->GetElement(elem_p_idx);
3250  VertexElement<ELEMENT_DIM,SPACE_DIM>* p_elem_p = this->GetElement(elem_n_idx);
3251 
3252  double swap_distance = (this->mCellRearrangementRatio) * (this->mCellRearrangementThreshold);
3253 
3254  // Calculate location of new node
3255  c_vector<double, 2> node_to_selected_elem = this->GetCentroidOfElement(elem_s_idx) - pRosetteNode->rGetLocation();
3256  node_to_selected_elem /= norm_2(node_to_selected_elem);
3257  c_vector<double, 2> new_node_location = pRosetteNode->rGetLocation() + (swap_distance * node_to_selected_elem);
3258 
3259  // Create new node in correct location
3260  unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(this->GetNumNodes(), new_node_location, false));
3261  Node<SPACE_DIM>* p_new_node = this->GetNode(new_node_global_index);
3262 
3274  // Add new node, and remove rosette node, from element S
3275  unsigned node_local_idx_in_elem_s = p_elem_s->GetNodeLocalIndex(rosette_node_global_idx);
3276  p_elem_s->AddNode(p_new_node, node_local_idx_in_elem_s);
3277  p_elem_s->DeleteNode(node_local_idx_in_elem_s);
3278 
3279  // Add new node to element N
3280  unsigned node_local_idx_in_elem_n = p_elem_n->GetNodeLocalIndex(rosette_node_global_idx);
3281  node_local_idx_in_elem_n = (node_local_idx_in_elem_n + p_elem_n->GetNumNodes() - 1) % p_elem_n->GetNumNodes();
3282  p_elem_n->AddNode(p_new_node, node_local_idx_in_elem_n);
3283 
3284  // Add new node to element P
3285  unsigned node_local_idx_in_elem_p = p_elem_p->GetNodeLocalIndex(rosette_node_global_idx);
3286  p_elem_p->AddNode(p_new_node, node_local_idx_in_elem_p);
3287 }
3288 
3289 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
3291 {
3300  // Vectors to store the nodes that need resolution events
3301  std::vector<Node<SPACE_DIM>* > protorosette_nodes;
3302  std::vector<Node<SPACE_DIM>* > rosette_nodes;
3303 
3304  // First loop in which we populate these vectors
3305  unsigned num_nodes = this->GetNumAllNodes();
3306  for (unsigned node_idx = 0 ; node_idx < num_nodes ; node_idx++)
3307  {
3308  Node<SPACE_DIM>* current_node = this->GetNode(node_idx);
3309  unsigned node_rank = current_node->rGetContainingElementIndices().size();
3310 
3311  if (node_rank < 4)
3312  {
3313  // Nothing to do if the node is not high-rank
3314  continue;
3315  }
3316  else if (node_rank == 4)
3317  {
3318  // For protorosette nodes, we check against a random number to decide if resolution is necessary
3320  {
3321  protorosette_nodes.push_back(current_node);
3322  }
3323  }
3324  else // if (node_rank > 4)
3325  {
3326  // For rosette nodes, we check against a random number to decide if resolution is necessary
3328  {
3329  rosette_nodes.push_back(current_node);
3330  }
3331  }
3332  }
3333 
3341  // First, resolve any protorosettes
3342  for (unsigned node_idx = 0 ; node_idx < protorosette_nodes.size() ; node_idx++)
3343  {
3344  Node<SPACE_DIM>* current_node = protorosette_nodes[node_idx];
3345 
3346  // Verify that node has not been marked for deletion, and that it is still contained in four elements
3347  assert( !(current_node->IsDeleted()) );
3348  assert( current_node->rGetContainingElementIndices().size() == 4 );
3349 
3350  // Perform protorosette resolution
3351  this->PerformProtorosetteResolution(current_node);
3352  }
3353 
3354  // Finally, resolve any rosettes
3355  for (unsigned node_idx = 0 ; node_idx < rosette_nodes.size() ; node_idx++)
3356  {
3357  Node<SPACE_DIM>* current_node = rosette_nodes[node_idx];
3358 
3359  // Verify that node has not been marked for deletion, and that it is still contained in at least four elements
3360  assert( !(current_node->IsDeleted()) );
3361  assert( current_node->rGetContainingElementIndices().size() > 4 );
3362 
3363  // Perform protorosette resolution
3364  this->PerformRosetteRankDecrease(current_node);
3365  }
3366 }
3367 
3368 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
3370  unsigned indexA, unsigned indexB, c_vector<double,2> intersection)
3371 {
3381  c_vector<double, SPACE_DIM> vertexA = this->GetNode(indexA)->rGetLocation();
3382  c_vector<double, SPACE_DIM> vertexB = this->GetNode(indexB)->rGetLocation();
3383  c_vector<double, SPACE_DIM> vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB);
3384 
3385  if (norm_2(vector_a_to_b) < 4.0*mCellRearrangementRatio*mCellRearrangementThreshold)
3386  {
3387  WARNING("Trying to merge a node onto an edge which is too small.");
3388 
3389  c_vector<double, SPACE_DIM> centre_a_and_b = vertexA + 0.5*vector_a_to_b;
3390 
3391  vertexA = centre_a_and_b - 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*vector_a_to_b/norm_2(vector_a_to_b);
3392  ChastePoint<SPACE_DIM> vertex_A_point(vertexA);
3393  SetNode(indexA, vertex_A_point);
3394 
3395  vertexB = centre_a_and_b + 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*vector_a_to_b/norm_2(vector_a_to_b);
3396  ChastePoint<SPACE_DIM> vertex_B_point(vertexB);
3397  SetNode(indexB, vertex_B_point);
3398 
3399  intersection = centre_a_and_b;
3400  }
3401 
3402  // Reset distances
3403  vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB);
3404  c_vector<double,2> edge_ab_unit_vector = vector_a_to_b/norm_2(vector_a_to_b);
3405 
3406  // Reset the intersection away from vertices A and B to allow enough room for new nodes
3415  if (norm_2(intersection - vertexA) < 2.0*mCellRearrangementRatio*mCellRearrangementThreshold)
3416  {
3417  intersection = vertexA + 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
3418  }
3419  if (norm_2(intersection - vertexB) < 2.0*mCellRearrangementRatio*mCellRearrangementThreshold)
3420  {
3421  intersection = vertexB - 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector;
3422  }
3423  return intersection;
3424 }
3425 
3426 // Explicit instantiation
3427 template class MutableVertexMesh<1,1>;
3428 template class MutableVertexMesh<1,2>;
3429 template class MutableVertexMesh<1,3>;
3430 template class MutableVertexMesh<2,2>;
3431 template class MutableVertexMesh<2,3>;
3432 template class MutableVertexMesh<3,3>;
3433 
3434 // Serialization for Boost >= 1.36
unsigned DivideElement(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned nodeAIndex, unsigned nodeBIndex, bool placeOriginalElementBelow=false)
void SetRosetteResolutionProbabilityPerTimestep(double rosetteResolutionProbabilityPerTimestep)
void PerformIntersectionSwap(Node< SPACE_DIM > *pNode, unsigned elementIndex)
void SetDistanceForT3SwapChecking(double distanceForT3SwapChecking)
virtual void Clear()
Definition: VertexMesh.cpp:579
unsigned GetNumAllElements() const
Definition: VertexMesh.cpp:616
c_vector< double, 2 > WidenEdgeOrCorrectIntersectionLocationIfNecessary(unsigned indexA, unsigned indexB, c_vector< double, 2 > intersection)
std::vector< c_vector< double, SPACE_DIM > > GetLocationsOfIntersectionSwaps()
std::vector< c_vector< double, SPACE_DIM > > GetLocationsOfT3Swaps()
void RemoveDeletedNodesAndElements(VertexElementMap &rElementMap)
void SetPoint(ChastePoint< SPACE_DIM > point)
Definition: Node.cpp:115
void PerformRosetteRankDecrease(Node< SPACE_DIM > *pRosetteNode)
std::vector< c_vector< double, SPACE_DIM > > mLocationsOfT3Swaps
double GetCellRearrangementRatio() const
unsigned DivideElementAlongGivenAxis(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, c_vector< double, SPACE_DIM > axisOfDivision, bool placeOriginalElementBelow=false)
unsigned randMod(unsigned base)
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
Definition: Node.hpp:58
void SetAsBoundaryNode(bool value=true)
Definition: Node.cpp:127
bool CheckForT2Swaps(VertexElementMap &rElementMap)
std::vector< c_vector< double, SPACE_DIM > > GetLocationsOfT1Swaps()
unsigned GetNumContainingElements() const
Definition: Node.cpp:312
unsigned DivideElementAlongShortAxis(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, bool placeOriginalElementBelow=false)
void PerformNodeMerge(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB)
virtual bool CheckForSwapsFromShortEdges()
void SetProtorosetteResolutionProbabilityPerTimestep(double protorosetteResolutionProbabilityPerTimestep)
void ClearLocationsOfIntersectionSwaps()
std::vector< VertexElement< ELEMENT_DIM - 1, SPACE_DIM > * > mFaces
Definition: VertexMesh.hpp:83
#define EXCEPTION(message)
Definition: Exception.hpp:143
VertexElement< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
Definition: VertexMesh.cpp:628
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
void ReplaceNode(Node< SPACE_DIM > *pOldNode, Node< SPACE_DIM > *pNewNode)
std::vector< unsigned > mDeletedNodeIndices
NodeIterator GetNodeIteratorEnd()
void PerformVoidRemoval(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB, Node< SPACE_DIM > *pNodeC)
std::set< unsigned > & rGetContainingElementIndices()
Definition: Node.cpp:300
double mRosetteResolutionProbabilityPerTimestep
void SetIndex(unsigned index)
Definition: Node.cpp:121
unsigned GetIndex() const
Definition: Node.cpp:158
std::vector< c_vector< double, SPACE_DIM > > mLocationsOfT1Swaps
c_vector< double, SPACE_DIM > mLastT2SwapLocation
unsigned GetNumNodes() const
unsigned GetNumElements() const
#define NEVER_REACHED
Definition: Exception.hpp:206
unsigned GetIndex() const
Node< SPACE_DIM > * GetNode(unsigned index) const
c_vector< double, SPACE_DIM > GetPreviousEdgeGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
unsigned GetNodeLocalIndex(unsigned globalIndex) const
bool GetCheckForInternalIntersections() const
void SetCellRearrangementThreshold(double cellRearrangementThreshold)
double GetDistanceBetweenNodes(unsigned indexA, unsigned indexB)
unsigned GetNodeGlobalIndex(unsigned localIndex) const
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:139
bool mMeshChangesDuringSimulation
void PerformT3Swap(Node< SPACE_DIM > *pNode, unsigned elementIndex)
void AddNode(Node< SPACE_DIM > *pNode, const unsigned &rIndex)
std::vector< Node< SPACE_DIM > * > mNodes
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:679
virtual void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > point)
double GetNodeLocation(unsigned localIndex, unsigned dimension) const
unsigned AddElement(VertexElement< ELEMENT_DIM, SPACE_DIM > *pNewElement)
void PerformProtorosetteResolution(Node< SPACE_DIM > *pProtorosetteNode)
void SetDeleted(unsigned index)
double mProtorosetteResolutionProbabilityPerTimestep
double GetDistanceForT3SwapChecking() const
virtual unsigned GetNumAllNodes() const
std::vector< c_vector< double, SPACE_DIM > > mLocationsOfIntersectionSwaps
void PerformRosetteRankIncrease(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB)
double GetT2Threshold() const
double mProtorosetteFormationProbability
void DeleteNodePriorToReMesh(unsigned index)
void SetNewIndex(unsigned oldIndex, unsigned newIndex)
static RandomNumberGenerator * Instance()
double GetCellRearrangementThreshold() const
virtual double GetVolumeOfElement(unsigned index)
void RegisterWithNodes()
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
void SetProtorosetteFormationProbability(double protorosetteFormationProbability)
std::vector< VertexElement< ELEMENT_DIM, SPACE_DIM > * > mElements
Definition: VertexMesh.hpp:80
virtual void HandleHighOrderJunctions(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB)
void DivideEdge(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB)
void SetCheckForInternalIntersections(bool checkForInternalIntersections)
void AddElement(unsigned index)
Definition: Node.cpp:268
void DeleteElementPriorToReMesh(unsigned index)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
double GetProtorosetteResolutionProbabilityPerTimestep() const
virtual c_vector< double, SPACE_DIM > GetCentroidOfElement(unsigned index)
Definition: VertexMesh.cpp:642
std::set< unsigned > GetNeighbouringElementIndices(unsigned elementIndex)
Definition: VertexMesh.cpp:783
void SetCellRearrangementRatio(double cellRearrangementRatio)
double GetRosetteResolutionProbabilityPerTimestep() const
void DeleteNode(const unsigned &rIndex)
unsigned GetNumNodes() const
void PerformT1Swap(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB, std::set< unsigned > &rElementsContainingNodes)
double GetProtorosetteFormationProbability() const
bool IsDeleted() const
Definition: Node.cpp:412
void SetT2Threshold(double t2Threshold)
virtual void IdentifySwapType(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB)
VertexElementIterator GetElementIteratorEnd()
Definition: VertexMesh.hpp:686
c_vector< double, SPACE_DIM > & rGetModifiableLocation()
Definition: Node.cpp:151
void MarkAsDeleted()
Definition: Node.cpp:406
bool IsBoundaryNode() const
Definition: Node.cpp:164
bool ElementIncludesPoint(const c_vector< double, SPACE_DIM > &rTestPoint, unsigned elementIndex)
c_vector< double, SPACE_DIM > GetLastT2SwapLocation()
void PerformT2Swap(VertexElement< ELEMENT_DIM, SPACE_DIM > &rElement)
unsigned GetLocalIndexForElementEdgeClosestToPoint(const c_vector< double, SPACE_DIM > &rTestPoint, unsigned elementIndex)
std::vector< unsigned > mDeletedElementIndices
void Resize(unsigned size)
c_vector< double, SPACE_DIM > GetShortAxisOfElement(unsigned index)