Chaste  Release::2017.1
Cylindrical2dMesh.cpp
1 /*
2 
3 Copyright (c) 2005-2017, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include <map>
37 
38 /* These lines are very useful for debugging (visualize with 'showme').
39 #include "TrianglesMeshWriter.hpp"
40 TrianglesMeshWriter<2,2> mesh_writer("Cylindrical2dMeshDebug", "mesh", false);
41 mesh_writer.WriteFilesUsingMesh(*this);
42 */
43 #include "Cylindrical2dMesh.hpp"
44 #include "Exception.hpp"
45 
47  : MutableMesh<2,2>(),
48  mWidth(width)
49 {
50  assert(width > 0.0);
51 }
52 
54 {
55 }
56 
57 Cylindrical2dMesh::Cylindrical2dMesh(double width, std::vector<Node<2>* > nodes)
58  : MutableMesh<2,2>(),
59  mWidth(width)
60 {
61  assert(width > 0.0);
62 // mMismatchedBoundaryElements = false;
63  for (unsigned index=0; index<nodes.size(); index++)
64  {
65  Node<2>* p_temp_node = nodes[index];
66  double x = p_temp_node->rGetLocation()[0];
67  UNUSED_OPT(x); // Fix optimised build
68  assert( 0 <= x && x < width);
69  mNodes.push_back(p_temp_node);
70  }
71 
72  NodeMap node_map(nodes.size());
73  ReMesh(node_map);
74 }
75 
76 //bool Cylindrical2dMesh::GetInstanceOfMismatchedBoundaryNodes()
77 //{
78 // return mMismatchedBoundaryElements;
79 //}
80 
82 {
83  ChasteCuboid<2> bounding_box = CalculateBoundingBox();
84  mBottom = bounding_box.rGetLowerCorner()[1];
85  mTop = bounding_box.rGetUpperCorner()[1];
86 }
87 
89 {
90  double half_way = 0.5*mWidth;
91 
92  mLeftOriginals.clear();
93  mLeftImages.clear();
95  mRightOriginals.clear();
96  mRightImages.clear();
100 
102  node_iter != GetNodeIteratorEnd();
103  ++node_iter)
104  {
105  c_vector<double, 2> location;
106  location = node_iter->rGetLocation();
107  unsigned this_node_index = node_iter->GetIndex();
108  double this_node_x_location = location[0];
109 
110  // Check the mesh currently conforms to the dimensions given
111  assert(0.0 <= location[0]);
112  assert(location[0] <= mWidth);
113 
114  // Put the nodes which are to be mirrored in the relevant vectors
115  if (this_node_x_location < half_way)
116  {
117  mLeftOriginals.push_back(this_node_index);
118  }
119  else
120  {
121  mRightOriginals.push_back(this_node_index);
122  }
123  }
124 
125  // For each left original node, create an image node and record its new index
126  for (unsigned i=0; i<mLeftOriginals.size(); i++)
127  {
128  c_vector<double, 2> location;
129  location = mNodes[mLeftOriginals[i]]->rGetLocation();
130  location[0] = location[0] + mWidth;
131 
132  unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
133  mLeftImages.push_back(new_node_index);
134  mImageToLeftOriginalNodeMap[new_node_index] = mLeftOriginals[i];
135  }
136 
137  // For each right original node, create an image node and record its new index
138  for (unsigned i=0; i<mRightOriginals.size(); i++)
139  {
140  c_vector<double, 2> location;
141  location = mNodes[mRightOriginals[i]]->rGetLocation();
142  location[0] = location[0] - mWidth;
143 
144  unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
145  mRightImages.push_back(new_node_index);
146  mImageToRightOriginalNodeMap[new_node_index] = mRightOriginals[i];
147  }
148 
149  assert(mRightOriginals.size() == mRightImages.size());
150  assert(mLeftOriginals.size() == mLeftImages.size());
151  assert(mImageToLeftOriginalNodeMap.size() == mLeftOriginals.size());
152  assert(mImageToRightOriginalNodeMap.size() == mRightOriginals.size());
153 }
154 
156 {
158 
159  mTopHaloNodes.clear();
160  mBottomHaloNodes.clear();
161 
162  unsigned num_halo_nodes = (unsigned)(floor(mWidth*2.0));
163  double halo_node_separation = mWidth/((double)(num_halo_nodes));
164  double y_top_coordinate = mTop + halo_node_separation;
165  double y_bottom_coordinate = mBottom - halo_node_separation;
166 
167  c_vector<double, 2> location;
168  for (unsigned i=0; i<num_halo_nodes; i++)
169  {
170  double x_coordinate = 0.5*halo_node_separation + (double)(i)*halo_node_separation;
171 
172  // Inserting top halo node in mesh
173  location[0] = x_coordinate;
174  location[1] = y_top_coordinate;
175  unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
176  mTopHaloNodes.push_back(new_node_index);
177 
178  location[1] = y_bottom_coordinate;
179  new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
180  mBottomHaloNodes.push_back(new_node_index);
181  }
182 }
183 
185 {
186  unsigned old_num_all_nodes = GetNumAllNodes();
187 
188  rMap.Resize(old_num_all_nodes);
189  rMap.ResetToIdentity();
190 
191  // Flag the deleted nodes as deleted in the map
192  for (unsigned i=0; i<old_num_all_nodes; i++)
193  {
194  if (mNodes[i]->IsDeleted())
195  {
196  rMap.SetDeleted(i);
197  }
198  }
199 
200  CreateHaloNodes();
201 
202  // Create mirrored nodes for the normal remesher to work with
204 
205  /*
206  * The mesh now has messed up boundary elements, but this
207  * doesn't matter as the ReMesh() below doesn't read them in
208  * and reconstructs the boundary elements.
209  *
210  * Call ReMesh() on the parent class. Note that the mesh now has lots
211  * of extra nodes which will be deleted, hence the name 'big_map'.
212  */
213  NodeMap big_map(GetNumAllNodes());
214  MutableMesh<2,2>::ReMesh(big_map);
215 
216  /*
217  * If the big_map isn't the identity map, the little map ('map') needs to be
218  * altered accordingly before being passed to the user. Not sure how this all
219  * works, so deal with this bridge when we get to it.
220  */
221  assert(big_map.IsIdentityMap());
222 
223  // Re-index the vectors according to the big nodemap, and set up the maps.
226 
227  assert(mLeftOriginals.size() == mLeftImages.size());
228  assert(mRightOriginals.size() == mRightImages.size());
229 
230  for (unsigned i=0; i<mLeftOriginals.size(); i++)
231  {
232  mLeftOriginals[i] = big_map.GetNewIndex(mLeftOriginals[i]);
233  mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]);
235  }
236 
237  for (unsigned i=0; i<mRightOriginals.size(); i++)
238  {
240  mRightImages[i] = big_map.GetNewIndex(mRightImages[i]);
242  }
243 
244  for (unsigned i=0; i<mTopHaloNodes.size(); i++)
245  {
246  mTopHaloNodes[i] = big_map.GetNewIndex(mTopHaloNodes[i]);
248  }
249 
250  /*
251  * Check that elements crossing the periodic boundary have been meshed
252  * in the same way at each side.
253  */
255 
256  /*
257  * Take the double-sized mesh, with its new boundary elements, and
258  * remove the relevant nodes, elements and boundary elements to leave
259  * a proper periodic mesh.
260  */
262 
263  DeleteHaloNodes();
264 
265  /*
266  * Create a random boundary element between two nodes of the first
267  * element if it is not deleted. This is a temporary measure to get
268  * around re-index crashing when there are no boundary elements.
269  */
270  unsigned num_elements = GetNumAllElements();
271  bool boundary_element_made = false;
272  unsigned elem_index = 0;
273 
274  while (elem_index<num_elements && !boundary_element_made)
275  {
276  Element<2,2>* p_element = GetElement(elem_index);
277  if (!p_element->IsDeleted())
278  {
279  boundary_element_made = true;
280  std::vector<Node<2>*> nodes;
281  nodes.push_back(p_element->GetNode(0));
282  nodes.push_back(p_element->GetNode(1));
283  BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes);
284  p_boundary_element->RegisterWithNodes();
285  mBoundaryElements.push_back(p_boundary_element);
286  this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2));
287  this->mBoundaryElementJacobianDeterminants.push_back(0.0);
288  }
289  elem_index++;
290  }
291 
292  // Now call ReIndex() to remove the temporary nodes which are marked as deleted
293  NodeMap reindex_map(GetNumAllNodes());
294  ReIndex(reindex_map);
295  assert(!reindex_map.IsIdentityMap()); // maybe don't need this
296 
297  /*
298  * Go through the reindex map and use it to populate the original NodeMap
299  * (the one that is returned to the user).
300  */
301  for (unsigned i=0; i<rMap.GetSize(); i++) // only going up to be size of map, not size of reindex_map
302  {
303  if (reindex_map.IsDeleted(i))
304  {
305  /*
306  * i < num_original_nodes and node is deleted, this should correspond to
307  * a node that was labelled as before the remeshing, so should have already
308  * been set as deleted in the map above.
309  */
310  assert(rMap.IsDeleted(i));
311  }
312  else
313  {
314  rMap.SetNewIndex(i, reindex_map.GetNewIndex(i));
315  }
316  }
317 
318  // We can now clear the index vectors and maps; they are only used for remeshing
319  mLeftOriginals.clear();
320  mLeftImages.clear();
322  mRightOriginals.clear();
323  mRightImages.clear();
327 }
328 
330 {
331  /*
332  * Figure out which elements have real nodes and image nodes in them
333  * and replace image nodes with corresponding real ones.
334  */
336  elem_iter != GetElementIteratorEnd();
337  ++elem_iter)
338  {
339  // Left images are on the right of the mesh
340  unsigned number_of_left_image_nodes = 0;
341  unsigned number_of_right_image_nodes = 0;
342 
343  for (unsigned i=0; i<3; i++)
344  {
345  unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
346 
347  if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
348  {
349  number_of_left_image_nodes++;
350  }
351  else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
352  {
353  number_of_right_image_nodes++;
354  }
355  }
356 
357  // Delete all the elements on the left hand side (images of right)...
358  if (number_of_right_image_nodes >= 1)
359  {
360  elem_iter->MarkAsDeleted();
361  mDeletedElementIndices.push_back(elem_iter->GetIndex());
362  }
363 
364  // Delete only purely imaginary elements on the right (images of left nodes)
365  if (number_of_left_image_nodes == 3)
366  {
367  elem_iter->MarkAsDeleted();
368  mDeletedElementIndices.push_back(elem_iter->GetIndex());
369  }
370 
371  /*
372  * If some are images then replace them with the real nodes. There
373  * can be elements with either two image nodes on the right (and one
374  * real) or one image node on the right (and two real).
375  */
376  if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
377  {
378  for (unsigned i=0; i<3; i++)
379  {
380  unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
381  std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
382  if (it != mImageToLeftOriginalNodeMap.end())
383  {
384  elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
385  }
386  }
387  }
388  }
389 
390  /*
391  * Figure out which boundary elements have real nodes and image nodes in them
392  * and replace image nodes with corresponding real ones.
393  */
394  for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
395  {
396  BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
397  if (!p_boundary_element->IsDeleted())
398  {
399  unsigned number_of_image_nodes = 0;
400  for (unsigned i=0; i<2; i++)
401  {
402  unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
403 
404  if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
405  {
406  number_of_image_nodes++;
407  }
408  else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
409  {
410  number_of_image_nodes++;
411  }
412  }
413 
414  if (number_of_image_nodes == 2)
415  {
416  p_boundary_element->MarkAsDeleted();
417  mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
418  }
419 
420  /*
421  * To avoid having two copies of the boundary elements on the periodic
422  * boundaries we only deal with the elements on the left image and
423  * delete the ones on the right image.
424  */
425  if (number_of_image_nodes == 1)
426  {
427  for (unsigned i=0; i<2; i++)
428  {
429  unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
430  std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
431  if (it != mImageToLeftOriginalNodeMap.end())
432  {
433  p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
434  }
435  else
436  {
437  it = mImageToRightOriginalNodeMap.find(this_node_index);
438  if (it != mImageToRightOriginalNodeMap.end())
439  {
440  p_boundary_element->MarkAsDeleted();
441  mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
442  }
443  }
444  }
445  }
446  }
447  }
448 
449  // Delete all image nodes unless they have already gone (halo nodes)
450  for (unsigned i=0; i<mLeftImages.size(); i++)
451  {
452  mNodes[mLeftImages[i]]->MarkAsDeleted();
453  mDeletedNodeIndices.push_back(mLeftImages[i]);
454  }
455 
456  for (unsigned i=0; i<mRightImages.size(); i++)
457  {
458  mNodes[mRightImages[i]]->MarkAsDeleted();
459  mDeletedNodeIndices.push_back(mRightImages[i]);
460  }
461 }
462 
464 {
465  assert(mTopHaloNodes.size() == mBottomHaloNodes.size());
466  for (unsigned i=0; i<mTopHaloNodes.size(); i++)
467  {
470  }
471 }
472 
473 c_vector<double, 2> Cylindrical2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
474 {
475  assert(mWidth > 0.0);
476 
477  c_vector<double, 2> vector = rLocation2 - rLocation1;
478  vector[0] = fmod(vector[0], mWidth);
479 
480  /*
481  * Handle the cylindrical condition here: if the points are more
482  * than halfway around the cylinder apart, measure the other way.
483  */
484  if (vector[0] > 0.5*mWidth)
485  {
486  vector[0] -= mWidth;
487  }
488  else if (vector[0] < -0.5*mWidth)
489  {
490  vector[0] += mWidth;
491  }
492  return vector;
493 }
494 
495 void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
496 {
497  // Perform a periodic movement if necessary
498  if (point.rGetLocation()[0] >= mWidth)
499  {
500  // Move point to the left
501  point.SetCoordinate(0, point.rGetLocation()[0] - mWidth);
502  }
503  else if (point.rGetLocation()[0] < 0.0)
504  {
505  // Move point to the right
506  point.SetCoordinate(0, point.rGetLocation()[0] + mWidth);
507  }
508 
509  // Update the node's location
510  MutableMesh<2,2>::SetNode(index, point, concreteMove);
511 }
512 
513 double Cylindrical2dMesh::GetWidth(const unsigned& rDimension) const
514 {
515  double width = 0.0;
516  assert(rDimension==0 || rDimension==1);
517  if (rDimension==0)
518  {
519  width = mWidth;
520  }
521  else
522  {
523  width = MutableMesh<2,2>::GetWidth(rDimension);
524  }
525  return width;
526 }
527 
529 {
530  unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
531 
532  // If necessary move it to be back on the cylinder
533  ChastePoint<2> new_node_point = pNewNode->GetPoint();
534  SetNode(node_index, new_node_point, false);
535 
536  return node_index;
537 }
538 
540 {
542 
543  /*
544  * Copy the member variables into new vectors, which we modify
545  * by knocking out elements which pair up on each side.
546  */
547  std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
548  std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
549 
550 // if ((mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size())
551 // || (temp_left_hand_side_elements.size() <= 2)
552 // || (temp_right_hand_side_elements.size() <= 2) )
553 // {
554 // mMismatchedBoundaryElements = true;
555 // }
557 
558  // Go through all of the elements on the left periodic boundary
559  for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
560  left_iter != mLeftPeriodicBoundaryElementIndices.end();
561  ++left_iter)
562  {
563  unsigned elem_index = *left_iter;
564 
565  Element<2,2>* p_element = GetElement(elem_index);
566 
567  /*
568  * Make lists of the nodes which the elements on the left contain and
569  * the nodes which should be in a corresponding element on the right.
570  */
571  c_vector<unsigned,3> original_element_node_indices;
572  c_vector<unsigned,3> corresponding_element_node_indices;
573  for (unsigned i=0; i<3; i++)
574  {
575  original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
576  corresponding_element_node_indices[i] = GetCorrespondingNodeIndex(original_element_node_indices[i]);
577  }
578 
579  // Search the right hand side elements for the corresponding element
580  for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
581  right_iter != mRightPeriodicBoundaryElementIndices.end();
582  ++right_iter)
583  {
584  unsigned corresponding_elem_index = *right_iter;
585 
586  Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
587 
588  bool is_corresponding_node = true;
589 
590  for (unsigned i=0; i<3; i++)
591  {
592  if ((corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
593  (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
594  (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
595  {
596  is_corresponding_node = false;
597  break;
598  }
599  }
600 
601  if (is_corresponding_node)
602  {
603  // Remove original and corresponding element from sets
604  temp_left_hand_side_elements.erase(elem_index);
605  temp_right_hand_side_elements.erase(corresponding_elem_index);
606  }
607  }
608  }
609 
610  /*
611  * If either of these ever throw you have more than one situation where the mesher has an option
612  * of how to mesh. If it does ever throw you need to be cleverer and match up the
613  * elements into as many pairs as possible on the left hand and right hand sides.
614  */
615 // assert(temp_left_hand_side_elements.size() <= 2);
616 // assert(temp_right_hand_side_elements.size() <= 2);
617 
618  /*
619  * Now we just have to use the first pair of elements and copy their info over to the other side.
620  * First we need to get hold of both elements on either side.
621  */
622  if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty())
623  {
624  assert(temp_right_hand_side_elements.empty());
625  assert(temp_left_hand_side_elements.empty());
626  }
627  else
628  {
629  if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2)
630  {
631  if (temp_right_hand_side_elements.size() == 2)
632  {
633  // Use the right hand side meshing and map to left
634  UseTheseElementsToDecideMeshing(temp_right_hand_side_elements);
635  }
636  else
637  {
638  /*
639  * If you get here there are more than two mixed up elements on the periodic edge.
640  * We need to knock the pair out and then rerun this function. This shouldn't be
641  * too hard to do but is as yet unnecessary.
642  */
644  }
645  }
646  }
647 }
648 
649 void Cylindrical2dMesh::UseTheseElementsToDecideMeshing(std::set<unsigned>& rMainSideElements)
650 {
651  assert(rMainSideElements.size() == 2);
652 
653  // We find the four nodes surrounding the dodgy meshing, on each side.
654  std::set<unsigned> main_four_nodes;
655  for (std::set<unsigned>::iterator left_iter = rMainSideElements.begin();
656  left_iter != rMainSideElements.end();
657  ++left_iter)
658  {
659  unsigned elem_index = *left_iter;
660  Element<2,2>* p_element = GetElement(elem_index);
661  for (unsigned i=0; i<3; i++)
662  {
663  unsigned index = p_element->GetNodeGlobalIndex(i);
664  main_four_nodes.insert(index);
665  }
666  }
667  assert(main_four_nodes.size() == 4);
668 
669  std::set<unsigned> other_four_nodes;
670  for (std::set<unsigned>::iterator iter = main_four_nodes.begin();
671  iter != main_four_nodes.end();
672  ++iter)
673  {
674  other_four_nodes.insert(GetCorrespondingNodeIndex(*iter));
675  }
676  assert(other_four_nodes.size() == 4);
677 
678  /*
679  * Find the elements surrounded by the nodes on the right
680  * and change them to match the elements on the left.
681  */
682  std::vector<unsigned> corresponding_elements;
683 
684  // Loop over all elements
686  elem_iter != GetElementIteratorEnd();
687  ++elem_iter)
688  {
689  // Loop over the nodes of the element
690  if (!(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(0))==other_four_nodes.end()) &&
691  !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(1))==other_four_nodes.end()) &&
692  !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(2))==other_four_nodes.end()) )
693  {
694  corresponding_elements.push_back(elem_iter->GetIndex());
695  elem_iter->MarkAsDeleted();
696  mDeletedElementIndices.push_back(elem_iter->GetIndex());
697  }
698  }
699  assert(corresponding_elements.size() == 2);
700 
701  // Now corresponding_elements contains the two elements which are going to be replaced by rMainSideElements
702  unsigned num_elements = GetNumAllElements();
703  for (std::set<unsigned>::iterator iter = rMainSideElements.begin();
704  iter != rMainSideElements.end();
705  ++iter)
706  {
707  Element<2,2>* p_main_element = GetElement(*iter);
708  std::vector<Node<2>*> nodes;
709 
710  // Put corresponding nodes into a std::vector
711  for (unsigned i=0; i<3; i++)
712  {
713  unsigned main_node = p_main_element->GetNodeGlobalIndex(i);
714  nodes.push_back(this->GetNode(GetCorrespondingNodeIndex(main_node)));
715  }
716 
717  // Make a new element
718  Element<2,2>* p_new_element = new Element<2,2>(num_elements, nodes);
719  this->mElements.push_back(p_new_element);
720  this->mElementJacobians.push_back(zero_matrix<double>(2,2));
721  this->mElementInverseJacobians.push_back(zero_matrix<double>(2,2));
722  this->mElementJacobianDeterminants.push_back(0.0);
723  num_elements++;
724  }
725 
726  // Reindex to get rid of extra elements indices
727  NodeMap map(GetNumAllNodes());
728  this->ReIndex(map);
729 }
730 
732 {
735 
736  unsigned incidences_of_zero_left_image_nodes = 0;
737  unsigned incidences_of_zero_right_image_nodes = 0;
738 
740  elem_iter != GetElementIteratorEnd();
741  ++elem_iter)
742  {
743  // Left images are on the right of the mesh
744  unsigned number_of_left_image_nodes = 0;
745  unsigned number_of_right_image_nodes = 0;
746 
747  for (unsigned i=0; i<3; i++)
748  {
749  unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
750 
751  if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
752  {
753  number_of_left_image_nodes++;
754  }
755  else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
756  {
757  number_of_right_image_nodes++;
758  }
759  }
760 
761  if ((number_of_left_image_nodes == 0) && (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2) )
762  {
763  incidences_of_zero_left_image_nodes++;
764  }
765  if ((number_of_right_image_nodes == 0) && (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) )
766  {
767  incidences_of_zero_right_image_nodes++;
768  }
769 
770  /* SJ - Have checked the following:
771  * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3
772  * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes
773  * - There are 450 incidences of zero left image nodes and non-zero right image nodes; 438 incidences of zero right image nodes and non-zero left
774  * image nodes
775  * - There are 40 incidences of 0 left image nodes, and 1/2 right image nodes; 39 incidences of 0 right image nodes and 1/2 left image nodes
776  * As this corresponds to 40 left-hand boundary elements and 39 right-hand boundary elements, then it is this extra occurrence of a 0 left
777  * image node with 1/2 right image nodes that is responsible for the extra element.
778  */
779 
780  // Elements on the left hand side (images of right nodes)
781  if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2)
782  {
783  mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
784  }
785 
786  // Elements on the right (images of left nodes)
787  if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
788  {
789  mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
790  }
791  }
792 
793 // if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
794 // {
795 // mMismatchedBoundaryElements = true;
796 // // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
797 //
798 // }
799 
800  // Every boundary element on the left must have a corresponding element on the right
802 }
803 
805 {
806  unsigned corresponding_node_index = UINT_MAX;
807 
808  // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages
809  std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex);
810  if (right_orig_iter != mRightOriginals.end())
811  {
812  corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()];
813  }
814  else
815  {
816  // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals
817  std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex);
818  if (right_im_iter != mRightImages.end())
819  {
820  corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()];
821  }
822  else
823  {
824  // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages
825  std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex);
826  if (left_orig_iter != mLeftOriginals.end())
827  {
828  corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()];
829  }
830  else
831  {
832  // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals
833  std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex);
834  if (left_im_iter != mLeftImages.end())
835  {
836  corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()];
837  }
838  }
839  }
840  }
841 
842  // We must have found the corresponding node index
843  assert(corresponding_node_index != UINT_MAX);
844  return corresponding_node_index;
845 }
846 
847 // Serialization for Boost >= 1.36
std::vector< c_matrix< double, SPACE_DIM, ELEMENT_DIM > > mElementJacobians
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
std::vector< Element< ELEMENT_DIM, SPACE_DIM > * > mElements
Definition: Node.hpp:58
c_vector< double, DIM > & rGetLocation()
Definition: ChastePoint.cpp:76
std::vector< unsigned > mDeletedBoundaryElementIndices
unsigned GetNodeGlobalIndex(unsigned localIndex) const
void SetNode(unsigned index, ChastePoint< 2 > point, bool concreteMove)
std::set< unsigned > mLeftPeriodicBoundaryElementIndices
std::vector< unsigned > mTopHaloNodes
Node< SPACE_DIM > * GetNode(unsigned index) const
unsigned GetCorrespondingNodeIndex(unsigned nodeIndex)
std::vector< c_matrix< double, ELEMENT_DIM, SPACE_DIM > > mElementInverseJacobians
void UseTheseElementsToDecideMeshing(std::set< unsigned > &rMainSideElements)
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
void ReplaceNode(Node< SPACE_DIM > *pOldNode, Node< SPACE_DIM > *pNewNode)
NodeIterator GetNodeIteratorEnd()
std::vector< unsigned > mLeftOriginals
void ReIndex(NodeMap &map)
void ResetToIdentity()
Definition: NodeMap.cpp:57
virtual ChasteCuboid< SPACE_DIM > CalculateBoundingBox() const
unsigned GetSize()
Definition: NodeMap.cpp:105
virtual unsigned GetNumAllNodes() const
#define NEVER_REACHED
Definition: Exception.hpp:206
virtual void SetNode(unsigned index, ChastePoint< SPACE_DIM > point, bool concreteMove=true)
virtual unsigned AddNode(Node< SPACE_DIM > *pNewNode)
Definition: MutableMesh.cpp:80
bool IsDeleted() const
void SetNewIndex(unsigned oldIndex, unsigned newIndex)
Definition: NodeMap.cpp:66
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
std::vector< unsigned > mDeletedNodeIndices
const ChastePoint< SPACE_DIM > & rGetUpperCorner() const
std::vector< Node< SPACE_DIM > * > mNodes
c_vector< double, 2 > GetVectorFromAtoB(const c_vector< double, 2 > &rLocation1, const c_vector< double, 2 > &rLocation2)
void SetCoordinate(unsigned i, double value)
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * > mBoundaryElements
std::map< unsigned, unsigned > mImageToRightOriginalNodeMap
void SetDeleted(unsigned index)
Definition: NodeMap.cpp:76
std::vector< double > mElementJacobianDeterminants
std::vector< unsigned > mRightOriginals
std::vector< c_vector< double, SPACE_DIM > > mBoundaryElementWeightedDirections
void GenerateVectorsOfElementsStraddlingPeriodicBoundaries()
unsigned AddNode(Node< 2 > *pNewNode)
bool IsIdentityMap()
Definition: NodeMap.cpp:100
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
std::vector< unsigned > mLeftImages
std::vector< unsigned > mRightImages
BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * GetBoundaryElement(unsigned index) const
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:139
#define UNUSED_OPT(var)
Definition: Exception.hpp:216
bool IsDeleted(unsigned index)
Definition: NodeMap.cpp:82
unsigned GetNewIndex(unsigned oldIndex) const
Definition: NodeMap.cpp:87
unsigned GetIndex() const
ChastePoint< SPACE_DIM > GetPoint() const
Definition: Node.cpp:133
virtual double GetWidth(const unsigned &rDimension) const
std::vector< double > mBoundaryElementJacobianDeterminants
unsigned GetNumAllBoundaryElements() const
#define CHASTE_CLASS_EXPORT(T)
Cylindrical2dMesh(double width)
std::set< unsigned > mRightPeriodicBoundaryElementIndices
void DeleteBoundaryNodeAt(unsigned index)
std::map< unsigned, unsigned > mImageToLeftOriginalNodeMap
std::vector< unsigned > mDeletedElementIndices
void Resize(unsigned size)
Definition: NodeMap.cpp:52
std::vector< unsigned > mBottomHaloNodes
double GetWidth(const unsigned &rDimension) const
const ChastePoint< SPACE_DIM > & rGetLowerCorner() const