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