triangle_mesh.template.cc
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 #ifndef OOMPH_TRIANGLE_MESH_TEMPLATE_CC
31 #define OOMPH_TRIANGLE_MESH_TEMPLATE_CC
32 
33 #include <iostream>
34 
35 #include "triangle_mesh.template.h"
36 #include "../generic/map_matrix.h"
37 #include "../generic/multi_domain.h"
38 #include "../generic/projection.h"
39 #include "../generic/face_element_as_geometric_object.h"
40 
41 namespace oomph
42 {
43 
44  //======================================================================
45  /// Build with the help of the scaffold mesh coming
46  /// from the triangle mesh generator Triangle.
47  //======================================================================
48  template<class ELEMENT>
50  const bool &use_attributes)
51  {
52  // Mesh can only be built with 2D Telements.
53  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
54 
55  // Create space for elements
56  unsigned nelem = Tmp_mesh_pt->nelement();
57  Element_pt.resize(nelem);
58 
59  // Create space for nodes
60  unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
61 
62  // Create a map storing the node_id of the mesh used to update the
63  // node position in the update_triangulateio function
64  std::map<Node*, unsigned> old_global_number;
65 
66  // Store the TriangulateIO node id
67  for (unsigned inod = 0; inod < nnode_scaffold; inod++)
68  {
69  Node* old_node_pt = Tmp_mesh_pt->node_pt(inod);
70  old_global_number[old_node_pt] = inod;
71  }
72 
73  // Initialize the old node id vector
74  Oomph_vertex_nodes_id.resize(nnode_scaffold);
75 
76  // Create space for nodes
77  Node_pt.resize(nnode_scaffold, 0);
78 
79  // Set number of boundaries
80  unsigned nbound = Tmp_mesh_pt->nboundary();
81 
82  // Resize the boundary information
83  set_nboundary(nbound);
84  Boundary_element_pt.resize(nbound);
85  Face_index_at_boundary.resize(nbound);
86 
87  //If we have different regions, then resize the region
88  //information
89  if (use_attributes)
90  {
91  Boundary_region_element_pt.resize(nbound);
92  Face_index_region_at_boundary.resize(nbound);
93  }
94 
95  // Loop over elements in scaffold mesh, visit their nodes
96  for (unsigned e = 0; e < nelem; e++)
97  {
98  Element_pt[e] = new ELEMENT;
99  }
100 
101  //Number of nodes per element from the scaffold mesh
102  unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
103 
104  // Setup map to check the (pseudo-)global node number
105  // Nodes whose number is zero haven't been copied across
106  // into the mesh yet.
107  std::map<Node*, unsigned> global_number;
108  unsigned global_count = 0;
109 
110  // Map of Element attribute pairs
111  std::map<double, Vector<FiniteElement*> > element_attribute_map;
112 
113  // If we're using attributes
114  if (use_attributes)
115  {
116  // If we're using attributes then we need attribute 0 which will
117  // be associated with region 0
118  element_attribute_map[0].resize(0);
119  }
120 
121  // Loop over elements in scaffold mesh, visit their nodes
122  for (unsigned e = 0; e < nelem; e++)
123  {
124  // Loop over all nodes in element
125  for (unsigned j = 0; j < nnod_el; j++)
126  {
127  // Pointer to node in the scaffold mesh
128  Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
129 
130  // Get the (pseudo-)global node number in scaffold mesh
131  // (It's zero [=default] if not visited this one yet)
132  unsigned j_global = global_number[scaffold_node_pt];
133 
134  // Haven't done this one yet
135  if (j_global == 0)
136  {
137  // Find and store the node_id in the old nodes map
138  Oomph_vertex_nodes_id[global_count] =
139  old_global_number[scaffold_node_pt];
140 
141  // Get pointer to set of mesh boundaries that this
142  // scaffold node occupies; NULL if the node is not on any boundary
143  std::set<unsigned>* boundaries_pt;
144  scaffold_node_pt->get_boundaries_pt(boundaries_pt);
145 
146  //Storage for the new node
147  Node* new_node_pt = 0;
148 
149  //Is it on boundaries
150  if (boundaries_pt != 0)
151  {
152  //Create new boundary node
153  new_node_pt=
154  finite_element_pt(e)->construct_boundary_node(j,time_stepper_pt);
155 
156  // Add to boundaries
157  for (std::set<unsigned>::iterator it = boundaries_pt->begin(); it
158  != boundaries_pt->end(); ++it)
159  {
160  add_boundary_node(*it, new_node_pt);
161  }
162  }
163  //Build normal node
164  else
165  {
166  //Create new normal node
167  new_node_pt = finite_element_pt(e)->construct_node(j,time_stepper_pt);
168  }
169 
170  // Give it a number (not necessarily the global node
171  // number in the scaffold mesh -- we just need something
172  // to keep track...)
173  global_count++;
174  global_number[scaffold_node_pt] = global_count;
175 
176  // Copy new node, created using the NEW element's construct_node
177  // function into global storage, using the same global
178  // node number that we've just associated with the
179  // corresponding node in the scaffold mesh
180  Node_pt[global_count - 1] = new_node_pt;
181 
182  // Assign coordinates
183  for (unsigned i = 0; i < finite_element_pt(e)->dim(); i++)
184  {
185  new_node_pt->x(i) = scaffold_node_pt->x(i);
186  }
187  }
188  // This one has already been done: Copy accross
189  else
190  {
191  finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
192  }
193  }
194 
195  // If we're using attributes
196  if (use_attributes)
197  {
198  element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
199  finite_element_pt(e));
200  }
201  }
202 
203  //Now let's construct lists
204  //Find the number of attributes
205  if (use_attributes)
206  {
207  unsigned n_attribute = element_attribute_map.size();
208 
209  //There are n_attribute different regions
210  this->Region_attribute.resize(n_attribute);
211 
212  //Copy the vectors in the map over to our internal storage
213  unsigned count = 0;
214  for (std::map<double, Vector<FiniteElement*> >::iterator it =
215  element_attribute_map.begin(); it!=element_attribute_map.end(); ++it)
216  {
217  this->Region_attribute[count] = it->first;
218  Region_element_pt[static_cast<unsigned>(Region_attribute[count])] =
219  it->second;
220  ++count;
221  }
222 
223  }
224 
225  // At this point we've created all the elements and
226  // created their vertex nodes. Now we need to create
227  // the additional (midside and internal) nodes!
228 
229  unsigned boundary_id=0;
230 
231  // Get number of nodes along element edge and dimension of element (2)
232  // from first element
233  unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
234  unsigned dim = finite_element_pt(0)->dim();
235 
236  // Storage for the local coordinate of the new node
237  Vector<double> s(dim);
238 
239  // Get number of nodes in the element from first element
240  unsigned n_node = finite_element_pt(0)->nnode();
241 
242  //Storage for each global edge of the mesh
243  unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
244  Vector < Vector<Node*> > nodes_on_global_edge(n_global_edge);
245 
246  // Loop over elements
247  for (unsigned e = 0; e < nelem; e++)
248  {
249  //Cache pointers to the elements
250  FiniteElement* const elem_pt = finite_element_pt(e);
251  FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
252 
253  //The number of edge nodes is 3*(nnode_1d-1)
254  unsigned n_edge_node = 3 * (n_node_1d - 1);
255 
256  //If there are any more nodes, these are internal and can be
257  //constructed and added directly to the mesh
258  for (unsigned n = n_edge_node; n < n_node; ++n)
259  {
260  // Create new node (it can never be a boundary node)
261  Node* new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
262 
263  // What are the node's local coordinates?
264  elem_pt->local_coordinate_of_node(n, s);
265 
266  // Find the coordinates of the new node from the existing
267  // and fully-functional element in the scaffold mesh
268  for (unsigned i = 0; i < dim; i++)
269  {
270  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
271  }
272 
273  //Add the node to the mesh's global look-up scheme
274  Node_pt.push_back(new_node_pt);
275  }
276 
277  //Now loop over the mid-side edge nodes
278  //Start from node number 3
279  unsigned n = 3;
280 
281  // Loop over edges
282  for (unsigned j = 0; j < 3; j++)
283  {
284  //Find the boundary id of the edge
285  boundary_id = Tmp_mesh_pt->edge_boundary(e, j);
286 
287  //Find the global edge index
288  unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
289 
290  //If the nodes on the edge have not been allocated, construct them
291  if (nodes_on_global_edge[edge_index].size() == 0)
292  {
293  //Loop over the nodes on the edge excluding the ends
294  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
295  {
296  //Storage for the new node
297  Node* new_node_pt = 0;
298 
299  //If the edge is on a boundary, construct a boundary node
300  if (boundary_id > 0)
301  {
302  new_node_pt = elem_pt->construct_boundary_node(n, time_stepper_pt);
303  //Add it to the boundary
304  this->add_boundary_node(boundary_id - 1, new_node_pt);
305  }
306  //Otherwise construct a normal node
307  else
308  {
309  new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
310  }
311 
312  // What are the node's local coordinates?
313  elem_pt->local_coordinate_of_node(n, s);
314 
315  // Find the coordinates of the new node from the existing
316  // and fully-functional element in the scaffold mesh
317  for (unsigned i = 0; i < dim; i++)
318  {
319  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
320  }
321 
322  //Add to the global node list
323  Node_pt.push_back(new_node_pt);
324 
325  //Add to the edge index
326  nodes_on_global_edge[edge_index].push_back(new_node_pt);
327  //Increment the node number
328  ++n;
329  }
330  }
331  //Otherwise just set the pointers
332  //using the fact that the next time the edge is visited
333  //the nodes must be arranged in the other order because all
334  //triangles have the same orientation
335  else
336  {
337  //Loop over the nodes on the edge excluding the ends
338  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
339  {
340  //Set the local node from the edge but indexed the other
341  //way around
342  elem_pt->node_pt(n) = nodes_on_global_edge[edge_index][n_node_1d - 3
343  - j2];
344  ++n;
345  }
346  }
347 
348  //Set the elements adjacent to the boundary from the
349  //boundary id information
350  if (boundary_id > 0)
351  {
352  Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
353  //Need to put a shift in here because of an inconsistent naming
354  //convention between triangle and face elements
355  Face_index_at_boundary[boundary_id - 1].push_back((j + 2) % 3);
356 
357  //If using regions set up the boundary information
358  if (use_attributes)
359  {
360  unsigned tmp_region =
361  static_cast<unsigned> (Tmp_mesh_pt->element_attribute(e));
362  //Element adjacent to boundary
363  Boundary_region_element_pt[boundary_id - 1]
364  [tmp_region].push_back(elem_pt);
365  //Need to put a shift in here because of an inconsistent naming
366  //convention between triangle and face elements
367  Face_index_region_at_boundary[boundary_id - 1]
368  [tmp_region].push_back((j + 2) % 3);
369  }
370  }
371 
372  } //end of loop over edges
373  } //end of loop over elements
374 
375 
376  // Lookup scheme has now been setup
377  Lookup_for_elements_next_boundary_is_setup = true;
378 
379  }
380 
381 #ifdef OOMPH_HAS_MPI
382 
383  //======================================================================
384  /// \short Identify the segments from the old mesh (original mesh)
385  /// in the new mesh (this) and assign initial and final boundary
386  /// coordinates for the segments that create the boundary
387  //======================================================================
388  template<class ELEMENT>
391  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt)
392  {
393  // ------------------------------------------------------------------
394  // First: Get the face elements associated with the current boundary
395  // (nonhalo elements only)
396  // ------------------------------------------------------------------
397  // Temporary storage for face elements
398  Vector<FiniteElement*> face_el_pt;
399 
400  // Temporary storage for number of elements adjacent to the boundary
401  unsigned nele = 0;
402 
403  // Temporary storage for elements adjacent to the boundary that have
404  // a common edge (related with internal boundaries)
405  unsigned n_repeated_ele = 0;
406 
407  const unsigned n_regions = this->nregion();
408 
409  // map to associate the face element to the bulk element, necessary
410  // to attach halo face elements at both sides of each found segment
411  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
412 
413  // Temporary storage for already done nodes
414  Vector<std::pair<Node*, Node*> > done_nodes_pt;
415 
416  // If there is more than one region then only use boundary
417  // coordinates from the bulk side (region 0)
418  if (n_regions > 1)
419  {
420  for (unsigned rr = 0 ; rr < n_regions; rr++)
421  {
422  const unsigned region_id =
423  static_cast<unsigned>(this->Region_attribute[rr]);
424 
425  // Loop over all elements on boundaries in region i_r
426  const unsigned nel_in_region =
427  this->nboundary_element_in_region(b, region_id);
428 
429  unsigned nel_repetead_in_region = 0;
430 
431  // Only bother to do anything else, if there are elements
432  // associated with the boundary and the current region
433  if (nel_in_region > 0)
434  {
435  // Flag that activates when a repeated face element is found,
436  // possibly because we are dealing with an internal boundary
437  bool repeated = false;
438 
439  // Loop over the bulk elements adjacent to boundary b
440  for (unsigned e = 0; e < nel_in_region; e++)
441  {
442  // Get pointer to the bulk element that is adjacent to boundary b
443  FiniteElement* bulk_elem_pt =
444  this->boundary_element_in_region_pt(b, region_id, e);
445 
446 #ifdef OOMPH_HAS_MPI
447  // In a distributed mesh only work with nonhalo elements
448  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
449  {
450  // Increase the number of repeated elements
451  n_repeated_ele++;
452  // Go for the next element
453  continue;
454  }
455 #endif
456 
457  //Find the index of the face of element e along boundary b
458  int face_index =
459  this->face_index_at_boundary_in_region(b,region_id,e);
460 
461  // Before adding the new element we need to be sure that
462  // the edge that this element represent has not been
463  // already added
464  FiniteElement* tmp_ele_pt =
465  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
466 
467  const unsigned n_nodes = tmp_ele_pt->nnode();
468 
469  std::pair<Node*, Node*> tmp_pair =
470  std::make_pair(tmp_ele_pt->node_pt(0),
471  tmp_ele_pt->node_pt(n_nodes - 1));
472 
473  std::pair<Node*, Node*> tmp_pair_inverse =
474  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
475  tmp_ele_pt->node_pt(0));
476 
477  // Search for repeated nodes
478  const unsigned n_done_nodes = done_nodes_pt.size();
479  for (unsigned l = 0; l < n_done_nodes; l++)
480  {
481  if (tmp_pair == done_nodes_pt[l] ||
482  tmp_pair_inverse == done_nodes_pt[l])
483  {
484  nel_repetead_in_region++;
485  repeated = true;
486  break;
487  }
488  }
489 
490  // Create new face element
491  if (!repeated)
492  {
493  // Add the pair of nodes (edge) to the node dones
494  done_nodes_pt.push_back(tmp_pair);
495  // Create the map to know if the element is halo
496  face_el_pt.push_back(tmp_ele_pt);
497  // Add the element to the face elements
498  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
499  }
500  else
501  {
502  // Clean up
503  delete tmp_ele_pt;
504  tmp_ele_pt = 0;
505  }
506 
507  // Re-start
508  repeated = false;
509 
510  } // for (e < nel_in_region)
511 
512  nele += nel_in_region;
513 
514  n_repeated_ele += nel_repetead_in_region;
515 
516  } // if (nel_in_region > 0)
517  } // for (rr < n_regions)
518  } // if (n_regions > 1)
519  //Otherwise it's just the normal boundary functions
520  else
521  {
522  // Loop over all elements on boundaries
523  nele = this->nboundary_element(b);
524 
525  //Only bother to do anything else, if there are elements
526  if (nele > 0)
527  {
528  // Flag that activates when a repeated face element is found,
529  // possibly because we are dealing with an internal boundary
530  bool repeated = false;
531 
532  // Loop over the bulk elements adjacent to boundary b
533  for (unsigned e = 0; e < nele; e++)
534  {
535  // Get pointer to the bulk element that is adjacent to boundary b
536  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
537 
538 #ifdef OOMPH_HAS_MPI
539  // In a distributed mesh only work with nonhalo elements
540  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
541  {
542  // Increase the number of repeated elements
543  n_repeated_ele++;
544  // Go for the next element
545  continue;
546  }
547 #endif
548 
549  //Find the index of the face of element e along boundary b
550  int face_index = this->face_index_at_boundary(b, e);
551 
552  // Before adding the new element we need to be sure that
553  // the edge that this element represents has not been
554  // already added (only applies for internal boundaries)
555  FiniteElement* tmp_ele_pt =
556  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
557 
558  const unsigned n_nodes = tmp_ele_pt->nnode();
559 
560  std::pair<Node*, Node*> tmp_pair =
561  std::make_pair(tmp_ele_pt->node_pt(0),
562  tmp_ele_pt->node_pt(n_nodes - 1));
563 
564  std::pair<Node*, Node*> tmp_pair_inverse =
565  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
566  tmp_ele_pt->node_pt(0));
567 
568  // Search for repeated nodes
569  const unsigned n_done_nodes = done_nodes_pt.size();
570  for (unsigned l = 0; l < n_done_nodes; l++)
571  {
572  if (tmp_pair == done_nodes_pt[l] ||
573  tmp_pair_inverse == done_nodes_pt[l])
574  {
575  // Increase the number of repeated elements
576  n_repeated_ele++;
577  // Mark the element as repeated
578  repeated = true;
579  break;
580  }
581  }
582 
583  // Create new face element
584  if (!repeated)
585  {
586  // Add the pair of nodes (edge) to the node dones
587  done_nodes_pt.push_back(tmp_pair);
588  // Add the element to the face elements
589  face_el_pt.push_back(tmp_ele_pt);
590  // Create the map to know if the element is halo
591  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
592  }
593  else
594  {
595  // Free the repeated bulk element!!
596  delete tmp_ele_pt;
597  tmp_ele_pt = 0;
598  }
599 
600  // Re-start
601  repeated = false;
602 
603  } // for (e < nel)
604  } // if (nel > 0)
605 
606  } // else (n_regions > 1)
607 
608  // Do not consider the repeated elements
609  nele-= n_repeated_ele;
610 
611 #ifdef PARANOID
612  if (nele!=face_el_pt.size())
613  {
614  std::ostringstream error_message;
615  error_message
616  << "The independent counting of face elements ("<<nele<<") for "
617  << "boundary ("<<b<<") is different\n"
618  << "from the real number of face elements in the container ("
619  << face_el_pt.size() <<")\n";
620  throw OomphLibError(error_message.str(),
621  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
622  OOMPH_EXCEPTION_LOCATION);
623  }
624 #endif
625 
626  // Continue even thought there are no elements, the processor needs
627  // to participate in the communications
628 
629  // ----------------------------------------------------------------
630  // Second: Sort the face elements, only consider nonhalo elements
631  // ----------------------------------------------------------------
632 
633  // A flag vector to mark those face elements that are considered as
634  // halo in the current processor
635  std::vector<bool> is_halo_face_element(nele,false);
636 
637  // Count the total number of non halo face elements
638  unsigned nnon_halo_face_elements = 0;
639 
640  // We will have halo face elements if the mesh is distributed
641  for (unsigned ie = 0; ie < nele; ie++)
642  {
643  // Get the face element
644  FiniteElement* face_ele_pt = face_el_pt[ie];
645  // Get the bulk element
646  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
647  // Check if the bulk element is halo
648  if (!tmp_bulk_ele_pt->is_halo())
649  {
650  is_halo_face_element[ie] = false;
651  nnon_halo_face_elements++;
652  }
653  else
654  {
655  // Mark the face element as halo
656  is_halo_face_element[ie] = true;
657  }
658  } // for (ie < nele)
659 
660 #ifdef PARANOID
661  // Get the total number of halo face elements
662  const unsigned nhalo_face_element = nele - nnon_halo_face_elements;
663  if (nhalo_face_element > 0)
664  {
665  std::ostringstream error_message;
666  error_message
667  << "There should not be halo face elements since they were not "
668  << "considered when computing the face elements\n\n"
669  << "The number of found halo face elements is: "
670  << nhalo_face_element << "\n\n";
671  throw OomphLibError(error_message.str(),
672  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
673  OOMPH_EXCEPTION_LOCATION);
674  }
675 #endif
676 
677  // The vector of list to store the "segments" that compound the
678  // boundary (segments may appear only in a distributed mesh)
679  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
680 
681  // Number of already sorted face elements (only nonhalo elements for
682  // a distributed mesh)
683  unsigned nsorted_face_elements = 0;
684 
685  // Keep track of who's done (this apply to nonhalo only, remember we
686  // are only working with nonhalo elements)
687  std::map<FiniteElement*, bool> done_el;
688 
689  // Keep track of which element is inverted (in distributed mesh the
690  // elements may be inverted with respect to the segment they belong)
691  std::map<FiniteElement*, bool> is_inverted;
692 
693  // Iterate until all possible segments have been created
694  while(nsorted_face_elements < nnon_halo_face_elements)
695  {
696  // The ordered list of face elements (in a distributed mesh a
697  // collection of contiguous face elements define a segment)
698  std::list<FiniteElement*> sorted_el_pt;
699  sorted_el_pt.clear();
700 
701 #ifdef PARANOID
702  // Select an initial element for the segment
703  bool found_initial_face_element = false;
704 #endif
705 
706  FiniteElement* ele_face_pt = 0;
707 
708  unsigned iface = 0;
709  for (iface = 0; iface < nele; iface++)
710  {
711  if (!is_halo_face_element[iface])
712  {
713  ele_face_pt = face_el_pt[iface];
714  // If not done then take it as initial face element
715  if (!done_el[ele_face_pt])
716  {
717 #ifdef PARANOID
718  found_initial_face_element = true;
719 #endif
720  nsorted_face_elements++;
721  iface++; // The next element number
722  sorted_el_pt.push_back(ele_face_pt);
723  // Mark as done
724  done_el[ele_face_pt] = true;
725  break;
726  }
727  }
728  } // for (iface < nele)
729 
730 #ifdef PARANOID
731  if (!found_initial_face_element)
732  {
733  std::ostringstream error_message;
734  error_message
735  <<"Could not find an initial face element for the current segment\n";
736  throw OomphLibError(error_message.str(),
737  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
738  OOMPH_EXCEPTION_LOCATION);
739  }
740 #endif
741 
742  // Number of nodes
743  const unsigned nnod = ele_face_pt->nnode();
744 
745  // Left and right most nodes (the left and right nodes of the
746  // current face element)
747  Node* left_node_pt = ele_face_pt->node_pt(0);
748  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
749 
750  // Continue iterating if a new face element has been added to the
751  // list
752  bool face_element_added = false;
753 
754  // While a new face element has been added to the set of sorted
755  // face elements then re-iterate
756  do
757  {
758  // Start from the next face element since we have already added
759  // the previous one as the initial face element (any previous
760  // face element had to be added on previous iterations)
761  for (unsigned iiface = iface; iiface < nele; iiface++)
762  {
763  // Re-start flag
764  face_element_added = false;
765 
766  // Get the candidate element
767  ele_face_pt = face_el_pt[iiface];
768 
769  // Check that the candidate element has not been done and is
770  // not a halo element
771  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
772  {
773  // Get the left and right nodes of the current element
774  Node* local_left_node_pt = ele_face_pt->node_pt(0);
775  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
776  // New element fits at the left of segment and is not inverted
777  if (left_node_pt == local_right_node_pt)
778  {
779  left_node_pt = local_left_node_pt;
780  sorted_el_pt.push_front(ele_face_pt);
781  is_inverted[ele_face_pt] = false;
782  face_element_added = true;
783  }
784  // New element fits at the left of segment and is inverted
785  else if (left_node_pt == local_left_node_pt)
786  {
787  left_node_pt = local_right_node_pt;
788  sorted_el_pt.push_front(ele_face_pt);
789  is_inverted[ele_face_pt] = true;
790  face_element_added = true;
791  }
792  // New element fits on the right of segment and is not inverted
793  else if (right_node_pt == local_left_node_pt)
794  {
795  right_node_pt = local_right_node_pt;
796  sorted_el_pt.push_back(ele_face_pt);
797  is_inverted[ele_face_pt] = false;
798  face_element_added = true;
799  }
800  // New element fits on the right of segment and is inverted
801  else if (right_node_pt == local_right_node_pt)
802  {
803  right_node_pt = local_left_node_pt;
804  sorted_el_pt.push_back(ele_face_pt);
805  is_inverted[ele_face_pt] = true;
806  face_element_added = true;
807  }
808 
809  if (face_element_added)
810  {
811  done_el[ele_face_pt] = true;
812  nsorted_face_elements++;
813  break;
814  }
815 
816  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
817  } // for (iiface<nnon_halo_face_element)
818  }while(face_element_added &&
819  (nsorted_face_elements < nnon_halo_face_elements));
820 
821  // Store the created segment in the vector of segments
822  segment_sorted_ele_pt.push_back(sorted_el_pt);
823 
824  } // while(nsorted_face_elements < nnon_halo_face_elements);
825 
826  // The number of segments in this processor
827  const unsigned nsegments = segment_sorted_ele_pt.size();
828 
829  // ------------------------------------------------------------------
830  // Third: We have the face elements sorted (nonhalo only), now
831  // assign boundary coordinates to the nodes in the segments. This is
832  // the LOCAL boundary coordinate which is required if the zeta
833  // values need to be inverted
834  // ------------------------------------------------------------------
835  // Necessary in case boundaries with no geom object associated need
836  // to be inverted the zeta values (It is necessary to compute the
837  // arclength but also to store the nodes in a container (set))
838  // ------------------------------------------------------------------
839 
840  // Vector of sets that stores the nodes of each segment based on a
841  // lexicographically order starting from the bottom left node of
842  // each segment
843  Vector<std::set<Node*> > segment_all_nodes_pt;
844 
845  // The arclength of each segment in the current processor
846  Vector<double> segment_arclength(nsegments);
847 
848  // The number of vertices of each segment
849  Vector<unsigned> nvertices_per_segment(nsegments);
850 
851  // The initial zeta for the segment
852  Vector<double> initial_zeta_segment(nsegments);
853 
854  // The final zeta for the segment
855  Vector<double> final_zeta_segment(nsegments);
856 
857 #ifdef PARANOID
858  if (nnon_halo_face_elements > 0 && nsegments == 0)
859  {
860  std::ostringstream error_message;
861  error_message
862  << "The number of segments is zero, but the number of nonhalo\n"
863  << "elements is: (" << nnon_halo_face_elements << ")\n";
864  throw OomphLibError(error_message.str(),
865  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
866  OOMPH_EXCEPTION_LOCATION);
867  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
868 #endif
869 
870  // Go through all the segments and compute the LOCAL boundary
871  // coordinates
872  for (unsigned is = 0; is < nsegments; is++)
873  {
874 #ifdef PARANOID
875  if (segment_sorted_ele_pt[is].size() == 0)
876  {
877  std::ostringstream error_message;
878  error_message
879  << "The (" << is << ")-th segment has no elements\n";
880  throw OomphLibError(error_message.str(),
881  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
882  OOMPH_EXCEPTION_LOCATION);
883  } // if (segment_sorted_ele_pt[is].size() == 0)
884 #endif
885 
886  // Get access to the first element on the segment
887  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
888 
889  // Number of nodes
890  const unsigned nnod = first_ele_pt->nnode();
891 
892  // Get the first node of the current segment
893  Node *first_node_pt = first_ele_pt->node_pt(0);
894  if (is_inverted[first_ele_pt])
895  {
896  first_node_pt = first_ele_pt->node_pt(nnod-1);
897  }
898 
899  // Get access to the last element on the segment
900  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
901 
902  // Get the last node of the current segment
903  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
904  if (is_inverted[last_ele_pt])
905  {
906  last_node_pt = last_ele_pt->node_pt(0);
907  }
908 
909  // Coordinates of left node
910  double x_left = first_node_pt->x(0);
911  double y_left = first_node_pt->x(1);
912 
913  // Initialise boundary coordinate (local boundary coordinate for
914  // boundaries with more than one segment)
915  Vector<double> zeta(1, 0.0);
916 
917  // If the boundary has an associated GeomObject then it is not
918  // necessary to compute the arclength, only read the values from
919  // the nodes at the edges
920  if (this->boundary_geom_object_pt(b)!=0)
921  {
922  first_node_pt->get_coordinates_on_boundary(b, zeta);
923  initial_zeta_segment[is] = zeta[0];
924  last_node_pt->get_coordinates_on_boundary(b, zeta);
925  final_zeta_segment[is] = zeta[0];
926  }
927 
928  // Lexicographically bottom left node
929  std::set<Node*> local_nodes_pt;
930  local_nodes_pt.insert(first_node_pt);
931 
932  // Now loop over nodes in order
933  for (std::list<FiniteElement*>::iterator it =
934  segment_sorted_ele_pt[is].begin();
935  it != segment_sorted_ele_pt[is].end(); it++)
936  {
937  // Get element
938  FiniteElement* el_pt = *it;
939 
940  // Start node and increment
941  unsigned k_nod = 1;
942  int nod_diff = 1;
943  if (is_inverted[el_pt])
944  {
945  k_nod = nnod - 2;
946  nod_diff = -1;
947  }
948 
949  // Loop over nodes
950  for (unsigned j = 1; j < nnod; j++)
951  {
952  Node* nod_pt = el_pt->node_pt(k_nod);
953  k_nod += nod_diff;
954 
955  // Coordinates of right node
956  double x_right = nod_pt->x(0);
957  double y_right = nod_pt->x(1);
958 
959  // Increment boundary coordinate (the arclength)
960  zeta[0] += sqrt(
961  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
962  * (y_right - y_left));
963 
964  // // When we have a GeomObject associated to the boundary we already
965  // // know the zeta values for the nodes, there is no need to compute
966  // // the arclength
967  // if (this->boundary_geom_object_pt(b)==0)
968  // {
969  // // Set boundary coordinate
970  // nod_pt->set_coordinates_on_boundary(b, zeta);
971  // }
972 
973  // Increment reference coordinate
974  x_left = x_right;
975  y_left = y_right;
976 
977  // Get lexicographically bottom left node but only
978  // use vertex nodes as candidates
979  local_nodes_pt.insert(nod_pt);
980  } // for (j < nnod)
981 
982  } // iterator over the elements in the segment
983 
984  // Store the arclength of the segment
985  segment_arclength[is] = zeta[0];
986 
987  // Store the number of vertices in the segment
988  nvertices_per_segment[is] = local_nodes_pt.size();
989 
990  // Add the nodes for the corresponding segment in the container
991  segment_all_nodes_pt.push_back(local_nodes_pt);
992 
993  } // for (is < nsegments)
994 
995  // Get the number of sets for nodes
996 #ifdef PARANOID
997  if (segment_all_nodes_pt.size() != nsegments)
998  {
999  std::ostringstream error_message;
1000  error_message
1001  <<"The number of segments ("<<nsegments<<") and the number of "
1002  <<"sets of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
1003  <<"the\nsegments is different!!!\n\n";
1004  throw OomphLibError(
1005  error_message.str(),
1006  OOMPH_CURRENT_FUNCTION,
1007  OOMPH_EXCEPTION_LOCATION);
1008  }
1009 #endif
1010 
1011  // Store the initial arclength for each segment of boundary in the
1012  // current processor, initalise to zero in case we have a non
1013  // distributed boundary
1014  Vector<double> initial_segment_arclength(nsegments,0.0);
1015 
1016  // Associated the index of the current segment to the segment index
1017  // in the original mesh (input mesh)
1018  Vector<unsigned> current_segment_to_original_segment_index(nsegments);
1019 
1020  // Each segment needs to know whether it has to be inverted or not
1021  // Store whether a segment needs to be inverted or not
1022  Vector<unsigned> segment_inverted(nsegments);
1023 
1024  // -----------------------------------------------------------------
1025  // Fourth: Identify the segments with the ones in the original mesh
1026  // (has sense only in the adaptation process)
1027  // -----------------------------------------------------------------
1028 
1029  // Now check if there are segments associated to this boundary
1030  if (nsegments > 0)
1031  {
1032 #ifdef PARANOID
1033  // Double check that the same number of coordinates (nsegments)
1034  // have been established for the boundary
1035  const unsigned nsegments_initial_coordinates =
1036  original_mesh_pt->boundary_segment_initial_coordinate(b).size();
1037 
1038  const unsigned nsegments_final_coordinates =
1039  original_mesh_pt->boundary_segment_final_coordinate(b).size();
1040 
1041  if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1042  {
1043  std::stringstream error_message;
1044  error_message
1045  <<"The number of segments that present initial coordinates "
1046  <<nsegments_initial_coordinates<<" is different from "
1047  <<"the\nnumber of segments that present final coordinates "
1048  <<nsegments_final_coordinates<<"\n\n";
1049  throw OomphLibError(
1050  error_message.str(),
1051  OOMPH_CURRENT_FUNCTION,
1052  OOMPH_EXCEPTION_LOCATION);
1053  } // if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1054 
1055  // Also check that the number of segments found in the previous
1056  // mesh is the same as the number of segments found in this mesh
1057  if (nsegments_initial_coordinates != nsegments)
1058  {
1059  std::stringstream error_message;
1060  error_message
1061  <<"Working with boundary ("<< b << ").\n The number of initial and "
1062  <<"final coordinates ("
1063  <<nsegments_initial_coordinates<<") is different from\n"
1064  <<"the number of found segments ("<< nsegments <<").\n\n";
1065  throw OomphLibError(
1066  error_message.str(),
1067  OOMPH_CURRENT_FUNCTION,
1068  OOMPH_EXCEPTION_LOCATION);
1069  } // if (nsegments_initial_coordinates != nsegments)
1070 #endif
1071 
1072  // Create a backup for the data from the original mesh
1073  // Backup for the coordinates
1074  Vector<Vector<double> >original_mesh_segment_initial_coordinate(nsegments);
1075  Vector<Vector<double> >original_mesh_segment_final_coordinate(nsegments);
1076  // Backup for the zeta values
1077  Vector<double> original_mesh_segment_initial_zeta(nsegments);
1078  Vector<double> original_mesh_segment_final_zeta(nsegments);
1079  // Backup for the arclengths
1080  Vector<double> original_mesh_segment_initial_arclength(nsegments);
1081  Vector<double> original_mesh_segment_final_arclength(nsegments);
1082  // Do the backup
1083  for (unsigned is = 0; is < nsegments; is++)
1084  {
1085  original_mesh_segment_initial_coordinate[is].resize(2);
1086  original_mesh_segment_final_coordinate[is].resize(2);
1087  for (unsigned k = 0; k < 2; k++)
1088  {
1089  original_mesh_segment_initial_coordinate[is][k] =
1090  original_mesh_pt->boundary_segment_initial_coordinate(b)[is][k];
1091  original_mesh_segment_final_coordinate[is][k] =
1092  original_mesh_pt->boundary_segment_final_coordinate(b)[is][k];
1093  }
1094  // Check if the boudary has an associated GeomObject
1095  if (this->boundary_geom_object_pt(b)!=0)
1096  {
1097  original_mesh_segment_initial_zeta[is] =
1098  original_mesh_pt->boundary_segment_initial_zeta(b)[is];
1099  original_mesh_segment_final_zeta[is] =
1100  original_mesh_pt->boundary_segment_final_zeta(b)[is];
1101  }
1102  else
1103  {
1104  original_mesh_segment_initial_arclength[is] =
1105  original_mesh_pt->boundary_segment_initial_arclength(b)[is];
1106  original_mesh_segment_final_arclength[is] =
1107  original_mesh_pt->boundary_segment_final_arclength(b)[is];
1108  }
1109  } // for (is < nsegments)
1110 
1111  // Clear all the storage
1112  Boundary_segment_inverted[b].clear();
1113  Boundary_segment_initial_coordinate[b].clear();
1114  Boundary_segment_final_coordinate[b].clear();
1115 
1116  Boundary_segment_initial_zeta[b].clear();
1117  Boundary_segment_final_zeta[b].clear();
1118 
1119  Boundary_segment_initial_arclength[b].clear();
1120  Boundary_segment_final_arclength[b].clear();
1121 
1122  // Identify each segment in the processor with the ones created
1123  // by the original mesh
1124  // -----------------------------------------------------------------
1125  // Keep track of the already identified segments
1126  std::map<unsigned,bool> segment_done;
1127  for (unsigned is = 0; is < nsegments; is++)
1128  {
1129 #ifdef PARANOID
1130  // Flag to know if the segment was identified
1131  bool found_original_segment = false;
1132 #endif
1133 
1134  // Get the initial and final coordinates of the current segment
1135  Vector<double> current_seg_initial_coord(2);
1136  Vector<double> current_seg_final_coord(2);
1137 
1138  // Get access to the initial element on the segment
1139  FiniteElement* current_seg_initial_ele_pt =
1140  segment_sorted_ele_pt[is].front();
1141 
1142  // Number of nodes
1143  const unsigned nnod = current_seg_initial_ele_pt->nnode();
1144 
1145  // Get the first node of the current segment
1146  Node *current_seg_first_node_pt=
1147  current_seg_initial_ele_pt->node_pt(0);
1148  if (is_inverted[current_seg_initial_ele_pt])
1149  {
1150  current_seg_first_node_pt =
1151  current_seg_initial_ele_pt->node_pt(nnod-1);
1152  }
1153 
1154  // Get access to the last element on the segment
1155  FiniteElement* current_seg_last_ele_pt =
1156  segment_sorted_ele_pt[is].back();
1157 
1158  // Get the last node of the current segment
1159  Node *current_seg_last_node_pt =
1160  current_seg_last_ele_pt->node_pt(nnod-1);
1161  if (is_inverted[current_seg_last_ele_pt])
1162  {
1163  current_seg_last_node_pt =
1164  current_seg_last_ele_pt->node_pt(0);
1165  }
1166 
1167  // Get the coordinates for the first and last seg node
1168  for (unsigned i = 0; i < 2; i++)
1169  {
1170  current_seg_initial_coord[i]=current_seg_first_node_pt->x(i);
1171  current_seg_final_coord[i]=current_seg_last_node_pt->x(i);
1172  }
1173 
1174  // We have got the initial and final coordinates of the current
1175  // segment, compare those with the initial and final coordinates
1176  // of the original mesh segments to identify which segments is
1177  // which
1178  for (unsigned orig_s = 0; orig_s < nsegments; orig_s++)
1179  {
1180  if (!segment_done[orig_s])
1181  {
1182  // Get the coordinates to compare
1183  Vector<double> initial_coordinate =
1184  original_mesh_segment_initial_coordinate[orig_s];
1185  Vector<double> final_coordinate =
1186  original_mesh_segment_final_coordinate[orig_s];
1187 
1188  // Compute the distance initial(current)-initial(original)
1189  // coordinates
1190  double dist =
1191  ((current_seg_initial_coord[0] - initial_coordinate[0])*
1192  (current_seg_initial_coord[0] - initial_coordinate[0]))
1193  +
1194  ((current_seg_initial_coord[1] - initial_coordinate[1])*
1195  (current_seg_initial_coord[1] - initial_coordinate[1]));
1196  dist = sqrt(dist);
1197 
1198  // If the initial node is the same, check for the last node
1199  if (dist <
1201  {
1202  // Compute the distance final(current)-final(original)
1203  // coordinates
1204  dist =
1205  ((current_seg_final_coord[0] - final_coordinate[0])*
1206  (current_seg_final_coord[0] - final_coordinate[0]))
1207  +
1208  ((current_seg_final_coord[1] - final_coordinate[1])*
1209  (current_seg_final_coord[1] - final_coordinate[1]));
1210  dist = sqrt(dist);
1211 
1212  // The final node is the same, we have identified the
1213  // segments
1214  if (dist <
1216  {
1217  // Store the index that relates the previous index with the
1218  // current one
1219  current_segment_to_original_segment_index[is] = orig_s;
1220 
1221  // In this case the segment is not inverted
1222  Boundary_segment_inverted[b].push_back(0);
1223 
1224  // Copy the initial and final coordinates for each segment
1225  Boundary_segment_initial_coordinate[b].push_back(
1226  initial_coordinate);
1227  Boundary_segment_final_coordinate[b].push_back(
1228  final_coordinate);
1229 
1230  // Check if the boundary has an associated GeomObject
1231  if (this->boundary_geom_object_pt(b)!=0)
1232  {
1233  // Copy the initial zeta value for the segment
1234  Boundary_segment_initial_zeta[b].push_back(
1235  original_mesh_segment_initial_zeta[orig_s]);
1236  Boundary_segment_final_zeta[b].push_back(
1237  original_mesh_segment_final_zeta[orig_s]);
1238  }
1239  else
1240  {
1241  // Copy the initial and final arclength for each
1242  // segment
1243  Boundary_segment_initial_arclength[b].push_back(
1244  original_mesh_segment_initial_arclength[orig_s]);
1245  Boundary_segment_final_arclength[b].push_back(
1246  original_mesh_segment_final_arclength[orig_s]);
1247  }
1248  // Mark the segment as done
1249  segment_done[orig_s] = true;
1250 #ifdef PARANOID
1251  found_original_segment = true;
1252 #endif
1253  break;
1254  } // The final(current) node matched with the
1255  // final(original) node
1256  } // The initial(current) node matched with the
1257  // initial(original) node
1258  else
1259  {
1260  // Check the inverted case Compute the distance
1261  // initial(current)-final(original) coordinates
1262  double dist_inv =
1263  ((current_seg_initial_coord[0] - final_coordinate[0])*
1264  (current_seg_initial_coord[0] - final_coordinate[0]))
1265  +
1266  ((current_seg_initial_coord[1] - final_coordinate[1])*
1267  (current_seg_initial_coord[1] - final_coordinate[1]));
1268  dist_inv = sqrt(dist_inv);
1269 
1270  // If the initial node is the same as the final node of
1271  // the segment, check for the last node
1272  if (dist_inv <
1274  {
1275  // Compute the distance final(current)-initial(original)
1276  // coordinates
1277  dist_inv =
1278  ((current_seg_final_coord[0] - initial_coordinate[0])*
1279  (current_seg_final_coord[0] - initial_coordinate[0]))
1280  +
1281  ((current_seg_final_coord[1] - initial_coordinate[1])*
1282  (current_seg_final_coord[1] - initial_coordinate[1]));
1283  dist_inv = sqrt(dist_inv);
1284 
1285  // The final node is the same as the initial node, we
1286  // have identified the segments
1287  if (dist_inv <
1289  {
1290  // Store the index that related the previous index with the
1291  // current one
1292  current_segment_to_original_segment_index[is] = orig_s;
1293 
1294  // In this case the segment is inverted
1295  Boundary_segment_inverted[b].push_back(1);
1296 
1297  // Copy the initial and final coordinates for each segment
1298  Boundary_segment_initial_coordinate[b].push_back(
1299  initial_coordinate);
1300  Boundary_segment_final_coordinate[b].push_back(
1301  final_coordinate);
1302 
1303  // Check that the boudary has an associated GeomObject
1304  if (this->boundary_geom_object_pt(b)!=0)
1305  {
1306  // Copy the initial zeta value for the segments
1307  Boundary_segment_initial_zeta[b].push_back(
1308  original_mesh_segment_initial_zeta[orig_s]);
1309  Boundary_segment_final_zeta[b].push_back(
1310  original_mesh_segment_final_zeta[orig_s]);
1311  }
1312  else
1313  {
1314  // Copy the initial and final arclength for each segment
1315  Boundary_segment_initial_arclength[b].push_back(
1316  original_mesh_segment_initial_arclength[orig_s]);
1317  Boundary_segment_final_arclength[b].push_back(
1318  original_mesh_segment_final_arclength[orig_s]);
1319  }
1320  // Mark the segment as done
1321  segment_done[orig_s] = true;
1322 #ifdef PARANOID
1323  found_original_segment = true;
1324 #endif
1325  break;
1326  } // The final(current) node matched with the
1327  // initial(original) node
1328  } // The initial(current) node matched with the
1329  // final(original) node
1330  } // else (the first(current) node did not matched with the
1331  // first(original) node. Else do the inverted case
1332 
1333  } // (!segment_done[orig_s])
1334 
1335  } // (orig_s < nsegments)
1336 
1337 #ifdef PARANOID
1338  if (!found_original_segment)
1339  {
1340  std::stringstream error_message;
1341  error_message
1342  <<"The ("<<is<<")-th segment on the current segment was not\n"
1343  << "found when trying to identify it with the original mesh's\n"
1344  << "segment coordinates\n";
1345  throw OomphLibError(error_message.str(),
1346  OOMPH_CURRENT_FUNCTION,
1347  OOMPH_EXCEPTION_LOCATION);
1348  } // if (!found_original_segment)
1349 #endif
1350  } // for (is < nsegments)
1351 
1352  } // if (nsegments > 0)
1353 
1354  // -------------------------------------------------------------------
1355  // Fourth: The original mesh is different from the current mesh
1356  // (this). For boundaries with no geom object associated check if it
1357  // is required to reverse the zeta values. In order to reverse the
1358  // zeta values it is required to previously compute the arclength of
1359  // the segments and store the nodes in a container (set). NOTE that
1360  // the setup_boundary_coordinate() method is not called for
1361  // boundaries with NO GeomObject associated, so this is the LAST
1362  // CHANCE to do it
1363  // -------------------------------------------------------------------
1364  // The original mesh is the same as the current mesh (this). The
1365  // setup_boundary_method() will be called only for the boundaries
1366  // with NO GeomObject associated
1367  // -------------------------------------------------------------------
1368  if (this != original_mesh_pt)
1369  {
1370  // Get the boundary arclength
1371 
1372  // Get the initial and final zeta values for the boundary
1373  // (arclength) from the original mesh
1374  Vector<double> first_node_zeta_coordinate =
1375  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1376  Vector<double> last_node_zeta_coordinate =
1377  original_mesh_pt->boundary_final_zeta_coordinate(b);
1378 
1379  // The boundary arclength is the maximum of the initial and final
1380  // zeta coordinate
1381  const double boundary_arclength =
1382  std::max(first_node_zeta_coordinate[0],
1383  last_node_zeta_coordinate[0]);
1384 
1385  for (unsigned is = 0; is < nsegments; is++)
1386  {
1387  // Here check if need to invert the elements and the boundary
1388  // coordinates for the segments in a boundary with no GeomObject
1389  // associated
1390  if (boundary_geom_object_pt(b)==0)
1391  {
1392  // This case only applies for the initial and iterative mesh in
1393  // the adaptation process because the method
1394  // setup_boundary_coordinates() is called by the original mesh
1395  // for boundaries with no GeomObject associated
1396 
1397  // We are goind to check if it is necessary to invert the order
1398  // of the zeta values
1399 
1400  // Get the first and last node of the current segment and their
1401  // zeta values (arclength)
1402 
1403  // There is no need to check for nonhalo elements since the
1404  // container has only nonhalo face elements
1405 
1406  // Get access to the first element on the segment
1407  FiniteElement* first_ele_pt=segment_sorted_ele_pt[is].front();
1408 
1409  // Number of nodes
1410  const unsigned nnod = first_ele_pt->nnode();
1411 
1412  // Get the first node of the current segment
1413  Node *first_node_pt = first_ele_pt->node_pt(0);
1414  if (is_inverted[first_ele_pt])
1415  {
1416  first_node_pt = first_ele_pt->node_pt(nnod-1);
1417  }
1418 
1419  // Get access to the last element on the segment
1420  FiniteElement* last_ele_pt=segment_sorted_ele_pt[is].back();
1421 
1422  // Get the last node of the current segment
1423  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
1424  if (is_inverted[last_ele_pt])
1425  {
1426  last_node_pt = last_ele_pt->node_pt(0);
1427  }
1428 
1429  // Get the zeta coordinates for the first and last node
1430  Vector<double> current_segment_initial_arclen(1);
1431  Vector<double> current_segment_final_arclen(1);
1432  // Is the segment in the current mesh (this) inverted?
1433  if (!Boundary_segment_inverted[b][is]) // Not inverted
1434  {
1435  first_node_pt->
1436  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1437  last_node_pt->
1438  get_coordinates_on_boundary(b, current_segment_final_arclen);
1439  }
1440  else // Inverted
1441  {
1442  first_node_pt->
1443  get_coordinates_on_boundary(b, current_segment_final_arclen);
1444  last_node_pt->
1445  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1446  }
1447 
1448  // Once the zeta values have been obtained check if they are set
1449  // in increasing or decreasing order
1450 
1451  // Flag to state that the values in the segment are in increasing
1452  // order
1453  bool increasing_order = false;
1454 
1455  // If the initial zeta value is smaller than the final zeta
1456  // value then they are in increasing order
1457  if (current_segment_initial_arclen[0] <
1458  current_segment_final_arclen[0])
1459  {
1460  increasing_order = true;
1461  }
1462  // If the initial zeta value is greater than the initial zeta
1463  // value then they are in decreasing order
1464  else if (current_segment_initial_arclen[0] >
1465  current_segment_final_arclen[0])
1466  {
1467  increasing_order = false;
1468  }
1469 #ifdef PARANOID
1470  else
1471  {
1472  std::stringstream error_message;
1473  error_message
1474  << "It was not possible to identify if the zeta values on "
1475  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1476  << "increasing or decreasing order.\n--- New mesh ---\n"
1477  << "Current segment initial arclength: ("
1478  << current_segment_initial_arclen[0]<<")\n"
1479  << "First node coordinates: ("
1480  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n"
1481  << "Current segment final arclength: ("
1482  << current_segment_final_arclen[0]<<")\n"
1483  << "Last node coordinates: ("
1484  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n"
1485  << "Current segment arclength: ("
1486  << segment_arclength[is] <<")\n";
1487  throw OomphLibError(error_message.str(),
1488  OOMPH_CURRENT_FUNCTION,
1489  OOMPH_EXCEPTION_LOCATION);
1490  }
1491 #endif
1492 
1493  // Now get the original initial and final arclengths and check
1494  // if they are in increasing or decreasing order
1495  const unsigned prev_s =
1496  current_segment_to_original_segment_index[is];
1497  const double original_segment_initial_arclength =
1498  original_mesh_pt->boundary_segment_initial_arclength(b)[prev_s];
1499  const double original_segment_final_arclength =
1500  original_mesh_pt->boundary_segment_final_arclength(b)[prev_s];
1501 
1502  // Flag to check if the values go in increasing or decreasing
1503  // order in the original mesh segment
1504  bool original_increasing_order = false;
1505 
1506  // Now check if the arclengths on the original mesh go in
1507  // increase or decrease order, this is also used to choose the
1508  // starting value to map the values in the current segment
1509  double starting_arclength = 0.0;
1510  if (original_segment_final_arclength >
1511  original_segment_initial_arclength)
1512  {
1513  // ... in increasing order in the original mesh ...
1514  original_increasing_order = true;
1515  // Select the starting arclength
1516  starting_arclength = original_segment_initial_arclength;
1517  }
1518  else if (original_segment_final_arclength <
1519  original_segment_initial_arclength)
1520  {
1521  // ... in decreasing order in the original mesh ...
1522  original_increasing_order = false;
1523  // Select the starting arclength
1524  starting_arclength = original_segment_final_arclength;
1525  }
1526 #ifdef PARANOID
1527  else
1528  {
1529  std::stringstream error_message;
1530  error_message
1531  << "It was not possible to identify if the zeta values on "
1532  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1533  << "increasing or decreasing order.\n--- Original mesh ---\n"
1534  << "Original segment initial arclength: ("
1535  << original_segment_initial_arclength<<")\n"
1536  << "Original segment final arclength: ("
1537  << original_segment_final_arclength<<")\n";
1538  throw OomphLibError(error_message.str(),
1539  OOMPH_CURRENT_FUNCTION,
1540  OOMPH_EXCEPTION_LOCATION);
1541  }
1542 #endif
1543 
1544  // Now scale the zeta values based considering if the zeta
1545  // values from the current mesh (this) go in the same order as
1546  // in the original mesh
1547  if (increasing_order && original_increasing_order)
1548  {
1549  // Current seg
1550  // |------|
1551  // 0 ---- 1
1552  //
1553  // Is mapped to the new values
1554  // |------|
1555  // a ---- b
1556  // a = original_segment_initial_arclength
1557  // b = original_segment_final_arclength
1558  // s = starting_arclength
1559  // The mapping is given by
1560  // new_z = s + z_old * (b - a)
1561 
1562  // Get the nodes associated to the segment
1563  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1564  // Go through all the nodes in the segment an change their
1565  // zeta values
1566  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1567  it != seg_nodes_pt.end(); it++)
1568  {
1569  // Storing for the zeta value
1570  Vector<double> zeta(1);
1571  // Get each node
1572  Node* nod_pt = (*it);
1573  // Get the zeta value of the current node
1574  nod_pt->get_coordinates_on_boundary(b, zeta);
1575  // ... and re-assign it
1576  const double temp =
1577  starting_arclength + (zeta[0] * segment_arclength[is]);
1578  // The zeta value
1579  zeta[0] = temp / boundary_arclength;
1580  // Correct
1581  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1582  {
1583  zeta[0] = 1.0;
1584  }
1585  else if (std::fabs(zeta[0]) < 1.0e-14)
1586  {
1587  zeta[0] = 0.0;
1588  }
1589 
1590  // Set the new value
1591  nod_pt->set_coordinates_on_boundary(b, zeta);
1592  } // Go through all the nodes
1593  } // if (increasing_order && original_increasing_order)
1594  else if (!increasing_order && original_increasing_order)
1595  {
1596  // Current seg
1597  // |------|
1598  // 1 ---- 0
1599  //
1600  // Is mapped to the new values
1601  // |------|
1602  // a ---- b
1603  // a = original_segment_initial_arclength
1604  // b = original_segment_final_arclength
1605  // s = starting_arclength
1606  // The mapping is given by
1607  // new_z = s + (1.0 - z_old) * (b - a)
1608 
1609  // Get the nodes associated to the segment
1610  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1611  // Go through all the nodes in the segment an change their
1612  // zeta values
1613  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1614  it != seg_nodes_pt.end(); it++)
1615  {
1616  // Storing for the zeta value
1617  Vector<double> zeta(1);
1618  // Get each node
1619  Node* nod_pt = (*it);
1620  // Get the zeta value of the current node
1621  nod_pt->get_coordinates_on_boundary(b, zeta);
1622  // ... and re-assign it
1623  const double temp =
1624  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1625  // The zeta value
1626  zeta[0] = temp / boundary_arclength;
1627  // Correct
1628  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1629  {
1630  zeta[0] = 1.0;
1631  }
1632  else if (std::fabs(zeta[0]) < 1.0e-14)
1633  {
1634  zeta[0] = 0.0;
1635  }
1636  // Set the new value
1637  nod_pt->set_coordinates_on_boundary(b, zeta);
1638  } // Go through all the nodes
1639  } // else if (!increasing_order && original_increasing_order)
1640  else if (increasing_order && !original_increasing_order)
1641  {
1642  // Current seg
1643  // |------|
1644  // 0 ---- 1
1645  //
1646  // Is mapped to the new values
1647  // |------|
1648  // b ---- a
1649  // a = original_segment_initial_arclength
1650  // b = original_segment_final_arclength
1651  // s = starting_arclength
1652  // The mapping is given by
1653  // new_z = s + (1.0 - z_old) * |(b - a)|
1654 
1655  // Get the nodes associated to the segment
1656  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1657  // Go through all the nodes in the segment an change their
1658  // zeta values
1659  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1660  it != seg_nodes_pt.end(); it++)
1661  {
1662  // Storing for the zeta value
1663  Vector<double> zeta(1);
1664  // Get each node
1665  Node* nod_pt = (*it);
1666  // Get the zeta value of the current node
1667  nod_pt->get_coordinates_on_boundary(b, zeta);
1668  // ... and re-assign it
1669  const double temp =
1670  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1671  // The zeta value
1672  zeta[0] = temp / boundary_arclength;
1673  // Correct
1674  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1675  {
1676  zeta[0] = 1.0;
1677  }
1678  else if (std::fabs(zeta[0]) < 1.0e-14)
1679  {
1680  zeta[0] = 0.0;
1681  }
1682  // Set the new value
1683  nod_pt->set_coordinates_on_boundary(b, zeta);
1684  } // Go through all the nodes
1685  } // else if (increasing_order && !original_increasing_order)
1686  else if (!increasing_order && !original_increasing_order)
1687  {
1688  // Current seg
1689  // |------|
1690  // 0 ---- 1
1691  //
1692  // Is mapped to the new values
1693  // |------|
1694  // a ---- b
1695  // a = original_segment_initial_arclength
1696  // b = original_segment_final_arclength
1697  // s = starting_arclength
1698  // The mapping is given by
1699  // new_z = s + z_old * |(b - a)|
1700 
1701  // Get the nodes associated to the segment
1702  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1703  // Go through all the nodes in the segment an change their
1704  // zeta values
1705  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1706  it != seg_nodes_pt.end(); it++)
1707  {
1708  // Storing for the zeta value
1709  Vector<double> zeta(1);
1710  // Get each node
1711  Node* nod_pt = (*it);
1712  // Get the zeta value of the current node
1713  nod_pt->get_coordinates_on_boundary(b, zeta);
1714  // ... and re-assign it
1715  const double temp =
1716  starting_arclength + (zeta[0] * segment_arclength[is]);
1717  // The zeta value
1718  zeta[0] = temp / boundary_arclength;
1719  // Correct
1720  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1721  {
1722  zeta[0] = 1.0;
1723  }
1724  else if (std::fabs(zeta[0]) < 1.0e-14)
1725  {
1726  zeta[0] = 0.0;
1727  }
1728  // Set the new value
1729  nod_pt->set_coordinates_on_boundary(b, zeta);
1730  } // Go through all the nodes
1731  } // else if (!increasing_order && !original_increasing_order)
1732 
1733 #ifdef PARANOID
1734  // Verify that the z values of the first and last node are not
1735  // out of the range [0,1]
1736  for (std::list<FiniteElement*>::iterator it_list =
1737  segment_sorted_ele_pt[is].begin();
1738  it_list != segment_sorted_ele_pt[is].end();
1739  it_list++)
1740  {
1741  // Number of nodes in the segment
1742  const unsigned nnod = (*it_list)->nnode();
1743 
1744  // Get the first node of the current segment
1745  Node *first_node_pt = (*it_list)->node_pt(0);
1746  if(is_inverted[(*it_list)])
1747  {
1748  first_node_pt = (*it_list)->node_pt(nnod-1);
1749  }
1750 
1751  // Get the last node of the current segment
1752  Node *last_node_pt = (*it_list)->node_pt(nnod-1);
1753  if(is_inverted[(*it_list)])
1754  {
1755  last_node_pt = (*it_list)->node_pt(0);
1756  }
1757 
1758  // The z value for the first node
1759  Vector<double> zeta(1);
1760  first_node_pt->get_coordinates_on_boundary(b, zeta);
1761  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1762  {
1763  std::ostringstream error_message;
1764  error_message
1765  <<"The boundary coordinate of the first node on boundary ("
1766  << b << ")\nand segment (" << is << ") is out of the "
1767  << "allowed values [0,1]\n"
1768  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1769  << "The vertex coordinates are: ("
1770  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n";
1771  throw OomphLibError(error_message.str(),
1772  OOMPH_CURRENT_FUNCTION,
1773  OOMPH_EXCEPTION_LOCATION);
1774  }
1775 
1776  // The z value for the last node
1777  last_node_pt->get_coordinates_on_boundary(b, zeta);
1778  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1779  {
1780  std::ostringstream error_message;
1781  error_message
1782  <<"The boundary coordinate of the last node on boundary ("
1783  << b << ")\nand segment (" << is << ") is out of the "
1784  << "allowed values [0,1]\n"
1785  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1786  << "The vertex coordinates are: ("
1787  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n";
1788  throw OomphLibError(error_message.str(),
1789  OOMPH_CURRENT_FUNCTION,
1790  OOMPH_EXCEPTION_LOCATION);
1791  }
1792  }
1793 #endif // #ifdef PARANOID
1794 
1795  } // if (boundary_geom_object_pt(b)==0)
1796 
1797  } // for (is < nsegments)
1798 
1799  } // if (this != original_mesh_pt)
1800 
1801  // ------------------------------------------------------------------
1802  // Copy the corrected (possible reversed) info. to the containers of
1803  // the current mesh
1804  // ------------------------------------------------------------------
1805  // Check if there are segments of b boundary in this processor
1806  if (nsegments > 0)
1807  {
1808  // Copy the initial and final coordinates
1809  Boundary_initial_coordinate[b] =
1810  original_mesh_pt->boundary_initial_coordinate(b);
1811 
1812  Boundary_final_coordinate[b] =
1813  original_mesh_pt->boundary_final_coordinate(b);
1814 
1815  // The initial and final zeta coordinates (In case of a geometric
1816  // object those are the limits of the geom object)
1817  Boundary_initial_zeta_coordinate[b] =
1818  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1819 
1820  Boundary_final_zeta_coordinate[b] =
1821  original_mesh_pt->boundary_final_zeta_coordinate(b);
1822 
1823  } // if (nsegments > 0)
1824 
1825  // Set the flag to indicate that the zeta values have been assigned
1826  // for the current boundary
1827  Assigned_segments_initial_zeta_values[b] = true;
1828 
1829  // Clean all the created face elements
1830  for (unsigned i = 0; i < nele; i++)
1831  {
1832  delete face_el_pt[i];
1833  face_el_pt[i] = 0;
1834  }
1835 
1836  }
1837 
1838  //======================================================================
1839  /// \short Compute the boundary segments connectivity for those
1840  /// boundaries that were splited during the distribution process
1841  /// and also the initial zeta values for each segment (the initial
1842  /// and final boundary nodes coordinates)
1843  //======================================================================
1844  template<class ELEMENT>
1847  const unsigned& b)
1848  {
1849  // ------------------------------------------------------------------
1850  // First: Get the face elements associated with the current boundary
1851  // ------------------------------------------------------------------
1852 
1853  // Get the communicator of the mesh
1854  OomphCommunicator* comm_pt = this->communicator_pt();
1855 
1856  // Get the number of processors
1857  const unsigned nproc = comm_pt->nproc();
1858  // Get the rank of the current processor
1859  const unsigned my_rank = comm_pt->my_rank();
1860 
1861  // Temporary storage for face elements
1862  Vector<FiniteElement*> all_face_ele_pt;
1863 
1864  // Flag to know whether we are working with an internal open curve
1865  // and then re-assign the initial and final zeta coordinates for
1866  // each segment (only used when the mesh is distributed)
1867  bool is_internal_boundary = false;
1868 
1869  // map to associate the face element to the bulk element, necessary
1870  // to attach halo face elements at both sides of each found segment
1871  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
1872 
1873  // Select the boundary face elements, using the criteria of highest
1874  // processor in charge and bottom-left element
1875  select_boundary_face_elements(all_face_ele_pt, b, is_internal_boundary,
1876  face_to_bulk_element_pt);
1877 
1878  // Get the number of face elements
1879  const unsigned n_all_face_ele = all_face_ele_pt.size();
1880 
1881  // ----------------------------------------------------------------
1882  // Second: Sort the face elements, only consider nonhalo elements
1883  // ----------------------------------------------------------------
1884 
1885  // A flag vector to mark those face elements that are considered as
1886  // halo in the current processor
1887  std::vector<bool> is_halo_face_element(n_all_face_ele, false);
1888 
1889  // Count the total number of non halo face elements
1890  unsigned nnon_halo_face_elements = 0;
1891 
1892  // Only mark the face elements as halo if the mesh is marked as
1893  // distributed
1894  for (unsigned ie = 0; ie < n_all_face_ele; ie++)
1895  {
1896  FiniteElement* face_ele_pt = all_face_ele_pt[ie];
1897  // Get the bulk element
1898  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
1899  // Check if the bulk element is halo
1900  if (!tmp_bulk_ele_pt->is_halo())
1901  {
1902  // Set the flag for non halo element
1903  is_halo_face_element[ie] = false;
1904  // Increase the non halo elements counter
1905  nnon_halo_face_elements++;
1906  }
1907  else
1908  {
1909  // Mark the face element as halo
1910  is_halo_face_element[ie] = true;
1911  }
1912 
1913  } // for (ie < n_ele)
1914 
1915  // Get the total number of halo face elements
1916  const unsigned nhalo_face_element = n_all_face_ele - nnon_halo_face_elements;
1917 
1918  // The vector of list to store the "segments" that compound the
1919  // boundary (segments may appear only in a distributed mesh)
1920  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
1921 
1922  // Number of already sorted face elements (only nonhalo elements for
1923  // a distributed mesh)
1924  unsigned nsorted_face_elements = 0;
1925 
1926  // Keep track of who's done (this apply to nonhalo only, remember we
1927  // are only working with halo elements)
1928  std::map<FiniteElement*, bool> done_el;
1929 
1930  // Keep track of which element is inverted (in distributed mesh the
1931  // elements may be inverted with respect to the segment they belong)
1932  std::map<FiniteElement*, bool> is_inverted;
1933 
1934  // Iterate until all possible segments have been created
1935  while(nsorted_face_elements < nnon_halo_face_elements)
1936  {
1937  // The ordered list of face elements (in a distributed mesh a
1938  // collection of contiguous face elements define a segment)
1939  std::list<FiniteElement*> sorted_el_pt;
1940  sorted_el_pt.clear();
1941 
1942 #ifdef PARANOID
1943  // Select an initial element for the segment (the first not done
1944  // nonhalo element)
1945  bool found_initial_face_element = false;
1946 #endif
1947 
1948  FiniteElement* ele_face_pt = 0;
1949 
1950  unsigned iface = 0;
1951  for (iface = 0; iface < n_all_face_ele; iface++)
1952  {
1953  if (!is_halo_face_element[iface])
1954  {
1955  ele_face_pt = all_face_ele_pt[iface];
1956  // If not done then take it as initial face element
1957  if (!done_el[ele_face_pt])
1958  {
1959 #ifdef PARANOID
1960  found_initial_face_element = true;
1961 #endif
1962  nsorted_face_elements++;
1963  iface++; // The next element number
1964  sorted_el_pt.push_back(ele_face_pt);
1965  // Mark as done
1966  done_el[ele_face_pt] = true;
1967  break;
1968  }
1969  }
1970  } // for (iface < nele)
1971 
1972 #ifdef PARANOID
1973  if (!found_initial_face_element)
1974  {
1975  std::ostringstream error_message;
1976  error_message
1977  <<"Could not find an initial face element for the current segment\n";
1978  // << "----- Possible memory leak -----\n";
1979  throw OomphLibError(error_message.str(),
1980  OOMPH_CURRENT_FUNCTION,
1981  OOMPH_EXCEPTION_LOCATION);
1982  }
1983 #endif
1984 
1985  // Number of nodes
1986  const unsigned nnod = ele_face_pt->nnode();
1987 
1988  // Left and rightmost nodes (the left and right nodes of the
1989  // current face element)
1990  Node* left_node_pt = ele_face_pt->node_pt(0);
1991  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
1992 
1993  // Continue iterating if a new face element has been added to the
1994  // list
1995  bool face_element_added = false;
1996 
1997  // While a new face element has been added to the set of sorted
1998  // face elements then re-iterate
1999  do
2000  {
2001  // Start from the next face element since we have already added
2002  // the previous one as the initial face element (any previous
2003  // face element had to be added on previous iterations)
2004  for (unsigned iiface = iface; iiface < n_all_face_ele; iiface++)
2005  {
2006  // Re-start flag
2007  face_element_added = false;
2008 
2009  // Get the candidate element
2010  ele_face_pt = all_face_ele_pt[iiface];
2011 
2012  // Check that the candidate element has not been done and is
2013  // not a halo element
2014  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2015  {
2016  // Get the left and right nodes of the current element
2017  Node* local_left_node_pt = ele_face_pt->node_pt(0);
2018  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
2019 
2020  // New element fits at the left of segment and is not inverted
2021  if (left_node_pt == local_right_node_pt)
2022  {
2023  left_node_pt = local_left_node_pt;
2024  sorted_el_pt.push_front(ele_face_pt);
2025  is_inverted[ele_face_pt] = false;
2026  face_element_added = true;
2027  }
2028  // New element fits at the left of segment and is inverted
2029  else if (left_node_pt == local_left_node_pt)
2030  {
2031  left_node_pt = local_right_node_pt;
2032  sorted_el_pt.push_front(ele_face_pt);
2033  is_inverted[ele_face_pt] = true;
2034  face_element_added = true;
2035  }
2036  // New element fits on the right of segment and is not inverted
2037  else if (right_node_pt == local_left_node_pt)
2038  {
2039  right_node_pt = local_right_node_pt;
2040  sorted_el_pt.push_back(ele_face_pt);
2041  is_inverted[ele_face_pt] = false;
2042  face_element_added = true;
2043  }
2044  // New element fits on the right of segment and is inverted
2045  else if (right_node_pt == local_right_node_pt)
2046  {
2047  right_node_pt = local_left_node_pt;
2048  sorted_el_pt.push_back(ele_face_pt);
2049  is_inverted[ele_face_pt] = true;
2050  face_element_added = true;
2051  }
2052 
2053  if (face_element_added)
2054  {
2055  done_el[ele_face_pt] = true;
2056  nsorted_face_elements++;
2057  break;
2058  }
2059 
2060  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2061  } // for (iiface<nnon_halo_face_element)
2062  }while(face_element_added &&
2063  (nsorted_face_elements < nnon_halo_face_elements));
2064 
2065  // Store the created segment in the vector of segments
2066  segment_sorted_ele_pt.push_back(sorted_el_pt);
2067 
2068  } // while(nsorted_face_elements < nnon_halo_face_elements);
2069 
2070  // -----------------------------------------------------------------
2071  // Third: We have the face elements sorted (in segments), now assign
2072  // boundary coordinates to the nodes in the segments, this is the
2073  // LOCAL boundary coordinate and further communication is needed to
2074  // compute the GLOBAL boundary coordinates
2075  // -----------------------------------------------------------------
2076 
2077  // Vector of sets that stores the nodes of each segment based on a
2078  // lexicographically order starting from the bottom left node of
2079  // each segment
2080  Vector<std::set<Node*> > segment_all_nodes_pt;
2081 
2082  // The number of segments in this processor
2083  const unsigned nsegments = segment_sorted_ele_pt.size();
2084 // DEBP(nsegments);
2085 
2086 #ifdef PARANOID
2087  if (nnon_halo_face_elements > 0 && nsegments == 0)
2088  {
2089  std::ostringstream error_message;
2090  error_message
2091  << "The number of segments is zero, but the number of nonhalo\n"
2092  << "elements is: (" << nnon_halo_face_elements << ")\n";
2093  throw OomphLibError(error_message.str(),
2094  OOMPH_CURRENT_FUNCTION,
2095  OOMPH_EXCEPTION_LOCATION);
2096  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
2097 #endif
2098 
2099  // The arclength of each segment in the current processor
2100  Vector<double> segment_arclength(nsegments);
2101 
2102  // The number of vertices of each segment
2103  Vector<unsigned> nvertices_per_segment(nsegments);
2104 
2105  // The initial zeta for the segment
2106  Vector<double> initial_zeta_segment(nsegments);
2107 
2108  // The final zeta for the segment
2109  Vector<double> final_zeta_segment(nsegments);
2110 
2111  // Go through all the segments and compute its ARCLENGTH (if the
2112  // boundary has a GeomObject associated then assign the initial and
2113  // final zeta values for the segment)
2114  for (unsigned is = 0; is < nsegments; is++)
2115  {
2116 #ifdef PARANOID
2117  if (segment_sorted_ele_pt[is].size() == 0)
2118  {
2119  std::ostringstream error_message;
2120  error_message
2121  << "The (" << is << ")-th segment has no elements\n";
2122  throw OomphLibError(error_message.str(),
2123  OOMPH_CURRENT_FUNCTION,
2124  OOMPH_EXCEPTION_LOCATION);
2125  } // if (segment_sorted_ele_pt[is].size() == 0)
2126 #endif
2127 
2128  // Get access to the first element on the segment
2129  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2130 
2131  // Number of nodes
2132  const unsigned nnod = first_ele_pt->nnode();
2133 
2134  // Get the first node of the current segment
2135  Node *first_node_pt = first_ele_pt->node_pt(0);
2136  if (is_inverted[first_ele_pt])
2137  {
2138  first_node_pt = first_ele_pt->node_pt(nnod-1);
2139  }
2140 
2141  // Coordinates of left node
2142  double x_left = first_node_pt->x(0);
2143  double y_left = first_node_pt->x(1);
2144 
2145  // Initialise boundary coordinate (local boundary coordinate for
2146  // boundaries with more than one segment)
2147  Vector<double> zeta(1, 0.0);
2148 
2149  // If we have associated a GeomObject then it is not necessary to
2150  // compute the arclength, only read the values from the nodes at
2151  // the edges and set the initial and final zeta segment values
2152  if (this->boundary_geom_object_pt(b)!=0)
2153  {
2154  // Get the initial node coordinate
2155  first_node_pt->get_coordinates_on_boundary(b, zeta);
2156  // Set the initial zeta segment value
2157  initial_zeta_segment[is] = zeta[0];
2158 
2159  // Get access to the last element on the segment
2160  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2161 
2162  // Get the last node of the current segment
2163  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2164  if (is_inverted[last_ele_pt])
2165  {
2166  last_node_pt = last_ele_pt->node_pt(0);
2167  }
2168 
2169  // Get the final node coordinate
2170  last_node_pt->get_coordinates_on_boundary(b, zeta);
2171  // Set the final zeta segment value
2172  final_zeta_segment[is] = zeta[0];
2173 
2174  }
2175 
2176  // Sort the nodes in the segment (lexicographically bottom left
2177  // node)
2178  std::set<Node*> local_nodes_pt;
2179  // Insert the first node
2180  local_nodes_pt.insert(first_node_pt);
2181 
2182  // Now loop over nodes in order and increase the ARCLENGTH
2183  for (std::list<FiniteElement*>::iterator it =
2184  segment_sorted_ele_pt[is].begin();
2185  it != segment_sorted_ele_pt[is].end(); it++)
2186  {
2187  // Get the pointer to the element
2188  FiniteElement* el_pt = (*it);
2189 
2190  // Start node and increment
2191  unsigned k_nod = 1;
2192  int nod_diff = 1;
2193  // Access nodes in reverse?
2194  if (is_inverted[el_pt])
2195  {
2196  k_nod = nnod - 2;
2197  nod_diff = -1;
2198  }
2199 
2200  // Loop over nodes in the face element
2201  for (unsigned j = 1; j < nnod; j++)
2202  {
2203  Node* nod_pt = el_pt->node_pt(k_nod);
2204  k_nod += nod_diff;
2205 
2206  // Coordinates of right node
2207  double x_right = nod_pt->x(0);
2208  double y_right = nod_pt->x(1);
2209 
2210  // Increment boundary coordinate (the arclength)
2211  zeta[0] += sqrt(
2212  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
2213  * (y_right - y_left));
2214 
2215  // When we have a GeomObject associated to the boundary we already
2216  // know the zeta values for the nodes, there is no need to compute
2217  // the arclength
2218 // if (this->boundary_geom_object_pt(b)==0)
2219 // {
2220 // // Set boundary coordinate
2221 // // nod_pt->set_coordinates_on_boundary(b, zeta);
2222 // }
2223 
2224  // Increment reference coordinate
2225  x_left = x_right;
2226  y_left = y_right;
2227 
2228  // Get lexicographically bottom left node but only
2229  // use vertex nodes as candidates
2230  local_nodes_pt.insert(nod_pt);
2231 
2232  } // for (j < nnod)
2233 
2234  } // iterator over the elements in the segment
2235 
2236  // Info. to be passed to other processors
2237  // The initial arclength for the segment that goes after this depends
2238  // on the current segment arclength
2239  segment_arclength[is] = zeta[0];
2240 
2241  // Info. to be passed to the other processors
2242  // The initial vertex number for the segment that goes after this
2243  // depends on the current segment vertices number
2244  nvertices_per_segment[is] = local_nodes_pt.size();
2245 
2246  // Add the nodes for the corresponding segment in the container
2247  segment_all_nodes_pt.push_back(local_nodes_pt);
2248 
2249  // The attaching of the halo elements at both sides of the segments is
2250  // performed only if segments connectivity needs to be computed
2251 
2252  } // for (is < nsegments)
2253 
2254  // Container to store the number of vertices before each segment,
2255  // initialise to zero in case we have a non distributed boundary
2256  Vector<unsigned> nvertices_before_segment(nsegments,0);
2257 
2258  // Store the initial arclength for each segment of boundary in the
2259  // current processor, initalise to zero in case we have a non
2260  // distributed boundary
2261  Vector<double> initial_segment_arclength(nsegments,0.0);
2262 
2263  // Info. to be passed to other processors
2264  // If the boundary is distributed we need to know which processors does
2265  // have the initial and final segments, this helps to get the first and
2266  // last nodes coordinates (info. used to scale the bound coordinates)
2267 
2268  // Processors with the initial and final segment
2269  unsigned proc_with_initial_seg = 0;
2270  unsigned proc_with_final_seg = 0;
2271 
2272  // ... and the index of those segments (only of interest in the
2273  // processors that have the initial and final segments)
2274  unsigned initial_segment = 0;
2275  unsigned final_segment = 0;
2276 
2277  // Each segment needs to know whether it has to be inverted or not
2278  // Store whether a segment needs to be inverted or not
2279  Vector<unsigned> segment_inverted(nsegments);
2280 
2281  // Before attaching the halo elements create a copy of the data
2282  // structure without halo elements
2283  Vector<std::list<FiniteElement*> > segment_sorted_nonhalo_ele_pt(nsegments);
2284  for (unsigned is = 0; is < nsegments; is++)
2285  {
2286  for (std::list<FiniteElement*>::iterator it_seg =
2287  segment_sorted_ele_pt[is].begin();
2288  it_seg != segment_sorted_ele_pt[is].end();
2289  it_seg++)
2290  {
2291  segment_sorted_nonhalo_ele_pt[is].push_back((*it_seg));
2292  }
2293 
2294  } // for (is < nsegments)
2295 
2296  // --------------------------------------------------------------
2297  // Attach the halo elements at both sides of the segments
2298  for (unsigned is = 0; is < nsegments; is++)
2299  {
2300  // Get access to the first element on the segment
2301  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2302 
2303  // Number of nodes
2304  const unsigned nnod = first_ele_pt->nnode();
2305 
2306  // Get the first node of the current segment
2307  Node *first_node_pt = first_ele_pt->node_pt(0);
2308  if (is_inverted[first_ele_pt])
2309  {
2310  first_node_pt = first_ele_pt->node_pt(nnod-1);
2311  }
2312 
2313  // Get access to the last element on the segment
2314  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2315 
2316  // Get the last node of the current segment
2317  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2318  if (is_inverted[last_ele_pt])
2319  {
2320  last_node_pt = last_ele_pt->node_pt(0);
2321  }
2322 
2323  // -----------------------------------------------------------------
2324  // Fourth: Now attach the halo elements to the left and right side
2325  // of each segment
2326  // -----------------------------------------------------------------
2327  bool attached_left_halo = false;
2328  bool attached_right_halo = false;
2329  if (nhalo_face_element > 0)
2330  {
2331  for (unsigned iiface = 0; iiface < n_all_face_ele; iiface++)
2332  {
2333  // Get the candidate element
2334  FiniteElement* halo_face_ele_pt = all_face_ele_pt[iiface];
2335 
2336  // Check that the element is a halo face element, we do not check
2337  // if the element has been already done since the halo elements
2338  // may be connected to more than one segment (2 at most), to the
2339  // left and right of different segments
2340  //
2341  // Segment k Halo Segment r
2342  // |---|---|---| |xxx| |---|---|---|
2343  //
2344  // Segment k Halo Segment r
2345  // |---|---|---|xxx|---|---|---|
2346  //
2347  if (is_halo_face_element[iiface])
2348  {
2349  // Get its left and right nodes
2350  Node* left_node_pt = halo_face_ele_pt->node_pt(0);
2351  Node* right_node_pt = halo_face_ele_pt->node_pt(nnod-1);
2352  // The halo element fits to the left of segment
2353  if (!attached_left_halo && (first_node_pt == right_node_pt ||
2354  first_node_pt == left_node_pt))
2355  {
2356  // Add the halo element to the left of the segment
2357  segment_sorted_ele_pt[is].push_front(halo_face_ele_pt);
2358 
2359  // Once a halo face element has been added to the left
2360  // mark as found halo to the left
2361  attached_left_halo = true;
2362  }
2363  // The halo element fits to the right of the segment
2364  else if (!attached_right_halo && (last_node_pt == left_node_pt ||
2365  last_node_pt == right_node_pt))
2366  {
2367  // Add the halo element to the right of the segment
2368  segment_sorted_ele_pt[is].push_back(halo_face_ele_pt);
2369  // Once a halo face element has been added to the right
2370  // mark as found halo to the right
2371  attached_right_halo = true;
2372  }
2373  // If we have already found elements to left and right then
2374  // break the loop
2375  if (attached_left_halo && attached_right_halo)
2376  {break;}
2377 
2378  } // if (is_halo_face_element[iiface])
2379 
2380  } // for (iiface < nel)
2381 
2382  } // if (nhalo_face_element > 0)
2383 
2384  } // for (is < nsegments)
2385 
2386  // The segments now have local coordinates assigned and halo
2387  // elements attached to them. Store that info. in the corresponding
2388  // data structures and be ready to send that info. to a root
2389  // processor. The root processor will be in charge of computing the
2390  // boundary coordinates for each segment of the boundary.
2391 
2392  // For each segment store the following information
2393  // --------------------------------------------------------------------
2394  // Stores the "rank" of the processor to the left of each segment,
2395  // zero if there is no processor to the left which states that the
2396  // segment is the first one on the boundary
2397  Vector<unsigned> left_processor_plus_one(nsegments);
2398 
2399  // Stores the "rank" of the processor to the right of each segment,
2400  // zero if there is no processor to the right which states that the
2401  // segment is the last one on the boundary
2402  Vector<unsigned> right_processor_plus_one(nsegments);
2403 
2404  // The id. of the halo element to the left of the segment, note that
2405  // this info. is not necessary if there is no processor to the left
2406  // of the segment
2407  Vector<unsigned> left_halo_element(nsegments);
2408 
2409  // The id. of the halo element to the right of the segment, note that
2410  // this info. is not necessary if there is no processor to the right
2411  // of the segment
2412  Vector<unsigned> right_halo_element(nsegments);
2413 
2414  // The id. of the haloed element to the left of the segment, note that
2415  // this info. is not necessary if there is no processor to the left
2416  // of the segment
2417  Vector<unsigned> left_haloed_element(nsegments);
2418 
2419  // The id. of the haloed element to the right of the segment, note
2420  // that this info. is not necessary if there is no processor to the
2421  // right of the segment
2422  Vector<unsigned> right_haloed_element(nsegments);
2423 
2424  // Go through all the segments and get the info.
2425  for (unsigned is = 0; is < nsegments; is++)
2426  {
2427  // Get access to the left most face element on the segment
2428  FiniteElement* left_face_ele_pt=segment_sorted_ele_pt[is].front();
2429 
2430  // Get the corresponding bulk element and check whether it is a halo
2431  // element or not
2432  FiniteElement* tmp_left_bulk_ele_pt =
2433  face_to_bulk_element_pt[left_face_ele_pt];
2434 
2435  // Check if the bulk element is halo
2436  if (tmp_left_bulk_ele_pt->is_halo())
2437  {
2438  // Then store the corresponding info.
2439  int left_proc = tmp_left_bulk_ele_pt->non_halo_proc_ID();
2440 #ifdef PARANOID
2441  if (left_proc < 0)
2442  {
2443  std::ostringstream error_message;
2444  error_message
2445  << "The current bulk element (left) is marked as halo but "
2446  << "the processor holding\nthe non-halo counterpart is "
2447  << "negative!\n";
2448  throw OomphLibError(error_message.str(),
2449  OOMPH_CURRENT_FUNCTION,
2450  OOMPH_EXCEPTION_LOCATION);
2451  }
2452 #endif
2453  // The processor "rank" to the left
2454  unsigned left_processor = static_cast<unsigned>(left_proc);
2455  left_processor_plus_one[is] = left_processor + 1;
2456 
2457  // Now get the id of the halo element to the left
2458  GeneralisedElement *left_element_pt = tmp_left_bulk_ele_pt;
2459 
2460  // Get the halo elements with left processor
2461  Vector<GeneralisedElement*> left_halo_element_pt =
2462  this->halo_element_pt(left_processor);
2463 
2464 #ifdef PARANOID
2465  // Flag to state that the halo element was found
2466  bool left_halo_element_found = false;
2467 #endif
2468 
2469  const unsigned n_halo_left = left_halo_element_pt.size();
2470  for (unsigned lh = 0; lh < n_halo_left; lh++)
2471  {
2472  if (left_element_pt == left_halo_element_pt[lh])
2473  {
2474  left_halo_element[is] = lh;
2475 #ifdef PARANOID
2476  left_halo_element_found = true;
2477 #endif
2478  break;
2479  }
2480  } // for (lh < n_halo_left)
2481 
2482 #ifdef PARANOID
2483  if (!left_halo_element_found)
2484  {
2485  std::ostringstream error_message;
2486  error_message
2487  << "The current bulk element (left) marked as halo was "
2488  << "not found in the vector of halo\nelements associated "
2489  << "with the (" << left_processor << ") processor.\n\n";
2490  throw OomphLibError(error_message.str(),
2491  OOMPH_CURRENT_FUNCTION,
2492  OOMPH_EXCEPTION_LOCATION);
2493  } // if (!left_halo_element_found)
2494 #endif
2495 
2496  // Get the left-most nonhalo element (use the backup list of
2497  // nonhalo elements)
2498  left_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].front();
2499 
2500  // Get the corresponding bulk element
2501  tmp_left_bulk_ele_pt = face_to_bulk_element_pt[left_face_ele_pt];
2502 
2503 #ifdef PARANOID
2504  // This element should not be marked as halo
2505  if (tmp_left_bulk_ele_pt->is_halo())
2506  {
2507  std::ostringstream error_message;
2508  error_message
2509  << "The bulk element represetation of the left-most nonhalo face\n"
2510  << "element of the current segment ("<<is<<") is marked as halo,\n"
2511  << "but the face element created from it is nonhalo\n";
2512  throw OomphLibError(error_message.str(),
2513  OOMPH_CURRENT_FUNCTION,
2514  OOMPH_EXCEPTION_LOCATION);
2515  } // if (tmp_left_bulk_ele_pt->is_halo())
2516 #endif
2517 
2518  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2519  // to search in the haloed vector
2520  left_element_pt = tmp_left_bulk_ele_pt;
2521 
2522 #ifdef PARANOID
2523  // Flag to state that the haloed element was found
2524  bool left_haloed_element_found = false;
2525 #endif
2526 
2527  // Now get the id for the haloed element to the left, get the
2528  // haloed elements from the processor to the left
2529  Vector<GeneralisedElement*> left_haloed_element_pt =
2530  this->haloed_element_pt(left_processor);
2531 
2532  const unsigned nhaloed_left = left_haloed_element_pt.size();
2533  for (unsigned lhd = 0; lhd < nhaloed_left; lhd++)
2534  {
2535  if (left_element_pt == left_haloed_element_pt[lhd])
2536  {
2537  left_haloed_element[is] = lhd;
2538 #ifdef PARANOID
2539  left_haloed_element_found = true;
2540 #endif
2541  break;
2542  }
2543  } // for (lhd < nhaloed_left)
2544 
2545 #ifdef PARANOID
2546  if (!left_haloed_element_found)
2547  {
2548  std::ostringstream error_message;
2549  error_message
2550  << "The current bulk element (left) marked as haloed was "
2551  << "not found in the vector of haloed\nelements associated "
2552  << "with processor ("<< left_processor << ").\n";
2553  throw OomphLibError(error_message.str(),
2554  OOMPH_CURRENT_FUNCTION,
2555  OOMPH_EXCEPTION_LOCATION);
2556  }
2557 #endif
2558  } // if (tmp_left_bulk_ele_pt->is_halo())
2559  else
2560  {
2561  // If not halo then state the info. to indicate that
2562  left_processor_plus_one[is] = 0;
2563  // Null this info.
2564  left_halo_element[is] = 0;
2565  // Null this info.
2566  left_haloed_element[is] = 0;
2567  }
2568 
2569  // Get access to the right most face element on the segment
2570  FiniteElement* right_face_ele_pt = segment_sorted_ele_pt[is].back();
2571 
2572  // Get the corresponding bulk element and check whether it is
2573  // a halo element or not
2574  FiniteElement* tmp_right_bulk_ele_pt =
2575  face_to_bulk_element_pt[right_face_ele_pt];
2576 
2577  // Check if the bulk element is halo
2578  if (tmp_right_bulk_ele_pt->is_halo())
2579  {
2580  // Then store the corresponding info.
2581  int right_proc = tmp_right_bulk_ele_pt->non_halo_proc_ID();
2582 #ifdef PARANOID
2583  if (right_proc < 0)
2584  {
2585  std::ostringstream error_message;
2586  error_message
2587  << "The current bulk element (right) is marked as halo but "
2588  << "the processor holding\nthe non-halo counterpart is "
2589  << "negative!\n";
2590  throw OomphLibError(error_message.str(),
2591  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2592  OOMPH_EXCEPTION_LOCATION);
2593  }
2594 #endif
2595  // The processor "rank" to the right
2596  unsigned right_processor = static_cast<unsigned>(right_proc);
2597  right_processor_plus_one[is] = right_processor + 1;
2598 
2599  // Now get the id of the halo element to the right
2600  GeneralisedElement *right_element_pt = tmp_right_bulk_ele_pt;
2601 
2602  // Get the halo elements with right processor
2603  Vector<GeneralisedElement*> right_halo_element_pt =
2604  this->halo_element_pt(right_processor);
2605 
2606 #ifdef PARANOID
2607  // Flag to state that the halo element was found
2608  bool right_halo_element_found = false;
2609 #endif
2610 
2611  const unsigned nhalo_right = right_halo_element_pt.size();
2612  for (unsigned rh = 0; rh < nhalo_right; rh++)
2613  {
2614  if (right_element_pt == right_halo_element_pt[rh])
2615  {
2616  right_halo_element[is] = rh;
2617 #ifdef PARANOID
2618  right_halo_element_found = true;
2619 #endif
2620  break;
2621  }
2622  } // for (rh < nhalo_right)
2623 #ifdef PARANOID
2624  if (!right_halo_element_found)
2625  {
2626  std::ostringstream error_message;
2627  error_message
2628  << "The current bulk element (right) marked as halo was not "
2629  << "found in the vector of halo\nelements associated with "
2630  << "the (" << right_processor << ") processor.\n\n";
2631  throw OomphLibError(error_message.str(),
2632  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2633  OOMPH_EXCEPTION_LOCATION);
2634  }
2635 #endif
2636 
2637  // Get the right-most nonhalo element (use the backup list of
2638  // nonhalo elements)
2639  right_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
2640 
2641  // Get the corresponding bulk element
2642  tmp_right_bulk_ele_pt=face_to_bulk_element_pt[right_face_ele_pt];
2643 #ifdef PARANOID
2644  // This element should not be marked as halo
2645  if (tmp_right_bulk_ele_pt->is_halo())
2646  {
2647  std::ostringstream error_message;
2648  error_message
2649  << "The bulk element represetation of the right-most nonhalo face\n"
2650  << "element of the current segment ("<<is<<") is marked as halo,\n"
2651  << "but the face element created from it is nonhalo\n";
2652  throw OomphLibError(error_message.str(),
2653  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2654  OOMPH_EXCEPTION_LOCATION);
2655  } // if (tmp_right_bulk_ele_pt->is_halo())
2656 #endif
2657 
2658  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2659  // to search in the haloed vector
2660  right_element_pt = tmp_right_bulk_ele_pt;
2661 
2662 #ifdef PARANOID
2663  // Flag to state that the haloed element was found
2664  bool right_haloed_element_found = false;
2665 #endif
2666 
2667  // Now get the id for the haloed element to the right
2668  Vector<GeneralisedElement*> right_haloed_element_pt =
2669  this->haloed_element_pt(right_processor);
2670 
2671  const unsigned nhaloed_right = right_haloed_element_pt.size();
2672  for (unsigned rhd = 0; rhd < nhaloed_right; rhd++)
2673  {
2674  if (right_element_pt == right_haloed_element_pt[rhd])
2675  {
2676  right_haloed_element[is] = rhd;
2677 #ifdef PARANOID
2678  right_haloed_element_found = true;
2679 #endif
2680  break;
2681  }
2682  } // for (rhd < nhaloed_right)
2683 
2684 #ifdef PARANOID
2685  if (!right_haloed_element_found)
2686  {
2687  std::ostringstream error_message;
2688  error_message
2689  << "The current bulk element (right) marked as haloed was not "
2690  << "found in the vector of haloed\nelements associated with "
2691  << "the ("<< right_processor << ") processor.\n\n";
2692  throw OomphLibError(error_message.str(),
2693  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2694  OOMPH_EXCEPTION_LOCATION);
2695  }
2696 #endif
2697 
2698  } // if (tmp_right_bulk_ele_pt->is_halo())
2699  else
2700  {
2701  // If not halo then state the info. to indicate that
2702  right_processor_plus_one[is] = 0;
2703  // Null this info.
2704  right_halo_element[is] = 0;
2705  // Null this info.
2706  right_haloed_element[is] = 0;
2707  }
2708 
2709  } // for (is < nsegments). Used to get the halo info. of the
2710  // segments
2711 
2712  // Now we have all the info. to be sent to the root processor and
2713  // compute the correct (global) boundary coordinates for the current
2714  // boundary
2715 
2716  // The root processor will be in charge of performing the computing
2717  // of the coordinate values along the boundary, all the other
2718  // processors only send their info. and wait for receiving the new
2719  // starting values for each of its segments
2720 
2721  // Choose the root processor
2722  const unsigned root_processor = 0;
2723  // ------------------------------------------------------------------
2724  // Starts the MPI stage
2725 
2726  // The root processor receives the number of segments of each
2727  // processor associated to the current boundary
2728  Vector<unsigned> root_nsegments_per_processor(nproc);
2729  unsigned nsegments_mpi = nsegments;
2730  MPI_Gather(&nsegments_mpi, 1, MPI_UNSIGNED,
2731  &root_nsegments_per_processor[0], 1, MPI_UNSIGNED,
2732  root_processor, comm_pt->mpi_comm());
2733 
2734  // Package the info. and prepare it to be sent
2735  // For the packaged info. we send 7 data per each segment, the indexes
2736  // are as follow; 0 left proc, 1 right proc, 2 left halo, 3 right
2737  // halo, 4 left haloed, 5 right haloed and 6 for nvertices per
2738  // segment
2739  // The size of the package (unsigned)
2740  const unsigned spu = 7;
2741  Vector<unsigned> flat_packed_unsigned_send_data(nsegments*spu);
2742  for (unsigned is = 0; is < nsegments; is++)
2743  {
2744  flat_packed_unsigned_send_data[(spu*is)+0]=left_processor_plus_one[is];
2745  flat_packed_unsigned_send_data[(spu*is)+1]=right_processor_plus_one[is];
2746  flat_packed_unsigned_send_data[(spu*is)+2]=left_halo_element[is];
2747  flat_packed_unsigned_send_data[(spu*is)+3]=right_halo_element[is];
2748  flat_packed_unsigned_send_data[(spu*is)+4]=left_haloed_element[is];
2749  flat_packed_unsigned_send_data[(spu*is)+5]=right_haloed_element[is];
2750  flat_packed_unsigned_send_data[(spu*is)+6]=nvertices_per_segment[is];
2751  }
2752 
2753  // How many data will this processor send
2754  const unsigned nudata_to_send = flat_packed_unsigned_send_data.size();
2755 
2756  // How many data does the root processor will receive from each
2757  // processor
2758  Vector<int> root_nudata_to_receive(nproc,0);
2759  // Total number of data to receive from all processors
2760  unsigned root_nutotal_data_receive = 0;
2761  for (unsigned ip = 0; ip < nproc; ip++)
2762  {
2763  // Compute the number of data the root processor will receive from
2764  // each processor
2765  root_nudata_to_receive[ip] = root_nsegments_per_processor[ip] * spu;
2766  // Add on the total number of data to receive
2767  root_nutotal_data_receive+= root_nudata_to_receive[ip];
2768  }
2769 
2770  // Stores and compute the offsets (in root) for the data received
2771  // from each processor
2772  Vector<int> root_uoffsets_receive(nproc,0);
2773  root_uoffsets_receive[0] = 0;
2774  for (unsigned ip = 1; ip < nproc; ip++)
2775  {
2776  // Compute the offset to store the values from each processor
2777  root_uoffsets_receive[ip] =
2778  root_uoffsets_receive[ip-1] + root_nudata_to_receive[ip-1];
2779  }
2780 
2781  // Create at least one entry so we don't get a seg fault below
2782  if (flat_packed_unsigned_send_data.size()==0)
2783  {
2784  flat_packed_unsigned_send_data.resize(1);
2785  }
2786 
2787  // Vector where to receive the info.
2788  Vector<unsigned> flat_packed_unsigned_receive_data(
2789  root_nutotal_data_receive);
2790  if (my_rank!=root_processor)
2791  {
2792  // Create at least one entry so we don't get a seg fault below
2793  if (flat_packed_unsigned_receive_data.size()==0)
2794  {
2795  flat_packed_unsigned_receive_data.resize(1);
2796  }
2797  } // if (my_rank!=root_processor)
2798 
2799  MPI_Gatherv(&flat_packed_unsigned_send_data[0], // Flat package to
2800  // send info. from
2801  // each processor
2802  nudata_to_send, // Total number of data to send from
2803  // each processor
2804  MPI_UNSIGNED,
2805  &flat_packed_unsigned_receive_data[0], // Container
2806  // where to
2807  // receive the
2808  // info. from all
2809  // the processors
2810  &root_nudata_to_receive[0], // Number of data to receive
2811  // from each processor
2812  &root_uoffsets_receive[0], // The offset to store the
2813  // info. from each processor
2814  MPI_UNSIGNED,
2815  root_processor, //The processor that receives all the
2816  //info.
2817  comm_pt->mpi_comm());
2818 
2819  // Clear the flat package to send
2820  flat_packed_unsigned_send_data.clear();
2821  flat_packed_unsigned_send_data.resize(0);
2822 
2823  // Package the info. and prepare it to be sent
2824  // For the packaged info. we send 1 data per each segment which is
2825  // at the moment the arclength of each segment
2826  // The size of the package
2827  const unsigned spd = 1;
2828  Vector<double> flat_packed_double_send_data(nsegments*spd);
2829  for (unsigned is = 0; is < nsegments; is++)
2830  {
2831  flat_packed_double_send_data[(spd*is)+0]=segment_arclength[is];
2832  }
2833 
2834  // How many data will this processor send
2835  const unsigned nddata_to_send = flat_packed_double_send_data.size();
2836  // How many data does the root processor will receive from each
2837  // processor
2838  Vector<int> root_nddata_to_receive(nproc,0);
2839  // Total number of data to receive from all processors
2840  unsigned root_ndtotal_data_receive = 0;
2841  for (unsigned ip =0; ip < nproc; ip++)
2842  {
2843  root_nddata_to_receive[ip] = root_nsegments_per_processor[ip] * spd;
2844  root_ndtotal_data_receive+= root_nddata_to_receive[ip];
2845  }
2846 
2847  // Stores and compute the offsets for the data received from each
2848  // processor
2849  Vector<int> root_doffsets_receive(nproc,0);
2850  root_doffsets_receive[0] = 0;
2851  for (unsigned ip = 1; ip < nproc; ip++)
2852  {
2853  // Compute the offset to store the values from each processor
2854  root_doffsets_receive[ip] =
2855  root_doffsets_receive[ip-1] + root_nddata_to_receive[ip-1];
2856  }
2857 
2858  // Create at least one entry so we don't get a seg fault below
2859  if (flat_packed_double_send_data.size()==0)
2860  {
2861  flat_packed_double_send_data.resize(1);
2862  }
2863 
2864  // Vector where to receive the info.
2865  Vector<double> flat_packed_double_receive_data(root_ndtotal_data_receive);
2866  if (my_rank!=root_processor)
2867  {
2868  // Create at least one entry so we don't get a seg fault below
2869  if (flat_packed_double_receive_data.size()==0)
2870  {
2871  flat_packed_double_receive_data.resize(1);
2872  }
2873  }
2874 
2875  MPI_Gatherv(&flat_packed_double_send_data[0], // Flat package to
2876  // send info. from
2877  // each processor
2878  nddata_to_send, // Total number of data to send from
2879  // each processor
2880  MPI_DOUBLE,
2881  &flat_packed_double_receive_data[0], // Container where
2882  // to receive the
2883  // info. from all
2884  // the processors
2885  &root_nddata_to_receive[0], // Number of data to receive
2886  // from each processor
2887  &root_doffsets_receive[0], // The offset to store the
2888  // info. from each processor
2889  MPI_DOUBLE,
2890  root_processor, //The processor that receives all the
2891  //info.
2892  comm_pt->mpi_comm());
2893 
2894  // Clear the flat package to send
2895  flat_packed_double_send_data.clear();
2896  flat_packed_double_send_data.resize(0);
2897 
2898  // The next three containers are only used by the root processor at
2899  // the end of its computations but it is necessary that all the
2900  // processors know them when calling back the info.
2901 
2902  // Container that state the initial arclength for each segments
2903  // of each processor
2904  Vector<Vector<double> > root_initial_segment_arclength(nproc);
2905 
2906  // Container that state the number of vertices before each segment
2907  // in a given processor
2908  Vector<Vector<unsigned> > root_nvertices_before_segment(nproc);
2909 
2910  // The root processor needs to tell the other processor if it was
2911  // necessary to reverse a segment. Each processor should therefore
2912  // invert the face elements that compose every segment that was
2913  // inverted by the root processor
2914  Vector<Vector<unsigned> > root_segment_inverted(nproc);
2915 
2916  // Used to store the accumulated arclength, used at the end of
2917  // communications to store the total arclength
2918  double root_accumulated_arclength = 0.0;
2919 
2920  // Store the accumulated number of vertices, it means the total number
2921  // of vertices before each segment (counter)
2922  unsigned root_accumulated_vertices_before_segment = 0;
2923 
2924  // The root processor is in charge of performing the connections
2925  // of the segments that define the complete boundary
2926  if (my_rank == root_processor)
2927  {
2928  // From the flat packaged received data re-create the data
2929  // structures storing the info. regarding the connectivity of the
2930  // segments, the number of vertices per segment and the local
2931  // arclength of each segment
2932 
2933  // Stores the "rank" of the processor to the left of each segment,
2934  // zero if there is no processor to the left which states that the
2935  // segment is the first one on the boundary
2936  Vector<Vector<unsigned> > root_left_processor_plus_one(nproc);
2937 
2938  // Stores the "rank" of the processor to the right of each segment,
2939  // zero if there is no processor to the right which states that the
2940  // segment is the last one on the boundary
2941  Vector<Vector<unsigned> > root_right_processor_plus_one(nproc);
2942 
2943  // The id. of the halo element to the left of the segment, note that
2944  // this info. is not necessary if there is no processor to the left
2945  // of the segment or if the processor has no info about the boundary
2946  Vector<Vector<unsigned> > root_left_halo_element(nproc);
2947 
2948  // The id. of the halo element to the right of the segment, note
2949  // that this info. is not necessary if there is no processor to
2950  // the right of the segment or if the processor has no info about
2951  // the boundary
2952  Vector<Vector<unsigned> > root_right_halo_element(nproc);
2953 
2954  // The id. of the haloed element to the left of the segment, note
2955  // that this info. is not necessary if there is no processor to
2956  // the left of the segment or if the processor has no info about
2957  // the boundary
2958  Vector<Vector<unsigned> > root_left_haloed_element(nproc);
2959 
2960  // The id. of the haloed element to the right of the segment, note
2961  // that this info. is not necessary if there is no processor to the
2962  // right of the segment or if the processor has no info about the
2963  // boundary
2964  Vector<Vector<unsigned> > root_right_haloed_element(nproc);
2965 
2966  // The number of vertices per segment in each processor
2967  Vector<Vector<unsigned> > root_nvertices_per_segment(nproc);
2968 
2969  // The arclength of each of the segments in the processors
2970  Vector<Vector<double> > root_segment_arclength(nproc);
2971 
2972  unsigned ucounter = 0;
2973  unsigned dcounter = 0;
2974  for (unsigned ip = 0; ip < nproc; ip++)
2975  {
2976  // Get the number of segments in the current processor
2977  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
2978 
2979  root_left_processor_plus_one[ip].resize(nsegs_iproc);
2980  root_right_processor_plus_one[ip].resize(nsegs_iproc);
2981  root_left_halo_element[ip].resize(nsegs_iproc);
2982  root_right_halo_element[ip].resize(nsegs_iproc);
2983  root_left_haloed_element[ip].resize(nsegs_iproc);
2984  root_right_haloed_element[ip].resize(nsegs_iproc);
2985 
2986  // Additional info.
2987  root_nvertices_per_segment[ip].resize(nsegs_iproc);
2988  root_segment_arclength[ip].resize(nsegs_iproc);
2989  root_segment_inverted[ip].resize(nsegs_iproc);
2990 
2991  // Extract the info. from the BIG package received from all
2992  // processors
2993  for(unsigned is = 0; is < nsegs_iproc; is++)
2994  {
2995  // ------ The flat unsigned package ------
2996  root_left_processor_plus_one[ip][is] =
2997  flat_packed_unsigned_receive_data[ucounter++];
2998  root_right_processor_plus_one[ip][is] =
2999  flat_packed_unsigned_receive_data[ucounter++];
3000  root_left_halo_element[ip][is] =
3001  flat_packed_unsigned_receive_data[ucounter++];
3002  root_right_halo_element[ip][is] =
3003  flat_packed_unsigned_receive_data[ucounter++];
3004  root_left_haloed_element[ip][is] =
3005  flat_packed_unsigned_receive_data[ucounter++];
3006  root_right_haloed_element[ip][is] =
3007  flat_packed_unsigned_receive_data[ucounter++];
3008  root_nvertices_per_segment[ip][is] =
3009  flat_packed_unsigned_receive_data[ucounter++];
3010 
3011  // ------ The flat double package ------
3012  root_segment_arclength[ip][is] =
3013  flat_packed_double_receive_data[dcounter++];
3014  } // for (is < nsegs_iproc)
3015  } // for (ip < nproc)
3016 
3017  // Now the root processor has all the info. to find out the
3018  // CONNECTIVITY of the segments in each processor
3019 
3020  // Container that stores the info. related with the connectivity
3021  // of the segments of each processor
3022  Vector<Vector<int> > left_connected_segment_plus_one(nproc);
3023  Vector<Vector<int> > right_connected_segment_plus_one(nproc);
3024  for (unsigned ip = 0; ip < nproc; ip++)
3025  {
3026  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3027  left_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3028  right_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3029  } // for (ip < nprocs)
3030 
3031  // In charge of storing the connectivity of the segments, the pair
3032  // indicates the processor and the segment number
3033  std::list<std::pair<unsigned, unsigned> > proc_seg_connectivity;
3034  proc_seg_connectivity.clear();
3035 
3036  // Done segments on processor
3037  std::map<std::pair<unsigned, unsigned>, bool> done_segment;
3038 
3039  // Take the first segment of the first processor with segments and
3040  // add it to the list of segments
3041  unsigned left_proc = 0;
3042  unsigned right_proc = 0;
3043  unsigned left_seg = 0;
3044  unsigned right_seg = 0;
3045  for (unsigned ip = 0; ip < nproc; ip++)
3046  {
3047  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3048  if (nsegs_iproc > 0)
3049  {
3050  right_proc = left_proc = ip;
3051  right_seg = left_seg = 0;
3052  break; // Break because it is the first processor with at
3053  // least one segment
3054  }
3055  } // for (ip < nproc)
3056 
3057  // ... and add it to the list of segments
3058  std::pair<unsigned, unsigned> add_segment =
3059  std::make_pair(left_proc, left_seg);
3060  done_segment[add_segment] = true;
3061  proc_seg_connectivity.push_back(add_segment);
3062 
3063  // Flags to indicate when a segment was added to the left or right
3064  // of the current list of segments
3065  bool added_segment_to_the_left = false;
3066  bool added_segment_to_the_right = false;
3067 
3068  do // while(added_segment_to_the_left || added_segment_to_the_right)
3069  {
3070  // Read the left-most processor and segment in the list
3071  std::pair<unsigned, unsigned> left_pair =
3072  proc_seg_connectivity.front();
3073  left_proc = left_pair.first;
3074  left_seg = left_pair.second;
3075 
3076  // Get the processor number to the left of the left-most
3077  // segment in the list
3078  const unsigned new_left_proc =
3079  root_left_processor_plus_one[left_proc][left_seg];
3080 
3081  if (new_left_proc != 0)
3082  {
3083  // Initialise flag
3084  added_segment_to_the_left = false;
3085  // Get the left halo element id
3086  const unsigned left_halo_id =
3087  root_left_halo_element[left_proc][left_seg];
3088 
3089  // Get the left haloed element id
3090  const unsigned left_haloed_id =
3091  root_left_haloed_element[left_proc][left_seg];
3092 
3093  // Go through the segments on the new left processor and look
3094  // for the corresponding left_halo_id in the haloed_ids
3095  const unsigned nsegs_new_left_proc =
3096  root_nsegments_per_processor[new_left_proc-1];
3097 
3098  for (unsigned ils = 0; ils < nsegs_new_left_proc; ils++)
3099  {
3100  std::pair<unsigned, unsigned> candidate_seg =
3101  std::make_pair(new_left_proc-1, ils);
3102 
3103  // Check that the segment has not been already added
3104  if (!done_segment[candidate_seg])
3105  {
3106  // Only consider the segments on new left processor which
3107  // right processor is the current one (left_proc)
3108  const unsigned right_proc_of_new_left_proc =
3109  root_right_processor_plus_one[new_left_proc-1][ils];
3110  // Also get the left_proc_of_new_left_proc (in case that it
3111  // be necessary to invert the segment)
3112  const unsigned left_proc_of_new_left_proc =
3113  root_left_processor_plus_one[new_left_proc-1][ils];
3114  // Check the not inverted case (to the left and not
3115  // inverted)
3116  if (right_proc_of_new_left_proc != 0 &&
3117  right_proc_of_new_left_proc-1 == left_proc)
3118  {
3119  // Get the haloed/haloed element id of the current segment
3120  // in the new left processor and compare it to the
3121  // halo/haloed element id of the left_processor
3122  const unsigned right_halo_id =
3123  root_right_halo_element[new_left_proc-1][ils];
3124  const unsigned right_haloed_id =
3125  root_right_haloed_element[new_left_proc-1][ils];
3126  if (left_halo_id == right_haloed_id &&
3127  left_haloed_id == right_halo_id)
3128  {
3129  // We have a match of the segments (store the segment
3130  // number plus one on the processor to the left)
3131  left_connected_segment_plus_one[left_proc][left_seg]=
3132  ils+1;
3133  // Add the pair to the connectivity list
3134  proc_seg_connectivity.push_front(candidate_seg);
3135  added_segment_to_the_left = true;
3136  break;
3137  }
3138  } // if (right_proc_of_new_left_proc-1 == left_proc)
3139 
3140  // Check the inverted case (to the left and inverted)
3141  if (left_proc_of_new_left_proc != 0 &&
3142  left_proc_of_new_left_proc-1 == left_proc)
3143  {
3144  // Get the haloed element id of the current segment
3145  // (inverted version) in the new left processor and
3146  // compare it to the halo element id of the left_processor
3147  const unsigned inv_left_halo_id =
3148  root_left_halo_element[new_left_proc-1][ils];
3149  const unsigned inv_left_haloed_id =
3150  root_left_haloed_element[new_left_proc-1][ils];
3151  if (left_halo_id == inv_left_haloed_id &&
3152  left_haloed_id == inv_left_halo_id)
3153  {
3154  // We have a match of the segments (store the segment
3155  // number plus one on the processor to the left)
3156  left_connected_segment_plus_one[left_proc][left_seg]=
3157  ils+1;
3158  // Add the pair to the connectivity list
3159  proc_seg_connectivity.push_front(candidate_seg);
3160 
3161  // In addition to the connectivity we need to invert the
3162  // segment (the information)
3163  const unsigned tmp_proc =
3164  root_left_processor_plus_one[new_left_proc-1][ils];
3165  const unsigned tmp_halo =
3166  root_left_halo_element[new_left_proc-1][ils];
3167  const unsigned tmp_haloed =
3168  root_left_haloed_element[new_left_proc-1][ils];
3169 
3170  root_left_processor_plus_one[new_left_proc-1][ils] =
3171  root_right_processor_plus_one[new_left_proc-1][ils];
3172  root_left_halo_element[new_left_proc-1][ils] =
3173  root_right_halo_element[new_left_proc-1][ils];
3174  root_left_haloed_element[new_left_proc-1][ils] =
3175  root_right_haloed_element[new_left_proc-1][ils];
3176 
3177  root_right_processor_plus_one[new_left_proc-1][ils] =
3178  tmp_proc;
3179  root_right_halo_element[new_left_proc-1][ils]=tmp_halo;
3180  root_right_haloed_element[new_left_proc-1][ils] =
3181  tmp_haloed;
3182 
3183  // ... and mark the segment as inverted in the root
3184  // processor to inform back to the owner processor
3185  root_segment_inverted[new_left_proc-1][ils] = 1;
3186 
3187  added_segment_to_the_left = true;
3188  break;
3189  }
3190  } // if (left_proc_of_new_left_proc-1 == left_proc)
3191  } // if (!done_segment[candidate_segment])
3192  } // for (ils < nsegs_new_left_proc)
3193 
3194 #ifdef PARANOID
3195  if (!added_segment_to_the_left)
3196  {
3197  std::ostringstream error_message;
3198  error_message
3199  << "The corresponding processor and segment to the left of "
3200  << "the current left\nmost segment was not found\n";
3201  throw OomphLibError(error_message.str(),
3202  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3203  OOMPH_EXCEPTION_LOCATION);
3204  }
3205 #endif
3206  } // if (new_left_proc != 0)
3207  else
3208  {
3209  // No more segments to the left
3210  added_segment_to_the_left = false;
3211  }
3212 
3213  // Read the info. of the right processor and the right segment
3214  std::pair<unsigned, unsigned> right_pair =
3215  proc_seg_connectivity.back();
3216  right_proc = right_pair.first;
3217  right_seg = right_pair.second;
3218 
3219  // Get the processor number to the right of the right-most
3220  // segment in the list
3221  const unsigned new_right_proc =
3222  root_right_processor_plus_one[right_proc][right_seg];
3223 
3224  if (new_right_proc != 0)
3225  {
3226  // Initialise flag
3227  added_segment_to_the_right = false;
3228  // Get the right halo element id
3229  const unsigned right_halo_id =
3230  root_right_halo_element[right_proc][right_seg];
3231 
3232  // Get the right halo element id
3233  const unsigned right_haloed_id =
3234  root_right_haloed_element[right_proc][right_seg];
3235 
3236  // Go through the segments on the new right processor and look
3237  // for the corresponding right_halo_id in the haloed_ids
3238  const unsigned nsegs_new_right_proc =
3239  root_nsegments_per_processor[new_right_proc-1];
3240 
3241  for (unsigned irs = 0; irs < nsegs_new_right_proc; irs++)
3242  {
3243  std::pair<unsigned, unsigned> candidate_seg =
3244  std::make_pair(new_right_proc-1, irs);
3245 
3246  // Check that the segment has not been already added
3247  if (!done_segment[candidate_seg])
3248  {
3249  // Only consider the segments on new right processor which
3250  // left processor is the current one (right_proc)
3251  const unsigned left_proc_of_new_right_proc =
3252  root_left_processor_plus_one[new_right_proc-1][irs];
3253  // Also get the right_proc_of_new_right_proc (in case
3254  // that it be necessary to invert the segment)
3255  const unsigned right_proc_of_new_right_proc =
3256  root_right_processor_plus_one[new_right_proc-1][irs];
3257  // Check the not inverted case (to the right and not
3258  // inverted)
3259  if (left_proc_of_new_right_proc != 0 &&
3260  left_proc_of_new_right_proc-1 == right_proc)
3261  {
3262  // Get the haloed element id of the current segment in the
3263  // new right processor and compare it to the halo element
3264  // id of the right_processor
3265  const unsigned left_halo_id =
3266  root_left_halo_element[new_right_proc-1][irs];
3267  const unsigned left_haloed_id =
3268  root_left_haloed_element[new_right_proc-1][irs];
3269 
3270  if (right_halo_id == left_haloed_id &&
3271  right_haloed_id == left_halo_id)
3272  {
3273  // We have a match of the segments (store the segment
3274  // number plus one on the processor to the right)
3275  right_connected_segment_plus_one[right_proc][right_seg]=
3276  irs+1;
3277  // Add the connectivity information to the list
3278  proc_seg_connectivity.push_back(candidate_seg);
3279  added_segment_to_the_right = true;
3280  break;
3281  }
3282  } // if (left_proc_of_new_right_proc-1 == right_proc)
3283 
3284  // Check the inverted case (to the right and inverted)
3285  if (right_proc_of_new_right_proc != 0 &&
3286  right_proc_of_new_right_proc-1 == right_proc)
3287  {
3288  // Get the haloed element id of the current segment
3289  // (inverted version) in the new right processor and
3290  // compare it to the halo element id of the
3291  // right_processor
3292  const unsigned inv_right_halo_id =
3293  root_right_halo_element[new_right_proc-1][irs];
3294  const unsigned inv_right_haloed_id =
3295  root_right_haloed_element[new_right_proc-1][irs];
3296  if (right_halo_id == inv_right_haloed_id &&
3297  right_haloed_id == inv_right_halo_id)
3298  {
3299  // We have a match of the segments (store the segment
3300  // number plus one on the processor to the right)
3301  right_connected_segment_plus_one[right_proc][right_seg]=
3302  irs+1;
3303  // Add the connectivity information to the list
3304  proc_seg_connectivity.push_back(candidate_seg);
3305  // In addition to the connectivity we need to invert the
3306  // segment
3307  const unsigned tmp_proc =
3308  root_left_processor_plus_one[new_right_proc-1][irs];
3309  const unsigned tmp_halo =
3310  root_left_halo_element[new_right_proc-1][irs];
3311  const unsigned tmp_haloed =
3312  root_left_haloed_element[new_right_proc-1][irs];
3313 
3314  root_left_processor_plus_one[new_right_proc-1][irs] =
3315  root_right_processor_plus_one[new_right_proc-1][irs];
3316  root_left_halo_element[new_right_proc-1][irs] =
3317  root_right_halo_element[new_right_proc-1][irs];
3318  root_left_haloed_element[new_right_proc-1][irs] =
3319  root_right_haloed_element[new_right_proc-1][irs];
3320 
3321  root_right_processor_plus_one[new_right_proc-1][irs] =
3322  tmp_proc;
3323  root_right_halo_element[new_right_proc-1][irs]=tmp_halo;
3324  root_right_haloed_element[new_right_proc-1][irs] =
3325  tmp_haloed;
3326 
3327  // ... and mark the segment as inverted in the root
3328  // processor to inform back to the owner processor
3329  root_segment_inverted[new_right_proc-1][irs] = 1;
3330 
3331  added_segment_to_the_right = true;
3332  break;
3333  }
3334  } // if (right_proc_of_new_right_proc-1 == right_proc)
3335  } // if (!done_segment[candidate_segment])
3336  } // for (irs < nsegs_new_left_proc)
3337 
3338 #ifdef PARANOID
3339  if (!added_segment_to_the_right)
3340  {
3341  std::ostringstream error_message;
3342  error_message
3343  << "The corresponding processor and segment to the right of "
3344  << "the current right\nmost segment was not found\n";
3345  throw OomphLibError(error_message.str(),
3346  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3347  OOMPH_EXCEPTION_LOCATION);
3348  }
3349 #endif
3350  } // if (new_right_proc != 0)
3351  else
3352  {
3353  // No more segments to the left
3354  added_segment_to_the_right = false;
3355  }
3356 
3357  }while(added_segment_to_the_left || added_segment_to_the_right);
3358 
3359  // Once we have connected the segments then we can compute the
3360  // initial and final zeta values based on the arclength of each
3361  // individual segment
3362 
3363  // Get the total number of segments, which MUST be the same as the
3364  // total number of segments in all processors
3365  const unsigned ntotal_segments = proc_seg_connectivity.size();
3366 #ifdef PARANOID
3367  unsigned tmp_total_segments = 0;
3368  for (unsigned ip =0; ip < nproc; ip++)
3369  {
3370  tmp_total_segments+= root_nsegments_per_processor[ip];
3371  }
3372 
3373  // Check that the total number of segments in all processors is
3374  // the same as the number of segments that form the boundary
3375  if (ntotal_segments!=tmp_total_segments)
3376  {
3377  std::ostringstream error_message;
3378  error_message
3379  << "The number of sorted segments (" << ntotal_segments << ") on "
3380  << "boundary ("<< b <<")\nis different from the total number of "
3381  <<"segments ("<< tmp_total_segments <<") in all\nprocessors.\n\n";
3382  throw OomphLibError(error_message.str(),
3383  OOMPH_CURRENT_FUNCTION,
3384  OOMPH_EXCEPTION_LOCATION);
3385  } // if (ntotal_segments!=tmp_total_segments)
3386 #endif
3387 
3388  // Now that we know the connectivity of the segments we can
3389  // compute the initial arclength of each segment in the
3390  // processors. Additionally we also get the number of vertices
3391  // before each of the segments. Resize the containers considering
3392  // the number of segments in each processor
3393  for (unsigned ip = 0; ip < nproc; ip++)
3394  {
3395  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3396  root_initial_segment_arclength[ip].resize(nsegs_iproc);
3397  root_nvertices_before_segment[ip].resize(nsegs_iproc);
3398  }
3399 
3400  Vector<double> aux_initial_segment_arclength(ntotal_segments);
3401  Vector<unsigned> aux_nvertices_before_segment(ntotal_segments);
3402 
3403  ucounter = 0;
3404  for (std::list<std::pair<unsigned, unsigned> >::iterator
3405  it_list = proc_seg_connectivity.begin();
3406  it_list != proc_seg_connectivity.end(); it_list++)
3407  {
3408  const unsigned iproc = static_cast<unsigned>((*it_list).first);
3409  const unsigned iseg = static_cast<unsigned>((*it_list).second);
3410  const double iseg_arclength = root_segment_arclength[iproc][iseg];
3411  const unsigned iseg_nvertices = root_nvertices_per_segment[iproc][iseg];
3412 
3413  aux_initial_segment_arclength[ucounter] = root_accumulated_arclength;
3414  aux_nvertices_before_segment[ucounter] =
3415  root_accumulated_vertices_before_segment;
3416 
3417  // Set the initial zeta value for the segment
3418  root_initial_segment_arclength[iproc][iseg] = root_accumulated_arclength;
3419  // Set the number of vertices before the current segment
3420  root_nvertices_before_segment[iproc][iseg] =
3421  root_accumulated_vertices_before_segment;
3422 
3423  // Add the arclength of the segment to the global arclength
3424  root_accumulated_arclength+= iseg_arclength;
3425  // Add the number of vertices to the global number of vertices
3426  root_accumulated_vertices_before_segment+= iseg_nvertices - 1;
3427 
3428  // Increase the counter
3429  ucounter++;
3430  } // for (loop over the sorted segments to assigne initial
3431  // arlength and initial number of vertices)
3432 
3433  // Increase by one to get the total number of vertices on the
3434  // boundary
3435  root_accumulated_vertices_before_segment++;
3436 
3437  // Get the processors with the initial and final segment.
3438  proc_with_initial_seg = proc_seg_connectivity.front().first;
3439  proc_with_final_seg = proc_seg_connectivity.back().first;
3440  // Also get the corresponding initial and final segment indexes
3441  // (on the initial and final processors)
3442  initial_segment = proc_seg_connectivity.front().second;
3443  final_segment = proc_seg_connectivity.back().second;
3444 
3445  } // if (my_rank == root_processor)
3446 
3447  // Get the total number of segments
3448  unsigned root_ntotal_segments = 0;
3449  for (unsigned ip =0; ip < nproc; ip++)
3450  {
3451  root_ntotal_segments+= root_nsegments_per_processor[ip];
3452  }
3453 
3454  // Package the info. that will be sent to each processor. For the
3455  // unsigned package we send the number of vertices before each
3456  // segment in each processor and whether it was inverted or not
3457  // Package size
3458  const unsigned rspu = 2;
3459  flat_packed_unsigned_send_data.clear();
3460  flat_packed_unsigned_send_data.resize(root_ntotal_segments*rspu);
3461  unsigned ucounter = 0;
3462  // Collect the info. from all the segments in the processors
3463  for (unsigned ip = 0; ip < nproc; ip++)
3464  {
3465  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3466  for (unsigned is = 0; is < nsegs_iproc; is++)
3467  {
3468  flat_packed_unsigned_send_data[ucounter++] =
3469  root_nvertices_before_segment[ip][is];
3470  flat_packed_unsigned_send_data[ucounter++] =
3471  root_segment_inverted[ip][is];
3472  } // for (is < nsegs_iproc)
3473  } // for (ip < nproc)
3474 
3475  // How many data does the root processor will send to each processor
3476  Vector<int> root_nudata_to_send(nproc,0);
3477  for (unsigned ip =0; ip < nproc; ip++)
3478  {
3479  // Get the number of data to send to ip processor
3480  root_nudata_to_send[ip] = root_nsegments_per_processor[ip] * rspu;
3481  }
3482 
3483  // Store and compute the offsets for the data sent to each processor
3484  Vector<int> root_uoffsets_send(nproc,0);
3485  root_uoffsets_send[0] = 0;
3486  for (unsigned ip = 1; ip < nproc; ip++)
3487  {
3488  // Compute the offset to send the values to each processor
3489  root_uoffsets_send[ip] =
3490  root_uoffsets_send[ip-1] + root_nudata_to_send[ip-1];
3491  }
3492 
3493  // Number of data to receive from root
3494  unsigned nutotal_data_receive = nsegments * rspu;
3495 
3496  if (my_rank!=root_processor)
3497  {
3498  // Create at least one entry so we don't get a seg fault below
3499  if (flat_packed_unsigned_send_data.size()==0)
3500  {
3501  flat_packed_unsigned_send_data.resize(1);
3502  }
3503  }
3504 
3505  // Clear and resize the vector where to receive the info.
3506  flat_packed_unsigned_receive_data.clear();
3507  flat_packed_unsigned_receive_data.resize(nutotal_data_receive);
3508  // Create at least one entry so we don't get a seg fault below
3509  if (flat_packed_unsigned_receive_data.size()==0)
3510  {
3511  flat_packed_unsigned_receive_data.resize(1);
3512  }
3513 
3514  MPI_Scatterv(&flat_packed_unsigned_send_data[0],
3515  &root_nudata_to_send[0],
3516  &root_uoffsets_send[0],
3517  MPI_UNSIGNED,
3518  &flat_packed_unsigned_receive_data[0],
3519  nutotal_data_receive,
3520  MPI_UNSIGNED,
3521  root_processor,
3522  comm_pt->mpi_comm());
3523 
3524  // Package the info. that will be sent to each processor, for the
3525  // double package we send (one data per segment) the initial
3526  // arclength for each segment
3527  const unsigned rspd = 1;
3528  flat_packed_double_send_data.clear();
3529  flat_packed_double_send_data.resize(root_ntotal_segments*rspd);
3530  unsigned dcounter = 0;
3531  // Collect the info. from all the segments in the processors
3532  for (unsigned ip = 0; ip < nproc; ip++)
3533  {
3534  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3535  for (unsigned is = 0; is < nsegs_iproc; is++)
3536  {
3537  flat_packed_double_send_data[dcounter++] =
3538  root_initial_segment_arclength[ip][is];
3539  }
3540  }
3541 
3542  // How many data does the root processor will send to each processor
3543  Vector<int> root_nddata_to_send(nproc,0);
3544  for (unsigned ip =0; ip < nproc; ip++)
3545  {
3546  // Number of data send to ip processor
3547  root_nddata_to_send[ip] = root_nsegments_per_processor[ip] * rspd;
3548  }
3549 
3550  // Store and compute the offsets for the data sent to each processor
3551  Vector<int> root_doffsets_send(nproc,0);
3552  root_doffsets_send[0] = 0;
3553  for (unsigned ip = 1; ip < nproc; ip++)
3554  {
3555  // Compute the offset to send the values to each processor
3556  root_doffsets_send[ip] =
3557  root_doffsets_send[ip-1] + root_nddata_to_send[ip-1];
3558  }
3559 
3560  // Number of double data to receive from root
3561  unsigned ndtotal_data_receive = nsegments * rspd;
3562 
3563  if (my_rank!=root_processor)
3564  {
3565  // Create at least one entry so we don't get a seg fault below
3566  if (flat_packed_double_send_data.size()==0)
3567  {
3568  flat_packed_double_send_data.resize(1);
3569  }
3570  }
3571 
3572  // Clear and resize the vector where to receive the info.
3573  flat_packed_double_receive_data.clear();
3574  flat_packed_double_receive_data.resize(ndtotal_data_receive);
3575  // Create at least one entry so we don't get a seg fault below
3576  if (flat_packed_double_receive_data.size()==0)
3577  {
3578  flat_packed_double_receive_data.resize(1);
3579  }
3580 
3581  MPI_Scatterv(&flat_packed_double_send_data[0],
3582  &root_nddata_to_send[0],
3583  &root_doffsets_send[0],
3584  MPI_DOUBLE,
3585  &flat_packed_double_receive_data[0],
3586  ndtotal_data_receive,
3587  MPI_DOUBLE,
3588  root_processor,
3589  comm_pt->mpi_comm());
3590 
3591  // Read if the segments need to be inverted and read the initial
3592  // arclengths
3593  ucounter = 0;
3594  dcounter = 0;
3595 
3596  // Read the info. from the flat package and store it in their
3597  // corresponding containers
3598  for (unsigned is = 0; is < nsegments; is++)
3599  {
3600  // The flat unsigned package
3601  nvertices_before_segment[is] =
3602  flat_packed_unsigned_receive_data[ucounter++];
3603  // The segment inverted flag
3604  segment_inverted[is] = flat_packed_unsigned_receive_data[ucounter++];
3605  // The flat double package
3606  initial_segment_arclength[is] =
3607  flat_packed_double_receive_data[dcounter++];
3608  } // for (is < nsegments)
3609 
3610  // Perform two additional communications to get the total number of
3611  // vertices, the processors with the initial and final segments, the
3612  // corresponding initial and final segments ...
3613  const unsigned numore_info = 5;
3614  Vector<unsigned> flat_package_unsigned_more_info(numore_info);
3615  // Prepare the info ...
3616  flat_package_unsigned_more_info[0] = root_accumulated_vertices_before_segment;
3617  flat_package_unsigned_more_info[1] = proc_with_initial_seg;
3618  flat_package_unsigned_more_info[2] = proc_with_final_seg;
3619  flat_package_unsigned_more_info[3] = initial_segment;
3620  flat_package_unsigned_more_info[4] = final_segment;
3621 
3622  // Send the info. to all processors
3623  MPI_Bcast(&flat_package_unsigned_more_info[0], numore_info,
3624  MPI_UNSIGNED, root_processor, comm_pt->mpi_comm());
3625 
3626  // ... and store the info. in the proper containers
3627  root_accumulated_vertices_before_segment = flat_package_unsigned_more_info[0];
3628  proc_with_initial_seg = flat_package_unsigned_more_info[1];
3629  proc_with_final_seg = flat_package_unsigned_more_info[2];
3630  initial_segment = flat_package_unsigned_more_info[3];
3631  final_segment = flat_package_unsigned_more_info[4];
3632 
3633  // Do the same for the maximum zeta value
3634  MPI_Bcast(&root_accumulated_arclength, 1, MPI_DOUBLE,
3635  root_processor, comm_pt->mpi_comm());
3636 
3637  // -----------------------------------------------------------------
3638  // Clear the storage to store the data that will be used by the
3639  // setup boundary coordinates method, if we do not perform the
3640  // cleaning then previous data from previous iterations will remain
3641  // there
3642  // -----------------------------------------------------------------
3643  // The info. for the boundary
3644  Boundary_initial_coordinate[b].clear();
3645  Boundary_final_coordinate[b].clear();
3646 
3647  Boundary_initial_zeta_coordinate[b].clear();
3648  Boundary_final_zeta_coordinate[b].clear();
3649 
3650  // The info. for the segments
3651  Boundary_segment_inverted[b].clear();
3652  Boundary_segment_initial_coordinate[b].clear();
3653  Boundary_segment_final_coordinate[b].clear();
3654 
3655  Boundary_segment_initial_zeta[b].clear();
3656  Boundary_segment_final_zeta[b].clear();
3657 
3658  Boundary_segment_initial_arclength[b].clear();
3659  Boundary_segment_final_arclength[b].clear();
3660 
3661  // Now copy all the info. to the containers to be sent to any other
3662  // mesh (in the adaptation method)
3663  for (unsigned is = 0; is < nsegments; is++)
3664  {
3665  // At this point we can get the initial and final coordinates for
3666  // each segment
3667  Vector<double> first_seg_coord(2);
3668  Vector<double> last_seg_coord(2);
3669 
3670  // In order to get the first and last coordinates of each segment we
3671  // first need to identify the first and last nonhalo element of each
3672  // segment, and then get the first and last node of the segment
3673 
3674  // Get the first nonhalo face element on the segment
3675  FiniteElement* first_seg_ele_pt =
3676  segment_sorted_nonhalo_ele_pt[is].front();
3677 
3678 #ifdef PARANOID
3679  // Check if the face element is nonhalo, it shouldn't, but better
3680  // check
3681  if (first_seg_ele_pt->is_halo())
3682  {
3683  std::ostringstream error_message;
3684  error_message
3685  << "The first face element in the (" << is << ")-th segment is halo\n";
3686  throw OomphLibError(error_message.str(),
3687  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3688  OOMPH_EXCEPTION_LOCATION);
3689  } // if (tmp_first_bulk_ele_pt->is_halo())
3690 #endif
3691 
3692  // Number of nodes
3693  const unsigned nnod = first_seg_ele_pt->nnode();
3694 
3695  // Get the first node of the current segment
3696  Node *first_seg_node_pt = first_seg_ele_pt->node_pt(0);
3697  if (is_inverted[first_seg_ele_pt])
3698  {
3699  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);
3700  }
3701 
3702  // Get the last nonhalo face element on the segment
3703  FiniteElement* last_seg_ele_pt =
3704  segment_sorted_nonhalo_ele_pt[is].back();
3705 
3706 #ifdef PARANOID
3707  // Check if the face element is nonhalo, it shouldn't, but better
3708  // check
3709  if (last_seg_ele_pt->is_halo())
3710  {
3711  std::ostringstream error_message;
3712  error_message
3713  << "The last face element in the (" << is << ")-th segment is halo\n";
3714  throw OomphLibError(error_message.str(),
3715  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3716  OOMPH_EXCEPTION_LOCATION);
3717  } // if (tmp_first_bulk_ele_pt->is_halo())
3718 #endif
3719 
3720  // Get the last node of the current segment
3721  Node *last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
3722  if (is_inverted[last_seg_ele_pt])
3723  {
3724  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
3725  }
3726 
3727  // Get the coordinates for the first and last segment's node
3728  for (unsigned i = 0; i < 2; i++)
3729  {
3730  first_seg_coord[i] = first_seg_node_pt->x(i);
3731  last_seg_coord[i] = last_seg_node_pt->x(i);
3732  }
3733 
3734  // -----------------------------------------------------------------
3735  // Copy the info. if the segment is inverted
3736  Boundary_segment_inverted[b].push_back(segment_inverted[is]);
3737 
3738  // Check if the segment is inverted, if that is the case then invert
3739  // the first and last seg. coordinates
3740  if (!segment_inverted[is])
3741  {
3742  // Store the initial and final coordinates that will help to
3743  // identify the segments in the new meshes created from this one
3744  Boundary_segment_initial_coordinate[b].push_back(first_seg_coord);
3745  Boundary_segment_final_coordinate[b].push_back(last_seg_coord);
3746  }
3747  else
3748  {
3749  // Store the initial and final coordinates that will help to
3750  // identify the segments in the new meshes created from this one
3751  // Invert the initial and final coordinates
3752  Boundary_segment_initial_coordinate[b].push_back(last_seg_coord);
3753  Boundary_segment_final_coordinate[b].push_back(first_seg_coord);
3754  }
3755 
3756  // Now assign initial and final zeta boundary coordinates for each
3757  // segment
3758  // -----------------------------------------------------------------
3759  // If there is a geom object then
3760  if (boundary_geom_object_pt(b)!=0)
3761  {
3762  // Store the initial and final zeta for the current segments (we
3763  // got this when we assigned arclength to the segments in the
3764  // current processor)
3765  if (segment_inverted[is])
3766  {
3767  Boundary_segment_initial_zeta[b].push_back(final_zeta_segment[is]);
3768  Boundary_segment_final_zeta[b].push_back(initial_zeta_segment[is]);
3769  }
3770  else
3771  {
3772  Boundary_segment_initial_zeta[b].push_back(initial_zeta_segment[is]);
3773  Boundary_segment_final_zeta[b].push_back(final_zeta_segment[is]);
3774  }
3775  } // if (boundary_geom_object_pt(b)!=0)
3776  else
3777  {
3778  // Store the initial arclength and vertices number for the
3779  // current segment
3780  Boundary_segment_initial_arclength[b].push_back(
3781  initial_segment_arclength[is]);
3782 
3783  Boundary_segment_final_arclength[b].push_back(
3784  initial_segment_arclength[is] + segment_arclength[is]);
3785 
3786  } // else if (boundary_geom_object_pt(b)!=0)
3787 
3788  } // // for (is < nsegments)
3789 
3790  // Get the number of segments from the sets of nodes
3791 #ifdef PARANOID
3792  if (segment_all_nodes_pt.size() != nsegments)
3793  {
3794  std::ostringstream error_message;
3795  error_message
3796  <<"The number of segments ("<<nsegments<<") and the number of "
3797  <<"set of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
3798  <<"the\nsegments is different!!!\n\n";
3799  throw OomphLibError(error_message.str(),
3800  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3801  OOMPH_EXCEPTION_LOCATION);
3802  }
3803 #endif
3804 
3805  // The nodes have been assigned arc-length coordinates from one end
3806  // or the other of the connected segment.
3807 
3808  // -----------------------------------------------------------------
3809  // If mesh is distributed get the info. regarding the initial and
3810  // final nodes coordinates on the boundary, same as the zeta
3811  // boundary values for those nodes
3812 
3813  // Storage for the coordinates of the first and last nodes on the
3814  // boundary
3815  Vector<double> first_coordinate(2);
3816  Vector<double> last_coordinate(2);
3817 
3818  // Storage for the zeta coordinate of the first and last nodes on
3819  // the boundary
3820  Vector<double> first_node_zeta_coordinate(1,0.0);
3821  Vector<double> last_node_zeta_coordinate(1,0.0);
3822 
3823  // Send three data to all processors, the x[0], x[1] coordinate and
3824  // the zeta coordinate
3825  const unsigned ndtotal_data = 3;
3826  Vector<double> flat_packed_double_data_initial_seg(ndtotal_data);
3827 
3828  // If the mesh is distributed then check if this processor has the
3829  // initial segment
3830  if (my_rank == proc_with_initial_seg)
3831  {
3832  // Stores the firts element of the segment
3833  FiniteElement* first_ele_pt = 0;
3834  // Stores the first node of the boundary
3835  Node *first_node_pt = 0;
3836  // Check if the segment is inverted
3837  if (!segment_inverted[initial_segment])
3838  {
3839  // Get access to the first element on the segment marked as
3840  // initial
3841  first_ele_pt = segment_sorted_ele_pt[initial_segment].front();
3842 
3843  // Number of nodes
3844  const unsigned nnod = first_ele_pt->nnode();
3845 
3846  // Get the first node of the current segment
3847  first_node_pt = first_ele_pt->node_pt(0);
3848  if (is_inverted[first_ele_pt])
3849  {
3850  first_node_pt = first_ele_pt->node_pt(nnod-1);
3851  }
3852  } // if (!segment_inverted[initial_segment])
3853  else
3854  {
3855  // Get access to the first element on the segment marked as
3856  // initial
3857  first_ele_pt = segment_sorted_ele_pt[initial_segment].back();
3858 
3859  // Number of nodes
3860  const unsigned nnod = first_ele_pt->nnode();
3861 
3862  // Get the first node of the current segment
3863  first_node_pt = first_ele_pt->node_pt(nnod-1);
3864  if (is_inverted[first_ele_pt])
3865  {
3866  first_node_pt = first_ele_pt->node_pt(0);
3867  }
3868  } // else if (!segment_inverted[initial_segment])
3869 
3870  // Get the coordinates for the first node
3871  for (unsigned i = 0; i < 2; i++)
3872  {
3873  flat_packed_double_data_initial_seg[i] = first_node_pt->x(i);
3874  }
3875 
3876  // Get the zeta coordinates for the first node
3877  Vector<double> tmp_zeta(1);
3878  first_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3879 
3880  // If there is a geometric object associated to the boundary then
3881  // further process is necessary
3882  if (this->boundary_geom_object_pt(b)!=0)
3883  {
3884  //tmp_zeta[0] = this->boundary_coordinate_limits(b)[0];
3885  }
3886  else
3887  {
3888  // Check if the initial boundary coordinate is different from
3889  // zero, if that is the case then we need to set it to zero
3890  if (tmp_zeta[0] >= 1.0e-14)
3891  {
3892  tmp_zeta[0]=0;
3893  }
3894  } // if (this->boundary_geom_object_pt(b)!=0)
3895 
3896  // Store the initial zeta value
3897  flat_packed_double_data_initial_seg[2] = tmp_zeta[0];
3898 
3899  } // if (my_rank == proc_with_initial_seg)
3900 
3901  // All processor receive the info. from the processor that has the
3902  // initial segment
3903  MPI_Bcast(&flat_packed_double_data_initial_seg[0], ndtotal_data,
3904  MPI_DOUBLE, proc_with_initial_seg, comm_pt->mpi_comm());
3905 
3906  // ... and all processor put that info. into the appropriate
3907  // storages
3908  for (unsigned i = 0; i < 2; i++)
3909  {
3910  first_coordinate[i] = flat_packed_double_data_initial_seg[i];
3911  }
3912  first_node_zeta_coordinate[0]=flat_packed_double_data_initial_seg[2];
3913 
3914  // -----------------------------------------------------------------
3915  // Send three data to all processors, the x[0], x[1] coordinate and
3916  // the zeta coordinate
3917  Vector<double> flat_packed_double_data_final_seg(ndtotal_data);
3918 
3919  // If the mesh is distributed then check if this processor has the
3920  // final segment
3921  if (my_rank == proc_with_final_seg)
3922  {
3923  // Get access to the last element on the segment
3924  FiniteElement* last_ele_pt = 0;
3925 
3926  // Get the last node of the current segment
3927  Node *last_node_pt = 0;
3928 
3929  // Check if the segment is inverted
3930  if (!segment_inverted[final_segment])
3931  {
3932  // Get access to the last element on the segment marked as
3933  // final
3934  last_ele_pt = segment_sorted_ele_pt[final_segment].back();
3935 
3936  // Number of nodes
3937  const unsigned nnod = last_ele_pt->nnode();
3938 
3939  // Get the last node of the current segment
3940  last_node_pt = last_ele_pt->node_pt(nnod-1);
3941  if (is_inverted[last_ele_pt])
3942  {
3943  last_node_pt = last_ele_pt->node_pt(0);
3944  }
3945  } // if (!segment_inverted[final_segment])
3946  else
3947  {
3948  // Get access to the first element on the segment marked as
3949  // initial
3950  last_ele_pt = segment_sorted_ele_pt[final_segment].front();
3951 
3952  // Number of nodes
3953  const unsigned nnod = last_ele_pt->nnode();
3954 
3955  // Get the first node of the current segment
3956  last_node_pt = last_ele_pt->node_pt(0);
3957  if (is_inverted[last_ele_pt])
3958  {
3959  last_node_pt = last_ele_pt->node_pt(nnod-1);
3960  }
3961  } // if (!segment_inverted[final_segment])
3962 
3963  // Get the coordinates for the last node
3964  for (unsigned i = 0; i < 2; i++)
3965  {
3966  flat_packed_double_data_final_seg[i]=last_node_pt->x(i);
3967  }
3968 
3969  // Get the zeta coordinates for the last node
3970  Vector<double> tmp_zeta(1);
3971  last_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3972 
3973  // If there is not a geometric object associated to the boundary
3974  // then further process is required
3975  if (this->boundary_geom_object_pt(b)!=0)
3976  {
3977  // Do nothing
3978  } // if (this->boundary_geom_object_pt(b)!=0)
3979  else
3980  {
3981  // Check if the final boundary coordinate is different from
3982  // the boundary arclength, if that is the case then we need
3983  // to set it to the accumulated arclength
3984  if (std::fabs(tmp_zeta[0] - root_accumulated_arclength) >= 1.0e-14)
3985  {
3986  tmp_zeta[0] = root_accumulated_arclength;
3987  }
3988  } // else if (this->boundary_geom_object_pt(b)!=0)
3989 
3990  // Store the final zeta value
3991  flat_packed_double_data_final_seg[2] = tmp_zeta[0];
3992 
3993  } // if (my_rank == proc_with_final_seg)
3994 
3995  // All processor receive the info. from the processor that has the
3996  // final segment
3997  MPI_Bcast(&flat_packed_double_data_final_seg[0], ndtotal_data,
3998  MPI_DOUBLE, proc_with_final_seg, comm_pt->mpi_comm());
3999 
4000  // All processor receive the info. from the processor that has the
4001  // final segment
4002  for (unsigned i = 0; i < 2; i++)
4003  {
4004  last_coordinate[i] = flat_packed_double_data_final_seg[i];
4005  }
4006  last_node_zeta_coordinate[0]=flat_packed_double_data_final_seg[2];
4007 
4008  // -----------------------------------------------------------------
4009  // Copy the values to the permanent storage
4010  Boundary_initial_coordinate[b] = first_coordinate;
4011  Boundary_final_coordinate[b] = last_coordinate;
4012 
4013  Boundary_initial_zeta_coordinate[b] = first_node_zeta_coordinate;
4014  Boundary_final_zeta_coordinate[b] = last_node_zeta_coordinate;
4015 
4016  // If we are dealing with an internal boundary then re-assign the
4017  // initial and final zeta values for the segments
4018  if (is_internal_boundary)
4019  {
4020  // Only re-assign zeta values if there are at least one nonhalo
4021  // segment, if all the possible segments are halo then the
4022  // synchronisation method will be in charge of assigning the
4023  // correct boundary coordinates
4024  if (nsegments > 0)
4025  {
4026  // Call the following method to re-construct the segments but
4027  // using only the nonhalo elements, therefore the boundary
4028  // coordinates need to be re-assigned
4029  re_assign_initial_zeta_values_for_internal_boundary(
4030  b, segment_sorted_nonhalo_ele_pt, is_inverted);
4031  }
4032 
4033  } // if (is_internal_boundary)
4034 
4035  // Now identify the boundary segments
4036  if (nsegments > 0)
4037  {
4038  // Identify the boundary segments in the current mesh
4039  //identify_boundary_segments_and_assign_initial_zeta_values(
4040  // b, all_face_ele_pt, is_internal_boundary, face_to_bulk_element_pt);
4041  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
4042  } // if (nsegments > 0)
4043 
4044  // Clean all the created face elements
4045  for (unsigned i = 0; i < n_all_face_ele; i++)
4046  {
4047  delete all_face_ele_pt[i];
4048  all_face_ele_pt[i] = 0;
4049  }
4050 
4051  }
4052 
4053  //======================================================================
4054  /// \short Re-assign the boundary segments initial zeta (arclength)
4055  /// for those internal boundaries that were splited during the
4056  /// distribution process. Those boundaries that have one face element
4057  /// at each side of the boundary. Here we create the segments only
4058  /// with the nonhalo elements, therefore the boundary coordinates
4059  /// need to be re-assigned to be passed to the new meshes
4060  //======================================================================
4061  template<class ELEMENT>
4064  const unsigned& b,
4065  Vector<std::list<FiniteElement*> > &old_segment_sorted_ele_pt,
4066  std::map<FiniteElement*, bool> &old_is_inverted)
4067  {
4068  // ------------------------------------------------------------------
4069  // First: Get the face elements associated with the current boundary
4070  // Only include nonhalo face elements
4071  // ------------------------------------------------------------------
4072  // Temporary storage for face elements
4073  Vector<FiniteElement*> face_el_pt;
4074 
4075  // Temporary storage for the number of elements adjacent to the
4076  // boundary
4077  unsigned nele = 0;
4078 
4079  // Temporary storage for elements adjacent to the boundary that have
4080  // a common edge (related with internal boundaries)
4081  unsigned n_repeated_ele = 0;
4082 
4083  const unsigned n_regions = this->nregion();
4084 
4085  // Temporary storage for already done nodes
4086  Vector<std::pair<Node*, Node*> > done_nodes_pt;
4087 
4088  // If there is more than one region then only use boundary
4089  // coordinates from the bulk side (region 0)
4090  if (n_regions > 1)
4091  {
4092  for (unsigned rr = 0 ; rr < n_regions; rr++)
4093  {
4094  const unsigned region_id =
4095  static_cast<unsigned>(this->Region_attribute[rr]);
4096 
4097  // Loop over all elements on boundaries in region i_r
4098  const unsigned nel_in_region =
4099  this->nboundary_element_in_region(b, region_id);
4100 
4101  unsigned nel_repetead_in_region = 0;
4102 
4103  // Only bother to do anything else, if there are elements
4104  // associated with the boundary and the current region
4105  if (nel_in_region > 0)
4106  {
4107  bool repeated = false;
4108 
4109  // Loop over the bulk elements adjacent to boundary b
4110  for (unsigned e = 0; e < nel_in_region; e++)
4111  {
4112  // Get pointer to the bulk element that is adjacent to
4113  // boundary b
4114  FiniteElement* bulk_elem_pt =
4115  this->boundary_element_in_region_pt(b, region_id, e);
4116 
4117  // Remember only work with non halo elements
4118  if (bulk_elem_pt->is_halo())
4119  {
4120  n_repeated_ele++;
4121  continue;
4122  }
4123 
4124  // Find the index of the face of element e along boundary b
4125  int face_index =
4126  this->face_index_at_boundary_in_region(b,region_id,e);
4127 
4128  // Before adding the new element we need to be sure that the
4129  // edge that this element represent has not been already
4130  // added
4131  FiniteElement* tmp_ele_pt =
4132  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4133 
4134  const unsigned n_nodes = tmp_ele_pt->nnode();
4135 
4136  std::pair<Node*, Node*> tmp_pair =
4137  std::make_pair(tmp_ele_pt->node_pt(0),
4138  tmp_ele_pt->node_pt(n_nodes - 1));
4139 
4140  std::pair<Node*, Node*> tmp_pair_inverse =
4141  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4142  tmp_ele_pt->node_pt(0));
4143 
4144  // Search for repeated nodes
4145  const unsigned repeated_nodes_size = done_nodes_pt.size();
4146  for (unsigned l = 0; l < repeated_nodes_size; l++)
4147  {
4148  if (tmp_pair == done_nodes_pt[l] ||
4149  tmp_pair_inverse == done_nodes_pt[l])
4150  {
4151  nel_repetead_in_region++;
4152  repeated = true;
4153  break;
4154  }
4155  }
4156 
4157  // Create new face element
4158  if (!repeated)
4159  {
4160  // Add the pair of nodes (edge) to the node dones
4161  done_nodes_pt.push_back(tmp_pair);
4162  // Add the element to the face elements
4163  face_el_pt.push_back(tmp_ele_pt);
4164  }
4165  else
4166  {
4167  // Clean up
4168  delete tmp_ele_pt;
4169  tmp_ele_pt = 0;
4170  }
4171 
4172  // Re-start
4173  repeated = false;
4174 
4175  } // for nel
4176 
4177  nele += nel_in_region;
4178 
4179  n_repeated_ele += nel_repetead_in_region;
4180 
4181  } // if (nel_in_region > 0)
4182  } // for (rr < n_regions)
4183  } // if (n_regions > 1)
4184  //Otherwise it's just the normal boundary functions
4185  else
4186  {
4187  // Loop over all elements on boundaries
4188  nele = this->nboundary_element(b);
4189 
4190  //Only bother to do anything else, if there are elements
4191  if (nele > 0)
4192  {
4193  // Check for repeated ones
4194  bool repeated = false;
4195 
4196  // Loop over the bulk elements adjacent to boundary b
4197  for (unsigned e = 0; e < nele; e++)
4198  {
4199  // Get pointer to the bulk element that is adjacent to
4200  // boundary b
4201  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
4202 
4203  // Skip the halo elements, they are not included
4204  if (bulk_elem_pt->is_halo())
4205  {
4206  n_repeated_ele++;
4207  continue;
4208  }
4209 
4210  //Find the index of the face of element e along boundary b
4211  int face_index = this->face_index_at_boundary(b, e);
4212 
4213  // Before adding the new element we need to be sure that the
4214  // edge that this element represents has not been already
4215  // added (only applies for internal boundaries)
4216  FiniteElement* tmp_ele_pt =
4217  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4218 
4219  const unsigned n_nodes = tmp_ele_pt->nnode();
4220 
4221  std::pair<Node*, Node*> tmp_pair =
4222  std::make_pair(tmp_ele_pt->node_pt(0),
4223  tmp_ele_pt->node_pt(n_nodes - 1));
4224 
4225  std::pair<Node*, Node*> tmp_pair_inverse =
4226  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4227  tmp_ele_pt->node_pt(0));
4228 
4229  // Search for repeated nodes
4230  const unsigned repeated_nodes_size = done_nodes_pt.size();
4231  for (unsigned l = 0; l < repeated_nodes_size; l++)
4232  {
4233  if (tmp_pair == done_nodes_pt[l] ||
4234  tmp_pair_inverse == done_nodes_pt[l])
4235  {
4236  // Increase the number of repeated elements
4237  n_repeated_ele++;
4238  // Mark the element as repeated
4239  repeated = true;
4240  break;
4241  }
4242  }
4243 
4244  // Create new face element
4245  if (!repeated)
4246  {
4247  // Add the pair of nodes (edge) to the node dones
4248  done_nodes_pt.push_back(tmp_pair);
4249  // Add the element to the face elements
4250  face_el_pt.push_back(tmp_ele_pt);
4251  }
4252  else
4253  {
4254  // Free the repeated bulk element!!
4255  delete tmp_ele_pt;
4256  tmp_ele_pt = 0;
4257  }
4258 
4259  // Re-start
4260  repeated = false;
4261 
4262  } // for (e < nel)
4263  } // if (nel > 0)
4264 
4265  } // else (n_regions > 1)
4266 
4267  // Do not consider the repeated elements
4268  nele-= n_repeated_ele;
4269 
4270 #ifdef PARANOID
4271  if (nele!=face_el_pt.size())
4272  {
4273  std::ostringstream error_message;
4274  error_message
4275  << "The independet counting of face elements ("<<nele<<") for "
4276  << "boundary ("<<b<<") is different\n"
4277  << "from the real number of face elements in the container ("
4278  << face_el_pt.size() <<")\n";
4279  //<< "Possible memory leak\n"
4280  throw OomphLibError(error_message.str(),
4281  OOMPH_CURRENT_FUNCTION,
4282  OOMPH_EXCEPTION_LOCATION);
4283  }
4284 #endif
4285 
4286  // ----------------------------------------------------------------
4287  // Second: Sort the face elements, only consider nonhalo elements
4288  // ----------------------------------------------------------------
4289 
4290  // Get the total number of nonhalo face elements
4291  const unsigned nnon_halo_face_elements = face_el_pt.size();
4292 
4293  // The vector of list to store the "segments" that compound the
4294  // boundary (segments may appear only in a distributed mesh)
4295  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
4296 
4297  // Number of already sorted face elements
4298  unsigned nsorted_face_elements = 0;
4299 
4300  // Keep track of who's done
4301  std::map<FiniteElement*, bool> done_el;
4302 
4303  // Keep track of which element is inverted
4304  std::map<FiniteElement*, bool> is_inverted;
4305 
4306  // Iterate until all possible segments have been created
4307  while(nsorted_face_elements < nnon_halo_face_elements)
4308  {
4309  // The ordered list of face elements (in a distributed mesh a
4310  // collection of contiguous face elements define a segment)
4311  std::list<FiniteElement*> sorted_el_pt;
4312 
4313 #ifdef PARANOID
4314  // Select an initial element for the segment
4315  bool found_initial_face_element = false;
4316 #endif
4317 
4318  FiniteElement* ele_face_pt = 0;
4319 
4320  unsigned iface = 0;
4321  for (iface = 0; iface < nele; iface++)
4322  {
4323  ele_face_pt = face_el_pt[iface];
4324  // If not done then take it as initial face element
4325  if (!done_el[ele_face_pt])
4326  {
4327 #ifdef PARANOID
4328  // Mark as found the root face element
4329  found_initial_face_element = true;
4330 #endif
4331  // Increase the number of sorted face elements
4332  nsorted_face_elements++;
4333  // Increase the counter to mark the position of the next
4334  // element number
4335  iface++;
4336  // Add the face element in the list of sorted face elements
4337  sorted_el_pt.push_back(ele_face_pt);
4338  // Mark as done
4339  done_el[ele_face_pt] = true;
4340  break;
4341  } // if (!done_el[ele_face_pt])
4342  } // for (iface < nele)
4343 
4344 #ifdef PARANOID
4345  if (!found_initial_face_element)
4346  {
4347  std::ostringstream error_message;
4348  error_message
4349  <<"Could not find an initial face element for the current segment\n";
4350  throw OomphLibError(error_message.str(),
4351  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4352  OOMPH_EXCEPTION_LOCATION);
4353  }
4354 #endif
4355 
4356  // Number of nodes
4357  const unsigned nnod = ele_face_pt->nnode();
4358 
4359  // Left and rightmost nodes (the left and right nodes of the
4360  // current face element)
4361  Node* left_node_pt = ele_face_pt->node_pt(0);
4362  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
4363 
4364  // Continue iterating if a new face element has been added to the
4365  // list
4366  bool face_element_added = false;
4367 
4368  // While a new face element has been added to the set of sorted
4369  // face elements then re-iterate
4370  do
4371  {
4372  // Start from the next face element since we have already added
4373  // the previous one as the initial face element (any previous
4374  // face element had to be added on previous iterations)
4375  for (unsigned iiface = iface; iiface < nele; iiface++)
4376  {
4377  // Re-start flag
4378  face_element_added = false;
4379 
4380  // Get the candidate element
4381  ele_face_pt = face_el_pt[iiface];
4382 
4383  // Check that the candidate element has not been done and is
4384  // not a halo element
4385  if (!(done_el[ele_face_pt]))
4386  {
4387  // Get the left and right nodes of the current element
4388  Node* local_left_node_pt = ele_face_pt->node_pt(0);
4389  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
4390 
4391  // New element fits at the left of segment and is not inverted
4392  if (left_node_pt == local_right_node_pt)
4393  {
4394  left_node_pt = local_left_node_pt;
4395  sorted_el_pt.push_front(ele_face_pt);
4396  is_inverted[ele_face_pt] = false;
4397  face_element_added = true;
4398  }
4399  // New element fits at the left of segment and is inverted
4400  else if (left_node_pt == local_left_node_pt)
4401  {
4402  left_node_pt = local_right_node_pt;
4403  sorted_el_pt.push_front(ele_face_pt);
4404  is_inverted[ele_face_pt] = true;
4405  face_element_added = true;
4406  }
4407  // New element fits on the right of segment and is not inverted
4408  else if (right_node_pt == local_left_node_pt)
4409  {
4410  right_node_pt = local_right_node_pt;
4411  sorted_el_pt.push_back(ele_face_pt);
4412  is_inverted[ele_face_pt] = false;
4413  face_element_added = true;
4414  }
4415  // New element fits on the right of segment and is inverted
4416  else if (right_node_pt == local_right_node_pt)
4417  {
4418  right_node_pt = local_left_node_pt;
4419  sorted_el_pt.push_back(ele_face_pt);
4420  is_inverted[ele_face_pt] = true;
4421  face_element_added = true;
4422  }
4423 
4424  if (face_element_added)
4425  {
4426  done_el[ele_face_pt] = true;
4427  nsorted_face_elements++;
4428  break;
4429  } // if (face_element_added)
4430 
4431  } // if (!(done_el[ele_face_pt]))
4432 
4433  } // for (iiface<nnon_halo_face_element)
4434 
4435  }while(face_element_added &&
4436  (nsorted_face_elements < nnon_halo_face_elements));
4437 
4438  // Store the created segment in the vector of segments
4439  segment_sorted_ele_pt.push_back(sorted_el_pt);
4440 
4441  } // while(nsorted_face_elements < nnon_halo_face_elements);
4442 
4443  // --------------------------------------------------------------
4444  // Third: We have the face elements sorted, now assign boundary
4445  // coordinates to the nodes in the segments and compute the
4446  // arclength of the segment.
4447  // --------------------------------------------------------------
4448 
4449  // The number of segments in this processor
4450  const unsigned nsegments = segment_sorted_ele_pt.size();
4451 
4452 #ifdef PARANOID
4453  if (nnon_halo_face_elements > 0 && nsegments == 0)
4454  {
4455  std::ostringstream error_message;
4456  error_message
4457  << "The number of segments is zero, but the number of nonhalo\n"
4458  << "elements is: (" << nnon_halo_face_elements << ")\n";
4459  throw OomphLibError(error_message.str(),
4460  OOMPH_CURRENT_FUNCTION,
4461  OOMPH_EXCEPTION_LOCATION);
4462  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
4463 #endif
4464 
4465  // Vector of sets that stores the nodes of each segment based on a
4466  // lexicographically order starting from the bottom left node of
4467  // each segment
4468  Vector<std::set<Node*> > segment_all_nodes_pt(nsegments);
4469 
4470  // Stores the nodes on each segment in the order they appear in the
4471  // face elements
4472  Vector<Vector<Node*> > sorted_segment_all_nodes_pt(nsegments);
4473 
4474  // Associate and arclength to each node on each segment of the
4475  // boundary, the nodes and therefore the arclength come in the same
4476  // order as the face elements
4477  Vector<Vector<double> > sorted_segment_node_arclength(nsegments);
4478 
4479  // The arclength of each segment in the current processor
4480  Vector<double> segment_arclength(nsegments);
4481 
4482  // The number of vertices of each segment
4483  Vector<unsigned> nvertices_per_segment(nsegments);
4484 
4485  // The initial zeta for the segment
4486  Vector<double> initial_zeta_segment(nsegments);
4487 
4488  // The final zeta for the segment
4489  Vector<double> final_zeta_segment(nsegments);
4490 
4491  // Go through all the segments and compute the LOCAL boundary
4492  // coordinates
4493  for (unsigned is = 0; is < nsegments; is++)
4494  {
4495 #ifdef PARANOID
4496  if (segment_sorted_ele_pt[is].size() == 0)
4497  {
4498  std::ostringstream error_message;
4499  error_message
4500  << "The (" << is << ")-th segment has no elements\n";
4501  throw OomphLibError(error_message.str(),
4502  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4503  OOMPH_EXCEPTION_LOCATION);
4504  } // if (segment_sorted_ele_pt[is].size() == 0)
4505 #endif
4506 
4507  // Get access to the first element on the segment
4508  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
4509 
4510  // Number of nodes
4511  const unsigned nnod = first_ele_pt->nnode();
4512 
4513  // Get the first node of the current segment
4514  Node *first_node_pt = first_ele_pt->node_pt(0);
4515  if (is_inverted[first_ele_pt])
4516  {
4517  first_node_pt = first_ele_pt->node_pt(nnod-1);
4518  }
4519 
4520  // Coordinates of left node
4521  double x_left = first_node_pt->x(0);
4522  double y_left = first_node_pt->x(1);
4523 
4524  // Initialise boundary coordinate (local boundary coordinate for
4525  // boundaries with more than one segment)
4526  Vector<double> zeta(1, 0.0);
4527 
4528  // If we have associated a GeomObject then it is not necessary
4529  // to compute the arclength, only read the values from the nodes at
4530  // the edges
4531  if (this->boundary_geom_object_pt(b)!=0)
4532  {
4533  first_node_pt->get_coordinates_on_boundary(b, zeta);
4534  initial_zeta_segment[is] = zeta[0];
4535 
4536  // Get access to the last element on the segment
4537  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
4538 
4539  // Get the last node of the current segment
4540  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
4541  if (is_inverted[last_ele_pt])
4542  {
4543  last_node_pt = last_ele_pt->node_pt(0);
4544  }
4545 
4546  last_node_pt->get_coordinates_on_boundary(b, zeta);
4547  final_zeta_segment[is] = zeta[0];
4548  }
4549 
4550  // Sort the nodes in the segment (lexicographically bottom left
4551  // node)
4552  std::set<Node*> local_nodes_pt;
4553  local_nodes_pt.insert(first_node_pt);
4554 
4555  // Associate and arclength to the sorted nodes
4556  Vector<double> sorted_node_arclength;
4557  sorted_node_arclength.push_back(0.0);
4558 
4559  // Sorts the nodes in the segments according their sorting in the
4560  // face elements
4561  Vector<Node*> sorted_nodes_pt;
4562  sorted_nodes_pt.push_back(first_node_pt);
4563 
4564  // Now loop over nodes in order
4565  for (std::list<FiniteElement*>::iterator it =
4566  segment_sorted_ele_pt[is].begin();
4567  it != segment_sorted_ele_pt[is].end(); it++)
4568  {
4569  // Get the face element
4570  FiniteElement* el_pt = *it;
4571 
4572  // Start node and increment
4573  unsigned k_nod = 1;
4574  int nod_diff = 1;
4575  if (is_inverted[el_pt])
4576  {
4577  k_nod = nnod - 2;
4578  nod_diff = -1;
4579  }
4580 
4581  // Loop over nodes
4582  for (unsigned j = 1; j < nnod; j++)
4583  {
4584  Node* nod_pt = el_pt->node_pt(k_nod);
4585  k_nod += nod_diff;
4586 
4587  // Coordinates of right node
4588  double x_right = nod_pt->x(0);
4589  double y_right = nod_pt->x(1);
4590 
4591  // Increment boundary coordinate
4592  zeta[0] += sqrt(
4593  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
4594  * (y_right - y_left));
4595 
4596  // When we have a GeomObject associated to the boundary we already
4597  // know the zeta values for the nodes, there is no need to compute
4598  // the arclength
4599  if (this->boundary_geom_object_pt(b)==0)
4600  {
4601  // Set boundary coordinate
4602 // nod_pt->set_coordinates_on_boundary(b, zeta);
4603  }
4604 
4605  // Increment reference coordinate
4606  x_left = x_right;
4607  y_left = y_right;
4608 
4609  // Get lexicographically bottom left node but only
4610  // use vertex nodes as candidates
4611  local_nodes_pt.insert(nod_pt);
4612 
4613  // Associate the arclength for the current node
4614  sorted_node_arclength.push_back(zeta[0]);
4615 
4616  // Store the node in the sorted nodes storage
4617  sorted_nodes_pt.push_back(nod_pt);
4618 
4619  } // for (j < nnod)
4620 
4621  } // iterator over the elements in the segment
4622 
4623  // Info. to be passed to the other processors
4624  // The initial arclength for the segment that goes after this depends
4625  // on the current segment arclength
4626  segment_arclength[is] = zeta[0];
4627 
4628  // Info. to be passed to the other processors
4629  // The initial vertex number for the segment that goes after this
4630  // depends on the current sement vertices number
4631  nvertices_per_segment[is] = local_nodes_pt.size();
4632 
4633  // Add the nodes for the corresponding segment in the container
4634  segment_all_nodes_pt[is] = local_nodes_pt;
4635 
4636  // Add the arclengths to the nodes in the segment
4637  sorted_segment_node_arclength[is] = sorted_node_arclength;
4638 
4639  // Add the sorted nodes to the storage
4640  sorted_segment_all_nodes_pt[is] = sorted_nodes_pt;
4641 
4642  // The attaching of the halo elements at both sides of the segments is
4643  // performed only if segments connectivity needs to be computed
4644 
4645  } // for (is < nsegments)
4646 
4647  // ------------------------------------------------------------------
4648  // Fourth: Now we have the segments sorted, with arclength and with
4649  // LOCAL boundary coordinates assigned to the nodes. Identify the
4650  // nodes on the segments with the input segments and re-assign all
4651  // the info. related with the identification of segments
4652  // ------------------------------------------------------------------
4653 
4654  // Get the number of segments for the old sorted segments
4655  const unsigned old_nsegments = old_segment_sorted_ele_pt.size();
4656 
4657  // ------------------------------------------------------------------
4658  // Copy the old info. in temporary storages
4659  Vector<unsigned> old_boundary_segment_inverted(old_nsegments);
4660 
4662  old_boundary_segment_initial_coordinate(old_nsegments);
4664  old_boundary_segment_final_coordinate(old_nsegments);
4665 
4666  Vector<double> old_boundary_segment_initial_zeta(old_nsegments);
4667  Vector<double> old_boundary_segment_final_zeta(old_nsegments);
4668 
4669  Vector<double> old_boundary_segment_initial_arclength(old_nsegments);
4670  Vector<double> old_boundary_segment_final_arclength(old_nsegments);
4671 
4672  // Back-up the information
4673  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4674  {
4675  old_boundary_segment_inverted[old_is] =
4676  boundary_segment_inverted(b)[old_is];
4677 
4678  old_boundary_segment_initial_coordinate[old_is].resize(2);
4679  old_boundary_segment_final_coordinate[old_is].resize(2);
4680  for (unsigned i = 0; i < 2; i++)
4681  {
4682  old_boundary_segment_initial_coordinate[old_is][i] =
4683  boundary_segment_initial_coordinate(b)[old_is][i];
4684 
4685  old_boundary_segment_final_coordinate[old_is][i] =
4686  boundary_segment_final_coordinate(b)[old_is][i];
4687  }
4688 
4689  // Check if the boundary has an associated GeomObject
4690  if (this->boundary_geom_object_pt(b)!=0)
4691  {
4692  old_boundary_segment_initial_zeta[old_is] =
4693  boundary_segment_initial_zeta(b)[old_is];
4694 
4695  old_boundary_segment_final_zeta[old_is] =
4696  boundary_segment_final_zeta(b)[old_is];
4697 
4698  } // if (this->boundary_geom_object_pt(b)!=0)
4699  else
4700  {
4701  old_boundary_segment_initial_arclength[old_is] =
4702  boundary_segment_initial_arclength(b)[old_is];
4703 
4704  old_boundary_segment_final_arclength[old_is] =
4705  boundary_segment_final_arclength(b)[old_is];
4706 
4707  } // else if (this->boundary_geom_object_pt(b)!=0)
4708 
4709  } // for (old_is < old_nsegments)
4710 
4711  // ------------------------------------------------------------------
4712  // Now clear the original storages
4713  Boundary_segment_inverted[b].clear();
4714  Boundary_segment_initial_coordinate[b].clear();
4715  Boundary_segment_final_coordinate[b].clear();
4716 
4717  Boundary_segment_initial_zeta[b].clear();
4718  Boundary_segment_final_zeta[b].clear();
4719 
4720  Boundary_segment_initial_arclength[b].clear();
4721  Boundary_segment_final_arclength[b].clear();
4722  // ------------------------------------------------------------------
4723  // .. and resize the storages for the new number of segments
4724  Boundary_segment_inverted[b].resize(nsegments);
4725  Boundary_segment_initial_coordinate[b].resize(nsegments);
4726  Boundary_segment_final_coordinate[b].resize(nsegments);
4727 
4728  // Check if the boundary has an associated GeomObject
4729  if (this->boundary_geom_object_pt(b)!=0)
4730  {
4731  Boundary_segment_initial_zeta[b].resize(nsegments);
4732  Boundary_segment_final_zeta[b].resize(nsegments);
4733  }
4734  else
4735  {
4736  Boundary_segment_initial_arclength[b].resize(nsegments);
4737  Boundary_segment_final_arclength[b].resize(nsegments);
4738  }
4739  // ------------------------------------------------------------------
4740  // map to know if the new segment has been re-assigned the info.
4741  std::map<unsigned, bool> done_segment;
4742 
4743  // Count the number of re-assigned segments with the new values
4744  unsigned re_assigned_segments = 0;
4745 
4746  // Go through all the old segments (the input segments)
4747  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4748  {
4749  // Get the first and last zeta values for the current segment
4750  const double old_initial_arclength =
4751  old_boundary_segment_initial_arclength[old_is];
4752  const double old_final_arclength =
4753  old_boundary_segment_final_arclength[old_is];
4754  // Get the "is inverted" segment information
4755  const unsigned old_inverted_segment =
4756  old_boundary_segment_inverted[old_is];
4757 
4758  // Check if the boundary coordinates in the segment go in
4759  // increasing or decreasing order
4760  bool old_increasing_order = false;
4761  if (old_initial_arclength < old_final_arclength)
4762  {old_increasing_order = true;}
4763 
4764  // Now get the first and last node of the current segment
4765  // Get the first element
4766  FiniteElement* first_old_seg_ele_pt =
4767  old_segment_sorted_ele_pt[old_is].front();
4768 
4769  // Number of nodes
4770  const unsigned nnod = first_old_seg_ele_pt->nnode();
4771 
4772  // Get the first node of the current segment
4773  Node *first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(0);
4774  if (old_is_inverted[first_old_seg_ele_pt])
4775  {
4776  first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(nnod-1);
4777  }
4778 
4779  // Get access to the last element on the segment
4780  FiniteElement* last_old_seg_ele_pt =
4781  old_segment_sorted_ele_pt[old_is].back();
4782 
4783  // Get the last node of the current segment
4784  Node *last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(nnod-1);
4785  if (old_is_inverted[last_old_seg_ele_pt])
4786  {
4787  last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(0);
4788  }
4789  // Check if the segment is inverted, if that is the case then
4790  // also invert the nodes
4791  if (old_inverted_segment)
4792  {
4793  Node* temp_node_pt = first_old_seg_node_pt;
4794  first_old_seg_node_pt = last_old_seg_node_pt;
4795  last_old_seg_node_pt = temp_node_pt;
4796  }
4797 
4798  // We have the first and last node of the old segment (input
4799  // segment), now identify in which segment, of those with only
4800  // nonhalo face elements, they are
4801  for (unsigned is = 0; is < nsegments; is++)
4802  {
4803  if (!done_segment[is])
4804  {
4805  // Go through the nodes of the current segment and try to find
4806  // the old nodes
4807  bool found_first_old_seg_node = false;
4808  bool found_last_old_seg_node = false;
4809  bool same_order = false;
4810 
4811  // Get the first node of the current segment
4812  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
4813  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
4814  if (is_inverted[first_seg_ele_pt])
4815  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
4816 
4817  // Get the arclength for the first node
4818  const double segment_first_node_zeta =
4819  sorted_segment_node_arclength[is][0];
4820 
4821  // Get the node coordinates for the first node
4822  Vector<double> first_node_coord(2);
4823  for (unsigned i = 0; i < 2; i++)
4824  {first_node_coord[i] = first_seg_node_pt->x(i);}
4825 
4826  // Get the last node of the current segment
4827  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
4828  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
4829  if (is_inverted[last_seg_ele_pt])
4830  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
4831 
4832  // Get the arclength for the last node
4833  const double segment_final_node_zeta = segment_arclength[is];
4834 
4835  // Get the node coordinates for the last node
4836  Vector<double> last_node_coord(2);
4837  for (unsigned i = 0; i < 2; i++)
4838  {last_node_coord[i] = last_seg_node_pt->x(i);}
4839 
4840  // Temporary storage for the nodes of the current segment
4841  Vector<Node*> segment_node_pt = sorted_segment_all_nodes_pt[is];
4842  // Get the number of nodes in the segment
4843  const unsigned nsegment_node = segment_node_pt.size();
4844  for (unsigned in = 0; in < nsegment_node; in++)
4845  {
4846  Node* current_node_pt = segment_node_pt[in];
4847  if (!found_first_old_seg_node &&
4848  first_old_seg_node_pt == current_node_pt)
4849  {
4850  // Get the arclength assigned to the node on the old
4851  // segment
4852  const double current_node_zeta =
4853  sorted_segment_node_arclength[is][in];
4854 
4855  // Now check if the new segment has the same orientation
4856  // as the old one
4857  if (!found_last_old_seg_node) // has the same orientation
4858  {
4859  // Re-assign the first node coordinates
4860  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
4861 
4862  // Check if the boundary has an associated GeomObject
4863  if (this->boundary_geom_object_pt(b)!=0)
4864  {
4865  // Assign the zeta values if the current segment has the
4866  // nodes of the old one
4867 
4868  // If we are in the same order then pass the values as
4869  // they are
4870  Boundary_segment_initial_zeta[b][is] =
4871  initial_zeta_segment[is];
4872 
4873  } // if (this->boundary_geom_object_pt(b)!=0)
4874  else
4875  {
4876  // Get the distance to the first node
4877  const double distance =
4878  std::fabs(current_node_zeta - segment_first_node_zeta);
4879 
4880  double new_initial_arclength = old_initial_arclength;
4881 
4882  // Now check if the zeta values are in increasing order
4883  if (old_increasing_order)
4884  {
4885  // Substract the distance
4886  new_initial_arclength-= distance;
4887  }
4888  else
4889  {
4890  // Add the distance
4891  new_initial_arclength+= distance;
4892  }
4893 
4894  // Re-assign the initial arclength for the current segment
4895  Boundary_segment_initial_arclength[b][is] =
4896  new_initial_arclength;
4897 
4898  } // else if (this->boundary_geom_object_pt(b)!=0)
4899  } // if (!found_last_old_seg_node)
4900  else // has different orientation
4901  {
4902  // Re-assign the first node coordinates
4903  Boundary_segment_initial_coordinate[b][is] = last_node_coord;
4904 
4905  // Check if the boundary has an associated GeomObject
4906  if (this->boundary_geom_object_pt(b)!=0)
4907  {
4908  // Assign the zeta values if the current segment has the
4909  // nodes of the old one
4910 
4911  // Not the same order, we need to copy the zeta values
4912  // from the other end, the inverted flag is changed at
4913  // the end. Copy the value from the final end
4914  Boundary_segment_initial_zeta[b][is] =
4915  final_zeta_segment[is];
4916 
4917  } // if (this->boundary_geom_object_pt(b)!=0)
4918  else
4919  {
4920  // Get the distance to the final node
4921  const double distance =
4922  std::fabs(current_node_zeta - segment_final_node_zeta);
4923 
4924  double new_initial_arclength = old_initial_arclength;
4925 
4926  // Now check if the zeta values are in increasing order
4927  if (old_increasing_order)
4928  {
4929  // Substract the distance
4930  new_initial_arclength-= distance;
4931  }
4932  else
4933  {
4934  // Add the distance
4935  new_initial_arclength+= distance;
4936  }
4937 
4938  // Re-assign the initial arclength for the current segment
4939  Boundary_segment_initial_arclength[b][is] =
4940  new_initial_arclength;
4941 
4942  } // else if (this->boundary_geom_object_pt(b)!=0)
4943  } // else if (!found_last_old_seg_node)
4944 
4945  // Mark as found the first node
4946  found_first_old_seg_node = true;
4947 
4948  }
4949  // if (!found_first_old_seg_node &&
4950  // first_old_seg_node_pt == current_node_pt)
4951 
4952  // If we found first the first node then the segments have
4953  // the same order
4954  if (found_first_old_seg_node && !found_last_old_seg_node)
4955  {same_order = true;}
4956 
4957  if (!found_last_old_seg_node &&
4958  last_old_seg_node_pt == current_node_pt)
4959  {
4960  // Get the boundary coordinates assigned to the node on
4961  // the old segment
4962  const double current_node_zeta =
4963  sorted_segment_node_arclength[is][in];
4964 
4965  // Now check if the new segment has the same orientation
4966  // as the old one
4967  if (found_first_old_seg_node) // has the same orientation
4968  {
4969  // Re-assign the last node coordinates
4970  Boundary_segment_final_coordinate[b][is] = last_node_coord;
4971 
4972  // Check if the boundary has an associated GeomObject
4973  if (this->boundary_geom_object_pt(b)!=0)
4974  {
4975  // Assign the zeta values if the current segment has the
4976  // nodes of the old one
4977 
4978  // If we are in the same order then pass the values as
4979  // they are
4980  Boundary_segment_final_zeta[b][is] =
4981  final_zeta_segment[is];
4982 
4983  } // if (this->boundary_geom_object_pt(b)!=0)
4984  else
4985  {
4986  // Get the distance to the last node
4987  const double distance =
4988  std::fabs(current_node_zeta - segment_final_node_zeta);
4989 
4990  double new_final_arclength = old_final_arclength;
4991 
4992  // Now check if the zeta values are in increasing order
4993  if (old_increasing_order)
4994  {
4995  // Add the distance
4996  new_final_arclength+= distance;
4997  }
4998  else
4999  {
5000  // Substract the distance
5001  new_final_arclength-= distance;
5002  }
5003 
5004  // Re-assign the final arclength for the current segment
5005  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5006 
5007  } // else if (this->boundary_geom_object_pt(b)!=0)
5008  } // if (found_first_old_seg_node)
5009  else
5010  {
5011  // Re-assign the last node coordinates
5012  Boundary_segment_final_coordinate[b][is] = first_node_coord;
5013 
5014  // Check if the boundary has an associated GeomObject
5015  if (this->boundary_geom_object_pt(b)!=0)
5016  {
5017  // Assign the zeta values if the current segment has the
5018  // nodes of the old one
5019 
5020  // Not the same order, we need to copy the zeta values
5021  // from the other end, the inverted flag is changed at
5022  // the end. Copy the value from the initial end
5023  Boundary_segment_final_zeta[b][is] =
5024  initial_zeta_segment[is];
5025 
5026  } // if (this->boundary_geom_object_pt(b)!=0)
5027  else
5028  {
5029  // Get the distance to the last node
5030  const double distance =
5031  std::fabs(current_node_zeta - segment_first_node_zeta);
5032 
5033  double new_final_arclength = old_final_arclength;
5034 
5035  // Now check if the zeta values are in increasing order
5036  if (old_increasing_order)
5037  {
5038  // Add the distance
5039  new_final_arclength+= distance;
5040  }
5041  else
5042  {
5043  // Substract the distance
5044  new_final_arclength-= distance;
5045  }
5046 
5047  // Re-assign the final arclength for the current segment
5048  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5049 
5050  } // else if (this->boundary_geom_object_pt(b)!=0)
5051  } // if (found_first_old_seg_node)
5052 
5053  // Mark as found the last node
5054  found_last_old_seg_node = true;
5055 
5056  } // if (!found_last_old_seg_node &&
5057  // last_old_seg_node_pt == current_node_pt)
5058 
5059  // If we found the last node first then the segments have
5060  // not the same order
5061  if (!found_first_old_seg_node && found_last_old_seg_node)
5062  {same_order = false;}
5063 
5064  if (found_first_old_seg_node && found_last_old_seg_node)
5065  {
5066  // Check if necessary to change the information that
5067  // states if a segment is inverted or not
5068  if (same_order)
5069  {Boundary_segment_inverted[b][is] = old_inverted_segment;}
5070  else
5071  {Boundary_segment_inverted[b][is] = !old_inverted_segment;}
5072 
5073  // Mark the segment as done
5074  done_segment[is] = true;
5075 
5076  // Increase the number of re-assigned segments
5077  re_assigned_segments++;
5078 
5079  // Break the for that look for the nodes in the segments
5080  break;
5081  }
5082 
5083  } // for (in < nsegment_node)
5084 
5085 #ifdef PARANOID
5086  if ((found_first_old_seg_node && !found_last_old_seg_node) ||
5087  (!found_first_old_seg_node && found_last_old_seg_node))
5088  {
5089  std::stringstream error_message;
5090  error_message
5091  << "Working with boundary ("<< b << ").\nOnly the first node or "
5092  << "the last node of the old segment (" << old_is << ") was\n"
5093  << "found. Both, first and last node should have been found in "
5094  << "the same segment!!!.\n"
5095  << "Found first seg node:" << found_first_old_seg_node << "\n"
5096  << "Found last seg node:" << found_last_old_seg_node << "\n\n";
5097  throw OomphLibError(error_message.str(),
5098  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5099  OOMPH_EXCEPTION_LOCATION);
5100  }
5101 #endif
5102 
5103  } // if (!done_segment[is])
5104  } // for (is < nsegments)
5105  } // for (old_is < old_nsegments)
5106 
5107  // For those segments not identified set dummy values, the boundary
5108  // coordinates should be corrected at the synchronisation stage
5109 
5110  // loop over the new segments and check if there not identified
5111  // segments
5112  for (unsigned is = 0; is < nsegments; is++)
5113  {
5114  // Was the segment identified
5115  if (!done_segment[is])
5116  {
5117  // Get the first node of the current segment
5118  FiniteElement* first_seg_ele_pt =
5119  segment_sorted_ele_pt[is].front();
5120  // Number of nodes
5121  const unsigned nnod = first_seg_ele_pt->nnode();
5122 
5123  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
5124  if (is_inverted[first_seg_ele_pt])
5125  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
5126 
5127  // Get the arclength for the first node
5128  const double segment_first_node_zeta =
5129  sorted_segment_node_arclength[is][0];
5130 
5131  // Get the node coordinates for the first node
5132  Vector<double> first_node_coord(2);
5133  for (unsigned i = 0; i < 2; i++)
5134  {first_node_coord[i] = first_seg_node_pt->x(i);}
5135 
5136  // Get the last node of the current segment
5137  FiniteElement* last_seg_ele_pt =
5138  segment_sorted_ele_pt[is].back();
5139  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
5140  if (is_inverted[last_seg_ele_pt])
5141  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
5142 
5143  // Get the arclength for the last node
5144  const double segment_final_node_zeta = segment_arclength[is];
5145 
5146  // Get the node coordinates for the last node
5147  Vector<double> last_node_coord(2);
5148  for (unsigned i = 0; i < 2; i++)
5149  {last_node_coord[i] = last_seg_node_pt->x(i);}
5150 
5151  // Re-assign the initial node coordinates
5152  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
5153 
5154  // Check if the boundary has an associated GeomObject
5155  if (this->boundary_geom_object_pt(b)!=0)
5156  {
5157  // Assign the zeta values if the current segment has the
5158  // nodes of the old one
5159 
5160  // If we are in the same order then pass the values as
5161  // they are
5162  Boundary_segment_initial_zeta[b][is] =
5163  initial_zeta_segment[is];
5164 
5165  } // if (this->boundary_geom_object_pt(b)!=0)
5166  else
5167  {
5168  // Re-assign the initial arclength for the current segment
5169  Boundary_segment_initial_arclength[b][is] =
5170  segment_first_node_zeta;
5171 
5172  } // else if (this->boundary_geom_object_pt(b)!=0)
5173 
5174  // Re-assign the initial node coordinates
5175  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5176 
5177  // Check if the boundary has an associated GeomObject
5178  if (this->boundary_geom_object_pt(b)!=0)
5179  {
5180  // Assign the zeta values if the current segment has the
5181  // nodes of the old one
5182 
5183  // If we are in the same order then pass the values as
5184  // they are
5185  Boundary_segment_final_zeta[b][is] =
5186  final_zeta_segment[is];
5187 
5188  } // if (this->boundary_geom_object_pt(b)!=0)
5189  else
5190  {
5191  // Re-assign the final arclength for the current segment
5192  Boundary_segment_final_arclength[b][is] =
5193  segment_final_node_zeta;
5194 
5195  } // else if (this->boundary_geom_object_pt(b)!=0)
5196 
5197  Boundary_segment_inverted[b][is] = 0;
5198 
5199  // Mark the segment as done
5200  done_segment[is] = true;
5201 
5202  // Increase the number of re-assigned segments
5203  re_assigned_segments++;
5204 
5205  } // if (!done_segment[is])
5206 
5207  } // for (is < nsegments)
5208 
5209 #ifdef PARANOID
5210  // Compare the number of new segments identified with the old segments
5211  if (re_assigned_segments != nsegments)
5212  {
5213  std::stringstream error_message;
5214  error_message
5215  << "Working with boundary ("<< b << ").\nThe number of re-assigned "
5216  << "segments (" << re_assigned_segments
5217  << ") is different from the number\nof segments ("<< nsegments
5218  << ")\n\n";
5219  throw OomphLibError(error_message.str(),
5220  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5221  OOMPH_EXCEPTION_LOCATION);
5222  } // if (re_assigned_segments != nsegments)
5223 #endif
5224 
5225  // Clean all the created face elements
5226  for (unsigned i = 0; i < nele; i++)
5227  {
5228  delete face_el_pt[i];
5229  face_el_pt[i] = 0;
5230  }
5231 
5232  }
5233 
5234  ///=====================================================================
5235  /// Select face elements from a given boundary. In case the we are
5236  /// dealing with an internal boundary we use a set of criterias to
5237  /// decide which of the two face elements should be used on represent
5238  /// the internal boundary. We return the face elements, halo or
5239  /// haloed on this processor that form the boundary. The caller method
5240  /// should be in charge of selecting nonhalo elements and deleting the face
5241  /// elements created by this method
5242  /// =====================================================================
5243  template <class ELEMENT>
5246  const unsigned &b,
5247  bool &is_internal_boundary,
5248  std::map<FiniteElement*,FiniteElement*>
5249  &face_to_bulk_element_pt)
5250  {
5251  // Get the communicator of the mesh
5252  OomphCommunicator* comm_pt = this->communicator_pt();
5253 
5254  const unsigned my_rank = comm_pt->my_rank();
5255 
5256  // ------------------------------------------------------------------
5257  // 1) Get the face elements associated with the current boundary
5258  // ------------------------------------------------------------------
5259 
5260  // Temporary storage for face elements (do not take care of
5261  // repeated face elements)
5262  Vector<FiniteElement*> tmp_face_ele_pt;
5263 
5264  const unsigned nregions = this->nregion();
5265 
5266  // If there is more than one region then only use boundary
5267  // coordinates from the bulk side (region 0)
5268  if (nregions > 1)
5269  {
5270  for (unsigned ir = 0 ; ir < nregions; ir++)
5271  {
5272  const unsigned region_id =
5273  static_cast<unsigned>(this->Region_attribute[ir]);
5274 
5275  // Loop over all elements on boundaries in region -ir-
5276  const unsigned nele_in_region =
5277  this->nboundary_element_in_region(b, region_id);
5278 
5279  // Only bother to do anything else, if there are elements
5280  // associated with the boundary and the current region
5281  if (nele_in_region > 0)
5282  {
5283  // Loop over the bulk elements adjacent to boundary b
5284  for (unsigned e = 0; e < nele_in_region; e++)
5285  {
5286  // Get pointer to the bulk element that is adjacent
5287  // to boundary b
5288  FiniteElement* bulk_ele_pt =
5289  this->boundary_element_in_region_pt(b, region_id, e);
5290 
5291  // Get the index of the face of element e along
5292  // boundary b
5293  int face_index =
5294  this->face_index_at_boundary_in_region(b,region_id,e);
5295 
5296  // Create the face element
5297  FiniteElement* tmp_face_el_pt =
5298  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5299 
5300  // Associated the face element with the bulk
5301  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5302 
5303  // ... and add it to the tmp storage for all the
5304  // face elements, do not take care for repeated
5305  // ones (at the moment)
5306  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5307 
5308  } // for (e < nele_in_region)
5309 
5310  } // if (nele_in_region > 0)
5311 
5312  } // for (ir < n_regions)
5313 
5314  } // if (n_regions > 1)
5315 
5316  //Otherwise it's just the normal boundary functions
5317  else
5318  {
5319  // Loop over all elements on boundaries
5320  const unsigned nbound_ele = this->nboundary_element(b);
5321 
5322  //Only bother to do anything else, if there are elements
5323  if (nbound_ele > 0)
5324  {
5325  // Loop over the bulk elements adjacent to boundary b
5326  for (unsigned e = 0; e < nbound_ele; e++)
5327  {
5328  // Get pointer to the bulk element that is adjacent to
5329  // boundary b
5330  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5331 
5332  // Get the index of the face of element e along
5333  // boundary b
5334  int face_index = this->face_index_at_boundary(b, e);
5335 
5336  // Create the face element
5337  FiniteElement* tmp_face_el_pt =
5338  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5339 
5340  // Associated the face element with the bulk
5341  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5342 
5343  // ... and add it to the tmp storage for all the face
5344  // elements, do not care for repeated ones (at the
5345  // moment)
5346  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5347 
5348  } // (e < nbound_ele)
5349 
5350  } // (nbound_ele > 0)
5351 
5352  } // else (n_regions > 1)
5353 
5354  // map to know which face element has been already done
5355  std::map<FiniteElement*,bool> done_face;
5356 
5357  // Set the flag to indicate if we are working with an internal
5358  // boundary
5359  is_internal_boundary = false;
5360 
5361  // Free the memory of the elements in this container (only used
5362  // when working with internal boundaries)
5363  Vector<FiniteElement*> free_memory_face_ele_pt;
5364 
5365  // Get the number of face elements in the boundary (including
5366  // repeated)
5367  const unsigned n_tmp_face_ele = tmp_face_ele_pt.size();
5368  for (unsigned ie = 0; ie < n_tmp_face_ele; ie++)
5369  {
5370  // Get the possible main element
5371  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5372  if (!done_face[main_face_ele_pt])
5373  {
5374  // Mark the face element as done
5375  done_face[main_face_ele_pt] = true;
5376  // Get the number of nodes for the face element
5377  const unsigned nnodes = main_face_ele_pt->nnode();
5378  // Get the first and last node of the main face element
5379  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5380  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5381  // Look for the other side face element (we can start from
5382  // the next one, all previous face elements have been
5383  // already identified with its other side face)
5384  for (unsigned iie = ie + 1; iie < n_tmp_face_ele; iie++)
5385  {
5386  // Get the possible dependant element
5387  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5388  if (!done_face[dependant_face_ele_pt])
5389  {
5390  // Get the first and last node of the dependant
5391  // face element
5392  Node* dependant_first_node_pt =
5393  dependant_face_ele_pt->node_pt(0);
5394  Node* dependant_last_node_pt =
5395  dependant_face_ele_pt->node_pt(nnodes-1);
5396  // Check if the nodes at the ends of both face
5397  // elements match (also check the reversed case)
5398  if (((dependant_first_node_pt == main_first_node_pt) &&
5399  (dependant_last_node_pt == main_last_node_pt)) ||
5400  ((dependant_first_node_pt == main_last_node_pt) &&
5401  (dependant_last_node_pt == main_first_node_pt)))
5402  {
5403  // Set the flag to indicate we are working with an
5404  // internal boundary
5405  is_internal_boundary = true;
5406  // Mark the face element as done
5407  done_face[dependant_face_ele_pt] = true;
5408 
5409  // Now choose which face element will be used
5410  // as the main element. We get the processor in
5411  // charge of the element and choose the one
5412  // with the highest processor in charge or the
5413  // bottom-left bulk element in case the both
5414  // faces are on the same processor
5415 
5416  // Get the bulk element for each face element
5417  // (the main and the dependant face element)
5418  FiniteElement *main_bulk_ele_pt =
5419  face_to_bulk_element_pt[main_face_ele_pt];
5420  FiniteElement *dependant_bulk_ele_pt =
5421  face_to_bulk_element_pt[dependant_face_ele_pt];
5422 
5423  // Get the processor in charge for each bulk
5424  // element
5425  int processor_in_charge_main_bulk_ele =
5426  main_bulk_ele_pt->non_halo_proc_ID();
5427  int processor_in_charge_dependant_bulk_ele =
5428  dependant_bulk_ele_pt->non_halo_proc_ID();
5429 
5430  // If the processor in charge is negative the
5431  // element is not halo, therefore the processor
5432  // in charge is the current one
5433  if (processor_in_charge_main_bulk_ele < 0)
5434  {
5435  processor_in_charge_main_bulk_ele=
5436  static_cast<int>(my_rank);
5437  }
5438  if (processor_in_charge_dependant_bulk_ele < 0)
5439  {
5440  processor_in_charge_dependant_bulk_ele=
5441  static_cast<int>(my_rank);
5442  }
5443 
5444  // Flag to know if add the main or dependant
5445  // face element
5446  bool add_main_face_element = true;
5447  if (processor_in_charge_dependant_bulk_ele >
5448  processor_in_charge_main_bulk_ele)
5449  {
5450  // Include the dependant element
5451  add_main_face_element = false;
5452  }
5453  else if (processor_in_charge_main_bulk_ele ==
5454  processor_in_charge_dependant_bulk_ele)
5455  {
5456  // When the processor in charge for both
5457  // elements is the same then use the
5458  // bottom-left criteria on the bulk
5459  // elements to choose the main face element
5460  Vector<double> main_ele_coordinates(2);
5461  Vector<double> dependant_ele_coordinates(2);
5462  // Get the number of nodes on the bulk
5463  // elements
5464  const unsigned n_bulk_nodes =
5465  main_bulk_ele_pt->nnode();
5466  for (unsigned inode = 0; inode < n_bulk_nodes;
5467  inode++)
5468  {
5469  for (unsigned idim = 0; idim < 2; idim++)
5470  {
5471  main_ele_coordinates[idim]+=
5472  main_bulk_ele_pt->node_pt(inode)->
5473  x(idim);
5474  dependant_ele_coordinates[idim]+=
5475  dependant_bulk_ele_pt->node_pt(inode)->
5476  x(idim);
5477  } // (idim < 2)
5478 
5479  } // (inode < n_bulk_nodes)
5480 
5481  // Get the average of the nodes coordinates
5482  for (unsigned idim = 0; idim < 2; idim++)
5483  {
5484  main_ele_coordinates[idim]/=
5485  (double)n_bulk_nodes;
5486  dependant_ele_coordinates[idim]/=
5487  (double)n_bulk_nodes;
5488  }
5489 
5490  // Once we know the average coordinates for
5491  // each element then we choose the one with
5492  // the bottom-left averaged coordinates
5493  if (dependant_ele_coordinates[1] <
5494  main_ele_coordinates[1])
5495  {add_main_face_element = false;}
5496  else if(dependant_ele_coordinates[1]==
5497  main_ele_coordinates[1])
5498  {
5499  // The left-most element
5500  if(dependant_ele_coordinates[0] <
5501  main_ele_coordinates[0])
5502  {add_main_face_element = false;}
5503  }
5504  } // else -- The processor in charge is the
5505  // same for both elements
5506 
5507  if (add_main_face_element)
5508  {
5509  // Add the main face element to the storage
5510  // so we get the halo and haloed nodes from
5511  // it
5512  face_ele_pt.push_back(main_face_ele_pt);
5513  // Mark the dependat face element to free
5514  // its memory
5515  free_memory_face_ele_pt.
5516  push_back(dependant_face_ele_pt);
5517  }
5518  else
5519  {
5520  // Add the dependant face element to the
5521  // storage so we get the halo and haloed
5522  // nodes from it
5523  face_ele_pt.push_back(dependant_face_ele_pt);
5524  // Mark the main face element to free its
5525  // memory
5526  free_memory_face_ele_pt.
5527  push_back(main_face_ele_pt);
5528  }
5529 
5530  // Break the for to look for the next face
5531  // element
5532  break;
5533 
5534  } // if -- matching of nodes from main ele and
5535  // dependant ele
5536 
5537  } // if (!done_face[dependant_face_ele_pt])
5538 
5539  } // for (iie < n_tmp_face_ele)
5540 
5541  } // if (!done_face[main_face_ele_pt])
5542 
5543  } // for (ie < n_tmp_face_ele)
5544 
5545  // Are there any face element to free its memory
5546  const unsigned n_free_face_ele = free_memory_face_ele_pt.size();
5547  if (n_free_face_ele == 0)
5548  {
5549  // If there is not face elements to free memory that means that
5550  // we are not working with an internal boundary, therefore copy
5551  // all the element from the tmp face elements into the face
5552  // elements container
5553 
5554  // Resize the container
5555  face_ele_pt.resize(n_tmp_face_ele);
5556  // loop over the elements and copy them
5557  for (unsigned i = 0; i < n_tmp_face_ele; i++)
5558  {
5559  face_ele_pt[i] = tmp_face_ele_pt[i];
5560  } // for (i < n_tmp_face_ele)
5561 
5562  } // if (n_free_face_ele == 0)
5563  else
5564  {
5565  // ... otherwise free the memory of the indicated elements
5566  // loop over the elements to free its memory
5567  for (unsigned i = 0; i < n_free_face_ele; i++)
5568  {
5569  delete free_memory_face_ele_pt[i];
5570  free_memory_face_ele_pt[i] = 0;
5571  } // for (i < n_free_face_ele)
5572  }
5573 
5574  }
5575 
5576  ///========================================================================
5577  /// In charge of sinchronize the boundary coordinates for internal
5578  /// boundaries that were split as part of the distribution
5579  /// process. Called after setup_boundary_coordinates() for the
5580  /// original mesh only
5581  ///========================================================================
5582  template <class ELEMENT>
5585  {
5586  // ------------------------------------------------------------------
5587  // First: Get the face elements associated with the current boundary
5588  // ------------------------------------------------------------------
5589 
5590  // Get the communicator of the mesh
5591  OomphCommunicator* comm_pt = this->communicator_pt();
5592 
5593  const unsigned nproc = comm_pt->nproc();
5594  const unsigned my_rank = comm_pt->my_rank();
5595 
5596  // Temporary storage for face elements (do not take care of repeated
5597  // face elements)
5598  Vector<FiniteElement*> tmp_face_ele_pt;
5599 
5600  const unsigned nregions = this->nregion();
5601 
5602  // map to associate the face element to the bulk element, necessary
5603  // to get the processor in charge for the halo elements
5604  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
5605 
5606  // If there is more than one region then only use boundary
5607  // coordinates from the bulk side (region 0)
5608  if (nregions > 1)
5609  {
5610  for (unsigned ir = 0 ; ir < nregions; ir++)
5611  {
5612  const unsigned region_id =
5613  static_cast<unsigned>(this->Region_attribute[ir]);
5614 
5615  // Loop over all elements on boundaries in region -ir-
5616  const unsigned nele_in_region =
5617  this->nboundary_element_in_region(b, region_id);
5618 
5619  // Only bother to do anything else, if there are elements
5620  // associated with the boundary and the current region
5621  if (nele_in_region > 0)
5622  {
5623  // Loop over the bulk elements adjacent to boundary b
5624  for (unsigned e = 0; e < nele_in_region; e++)
5625  {
5626  // Get pointer to the bulk element that is adjacent to boundary b
5627  FiniteElement* bulk_ele_pt =
5628  this->boundary_element_in_region_pt(b, region_id, e);
5629 
5630  // Get the index of the face of element e along boundary b
5631  int face_index=this->face_index_at_boundary_in_region(b,region_id,e);
5632 
5633  // Create the face element
5634  FiniteElement* tmp_face_el_pt =
5635  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5636 
5637  // ... and add it to the tmp storage for all the face
5638  // elements, do not take care for repeated ones (at the
5639  // moment)
5640  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5641  // Create the map to know if the element is halo
5642  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5643 
5644  } // for (e < nele_in_region)
5645 
5646  } // if (nele_in_region > 0)
5647 
5648  } // for (ir < n_regions)
5649 
5650  } // if (n_regions > 1)
5651 
5652  //Otherwise it's just the normal boundary functions
5653  else
5654  {
5655  // Loop over all elements on boundaries
5656  const unsigned nbound_ele = this->nboundary_element(b);
5657 
5658  //Only bother to do anything else, if there are elements
5659  if (nbound_ele > 0)
5660  {
5661  // Loop over the bulk elements adjacent to boundary b
5662  for (unsigned e = 0; e < nbound_ele; e++)
5663  {
5664  // Get pointer to the bulk element that is adjacent to boundary b
5665  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5666 
5667  // Get the index of the face of element e along boundary b
5668  int face_index = this->face_index_at_boundary(b, e);
5669 
5670  // Create the face element
5671  FiniteElement* tmp_face_el_pt =
5672  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5673 
5674  // ... and add it to the tmp storage for all the face
5675  // elements, do not care for repeated ones (at the moment)
5676  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5677  // Create the map to know if the element is halo
5678  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5679 
5680  } // (e < nbound_ele)
5681 
5682  } // (nbound_ele > 0)
5683 
5684  } // else (n_regions > 1)
5685 
5686  // Temporary storage for one side face elements. In case we are
5687  // working with an internal boundary here we store only one of the
5688  // face elements that are at each side of the boundary
5689  Vector<FiniteElement*> face_ele_pt;
5690 
5691  // map to know which face element has been already done
5692  std::map<FiniteElement*,bool> done_face;
5693 
5694  // Flag to indicate if we are working with an internal boundary
5695  bool is_internal_boundary = false;
5696 
5697 #ifdef PARANOID
5698  // Flag to indicate if we are working with an internal boundary (paranoid)
5699  bool is_internal_boundary_paranoid = false;
5700 
5701  // Count the number of other side face elements found in case we are
5702  // working with an internal boundary
5703  unsigned nfound_face_elements = 0;
5704 #endif
5705 
5706  // Get the number of face elements in the boundary
5707  const unsigned nbound_ele = tmp_face_ele_pt.size();
5708  for (unsigned ie = 0; ie < nbound_ele; ie++)
5709  {
5710  // Get the possible main element
5711  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5712  if (!done_face[main_face_ele_pt])
5713  {
5714  // Mark the face element as done
5715  done_face[main_face_ele_pt] = true;
5716  // Get the number of nodes for the face element
5717  const unsigned nnodes = main_face_ele_pt->nnode();
5718  // Get the first and last node of the main face element
5719  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5720  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5721  // Look for the other side face element
5722  for (unsigned iie = ie + 1; iie < nbound_ele; iie++)
5723  {
5724  // Get the possible dependant element
5725  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5726  if (!done_face[dependant_face_ele_pt])
5727  {
5728  // Get the first and last node of the dependant face element
5729  Node* dependant_first_node_pt =
5730  dependant_face_ele_pt->node_pt(0);
5731  Node* dependant_last_node_pt =
5732  dependant_face_ele_pt->node_pt(nnodes-1);
5733  // Check if the nodes at the ends of both face elements
5734  // match (also check the reversed case)
5735  if (((dependant_first_node_pt == main_first_node_pt) &&
5736  (dependant_last_node_pt == main_last_node_pt)) ||
5737  ((dependant_first_node_pt == main_last_node_pt) &&
5738  (dependant_last_node_pt == main_first_node_pt)))
5739  {
5740 #ifdef PARANOID
5741  // Increase the number of found face elements
5742  nfound_face_elements+=2;
5743 #endif
5744  // Set the flag to indicate we are working with an
5745  // internal boundary
5746  is_internal_boundary = true;
5747  // Mark the face element as done
5748  done_face[dependant_face_ele_pt] = true;
5749 
5750  // Now choose which face element will be used as the main
5751  // element. Use the same criteria as the compute segments
5752  // connectivity method (highest processor in charge or
5753  // bottom-left bulk element)
5754 
5755  // Get the bulk element for each face element (the main
5756  // and the dependant face element)
5757  FiniteElement *main_bulk_ele_pt =
5758  face_to_bulk_element_pt[main_face_ele_pt];
5759  FiniteElement *dependant_bulk_ele_pt =
5760  face_to_bulk_element_pt[dependant_face_ele_pt];
5761 
5762  // Get the processor in charge for each bulk element
5763  int processor_in_charge_main_bulk_ele =
5764  main_bulk_ele_pt->non_halo_proc_ID();
5765  int processor_in_charge_dependant_bulk_ele =
5766  dependant_bulk_ele_pt->non_halo_proc_ID();
5767 
5768  // If the processor in charge is negative the element is
5769  // not halo, therefore the processor in charge is the
5770  // current one
5771  if (processor_in_charge_main_bulk_ele < 0)
5772  {
5773  processor_in_charge_main_bulk_ele=static_cast<int>(my_rank);
5774  }
5775  if (processor_in_charge_dependant_bulk_ele < 0)
5776  {
5777  processor_in_charge_dependant_bulk_ele=static_cast<int>(my_rank);
5778  }
5779 
5780  // Flag to know if add the main or dependant face element
5781  bool add_main_face_element = true;
5782  if (processor_in_charge_dependant_bulk_ele >
5783  processor_in_charge_main_bulk_ele)
5784  {
5785  // Include the dependant element
5786  add_main_face_element = false;
5787  }
5788  else if (processor_in_charge_main_bulk_ele ==
5789  processor_in_charge_dependant_bulk_ele)
5790  {
5791  // When the processor in charge for both elements is the same
5792  // then use the bottom-left criteria on the bulk elements to
5793  // choose the main face element
5794  Vector<double> main_ele_coordinates(2);
5795  Vector<double> dependant_ele_coordinates(2);
5796  // Get the number of nodes on the bulk elements
5797  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5798  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5799  {
5800  for (unsigned idim = 0; idim < 2; idim++)
5801  {
5802  main_ele_coordinates[idim]+=
5803  main_bulk_ele_pt->node_pt(inode)->x(idim);
5804  dependant_ele_coordinates[idim]+=
5805  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5806  } // (idim < 2)
5807  } // (inode < n_bulk_nodes)
5808 
5809  // Get the average of the nodes coordinates
5810  for (unsigned idim = 0; idim < 2; idim++)
5811  {
5812  main_ele_coordinates[idim]/=(double)n_bulk_nodes;
5813  dependant_ele_coordinates[idim]/=(double)n_bulk_nodes;
5814  }
5815 
5816  // Once we know the average coordinates for each element
5817  // then we choose the one with the bottom-left averaged
5818  // coordinates
5819  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5820  {add_main_face_element = false;}
5821  else if(dependant_ele_coordinates[1]==main_ele_coordinates[1])
5822  {
5823  // The left-most element
5824  if(dependant_ele_coordinates[0] < main_ele_coordinates[0])
5825  {add_main_face_element = false;}
5826  }
5827  } // else -- The processor in charge is the same for both
5828  // elements
5829 
5830  if (add_main_face_element)
5831  {
5832  // Add the main face element to the storage so we get
5833  // the halo and haloed nodes from these face element
5834  face_ele_pt.push_back(main_face_ele_pt);
5835  }
5836  else
5837  {
5838  // Add the main face element to the storage so we get
5839  // the halo and haloed nodes from these face element
5840  face_ele_pt.push_back(dependant_face_ele_pt);
5841  }
5842 
5843  // Break the for to look for the next face element
5844  break;
5845 
5846  } // if -- matching of nodes from main ele and dependant ele
5847  } // if (!done_face[dependant_face_ele_pt])
5848  } // for (iie < nbound_ele)
5849  } // if (!done_face[main_face_ele_pt])
5850  } // for (ie < nbound_ele)
5851 
5852  // Get the number of face elements
5853  const unsigned nface_ele = face_ele_pt.size();
5854 
5855 #ifdef PARANOID
5856  // Check if we are working with an internal open curve. First check
5857  // if there are elements, in a distributed approach they may be no
5858  // elements associated to the boundary
5859  if (nbound_ele > 0 && nfound_face_elements == nbound_ele)
5860  {is_internal_boundary_paranoid = true;}
5861 
5862  if (nbound_ele > 0 && is_internal_boundary_paranoid &&
5863  nbound_ele!=nface_ele*2)
5864  {
5865  std::ostringstream error_message;
5866  error_message
5867  << "The info. to perform the synchronisation of the boundary "
5868  << "coordinates was not completely established\n"
5869  << "In this case it was the number of non repeated boundary elements\n"
5870  << "Number of boundary elements: (" << nbound_ele << ")\n"
5871  << "Number of nonrepeated boundary elements: (" << nface_ele << ")\n";
5872  throw OomphLibError(error_message.str(),
5873  "TriangleMesh::synchronize_boundary_coordinates()",
5874  OOMPH_EXCEPTION_LOCATION);
5875  }
5876 #endif
5877 
5878  // ----------------------------------------------------------------
5879  // Second: Identify the halo face elements
5880  // ----------------------------------------------------------------
5881 
5882  // A flag vector to mark those face elements that are considered as
5883  // halo in the current processor
5884  std::vector<bool> is_halo_face_element(nface_ele, false);
5885 
5886  // Count the total number of non halo face elements
5887  unsigned nnon_halo_face_elements = 0;
5888 
5889  for (unsigned ie = 0; ie < nface_ele; ie++)
5890  {
5891  FiniteElement* face_el_pt = face_ele_pt[ie];
5892  // Get the bulk element
5893  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_el_pt];
5894  // Check if the bulk element is halo
5895  if (!tmp_bulk_ele_pt->is_halo())
5896  {
5897  is_halo_face_element[ie] = false;
5898  nnon_halo_face_elements++;
5899  }
5900  else
5901  {
5902  // Mark the face element as halo
5903  is_halo_face_element[ie] = true;
5904  }
5905  } // for (ie < nface_ele)
5906 
5907  // -----------------------------------------------------------------
5908  // Third: Go through the face elements and get the nodes from the
5909  // elements. The boundary coordinate from each node is sent to its
5910  // processor in charge, then that processor will be responsible to
5911  // send the bound coordinate to all the processors that have a halo
5912  // representation of the node
5913  // -----------------------------------------------------------------
5914 
5915  // A map to know which nodes are already done
5916  std::map<Node*,bool> done_node;
5917 
5918  // The storage for the halo nodes on face elements in this processor
5919  // with other processors
5920  Vector<Vector<Node*> > face_halo_node_pt(nproc);
5921 
5922  // The storage for the ids of the halo nodes on face elements in
5923  // this processor with other processors
5924  Vector<Vector<unsigned> > face_halo_node_id(nproc);
5925 
5926  // The storage for the haloed nodes on face elements in this
5927  // processor with other processors
5928  Vector<Vector<Node*> > face_haloed_node_pt(nproc);
5929 
5930  // The storage for the ids of the haloed nodes on face elements in
5931  // this processor with other processors
5932  Vector<Vector<unsigned> > face_haloed_node_id(nproc);
5933 
5934  // A map to know which nodes are face nodes and the processor in
5935  // charge is the current one
5936  std::map<Node*,bool> done_haloed_face_node;
5937 
5938  // Go through all the face elements
5939  for (unsigned iface = 0; iface < nface_ele; iface++)
5940  {
5941  // Only work with the non halo face elements
5942  if (!is_halo_face_element[iface])
5943  {
5944  // Get the face element
5945  FiniteElement *ele_face_pt = face_ele_pt[iface];
5946  // The number of nodes of the face elements
5947  const unsigned nnodes = ele_face_pt->nnode();
5948  // Go through all the nodes in the face element
5949  for (unsigned in = 0; in < nnodes; in++)
5950  {
5951  Node* face_node_pt = ele_face_pt->node_pt(in);
5952  // Check if node is done
5953  if (!done_node[face_node_pt])
5954  {
5955  // Mark the node as done
5956  done_node[face_node_pt] = true;
5957  // First check if the node is halo
5958  if (face_node_pt->is_halo())
5959  {
5960  // Get the processor in charge for the current node
5961  int int_nonhalo_ID = face_node_pt->non_halo_proc_ID();
5962 #ifdef PARANOID
5963  if (int_nonhalo_ID < 0)
5964  {
5965  std::ostringstream error_message;
5966  error_message
5967  << "The node was marked to be halo but the processor in "
5968  << "charge was found to be -1\n\n";
5969  throw OomphLibError(error_message.str(),
5970  "TriangleMesh::synchronize_boundary_coordinates()",
5971  OOMPH_EXCEPTION_LOCATION);
5972  }
5973 #endif
5974  const unsigned ip = static_cast<unsigned>(int_nonhalo_ID);
5975  // Add the node to the structure that holds the halo
5976  // nodes, the current processor will need to send the
5977  // info. to the processor in charge.
5978  face_halo_node_pt[ip].push_back(face_node_pt);
5979  // ... finally look for the halo id with the processor in
5980  // charge
5981 #ifdef PARANOID
5982  bool found_halo_node = false;
5983 #endif
5984  const unsigned nhalo_iproc = this->nhalo_node(ip);
5985  for (unsigned ihn = 0; ihn < nhalo_iproc; ihn++)
5986  {
5987  Node* compare_face_node_pt = this->halo_node_pt(ip, ihn);
5988  if (compare_face_node_pt == face_node_pt)
5989  {
5990  // Once found the id of the node with the processor
5991  // store the id in the proper storage
5992  face_halo_node_id[ip].push_back(ihn);
5993 #ifdef PARANOID
5994  // Set the flag to mark as found the halo node
5995  found_halo_node = true;
5996 #endif
5997  // Break the loop
5998  break;
5999  }
6000  } // for (ih < nhalo_iproc)
6001 #ifdef PARANOID
6002  if (!found_halo_node)
6003  {
6004  std::ostringstream error_message;
6005  error_message
6006  << "The halo id of the current node: ("
6007  << face_node_pt->x(0) << ", " << face_node_pt->x(1)
6008  << ") with processor (" << ip << ") was not found!!!\n\n";
6009  throw OomphLibError(error_message.str(),
6010  "TriangleMesh::synchronize_boundary_coordinates()",
6011  OOMPH_EXCEPTION_LOCATION);
6012  }
6013 #endif
6014  } // if (face_node_pt->is_halo())
6015  // If the node is not halo then it could be haloed. If that
6016  // is the case then store the processors at which the node
6017  // is haloed and its id. The info. of these nodes will be
6018  // sent to all the processors with a halo counterpart
6019  else
6020  {
6021  for (unsigned ip = 0; ip < nproc; ip++)
6022  {
6023  // Only work with processors different that the current one
6024  if (ip != my_rank)
6025  {
6026  // If the node is found to be haloed with the "ip"
6027  // processor then save the haloed id in the storage.
6028  // The current processor needs to send info. to the
6029  // other processors to establish the boundary
6030  // coordinates
6031 
6032  // Get the number of haloed nodes with processor ip
6033  const unsigned nhaloed_iproc = this->nhaloed_node(ip);
6034  for (unsigned ihdn = 0; ihdn < nhaloed_iproc; ihdn++)
6035  {
6036  Node* compare_face_node_pt=this->haloed_node_pt(ip, ihdn);
6037  if (face_node_pt == compare_face_node_pt)
6038  {
6039  // Store the node on the haloed node vector for
6040  // the corresponding processor
6041  face_haloed_node_pt[ip].push_back(face_node_pt);
6042  // Now store the halo id of the node with the
6043  // current processor
6044  face_haloed_node_id[ip].push_back(ihdn);
6045  // Mark the node as haloed with other processors,
6046  // so we know the processor in charge is the
6047  // current one "my_rank".
6048  done_haloed_face_node[face_node_pt] = true;
6049  // Break looking in the current processor, look in
6050  // the next one
6051  break;
6052  } // if (face_node_pt == compare_face_node_pt)
6053  } // for (ihdn < nhaloed_node_iproc)
6054  } // if (ip != my_rank)
6055  } // for (ip < nproc)
6056  } // else (non halo node)
6057  } // if (!done_node[node_face_pt])
6058  } // for (in < nnodes)
6059  } // if (!is_halo_face_element[iface])
6060  } // for (iface < nface_ele)
6061 
6062  // -----------------------------------------------------------------
6063  // Fourth: Go through the halo nodes, package and send the
6064  // info. necessary to identify the face nodes in the processor in
6065  // charge. Identify the haloed nodes in the processor in charge and
6066  // establish the boundary coordinates, check if those nodes are
6067  // (already) marked as faced nodes, if that is the case then do not
6068  // establish the boundary coordinates but register them to send back
6069  // the info. to all the processors that have a halo representation
6070  // of the face node
6071  // -----------------------------------------------------------------
6072 
6073  // Go through all processors
6074  for (unsigned ip = 0; ip < nproc; ip++)
6075  {
6076  // Only work with processors different than the current one
6077  if (ip != my_rank)
6078  {
6079  const unsigned nhalo_face_nodes = face_halo_node_pt[ip].size();
6080 #ifdef PARANOID
6081  if (nhalo_face_nodes!=face_halo_node_id[ip].size())
6082  {
6083  std::ostringstream error_message;
6084  error_message
6085  << "The number of found halo face nodes (" << nhalo_face_nodes
6086  << ") is different from the number of\nfound halo face ids ("
6087  << face_halo_node_id[ip].size() << ")!!!\n\n";
6088  throw OomphLibError(error_message.str(),
6089  "TriangleMesh::synchronize_boundary_coordinates()",
6090  OOMPH_EXCEPTION_LOCATION);
6091  }
6092 #endif
6093 
6094  // Container to send the info. related with the halo nodes to be
6095  // identified in the processors in charge
6096  Vector<unsigned> flat_unsigned_send_packed_data;
6097  Vector<double> flat_double_send_packed_data;
6098 
6099  // Go through the halo face nodes in the "ip" processor
6100  for (unsigned ihfn = 0; ihfn < nhalo_face_nodes; ihfn++)
6101  {
6102  // Get the "ihfn"-th face node with the "ip" processor
6103  Node *halo_face_node_pt = face_halo_node_pt[ip][ihfn];
6104  // Get the halo id with the "ip" processor
6105  const unsigned halo_id = face_halo_node_id[ip][ihfn];
6106  // Get the boundary coordinate of the node
6107  Vector<double> zeta(1);
6108  halo_face_node_pt->get_coordinates_on_boundary(b, zeta);
6109  // Store the info. in the containers
6110  flat_unsigned_send_packed_data.push_back(halo_id);
6111  flat_double_send_packed_data.push_back(zeta[0]);
6112  }
6113 
6114  // Send the info.
6115  MPI_Status status;
6116  MPI_Request request;
6117 
6118  // Processor to which send the info
6119  int send_proc = static_cast<int>(ip);
6120  // Processor from which receive the info
6121  int receive_proc = static_cast<int>(ip);
6122 
6123  // Storage to receive the info.
6124  Vector<unsigned> flat_unsigned_receive_packed_data;
6125  Vector<double> flat_double_receive_packed_data;
6126 
6127  // --------------
6128  // Unsigned data
6129  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6130  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6131  send_proc,1,comm_pt->mpi_comm(),&request);
6132 
6133  unsigned nflat_unsigned_receive = 0;
6134  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6135  receive_proc,1,comm_pt->mpi_comm(),&status);
6136 
6137  MPI_Wait(&request,MPI_STATUS_IGNORE);
6138 
6139  if (nflat_unsigned_send!=0)
6140  {
6141  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6142  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6143  }
6144 
6145  if (nflat_unsigned_receive!=0)
6146  {
6147  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6148  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6149  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6150  }
6151 
6152  if (nflat_unsigned_send!=0)
6153  {
6154  MPI_Wait(&request,MPI_STATUS_IGNORE);
6155  }
6156 
6157  // --------------
6158  // Double data
6159  unsigned nflat_double_send = flat_double_send_packed_data.size();
6160  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6161  send_proc,3,comm_pt->mpi_comm(),&request);
6162 
6163  unsigned nflat_double_receive = 0;
6164  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6165  receive_proc,3,comm_pt->mpi_comm(),&status);
6166 
6167  MPI_Wait(&request,MPI_STATUS_IGNORE);
6168 
6169  if (nflat_double_send!=0)
6170  {
6171  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6172  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6173  }
6174 
6175  if (nflat_double_receive!=0)
6176  {
6177  flat_double_receive_packed_data.resize(nflat_double_receive);
6178  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6179  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6180  }
6181 
6182  if (nflat_double_send!=0)
6183  {
6184  MPI_Wait(&request,MPI_STATUS_IGNORE);
6185  }
6186  // --------------
6187 
6188 #ifdef PARANOID
6189  if (nflat_unsigned_receive!=nflat_double_receive)
6190  {
6191  std::ostringstream error_message;
6192  error_message
6193  << "The number of unsigned received data ("
6194  << nflat_unsigned_receive << ") is different from the "
6195  << "number\nof double received data ("
6196  << nflat_double_receive << ")!!!\n\n";
6197  throw OomphLibError(error_message.str(),
6198  "TriangleMesh::synchronize_boundary_coordinates()",
6199  OOMPH_EXCEPTION_LOCATION);
6200  }
6201 #endif
6202 
6203  // With the received info. establish the boundary coordinates
6204  // for the face nodes that this processor is in charge (haloed
6205  // nodes)
6206  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6207  iflat_packed++)
6208  {
6209  // Get the haloed id for the node
6210  const unsigned haloed_id =
6211  flat_unsigned_receive_packed_data[iflat_packed];
6212  // Get the boundary coordinates
6213  Vector<double> zeta(1);
6214  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6215 
6216  // Get the haloed node
6217  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6218 
6219  // If the node has already set the boundary coordinates then
6220  // do not establish it. This is the case for the nodes that
6221  // lie on the boundary, for those nodes not identified on the
6222  // boundary since no elements lie on the boundary but the node
6223  // is on the boundary (a corner of an element lies on the
6224  // boundary) set boundary coordinates and register them to
6225  // send their info. to the processors with a halo counterpart
6226 
6227  // If the node is not haloed face in the procesor in charge
6228  // then set the boundary coordinates and register the node to
6229  // send back the boundary coordinates to the processors with a
6230  // halo counterpart
6231  if (!done_haloed_face_node[haloed_face_node_pt])
6232  {
6233  // Establish the boundary coordinates
6234  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6235 
6236  // Look in all processors where the node could be halo
6237  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6238  {
6239  // Only work with processors different than the current one
6240  if (iiproc != my_rank)
6241  {
6242  // Get the number of haloed nodes with processor iiproc
6243  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6244  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6245  {
6246  Node* compare_haloed_node_pt=this->haloed_node_pt(iiproc,ihdn);
6247  if (haloed_face_node_pt == compare_haloed_node_pt)
6248  {
6249  // Store the node on the haloed node vector for the
6250  // corresponding processor
6251  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6252  // Now store the halo id of the node with the current
6253  // processor
6254  face_haloed_node_id[iiproc].push_back(ihdn);
6255  // Break searching in the current processor, search in
6256  // the next one
6257  break;
6258  }// if (haloed_face_node_pt==compare_haloed_face_node_pt)
6259  } // for (ihdn < nhaloed_node_iproc)
6260  } // if (iiproc != my_rank)
6261  } // for (iiproc < nproc)
6262  } // if (!done_haloed_face_node[haloed_face_node_pt])
6263  } // for (iflat_packed < nflat_unsigned_receive)
6264  } // if (ip != my_rank)
6265  } // for (ip < nproc)
6266 
6267  // -----------------------------------------------------------------
6268  // Fifth: The boundary coordinates have been established in the
6269  // processors in charge of the nodes. Now each processor send back
6270  // the boundary coordinates to all the processors where there is a
6271  // halo representation of the node
6272  // -----------------------------------------------------------------
6273 
6274  // Go through all processors
6275  for (unsigned ip = 0; ip < nproc; ip++)
6276  {
6277  // Only work with processors different than the current one
6278  if (ip != my_rank)
6279  {
6280  // Container to send the info. of the haloed nodes to all the
6281  // processors
6282  Vector<unsigned> flat_unsigned_send_packed_data;
6283  Vector<double> flat_double_send_packed_data;
6284 
6285  // Get the total number of haloed face nodes with the "ip"
6286  // processor
6287  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6288  // Go through the haloed face nodes in the "ip" processor
6289  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6290  {
6291  // Get the "ihdfn"-th face node with the "ip" processor
6292  Node *haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6293  // Get the haloed id with the "ip" processor
6294  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6295  // Get the boundary coordinate of the node
6296  Vector<double> zeta(1);
6297  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6298  // Store the info. in the containers
6299  flat_unsigned_send_packed_data.push_back(haloed_id);
6300  flat_double_send_packed_data.push_back(zeta[0]);
6301  }
6302 
6303  // Send the info.
6304  MPI_Status status;
6305  MPI_Request request;
6306 
6307  // Processor to which send the info
6308  int send_proc = static_cast<int>(ip);
6309  // Processor from which receive the info
6310  int receive_proc = static_cast<int>(ip);
6311 
6312  // Storage to receive the info.
6313  Vector<unsigned> flat_unsigned_receive_packed_data;
6314  Vector<double> flat_double_receive_packed_data;
6315 
6316  // --------------
6317  // Unsigned data
6318  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6319  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6320  send_proc,1,comm_pt->mpi_comm(),&request);
6321 
6322  unsigned nflat_unsigned_receive = 0;
6323  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6324  receive_proc,1,comm_pt->mpi_comm(),&status);
6325 
6326  MPI_Wait(&request,MPI_STATUS_IGNORE);
6327 
6328  if (nflat_unsigned_send!=0)
6329  {
6330  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6331  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6332  }
6333 
6334  if (nflat_unsigned_receive!=0)
6335  {
6336  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6337  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6338  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6339  }
6340 
6341  if (nflat_unsigned_send!=0)
6342  {
6343  MPI_Wait(&request,MPI_STATUS_IGNORE);
6344  }
6345 
6346  // --------------
6347  // Double data
6348  unsigned nflat_double_send = flat_double_send_packed_data.size();
6349  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6350  send_proc,3,comm_pt->mpi_comm(),&request);
6351 
6352  unsigned nflat_double_receive = 0;
6353  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6354  receive_proc,3,comm_pt->mpi_comm(),&status);
6355 
6356  MPI_Wait(&request,MPI_STATUS_IGNORE);
6357 
6358  if (nflat_double_send!=0)
6359  {
6360  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6361  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6362  }
6363 
6364  if (nflat_double_receive!=0)
6365  {
6366  flat_double_receive_packed_data.resize(nflat_double_receive);
6367  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6368  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6369  }
6370 
6371  if (nflat_double_send!=0)
6372  {
6373  MPI_Wait(&request,MPI_STATUS_IGNORE);
6374  }
6375  // --------------
6376 
6377 #ifdef PARANOID
6378  if (nflat_unsigned_receive!=nflat_double_receive)
6379  {
6380  std::ostringstream error_message;
6381  error_message
6382  << "The number of unsigned received data ("
6383  << nflat_unsigned_receive << ") is different from the "
6384  << "number\nof double received data ("
6385  << nflat_double_receive << ")!!!\n\n";
6386  throw OomphLibError(error_message.str(),
6387  "TriangleMesh::synchronize_boundary_coordinates()",
6388  OOMPH_EXCEPTION_LOCATION);
6389  }
6390 #endif
6391 
6392  // With the received info. establish the boundary coordinates
6393  // received for the face nodes that this processor is not in
6394  // charge (halo nodes)
6395  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6396  iflat_packed++)
6397  {
6398  // Get the halo id for the node
6399  const unsigned halo_id =
6400  flat_unsigned_receive_packed_data[iflat_packed];
6401  // Get the boundary coordinates
6402  Vector<double> zeta(1);
6403  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6404 
6405  // Get the halo node
6406  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6407 
6408  // It could be possible that the node has been already
6409  // established boundary coordinates since it is a halo face
6410  // node. However, for those elements not on the boundary, but
6411  // having a corner node on the boundary this procedure will
6412  // establish boundary coordinates for those nodes
6413 
6414  //this->add_boundary_node(b, halo_face_node_pt);
6415 
6416  // Establish the boundary coordinates
6417  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6418  } // for (iflat_packed < nflat_unsigned_receive)
6419  } // if (ip != my_rank)
6420  } // for (ip < nproc)
6421 
6422  // Clean all the created face elements
6423  for (unsigned ie = 0; ie < nbound_ele; ie++)
6424  {
6425  delete tmp_face_ele_pt[ie];
6426  tmp_face_ele_pt[ie] = 0;
6427  }
6428 
6429  // Now get a new face mesh representation and fill the data for those
6430  // processors with halo segments
6431  if (is_internal_boundary)
6432  {
6433  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6434  }
6435 
6436  }
6437 
6438  //======================================================================
6439  /// \short Re-assign the boundary segments initial zeta (arclength)
6440  /// for those internal boundaries that were splited during the
6441  /// distribution process (only apply for internal boundaries that
6442  /// have one face element at each side of the boundary)
6443  //======================================================================
6444  template<class ELEMENT>
6447  const unsigned& b)
6448  {
6449  // ------------------------------------------------------------------
6450  // First: Get the face elements associated with the current boundary
6451  // Only include nonhalo face elements
6452  // ------------------------------------------------------------------
6453  // Temporary storage for face elements
6454  Vector<FiniteElement*> face_el_pt;
6455 
6456  // Temporary storage for the number of elements adjacent to the
6457  // boundary
6458  unsigned nele = 0;
6459 
6460  // Temporary storage for elements adjacent to the boundary that have
6461  // a common edge (related with internal boundaries)
6462  unsigned n_repeated_ele = 0;
6463 
6464  const unsigned n_regions = this->nregion();
6465 
6466  // Temporary storage for already done nodes
6467  Vector<std::pair<Node*, Node*> > done_nodes_pt;
6468 
6469  // If there is more than one region then only use boundary
6470  // coordinates from the bulk side (region 0)
6471  if (n_regions > 1)
6472  {
6473  for (unsigned rr = 0 ; rr < n_regions; rr++)
6474  {
6475  const unsigned region_id =
6476  static_cast<unsigned>(this->Region_attribute[rr]);
6477 
6478  // Loop over all elements on boundaries in region i_r
6479  const unsigned nel_in_region =
6480  this->nboundary_element_in_region(b, region_id);
6481 
6482  unsigned nel_repetead_in_region = 0;
6483 
6484  // Only bother to do anything else, if there are elements
6485  // associated with the boundary and the current region
6486  if (nel_in_region > 0)
6487  {
6488  bool repeated = false;
6489 
6490  // Loop over the bulk elements adjacent to boundary b
6491  for (unsigned e = 0; e < nel_in_region; e++)
6492  {
6493  // Get pointer to the bulk element that is adjacent to
6494  // boundary b
6495  FiniteElement* bulk_elem_pt =
6496  this->boundary_element_in_region_pt(b, region_id, e);
6497 
6498  // Remember only to work with nonhalo elements
6499  if (bulk_elem_pt->is_halo())
6500  {
6501  n_repeated_ele++;
6502  continue;
6503  }
6504 
6505  // Find the index of the face of element e along boundary b
6506  int face_index =
6507  this->face_index_at_boundary_in_region(b,region_id,e);
6508 
6509  // Before adding the new element we need to be sure that the
6510  // edge that this element represent has not been already
6511  // added
6512  FiniteElement* tmp_ele_pt =
6513  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6514 
6515  const unsigned n_nodes = tmp_ele_pt->nnode();
6516 
6517  std::pair<Node*, Node*> tmp_pair =
6518  std::make_pair(tmp_ele_pt->node_pt(0),
6519  tmp_ele_pt->node_pt(n_nodes - 1));
6520 
6521  std::pair<Node*, Node*> tmp_pair_inverse =
6522  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6523  tmp_ele_pt->node_pt(0));
6524 
6525  // Search for repeated nodes
6526  const unsigned n_done_nodes = done_nodes_pt.size();
6527  for (unsigned l = 0; l < n_done_nodes; l++)
6528  {
6529  if (tmp_pair == done_nodes_pt[l] ||
6530  tmp_pair_inverse == done_nodes_pt[l])
6531  {
6532  nel_repetead_in_region++;
6533  repeated = true;
6534  break;
6535  }
6536  }
6537 
6538  // Create new face element
6539  if (!repeated)
6540  {
6541  // Add the pair of nodes (edge) to the node dones
6542  done_nodes_pt.push_back(tmp_pair);
6543  // Add the element to the face elements
6544  face_el_pt.push_back(tmp_ele_pt);
6545  }
6546  else
6547  {
6548  // Clean up
6549  delete tmp_ele_pt;
6550  tmp_ele_pt = 0;
6551  }
6552 
6553  // Re-start
6554  repeated = false;
6555 
6556  } // for nel
6557 
6558  nele += nel_in_region;
6559 
6560  n_repeated_ele += nel_repetead_in_region;
6561 
6562  } // if (nel_in_region > 0)
6563  } // for (rr < n_regions)
6564  } // if (n_regions > 1)
6565  //Otherwise it's just the normal boundary functions
6566  else
6567  {
6568  // Loop over all elements on boundaries
6569  nele = this->nboundary_element(b);
6570 
6571  //Only bother to do anything else, if there are elements
6572  if (nele > 0)
6573  {
6574  // Check for repeated ones
6575  bool repeated = false;
6576 
6577  // Loop over the bulk elements adjacent to boundary b
6578  for (unsigned e = 0; e < nele; e++)
6579  {
6580  // Get pointer to the bulk element that is adjacent to
6581  // boundary b
6582  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6583 
6584  // Remember only to work with nonhalo elements
6585  if (bulk_elem_pt->is_halo())
6586  {
6587  n_repeated_ele++;
6588  // Skip the halo element
6589  continue;
6590  }
6591 
6592  //Find the index of the face of element e along boundary b
6593  int face_index = this->face_index_at_boundary(b, e);
6594 
6595  // Before adding the new element we need to be sure that the
6596  // edge that this element represents has not been already
6597  // added (only applies for internal boundaries)
6598  FiniteElement* tmp_ele_pt =
6599  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6600 
6601  const unsigned n_nodes = tmp_ele_pt->nnode();
6602 
6603  std::pair<Node*, Node*> tmp_pair =
6604  std::make_pair(tmp_ele_pt->node_pt(0),
6605  tmp_ele_pt->node_pt(n_nodes - 1));
6606 
6607  std::pair<Node*, Node*> tmp_pair_inverse =
6608  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6609  tmp_ele_pt->node_pt(0));
6610 
6611  // Search for repeated nodes
6612  const unsigned n_done_nodes = done_nodes_pt.size();
6613  for (unsigned l = 0; l < n_done_nodes; l++)
6614  {
6615  if (tmp_pair == done_nodes_pt[l] ||
6616  tmp_pair_inverse == done_nodes_pt[l])
6617  {
6618  // Increase the number of repeated elements
6619  n_repeated_ele++;
6620  // Mark the element as repeated
6621  repeated = true;
6622  break;
6623  }
6624  }
6625 
6626  // Create new face element
6627  if (!repeated)
6628  {
6629  // Add the pair of nodes (edge) to the node dones
6630  done_nodes_pt.push_back(tmp_pair);
6631  // Add the element to the face elements
6632  face_el_pt.push_back(tmp_ele_pt);
6633  }
6634  else
6635  {
6636  // Free the repeated bulk element!!
6637  delete tmp_ele_pt;
6638  tmp_ele_pt = 0;
6639  }
6640 
6641  // Re-start
6642  repeated = false;
6643 
6644  } // for (e < nel)
6645  } // if (nel > 0)
6646 
6647  } // else (n_regions > 1)
6648 
6649  // Do not consider the repeated elements
6650  nele-= n_repeated_ele;
6651 
6652 #ifdef PARANOID
6653  if (nele!=face_el_pt.size())
6654  {
6655  std::ostringstream error_message;
6656  error_message
6657  << "The independet counting of face elements ("<<nele<<") for "
6658  << "boundary ("<<b<<") is different\n"
6659  << "from the real number of face elements in the container ("
6660  << face_el_pt.size() <<")\n";
6661  //<< "Possible memory leak\n"
6662  throw OomphLibError(error_message.str(),
6663  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6664  OOMPH_EXCEPTION_LOCATION);
6665  }
6666 #endif
6667 
6668  // ----------------------------------------------------------------
6669  // Second: Sort the face elements (to create segments), only
6670  // consider nonhalo elements
6671  // ----------------------------------------------------------------
6672 
6673  // Get the total number of nonhalo face elements
6674  const unsigned nnon_halo_face_elements = face_el_pt.size();
6675 
6676  // The vector of list to store the "segments" that compound the
6677  // boundary (segments may appear only in a distributed mesh)
6678  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
6679 
6680  // Number of already sorted face elements
6681  unsigned nsorted_face_elements = 0;
6682 
6683  // Keep track of who's done
6684  std::map<FiniteElement*, bool> done_el;
6685 
6686  // Keep track of which element is inverted
6687  std::map<FiniteElement*, bool> is_inverted;
6688 
6689  // Iterate until all possible segments have been created
6690  while(nsorted_face_elements < nnon_halo_face_elements)
6691  {
6692  // The ordered list of face elements (in a distributed mesh a
6693  // collection of contiguous face elements define a segment)
6694  std::list<FiniteElement*> sorted_el_pt;
6695 
6696 #ifdef PARANOID
6697  // Select an initial element for the segment
6698  bool found_initial_face_element = false;
6699 #endif
6700 
6701  FiniteElement* ele_face_pt = 0;
6702 
6703  unsigned iface = 0;
6704  for (iface = 0; iface < nele; iface++)
6705  {
6706  ele_face_pt = face_el_pt[iface];
6707  // If not done then take it as initial face element
6708  if (!done_el[ele_face_pt])
6709  {
6710 #ifdef PARANOID
6711  found_initial_face_element = true;
6712 #endif
6713  nsorted_face_elements++;
6714  iface++; // The next element number
6715  sorted_el_pt.push_back(ele_face_pt);
6716  // Mark as done
6717  done_el[ele_face_pt] = true;
6718  break;
6719  }
6720  } // for (iface < nele)
6721 
6722 #ifdef PARANOID
6723  if (!found_initial_face_element)
6724  {
6725  std::ostringstream error_message;
6726  error_message
6727  <<"Could not find an initial face element for the current segment\n";
6728  // << "----- Possible memory leak -----\n";
6729  throw OomphLibError(error_message.str(),
6730  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6731  OOMPH_EXCEPTION_LOCATION);
6732  }
6733 #endif
6734 
6735  // Number of nodes
6736  const unsigned nnod = ele_face_pt->nnode();
6737 
6738  // Left and rightmost nodes (the left and right nodes of the
6739  // current face element)
6740  Node* left_node_pt = ele_face_pt->node_pt(0);
6741  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6742 
6743  // Continue iterating if a new face element has been added to the
6744  // list
6745  bool face_element_added = false;
6746 
6747  // While a new face element has been added to the set of sorted
6748  // face elements then re-iterate
6749  do
6750  {
6751  // Start from the next face element since we have already added
6752  // the previous one as the initial face element (any previous
6753  // face element had to be added on previous iterations)
6754  for (unsigned iiface = iface; iiface < nele; iiface++)
6755  {
6756  // Re-start flag
6757  face_element_added = false;
6758 
6759  // Get the candidate element
6760  ele_face_pt = face_el_pt[iiface];
6761 
6762  // Check that the candidate element has not been done
6763  if (!(done_el[ele_face_pt]))
6764  {
6765  // Get the left and right nodes of the current element
6766  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6767  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6768 
6769  // New element fits at the left of segment and is not inverted
6770  if (left_node_pt == local_right_node_pt)
6771  {
6772  left_node_pt = local_left_node_pt;
6773  sorted_el_pt.push_front(ele_face_pt);
6774  is_inverted[ele_face_pt] = false;
6775  face_element_added = true;
6776  }
6777  // New element fits at the left of segment and is inverted
6778  else if (left_node_pt == local_left_node_pt)
6779  {
6780  left_node_pt = local_right_node_pt;
6781  sorted_el_pt.push_front(ele_face_pt);
6782  is_inverted[ele_face_pt] = true;
6783  face_element_added = true;
6784  }
6785  // New element fits on the right of segment and is not inverted
6786  else if (right_node_pt == local_left_node_pt)
6787  {
6788  right_node_pt = local_right_node_pt;
6789  sorted_el_pt.push_back(ele_face_pt);
6790  is_inverted[ele_face_pt] = false;
6791  face_element_added = true;
6792  }
6793  // New element fits on the right of segment and is inverted
6794  else if (right_node_pt == local_right_node_pt)
6795  {
6796  right_node_pt = local_left_node_pt;
6797  sorted_el_pt.push_back(ele_face_pt);
6798  is_inverted[ele_face_pt] = true;
6799  face_element_added = true;
6800  }
6801 
6802  if (face_element_added)
6803  {
6804  done_el[ele_face_pt] = true;
6805  nsorted_face_elements++;
6806  break;
6807  }
6808 
6809  } // if (!(done_el[ele_face_pt]))
6810  } // for (iiface<nnon_halo_face_element)
6811  }while(face_element_added &&
6812  (nsorted_face_elements < nnon_halo_face_elements));
6813 
6814  // Store the created segment in the vector of segments
6815  segment_sorted_ele_pt.push_back(sorted_el_pt);
6816 
6817  } // while(nsorted_face_elements < nnon_halo_face_elements);
6818 
6819  // --------------------------------------------------------------
6820  // Third: We have the face elements sorted, now assign boundary
6821  // coordinates to the nodes in the segments and compute the
6822  // arclength of the segment
6823  // --------------------------------------------------------------
6824 
6825  // Vector of sets that stores the nodes of each segment based on a
6826  // lexicographically order starting from the bottom left node of
6827  // each segment
6828  Vector<std::set<Node*> > segment_all_nodes_pt;
6829 
6830  // The number of segments in this processor
6831  const unsigned nsegments = segment_sorted_ele_pt.size();
6832 
6833 #ifdef PARANOID
6834  if (nnon_halo_face_elements > 0 && nsegments == 0)
6835  {
6836  std::ostringstream error_message;
6837  error_message
6838  << "The number of segments is zero, but the number of nonhalo\n"
6839  << "elements is: (" << nnon_halo_face_elements << ")\n";
6840  throw OomphLibError(error_message.str(),
6841  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6842  OOMPH_EXCEPTION_LOCATION);
6843  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6844 #endif
6845 
6846  // The arclength of each segment in the current processor
6847  Vector<double> segment_arclength(nsegments);
6848 
6849  // The initial zeta for the segment
6850  Vector<double> initial_zeta_segment(nsegments);
6851 
6852  // The final zeta for the segment
6853  Vector<double> final_zeta_segment(nsegments);
6854 
6855  // Go through all the segments and compute the LOCAL boundary
6856  // coordinates
6857  for (unsigned is = 0; is < nsegments; is++)
6858  {
6859 #ifdef PARANOID
6860  if (segment_sorted_ele_pt[is].size() == 0)
6861  {
6862  std::ostringstream error_message;
6863  error_message
6864  << "The (" << is << ")-th segment has no elements\n";
6865  throw OomphLibError(error_message.str(),
6866  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6867  OOMPH_EXCEPTION_LOCATION);
6868  } // if (segment_sorted_ele_pt[is].size() == 0)
6869 #endif
6870 
6871  // Get access to the first element on the segment
6872  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6873 
6874  // Number of nodes
6875  const unsigned nnod = first_ele_pt->nnode();
6876 
6877  // Get the first node of the current segment
6878  Node *first_node_pt = first_ele_pt->node_pt(0);
6879  if (is_inverted[first_ele_pt])
6880  {
6881  first_node_pt = first_ele_pt->node_pt(nnod-1);
6882  }
6883 
6884  // Get access to the last element on the segment
6885  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
6886 
6887  // Get the last node of the current segment
6888  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
6889  if (is_inverted[last_ele_pt])
6890  {
6891  last_node_pt = last_ele_pt->node_pt(0);
6892  }
6893 
6894  // Coordinates of left node
6895  double x_left = first_node_pt->x(0);
6896  double y_left = first_node_pt->x(1);
6897 
6898  // Initialise boundary coordinate (local boundary coordinate for
6899  // boundaries with more than one segment)
6900  Vector<double> zeta(1, 0.0);
6901 
6902  // If we have associated a GeomObject then it is not necessary to
6903  // compute the arclength, only read the values from the nodes at
6904  // the edges
6905  if (this->boundary_geom_object_pt(b)!=0)
6906  {
6907  first_node_pt->get_coordinates_on_boundary(b, zeta);
6908  initial_zeta_segment[is] = zeta[0];
6909  last_node_pt->get_coordinates_on_boundary(b, zeta);
6910  final_zeta_segment[is] = zeta[0];
6911  }
6912 
6913  // Lexicographically bottom left node
6914  std::set<Node*> local_nodes_pt;
6915  local_nodes_pt.insert(first_node_pt);
6916 
6917  // Now loop over nodes in order
6918  for (std::list<FiniteElement*>::iterator it =
6919  segment_sorted_ele_pt[is].begin();
6920  it != segment_sorted_ele_pt[is].end(); it++)
6921  {
6922  // Get element
6923  FiniteElement* el_pt = *it;
6924 
6925  // Start node and increment
6926  unsigned k_nod = 1;
6927  int nod_diff = 1;
6928  if (is_inverted[el_pt])
6929  {
6930  k_nod = nnod - 2;
6931  nod_diff = -1;
6932  }
6933 
6934  // Loop over nodes
6935  for (unsigned j = 1; j < nnod; j++)
6936  {
6937  Node* nod_pt = el_pt->node_pt(k_nod);
6938  k_nod += nod_diff;
6939 
6940  // Coordinates of right node
6941  double x_right = nod_pt->x(0);
6942  double y_right = nod_pt->x(1);
6943 
6944  // Increment boundary coordinate
6945  zeta[0] += sqrt(
6946  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
6947  * (y_right - y_left));
6948 
6949  // Increment reference coordinate
6950  x_left = x_right;
6951  y_left = y_right;
6952 
6953  // Get lexicographically bottom left node but only
6954  // use vertex nodes as candidates
6955  local_nodes_pt.insert(nod_pt);
6956 
6957  } // for (j < nnod)
6958  } // iterator over the elements in the segment
6959 
6960  // Store the arclength of the segment
6961  segment_arclength[is] = zeta[0];
6962 
6963  // Add the nodes for the corresponding segment in the container
6964  segment_all_nodes_pt.push_back(local_nodes_pt);
6965 
6966  } // for (is < nsegments)
6967 
6968  // ------------------------------------------------------------------
6969  // Fourth: Now we have the segments sorted, with arclength and with
6970  // LOCAL arclength assigned to the nodes. Procced to re-scale the
6971  // coordinates on the nodes based on the arclength
6972  // ------------------------------------------------------------------
6973 
6974  // ------------------------------------------------------------------
6975  // Clear the original storages
6976  Boundary_segment_inverted[b].clear();
6977  Boundary_segment_initial_coordinate[b].clear();
6978  Boundary_segment_final_coordinate[b].clear();
6979 
6980  Boundary_segment_initial_zeta[b].clear();
6981  Boundary_segment_final_zeta[b].clear();
6982 
6983  Boundary_segment_initial_arclength[b].clear();
6984  Boundary_segment_final_arclength[b].clear();
6985 
6986  // Get the zeta values for the first and last node in the boundary
6987  Vector<double> first_node_zeta_coordinate(1,0.0);
6988  Vector<double> last_node_zeta_coordinate(1,0.0);
6989  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
6990  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
6991 
6992  // Get the boundary arclength
6993  const double boundary_arclength =
6994  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
6995 
6996  // Go through the segments and get the first and last node for each
6997  // segment
6998  for (unsigned is = 0; is < nsegments; is++)
6999  {
7000  // Get the first face element of the segment
7001  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
7002 
7003  // The number of nodes
7004  const unsigned nnod = first_face_ele_pt->nnode();
7005 
7006  // ... and the first node of the segment
7007  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7008  if (is_inverted[first_face_ele_pt])
7009  {
7010  first_node_pt = first_face_ele_pt->node_pt(nnod-1);
7011  }
7012 
7013  // Get the bound coordinates of the node
7014  Vector<double> zeta_first(1);
7015  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7016 
7017  // Get the last face element of the segment
7018  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7019 
7020  // ... and the last node of the segment
7021  Node* last_node_pt = last_face_ele_pt->node_pt(nnod-1);
7022  if (is_inverted[last_face_ele_pt])
7023  {
7024  last_node_pt = last_face_ele_pt->node_pt(0);
7025  }
7026 
7027  // Get the bound coordinates of the node
7028  Vector<double> zeta_last(1);
7029  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7030 
7031  // Now that we have the first and last node of the segment, get
7032  // the coordinates of the nodes
7033  Vector<double> first_node_coord(2);
7034  Vector<double> last_node_coord(2);
7035  for (unsigned i = 0; i < 2; i++)
7036  {
7037  first_node_coord[i] = first_node_pt->x(i);
7038  last_node_coord[i] = last_node_pt->x(i);
7039  }
7040 
7041  // Re-assign the values to identify the segments on the new mesh
7042  Boundary_segment_inverted[b].push_back(0);
7043  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7044  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7045 
7046  // Check if the boudary has an associated GeomObject
7047  if (this->boundary_geom_object_pt(b)!=0)
7048  {
7049  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7050  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7051  }
7052  else
7053  {
7054  // Re-assign the values and re-scale them
7055  Boundary_segment_initial_arclength[b].push_back(
7056  zeta_first[0] * boundary_arclength);
7057  Boundary_segment_final_arclength[b].push_back(
7058  zeta_last[0] * boundary_arclength);
7059  }
7060 
7061  } // for (is < nsegments)
7062 
7063  // Clean all the created face elements
7064  for (unsigned i = 0; i < nele; i++)
7065  {
7066  delete face_el_pt[i];
7067  face_el_pt[i] = 0;
7068  }
7069 
7070  }
7071 
7072 #endif // OOMPH_HAS_MPI
7073 
7074 
7075 
7076 #ifdef OOMPH_HAS_TRIANGLE_LIB
7077 
7078  //========================================================================
7079  /// Create TriangulateIO object via the .poly file
7080  //========================================================================
7081  template <class ELEMENT>
7083  build_triangulateio(const std::string& poly_file_name,
7084  TriangulateIO& triangulate_io,
7085  bool &use_attributes)
7086  {
7087 
7088  // Process poly file
7089  // -----------------
7090  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
7091  if(!poly_file)
7092  {
7093  throw OomphLibError("Error opening .poly file\n",
7094  OOMPH_CURRENT_FUNCTION,
7095  OOMPH_EXCEPTION_LOCATION);
7096  }
7097 
7098  // Initialize triangulateio structure
7100 
7101  // Ignore the first line with structure description
7102  poly_file.ignore(80,'\n');
7103 
7104  // Read and store number of nodes
7105  unsigned invertices;
7106  poly_file>>invertices;
7107  triangulate_io.numberofpoints=invertices;
7108 
7109  // Initialisation of the point list
7110  triangulate_io.pointlist =
7111  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7112 
7113  // Read and store spatial dimension of nodes
7114  unsigned mesh_dim;
7115  poly_file>>mesh_dim;
7116 
7117  if(mesh_dim == 0)
7118  {
7119  mesh_dim=2;
7120  }
7121 
7122 #ifdef PARANOID
7123  if(mesh_dim!=2)
7124  {
7125  throw OomphLibError("The dimension must be 2\n",
7126  OOMPH_CURRENT_FUNCTION,
7127  OOMPH_EXCEPTION_LOCATION);
7128  }
7129 #endif
7130 
7131  // Read and check the flag for attributes
7132  unsigned nextras;
7133  poly_file>> nextras;
7134 
7135  triangulate_io.numberofpointattributes = 0;
7136  triangulate_io.pointattributelist = (double *) NULL;
7137 
7138  // Read and check the flag for boundary markers
7139  unsigned nodemarkers;
7140  poly_file>>nodemarkers;
7141  triangulate_io.pointmarkerlist = (int *) NULL;
7142 
7143 #ifdef PARANOID
7144  // Reading the .poly with the oomph.lib we need
7145  // to set the point attribute and markers to 0
7146  if(nextras!=0 || nodemarkers!=0)
7147  {
7148  oomph_info << "===================================================="
7149  << std::endl<<std::endl;
7150  oomph_info <<"Reading the .poly file via oomph_lib \n"
7151  <<"point's attribute and point's markers \n"
7152  <<"are automatically set to 0"<<std::endl;
7153  oomph_info << "===================================================="
7154  <<std::endl;
7155  }
7156 #endif
7157 
7158  // Dummy for node number (and attribute or markers if included)
7159  unsigned dummy_value;
7160  unsigned count_point=0;
7161  std::string test_string;
7162 
7163  // Skip line with commentary
7164  getline(poly_file,test_string,'#');
7165  poly_file.ignore(80,'\n');
7166 
7167  // Read and store all the nodes coordinates
7168  // (hole's vertices as well)
7169  for(unsigned count=0;count<invertices;count++)
7170  {
7171  poly_file>>dummy_value;
7172  poly_file>>triangulate_io.pointlist[count_point];
7173  poly_file>>triangulate_io.pointlist[count_point+1];
7174  if(nextras!=0 || nodemarkers!=0)
7175  {
7176  for(unsigned j=0;j<nextras;j++)
7177  {
7178  poly_file>>dummy_value;
7179  }
7180  }
7181  else if(nextras!=0 && nodemarkers!=0)
7182  {
7183  for(unsigned j=0;j<nextras;j++)
7184  {
7185  poly_file>>dummy_value;
7186  poly_file>>dummy_value;
7187  }
7188  }
7189  // Read the next line
7190  poly_file.ignore(80,'\n');
7191 
7192  // Skip line with commentary for internal box whether found
7193  if(poly_file.get() == '#')
7194  {
7195  poly_file.ignore(80,'\n');
7196  }
7197  // If read the char should be put back in the string
7198 
7199  else
7200  {
7201  poly_file.unget();
7202  }
7203  count_point+=2;
7204  }
7205 
7206  // The line with the segment's commentary has been skipped
7207  // by the command of the last loop
7208 
7209  // Read and store the number of segments
7210  unsigned dummy_seg;
7211  unsigned inelements;
7212  poly_file>>inelements;
7213 
7214  unsigned segment_markers;
7215  poly_file>>segment_markers;
7216 
7217  // Marker list should be provided by the user to assign
7218  // each segment to a boundary
7219 #ifdef PARANOID
7220  if(segment_markers!=1)
7221  {
7222 
7223  std::ostringstream error_stream;
7224  error_stream
7225  <<"The segment marker should be provided \n"
7226  <<"In order to assign each segment to a boundary \n "<< std::endl;
7227 
7228  throw OomphLibError(error_stream.str(),
7229  OOMPH_CURRENT_FUNCTION,
7230  OOMPH_EXCEPTION_LOCATION);
7231  }
7232 #endif
7233 
7234  triangulate_io.numberofsegments = inelements;
7235  triangulate_io.segmentlist =
7236  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7237  triangulate_io.segmentmarkerlist =
7238  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
7239 
7240  // Read all the segments edges and markers
7241  for(unsigned i=0;i<2*inelements;i+=2)
7242  {
7243  poly_file>>dummy_seg;
7244  poly_file>>triangulate_io.segmentlist[i];
7245  poly_file>>triangulate_io.segmentlist[i+1];
7246  if(segment_markers!=0)
7247  {
7248  poly_file>>triangulate_io.segmentmarkerlist[i/2];
7249  }
7250 
7251  //Skip line with commentary
7252  poly_file.ignore(80,'\n');
7253  }
7254 
7255  // Read and store the number of holes if given
7256  // Skip line with commentary
7257  if(getline(poly_file,test_string,'#'))
7258  {
7259  poly_file.ignore(80,'\n');
7260 
7261  unsigned dummy_hole;
7262  unsigned nhole;
7263  poly_file>>nhole;
7264 
7265  triangulate_io.numberofholes = nhole;
7266  triangulate_io.holelist =
7267  (double *) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7268 
7269  // Loop over the holes to get centre coords and store value onto the
7270  // TriangulateIO object
7271  for(unsigned i=0;i<2*nhole;i+=2)
7272  {
7273  poly_file>>dummy_hole;
7274  poly_file>>triangulate_io.holelist[i];
7275  poly_file>>triangulate_io.holelist[i+1];
7276  }
7277  }
7278 
7279  // Read and store the number of regions if given
7280  // Skip line with commentary
7281  if(getline(poly_file,test_string,'#'))
7282  {
7283  poly_file.ignore(80,'\n');
7284 
7285  unsigned dummy_region;
7286  unsigned nregion;
7287  poly_file>>nregion;
7288  std::cerr << "Regions: "<< nregion << std::endl;
7289  getchar();
7290 
7291  triangulate_io.numberofregions = nregion;
7292  triangulate_io.regionlist =
7293  (double *) malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7294 
7295  // Check for using regions
7296  if (nregion > 0)
7297  {use_attributes=true;}
7298 
7299  // Loop over the regions to get coords and store value onto the
7300  // TriangulateIO object
7301  for(unsigned i=0;i<nregion;i++)
7302  {
7303  poly_file>>dummy_region;
7304  poly_file>>triangulate_io.regionlist[4*i];
7305  poly_file>>triangulate_io.regionlist[4*i+1];
7306  poly_file>>triangulate_io.regionlist[4*i+2];
7307  triangulate_io.regionlist[4*i+3] = 0.0;
7308  }
7309  }
7310 
7311  }
7312 
7313 #endif
7314 
7315 #ifdef OOMPH_HAS_TRIANGLE_LIB
7316 #ifdef OOMPH_HAS_MPI
7317 
7318  //======================================================================
7319  /// Used to dump info. related with distributed triangle meshes
7320  //======================================================================
7321  template<class ELEMENT>
7323  dump_distributed_info_for_restart(std::ostream &dump_file)
7324  {
7325  // First check that the mesh is distributed
7326  if (this->is_mesh_distributed())
7327  {
7328  // Save the original number of boundaries
7329  const unsigned nboundary = this->nboundary();
7330  dump_file << nboundary
7331  << " # number of original boundaries" << std::endl;
7332 
7333  // Save the number of shared boundaries
7334  const unsigned nshared_boundaries = this->nshared_boundaries();
7335  dump_file << nshared_boundaries
7336  << " # number of shared boundaries" << std::endl;
7337 
7338  // Save the initial and final shared boundaries ids
7339  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7340  dump_file << init_shd_bnd_id
7341  << " # initial shared boundaries id" << std::endl;
7342 
7343  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7344  dump_file << final_shd_bnd_id
7345  << " # final shared boundaries id" << std::endl;
7346 
7347  // Save the number of processors
7348  const unsigned nprocs = this->shared_boundaries_ids().size();
7349  dump_file << nprocs << " # number of processors" << std::endl;
7350 
7351  // Now save the processors ids and the shared boundary created
7352  // by them
7353  for (unsigned ip = 0; ip < nprocs; ip++)
7354  {
7355  for (unsigned jp = 0; jp < nprocs; jp++)
7356  {
7357  if (ip != jp)
7358  {
7359  // Get the number of shared boundaries with it these two
7360  // processors
7361  const unsigned nshared_boundaries_iproc_jproc =
7362  this->shared_boundaries_ids(ip, jp).size();
7363 
7364  // Save the number of shared boundaries with in these two
7365  // processors
7366  dump_file << nshared_boundaries_iproc_jproc
7367  << " # number of shared boundaries with in two "
7368  << "processors" << std::endl;
7369  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7370  {
7371  const unsigned shared_boundary_id =
7372  this->shared_boundaries_ids(ip, jp, is);
7373  dump_file << ip << " " << jp << " " << shared_boundary_id
7374  << " # ip jp shared_boundary of processors ip and jp"
7375  << std::endl;
7376 
7377  } // for (is < nshared_boundaries_iproc_jproc)
7378  }
7379  } // for (jp < nprocs)
7380  } // for (ip < nprocs)
7381 
7382  // Now save the info. that states which shared boundary overlaps
7383  // an internal boundary
7384 
7385  // First check if there are shared boundaries overlapping internal
7386  // boundaries
7387  const unsigned nshared_boundaries_overlap_internal_boundaries =
7388  this->nshared_boundary_overlaps_internal_boundary();
7389  dump_file << nshared_boundaries_overlap_internal_boundaries
7390  << " # number of shared boundaries that overlap internal "
7391  << "boundaries" << std::endl;
7392 
7393  if (nshared_boundaries_overlap_internal_boundaries > 0)
7394  {
7395  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7396  {
7397  // Check if the current shared boundary overlaps an internal
7398  // boundary
7399  if (this->shared_boundary_overlaps_internal_boundary(isb))
7400  {
7401  // Which internal boundary is overlapped by the shared
7402  // boundary
7403  const unsigned overlapped_internal_boundary =
7404  shared_boundary_overlapping_internal_boundary(isb);
7405  // Save the shared boundary that overlaps the internal boundary
7406  dump_file << isb << " " << overlapped_internal_boundary
7407  << " # the shared boundary overlaps the internal "
7408  << "boundary " << std::endl;
7409 
7410  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7411  } // for (isb < final_shd_bnd_id)
7412  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7413 
7414  // Now save the info. related with the initial and final
7415  // boundary coordinates for each original boundary
7416 
7417  // Go through all the (original) boundaries to update the initial
7418  // and final boundary coordinates
7419  for (unsigned b = 0; b < nboundary; b++)
7420  {
7421  // Check if the boundary zeta coordinates for this boundary have
7422  // been already assigned, if that is the case then state the
7423  // flag to know that info. should be read
7424  if (Assigned_segments_initial_zeta_values[b])
7425  {
7426  // The boundary coordinates have been computed then state
7427  // the flag and save the info.
7428  dump_file << "1 # assigned boundary coordinates initial zeta values"
7429  << std::endl;
7430 
7431  // Save the initial and final boundary coordinates, same as
7432  // the initial and final zeta values for each boundary
7433 
7434  // First the vertices coordinates
7435  Vector<double> initial_coordinates=this->boundary_initial_coordinate(b);
7436 
7437  Vector<double> final_coordinates=this->boundary_final_coordinate(b);
7438 
7439  dump_file << std::setprecision(14)
7440  << initial_coordinates[0] << " " << initial_coordinates[1]
7441  << " # initial coordinates for the current boundary"
7442  << std::endl;
7443 
7444  dump_file << std::setprecision(14)
7445  << final_coordinates[0] << " " << final_coordinates[1]
7446  << " # final coordinates for the current boundary"
7447  << std::endl;
7448 
7449  // ... then the zeta values
7450 
7451 #ifdef PARANOID
7452  // Get the number of zeta coordinates (should be one)
7453  const unsigned zeta_size =
7454  this->boundary_initial_zeta_coordinate(b).size();
7455 
7456  if (zeta_size != 1)
7457  {
7458  std::ostringstream error_message;
7459  error_message
7460  <<"The dimension for the zeta values container is different\n"
7461  << "from 1, the current implementation only supports\n"
7462  << "one-dimensioned zeta containers\n\n";
7463  throw OomphLibError(error_message.str(),
7464  "TriangleMesh::dump_distributed_info_for_restart()",
7465  OOMPH_EXCEPTION_LOCATION);
7466  }
7467 #endif
7468 
7469  Vector<double> zeta_initial = this->boundary_initial_zeta_coordinate(b);
7470  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7471 
7472  dump_file << std::setprecision(14)
7473  << zeta_initial[0]
7474  << " # initial zeta value for the current boundary"
7475  << std::endl;
7476 
7477  dump_file << std::setprecision(14)
7478  << zeta_final[0]
7479  << " # final zeta value for the current boundary"
7480  << std::endl;
7481 
7482  // Get the number of segments of the current boundary
7483  const unsigned nsegments = this->nboundary_segment(b);
7484  // Save the number of segments of the current boundary
7485  dump_file << b << " " << nsegments
7486  << " # of segments for the current boundary"
7487  << std::endl;
7488 
7489  // ... and then save that info for each segments
7490  for (unsigned is = 0; is < nsegments; is++)
7491  {
7492  // First the vertices coordinates
7493  Vector<double> initial_segment_coordinates =
7494  this->boundary_segment_initial_coordinate(b)[is];
7495  Vector<double> final_segment_coordinates =
7496  this->boundary_segment_final_coordinate(b)[is];
7497 
7498  dump_file << std::setprecision(14)
7499  << initial_segment_coordinates[0] << " "
7500  << initial_segment_coordinates[1]
7501  << " # initial segment coordinates for the current boundary"
7502  << std::endl;
7503 
7504  dump_file << std::setprecision(14)
7505  << final_segment_coordinates[0] << " "
7506  << final_segment_coordinates[1]
7507  << " # final segment coordinates for the current boundary"
7508  << std::endl;
7509 
7510  // ... then the zeta values
7511 
7512  if (this->boundary_geom_object_pt(b)!=0)
7513  {
7514  const double zeta_segment_initial =
7515  this->boundary_segment_initial_zeta(b)[is];
7516  const double zeta_segment_final =
7517  this->boundary_segment_final_zeta(b)[is];
7518 
7519  dump_file << std::setprecision(14)
7520  << zeta_segment_initial
7521  << " # initial segment zeta value for the current boundary"
7522  << std::endl;
7523 
7524  dump_file << std::setprecision(14)
7525  << zeta_segment_final
7526  << " # final segment zeta value for the current boundary"
7527  << std::endl;
7528  }
7529  else
7530  {
7531  const double arclength_segment_initial =
7532  this->boundary_segment_initial_arclength(b)[is];
7533  const double arclength_segment_final =
7534  this->boundary_segment_final_arclength(b)[is];
7535 
7536  dump_file << std::setprecision(14)
7537  << arclength_segment_initial
7538  << " # initial segment arclength for the current boundary"
7539  << std::endl;
7540 
7541  dump_file << std::setprecision(14)
7542  << arclength_segment_final
7543  << " # final segment arclength for the current boundary"
7544  << std::endl;
7545 
7546  } // else if (this->boundary_geom_object_pt(b)!=0)
7547 
7548  } // for (is < nsegments)
7549 
7550  } // if (Assigned_segments_initial_zeta_values[b])
7551  else
7552  {
7553  // The boundary coordinates have NOT been computed then state
7554  // the flag and save the info.
7555  dump_file << "0 # assigned boundary coordinates initial zeta values"
7556  << std::endl;
7557  }
7558 
7559  } // for (b < nboundary)
7560 
7561  } // if (this->is_mesh_distributed())
7562 
7563  }
7564 
7565  //======================================================================
7566  /// Used to read info. related with distributed triangle meshes
7567  //======================================================================
7568  template<class ELEMENT>
7570  read_distributed_info_for_restart(std::istream &restart_file)
7571  {
7572  // First check that the mesh is distributed
7573  if (this->is_mesh_distributed())
7574  {
7575  // Read the number of original boundaries
7576  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7577 
7578 #ifdef PARANOID
7579  if (n_boundary != this->nboundary())
7580  {
7581  std::ostringstream error_message;
7582  error_message
7583  << "The number of boundaries (" << n_boundary << ") on the "
7584  << "file used for restarting is different\nfrom the number of "
7585  << "boundaries ("<< this->nboundary() << ") on the current "
7586  << "mesh!!!\n\n\n";
7587  throw OomphLibError(error_message.str(),
7588  "TriangleMesh::read_distributed_info_for_restart()",
7589  OOMPH_EXCEPTION_LOCATION);
7590  }
7591 #endif
7592 
7593  // Read the number of shared boundaries
7594  unsigned n_shared_boundaries =
7595  read_unsigned_line_helper(restart_file);
7596  // We need to read the data because it comes in the file (add and
7597  // substract to avoid compilation warning)
7598  n_shared_boundaries++;
7599  n_shared_boundaries--;
7600 
7601  // Read the initial and final shared boundaries ids
7602  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7603  // We need to read the data because it comes in the file (add and
7604  // substract to avoid compilation warning)
7605  init_shd_bnd_id++;
7606  init_shd_bnd_id--;
7607  // Add and substract to avoid compilation warning
7608  unsigned final_shd_bnd_id = read_unsigned_line_helper(restart_file);
7609  // We need to read the data because it comes in the file (add and
7610  // substract to avoid compilation warning)
7611  final_shd_bnd_id++;
7612  final_shd_bnd_id--;
7613 
7614  // Read the number of processors involved in the generation of
7615  // mesh before restart
7616  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7617 
7618 #ifdef PARANOID
7619  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7620  {
7621  std::ostringstream error_message;
7622  error_message
7623  << "The number of previously used processors ("<< n_procs
7624  << ") (read from the restart file) is different\nfrom the "
7625  << "number of current used processors ("
7626  << this->communicator_pt()->nproc() << ")\n\n";
7627  throw OomphLibError(error_message.str(),
7628  "TriangleMesh::read_distributed_info_for_restart()",
7629  OOMPH_EXCEPTION_LOCATION);
7630  }
7631 #endif
7632 
7633  // Clear all previuos info. related with shared boundaries
7634  this->shared_boundaries_ids().clear();
7635  this->shared_boundary_from_processors().clear();
7636  this->shared_boundary_overlaps_internal_boundary().clear();
7637 
7638  // Create the storage for the shared boundaries ids related with
7639  // the processors
7640  this->shared_boundaries_ids().resize(n_procs);
7641 
7642  // Now read the processors ids and the shared boundary created
7643  // by them
7644  for (unsigned ip = 0; ip < n_procs; ip++)
7645  {
7646  // Create the storage for the shared boundaries ids related with
7647  // the processors
7648  this->shared_boundaries_ids(ip).resize(n_procs);
7649  for (unsigned jp = 0; jp < n_procs; jp++)
7650  {
7651  if (ip != jp)
7652  {
7653  // Read the number of shared boundaries with in these two
7654  // processors
7655  const unsigned nshared_boundaries_iproc_jproc =
7656  read_unsigned_line_helper(restart_file);
7657  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7658  {
7659  // Get the processors
7660  unsigned tmp_ip;
7661  restart_file >> tmp_ip;
7662  unsigned tmp_jp;
7663  restart_file >> tmp_jp;
7664 
7665  // Get the shared boundary id created by these two
7666  // processors
7667  const unsigned shared_boundary_id =
7668  read_unsigned_line_helper(restart_file);
7669 
7670  // Update the info. of the processors that give rise to
7671  // the shared boundaries
7672  this->shared_boundaries_ids(ip, jp).
7673  push_back(shared_boundary_id);
7674 
7675  // Update the structure that states the processors that
7676  // gave rise to the shared boundary
7677  Vector<unsigned> processors(2);
7678  processors[0] = ip;
7679  processors[1] = jp;
7680  this->shared_boundary_from_processors()[shared_boundary_id] =
7681  processors;
7682 
7683  } // for (is < nshared_boundaries_iproc_jproc)
7684  }
7685  } // for (jp < n_procs)
7686  } // for (ip < n_procs)
7687 
7688  // Now read the info. that states which shared boundary overlaps
7689  // an internal boundary
7690 
7691  // First check if there are shared boundaries overlapping internal
7692  // boundaries
7693  const unsigned nshared_boundaries_overlap_internal_boundaries =
7694  read_unsigned_line_helper(restart_file);
7695 
7696  for (unsigned isb = 0;
7697  isb < nshared_boundaries_overlap_internal_boundaries;
7698  isb++)
7699  {
7700  // Read the shared boundary that overlaps an internal boundary
7701  unsigned shared_boundary_overlapping;
7702  restart_file >> shared_boundary_overlapping;
7703  // ... and read the internal boundary that overlaps
7704  const unsigned overlapped_internal_boundary =
7705  read_unsigned_line_helper(restart_file);
7706 
7707  // Re-establish the info. of the shared boundaries overlapped
7708  // by internal boundaries
7709  this->shared_boundary_overlaps_internal_boundary()
7710  [shared_boundary_overlapping] = overlapped_internal_boundary;
7711  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7712 
7713  // Now read the info. related with the initial and final
7714  // boundary coordinates for each original boundary
7715 
7716  // Go through all the (original) boundaries to update the initial
7717  // and final boundary coordinates
7718  for (unsigned b = 0; b < n_boundary; b++)
7719  {
7720  // For each boundary check if the boundary coordinates initial
7721  // and final zeta vales were assigned in the restart file
7722  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7723  read_unsigned_line_helper(restart_file);
7724 
7725  if (boundary_coordinates_initial_zeta_values_assigned)
7726  {
7727  // Clear any previous stored info. There should not be
7728  // info. already stored but better clear the info. for the
7729  // boundary
7730  Boundary_initial_coordinate[b].clear();
7731  Boundary_final_coordinate[b].clear();
7732 
7733  Boundary_initial_zeta_coordinate[b].clear();
7734  Boundary_final_zeta_coordinate[b].clear();
7735 
7736  // The info. for the segments
7737  Boundary_segment_inverted[b].clear();
7738  Boundary_segment_initial_coordinate[b].clear();
7739  Boundary_segment_final_coordinate[b].clear();
7740 
7741  Boundary_segment_initial_zeta[b].clear();
7742  Boundary_segment_final_zeta[b].clear();
7743 
7744  Boundary_segment_initial_arclength[b].clear();
7745  Boundary_segment_final_arclength[b].clear();
7746 
7747  // Read the initial and final boundary coordinates, same as
7748  // the initial and final zeta values for each boundary
7749 
7750  // First the vertices coordinates
7751  Vector<double> initial_coordinates(2);
7752 
7753  // Read the initial coordinates
7754  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7755 
7756  // Ignore rest of line
7757  restart_file.ignore(80,'\n');
7758 
7759  Vector<double> final_coordinates(2);
7760 
7761  // Read the final coordinates
7762  restart_file >> final_coordinates[0] >> final_coordinates[1];
7763 
7764  // Ignore rest of line
7765  restart_file.ignore(80,'\n');
7766 
7767  // Set the values in the containers
7768 
7769 
7770  this->boundary_initial_coordinate(b)=initial_coordinates;
7771  this->boundary_final_coordinate(b)=final_coordinates;
7772 
7773  // ... now read the zeta values
7774  Vector<double> zeta_initial(1);
7775  restart_file >> zeta_initial[0];
7776 
7777  // Ignore rest of line
7778  restart_file.ignore(80,'\n');
7779 
7780  Vector<double> zeta_final(1);
7781  restart_file >> zeta_final[0];
7782 
7783  // Ignore rest of line
7784  restart_file.ignore(80,'\n');
7785 
7786  // Set the values in the containers
7787  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7788  this->boundary_final_zeta_coordinate(b) = zeta_final;
7789 
7790  // Get the curent boundary id from the restart file
7791  unsigned current_boundary;
7792  restart_file >> current_boundary;
7793 
7794 #ifdef PARANOID
7795  if (current_boundary != b)
7796  {
7797  std::ostringstream error_message;
7798  error_message
7799  << "The current boundary id from the restart file ("
7800  << current_boundary << ") is different from\nthe boundary id "
7801  << b << "currently used to re-establish the initial and\nfinal "
7802  << "segment's zeta values\n\n";
7803  throw OomphLibError(error_message.str(),
7804  "TriangleMesh::read_distributed_info_for_restart()",
7805  OOMPH_EXCEPTION_LOCATION);
7806  }
7807 #endif
7808 
7809  // ... and its number of segments
7810  unsigned nsegments;
7811  restart_file >> nsegments;
7812 
7813  // Ignore rest of line
7814  restart_file.ignore(80,'\n');
7815 
7816  // Now read all the segments info.
7817 
7818  // ... and then save that info for each segments
7819  for (unsigned is = 0; is < nsegments; is++)
7820  {
7821  // First the vertices coordinates
7822  Vector<double> initial_segment_coordinates(2);
7823 
7824  // Read the initial coordinates
7825  restart_file >> initial_segment_coordinates[0]
7826  >> initial_segment_coordinates[1];
7827 
7828  // Ignore rest of line
7829  restart_file.ignore(80,'\n');
7830 
7831  Vector<double> final_segment_coordinates(2);
7832 
7833  // Read the final coordinates
7834  restart_file >> final_segment_coordinates[0]
7835  >> final_segment_coordinates[1];
7836 
7837  // Ignore rest of line
7838  restart_file.ignore(80,'\n');
7839 
7840  // Set the values in the containers
7841  this->boundary_segment_initial_coordinate(b).push_back(
7842  initial_segment_coordinates);
7843  this->boundary_segment_final_coordinate(b).push_back(
7844  final_segment_coordinates);
7845 
7846  // ... then the zeta values for the segment
7847  if (this->boundary_geom_object_pt(b)!=0)
7848  {
7849  Vector<double> zeta_segment_initial(1);
7850  restart_file >> zeta_segment_initial[0];
7851 
7852  // Ignore rest of line
7853  restart_file.ignore(80,'\n');
7854 
7855  Vector<double> zeta_segment_final(1);
7856  restart_file >> zeta_segment_final[0];
7857 
7858  // Ignore rest of line
7859  restart_file.ignore(80,'\n');
7860 
7861  // Set the values in the containers for the segment
7862  this->boundary_segment_initial_zeta(b).push_back(
7863  zeta_segment_initial[0]);
7864  this->boundary_segment_final_zeta(b).push_back(
7865  zeta_segment_final[0]);
7866  }
7867  else
7868  {
7869  Vector<double> arclength_segment_initial(1);
7870  restart_file >> arclength_segment_initial[0];
7871 
7872  // Ignore rest of line
7873  restart_file.ignore(80,'\n');
7874 
7875  Vector<double> arclength_segment_final(1);
7876  restart_file >> arclength_segment_final[0];
7877 
7878  // Ignore rest of line
7879  restart_file.ignore(80,'\n');
7880 
7881  // Set the values in the containers for the segment
7882  this->boundary_segment_initial_arclength(b).push_back(
7883  arclength_segment_initial[0]);
7884  this->boundary_segment_final_arclength(b).push_back(
7885  arclength_segment_final[0]);
7886  } // else if (this->boundary_geom_object_pt(b)!=0)
7887 
7888  } // for (is < nsegments)
7889 
7890  } // if (boundary_coordinates_initial_zeta_values_assigned)
7891 
7892  } // for (b < n_boundary)
7893 
7894  } // if (this->is_mesh_distributed())
7895 
7896  }
7897 
7898 #endif // #ifdef OOMPH_HAS_MPI
7899 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
7900 
7901  //===================================================================
7902  // Output the nodes on the boundaries and their / respective boundary
7903  // coordinates(into separate tecplot / zones)
7904  //===================================================================
7905  template<class ELEMENT>
7907  std::ostream &outfile)
7908  {
7909  // First get all the elements adjacent to the given boundary, then
7910  // the face elements and extract the nodes on the boundaries using
7911  // the face elements. We can not use the data structure
7912  // Boundary_node_pt since the multi_domain functions add nodes there
7913  // without assigning the required boundary coordinate
7914 
7915  // Store the nodes in a set so we do not have repeated nodes
7916  std::set<Node*> boundary_nodes_pt;
7917  const unsigned n_boundary_ele = this->nboundary_element(b);
7918  for (unsigned e = 0; e < n_boundary_ele; e++)
7919  {
7920  // Get the boundary bulk element
7921  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
7922 #ifdef OOMPH_HAS_MPI
7923  // Only work with nonhalo elements if the mesh is distributed
7924  if (!bulk_ele_pt->is_halo())
7925  {
7926 #endif
7927  // Get the face index
7928  int face_index = this->face_index_at_boundary(b, e);
7929  // Create the face element
7930  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
7931  bulk_ele_pt, face_index);
7932 
7933  // Get the number of nodes on the face element
7934  const unsigned n_nodes = face_ele_pt->nnode();
7935  for (unsigned i = 0; i < n_nodes; i++)
7936  {
7937  // Get the nodes in the face elements
7938  Node* tmp_node_pt = face_ele_pt->node_pt(i);
7939  // Add the nodes to the set of boundary nodes
7940  boundary_nodes_pt.insert(tmp_node_pt);
7941  } // for (i < n_nodes)
7942 
7943  // Free the memory allocated for the face element
7944  delete face_ele_pt;
7945  face_ele_pt = 0;
7946 #ifdef OOMPH_HAS_MPI
7947  } // if (!bulk_ele_pt->is_halo())
7948 #endif
7949 
7950  } // for (e < n_boundary_ele)
7951 
7952  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
7953  // Set to store the boundary nodes in order
7954  std::set<Vector<double> > set_node_coord;
7955  // Loop over the nodes on the boundary and store them in the set
7956  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
7957  it != boundary_nodes_pt.end(); it++)
7958  {
7959  Node *inode_pt = (*it);
7960 
7961  // Get the node coordinates
7962  const unsigned n_dim = inode_pt->ndim();
7963  Vector<double> node_coord(n_dim+1);
7964 
7965  // Get the boundary coordinate
7966  Vector<double> zeta(1);
7967  inode_pt->get_coordinates_on_boundary(b, zeta);
7968  node_coord[0] = zeta[0];
7969  for (unsigned j = 0; j < n_dim; j++)
7970  {
7971  node_coord[j+1] = inode_pt->x(j);
7972  }
7973  set_node_coord.insert(node_coord);
7974  }
7975 
7976  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7977  it != set_node_coord.end(); it++)
7978  {
7979  // Get the node coordinates
7980  Vector<double> node_coord = (*it);
7981 
7982  // Output the node coordinates
7983  const unsigned n_dim = node_coord.size()-1;
7984  for (unsigned j = 0; j < n_dim; j++)
7985  {
7986  outfile << node_coord[j+1] << " ";
7987  }
7988  // ... add an extra coordinate to avoid error with tecplot
7989  outfile << "0.0" << std::endl;
7990  }
7991 
7992  // ... loop again to plot the bound coordinates
7993  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
7994  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7995  it != set_node_coord.end(); it++)
7996  {
7997  // Get the node coordinates
7998  Vector<double> node_coord = (*it);
7999 
8000  // Output the node coordinates
8001  const unsigned n_dim = node_coord.size()-1;
8002  for (unsigned j = 0; j < n_dim; j++)
8003  {
8004  outfile << node_coord[j+1] << " ";
8005  }
8006 
8007  // Output the boundary coordinate
8008  outfile << node_coord[0] << std::endl;
8009  }
8010 
8011  }
8012 
8013 #ifdef OOMPH_HAS_MPI
8014  //====================================================================
8015  // \short Creates the distributed domain representation. Joins the
8016  // original boundaires, shared boundaries and creates connections among
8017  // them to create the new polygons that represent the distributed
8018  // domain
8019  //====================================================================
8020  template<class ELEMENT>
8022  Vector<TriangleMeshPolygon *> &polygons_pt,
8023  Vector<TriangleMeshOpenCurve*> &open_curves_pt)
8024  {
8025  // Get the outer polygons, internal polygons, internal open curves
8026  // and join them with the shared polylines to create the distributed
8027  // domain representation (the new outer, internal polygons, and new
8028  // internal open curves)
8029 
8030  // Get the rank of the current processor
8031  const unsigned my_rank = this->communicator_pt()->my_rank();
8032 
8033  // *********************************************************************
8034  // Step (2) Get the outer, internal and shared boundaries to create the
8035  // new polygons
8036  // *********************************************************************
8037 
8038  // *********************************************************************
8039  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8040  // a new representation (for example when the boundary was splitted in
8041  // the distribution process)
8042  // *********************************************************************
8043 
8044  // Storage for new created polylines, non sorted
8045  Vector<TriangleMeshPolyLine *> unsorted_outer_polyline_pt;
8046 
8047  // Storing for the polylines on the boundaries
8048  // The first index is for a set of connected polylines
8049  // The second index is for a polyline on a set of connected polylines
8050  Vector<Vector<TriangleMeshPolyLine *> > sorted_outer_curves_pt;
8051 
8052  // Copy the outer boundaries to the vector of polylines
8053  const unsigned nouter=this->Outer_boundary_pt.size();
8054  for (unsigned i = 0; i < nouter; i++)
8055  {
8056  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8057  for (unsigned p = 0; p < npolylines; p++)
8058  {
8059  // Pointer to the current polyline
8060  TriangleMeshPolyLine *tmp_polyline_pt =
8061  this->Outer_boundary_pt[i]->polyline_pt(p);
8062  const unsigned nvertex = tmp_polyline_pt->nvertex();
8063  if (nvertex > 0)
8064  {
8065  // Get the boundary id of the polyline and check if that boundary
8066  // needs a new representation (for example when the boundary was
8067  // splitted in the distribution process)
8068  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8069  if (!boundary_was_splitted(bound_id))
8070  {
8071  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8072  } // if (!boundary_was_splitted(bound_id))
8073  else
8074  {
8075  // Get the polylines that will represent this boundary
8076  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8077  boundary_subpolylines(bound_id);
8078  const unsigned nsub_poly = tmp_vector_polylines.size();
8079 #ifdef PARANOID
8080  if (nsub_poly <= 1)
8081  {
8082  std::ostringstream error_message;
8083  error_message
8084  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8085  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8086  throw OomphLibError(error_message.str(),
8087  OOMPH_CURRENT_FUNCTION,
8088  OOMPH_EXCEPTION_LOCATION);
8089  }
8090 #endif
8091  // Add the new representation of the polylines (sub-polylines)
8092  // to represent this boundary
8093  for (unsigned isub = 0; isub < nsub_poly; isub++)
8094  {
8095  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8096 #ifdef PARANOID
8097  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8098  if (nsvertex == 0)
8099  {
8100  std::ostringstream error_message;
8101  error_message
8102  << "The current chunk ("<< isub <<") of the polyline with\n"
8103  << "boundary id (" << bound_id << ") has no vertices\n";
8104  throw OomphLibError(error_message.str(),
8105  OOMPH_CURRENT_FUNCTION,
8106  OOMPH_EXCEPTION_LOCATION);
8107  } // if (nsvertex == 0)
8108 #endif // #ifdef PARANOID
8109  } // for (isub < nsub_poly)
8110  } // else if (!boundary_was_splitted(bound_id))
8111  } // if (nvertex > 0)
8112  } // for (p < npolylines)
8113  } // for (i < nouter)
8114 
8115  // Get the number of unsorted polylines
8116  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8117  if (nunsorted_outer_polyline > 0)
8118  {
8119 
8120  // Now that we have all the new unsorted polylines it is time to sort them
8121  // so they be all contiguous
8122  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8123 
8124  } // if (nunsorted_outer_polyline > 0)
8125 
8126  // *********************************************************************
8127  // Step (2.2) Get the internal closed boundaries and check if it is
8128  // necessary to use a new representation (for example when the boundary
8129  // was splitted in the distribution process)
8130  // *********************************************************************
8131 
8132  // Storage for new created polylines, non sorted
8133  Vector<TriangleMeshPolyLine *> unsorted_internal_closed_polyline_pt;
8134 
8135  // Storing for the polylines on the boundaries
8136  // The first index is for a set of connected polylines
8137  // The second index is for a polyline on a set of connected polylines
8138  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_closed_curves_pt;
8139 
8140  // Copy the internal closed boundaries to the vector of polylines
8141  const unsigned ninternal_closed=this->Internal_polygon_pt.size();
8142  for (unsigned i = 0; i < ninternal_closed; i++)
8143  {
8144  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8145  for (unsigned p = 0; p < npolylines; p++)
8146  {
8147  // Pointer to the current polyline
8148  TriangleMeshPolyLine *tmp_polyline_pt =
8149  this->Internal_polygon_pt[i]->polyline_pt(p);
8150  const unsigned nvertex = tmp_polyline_pt->nvertex();
8151  if (nvertex > 0)
8152  {
8153  // Get the boundary id of the polyline and check if that boundary
8154  // needs a new representation (for example when the boundary was
8155  // splitted in the distribution process)
8156  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8157  if (!boundary_was_splitted(bound_id))
8158  {
8159  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8160  } // if (!boundary_was_splitted(bound_id))
8161  else
8162  {
8163  // Get the polylines that will represent this boundary
8164  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8165  boundary_subpolylines(bound_id);
8166  const unsigned nsub_poly = tmp_vector_polylines.size();
8167 #ifdef PARANOID
8168  if (nsub_poly <= 1)
8169  {
8170  std::ostringstream error_message;
8171  error_message
8172  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8173  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8174  throw OomphLibError(error_message.str(),
8175  OOMPH_CURRENT_FUNCTION,
8176  OOMPH_EXCEPTION_LOCATION);
8177  }
8178 #endif
8179  // Add the new representation of the polylines (sub-polylines)
8180  // to represent this boundary
8181  for (unsigned isub = 0; isub < nsub_poly; isub++)
8182  {
8183  unsorted_internal_closed_polyline_pt.push_back(tmp_vector_polylines[isub]);
8184 #ifdef PARANOID
8185  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8186  if (nsvertex == 0)
8187  {
8188  std::ostringstream error_message;
8189  error_message
8190  << "The current chunk ("<< isub <<") of the polyline with\n"
8191  << "boundary id (" << bound_id << ") has no vertices\n";
8192  throw OomphLibError(error_message.str(),
8193  OOMPH_CURRENT_FUNCTION,
8194  OOMPH_EXCEPTION_LOCATION);
8195  } // if (nsvertex == 0)
8196 #endif // #ifdef PARANOID
8197  } // for (isub < nsub_poly)
8198  } // else if (!boundary_was_splitted(bound_id))
8199  } // if (nvertex > 0)
8200  } // for (p < npolylines)
8201  } // for (i < ninternal_closed)
8202 
8203  const unsigned nunsorted_internal_closed_polyline =
8204  unsorted_internal_closed_polyline_pt.size();
8205 
8206  if (nunsorted_internal_closed_polyline > 0)
8207  {
8208  // Now that we have all the new unsorted polylines it is time to sort them
8209  // so they be all contiguous
8210  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8211  sorted_internal_closed_curves_pt);
8212  }
8213 
8214  // *********************************************************************
8215  // Step (2.3) Get the internal open boundaries and check if it is
8216  // necessary to use a new representation (for example when the boundary
8217  // was splitted in the distribution process)
8218  // *********************************************************************
8219 
8220  // Storage for new created polylines, non sorted
8221  Vector<TriangleMeshPolyLine *> unsorted_internal_open_polyline_pt;
8222 
8223  // Storing for the polylines on the boundaries
8224  // The first index is for a set of connected polylines
8225  // The second index is for a polyline on a set of connected polylines
8226  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_open_curves_pt;
8227 
8228  // Copy the internal open boundaries to the vector of polylines
8229  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8230  for (unsigned i = 0; i < ninternal_open; i++)
8231  {
8232  const unsigned ncurve_section =
8233  this->Internal_open_curve_pt[i]->ncurve_section();
8234  for (unsigned p = 0; p < ncurve_section; p++)
8235  {
8236  // Pointer to the current polyline
8237  TriangleMeshPolyLine *tmp_polyline_pt =
8238  this->Internal_open_curve_pt[i]->polyline_pt(p);
8239  const unsigned nvertex = tmp_polyline_pt->nvertex();
8240  if (nvertex > 0)
8241  {
8242  // Get the boundary id of the polyline and check if that boundary
8243  // needs a new representation (for example when the boundary was
8244  // splitted in the distribution process)
8245  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8246  if (!boundary_was_splitted(bound_id))
8247  {
8248  // Only include as internal boundaries those not marked as
8249  // shared boundaries
8250  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8251  {
8252  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8253  }
8254  } // if (!boundary_was_splitted(bound_id))
8255  else
8256  {
8257  // Get the polylines that will represent this boundary
8258  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8259  boundary_subpolylines(bound_id);
8260  const unsigned nsub_poly = tmp_vector_polylines.size();
8261 #ifdef PARANOID
8262  if (nsub_poly <= 1)
8263  {
8264  std::ostringstream error_message;
8265  error_message
8266  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8267  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8268  throw OomphLibError(error_message.str(),
8269  OOMPH_CURRENT_FUNCTION,
8270  OOMPH_EXCEPTION_LOCATION);
8271  }
8272 #endif
8273  // Add the new representation of the polylines (sub-polylines)
8274  // to represent this boundary
8275  for (unsigned isub = 0; isub < nsub_poly; isub++)
8276  {
8277  // Only include as internal boundaries those not marked as
8278  // shared boundaries
8279  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8280  {
8281  unsorted_internal_open_polyline_pt.push_back(tmp_vector_polylines[isub]);
8282  }
8283 #ifdef PARANOID
8284  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8285  if (nsvertex == 0)
8286  {
8287  std::ostringstream error_message;
8288  error_message
8289  << "The current chunk ("<< isub <<") of the polyline with\n"
8290  << "boundary id (" << bound_id << ") has no vertices\n";
8291  throw OomphLibError(error_message.str(),
8292  OOMPH_CURRENT_FUNCTION,
8293  OOMPH_EXCEPTION_LOCATION);
8294  } // if (nsvertex == 0)
8295 #endif // #ifdef PARANOID
8296  } // for (isub < nsub_poly)
8297  } // else if (!boundary_was_splitted(bound_id))
8298  } // if (nvertex > 0)
8299  } // for (p < npolylines)
8300  } // for (i < ninternal_open)
8301 
8302  const unsigned nunsorted_internal_open_polyline =
8303  unsorted_internal_open_polyline_pt.size();
8304 
8305  if (nunsorted_internal_open_polyline > 0)
8306  {
8307  // Now that we have all the new unsorted polylines it is time to sort them
8308  // so they be all contiguous
8309  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8310  sorted_internal_open_curves_pt);
8311  }
8312 
8313  // ********************************************************************
8314  // Step (2.4) Sort the polylines on the shared boundaries
8315  // ********************************************************************
8316 
8317  // Storage for new created polylines, non sorted
8318  Vector<TriangleMeshPolyLine *> unsorted_shared_polyline_pt;
8319 
8320  // Special storage for the shared polylines that will be also used
8321  // to connect with the internal boundaries
8322  Vector<TriangleMeshPolyLine *> unsorted_shared_to_internal_polyline_pt;
8323 
8324  // Storing for the polylines on the shared boundaries
8325  // The first index is for a set of connected polylines
8326  // The second index is for a polyline on a set of connected polylines
8327  Vector<Vector<TriangleMeshPolyLine *> > sorted_shared_curves_pt;
8328 
8329  // Copy the shared boudaries to the vector of polylines
8330  const unsigned ncurves = nshared_boundary_curves(my_rank);
8331  for (unsigned i = 0; i < ncurves; i++)
8332  {
8333  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8334  for (unsigned p = 0; p < npolylines; p++)
8335  {
8336  const unsigned nvertex =
8337  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8338  if (nvertex > 0)
8339  {
8340  TriangleMeshPolyLine *tmp_shared_poly_pt =
8341  shared_boundary_polyline_pt(my_rank, i, p);
8342 
8343  // First check if there are shared boundaries overlapping
8344  // internal boundaries
8345  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8346  {
8347  // Get the boundary id of the shared polyline
8348  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8349  // If the shared polyline is marked as internal boundary
8350  // then include it in the special storage to look for
8351  // connection with internal boundaries
8352  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8353  {
8354  unsorted_shared_to_internal_polyline_pt.push_back(
8355  tmp_shared_poly_pt);
8356  }
8357  }
8358  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8359  }
8360  }
8361  }
8362 
8363  // Get the total number of shared polylines
8364  const unsigned nunsorted_shared_polyline =
8365  unsorted_shared_polyline_pt.size();
8366 
8367  if (nunsorted_shared_polyline > 0)
8368  {
8369  // Now that we have all the new unsorted polylines it is time to
8370  // sort them so they be all contiguous
8371  sort_polylines_helper(unsorted_shared_polyline_pt, sorted_shared_curves_pt);
8372  }
8373 
8374  // ********************************************************************
8375  // Step (3) Join the boundaries (shared, internal and outer to
8376  // create the new polygons)
8377  // ********************************************************************
8378 
8379  // Create the set of curves that will be used to create the new polygons
8380  // Get the total number of curves
8381  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8382  const unsigned ninternal_closed_curves =
8383  sorted_internal_closed_curves_pt.size();
8384  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8385  const unsigned ntotal_curves = nouter_curves +
8386  ninternal_closed_curves +
8387  nshared_curves;
8388 
8389  // Add all the polylines to a container
8390  unsigned counter = 0;
8391  Vector<Vector<TriangleMeshPolyLine *> > all_curves_pt(ntotal_curves);
8392 
8393  // Add the shared curves first, this ensure the generation of
8394  // internal polygons defined by the shared boundaries
8395  for (unsigned i = 0; i < nshared_curves; i++,counter++)
8396  {
8397  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8398  }
8399 
8400  // Add the internal polygons (if any)
8401  for (unsigned i = 0; i < ninternal_closed_curves; i++,counter++)
8402  {
8403  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8404  }
8405 
8406  // Add the outer polygons
8407  for (unsigned i = 0; i < nouter_curves; i++,counter++)
8408  {
8409  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8410  }
8411 
8412  // Create the temporary version of the domain by joining the new
8413  // polylines
8414  this->create_tmp_polygons_helper(all_curves_pt,polygons_pt);
8415  // Create the new open curves
8416  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8417  unsorted_shared_to_internal_polyline_pt,
8418  open_curves_pt);
8419 
8420  // ********************************************************************
8421  // Step (4) Create connections among the outer boundaries
8422  // (intersections with themselves)
8423  // ********************************************************************
8424 
8425  // After creating the new boundaries representation (polylines)
8426  // establish the connections of the shared boundaries (with
8427  // themselves or with the original boundaries). This avoids the
8428  // multiple definition of vertices in the domain which cause
8429  // problems when calling Triangle
8430 
8431  this->create_shared_polylines_connections();
8432 
8433  // ------------------------------------------------------------------
8434  // Compute the new holes information. Those from the
8435  // extra_holes_coordinates container, and those from the original
8436  // closed boundaries. Add the holes created by the halo elements
8437  // adjacent to the shared boundaries
8438 
8439  // The storage for the new holes, get those from the
8440  // extra_holes_coordinates container and those from the internal
8441  // closed boundaries that are defined as holes
8442  Vector<Vector<double> > new_holes_coordinates;
8443 
8444  // Copy the holes (those defined by the original internal closed
8445  // boundaries and those in the extra holes container)
8446 
8447  // The holes defined by the original internal closed boundaries
8448  const unsigned n_holes = this->Internal_polygon_pt.size();
8449  for (unsigned h = 0; h < n_holes; h++)
8450  {
8451  Vector<double> hole_coordinates =
8452  this->Internal_polygon_pt[h]->internal_point();
8453  // If the closed boundary is a hole, then copy its hole
8454  if (!hole_coordinates.empty())
8455  {
8456  new_holes_coordinates.push_back(hole_coordinates);
8457  }
8458  } // for (h < n_holes)
8459 
8460  // Is this the first time we are going to copy the extra holes
8461  // coordinates
8462  if (First_time_compute_holes_left_by_halo_elements)
8463  {
8464  // The holes in the extra holes container
8465  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8466  for (unsigned h = 0; h < n_extra_holes; h++)
8467  {
8468  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8469  new_holes_coordinates.push_back(hole_coordinates);
8470  } // for (h < n_extra_holes)
8471 
8472  // Copy the extra holes coordinates
8473  Original_extra_holes_coordinates = Extra_holes_coordinates;
8474 
8475  // Set the flag to false
8476  First_time_compute_holes_left_by_halo_elements = false;
8477 
8478  } // if (First_time_compute_holes_left_by_halo_elements)
8479  else
8480  {
8481  // Not the first time, then only copy the original extra holes
8482  // coordinates
8483  const unsigned n_original_extra_holes =
8484  Original_extra_holes_coordinates.size();
8485  for (unsigned h = 0; h < n_original_extra_holes; h++)
8486  {
8487  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8488  new_holes_coordinates.push_back(hole_coordinates);
8489  } // for (h < n_original_extra_holes)
8490  }
8491 
8492  // Add the holes created by the halo elements adjacent to the shared
8493  // boundaries
8494  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8495 
8496  // Update the holes information, only use the coordinate inside the
8497  // poylgons that define the new domain
8498  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8499 
8500  // tachidok Clear the storage by now
8501  //new_holes_coordinates.clear();
8502 
8503  // Now copy the info. in the extra holes coordinates container
8504  Extra_holes_coordinates = new_holes_coordinates;
8505 
8506  // Do not delete halo(ed) info., this will be "deleted"
8507  // automatically by not passing that information to the new adapted
8508  // mesh. Once the transfer of target areas is performed the halo(ed)
8509  // information is no longer required
8510 
8511  }
8512 
8513  //======================================================================
8514  // \short Take the polylines from the shared boundaries and the boundaries
8515  // to create polygons
8516  //======================================================================
8517  template<class ELEMENT>
8520  &polylines_pt,
8521  Vector<TriangleMeshPolygon *> &polygons_pt)
8522  {
8523  // Each vector of polylines (curve) is already sorted, it means that
8524  // all the polylines on the vector polylines_pt[i] point to the same
8525  // direction
8526 
8527  // --- Using this fact we should compare the first and last points from
8528  // these arrays of polylines (curves) and compare with the others
8529  // vectors of polylines (curves) end points
8530  // --- Once created a closed curve create a polygon
8531 
8532  // The number of curves
8533  const unsigned ncurves = polylines_pt.size();
8534 
8535  // The number of non sorted curves
8536  const unsigned nunsorted_curves = ncurves;
8537  // The number of sorted curves
8538  unsigned nsorted_curves = 0;
8539 
8540  // Vector to know which ncurve is already done
8541  std::vector<bool> done_curve(ncurves);
8542 
8543  do
8544  {
8545  // The list where to add the curves so that they be contiguous
8546  std::list<Vector<TriangleMeshPolyLine*> > list_building_polygon_pt;
8547 #ifdef PARANOID
8548  // Flag to indicate that a root curve was found
8549  bool root_curve_found = false;
8550 #endif
8551 
8552  // The index for the root_curve (we use it in further iterations as the
8553  // starting index so we dont need to search in already done curves)
8554  unsigned root_curve_idx = 0;
8555 
8556  // Get the root curve
8557  for (unsigned ic = 0; ic < ncurves; ic++)
8558  {
8559  if (!done_curve[ic])
8560  {
8561  root_curve_idx = ic;
8562  nsorted_curves++;
8563 #ifdef PARANOID
8564  root_curve_found = true;
8565 #endif
8566  done_curve[ic] = true;
8567  // ... break the loop
8568  break;
8569  }
8570  }
8571 
8572 #ifdef PARANOID
8573  if (!root_curve_found)
8574  {
8575  std::stringstream err;
8576  err <<"The root curve to create a polygon from the shared and "
8577  <<"original boundaries was not found!!!\n";
8578  throw OomphLibError(err.str(),
8579  "TriangleMesh::create_tmp_polygons_helper()",
8580  OOMPH_EXCEPTION_LOCATION);
8581  }
8582 #endif
8583 
8584  // Get the root curve
8585  Vector<TriangleMeshPolyLine*> root_curve_pt=polylines_pt[root_curve_idx];
8586 
8587  // Add the root curve to the list
8588  list_building_polygon_pt.push_back(root_curve_pt);
8589 
8590  // Get the initial and final vertices from the root curve
8591  Vector<double> root_curve_initial_vertex(2);
8592  Vector<double> root_curve_final_vertex(2);
8593 
8594  // We need to get the number of polylines that compose the root curve
8595  const unsigned nroot_curve_polyline = root_curve_pt.size();
8596  // ... and now get the initial and final vertex
8597  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8598  root_curve_pt[nroot_curve_polyline-1]->
8599  final_vertex_coordinate(root_curve_final_vertex);
8600 
8601  // First check if it already create a polygon
8602  double diff =
8603  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8604  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8605  +
8606  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8607  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8608  diff = sqrt(diff);
8610  {
8611  // The polyline already create a Polygon, then create it!!!
8612  // Create the curve section representation of the current root curve
8614  curve_section_pt(nroot_curve_polyline);
8615 
8616  // Copy the polylines into its curve section representation
8617  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8618  {curve_section_pt[i] = root_curve_pt[i];}
8619 
8620  // ... and create the Polygon
8621  TriangleMeshPolygon *new_polygon_pt =
8622  new TriangleMeshPolygon(curve_section_pt);
8623 
8624  // Mark the polygon for deletion (in the destructor)
8625  this->Free_polygon_pt.insert(new_polygon_pt);
8626 
8627  // Add the polygon to the output polygons
8628  polygons_pt.push_back(new_polygon_pt);
8629  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8630  // when the curve creates a Polygon by itself
8631  else
8632  {
8633  // Flag to continue iterating while curves be added to the left
8634  // or right of the list of curves
8635  bool added_curve = false;
8636 #ifdef PARANOID
8637  // Flag to know if the "loop" finish because a polygon was
8638  // created or because no more curves can be added to the left or
8639  // right
8640  bool polygon_created = false;
8641 #endif
8642  do
8643  {
8644  added_curve = false;
8645  // If the root curve does not create a closed polygon then add curves
8646  // to the left or right until the curves create a closed polygon
8647  for (unsigned ic = root_curve_idx+1; ic < ncurves; ic++)
8648  {
8649  if (!done_curve[ic])
8650  {
8651  // Get the current curve
8652  Vector<TriangleMeshPolyLine*> current_curve_pt =
8653  polylines_pt[ic];
8654 
8655  // We need to get the number of polylines that compose the
8656  // current curve
8657  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8658 
8659  // ... and get the initial and final coordinates for the current
8660  // curve
8661  Vector<double> current_curve_initial_vertex(2);
8662  Vector<double> current_curve_final_vertex(2);
8663 
8664  current_curve_pt[0]->
8665  initial_vertex_coordinate(current_curve_initial_vertex);
8666  current_curve_pt[ncurrent_curve_polyline-1]->
8667  final_vertex_coordinate(current_curve_final_vertex);
8668 
8669  // ---------------------------------------------------------------
8670  // Start adding curves to the left or right
8671  // ---------------------------------------------------------------
8672  diff =
8673  ((current_curve_final_vertex[0] - root_curve_initial_vertex[0])*
8674  (current_curve_final_vertex[0] - root_curve_initial_vertex[0]))
8675  +
8676  ((current_curve_final_vertex[1] - root_curve_initial_vertex[1])*
8677  (current_curve_final_vertex[1] - root_curve_initial_vertex[1]));
8678  diff = sqrt(diff);
8679  // CURRENT curve to the LEFT of the ROOT curve
8681  {
8682  // Add the current curve to the left
8683  list_building_polygon_pt.push_front(current_curve_pt);
8684  // Mark the curve as done
8685  done_curve[ic] = true;
8686  // Update the initial vertex values
8687  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8688  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8689  // Increase the number of sorted curves
8690  nsorted_curves++;
8691  // Set the flag to indicate that a curve was added to the list
8692  added_curve = true;
8693  break;
8694  }
8695 
8696  diff =
8697  ((current_curve_initial_vertex[0] - root_curve_initial_vertex[0])*
8698  (current_curve_initial_vertex[0] - root_curve_initial_vertex[0]))
8699  +
8700  ((current_curve_initial_vertex[1] - root_curve_initial_vertex[1])*
8701  (current_curve_initial_vertex[1] - root_curve_initial_vertex[1]));
8702  diff = sqrt(diff);
8703  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8705  {
8707  tmp_curve_pt(ncurrent_curve_polyline);
8708  // Reverse each polyline and back them up
8709  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8710  {
8711  current_curve_pt[it]->reverse();
8712  tmp_curve_pt[it] = current_curve_pt[it];
8713  }
8714  // Now copy them back but in reverse order
8715  unsigned count = 0;
8716  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8717  {current_curve_pt[count] = tmp_curve_pt[i];}
8718  // Add the current curve to the left
8719  list_building_polygon_pt.push_front(current_curve_pt);
8720  // Mark the curve as done
8721  done_curve[ic] = true;
8722  // Update the initial vertex values
8723  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8724  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8725  // Increase the number of sorted curves
8726  nsorted_curves++;
8727  // Set the flag to indicate that a curve was added to the list
8728  added_curve = true;
8729  break;
8730  }
8731 
8732  diff =
8733  ((current_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8734  (current_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8735  +
8736  ((current_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8737  (current_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8738  diff = sqrt(diff);
8739  // CURRENT curve to the RIGHT of the ROOT curve
8741  {
8742  // Add the current curve to the right
8743  list_building_polygon_pt.push_back(current_curve_pt);
8744  // Mark the curve as done
8745  done_curve[ic] = true;
8746  // Update the initial vertex values
8747  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8748  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8749  // Increase the number of sorted curves
8750  nsorted_curves++;
8751  // Set the flag to indicate that a curve was added to the list
8752  added_curve = true;
8753  break;
8754  }
8755 
8756  diff =
8757  ((current_curve_final_vertex[0] - root_curve_final_vertex[0])*
8758  (current_curve_final_vertex[0] - root_curve_final_vertex[0]))
8759  +
8760  ((current_curve_final_vertex[1] - root_curve_final_vertex[1])*
8761  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8762  diff = sqrt(diff);
8763  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8765  {
8767  tmp_curve_pt(ncurrent_curve_polyline);
8768  // Reverse each polyline and back them up
8769  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8770  {
8771  current_curve_pt[it]->reverse();
8772  tmp_curve_pt[it] = current_curve_pt[it];
8773  }
8774  // Now copy them back but in reverse order
8775  unsigned count = 0;
8776  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8777  {current_curve_pt[count] = tmp_curve_pt[i];}
8778  // Add the current curve to the right
8779  list_building_polygon_pt.push_back(current_curve_pt);
8780  // Mark the curve as done
8781  done_curve[ic] = true;
8782  // Update the initial vertex values
8783  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8784  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8785  // Increase the number of sorted curves
8786  nsorted_curves++;
8787  // Set the flag to indicate that a curve was added to the list
8788  added_curve = true;
8789  break;
8790  }
8791 
8792  } // if (!done_curve[ic])
8793 
8794  } // for (ic < ncurves)
8795 
8796  // After adding a curve check if it is possible to create a polygon
8797  double diff =
8798  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8799  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8800  +
8801  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8802  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8803  diff = sqrt(diff);
8805  {
8806  // If the curves already create a Polygon then go out of the
8807  // loop and create the Polygon
8808  added_curve = false;
8809 #ifdef PARANOID
8810  // Set the flag to indicate that a Polygon has been created
8811  polygon_created = true;
8812 #endif
8813  } // (diff <
8814  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8815  // when the curve creates a Polygon by itself
8816 
8817  }while(added_curve);
8818 
8819 #ifdef PARANOID
8820  if (!polygon_created)
8821  {
8822  std::stringstream error_message;
8823  error_message
8824  << "It was no possible to create a TriangleMeshPolygon with "
8825  << "the input set of curves\n"
8826  << "These are the initial and final vertices in the current "
8827  << "sorted list of\nTriangleMeshPolyLines\n\n";
8828  Vector<double> init_vertex(2);
8829  Vector<double> final_vertex(2);
8830  unsigned icurve = 0;
8831  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8832  = list_building_polygon_pt.begin();
8833  it != list_building_polygon_pt.end(); it++, icurve++)
8834  {
8835  const unsigned ncurrent_curve_polyline = (*it).size();
8836  error_message
8837  << "TriangleMeshCurve #" << icurve << "\n"
8838  << "-----------------------------------\n";
8839  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8840  {
8841  Vector<double> init_vertex(2);
8842  Vector<double> final_vertex(2);
8843  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8844  (*it)[ip]->final_vertex_coordinate(final_vertex);
8845  error_message
8846  <<"TriangleMeshPolyLine #" << ip << "\n"
8847  <<"Initial vertex: ("<<init_vertex[0]<<","<<init_vertex[1]<<")\n"
8848  <<"Final vertex: ("<<final_vertex[0]<<","<<final_vertex[1]<<")\n";
8849  } // for (ip < ncurrent_curve_polyline)
8850  } // for (it != list_building_polygon_pt.end())
8851 
8852  throw OomphLibError(error_message.str(),
8853  "TriangleMesh::create_tmp_polygons_helper()",
8854  OOMPH_EXCEPTION_LOCATION);
8855 
8856  } // if (!polygon_created)
8857 #endif
8858 
8859  // Create the polygon after joining the curves
8860  unsigned ntotal_polylines = 0;
8861  // Get the total number of polylines
8862  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8863  = list_building_polygon_pt.begin();
8864  it != list_building_polygon_pt.end(); it++)
8865  {
8866  ntotal_polylines+=(*it).size();
8867  }
8868 
8869  // Create the curve section representation of the curves on the list
8870  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
8871 
8872  // Copy the polylines into its curve section representation
8873  unsigned counter = 0;
8874  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8875  = list_building_polygon_pt.begin();
8876  it != list_building_polygon_pt.end(); it++)
8877  {
8878  const unsigned ncurrent_curve_polyline = (*it).size();
8879  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++,counter++)
8880  {
8881  curve_section_pt[counter] = (*it)[ip];
8882  } // for (ip < ncurrent_curve_polyline)
8883  } // Loop over the list of polylines
8884 
8885  // ... and create the Polygon
8886  TriangleMeshPolygon *new_polygon_pt =
8887  new TriangleMeshPolygon(curve_section_pt);
8888 
8889  // Mark the polygon for deletion (in the destructor)
8890  this->Free_polygon_pt.insert(new_polygon_pt);
8891 
8892  // Add the polygon to the output polygons
8893  polygons_pt.push_back(new_polygon_pt);
8894 
8895  } // else
8896  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8897 
8898  }while(nsorted_curves < nunsorted_curves);
8899 
8900  }
8901 
8902  //======================================================================
8903  //\short Take the polylines from the original open curves and created
8904  //new temporaly representations of open curves with the bits of
8905  //original curves not overlapped by shared boundaries
8906  //======================================================================
8907  template<class ELEMENT>
8909  Vector<Vector<TriangleMeshPolyLine *> > &sorted_open_curves_pt,
8910  Vector<TriangleMeshPolyLine*> &unsorted_shared_to_internal_poly_pt,
8911  Vector<TriangleMeshOpenCurve *> &open_curves_pt)
8912  {
8913  // Here search for the connections of the open curves remaining as
8914  // open curves with the shared boundaries markes as internal
8915  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
8916 
8917  // Once identified the connections created with the new internal
8918  // boundaries representations add them to the open curves container
8919  for (unsigned i = 0; i < ninternal_open_curves; i++)
8920  {
8921  // Create the curve section representation of the polylines
8922  const unsigned npoly = sorted_open_curves_pt[i].size();
8923  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
8924  for (unsigned j = 0; j < npoly; j++)
8925  {
8926  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
8927  }
8928  // ... and create the Open Curve
8929  TriangleMeshOpenCurve *new_open_curve_pt =
8930  new TriangleMeshOpenCurve(tmp_curve_section);
8931 
8932  // Mark the open curve for deletion (in the destructor)
8933  this->Free_open_curve_pt.insert(new_open_curve_pt);
8934 
8935  // Add the open curve to the output open curves
8936  open_curves_pt.push_back(new_open_curve_pt);
8937 
8938  } // (i < ninternal_open_curves)
8939 
8940  }
8941 
8942  //======================================================================
8943  //\short Check for any possible connections that the array of sorted
8944  //nodes have with original boundary nodes, previous shared polyline
8945  //nodes or with itself polyline nodes. In case that there is a
8946  //connection, get the boundary id to which connects
8947  //======================================================================
8948  template<class ELEMENT>
8950  std::set<FiniteElement*> &element_in_processor_pt,
8951  const int &root_edge_bnd_id,
8952  std::map<std::pair<Node*,Node*>, bool> &overlapped_face,
8953  std::map<unsigned, std::map<Node*, bool> >
8954  &node_on_bnd_not_overlapped_by_shd_bnd,
8955  std::list<Node*> &current_polyline_nodes,
8956  std::map<unsigned, std::list<Node*> >
8957  &shared_bnd_id_to_sorted_list_node_pt,
8958  const unsigned &node_degree,
8959  Node* &new_node_pt,
8960  const bool called_from_load_balance)
8961  {
8962  // Initialize the flag to return
8963  int flag_to_return = -1;
8964 
8965  // --------------------------------------------------------------------
8966  // First try to find a connection with any original boundary (keep
8967  // in mind the case when internal boundaries may be overlapped by
8968  // shared boundaries)
8969  // --------------------------------------------------------------------
8970 
8971  // Check if the shared boundary is overlapping an internal boundary
8972  bool overlapping_internal_boundary = false;
8973  // The boundary id overlapped by the current shared boundary
8974  unsigned internal_overlaping_bnd_id = 0;
8975  if (root_edge_bnd_id != -1)
8976  {
8977  // Set the flat to true
8978  overlapping_internal_boundary = true;
8979  // Set the bnd id of the overlapped internal boundary
8980  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
8981  } // if (root_edge_bnd_id != -1)
8982 
8983  // ---------------------------------------------------------------
8984  // Check if the connection is with an original boundary by checking
8985  // if the new node is a boundary node, and it lives in an element
8986  // that is part of the domain
8987  // ---------------------------------------------------------------
8988  if (new_node_pt->is_on_boundary())
8989  {
8990  // Flag to indicate if the node lives in a non overlapped boundary
8991  bool is_node_living_in_non_overlapped_boundary = false;
8992 
8993  // If the node is a boundary node then check in which boundary it
8994  // is
8995  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
8996  for (unsigned bb=0;bb<noriginal_bnd;bb++)
8997  {
8998  // If the shared boundary overlaps an internal boundary it will
8999  // be indicated by (root_edge_bnd_id != -1), the original
9000  // internal boundary that overlaps is given by the
9001  // root_edge_bnd_id value. We skip that original internal
9002  // boundary because the new node will be obviously ON the
9003  // internal boundary
9004  if (overlapping_internal_boundary)
9005  {
9006  // Is the node on boundary bb?
9007  if (new_node_pt->is_on_boundary(bb))
9008  {
9009  // If overlaping then check that the boundary is different
9010  // from the one that is being overlapped, or if overlapped
9011  // then check that the node is on an edge on the bb
9012  // boundary not overlapped by a shared boundary
9013  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9014  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9015  if (bb != internal_overlaping_bnd_id ||
9016  ((bb == internal_overlaping_bnd_id) &&
9017  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9018  {
9019  // Is the node living in a non overlapped boundary
9020  if (bb != internal_overlaping_bnd_id)
9021  {
9022  is_node_living_in_non_overlapped_boundary = true;
9023  }
9024 
9025  // Now we need to check that the node lies on a boundary
9026  // that still exist (the elements associated to the
9027  // boundary may have been removed at the mesh distribution
9028  // stage). The node may be still marked as a boundary node
9029  // but the boundary may not have elements associated.
9030 
9031  // Get the number of elements in the boundary
9032  const unsigned n_bound_ele = this->nboundary_element(bb);
9033  if (n_bound_ele > 0)
9034  {
9035  // Check that node lies on a nonhalo element, those are
9036  // the elements used to update the domain representation
9037  for (unsigned e = 0; e < n_bound_ele; e++)
9038  {
9039  // Get the boundary bulk element
9040  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9041  // Check if the element will be retained, it means it
9042  // is a nonhalo element
9043  std::set<FiniteElement*>::iterator it =
9044  element_in_processor_pt.find(bulk_ele_pt);
9045  // If found then check if the node live in the element
9046  if (it!=element_in_processor_pt.end())
9047  {
9048  // Found the node in the nonhalo face element
9049  bool found_node = false;
9050  // Get the face index
9051  int face_index = this->face_index_at_boundary(bb, e);
9052  // Create the face element
9053  FiniteElement* face_ele_pt =
9054  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9055  // Get the number of nodes in the face element
9056  const unsigned n_node_face = face_ele_pt->nnode();
9057  // Get the first and last node of the face element
9058  Node* first_node_pt = face_ele_pt->node_pt(0);
9059  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9060  // Create the edge with the pair of nodes
9061  std::pair<Node*, Node*> tmp_edge =
9062  std::make_pair(first_node_pt, last_node_pt);
9063  // Check if the face element edge is overlapped by a
9064  // shared boundary
9065  // Is the face not overlapped?
9066  if (!overlapped_face[tmp_edge])
9067  {
9068  // Look for the node in the current face element
9069  for (unsigned n = 0; n < n_node_face; n++)
9070  {
9071  // Check for every individual node
9072  if (face_ele_pt->node_pt(n) == new_node_pt)
9073  {
9074  found_node = true;
9075  break;
9076  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9077  } // for (n < n_node_face)
9078  } // if (!overlapped_face[tmp_edge])
9079  // Free the memory of the face element
9080  delete face_ele_pt;
9081  if (found_node)
9082  {
9083  // return the first original boundary id found,
9084  // does not matter if the node lies on more than
9085  // one original boundary (with boundary
9086  // elements). This is the original boundary id
9087  // that will be used to create the connection
9088  flag_to_return = bb;
9089  return flag_to_return;
9090  } // if (found_node)
9091 
9092  } // if (it!=element_in_processor_pt.end())
9093 
9094  } // for (e < n_bound_ele)
9095 
9096  } // if (n_bound_ele > 0)
9097 
9098  } // if (bb != internal_overlaping_bnd_id ||
9099  // ((bb == internal_overlaping_bnd_id) &&
9100  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9101 
9102  } // if (nod_pt->is_on_boundary(bb))
9103 
9104  } // if (overlapping_internal_boundary)
9105  else
9106  {
9107  // Is the node on boundary bb?
9108  if (new_node_pt->is_on_boundary(bb))
9109  {
9110  // Now we need to check that the node lies on a boundary
9111  // that still exist (the elements associated to the boundary
9112  // may have been removed at the mesh distribution
9113  // stage). The node may be still marked as a boundary node
9114  // but the boundary may not have elements associated.
9115 
9116  // Get the number of elements in the boundary
9117  const unsigned n_bound_ele = this->nboundary_element(bb);
9118  if (n_bound_ele > 0)
9119  {
9120  // Check that node lies on a nonhalo element, those are
9121  // the elements used to update the domain representation
9122  for (unsigned e = 0; e < n_bound_ele; e++)
9123  {
9124  // Get the boundary bulk element
9125  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9126  // Check if the element will be retained, it means it is
9127  // a nonhalo element
9128  std::set<FiniteElement*>::iterator it =
9129  element_in_processor_pt.find(bulk_ele_pt);
9130  // If found then check if the node live in the element
9131  if (it!=element_in_processor_pt.end())
9132  {
9133  // Found the node in the nonhalo face element
9134  bool found_node = false;
9135  // Get the face index
9136  int face_index = this->face_index_at_boundary(bb, e);
9137  // Create the face element
9138  FiniteElement* face_ele_pt =
9139  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9140  // Get the number of nodes in the face element
9141  const unsigned n_node_face = face_ele_pt->nnode();
9142  // Get the first and last node of the face element
9143  Node* first_node_pt = face_ele_pt->node_pt(0);
9144  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9145  // Create the edge with the pair of nodes
9146  std::pair<Node*, Node*> tmp_edge =
9147  std::make_pair(first_node_pt, last_node_pt);
9148  // Check if the face element edge is overlapped by a
9149  // shared boundary
9150  // Is the face not overlapped?
9151  if (!overlapped_face[tmp_edge])
9152  {
9153  // Look for the node in the current face element
9154  for (unsigned n = 0; n < n_node_face; n++)
9155  {
9156  // Check for every individual node
9157  if (face_ele_pt->node_pt(n) == new_node_pt)
9158  {
9159  found_node = true;
9160  break;
9161  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9162  } // for (n < n_node_face)
9163  } // if (!overlapped_face[tmp_edge])
9164  // Free the memory of the face element
9165  delete face_ele_pt;
9166  if (found_node)
9167  {
9168  // return the first original boundary id found, does
9169  // not matter if the node lies on more than one
9170  // original boundary (with boundary elements). This
9171  // is the original boundary id that will be used to
9172  // create the connection
9173  flag_to_return = bb;
9174  return flag_to_return;
9175  } // if (found_node)
9176 
9177  } // if (it!=element_in_processor_pt.end())
9178 
9179  } // for (e < n_bound_ele)
9180 
9181  } // if (n_bound_ele > 0)
9182 
9183  } // if (nod_pt->is_on_boundary(bb))
9184  } // else if (overlapping_internal_boundary)
9185  } // for (bb < noriginal_bnd)
9186 
9187  // We will only reach this stage when the node was found to be
9188  // connected to an original boundary but the element(s) on that
9189  // boundary where the node should live are not part of the domain.
9190  // Think in a corner of a triangle which touches the boundary
9191  // which elements will not be part of the domain
9192 
9193  // We need to break the currently forming polyline
9194  //flag_to_return = -3;
9195 
9196  // We need to break the currently forming polyline if and only if
9197  // the boundary(ies) in which the node is living is(are) not an
9198  // overlapped boundary
9199  if (!overlapping_internal_boundary)
9200  {
9201  // If the boundary(ies) in which the node is living is(are) an
9202  // overlapped boundary then break the break the formation of the
9203  // polyline
9204  flag_to_return = -3;
9205  }
9206  else
9207  {
9208  // The boundary is overlapped, if the node lives in a non
9209  // overlapped boundary then we can break the formation of the
9210  // polyline
9211  if (is_node_living_in_non_overlapped_boundary)
9212  {
9213  flag_to_return = -3;
9214  } // if (is_node_living_in_non_overlapped_boundar)y
9215 
9216  } // if (!overlapping_internal_boundary)
9217 
9218  } // if (new_node_pt->is_on_boundary())
9219 
9220  // Return inmediately if the connection is with an original boundary
9221  // whose elements are still part of the domain
9222  if (flag_to_return >= 0)
9223  {
9224  return flag_to_return;
9225  }
9226 
9227  // ----------------------------------------------------------------------
9228  // Secondly, if there is not a connection with any original
9229  // boundary, or if there is connection but with an original boundary
9230  // whose elements are not part of the domain, then check for
9231  // connections with previously created shared polylines
9232  // ----------------------------------------------------------------------
9233  // Store all the previous shared polylines to which the current
9234  // found is found to be connected
9235  Vector<unsigned> candidate_shared_bnd_to_connect;
9236  // Check for all the previous polylines except the current one
9237  for (std::map<unsigned, std::list<Node*> >::iterator it =
9238  shared_bnd_id_to_sorted_list_node_pt.begin();
9239  it != shared_bnd_id_to_sorted_list_node_pt.end();
9240  it++)
9241  {
9242  // Get the boundary id of the list of nodes that created the
9243  // polyline (the shared boundary id associated with the list of
9244  // nodes)
9245  const unsigned i_bnd_id = (*it).first;
9246  // Get an iterator pointer to the list of nodes of the shared
9247  // polyline
9248  std::list<Node*>::iterator it_list = (*it).second.begin();
9249  // Get the total number of nodes associated to the boundary
9250  const unsigned n_nodes = (*it).second.size();
9251  // Search for connections in the list of nodes
9252  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9253  {
9254  // Is the node already part of any other shared boundary
9255  if ((*it_list) == new_node_pt)
9256  {
9257  // Include the i-th boundary id in the list of candidate
9258  // shared boundaries to connect
9259  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9260  // Break the look with the i-th shared boundary, check with
9261  // the others shared boundaries
9262  break;
9263  } // if ((*it_list) == new_node_pt)
9264 
9265  } // for (i < nnodes)
9266 
9267  } // Loop over the shared boundaries and associated nodes
9268 
9269  // Get the number of candidate shared boundaries to connect
9270  const unsigned n_candidate_shared_bnd_to_connect =
9271  candidate_shared_bnd_to_connect.size();
9272 
9273  // Is there a connection with any previous shared polyline
9274  if (n_candidate_shared_bnd_to_connect > 0)
9275  {
9276  // If called from load balance we do not need to check if the
9277  // shared boundary is part of the processor since it certanily is,
9278  // only the shared boundaries that are pare of the processor are
9279  // used to created connection when creating the new shared
9280  // boundaries in the load balance rutine
9281  if (called_from_load_balance)
9282  {
9283  return candidate_shared_bnd_to_connect[0];
9284  }
9285 
9286  // We need to ensure that the shared boundary to which we are
9287  // connecting is part of the current processor, if none of the
9288  // found shared bundaries is in the current processor then return
9289  // the flag for "connection with boundary not in the current
9290  // processor"
9291 
9292  // Store the shared boundaries associated with the current processor
9293  Vector<unsigned> shared_bound_in_this_proc;
9294 
9295  // Get the shared boundaries associated with the current processor
9296  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9297 
9298  // If any of the candidate shared boundaries to connect is in the
9299  // current processor then return that shared boundary id
9300 
9301  // The number of shared boundaries in the current processor
9302  const unsigned n_shared_bound_in_this_proc =
9303  shared_bound_in_this_proc.size();
9304 
9305  // Loop over the candidate shared boundaries to connect
9306  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9307  {
9308  // Get the i-th candidate shared boundary to connect
9309  const unsigned i_candidate_shared_bnd =
9310  candidate_shared_bnd_to_connect[i];
9311 
9312  // Loop over the shared boundaries in the current processor
9313  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9314  {
9315  // Is the candidate boundary a shared boundary in this processor?
9316  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9317  {
9318  // Return the candidate shared boundary
9319  flag_to_return = i_candidate_shared_bnd;
9320  return flag_to_return;
9321  } // The candidate shared boundary is a boundary in the
9322  // current processor
9323 
9324  } // for (j < n_shared_bound_in_this_proc)
9325 
9326  } // for (i < n_candidate_shared_bnd_to_connect)
9327 
9328  // If non of the candidate shared boundaries to connect is in the
9329  // current processor the mark that we need to stop the addition of
9330  // vertices at this side of the polyline
9331  flag_to_return = -3;
9332 
9333  } // if (n_candidate_shared_bnd_to_connect > 0)
9334 
9335  // Return inmediately if the connection is with a previuos shared
9336  // boundary
9337  if (flag_to_return >= 0)
9338  {
9339  return flag_to_return;
9340  }
9341 
9342  // ------------------------------------------------------------------
9343  // Finally,check for connections with the same polyline (the shared
9344  // boundary that is being constructed). We are trying to avoid loops
9345  // or connections with the same shared boundary that is why this is
9346  // checked at the end
9347  // ------------------------------------------------------------------
9348  unsigned nrepeated = 0;
9349  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9350  it_list != current_polyline_nodes.end();
9351  it_list++)
9352  {
9353  // There must be at least one repeated node (the one that we have
9354  // just added, and it should be the first or last node)
9355  if ((*it_list) == new_node_pt) {nrepeated++;}
9356  }
9357  // If the number of repeated nodes is greater than one then the
9358  // polyline has a connection with itself
9359  if (nrepeated > 1)
9360  {
9361  // Return the flag value to indicate connection with itself, we
9362  // can not return the boundary id of the current polyline since it
9363  // has not been already assigned
9364  flag_to_return = -2;
9365  }
9366 
9367  // If there is no connection at all check the degree of the node, if
9368  // it is greater than 2 then return the flag to stop adding nodes
9369  // after this one
9370  if (node_degree > 2)
9371  {
9372  flag_to_return = -3;
9373  }
9374 
9375  // Return the flag
9376  return flag_to_return;
9377 
9378  }
9379 
9380  //======================================================================
9381  // \short Establish the connections of the polylines previously
9382  // marked as having connections. This connections were created in the
9383  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9384  // In case of doing load balancing the connections were created by the
9385  // function RefineableTriangleMesh::create_new_shared_boundaries()
9386  // ======================================================================
9387  template<class ELEMENT>
9389  {
9390  // Get the rank of the current processor
9391  const unsigned my_rank = this->communicator_pt()->my_rank();
9392 
9393  // Get the shared curves associated with this processor
9394  Vector<Vector<TriangleMeshPolyLine*> > shared_curves_pt =
9395  this->Shared_boundary_polyline_pt[my_rank];
9396 
9397  // Loop through the shared boundaries on the current processor and
9398  // check if they are marked to create a connection
9399  const unsigned ncurves = shared_curves_pt.size();
9400  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9401  {
9402  // Get the number of polylines in the current shared curve
9403  const unsigned npoly = shared_curves_pt[icurve].size();
9404  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9405  {
9406  // Get the polyline representation of the shared boundary
9407  TriangleMeshPolyLine *shd_poly_pt = shared_curves_pt[icurve][ipoly];
9408 
9409  // Get the boundary id of the current polyline
9410  const unsigned bound_id = shd_poly_pt->boundary_id();
9411 
9412  // Is the left vertex connected
9413  const bool is_connected_to_the_left =
9414  shd_poly_pt->is_initial_vertex_connected();
9415 
9416  // Is the right vertex connected
9417  const bool is_connected_to_the_right =
9418  shd_poly_pt->is_final_vertex_connected();
9419 
9420  // -----------------------------------------------------------------
9421  // If there is a connection at one of the ends we need to
9422  // establish that connection
9423  if (is_connected_to_the_left || is_connected_to_the_right)
9424  {
9425  // Now get the new left and right vertices of the shared
9426  // polyline
9427  const unsigned n_vertex = shd_poly_pt->nvertex();
9428 
9429  // Now get the polylines to where the current shared boundary is
9430  // connected and create the connections
9431 
9432  // --------------------------------------------------------------
9433  // Connection to the left
9434  if (is_connected_to_the_left)
9435  {
9436  // Get the unsigned version of the bound id to connect to
9437  // the left
9438  const unsigned uconnection_to_the_left =
9439  shd_poly_pt->initial_vertex_connected_bnd_id();
9440 
9441  // The pointer to the boundary to connect
9442  TriangleMeshPolyLine *poly_to_connect_pt = 0;
9443 
9444  // Flag to indicate we are trying to connect to an split
9445  // boundary
9446  bool connecting_to_an_split_boundary = false;
9447 
9448  // Flag to indicate we are trying to connecto to an internal
9449  // boundary that is overlaped by a shared boundary
9450  bool connecting_to_an_overlaped_boundary = false;
9451 
9452  // Check if the connection is with itself
9453  if (uconnection_to_the_left == bound_id)
9454  {
9455  // Set the pointer to the polyline to connect
9456  poly_to_connect_pt = shd_poly_pt;
9457  }
9458  else
9459  {
9460  // Get the initial shared boundary ids
9461  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9462  // Check if the boundary to connect is a shared polyline
9463  if (uconnection_to_the_left >= initial_shd_bnd_id)
9464  {
9465  // Get the polyline pointer representing the destination
9466  // boundary
9467  poly_to_connect_pt =
9468  boundary_polyline_pt(uconnection_to_the_left);
9469  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9470  else
9471  {
9472  // If we are going to connect to an original boundary
9473  // verify if the boundary was splitted during the
9474  // distribution process to consider all the chunks
9475  // (sub-polylines) of the boundary
9476  if (boundary_was_splitted(uconnection_to_the_left))
9477  {
9478  connecting_to_an_split_boundary = true;
9479  } // if (boundary_was_splitted(uconnection_to_the_left))
9480 
9481  // If we are going to connect to an original boundary
9482  // verify if the boundary, or any of its chunks is
9483  // marked to be overlapped by a shared boundary, if that
9484  // is the case we first check for connections in the
9485  // shared boundary that overlaps the internal boundary,
9486  // or the chunks, and then check for connections in the
9487  // original boundary
9488  if (connecting_to_an_split_boundary)
9489  {
9490  // Get the number of chucks that represent the
9491  // destination boundary
9492  const unsigned n_sub_poly =
9493  nboundary_subpolylines(uconnection_to_the_left);
9494  // Now loop over the chunks of the destination
9495  // boundary and if any of them is marked to be
9496  // overlaped by a shared boundary then set the flag
9497  // and break the loop
9498  for (unsigned ii =0; ii < n_sub_poly; ii++)
9499  {
9500  if (boundary_marked_as_shared_boundary(
9501  uconnection_to_the_left, ii))
9502  {
9503  // Mark the boundary as being overlaped by a
9504  // shared boundary
9505  connecting_to_an_overlaped_boundary = true;
9506  // Break, no need to look for more overlapings
9507  break;
9508  } // if (boundary_marked_as_shared_boundary(...))
9509  } // for (ii < n_sub_poly)
9510  } // if (connecting_to_an_split_boundary)
9511  else
9512  {
9513  // If not connecting to an split boundary then check
9514  // if the whole destination boundary is overlaped by
9515  // an internal boundary
9516  if (boundary_marked_as_shared_boundary(
9517  uconnection_to_the_left, 0))
9518  {
9519  // Mark the boundary as being overlaped by a shared
9520  // boundary
9521  connecting_to_an_overlaped_boundary = true;
9522  } // if (boundary_marked_as_shared_boundary(...))
9523  } // else if (connecting_to_an_split_boundary)
9524 
9525  // If we are connecting neither to an split boundary nor
9526  // an overlaped boundary then get the pointer to the
9527  // original boundary
9528  if (!(connecting_to_an_split_boundary ||
9529  connecting_to_an_overlaped_boundary))
9530  {
9531  // Get the polyline pointer representing the
9532  // destination boundary
9533  poly_to_connect_pt =
9534  boundary_polyline_pt(uconnection_to_the_left);
9535  } // else if (NOT split, NOT overlaped)
9536  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9537 
9538  } // else if (uconnection_to_the_left == bound_id)
9539 
9540 #ifdef PARANOID
9541  // If we are not connecting to an original boundary
9542  // (connecting to the same shared boundary or to another
9543  // shared boundary) then the boundary should not be marked
9544  // as split
9545  if (!connecting_to_an_split_boundary)
9546  {
9547  if (boundary_was_splitted(uconnection_to_the_left))
9548  {
9549  std::stringstream error;
9550  error
9551  << "The current shared boundary (" << bound_id << ") was "
9552  << "marked to have a connection\nto the left with the "
9553  << "boundary (" << uconnection_to_the_left << ").\n"
9554  << "The problem is that the destination boundary (possibly\n"
9555  << "another shared boundary) is marked to be split\n"
9556  << "There should not be split shared boundaries\n\n";
9557  throw OomphLibError(
9558  error.str(),
9559  "TriangleMesh::create_shared_polylines_connections()",
9560  OOMPH_EXCEPTION_LOCATION);
9561  }
9562  } // if (!connecting_to_an_split_boundary)
9563 #endif
9564 
9565  // Now look for the vertex number on the destination
9566  // boundary(ies) -- in case that the boundary was split ---
9567 
9568  // Do not check for same orientation, that was previously
9569  // worked by interchanging the connections boundaries (if
9570  // necessary)
9571 
9572  // Get the left vertex in the shared boundary
9573  Vector<double> shd_bnd_left_vertex =
9574  shd_poly_pt->vertex_coordinate(0);
9575 
9576  // If the boundary was not split then ...
9577  if (!connecting_to_an_split_boundary)
9578  {
9579  // ... check if the boundary is marked to be overlaped by
9580  // a shared boundary
9581  if (!connecting_to_an_overlaped_boundary)
9582  {
9583  // If that is not the case then we can safely look for
9584  // the vertex number on the destination boundar
9585  unsigned vertex_index = 0;
9586 
9587  const bool found_vertex_index =
9588  get_connected_vertex_number_on_destination_polyline(
9589  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9590 
9591  // If we could not find the vertex index to connect then
9592  // we are in trouble
9593  if (!found_vertex_index)
9594  {
9595  std::stringstream error;
9596  error
9597  << "The current shared boundary (" << bound_id << ") was "
9598  << "marked to have a connection\nto the left with the "
9599  << "boundary (" << uconnection_to_the_left << ").\n"
9600  << "The problem is that the left vertex of the current\n"
9601  << "shared boundary is not in the list of vertices of the\n"
9602  << "boundary to connect.\n\n"
9603  << "This is the left vertex of the current shared boundary\n"
9604  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9605  << shd_bnd_left_vertex[1] << ")\n\n"
9606  << "This is the list of vertices on the destination "
9607  << "boundary\n";
9608  const unsigned n_v = poly_to_connect_pt->nvertex();
9609  for (unsigned i = 0; i < n_v; i++)
9610  {
9611  Vector<double> cvertex =
9612  poly_to_connect_pt->vertex_coordinate(i);
9613  error
9614  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
9615  }
9616  throw OomphLibError(
9617  error.str(),
9618  "TriangleMesh::create_shared_polylines_connections()",
9619  OOMPH_EXCEPTION_LOCATION);
9620  } // if (!found_vertex_index)
9621 
9622  // Create the connection, the left vertex of the current
9623  // shared boundary is connected with the vertex_index-th
9624  // vertex on the destination boundary
9626  poly_to_connect_pt, vertex_index);
9627 
9628  } // if (!connecting_to_an_overlaped_boundary)
9629  else
9630  {
9631  // If the boundary is marked to be overlaped by a shared
9632  // boundary then get that shared boundary and look for
9633  // the connection in that boundary
9634 
9635  // The vertex where to store the index to connect
9636  unsigned vertex_index = 0;
9637  // A flag to indicate if the connection was found
9638  bool found_vertex_index = false;
9639 
9640  // Get the shared boundary id that is overlaping the
9641  // internal boundary
9642  Vector<unsigned> dst_shd_bnd_ids;
9643  get_shared_boundaries_overlapping_internal_boundary(
9644  uconnection_to_the_left, dst_shd_bnd_ids);
9645 
9646  // Get the number of shared polylines that were found to
9647  // overlap the internal boundary
9648  const unsigned n_shd_bnd_overlap_int_bnd =
9649  dst_shd_bnd_ids.size();
9650 
9651  // Loop over the shared boundaries that overlap the
9652  // internal boundary and look for the vertex to connect
9653  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9654  {
9655  // Get the shared polyline
9656  const unsigned new_connection_to_the_left =
9657  dst_shd_bnd_ids[ss];
9658 
9659  // Get the shared polyline that is overlaping the
9660  // internal boundary
9661  poly_to_connect_pt =
9662  boundary_polyline_pt(new_connection_to_the_left);
9663 
9664  if (poly_to_connect_pt!=0)
9665  {
9666  // Look for the vertex number in the destination
9667  // shared polyline
9668  found_vertex_index =
9669  get_connected_vertex_number_on_destination_polyline(
9670  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9671  } // if (poly_to_connect_pt!=0)
9672 
9673  // If we have found the vertex to connect then
9674  // break the loop
9675  if (found_vertex_index)
9676  {
9677  break;
9678  } // if (found_vertex_index)
9679 
9680  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9681 
9682 #ifdef PARANOID
9683  // If we could not find the vertex index to connect then
9684  // we are in trouble
9685  if (!found_vertex_index)
9686  {
9687  std::stringstream error;
9688  error
9689  << "The current shared boundary (" << bound_id << ") was "
9690  << "marked to have a connection\nto the left with the "
9691  << "boundary (" << uconnection_to_the_left << ").\n"
9692  << "This last boundary is marked to be overlaped by "
9693  << "shared boundaries\n"
9694  << "The problem is that the left vertex of the current\n"
9695  << "shared boundary is not in the list of vertices of the\n"
9696  << "boundary to connect.\n\n"
9697  << "This is the left vertex of the current shared boundary\n"
9698  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9699  << shd_bnd_left_vertex[1] << ")\n\n"
9700  << "This is the list of vertices on the destination "
9701  << "boundary\n";
9702  Vector<unsigned> dst_shd_bnd_ids;
9703  get_shared_boundaries_overlapping_internal_boundary(
9704  uconnection_to_the_left, dst_shd_bnd_ids);
9705  const unsigned n_shd_bnd_overlap_int_bnd =
9706  dst_shd_bnd_ids.size();
9707  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9708  {
9709  const unsigned new_connection_to_the_left =
9710  dst_shd_bnd_ids[ss];
9711  poly_to_connect_pt =
9712  boundary_polyline_pt(new_connection_to_the_left);
9713  if (poly_to_connect_pt != 0)
9714  {
9715  const unsigned shd_bnd_id_overlap =
9716  poly_to_connect_pt->boundary_id();
9717  error << "Shared boundary id("
9718  << shd_bnd_id_overlap << ")\n";
9719  const unsigned n_v = poly_to_connect_pt->nvertex();
9720  for (unsigned i = 0; i < n_v; i++)
9721  {
9722  Vector<double> cvertex =
9723  poly_to_connect_pt->vertex_coordinate(i);
9724  error
9725  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9726  <<cvertex[1]<<")\n";
9727  }
9728  } // if (poly_to_connect_pt != 0)
9729  } // for (ss < n_shd_bnd_overlap_int_bnd)
9730 
9731  throw OomphLibError(
9732  error.str(),
9733  "TriangleMesh::create_shared_polylines_connections()",
9734  OOMPH_EXCEPTION_LOCATION);
9735 
9736  } // if (!found_vertex_index)
9737 #endif
9738 
9739  // Create the connection, the left vertex of the current
9740  // shared boundary is connected with the vertex_index-th
9741  // vertex on the destination boundary
9743  poly_to_connect_pt, vertex_index);
9744 
9745  } // else if (!connecting_to_an_overlaped_boundary)
9746 
9747  } // if (!connecting_to_an_split_boundary)
9748  else
9749  {
9750  // If the boundary was split then we need to look for the
9751  // vertex in the sub-polylines
9752 
9753  // Get the sub-polylines vector
9754  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9755  boundary_subpolylines(uconnection_to_the_left);
9756 
9757  // Get the number of sub-polylines
9758  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9759 #ifdef PARANOID
9760  if (nsub_poly <= 1)
9761  {
9762  std::ostringstream error_message;
9763  error_message
9764  <<"The boundary (" << uconnection_to_the_left << ") was "
9765  << "marked to be splitted but\n"
9766  << "there are only ("<<nsub_poly<<") polylines to "
9767  << "represent it.\n";
9768  throw OomphLibError(
9769  error_message.str(),
9770  "TriangleMesh::create_shared_polylines_connections()",
9771  OOMPH_EXCEPTION_LOCATION);
9772  } // if (nsub_poly <= 1)
9773 #endif
9774  // We need to check if the boundary is marked to be
9775  // overlaped by an internal boundary, if that is the case
9776  // we need to check for each indivual subpolyline, and for
9777  // those overlaped by a shared polyline look for the
9778  // vertex in the shared polyline representation instead of
9779  // the original subpolyline
9780 
9781  // ... check if the boundary is marked to be overlaped by
9782  // a shared boundary
9783  if (!connecting_to_an_overlaped_boundary)
9784  {
9785  // We can work without checking the subpolylines
9786  // individually
9787 
9788  // The vertex where to store the index to connect
9789  unsigned vertex_index = 0;
9790  // The subpoly number to connect
9791  unsigned sub_poly_to_connect = 0;
9792  // A flag to indicate if the connection was found
9793  bool found_vertex_index = false;
9794 
9795  // Look for the vertex number to connect on each of the
9796  // subpolyines
9797  for (unsigned isub = 0; isub < nsub_poly; isub++)
9798  {
9799  // Assign the pointer to the sub-polyline
9800  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9801  // Search for the vertex in the current sub-polyline
9802  found_vertex_index =
9803  get_connected_vertex_number_on_destination_polyline(
9804  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9805  // If we have found the vertex to connect then break the
9806  // loop
9807  if (found_vertex_index)
9808  {
9809  // But first save the subpoly number (chunk), that
9810  // will be used to perform the connection
9811  sub_poly_to_connect = isub;
9812  break;
9813  } // if (found_vertex_index)
9814  } // for (isub < nsub_poly)
9815 
9816 #ifdef PARANOID
9817  // If we could not find the vertex index to connect then
9818  // we are in trouble
9819  if (!found_vertex_index)
9820  {
9821  std::stringstream error;
9822  error
9823  << "The current shared boundary (" << bound_id << ") was "
9824  << "marked to have a connection\nto the left with the "
9825  << "boundary (" << uconnection_to_the_left << ").\n"
9826  << "The problem is that the left vertex of the current\n"
9827  << "shared boundary is not in the list of vertices of any\n"
9828  << "of the sub polylines that represent the boundary to\n"
9829  << "connect.\n\n"
9830  << "This is the left vertex of the current shared boundary\n"
9831  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9832  << shd_bnd_left_vertex[1] << ")\n\n"
9833  << "This is the list of vertices on the destination "
9834  << "boundary\n";
9835  for (unsigned p = 0; p < nsub_poly; p++)
9836  {
9837  error << "Subpolyline #("<< p << ")\n";
9838  poly_to_connect_pt = tmp_vector_subpolylines[p];
9839  const unsigned n_v = poly_to_connect_pt->nvertex();
9840  for (unsigned i = 0; i < n_v; i++)
9841  {
9842  Vector<double> cvertex =
9843  poly_to_connect_pt->vertex_coordinate(i);
9844  error
9845  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9846  <<cvertex[1]<<")\n";
9847  }
9848  } // for (p < nsub_poly)
9849  throw OomphLibError(
9850  error.str(),
9851  "TriangleMesh::create_shared_polylines_connections()",
9852  OOMPH_EXCEPTION_LOCATION);
9853  } // if (!found_vertex_index)
9854 #endif
9855 
9856  // Create the connection, the left vertex of the current
9857  // shared boundary is connected with the vertex_index-th
9858  // vertex of sub_poly_to_connect-th subpolyline of the
9859  // destination boundary
9861  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9862 
9863  } // if (!connecting_to_an_overlaped_boundary)
9864  else
9865  {
9866  // We first look on the shared boundaries that overlap
9867  // the internal boundaries and the look for the
9868  // sub-polylines that are not marked as being overlaped
9869  // by shared boundaries
9870 
9871  // The vertex where to store the index to connect
9872  unsigned vertex_index = 0;
9873  // The subpoly number to connect
9874  unsigned sub_poly_to_connect = 0;
9875  // A flag to indicate if the connection was found
9876  bool found_vertex_index = false;
9877 
9878  // Get the shared boundaries id that are overlaping the
9879  // internal boundary
9880  Vector<unsigned> dst_shd_bnd_ids;
9881  get_shared_boundaries_overlapping_internal_boundary(
9882  uconnection_to_the_left, dst_shd_bnd_ids);
9883 
9884  // Get the number of shared polylines that were found to
9885  // overlap the internal boundary
9886  const unsigned n_shd_bnd_overlap_int_bnd =
9887  dst_shd_bnd_ids.size();
9888 
9889  // Loop over the shared boundaries that overlap the
9890  // internal boundary and look for the vertex to connect
9891  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9892  {
9893  // Get the shared polyline
9894  const unsigned new_connection_to_the_left =
9895  dst_shd_bnd_ids[ss];
9896 
9897  // Make sure that the destination polyline is not the
9898  // same as the current shared polyline
9899  if (bound_id != new_connection_to_the_left)
9900  {
9901  // Get the shared polyline that is overlaping the
9902  // internal boundary
9903  poly_to_connect_pt =
9904  boundary_polyline_pt(new_connection_to_the_left);
9905 
9906  if (poly_to_connect_pt != 0)
9907  {
9908  // Look for the vertex number in the destination
9909  // shared polyline
9910  found_vertex_index =
9911  get_connected_vertex_number_on_destination_polyline(
9912  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9913  } // if (poly_to_connect_pt != 0)
9914 
9915  // If we have found the vertex to connect then
9916  // break the loop
9917  if (found_vertex_index)
9918  {
9919  break;
9920  } // if (found_vertex_index)
9921 
9922  } // if (bound_id != new_connection_to_the_left)
9923 
9924  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9925 
9926  // If we have not yet found the vertex then look for it
9927  // in the sub-polylines that are not overlaped by shared
9928  // boundaries
9929  if (!found_vertex_index)
9930  {
9931  // Look for the vertex number to connect on each of
9932  // the subpolyines
9933  for (unsigned isub = 0; isub < nsub_poly; isub++)
9934  {
9935  // Only work with those sub-polylines that are not
9936  // overlaped by shared boundaries
9937  if (!boundary_marked_as_shared_boundary(
9938  uconnection_to_the_left, isub))
9939  {
9940  // Assign the pointer to the sub-polyline
9941  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9942  // Search for the vertex in the current sub-polyline
9943  found_vertex_index =
9944  get_connected_vertex_number_on_destination_polyline(
9945  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9946  // If we have found the vertex to connect then break the
9947  // loop
9948  if (found_vertex_index)
9949  {
9950  // But first save the subpoly number (chunk), that
9951  // will be used to perform the connection
9952  sub_poly_to_connect = isub;
9953  break;
9954  } // if (found_vertex_index)
9955 
9956  } // if (not overlaped by shared boundary)
9957 
9958  } // for (isub < nsub_poly)
9959 
9960  } // if (!found_vertex_index)
9961 
9962 #ifdef PARANOID
9963  // If we could not find the vertex index to connect then
9964  // we are in trouble
9965  if (!found_vertex_index)
9966  {
9967  std::stringstream error;
9968  error
9969  << "The current shared boundary (" << bound_id << ") was "
9970  << "marked to have a connection\nto the left with the "
9971  << "boundary (" << uconnection_to_the_left << ").\n"
9972  << "This last boundary is marked to be overlaped by "
9973  << "shared boundaries\n"
9974  << "The problem is that the left vertex of the current\n"
9975  << "shared boundary is not in the list of vertices of "
9976  << "the\nboundary to connect.\n\n"
9977  << "This is the left vertex of the current shared "
9978  << "boundary\n"
9979  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9980  << shd_bnd_left_vertex[1] << ")\n\n"
9981  << "This is the list of vertices on the destination "
9982  << "boundary (only those subpolylines not marked as "
9983  << "overlaped by\nshared boundaries)\n";
9984  for (unsigned p = 0; p < nsub_poly; p++)
9985  {
9986  if (!boundary_marked_as_shared_boundary(
9987  uconnection_to_the_left, p))
9988  {
9989  error << "Subpolyline #("<< p << ")\n";
9990  poly_to_connect_pt = tmp_vector_subpolylines[p];
9991  const unsigned n_v = poly_to_connect_pt->nvertex();
9992  for (unsigned i = 0; i < n_v; i++)
9993  {
9994  Vector<double> cvertex =
9995  poly_to_connect_pt->vertex_coordinate(i);
9996  error
9997  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9998  <<cvertex[1]<<")\n";
9999  }
10000  } // Not marked as overlaped
10001  } // for (p < nsub_poly)
10002  error << "\nThis is the list of vertices of the shared "
10003  << "polylines that overlap\nthe internal "
10004  << "boundary\n";
10005  Vector<unsigned> dst_shd_bnd_ids;
10006  get_shared_boundaries_overlapping_internal_boundary(
10007  uconnection_to_the_left, dst_shd_bnd_ids);
10008  const unsigned n_shd_bnd_overlap_int_bnd =
10009  dst_shd_bnd_ids.size();
10010  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10011  {
10012  const unsigned new_connection_to_the_left =
10013  dst_shd_bnd_ids[ss];
10014  poly_to_connect_pt =
10015  boundary_polyline_pt(new_connection_to_the_left);
10016  if (poly_to_connect_pt != 0)
10017  {
10018  const unsigned shd_bnd_id_overlap =
10019  poly_to_connect_pt->boundary_id();
10020  error << "Shared boundary id("
10021  << shd_bnd_id_overlap << ")\n";
10022  const unsigned n_v = poly_to_connect_pt->nvertex();
10023  for (unsigned i = 0; i < n_v; i++)
10024  {
10025  Vector<double> cvertex =
10026  poly_to_connect_pt->vertex_coordinate(i);
10027  error
10028  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10029  <<cvertex[1]<<")\n";
10030  }
10031  } // if (poly_to_connect_pt != 0)
10032  } // for (ss < n_shd_bnd_overlap_int_bnd)
10033 
10034  throw OomphLibError(
10035  error.str(),
10036  "TriangleMesh::create_shared_polylines_connections()",
10037  OOMPH_EXCEPTION_LOCATION);
10038  } // if (!found_vertex_index)
10039 #endif
10040 
10041  // Create the connection, the left vertex of the current
10042  // shared boundary is connected with the vertex_index-th
10043  // vertex of sub_poly_to_connect-th subpolyline of the
10044  // destination boundary
10046  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10047 
10048  } // else if (!connecting_to_an_overlaped_boundary)
10049 
10050  } // else if (!connecting_to_an_split_boundary)
10051 
10052  } // if (connection_to_the_left != -1)
10053 
10054  // --------------------------------------------------------------
10055  // Connection to the right
10056  if (is_connected_to_the_right)
10057  {
10058  // Get the unsigned version of the bound id to connect to
10059  // the right
10060  const unsigned uconnection_to_the_right =
10061  shd_poly_pt->final_vertex_connected_bnd_id();
10062 
10063  // The pointer to the boundary to connect
10064  TriangleMeshPolyLine *poly_to_connect_pt = 0;
10065 
10066  // Flag to indicate we are trying to connect to an split
10067  // boundary
10068  bool connecting_to_an_split_boundary = false;
10069 
10070  // Flag to indicate we are trying to connecto to an internal
10071  // boundary that is overlaped by a shared boundary
10072  bool connecting_to_an_overlaped_boundary = false;
10073 
10074  // Check if the connection is with itself
10075  if (uconnection_to_the_right == bound_id)
10076  {
10077  // Set the pointer to the polyline to connect
10078  poly_to_connect_pt = shd_poly_pt;
10079  }
10080  else
10081  {
10082  // Get the initial shared boundary ids
10083  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10084  // Check if the boundary to connect is a shared polyline
10085  if (uconnection_to_the_right >= initial_shd_bnd_id)
10086  {
10087  // Get the polyline pointer representing the destination
10088  // boundary
10089  poly_to_connect_pt =
10090  boundary_polyline_pt(uconnection_to_the_right);
10091  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10092  else
10093  {
10094  // If we are going to connect to an original boundary
10095  // verify if the boundary was splitted during the
10096  // distribution process to consider all the chunks
10097  // (sub-polylines) of the boundary
10098  if (boundary_was_splitted(uconnection_to_the_right))
10099  {
10100  connecting_to_an_split_boundary = true;
10101  } // if (boundary_was_splitted(uconnection_to_the_right))
10102 
10103  // If we are going to connect to an original boundary
10104  // verify if the boundary, or any of its chunks is
10105  // marked to be overlapped by a shared boundary, if that
10106  // is the case we first check for connections in the
10107  // shared boundary that overlaps the internal boundary,
10108  // or the chunks, and then check for connections in the
10109  // original boundary
10110  if (connecting_to_an_split_boundary)
10111  {
10112  // Get the number of chucks that represent the
10113  // destination boundary
10114  const unsigned n_sub_poly =
10115  nboundary_subpolylines(uconnection_to_the_right);
10116  // Now loop over the chunks of the destination
10117  // boundary and if any of them is marked to be
10118  // overlaped by a shared boundary then set the flag
10119  // and break the loop
10120  for (unsigned ii =0; ii < n_sub_poly; ii++)
10121  {
10122  if (boundary_marked_as_shared_boundary(
10123  uconnection_to_the_right, ii))
10124  {
10125  // Mark the boundary as being overlaped by a
10126  // shared boundary
10127  connecting_to_an_overlaped_boundary = true;
10128  // Break, no need to look for more overlapings
10129  break;
10130  } // if (boundary_marked_as_shared_boundary(...))
10131  } // for (ii < n_sub_poly)
10132  } // if (connecting_to_an_split_boundary)
10133  else
10134  {
10135  // If not connecting to an split boundary then check
10136  // if the whole destination boundary is overlaped by
10137  // an internal boundary
10138  if (boundary_marked_as_shared_boundary(
10139  uconnection_to_the_right, 0))
10140  {
10141  // Mark the boundary as being overlaped by a shared
10142  // boundary
10143  connecting_to_an_overlaped_boundary = true;
10144  } // if (boundary_marked_as_shared_boundary(...))
10145  } // else if (connecting_to_an_split_boundary)
10146 
10147  // If we are connecting neither to an split boundary nor
10148  // an overlaped boundary then get the pointer to the
10149  // original boundary
10150  if (!(connecting_to_an_split_boundary ||
10151  connecting_to_an_overlaped_boundary))
10152  {
10153  // Get the polyline pointer representing the
10154  // destination boundary
10155  poly_to_connect_pt =
10156  boundary_polyline_pt(uconnection_to_the_right);
10157  } // else if (NOT split, NOT overlaped)
10158  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10159 
10160  } // else if (uconnection_to_the_right == bound_id)
10161 
10162 #ifdef PARANOID
10163  // If we are not connecting to an original boundary
10164  // (connecting to the same shared boundary or to another
10165  // shared boundary) then the boundary should not be marked
10166  // as split
10167  if (!connecting_to_an_split_boundary)
10168  {
10169  if (boundary_was_splitted(uconnection_to_the_right))
10170  {
10171  std::stringstream error;
10172  error
10173  << "The current shared boundary (" << bound_id << ") was "
10174  << "marked to have a connection\nto the right with the "
10175  << "boundary (" << uconnection_to_the_right << ").\n"
10176  << "The problem is that the destination boundary (possibly\n"
10177  << "another shared boundary) is marked to be split\n"
10178  << "There should not be split shared boundaries\n\n";
10179  throw OomphLibError(
10180  error.str(),
10181  "TriangleMesh::create_shared_polylines_connections()",
10182  OOMPH_EXCEPTION_LOCATION);
10183  }
10184  } // if (!connecting_to_an_split_boundary)
10185 #endif
10186 
10187  // Now look for the vertex number on the destination
10188  // boundary(ies) -- in case that the boundary was split ---
10189 
10190  // Do not check for same orientation, that was previously
10191  // worked by interchanging the connections boundaries (if
10192  // necessary)
10193 
10194  // Get the right vertex in the shared boundary
10195  Vector<double> shd_bnd_right_vertex =
10196  shd_poly_pt->vertex_coordinate(n_vertex-1);
10197 
10198  // If the boundary was not split then inmediately look for
10199  // the vertex index in the destination boundary
10200  if (!connecting_to_an_split_boundary)
10201  {
10202  // ... check if the boundary is marked to be overlaped by
10203  // a shared boundary
10204  if (!connecting_to_an_overlaped_boundary)
10205  {
10206  // If that is not the case then we can safely look for
10207  // the vertex number on the destination boundar
10208 
10209  unsigned vertex_index = 0;
10210  const bool found_vertex_index =
10211  get_connected_vertex_number_on_destination_polyline(
10212  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10213 
10214  // If we could not find the vertex index to connect then
10215  // we are in trouble
10216  if (!found_vertex_index)
10217  {
10218  std::stringstream error;
10219  error
10220  << "The current shared boundary (" << bound_id << ") was "
10221  << "marked to have a connection\nto the right with the "
10222  << "boundary (" << uconnection_to_the_right << ").\n"
10223  << "The problem is that the right vertex of the current\n"
10224  << "shared boundary is not in the list of vertices of the\n"
10225  << "boundary to connect.\n\n"
10226  << "This is the right vertex of the current shared boundary\n"
10227  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10228  << shd_bnd_right_vertex[1] << ")\n\n"
10229  << "This is the list of vertices on the destination boundary\n";
10230  const unsigned n_v = poly_to_connect_pt->nvertex();
10231  for (unsigned i = 0; i < n_v; i++)
10232  {
10233  Vector<double> cvertex =
10234  poly_to_connect_pt->vertex_coordinate(i);
10235  error
10236  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
10237  }
10238  throw OomphLibError(
10239  error.str(),
10240  "TriangleMesh::create_shared_polylines_connections()",
10241  OOMPH_EXCEPTION_LOCATION);
10242  } // if (!found_vertex_index)
10243 
10244  // Create the connection, the right vertex of the current
10245  // shared boundary is connected with the vertex_index-th
10246  // vertex on the destination boundary
10247  shd_poly_pt->connect_final_vertex_to_polyline(
10248  poly_to_connect_pt, vertex_index);
10249 
10250  } // if (!connecting_to_an_overlaped_boundary)
10251  else
10252  {
10253  // If the boundary is marked to be overlaped by a shared
10254  // boundary then get that shared boundary and look for
10255  // the connection in that boundary
10256 
10257  // The vertex where to store the index to connect
10258  unsigned vertex_index = 0;
10259  // A flag to indicate if the connection was found
10260  bool found_vertex_index = false;
10261 
10262  // Get the shared boundary id that is overlaping the
10263  // internal boundary
10264  Vector<unsigned> dst_shd_bnd_ids;
10265  get_shared_boundaries_overlapping_internal_boundary(
10266  uconnection_to_the_right, dst_shd_bnd_ids);
10267 
10268  // Get the number of shared polylines that were found to
10269  // overlap the internal boundary
10270  const unsigned n_shd_bnd_overlap_int_bnd =
10271  dst_shd_bnd_ids.size();
10272 
10273  // Loop over the shared boundaries that overlap the
10274  // internal boundary and look for the vertex to connect
10275  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10276  {
10277  // Get the shared polyline
10278  const unsigned new_connection_to_the_right =
10279  dst_shd_bnd_ids[ss];
10280 
10281  // Get the shared polyline that is overlaping the
10282  // internal boundary
10283  poly_to_connect_pt =
10284  boundary_polyline_pt(new_connection_to_the_right);
10285 
10286  if (poly_to_connect_pt!=0)
10287  {
10288  // Look for the vertex number in the destination
10289  // shared polyline
10290  found_vertex_index =
10291  get_connected_vertex_number_on_destination_polyline(
10292  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10293  } // if (poly_to_connect_pt!=0)
10294 
10295  // If we have found the vertex to connect then
10296  // break the loop
10297  if (found_vertex_index)
10298  {
10299  break;
10300  } // if (found_vertex_index)
10301 
10302  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10303 
10304 #ifdef PARANOID
10305  // If we could not find the vertex index to connect then
10306  // we are in trouble
10307  if (!found_vertex_index)
10308  {
10309  std::stringstream error;
10310  error
10311  << "The current shared boundary (" << bound_id << ") was "
10312  << "marked to have a connection\nto the right with the "
10313  << "boundary (" << uconnection_to_the_right << ").\n"
10314  << "This last boundary is marked to be overlaped by "
10315  << "shared boundaries\n"
10316  << "The problem is that the right vertex of the current\n"
10317  << "shared boundary is not in the list of vertices of the\n"
10318  << "boundary to connect.\n\n"
10319  << "This is the right vertex of the current shared boundary\n"
10320  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10321  << shd_bnd_right_vertex[1] << ")\n\n"
10322  << "This is the list of vertices on the destination "
10323  << "boundary\n";
10324  Vector<unsigned> dst_shd_bnd_ids;
10325  get_shared_boundaries_overlapping_internal_boundary(
10326  uconnection_to_the_right, dst_shd_bnd_ids);
10327  const unsigned n_shd_bnd_overlap_int_bnd =
10328  dst_shd_bnd_ids.size();
10329  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10330  {
10331  const unsigned new_connection_to_the_right =
10332  dst_shd_bnd_ids[ss];
10333  poly_to_connect_pt =
10334  boundary_polyline_pt(new_connection_to_the_right);
10335  if (poly_to_connect_pt != 0)
10336  {
10337  const unsigned shd_bnd_id_overlap =
10338  poly_to_connect_pt->boundary_id();
10339  error << "Shared boundary id("
10340  << shd_bnd_id_overlap << ")\n";
10341  const unsigned n_v = poly_to_connect_pt->nvertex();
10342  for (unsigned i = 0; i < n_v; i++)
10343  {
10344  Vector<double> cvertex =
10345  poly_to_connect_pt->vertex_coordinate(i);
10346  error
10347  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10348  <<cvertex[1]<<")\n";
10349  }
10350  } // if (poly_to_connect_pt != 0)
10351  } // for (ss < n_shd_bnd_overlap_int_bnd)
10352 
10353  throw OomphLibError(
10354  error.str(),
10355  "TriangleMesh::create_shared_polylines_connections()",
10356  OOMPH_EXCEPTION_LOCATION);
10357 
10358  } // if (!found_vertex_index)
10359 #endif
10360 
10361  // Create the connection, the right vertex of the
10362  // current shared boundary is connected with the
10363  // vertex_index-th vertex on the destination boundary
10364  shd_poly_pt->connect_final_vertex_to_polyline(
10365  poly_to_connect_pt, vertex_index);
10366 
10367  } // else if (!connecting_to_an_overlaped_boundary)
10368 
10369  } // if (!connecting_to_an_split_boundary)
10370  else
10371  {
10372  // If the boundary was split then we need to look for the
10373  // vertex in the sub-polylines
10374 
10375  // Get the sub-polylines vector
10376  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10377  boundary_subpolylines(uconnection_to_the_right);
10378 
10379  // Get the number of sub-polylines
10380  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10381 #ifdef PARANOID
10382  if (nsub_poly <= 1)
10383  {
10384  std::ostringstream error_message;
10385  error_message
10386  <<"The boundary (" << uconnection_to_the_right << ") was "
10387  << "marked to be splitted but\n"
10388  << "there are only ("<<nsub_poly<<") polylines to "
10389  << "represent it.\n";
10390  throw OomphLibError(
10391  error_message.str(),
10392  "TriangleMesh::create_shared_polylines_connections()",
10393  OOMPH_EXCEPTION_LOCATION);
10394  } // if (nsub_poly <= 1)
10395 #endif
10396 
10397  // We need to check if the boundary is marked to be
10398  // overlaped by an internal boundary, if that is the case
10399  // we need to check for each indivual subpolyline, and for
10400  // those overlaped by a shared polyline look for the
10401  // vertex in the shared polyline representation instead of
10402  // the original subpolyline
10403 
10404  // ... check if the boundary is marked to be overlaped by
10405  // a shared boundary
10406  if (!connecting_to_an_overlaped_boundary)
10407  {
10408  // We can work without checking the subpolylines
10409  // individually
10410 
10411  // The vertex where to store the index to connect
10412  unsigned vertex_index = 0;
10413  // The subpoly number to connect
10414  unsigned sub_poly_to_connect = 0;
10415  // A flag to indicate if the connection was found
10416  bool found_vertex_index = false;
10417 
10418  // Look for the vertex number to connect on each of the
10419  // subpolyines
10420  for (unsigned isub = 0; isub < nsub_poly; isub++)
10421  {
10422  // Assign the pointer to the sub-polyline
10423  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10424  // Search for the vertex in the current sub-polyline
10425  found_vertex_index =
10426  get_connected_vertex_number_on_destination_polyline(
10427  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10428  // If we have found the vertex to connect then break the
10429  // loop
10430  if (found_vertex_index)
10431  {
10432  // But first save the subpoly number (chunk), that
10433  // will be used to perform the connection
10434  sub_poly_to_connect = isub;
10435  break;
10436  } // if (found_vertex_index)
10437  } // for (isub < nsub_poly)
10438 
10439 #ifdef PARANOID
10440  // If we could not find the vertex index to connect then
10441  // we are in trouble
10442  if (!found_vertex_index)
10443  {
10444  std::stringstream error;
10445  error
10446  << "The current shared boundary (" << bound_id << ") was "
10447  << "marked to have a connection\nto the right with the "
10448  << "boundary (" << uconnection_to_the_right << ").\n"
10449  << "The problem is that the right vertex of the current\n"
10450  << "shared boundary is not in the list of vertices of any\n"
10451  << "of the sub polylines that represent the boundary to\n"
10452  << "connect.\n\n"
10453  << "This is the right vertex of the current shared boundary\n"
10454  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10455  << shd_bnd_right_vertex[1] << ")\n\n"
10456  << "This is the list of vertices on the destination "
10457  << "boundary\n";
10458  for (unsigned p = 0; p < nsub_poly; p++)
10459  {
10460  error << "Subpolyline #("<< p << ")\n";
10461  poly_to_connect_pt = tmp_vector_subpolylines[p];
10462  const unsigned n_v = poly_to_connect_pt->nvertex();
10463  for (unsigned i = 0; i < n_v; i++)
10464  {
10465  Vector<double> cvertex =
10466  poly_to_connect_pt->vertex_coordinate(i);
10467  error
10468  <<"Vertex #"<<i<<": ("<<cvertex[0]
10469  <<", "<<cvertex[1]<<")\n";
10470  }
10471  } // for (p < nsub_poly)
10472  throw OomphLibError(
10473  error.str(),
10474  "TriangleMesh::create_shared_polylines_connections()",
10475  OOMPH_EXCEPTION_LOCATION);
10476  } // if (!found_vertex_index)
10477 #endif
10478 
10479  // Create the connection, the right vertex of the current
10480  // shared boundary is connected with the vertex_index-th
10481  // vertex of sub_poly_to_connect-th subpolyline of the
10482  // destination boundary
10483  shd_poly_pt->connect_final_vertex_to_polyline(
10484  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10485 
10486  } // if (!connecting_to_an_overlaped_boundary)
10487  else
10488  {
10489  // We first look on the shared boundaries that overlap
10490  // the internal boundaries and the look for the
10491  // sub-polylines that are not marked as being overlaped
10492  // by shared boundaries
10493 
10494  // The vertex where to store the index to connect
10495  unsigned vertex_index = 0;
10496  // The subpoly number to connect
10497  unsigned sub_poly_to_connect = 0;
10498  // A flag to indicate if the connection was found
10499  bool found_vertex_index = false;
10500 
10501  // Get the shared boundaries id that are overlaping the
10502  // internal boundary
10503  Vector<unsigned> dst_shd_bnd_ids;
10504  get_shared_boundaries_overlapping_internal_boundary(
10505  uconnection_to_the_right, dst_shd_bnd_ids);
10506 
10507  // Get the number of shared polylines that were found to
10508  // overlap the internal boundary
10509  const unsigned n_shd_bnd_overlap_int_bnd =
10510  dst_shd_bnd_ids.size();
10511 
10512  // Loop over the shared boundaries that overlap the
10513  // internal boundary and look for the vertex to connect
10514  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10515  {
10516  // Get the shared polyline
10517  const unsigned new_connection_to_the_right =
10518  dst_shd_bnd_ids[ss];
10519 
10520  // Make sure that the destination polyline is not the
10521  // same as the current shared polyline
10522  if (bound_id != new_connection_to_the_right)
10523  {
10524  // Get the shared polyline that is overlaping the
10525  // internal boundary
10526  poly_to_connect_pt =
10527  boundary_polyline_pt(new_connection_to_the_right);
10528 
10529  if (poly_to_connect_pt != 0)
10530  {
10531  // Look for the vertex number in the destination
10532  // shared polyline
10533  found_vertex_index =
10534  get_connected_vertex_number_on_destination_polyline(
10535  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10536  } // if (poly_to_connect_pt != 0)
10537 
10538  // If we have found the vertex to connect then
10539  // break the loop
10540  if (found_vertex_index)
10541  {
10542  break;
10543  } // if (found_vertex_index)
10544 
10545  } // if (bound_id != new_connection_to_the_right)
10546 
10547  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10548 
10549  // If we have not yet found the vertex then look for it
10550  // in the sub-polylines that are not overlaped by shared
10551  // boundaries
10552  if (!found_vertex_index)
10553  {
10554  // Look for the vertex number to connect on each of
10555  // the subpolyines
10556  for (unsigned isub = 0; isub < nsub_poly; isub++)
10557  {
10558  // Only work with those sub-polylines that are not
10559  // overlaped by shared boundaries
10560  if (!boundary_marked_as_shared_boundary(
10561  uconnection_to_the_right, isub))
10562  {
10563  // Assign the pointer to the sub-polyline
10564  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10565  // Search for the vertex in the current sub-polyline
10566  found_vertex_index =
10567  get_connected_vertex_number_on_destination_polyline(
10568  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10569  // If we have found the vertex to connect then break the
10570  // loop
10571  if (found_vertex_index)
10572  {
10573  // But first save the subpoly number (chunk), that
10574  // will be used to perform the connection
10575  sub_poly_to_connect = isub;
10576  break;
10577  } // if (found_vertex_index)
10578 
10579  } // if (not overlaped by shared boundary)
10580 
10581  } // for (isub < nsub_poly)
10582 
10583  } // if (!found_vertex_index)
10584 
10585 #ifdef PARANOID
10586  // If we could not find the vertex index to connect then
10587  // we are in trouble
10588  if (!found_vertex_index)
10589  {
10590  std::stringstream error;
10591  error
10592  << "The current shared boundary (" << bound_id << ") was "
10593  << "marked to have a connection\nto the right with the "
10594  << "boundary (" << uconnection_to_the_right << ").\n"
10595  << "This last boundary is marked to be overlaped by "
10596  << "shared boundaries\n"
10597  << "The problem is that the right vertex of the current\n"
10598  << "shared boundary is not in the list of vertices of "
10599  << "the\nboundary to connect.\n\n"
10600  << "This is the right vertex of the current shared "
10601  << "boundary\n"
10602  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10603  << shd_bnd_right_vertex[1] << ")\n\n"
10604  << "This is the list of vertices on the destination "
10605  << "boundary (only those subpolylines not marked as "
10606  << "overlaped by\nshared boundaries)\n";
10607  for (unsigned p = 0; p < nsub_poly; p++)
10608  {
10609  if (!boundary_marked_as_shared_boundary(
10610  uconnection_to_the_right, p))
10611  {
10612  error << "Subpolyline #("<< p << ")\n";
10613  poly_to_connect_pt = tmp_vector_subpolylines[p];
10614  const unsigned n_v = poly_to_connect_pt->nvertex();
10615  for (unsigned i = 0; i < n_v; i++)
10616  {
10617  Vector<double> cvertex =
10618  poly_to_connect_pt->vertex_coordinate(i);
10619  error
10620  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10621  <<cvertex[1]<<")\n";
10622  }
10623  } // Not marked as overlaped
10624  } // for (p < nsub_poly)
10625  error << "\nThis is the list of vertices of the shared "
10626  << "polylines that overlap\nthe internal "
10627  << "boundary\n";
10628  Vector<unsigned> dst_shd_bnd_ids;
10629  get_shared_boundaries_overlapping_internal_boundary(
10630  uconnection_to_the_right, dst_shd_bnd_ids);
10631  const unsigned n_shd_bnd_overlap_int_bnd =
10632  dst_shd_bnd_ids.size();
10633  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10634  {
10635  const unsigned new_connection_to_the_right =
10636  dst_shd_bnd_ids[ss];
10637  poly_to_connect_pt =
10638  boundary_polyline_pt(new_connection_to_the_right);
10639  if (poly_to_connect_pt != 0)
10640  {
10641  const unsigned shd_bnd_id_overlap =
10642  poly_to_connect_pt->boundary_id();
10643  error << "Shared boundary id("
10644  << shd_bnd_id_overlap << ")\n";
10645  const unsigned n_v = poly_to_connect_pt->nvertex();
10646  for (unsigned i = 0; i < n_v; i++)
10647  {
10648  Vector<double> cvertex =
10649  poly_to_connect_pt->vertex_coordinate(i);
10650  error
10651  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10652  <<cvertex[1]<<")\n";
10653  }
10654  } // if (poly_to_connect_pt != 0)
10655  } // for (ss < n_shd_bnd_overlap_int_bnd)
10656 
10657  throw OomphLibError(
10658  error.str(),
10659  "TriangleMesh::create_shared_polylines_connections()",
10660  OOMPH_EXCEPTION_LOCATION);
10661  } // if (!found_vertex_index)
10662 #endif
10663 
10664  // Create the connection, the left vertex of the current
10665  // shared boundary is connected with the vertex_index-th
10666  // vertex of sub_poly_to_connect-th subpolyline of the
10667  // destination boundary
10668  shd_poly_pt->connect_final_vertex_to_polyline(
10669  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10670 
10671  } // else if (!connecting_to_an_overlaped_boundary)
10672 
10673  } // else if (!connecting_to_an_split_boundary)
10674 
10675  } // if (connection_to_the_right != -1)
10676 
10677  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10678 
10679  } // for (ipoly < npoly)
10680 
10681  } // for (icurve < ncurves)
10682 
10683  }
10684 
10685  //=======================================================================
10686  // \short Compute the holes left by the halo elements, those adjacent
10687  // to the shared boundaries
10688  //=======================================================================
10689  template<class ELEMENT>
10691  Vector<Vector<double> > &output_holes_coordinates)
10692  {
10693  // Storage for number of processors and current processor
10694  const unsigned n_proc = this->communicator_pt()->nproc();
10695  const unsigned my_rank = this->communicator_pt()->my_rank();
10696 
10697  // Mark those done elements, so we do not repeat any coordinate left
10698  // by repeated halo elements
10699  std::map<FiniteElement*, bool> done_ele;
10700 
10701  // Loop over the processors and get the shared boundaries ids that
10702  // the current processor has with the other processors
10703  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10704  {
10705  // There are shared boundaries only with the other processors
10706  if (iproc != my_rank)
10707  {
10708  // Get the number of shared boundaries with the iproc
10709  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10710 
10711 #ifdef PARANOID
10712  // Get the number of shared boundaries with the iproc, but
10713  // reversing the indexes
10714  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10715  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10716  {
10717  std::ostringstream error_stream;
10718  error_stream
10719  << "The number of shared boundaries of processor ("
10720  << my_rank << ") with processor(" << iproc << "): ("
10721  << n_shd_bnd_iproc << ")\n"
10722  << "is different from the number of shared boundaries of "
10723  << "processor (" << iproc << ")\nwith processor ("
10724  << my_rank << "): (" << n_shd_bnd_iproc << ")\n\n";
10725  throw OomphLibError(error_stream.str(),
10726  OOMPH_CURRENT_FUNCTION,
10727  OOMPH_EXCEPTION_LOCATION);
10728 
10729  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10730 #endif
10731 
10732  // Loop over the shared boundaries ids
10733  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10734  {
10735  // Get the shared boundary id
10736  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10737 
10738  // Get the number of shared boundary elements
10739  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10740 
10741  // Loop over the shared boundary elements
10742  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10743  {
10744  // Get the shared boundary element
10745  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10746 
10747  // Only work with halo elements
10748  if (ele_pt->is_halo())
10749  {
10750  // If the element has not been visited
10751  if (!done_ele[ele_pt])
10752  {
10753  // Get the number of nodes
10754  const unsigned n_nodes = ele_pt->nnode();
10755 
10756  // Compute the centroid of the element
10757  Vector<double> element_centroid(2, 0.0);
10758  // Loop over the nodes
10759  for (unsigned k = 0; k < n_nodes; k++)
10760  {
10761  Node* tmp_node_pt = ele_pt->node_pt(k);
10762  // Loop over the dimension
10763  for (unsigned d = 0; d < 2; d++)
10764  {
10765  element_centroid[d]+=tmp_node_pt->x(d);
10766  } // for (d < 2)
10767  } // for (k < n_nodes)
10768 
10769  // Average the data
10770  for (unsigned d = 0; d < 2; d++)
10771  {
10772  element_centroid[d] =
10773  element_centroid[d] / (double)n_nodes;
10774  } // for (d < 2)
10775 
10776  // Add the centroid to the output holes
10777  output_holes_coordinates.push_back(element_centroid);
10778 
10779  } // if (!done_ele[ele_pt])
10780 
10781  } // if (ele_pt->is_halo())
10782 
10783  } // for1 (e < n_shd_bnd_ele)
10784 
10785  } // for (i < n_shd_bnd_iproc)
10786 
10787  } // if (iproc != my_rank)
10788 
10789  } // for (iproc < n_proc)
10790 
10791  }
10792 
10793  //======================================================================
10794  // \short Keeps those vertices that define a hole, those that are
10795  // inside closed internal boundaries in the new polygons that define
10796  // the domain. Delete those outside/inside the outer polygons (this
10797  // is required since Triangle can not deal with vertices that define
10798  // holes outside the new outer polygons of the domain)
10799  //======================================================================
10800  template<class ELEMENT>
10802  Vector<TriangleMeshPolygon *> &polygons_pt,
10803  Vector<Vector<double> > &output_holes_coordinates)
10804  {
10805  // General strategy
10806 
10807  // 1) Identify the inner closed boundaries
10808 
10809  // 2) Separate the vertices in three groups
10810 
10811  // --- 2.1) The vertices inside the inner closed boundaries, these
10812  // are not deleted because they define holes
10813 
10814  // --- 2.2) The vertices outside the outer boundaries, these are
10815  // deleted only if they are outside the convex hull defined
10816  // by all the polygons
10817 
10818  // --- 2.3) Any other vertex is deleted
10819 
10820  // Get the number of input holes
10821  const unsigned n_input_holes = output_holes_coordinates.size();
10822 
10823  // Only do something if there are holes
10824  if (n_input_holes == 0)
10825  {
10826  return;
10827  }
10828 
10829  // Get the number of input polygons
10830  const unsigned n_polygons = polygons_pt.size();
10831 
10832  // Store the vertices of all the input polygons
10833  // vertices_polygons[x][ ][ ]: Polygon number
10834  // vertices_polygons[ ][x][ ]: Vertex number
10835  // vertices_polygons[ ][ ][x]: Vertex coordinate
10836  Vector<Vector<Vector<double> > > vertices_polygons(n_polygons);
10837 
10838  // Loop over all the polygons and get the vertices
10839  for (unsigned p = 0; p < n_polygons; p++)
10840  {
10841  // Get the number of polylines associated to the polygon
10842  const unsigned n_polylines = polygons_pt[p]->npolyline();
10843  // Loop over the polylines and get the vertices
10844  for (unsigned pp = 0; pp < n_polylines; pp++)
10845  {
10846  // Get the polyline
10847  const TriangleMeshPolyLine* tmp_poly_pt =
10848  polygons_pt[p]->polyline_pt(pp);
10849  // Get the number of vertices in the polyline
10850  const unsigned n_vertices = tmp_poly_pt->nvertex();
10851  // Loop over the vertices but only add (n_vertices-1) vertices,
10852  // the last vertex of polyline (pp) is the first vertex of
10853  // polyline (pp+1)
10854  for (unsigned v = 0; v < n_vertices-1; v++)
10855  {
10856  // Get the current vertex
10857  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10858  vertices_polygons[p].push_back(current_vertex);
10859  } // for (v < nvertex)
10860  } // for (p < nouter_polylines)
10861  } // for (p < n_polygons)
10862 
10863  // -------------------------------------------------------------------
10864  // 1) Identify the inner closed boundaries
10865  // -------------------------------------------------------------------
10866 
10867  // A container that indicates if a given polygon should be
10868  // considered as an outer or as an inner polygon. By default all the
10869  // polygons are considered as outer polygons
10870  std::vector<bool> is_outer_polygon(n_polygons, true);
10871 
10872  // We only check for innner polygons if there are more than one
10873  // polygon
10874  if (n_polygons > 1)
10875  {
10876  // Propose an inner polygon, if one of the middle points of its
10877  // edges lies inside any other polygon then the proposed inner
10878  // polygon is marked as an internal polygon
10879 
10880  // Pre-compute the middle points of the edges in the polygons
10881  Vector<Vector<Vector<double> > > polygon_edge_middle_vertex(n_polygons);
10882 
10883  for (unsigned p = 0; p < n_polygons; p++)
10884  {
10885  // Temporary store the vertices of the proposed inner polygon
10886  Vector<Vector<double> > tmp_inner_polygon = vertices_polygons[p];
10887 
10888  // Get the number of vertices in the current proposed inner polygon
10889  const unsigned n_vertices = tmp_inner_polygon.size();
10890 
10891  // Resize with the number of edges in the polygon
10892  polygon_edge_middle_vertex[p].resize(n_vertices-1);
10893 
10894  // Loop over the vertices and compute the middle point in the edge
10895  // that joins each pair of contiguous vertices
10896  for (unsigned e = 0; e < n_vertices - 1; e++)
10897  {
10898  // The dimension
10899  const unsigned dim = 2;
10900  polygon_edge_middle_vertex[p][e].resize(dim);
10901  for (unsigned d = 0; d < dim; d++)
10902  {
10903  polygon_edge_middle_vertex[p][e][d] =
10904  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e+1][d]) / 2.0;
10905  } // for (d < 2)
10906 
10907  } // for (e < n_vertices - 1)
10908 
10909  } // for (p < n_polygons)
10910 
10911  // Loop over the polygons and for every loop propose a different
10912  // inner polygon
10913  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
10914  {
10915  // Flag to indicate that ONE of the middle edge vertices of the
10916  // proposed inner polygon is inside another polygon, this will
10917  // set the proposed inner polygon as an actual inner polygon
10918  bool is_inner_polygon = false;
10919 
10920  // Loop over all the polygons, except the proposed one and check
10921  // if all the middle edges of its edges are inside any other
10922  // polygon
10923  for (unsigned i = 0; i < n_polygons; i++)
10924  {
10925  // Do not check with the polygon itself
10926  if (i != idx_inner)
10927  {
10928  // Get the number of edges of the proposed inner polygon
10929  const unsigned n_edges =
10930  polygon_edge_middle_vertex[idx_inner].size();
10931  // Loop over the middle points in the edges of the current
10932  // proposed inner polygon
10933  for (unsigned e = 0; e < n_edges; e++)
10934  {
10935  // Get the vertex in the current proposed inner polygon
10936  Vector<double> current_vertex =
10937  polygon_edge_middle_vertex[idx_inner][e];
10938  // Check if the current vertex is inside the current i-th
10939  // polygon
10940  const bool is_point_inside =
10941  is_point_inside_polygon_helper(vertices_polygons[i],
10942  current_vertex);
10943 
10944  // If one point is inside then the polygon is inside the
10945  // i-th polygon
10946  if (is_point_inside)
10947  {
10948  // The polygon is an inner polygon
10949  is_inner_polygon = true;
10950  // Break the loop
10951  break;
10952  } // if (is_point_inside)
10953 
10954  } // for (e < n_edges)
10955 
10956  } // if (i != idx_inner)
10957 
10958  // Are all the vertices of the current proposed inner polygon
10959  // inside the i-th polygon
10960  if (is_inner_polygon)
10961  {
10962  // The current proposed inner polygon is an actual inner
10963  // polygon, and is inside the i-th polygon
10964  break;
10965  }
10966 
10967  } // for (i < n_polygons)
10968 
10969  // Is the current proposed inner polygon an actual inner polygon
10970  if (is_inner_polygon)
10971  {
10972  // The current proposed inner polygon is a real inner polygon
10973  is_outer_polygon[idx_inner] = false;
10974  }
10975  else
10976  {
10977  // The current proposed inner polygon IS NOT a real inner
10978  // polygon
10979  is_outer_polygon[idx_inner] = true;
10980  }
10981 
10982  } // for (idx_outer < npolygons)
10983 
10984  } // if (n_polygons > 1)
10985 
10986  // Count the number of outer closed boundaries and inner closed
10987  // boundaries
10988  unsigned n_outer_polygons = 0;
10989  unsigned n_inner_polygons = 0;
10990  // Also get the indexes of the inner polygons
10991  Vector<unsigned> index_inner_polygon;
10992  // Loop over the polygons
10993  for (unsigned i = 0; i < n_polygons; i++)
10994  {
10995  if (is_outer_polygon[i])
10996  {
10997  // Increase the counter for outer polygons
10998  n_outer_polygons++;
10999  }
11000  else
11001  {
11002  // Increase the counter for inner polygons
11003  n_inner_polygons++;
11004  // Store the index of the inner polygon
11005  index_inner_polygon.push_back(i);
11006  }
11007  } // for (i < n_polygons)
11008 
11009  // -------------------------------------------------------------------
11010  // 2) Separate the vertices in three groups
11011 
11012  // --- 2.1) The vertices inside the inner closed boundaries, these are
11013  // not deleted because they define holes
11014 
11015  // --- 2.2) The vertices outside the outer boundaries, these are
11016  // deleted only if they are outside the convex hull defined
11017  // by all the polygons
11018 
11019  // --- 2.3) Any other vertex is deleted
11020  // -------------------------------------------------------------------
11021 
11022  // Keep track of the vertices inside the inner closed boundaries (by
11023  // default all vertices not inside the inner polygons)
11024  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11025 
11026  // Keep track of the vertices outside the outer closed boundaries
11027  // (by default all the vertices are outside the outer polygons)
11028  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11029 
11030  // Keep track of the vertices inside the convex hull (by default
11031  // all the vertices are not inside the convex hull)
11032  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11033 
11034  // Mark the vertices inside the inner closed boundaries
11036  vertex_inside_inner_polygon(n_inner_polygons);
11037 
11038  // -------------------------------------------------------------------
11039  // Loop over the inner polygons and find all the vertices inside
11040  // each one
11041  for (unsigned i = 0; i < n_inner_polygons; i++)
11042  {
11043  // Get the vertex of the inner polygon
11044  const unsigned ii = index_inner_polygon[i];
11045  // Loop over the vertices defining holes, mark and store those
11046  // inside the inner polygon
11047  for (unsigned h = 0; h < n_input_holes; h++)
11048  {
11049  // Check if the vertex has not been already marked as inside
11050  // another polygon
11051  if (!is_inside_an_inner_polygon[h])
11052  {
11053  // Check if the hole is inside the current inner polygon
11054  const bool is_inside_polygon =
11055  is_point_inside_polygon_helper(vertices_polygons[ii],
11056  output_holes_coordinates[h]);
11057 
11058  // If the vertex is inside the current inner polygon then mark
11059  // it and associate the vertices to the current inner polygon
11060  if (is_inside_polygon)
11061  {
11062  // Set as inside an inner polygon
11063  is_inside_an_inner_polygon[h] = true;
11064  // Associate the vertex to the current inner polygon
11065  vertex_inside_inner_polygon[i].
11066  push_back(output_holes_coordinates[h]);
11067  } // if (is_inside_polygon)
11068 
11069  } // if (!is_inside_an_inner_polygon[h])
11070 
11071  } // for (h < n_input_holes)
11072 
11073  } // for (i < n_polygons)
11074 
11075  // -------------------------------------------------------------------
11076  // Loop over the vertices defining holes and mark those as outside the
11077  // outer polygons
11078  for (unsigned h = 0; h < n_input_holes; h++)
11079  {
11080  // Check if the vertex has not been already marked as inside
11081  // another polygon
11082  if (!is_inside_an_inner_polygon[h])
11083  {
11084  // Loop over the polygons and check if the vertex is outside ALL
11085  // the outer polygons
11086  for (unsigned i = 0; i < n_polygons; i++)
11087  {
11088  // Only work with outer polygons
11089  if (is_outer_polygon[i])
11090  {
11091  // Check if the hole is inside the current outer polygon
11092  const bool is_inside_polygon =
11093  is_point_inside_polygon_helper(vertices_polygons[i],
11094  output_holes_coordinates[h]);
11095 
11096  // If the vertex is inside the current outer polygon then
11097  // mark it and break the loop (it is not outside ALL the
11098  // polygons)
11099  if (is_inside_polygon)
11100  {
11101  // Set as inside an outer polygon
11102  is_outside_the_outer_polygons[h] = false;
11103  // Break the loop
11104  break;
11105  } // if (is_inside_polygon)
11106 
11107  } // if (is_outer_polygon[i])
11108 
11109  } // for (i < n_polygons)
11110 
11111  } // if (!is_inside_an_inner_polygon[h])
11112  else
11113  {
11114  // If the vertex is inside an inner polygon then it is inside an
11115  // outer polygon
11116  is_outside_the_outer_polygons[h] = false;
11117  } // else if (!is_inside_an_inner_polygon[h])
11118 
11119  } // for (h < n_input_holes)
11120 
11121  // -------------------------------------------------------------------
11122  // Compute the convex hull Create the data structure
11123  std::vector<Point> input_vertices_convex_hull;
11124  // Copy ALL the vertices of the polygons
11125  // Loop over the polygons
11126  for (unsigned p = 0; p < n_polygons; p++)
11127  {
11128  // Get the number of vertices
11129  const unsigned n_vertices = vertices_polygons[p].size();
11130  // Loop over the vertices in the polygon
11131  for (unsigned v = 0; v < n_vertices; v++)
11132  {
11133  // Create a new "Point" to store in the input vertices
11134  Point point;
11135  // Assign the values to the "Point"
11136  point.x = vertices_polygons[p][v][0];
11137  point.y = vertices_polygons[p][v][1];
11138  // Add the "Point" to the input vertices
11139  input_vertices_convex_hull.push_back(point);
11140  } // for (v < n_vertices)
11141  } // for (p < n_polygons)
11142 
11143  // Compute the convex hull
11144  std::vector<Point> output_vertices_convex_hull =
11145  convex_hull(input_vertices_convex_hull);
11146 
11147  // Get the number of vertices in the convex hull
11148  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11149 
11150  // Copy the output to the used data structures
11151  Vector<Vector<double> > vertices_convex_hull(n_vertices_convex_hull);
11152  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11153  {
11154  // Resize the data structure
11155  vertices_convex_hull[i].resize(2);
11156  // Copy the data
11157  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11158  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11159  } // for (i < n_vertices_convex_hull)
11160 
11161  // Loop over the vertices defining holes, work only with those
11162  // outside ALL the outer boundaries and mark those inside the convex
11163  // hull
11164  for (unsigned h = 0; h < n_input_holes; h++)
11165  {
11166  // Only work with those outside ALL the outer polygons
11167  if (is_outside_the_outer_polygons[h])
11168  {
11169  // Check if the hole is inside the convex hull
11170  const bool is_inside_convex_hull =
11171  is_point_inside_polygon_helper(vertices_convex_hull,
11172  output_holes_coordinates[h]);
11173 
11174  // If the vertex is inside the convex hull then mark it
11175  if (is_inside_convex_hull)
11176  {
11177  // Set as inside the convex hull
11178  is_inside_the_convex_hull[h] = true;
11179  } // if (is_inside_convex_hull)
11180 
11181  } // if (is_outside_the_outer_polygons[h])
11182  else
11183  {
11184  // Any vertex inside any outer polygon is inside the convex hull
11185  is_inside_the_convex_hull[h] = true;
11186  } // else if (is_outside_the_outer_polygons[h])
11187 
11188  } // for (h < n_input_holes)
11189 
11190  // Store the output holes, only (those inside an inner polygon) OR
11191  // (those outside ALL the polygons AND inside the convex hull)
11192  Vector<Vector<double> > hole_kept;
11193  for (unsigned h = 0; h < n_input_holes; h++)
11194  {
11195  // Check if the hole should be kept
11196  if ((is_inside_an_inner_polygon[h]) ||
11197  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11198  {
11199  // Copy the hole information
11200  hole_kept.push_back(output_holes_coordinates[h]);
11201  } // if (keep_hole[h])
11202  } // for (h < n_input_holes)
11203 
11204  // Clear the previous storage
11205  output_holes_coordinates.clear();
11206  // Set the output holes
11207  output_holes_coordinates = hole_kept;
11208 
11209  }
11210 
11211  //======================================================================
11212  // \short Sorts the polylines so they be contiguous and then we can
11213  // create a closed or open curve from them
11214  //======================================================================
11215  template<class ELEMENT>
11218  &unsorted_polylines_pt,
11220  &sorted_polylines_pt)
11221  {
11222  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11223  unsigned n_sorted_polylines = 0;
11224  unsigned curves_index = 0;
11225 
11226  // Map to know which polyline has been already sorted
11227  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11228 
11229  do
11230  {
11231  // Create the list that stores the polylines and allows to introduce
11232  // polylines to the left and to the right
11233  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11234  bool changes = false;
11235 
11236  // Create pointers to the left and right "side" of the sorted list of
11237  // new created TriangleMeshPolyLines
11238  TriangleMeshPolyLine* left_pt = 0;
11239  TriangleMeshPolyLine* right_pt = 0;
11240 
11241  // 1) Take the first non done polyline on the unsorted list of polylines
11242  unsigned pp = 0;
11243  bool found_root_polyline = false;
11244  while (pp < n_unsorted_polylines && !found_root_polyline)
11245  {
11246  if (!done_polyline[unsorted_polylines_pt[pp]])
11247  {found_root_polyline = true;}
11248  else
11249  {pp++;}
11250  }
11251 
11252  // Check if there are polylines to be sorted
11253  if (pp < n_unsorted_polylines)
11254  {
11255  // 2) Mark the polyline as done
11256  left_pt = right_pt = unsorted_polylines_pt[pp];
11257  done_polyline[left_pt] = true;
11258  // Increment the number of sorted polylines
11259  n_sorted_polylines++;
11260 
11261  // 3) Add this polyline to the sorted list and use it as root
11262  // to sort the other polylines
11263  sorted_polyline_list_pt.push_back(left_pt);
11264 
11265  do {
11266 
11267  changes = false;
11268 
11269  Vector<double> left_vertex(2);
11270  Vector<double> right_vertex(2);
11271 
11272  left_pt->initial_vertex_coordinate(left_vertex);
11273  right_pt->final_vertex_coordinate(right_vertex);
11274 
11275  for (unsigned i = pp+1; i < n_unsorted_polylines; i++)
11276  {
11277  TriangleMeshPolyLine *current_polyline_pt =
11278  unsorted_polylines_pt[i];
11279  if (!done_polyline[current_polyline_pt])
11280  {
11281  Vector<double> initial_vertex(2);
11282  Vector<double> final_vertex(2);
11283  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11284  current_polyline_pt->final_vertex_coordinate(final_vertex);
11285 
11286  // Compare if the current polyline should go to the left or
11287  // to the right on the sorted polyline list
11288 
11289  // Go to the left
11290  if (left_vertex == final_vertex)
11291  {
11292  left_pt = current_polyline_pt;
11293  sorted_polyline_list_pt.push_front(left_pt);
11294  done_polyline[left_pt] = true;
11295  n_sorted_polylines++;
11296 
11297  // We have added one more polyline, go for another round
11298  changes = true;
11299  }
11300  // Go to the right
11301  else if (right_vertex == initial_vertex)
11302  {
11303  right_pt = current_polyline_pt;
11304  sorted_polyline_list_pt.push_back(right_pt);
11305  done_polyline[right_pt] = true;
11306  n_sorted_polylines++;
11307 
11308  // We have added one more polyline, go for another round
11309  changes = true;
11310  }
11311  // Go to the left but it is reversed
11312  else if (left_vertex == initial_vertex)
11313  {
11314  current_polyline_pt->reverse();
11315  left_pt = current_polyline_pt;
11316  sorted_polyline_list_pt.push_front(left_pt);
11317  done_polyline[left_pt] = true;
11318  n_sorted_polylines++;
11319 
11320  // We have added one more polyline, go for another round
11321  changes = true;
11322  }
11323  // Go to the right but it is reversed
11324  else if (right_vertex == final_vertex)
11325  {
11326  current_polyline_pt->reverse();
11327  right_pt = current_polyline_pt;
11328  sorted_polyline_list_pt.push_back(right_pt);
11329  done_polyline[right_pt] = true;
11330  n_sorted_polylines++;
11331 
11332  // We have added one more polyline, go for another round
11333  changes = true;
11334  }
11335  } // if (!done_polyline[current_polyline_pt])
11336  if (changes) {break;}
11337  } // for (i < n_unsorted_polylines)
11338  }while(changes);
11339 
11340  } // if (pp < n_unsorted_polylines)
11341  else
11342  {
11343  // All the polylines are now on the sorted list of polylines
11344 #ifdef PARANOID
11345  // This case comes when it was not possible to find a root polyline
11346  // since all of them are marked as done but the number of sorted and
11347  // unsorted polylines is not the same
11348  if (!found_root_polyline)
11349  {
11350  std::stringstream err;
11351  err << "It was not possible to find a root polyline to sort the "
11352  << "others around it.\nThe number of unsorted and sorted "
11353  << "polylines is different, it means that\nnot all the "
11354  << "polylines have been sorted.\n"
11355  << "Found root polyline: ("<<found_root_polyline<<")\n"
11356  << "Sorted polylines: ("<<n_sorted_polylines<<")\n"
11357  << "Unsorted polylines: ("<<n_unsorted_polylines<<")\n";
11358  throw OomphLibError(err.str(),"TriangleMesh::sort_polylines_helper()",
11359  OOMPH_EXCEPTION_LOCATION);
11360  }
11361 #endif
11362  }
11363 
11364  // Create the storage for the new sorted polylines and copy them on the
11365  // vector structure for sorted polylines
11366  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11367 
11368  // Create the temporal vector that stores the sorted polylines
11370  tmp_sorted_polylines(n_sorted_polyline_on_list);
11371  unsigned counter = 0;
11372 
11373  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11374  for (it_polyline = sorted_polyline_list_pt.begin();
11375  it_polyline != sorted_polyline_list_pt.end();
11376  it_polyline++)
11377  {
11378  tmp_sorted_polylines[counter] = *it_polyline;
11379  counter++;
11380  }
11381 
11382  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11383 
11384  ++curves_index;
11385 
11386  }while(n_sorted_polylines < n_unsorted_polylines);
11387 
11388 #ifdef PARANOID
11389  // Verify that the number of polylines on the sorted list is the same
11390  // as the number of polylines on the unsorted list
11391  if (n_sorted_polylines != n_unsorted_polylines)
11392  {
11393  std::stringstream err;
11394  err << "The number of polylines on the unsorted and sorted vectors"
11395  << " is different,\n"
11396  << "it means that not all the polylines have been sorted.\n"
11397  << "Sorted polylines: "<<n_sorted_polylines
11398  << "\nUnsorted polylines: "<<n_unsorted_polylines;
11399  throw OomphLibError(err.str(), "TriangleMesh::sort_polylines_helper()",
11400  OOMPH_EXCEPTION_LOCATION);
11401  }
11402 #endif
11403 
11404  }
11405 
11406  //======================================================================
11407  // \short Creates the shared boundaries
11408  //======================================================================
11409  template<class ELEMENT>
11411  OomphCommunicator* comm_pt,
11412  const Vector<unsigned> &element_domain,
11413  const Vector<GeneralisedElement*> &backed_up_el_pt,
11414  const Vector<FiniteElement*> &backed_up_f_el_pt,
11415  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11416  const bool& overrule_keep_as_halo_element_status)
11417  {
11418  // Storage for number of processors and current processor
11419  const unsigned nproc = comm_pt->nproc();
11420  const unsigned my_rank = comm_pt->my_rank();
11421 
11422  // Storage for all the halo elements on all processors
11423  // halo_element[iproc][jproc][ele_number]
11424  // Stores the "ele_number"-th halo element of processor "iproc" with
11425  // processor "jproc"
11426  Vector<Vector<Vector<GeneralisedElement*> > > halo_element_pt(nproc);
11427  // Create complete storage for the halo_element_pt container
11428  for (unsigned iproc = 0; iproc < nproc; iproc++)
11429  {halo_element_pt[iproc].resize(nproc);}
11430 
11431  // Store the global index of the element, used to check for possible
11432  // misclassification of halo elements in the above container
11433  // (halo_element_pt)
11434  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11435 
11436  // Get the halo elements on all processors
11437  this->get_halo_elements_on_all_procs(nproc, element_domain,
11438  backed_up_el_pt,
11439  processors_associated_with_data,
11440  overrule_keep_as_halo_element_status,
11441  element_to_global_index,
11442  halo_element_pt);
11443 
11444  // Resize the shared polylines container
11445  flush_shared_boundary_polyline_pt();
11446  Shared_boundary_polyline_pt.resize(nproc);
11447 
11448  // Create a set that store only the elements that will be kept in
11449  // the processor as nonhalo element, those whose element_domains is
11450  // equal to my_rank. This set is used when creating the shared
11451  // polylines and identify the connections to the original boundaries
11452  std::set<FiniteElement*> element_in_processor_pt;
11453  const unsigned n_ele = backed_up_f_el_pt.size();
11454  for (unsigned e = 0; e < n_ele; e++)
11455  {
11456  if (element_domain[e] == my_rank)
11457  {
11458  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11459  } // if (element_domain[e] == my_rank)
11460  } // for (e < n_elex)
11461 
11462  // Look for elements edges that may lie on internal boundaries
11463  // If that is the case then relate the face with the boundary on
11464  // which it lies
11465  std::map<std::pair<Node*,Node*>, unsigned> elements_edges_on_boundary;
11466  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11467 
11468  // Now we have all the halo elements on all processors. Use the
11469  // edges shared by the halo elements to create the shared boundaries.
11470  this->create_polylines_from_halo_elements_helper(element_domain,
11471  element_to_global_index,
11472  element_in_processor_pt,
11473  halo_element_pt,
11474  elements_edges_on_boundary,
11475  Shared_boundary_polyline_pt);
11476 
11477  }
11478 
11479  //======================================================================
11480  /// \short Creates the halo elements on all processors
11481  /// Gets the halo elements on all processors, these elements are then used
11482  /// on the function that computes the shared boundaries among the processors
11483  //======================================================================
11484  template<class ELEMENT>
11486  const unsigned &nproc, const Vector<unsigned> &element_domain,
11487  const Vector<GeneralisedElement*> &backed_up_el_pt,
11488  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11489  const bool&overrule_keep_as_halo_element_status,
11490  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11491  Vector<Vector<Vector<GeneralisedElement*> > > &output_halo_elements_pt)
11492  {
11493  const unsigned n_ele = backed_up_el_pt.size();
11494 
11495  // Loop over all the processors
11496  for (unsigned iproc = 0; iproc < nproc; iproc++)
11497  {
11498  // Boolean to know which elements has been already added to the
11499  // halo scheme on "iproc" processor
11500  Vector<std::map<GeneralisedElement*, bool> > already_added(nproc);
11501 
11502  // Loop over all backed up elements
11503  for (unsigned e=0;e<n_ele;e++)
11504  {
11505  // Get element and its domain
11506  GeneralisedElement* el_pt=backed_up_el_pt[e];
11507  unsigned el_domain=element_domain[e];
11508 
11509  // If element is NOT located on "iproc" processor then check if it is
11510  // halo with "el_domain" processor
11511  if (el_domain!=iproc)
11512  {
11513  // If this current mesh has been told to keep all elements as halos,
11514  // OR the element itself knows that it must be kept then
11515  // keep it
11516  if ((this->Keep_all_elements_as_halos) ||
11517  (el_pt->must_be_kept_as_halo()))
11518  {
11519  if (!overrule_keep_as_halo_element_status)
11520  {
11521  // Add as halo element whose non-halo counterpart is
11522  // located on processor "el_domain"
11523  if (!already_added[el_domain][el_pt])
11524  {
11525  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11526  already_added[el_domain][el_pt] = true;
11527  element_to_global_index[el_pt] = e;
11528  }
11529  }
11530  }
11531  // Otherwise: Is one of the nodes associated with other processor?
11532  else
11533  {
11534  //Can only have nodes if this is a finite element
11535  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11536  if(finite_el_pt!=0)
11537  {
11538  unsigned n_node = finite_el_pt->nnode();
11539  for (unsigned n=0;n<n_node;n++)
11540  {
11541  Node* nod_pt=finite_el_pt->node_pt(n);
11542 
11543  // Keep element?
11544  std::set<unsigned>::iterator it =
11545  processors_associated_with_data[nod_pt].find(iproc);
11546  if (it!=processors_associated_with_data[nod_pt].end())
11547  {
11548  // Add as root halo element whose non-halo counterpart is
11549  // located on processor "el_domain"
11550  if (!already_added[el_domain][el_pt])
11551  {
11552  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11553  already_added[el_domain][el_pt] = true;
11554  element_to_global_index[el_pt] = e;
11555  }
11556  // Now break out of loop over nodes
11557  break;
11558  } // if (it!=processors_associated_with_data[nod_pt].end())
11559  } // for (n < n_node)
11560  } // if (finite_el_pt!=0)
11561  } // else (this->Keep_all_elements_as_halos)
11562  } // if (el_domain!=iproc)
11563  } // for (e < nele)
11564  } // for (iproc < nproc)
11565 
11566  }
11567 
11568  //====================================================================
11569  // \short Get the element edges (pair of nodes, edges) that lie
11570  // on a boundary (used to mark shared boundaries that lie on
11571  // internal boundaries)
11572  //====================================================================
11573  template <class ELEMENT>
11575  std::map<std::pair<Node*,Node*>, unsigned> &element_edges_on_boundary)
11576  {
11577  // The number of original boundaries
11578  const unsigned nbound = this->nboundary();
11579  // Loop over the boundaries
11580  for (unsigned b = 0; b < nbound; b++)
11581  {
11582  // Keep track of the pair of nodes done
11583  std::map<std::pair<Node*, Node*>, bool> edge_done;
11584  // Get the number of elements on the boundary
11585  const unsigned nbound_ele = this->nboundary_element(b);
11586  for (unsigned e = 0; e < nbound_ele; e++)
11587  {
11588  // Get the boundary bulk element
11589  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11590  // Get the face index
11591  int face_index = this->face_index_at_boundary(b, e);
11592  // Create the face element
11593  FiniteElement* face_ele_pt =
11594  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
11595  // Get the number of nodes on the face element
11596  const unsigned nnodes = face_ele_pt->nnode();
11597  // Get the first and last node
11598  Node* first_node_pt = face_ele_pt->node_pt(0);
11599  Node* last_node_pt = face_ele_pt->node_pt(nnodes-1);
11600 
11601  // Create the pair to store the nodes
11602  std::pair<Node*,Node*> edge =
11603  std::make_pair(first_node_pt, last_node_pt);
11604 
11605  // Has the edge been included
11606  if (!edge_done[edge])
11607  {
11608  // Mark the edge as done
11609  edge_done[edge] = true;
11610 
11611  // Create the reversed version and mark it as done too
11612  std::pair<Node*,Node*> inv_edge =
11613  std::make_pair(last_node_pt, first_node_pt);
11614 
11615  // Mark the reversed edge as done
11616  edge_done[inv_edge] = true;
11617 
11618  // Mark the edge to belong to boundary b
11619  element_edges_on_boundary[edge] = b;
11620  } // if (!edge_done[edge])
11621 
11622  // Free the memory allocated for the face element
11623  delete face_ele_pt;
11624  face_ele_pt = 0;
11625 
11626  } // for (e < nbound_ele)
11627 
11628  } // for (b < nbound)
11629 
11630  }
11631 
11632  // ======================================================================
11633  // \short Creates polylines from the intersection of halo elements on
11634  // all processors. The new polylines define the shared boundaries in
11635  // the domain This method computes the polylines on ALL processors,
11636  // that is why the three dimensions in the structure
11637  // output_polylines_pt[iproc][ncurve][npolyline]
11638  // ======================================================================
11639  template<class ELEMENT>
11641  const Vector<unsigned> &element_domain,
11642  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11643  std::set<FiniteElement*> &element_in_processor_pt,
11644  Vector<Vector<Vector<GeneralisedElement*> > > &input_halo_elements,
11645  std::map<std::pair<Node*,Node*>, unsigned> &elements_edges_on_boundary,
11646  Vector<Vector<Vector<TriangleMeshPolyLine *> > > &output_polylines_pt)
11647  {
11648  const unsigned nproc = this->communicator_pt()->nproc();
11649  const unsigned my_rank = this->communicator_pt()->my_rank();
11650 
11651  // ---------------------------------------------------------------
11652  // Get the edges shared between each pair of processors
11653  // ---------------------------------------------------------------
11654 
11655  // Storage for the edges (pair of nodes) shared between a pair of
11656  // processors
11658 
11659  // Each edge is associated to two elements, a haloi (halo element
11660  // in processors i) and a haloj (halo element in processors j)
11661  Vector<Vector<Vector<Vector<FiniteElement*> > > > edge_element_pt(nproc);
11662 
11663  // Each edge is associated to two elements, a haloi and a haloj,
11664  // the edge was created from a given face from each element, the
11665  // haloi face is stored at [0], the haloj face is stored at [1]
11666  Vector<Vector<Vector<Vector<int> > > > edge_element_face(nproc);
11667 
11668  // Store the possible internal boundary id associated to each edge
11669  // (-1 if there is no association). Some edges may overlap an
11670  // internal boundary (and only internal boundaries)
11671  Vector<Vector<Vector<int> > > edge_boundary(nproc);
11672 
11673  // Mark those edges (pair of nodes overlapped by a shared boundary)
11674  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
11675 
11676  // Resize the containers, they store info. for each pair of
11677  // processors
11678 
11679  // First resize the global container
11680  Shared_boundaries_ids.resize(nproc);
11681  for (unsigned j = 0 ; j < nproc; j++)
11682  {
11683  edges[j].resize(nproc);
11684  edge_element_pt[j].resize(nproc);
11685  edge_element_face[j].resize(nproc);
11686  edge_boundary[j].resize(nproc);
11687 
11688  // Resize the global container for shared boundaries ids
11689  Shared_boundaries_ids[j].resize(nproc);
11690 
11691  } // for (j < nproc)
11692 
11693  // Take the halo elements of processor "iproc" and compare their
11694  // edges with halo elements of other processors (except itself)
11695  for (unsigned iproc = 0; iproc < nproc; iproc++)
11696  {
11697  // Take the halo elements of processor iproc and compare with
11698  // other processors
11699  // Start from the iproc + 1,
11700  // 1) To avoid comparing with itself,
11701  // 2) To avoid generation of repeated boundaries
11702  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11703  {
11704  // **************************************************************
11705  // FIRST PART
11706  // 1) Get the halo elements of processor "iproc" with processor
11707  // "jproc"
11708  // 2) Get the halo elements of processor "jproc" with processor
11709  // "iproc"
11710  // 3) Compare their edges and those that match are the ones that
11711  // define the shared boundaries
11712  // **************************************************************
11713 
11714  // Storage for halo elements
11715  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11716  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11717 
11718  // Get the halo elements of "iproc" with "jproc"
11719  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11720 
11721  // If there are halo elements then there are shared boundaries
11722  const unsigned nhalo_elements_iproc_with_jproc =
11723  halo_elements_iproc_with_jproc.size();
11724 // DEBP(nhalo_elements_iproc_with_jproc);
11725  if (nhalo_elements_iproc_with_jproc > 0)
11726  {
11727  // Get the halo elements of "jproc" with "iproc"
11728  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11729 
11730  // If there are halo elements then there are shared
11731  // boundaries
11732  const unsigned nhalo_elements_jproc_with_iproc =
11733  halo_elements_jproc_with_iproc.size();
11734 // DEBP(nhalo_elements_jproc_with_iproc);
11735 #ifdef PARANOID
11736  if (nhalo_elements_jproc_with_iproc == 0)
11737  {
11738  // If there are halo elements of iproc with jproc there
11739  // MUST be halo elements on the other way round, not
11740  // necessary the same but at least one
11741  std::stringstream err;
11742  err <<"There are no halo elements from processor ("<<jproc<<") "
11743  <<"with processor ("<<iproc<<").\n"
11744  <<"This is strange since there are halo elements from "
11745  <<"processor ("<<iproc<<") with processor ("<<jproc<<").\n"
11746  <<"Number of halo elements from ("<<iproc<<") to ("
11747  <<jproc<<") : ("<< nhalo_elements_iproc_with_jproc<<")\n"
11748  <<"Number of halo elements from ("<<jproc<<") to ("
11749  <<iproc<<") : ("<< nhalo_elements_jproc_with_iproc<<")\n";
11750  throw OomphLibError(err.str(),
11751  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11752  OOMPH_EXCEPTION_LOCATION);
11753  }
11754 #endif
11755  // The edges are defined as pair of nodes
11756  Vector<Node*> halo_edges_iproc;
11757  unsigned halo_edges_counter_iproc = 0;
11758  Vector<Node*> halo_edges_jproc;
11759  unsigned halo_edges_counter_jproc = 0;
11760 
11761  // Map to associate the edge with the element used to create it
11762  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesi_to_element_pt;
11763 
11764  // Map to associated the edge with the face number of the
11765  // element that created it
11766  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11767  edgesi_element_pt_to_face_index;
11768 
11769  // Map to associate the edge with the element used to create it
11770  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesj_to_element_pt;
11771 
11772  // Map to associated the edge with the face number of the
11773  // element that created it
11774  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11775  edgesj_element_pt_to_face_index;
11776 
11777  // **************************************************************
11778  // 1.1) Store the edges of the "iproc" halo elements
11779  // **************************************************************
11780  // Go throught halo elements on "iproc" processor
11781  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11782  {
11783 #ifdef PARANOID
11784  unsigned e =
11785  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11786  // Only work with halo elements inside the "jproc" processor
11787  if (element_domain[e] != jproc)
11788  {
11789  // There was a problem on the ihalo-jhalo classification
11790  std::stringstream err;
11791  err << "There was a problem on the ihalo-jhalo classification.\n"
11792  << "One of the elements, (the one with the ("<<e<<")-th "
11793  << "index ) is not on the ("<<jproc<<")-th processor\n"
11794  << "but it was stored as a halo element of processor ("
11795  << iproc<<") with processor ("<<jproc<<").\n";
11796  throw OomphLibError(
11797  err.str(),
11798  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11799  OOMPH_EXCEPTION_LOCATION);
11800  }
11801 #endif
11802 
11803  FiniteElement* el_pt =
11804  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11805 
11806  if (el_pt==0)
11807  {
11808  std::stringstream err;
11809  err << "The halo element ("<<ih<<") could not be casted to the "
11810  << "FiniteElement type.\n";
11811  throw OomphLibError(
11812  err.str(),
11813  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11814  OOMPH_EXCEPTION_LOCATION);
11815  }
11816 
11817 #ifdef PARANOID
11818  // Number of nodes on this element
11819  const unsigned n_nodes = el_pt->nnode();
11820 
11821  // The number of nodes on every element should be at least
11822  // three since we are going to work with the cornes nodes,
11823  // the ones with index 0, 1 and 2
11824  if (n_nodes<3)
11825  {
11826  std::stringstream err;
11827  err << "The number of nodes of the "<<ih<<"-th halo element is"
11828  << " ("<< n_nodes << ").\nWe can not work with triangle "
11829  << "elements with less than three nodes\n";
11830  throw OomphLibError(err.str(),
11831  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11832  OOMPH_EXCEPTION_LOCATION);
11833  }
11834 #endif
11835 
11836  // Get the corner nodes, the first three nodes
11837  Node *first_node_pt = el_pt->node_pt(0);
11838  Node *second_node_pt = el_pt->node_pt(1);
11839  Node *third_node_pt = el_pt->node_pt(2);
11840 
11841  // Store the edges
11842  halo_edges_iproc.push_back(first_node_pt);
11843  halo_edges_iproc.push_back(second_node_pt);
11844  halo_edges_counter_jproc++;
11845 
11846  halo_edges_iproc.push_back(second_node_pt);
11847  halo_edges_iproc.push_back(third_node_pt);
11848  halo_edges_counter_jproc++;
11849 
11850  halo_edges_iproc.push_back(third_node_pt);
11851  halo_edges_iproc.push_back(first_node_pt);
11852  halo_edges_counter_jproc++;
11853 
11854  // Store the info. of the element used to create these edges
11855  std::pair<Node*, Node*> edge1 =
11856  std::make_pair(first_node_pt, second_node_pt);
11857  edgesi_to_element_pt[edge1] = el_pt;
11858 
11859  std::pair<Node*, Node*> edge2 =
11860  std::make_pair(second_node_pt, third_node_pt);
11861  edgesi_to_element_pt[edge2] = el_pt;
11862 
11863  std::pair<Node*, Node*> edge3 =
11864  std::make_pair(third_node_pt, first_node_pt);
11865  edgesi_to_element_pt[edge3] = el_pt;
11866 
11867  // Store the face index of the edge in the element
11868  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11869  std::make_pair(edge1, el_pt);
11870  edgesi_element_pt_to_face_index[edge_ele1] = 2;
11871 
11872  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11873  std::make_pair(edge2, el_pt);
11874  edgesi_element_pt_to_face_index[edge_ele2] = 0;
11875 
11876  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11877  std::make_pair(edge3, el_pt);
11878  edgesi_element_pt_to_face_index[edge_ele3] = 1;
11879 
11880  } // for (ih < nhalo_elements_iproc_with_jproc)
11881 
11882  // **************************************************************
11883  // 1.2) Store the edges of the "jproc" halo elements
11884  // **************************************************************
11885  // Go throught halo elements on "jproc" processor
11886  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
11887  {
11888 #ifdef PARANOID
11889  unsigned e =
11890  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
11891  // Only work with halo elements inside the "jproc" processor
11892  if (element_domain[e] != iproc)
11893  {
11894  // There was a problem on the jhalo-ihalo classification
11895  std::stringstream err;
11896  err << "There was a problem on the jhalo-ihalo classification.\n"
11897  << "One of the elements, (the one with the ("<<e<<")-th "
11898  << "index ) is not on the ("<<iproc<<")-th processor\n"
11899  << "but it was stored as a halo element of processor ("
11900  << jproc<<") with processor ("<<iproc<<").\n";
11901  throw OomphLibError(
11902  err.str(),
11903  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11904  OOMPH_EXCEPTION_LOCATION);
11905  }
11906 #endif
11907 
11908  FiniteElement* el_pt =
11909  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
11910  if (el_pt==0)
11911  {
11912  std::stringstream err;
11913  err << "The halo element ("<<jh<<") could not be casted to the "
11914  << "FiniteElement type.\n";
11915  throw OomphLibError(
11916  err.str(),
11917  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11918  OOMPH_EXCEPTION_LOCATION);
11919  }
11920 
11921 #ifdef PARANOID
11922  // Number of nodes on this element
11923  const unsigned n_nodes = el_pt->nnode();
11924 
11925  // The number of nodes on every element should be at least
11926  // three since we are going to work with the cornes nodes,
11927  // the ones with index 0, 1 and 2
11928  if (n_nodes<3)
11929  {
11930  std::stringstream err;
11931  err << "The number of nodes of the "<<jh<<"-th halo element is"
11932  << " ("<< n_nodes << ").\nWe can not work with triangle "
11933  << "elements with less than three nodes\n";
11934  throw OomphLibError(err.str(),
11935  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11936  OOMPH_EXCEPTION_LOCATION);
11937  }
11938 #endif
11939 
11940  // Get the nodes pointers
11941  Node *first_node_pt = el_pt->node_pt(0);
11942  Node *second_node_pt = el_pt->node_pt(1);
11943  Node *third_node_pt = el_pt->node_pt(2);
11944 
11945  // Store the edges
11946  halo_edges_jproc.push_back(first_node_pt);
11947  halo_edges_jproc.push_back(second_node_pt);
11948  halo_edges_counter_iproc++;
11949 
11950  halo_edges_jproc.push_back(second_node_pt);
11951  halo_edges_jproc.push_back(third_node_pt);
11952  halo_edges_counter_iproc++;
11953 
11954  halo_edges_jproc.push_back(third_node_pt);
11955  halo_edges_jproc.push_back(first_node_pt);
11956  halo_edges_counter_iproc++;
11957 
11958  // Store the info. of the element used to create these edges
11959  std::pair<Node*, Node*> edge1 =
11960  std::make_pair(first_node_pt, second_node_pt);
11961  edgesj_to_element_pt[edge1] = el_pt;
11962 
11963  std::pair<Node*, Node*> edge2 =
11964  std::make_pair(second_node_pt, third_node_pt);
11965  edgesj_to_element_pt[edge2] = el_pt;
11966 
11967  std::pair<Node*, Node*> edge3 =
11968  std::make_pair(third_node_pt, first_node_pt);
11969  edgesj_to_element_pt[edge3] = el_pt;
11970 
11971  // Store the face index of the edge in the element
11972  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11973  std::make_pair(edge1, el_pt);
11974  edgesj_element_pt_to_face_index[edge_ele1] = 2;
11975 
11976  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11977  std::make_pair(edge2, el_pt);
11978  edgesj_element_pt_to_face_index[edge_ele2] = 0;
11979 
11980  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11981  std::make_pair(edge3, el_pt);
11982  edgesj_element_pt_to_face_index[edge_ele3] = 1;
11983 
11984  } // for (jh < nhalo_elements_jproc_with_iproc)
11985 
11986  // ***************************************************************
11987  // SECOND PART
11988  // 1) We already have the information of the edges on the iproc
11989  // halo and jproc halo elements
11990  // 2) Identify the shared edges to create the shared boundaries
11991  // (Only store the information but do not create the polyline)
11992  // ***************************************************************
11993 
11994  // Get the number of edges from each processor
11995  unsigned nhalo_iedges = halo_edges_iproc.size();
11996  unsigned nhalo_jedges = halo_edges_jproc.size();
11997 
11998  // Start comparing the edges to check which of those are
11999  // shared between the "ihalo_edge" and the "jhalo_edge"
12000  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe+=2)
12001  {
12002  // Get the ihe-th edge (pair of nodes)
12003  Vector<Node*> ihalo_edge(2);
12004  ihalo_edge[0] = halo_edges_iproc[ihe];
12005  ihalo_edge[1] = halo_edges_iproc[ihe+1];
12006 
12007  // Create the pair that defines the edge
12008  std::pair<Node*,Node*> tmp_edge = std::make_pair(ihalo_edge[0],
12009  ihalo_edge[1]);
12010 
12011  // Check if the edge lies on a boundary (default values is
12012  // -1 for no association with an internal boundary)
12013  int edge_boundary_id = -1;
12014  {
12015  std::map<std::pair<Node*,Node*>,unsigned >::iterator it;
12016  it = elements_edges_on_boundary.find(tmp_edge);
12017  // If the edges lie on a boundary then get the boundary id
12018  // on which the edges lie
12019  if (it != elements_edges_on_boundary.end())
12020  {
12021  // Assign the internal boundary id associated with the
12022  // edge
12023  edge_boundary_id = (*it).second;
12024  }
12025  else
12026  {
12027  // Look for the reversed version of the edge (the nodes
12028  // inverted)
12029  std::pair<Node*,Node*> rtmp_edge = std::make_pair(ihalo_edge[1],
12030  ihalo_edge[0]);
12031  it = elements_edges_on_boundary.find(rtmp_edge);
12032  if (it != elements_edges_on_boundary.end())
12033  {
12034  // Assign the internal boundary id associated with the
12035  // edge
12036  edge_boundary_id = (*it).second;
12037  }
12038  }
12039  }
12040 
12041  // Go through the jhalo_edge and compare with the
12042  // ihalo_edge
12043  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe+=2)
12044  {
12045  // Get the jhe-th edge (pair of nodes)
12046  Vector<Node*> jhalo_edge(2);
12047  jhalo_edge[0] = halo_edges_jproc[jhe];
12048  jhalo_edge[1] = halo_edges_jproc[jhe+1];
12049 
12050  // Comparing pointer of nodes
12051  if (ihalo_edge[0] == jhalo_edge[0] &&
12052  ihalo_edge[1] == jhalo_edge[1])
12053  {
12054  // Create the edge (both nodes that make the edge)
12055  std::pair<Node*, Node*> new_edge =
12056  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12057 
12058  // Get the elements involved in the creation of the
12059  // edge to check that there are elements associated to
12060  // the edge
12061  FiniteElement* haloi_ele_pt = 0;
12062  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12063  FiniteElement* haloj_ele_pt = 0;
12064  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12065 
12066  // Verify that there is an element associated with it
12067  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12068  {
12069  std::stringstream err;
12070  err << "There is no associated elements with the new "
12071  << "shared boundary. This is an storing problem,\n"
12072  << "possibly related with a memory leak problem!!!\n"
12073  << "The nodes that compound the edge are these:\n"
12074  << "On processor ("<<iproc<<"):\n"
12075  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12076  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12077  <<ihalo_edge[1]->x(1)<<")\n\n"
12078  << "On processor ("<<jproc<<"):\n"
12079  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12080  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12081  <<jhalo_edge[1]->x(1)<<")\n\n"
12082  << "The nodes coordinates should be the same!!!\n";
12083  throw OomphLibError(err.str(),
12084  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12085  OOMPH_EXCEPTION_LOCATION);
12086  }
12087 
12088  // Store the edge
12089  edges[iproc][jproc].push_back(new_edge);
12090 
12091  // Is the edge overlapped by a shared boundary
12092  if (edge_boundary_id >= 0)
12093  {
12094  // Mark the edge as overlapped
12095  overlapped_edge[new_edge] = true;
12096 
12097  // Also mark the reversed edge
12098  std::pair<Node*, Node*> rev_new_edge =
12099  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12100 
12101  // Mark the edge as overlapped
12102  overlapped_edge[rev_new_edge] = true;
12103 
12104  } // if (edge_boundary_id >= 0)
12105 
12106  // Store the internal boundary id (default -1)
12107  // associated to the edge
12108  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12109 
12110  // Store the two elements associated with the edge
12111  Vector<FiniteElement*> tmp_elements_pt;
12112  tmp_elements_pt.push_back(haloi_ele_pt);
12113  tmp_elements_pt.push_back(haloj_ele_pt);
12114 
12115  // Associate the edge with the elements that gave rise to it
12116  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12117 
12118  // Get the face index on each element that gave rise to
12119  // the edge
12120 
12121  // .. first create the pair (edge, finite_element)
12122  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12123  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12124 
12125  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12126  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12127 
12128  // Set default values to later check if values were
12129  // read from the map structure
12130  int face_index_haloi_ele = -1;
12131  face_index_haloi_ele =
12132  edgesi_element_pt_to_face_index[edge_elementi_pair];
12133  int face_index_haloj_ele = -1;
12134  face_index_haloj_ele =
12135  edgesj_element_pt_to_face_index[edge_elementj_pair];
12136  // Verify that there is an element associated with it
12137  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12138  {
12139  std::stringstream err;
12140  err << "There is no associated face indexes to the"
12141  << "elements that gave\nrise to the shared edge\n"
12142  << "The nodes that compound the edge are these:\n"
12143  << "On processor ("<<iproc<<"):\n"
12144  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12145  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12146  <<ihalo_edge[1]->x(1)<<")\n\n"
12147  << "On processor ("<<jproc<<"):\n"
12148  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12149  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12150  <<jhalo_edge[1]->x(1)<<")\n\n"
12151  << "The nodes coordinates should be the same!!!\n";
12152  throw OomphLibError(err.str(),
12153  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12154  OOMPH_EXCEPTION_LOCATION);
12155  } // if (face_index_haloi_ele == -1 ||
12156  // face_index_haloj_ele == -1)
12157 
12158  // Get the face indexes from the map structure
12159  Vector<int> tmp_edge_element_face_index;
12160  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12161  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12162  // Store the face indexes
12163  edge_element_face[iproc][jproc].
12164  push_back(tmp_edge_element_face_index);
12165 
12166  break; // break for (jhe < nhalo_jedges) since edge
12167  // found
12168 
12169  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12170  // ihalo_edge[1] == jhalo_edge[1])
12171  // Comparing nodes pointers
12172  else if (ihalo_edge[0] == jhalo_edge[1] &&
12173  ihalo_edge[1] == jhalo_edge[0])
12174  {
12175  // Create the edge (both nodes that make the edge)
12176  std::pair<Node*, Node*> new_edge =
12177  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12178 
12179  // Get the elements involved in the creation of the
12180  // edge
12181  FiniteElement* haloi_ele_pt = 0;
12182  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12183 
12184  FiniteElement* haloj_ele_pt = 0;
12185  // Create the edge (reversed, that is how it was
12186  // originally stored)
12187  std::pair<Node*, Node*> new_edge_reversed =
12188  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12189  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12190 
12191  // Verify that there is an element associated with it
12192  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12193  {
12194  std::stringstream err;
12195  err << "There is no associated elements with the new "
12196  << "shared boundary (reversed version). This is an "
12197  << "storing problem, possibly related with a memory "
12198  << "leak problem!!!\n"
12199  << "The nodes that compound the edge are these:\n"
12200  << "On processor ("<<iproc<<"):\n"
12201  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12202  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12203  <<ihalo_edge[1]->x(1)<<")\n\n"
12204  << "On processor ("<<jproc<<"):\n"
12205  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12206  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12207  <<jhalo_edge[1]->x(1)<<")\n\n"
12208  << "The nodes coordinates should be the same!!!\n";
12209  throw OomphLibError(err.str(),
12210  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12211  OOMPH_EXCEPTION_LOCATION);
12212  }
12213 
12214  // Store the edge
12215  edges[iproc][jproc].push_back(new_edge);
12216 
12217  // Is the edge overlapped by a shared boundary
12218  if (edge_boundary_id >= 0)
12219  {
12220  // Mark the edge as overlapped
12221  overlapped_edge[new_edge] = true;
12222 
12223  // Also mark the reversed edge
12224  std::pair<Node*, Node*> rev_new_edge =
12225  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12226 
12227  // Mark the edge as overlapped
12228  overlapped_edge[rev_new_edge] = true;
12229  } // if (edge_boundary_id >= 0)
12230 
12231  // Store the internal boundary id (default -1)
12232  // associated to the edge
12233  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12234 
12235  // Store the two elements associated with the edge
12236  Vector<FiniteElement*> tmp_elements_pt;
12237  tmp_elements_pt.push_back(haloi_ele_pt);
12238  tmp_elements_pt.push_back(haloj_ele_pt);
12239 
12240  // Associate the edge with the elements that gave rise to it
12241  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12242 
12243  // Get the face index on each element that gave rise to
12244  // the edge
12245 
12246  // .. first create the pair (edge, finite_element)
12247  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12248  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12249 
12250  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12251  edge_elementj_pair = make_pair(new_edge_reversed,
12252  haloj_ele_pt);
12253 
12254  // Set default values to later check if values were
12255  // read from the map structure
12256  int face_index_haloi_ele = -1;
12257  face_index_haloi_ele =
12258  edgesi_element_pt_to_face_index[edge_elementi_pair];
12259  int face_index_haloj_ele = -1;
12260  face_index_haloj_ele =
12261  edgesj_element_pt_to_face_index[edge_elementj_pair];
12262  // Verify that there is an element associated with it
12263  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12264  {
12265  std::stringstream err;
12266  err << "There is no associated face indexes to the"
12267  << "elements that gave\nrise to the shared edge\n"
12268  << "The nodes that compound the edge are these:\n"
12269  << "On processor ("<<iproc<<"):\n"
12270  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12271  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12272  <<ihalo_edge[1]->x(1)<<")\n\n"
12273  << "On processor ("<<jproc<<"):\n"
12274  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12275  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12276  <<jhalo_edge[1]->x(1)<<")\n\n"
12277  << "The nodes coordinates should be the same!!!\n";
12278  throw OomphLibError(err.str(),
12279  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12280  OOMPH_EXCEPTION_LOCATION);
12281  } // if (face_index_haloi_ele == -1 ||
12282  // face_index_haloj_ele == -1)
12283 
12284  // Get the face indexes from the map structure
12285  Vector<int> tmp_edge_element_face_index;
12286  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12287  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12288  // Store the face indexes
12289  edge_element_face[iproc][jproc].
12290  push_back(tmp_edge_element_face_index);
12291 
12292  break; // break for (jhe < nhalo_jedges) since edge found
12293 
12294  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12295  // ihalo_edge[1] == jhalo_edge[0])
12296 
12297  } // for (jhe < nhaloj_edges)
12298 
12299  } // for (ihe < nhaloi_edges)
12300 
12301  } // if (nhalo_elements_iproc_with_jproc > 0)
12302 
12303  } // for (jproc < nproc)
12304 
12305  } // for (iproc < nproc)
12306 
12307  // ------------------------------------------------------------------
12308  // Compute the degree of each node in the shared edges
12309  // ------------------------------------------------------------------
12310 
12311  // Visit all the shared edges between each pair of processors,
12312  // visit the nodes of each edge and compute the degree of each node
12313 
12314  // Store the degree (valency) of each node
12315  std::map<Node*, unsigned> global_shared_node_degree;
12316 
12317 #ifdef PARANOID
12318  // Map to check if an edge has been already visited
12319  std::map<std::pair<Node*, Node*>,bool> edge_done;
12320 #endif // #ifdef PARANOID
12321  // Map to check if a node has been already visited
12322  std::map<Node*,bool> node_done;
12323 
12324  // Loop over the processors and get the shared edged between each
12325  // pair of processors
12326  for (unsigned iproc = 0; iproc < nproc; iproc++)
12327  {
12328  // Start from iproc + 1 to avoid checking with itself (there is
12329  // no shared edges between the same processor), and to avoid
12330  // double counting the edges and nodes (the shared edges between
12331  // processor (iproc, jproc) are the same as those between
12332  // processor jproc, iproc)
12333  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12334  {
12335  // Get the number of edges shared between the pair of processors
12336  const unsigned nshd_edges = edges[iproc][jproc].size();
12337 #ifdef PARANOID
12338  // There must be the same number of information on each of the
12339  // containers
12340 
12341  // Get the number of edge elements
12342  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12343  if (nshd_edges != nedge_element)
12344  {
12345  std::stringstream error_message;
12346  error_message
12347  << "The number of shared edges between processor iproc and jproc\n"
12348  << "is different form the number of edge elements between the\n"
12349  << "pair of processors\n"
12350  << "iproc: (" << iproc << ")\n"
12351  << "jproc: (" << jproc << ")\n"
12352  << "# of shared edges: (" << nshd_edges << ")\n"
12353  << "# of edge elements: (" << nedge_element << ")\n\n";
12354  throw OomphLibError(error_message.str(),
12355  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12356  OOMPH_EXCEPTION_LOCATION);
12357  }
12358 
12359  // Get the number of edge element faces
12360  const unsigned nedge_element_face =
12361  edge_element_face[iproc][jproc].size();
12362  if (nshd_edges != nedge_element_face)
12363  {
12364  std::stringstream error_message;
12365  error_message
12366  << "The number of shared edges between processor iproc and jproc\n"
12367  << "is different form the number of edge element faces between the\n"
12368  << "pair of processors\n"
12369  << "iproc: (" << iproc << ")\n"
12370  << "jproc: (" << jproc << ")\n"
12371  << "# of shared edges: (" << nshd_edges << ")\n"
12372  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12373  throw OomphLibError(error_message.str(),
12374  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12375  OOMPH_EXCEPTION_LOCATION);
12376  }
12377 
12378  // Get the number of edge boundaries
12379  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12380  if (nshd_edges != nedge_boundary)
12381  {
12382  std::stringstream error_message;
12383  error_message
12384  << "The number of shared edges between processor iproc and jproc\n"
12385  << "is different form the number of edge boundaries ids between the\n"
12386  << "pair of processors\n"
12387  << "iproc: (" << iproc << ")\n"
12388  << "jproc: (" << jproc << ")\n"
12389  << "# of shared edges: (" << nshd_edges << ")\n"
12390  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12391  throw OomphLibError(error_message.str(),
12392  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12393  OOMPH_EXCEPTION_LOCATION);
12394  }
12395 
12396 #endif // #ifdef PARANOID
12397 
12398  // Loop over the shared edges between (iproc, jproc) processors
12399  for (unsigned se = 0; se < nshd_edges; se++)
12400  {
12401  // Get the edge
12402  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12403 #ifdef PARANOID
12404  // Check that the edge has not been previously visited
12405  if (edge_done[edge])
12406  {
12407  std::stringstream error_message;
12408  error_message
12409  << "The shared edge between processor iproc and processor\n"
12410  << "jproc has been already visited, this is weird since the\n"
12411  << "edge should not be shared by other pair of processors\n"
12412  << "iproc: (" << iproc << ")\n"
12413  << "jproc: (" << jproc << ")\n"
12414  << "First node of edge: (" << edge.first->x(0) << ", "
12415  << edge.first->x(1) << ")\n"
12416  << "Second node of edge: (" << edge.second->x(0) << ", "
12417  << edge.second->x(1) << ")\n"
12418  << "Associated edge boundary id: ("
12419  << edge_boundary[iproc][jproc][se] << ")\n\n";
12420  throw OomphLibError(error_message.str(),
12421  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12422  OOMPH_EXCEPTION_LOCATION);
12423  }
12424 
12425  // Mark the edge as done
12426  edge_done[edge] = true;
12427  // Create the reversed version and include it too
12428  std::pair<Node*, Node*> rev_edge =
12429  std::make_pair(edge.second, edge.first);
12430  // Mark reversed edge as done
12431  edge_done[rev_edge] = true;
12432 #endif // #ifdef PARANOID
12433 
12434  // Get each of the nodes that conform the edge
12435  Node* left_node_pt = edge.first;
12436  Node* right_node_pt = edge.second;
12437 
12438  // Check if the left node has been already done
12439  if (!node_done[left_node_pt])
12440  {
12441  // Set the degree of the node to once since this is the
12442  // first time it has been found
12443  global_shared_node_degree[left_node_pt] = 1;
12444 
12445  } // if (!done_node[left_node_pt])
12446  else
12447  {
12448  // Increase the degree of the node
12449  global_shared_node_degree[left_node_pt]++;
12450  }
12451 
12452  // Check if the right node has been already done
12453  if (!node_done[right_node_pt])
12454  {
12455  // Set the degree of the node to once since this is the
12456  // first time it has been found
12457  global_shared_node_degree[right_node_pt] = 1;
12458  } // if (!done_node[right_node_pt])
12459  else
12460  {
12461  // Increase the degree of the node
12462  global_shared_node_degree[right_node_pt]++;
12463  }
12464 
12465  } // for (se < nshd_edges)
12466 
12467  } // for (jproc < nproc)
12468 
12469  } // for (iproc < nproc)
12470 
12471  // -----------------------------------------------------------------
12472  // Identify those nodes living on edges of original boundaries not
12473  // overlapped by a shared boundary
12474 
12475  // Mark the nodes on original boundaries not overlapped by shared
12476  // boundaries
12477  std::map<unsigned, std::map<Node*, bool> >
12478  node_on_bnd_not_overlapped_by_shd_bnd;
12479 
12480  // Loop over the edges of the original boundaries
12481  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
12482  elements_edges_on_boundary.begin();
12483  it_map != elements_edges_on_boundary.end(); it_map++)
12484  {
12485  // Get the edge
12486  std::pair<Node*,Node*> edge_pair = (*it_map).first;
12487 
12488  // Is the edge overlaped by a shared boundary
12489  if (!overlapped_edge[edge_pair])
12490  {
12491  // Mark the nodes of the edge as being on an edge not overlaped
12492  // by a shared boundary on the boundary the edge is
12493  unsigned b = (*it_map).second;
12494 
12495  // Get the left node
12496  Node* left_node_pt = edge_pair.first;
12497  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12498 
12499  // Get the right node
12500  Node* right_node_pt = edge_pair.second;
12501  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12502 
12503  } // if (!overlapped_edge[edge_pair])
12504 
12505  } // Loop over edges to mark those nodes on overlaped edge by
12506  // shared boundaries
12507 
12508  // ------------------------------------------------------------------
12509  // Now create the shared polylines but including the degree of the
12510  // nodes as a nw stop condition for adding more edges to the side
12511  // or a root edge
12512  // ------------------------------------------------------------------
12513 
12514  // Storage for new created polylines with "each processor", non
12515  // sorted (shared polylines of the current processor only)
12516  Vector<Vector<TriangleMeshPolyLine *> > unsorted_polylines_pt(nproc);
12517 
12518  // Map that associates the shared boundary id with the list of
12519  // nodes that create it (shared boundary of the current processor
12520  // only)
12521  std::map<unsigned, std::list<Node*> > shared_bnd_id_to_sorted_list_node_pt;
12522 
12523  // Get maximum user boundary id and set the initial shared boundary
12524  // id
12525  unsigned shared_boundary_id_start = this->nboundary();
12526  Initial_shared_boundary_id = shared_boundary_id_start;
12527 
12528  // Aqui
12529 
12530  // Loop over the processors and get the shared edged between each
12531  // pair of processors
12532  for (unsigned iproc = 0; iproc < nproc; iproc++)
12533  {
12534  // Start from iproc + 1 to avoid checking with itself (there is
12535  // no shared edges between the same processor), and to avoid
12536  // double counting the edges and nodes (the shared edges between
12537  // processor (iproc, jproc) are the same as those between
12538  // processor jproc, iproc)
12539  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12540  {
12541  // *************************************************************
12542  // THIRD PART
12543  // 1) Sort the edges (make them contiguous) so that they can
12544  // be used as the vertex coordinates that define a shared
12545  // boundary (polyline)
12546  // *************************************************************
12547  unsigned npolylines_counter = 0;
12548  const unsigned nedges = edges[iproc][jproc].size();
12549 
12550  // -----------------------------------------------------------
12551  // Compute all the SHARED POLYLINES
12552  // -----------------------------------------------------------
12553  // The number of sorted edges
12554  unsigned nsorted_edges = 0;
12555 
12556  // Keep track of the already done edges
12557  std::map<std::pair<Node*,Node*>, bool> edge_done;
12558 
12559  // Loop over all the edges to create all the polylines with
12560  // the current processors involved
12561  while(nsorted_edges < nedges)
12562  {
12563  // Temporaly storage for the elements associated to the
12564  // sorted edges
12565  std::list<FiniteElement*> tmp_boundary_element_pt;
12566  // Temporly storage for the face indexes on the element
12567  // that created the given edge
12568  std::list<int> tmp_face_index_element;
12569  // Get an initial pair of nodes to create an edge
12570  std::pair<Node*,Node*> edge;
12571 #ifdef PARANOID
12572  bool found_initial_edge = false;
12573 #endif
12574  int root_edge_bound_id = -1;
12575  unsigned iedge = 0;
12576  for (iedge = 0; iedge < nedges; iedge++)
12577  {
12578  edge = edges[iproc][jproc][iedge];
12579  // If not done then take it as initial edge
12580  if (!edge_done[edge])
12581  {
12582  // Get the boundary id that the edge may be overlapping
12583  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12584 #ifdef PARANOID
12585  found_initial_edge = true;
12586 #endif
12587  nsorted_edges++;
12588  iedge++;
12589  break;
12590  } // if (!edge_done[edge])
12591  } // for (iedge < nedges)
12592 
12593 #ifdef PARANOID
12594  if (!found_initial_edge)
12595  {
12596  std::ostringstream error_message;
12597  error_message
12598  << "All the edge are already done, but the number of done\n"
12599  << "edges ("<<nsorted_edges<<") is still less than the total\n"
12600  << "number of edges (" << nedges << ").\n";
12601  // << "----- Possible memory leak -----\n";
12602  throw OomphLibError(error_message.str(),
12603  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12604  OOMPH_EXCEPTION_LOCATION);
12605  }
12606 #endif
12607 
12608  // Storing for the sorting nodes extracted from the
12609  // edges. The sorted nodes are used to create a polyline
12610  std::list<Node*> sorted_nodes;
12611  sorted_nodes.clear();
12612 
12613  // The initial and final nodes of the list
12614  Node *first_node_pt = edge.first;
12615  Node *last_node_pt = edge.second;
12616 
12617  // Push back on the list the new edge (nodes)
12618  sorted_nodes.push_back(first_node_pt);
12619  sorted_nodes.push_back(last_node_pt);
12620 
12621  // Get the elements associated to the edge and store them
12622  // in the temporaly boundary elements storage
12623  tmp_boundary_element_pt.
12624  push_back(edge_element_pt[iproc][jproc][iedge-1][0]);
12625  tmp_boundary_element_pt.
12626  push_back(edge_element_pt[iproc][jproc][iedge-1][1]);
12627 
12628  // ... then get the face index of the element from where
12629  // the edge came from
12630  tmp_face_index_element.
12631  push_back(edge_element_face[iproc][jproc][iedge-1][0]);
12632  tmp_face_index_element.
12633  push_back(edge_element_face[iproc][jproc][iedge-1][1]);
12634 
12635  // Mark edge as done
12636  edge_done[edge] = true;
12637 
12638  // Continue iterating if a new node (that creates a new
12639  // edge) is added to the list, we have just added two nodes
12640  // (the first and last of the root edge)
12641  bool node_added = true;
12642 
12643  // Flags to indicate at which end the node was added (left
12644  // or right)
12645  bool node_added_to_the_left = true;
12646  bool node_added_to_the_right = true;
12647 
12648  // The nodes that create a shared boundary are obtained by
12649  // connecting the edges shared by the halo and haloed
12650  // elements. These edges are connected to left or right of
12651  // the shared boundary. Every time a new edge is added to
12652  // the left (or right), the most left (or right) node is
12653  // searched in the list of nodes of previous shared
12654  // boundaries, if the node is found then it is said to be
12655  // shared with another boundary and a connection to that
12656  // boundary needs to be specified. We stop adding edges
12657  // (and nodes) to the side where that nodes was found to be
12658  // shared. Note that the intersection (shared node) may be
12659  // with the same shared boundary
12660 
12661  // Flag to indicate a node was found to be shared with
12662  // another boundary at the left end (most left node) of the
12663  // shared boundary
12664  bool connection_to_the_left = false;
12665 
12666  // Flag to indicate a node was found to be shared with
12667  // another boundary at the right end (most right node) of
12668  // the shared boundary
12669  bool connection_to_the_right = false;
12670 
12671  // Flag to stop the adding of edges (and nodes) to the
12672  // current shared boundary
12673  bool current_polyline_has_connections_at_both_ends = false;
12674 
12675  // Store the boundary ids of the polylines to connect (only
12676  // used when the polyline was found to have a connection)
12677  // -1: Indicates no connection
12678  // -2: Indicates connection with itself
12679  // Any other value: Boundary id to connect
12680  int bound_id_connection_to_the_left = -1;
12681  int bound_id_connection_to_the_right = -1;
12682 
12683  // Get the degree of the first node
12684  const unsigned first_node_degree =
12685  global_shared_node_degree[first_node_pt];
12686 
12687  // Check if the nodes of the root edge have connections
12688  // ... to the left
12689  bound_id_connection_to_the_left =
12690  check_connections_of_polyline_nodes(
12691  element_in_processor_pt,
12692  root_edge_bound_id,
12693  overlapped_edge,
12694  node_on_bnd_not_overlapped_by_shd_bnd,
12695  sorted_nodes,
12696  shared_bnd_id_to_sorted_list_node_pt,
12697  first_node_degree,
12698  first_node_pt);
12699 
12700  // If there is a connection then set the
12701  // corresponding flag
12702  // (-1): No connection
12703  // (-2): Connection with itself
12704  // (-3): No connection, stop adding nodes
12705  // (other value): Boundary id
12706  if (bound_id_connection_to_the_left != -1)
12707  {
12708  connection_to_the_left = true;
12709  } // if (bound_id_connection_to_the_left != -1)
12710 
12711  // Get the degree of the last node
12712  const unsigned last_node_degree =
12713  global_shared_node_degree[last_node_pt];
12714 
12715  // Check if the nodes of the root edge have connections
12716  // ... to the right
12717  bound_id_connection_to_the_right =
12718  check_connections_of_polyline_nodes(
12719  element_in_processor_pt,
12720  root_edge_bound_id,
12721  overlapped_edge,
12722  node_on_bnd_not_overlapped_by_shd_bnd,
12723  sorted_nodes,
12724  shared_bnd_id_to_sorted_list_node_pt,
12725  last_node_degree,
12726  last_node_pt);
12727 
12728  // If there is a connection then set the
12729  // corresponding flag
12730  // (-1): No connection
12731  // (-2): Connection with itself
12732  // (other value): Boundary id
12733  if (bound_id_connection_to_the_right != -1)
12734  {
12735  connection_to_the_right = true;
12736  } // if (bound_id_connection_to_the_right != -1)
12737 
12738  // If the current shared boundary has connections at both
12739  // ends then stop the adding of nodes
12740  if (connection_to_the_left && connection_to_the_right)
12741  {current_polyline_has_connections_at_both_ends = true;}
12742 
12743  // Continue searching for more edges if
12744  // 1) A new node was added at the left or right of the list
12745  // 2) There are more edges to possible add
12746  // 3) The added node is not part of any other previous
12747  // shared polyline
12748  while(node_added && (nsorted_edges < nedges)
12749  && !current_polyline_has_connections_at_both_ends)
12750  {
12751  // Start from the next edge since we have already added
12752  // the previous one as the initial edge (any previous
12753  // edge had to be added to previous polylines)
12754  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12755  {
12756  // Reset the flags for added nodes, to the left and right
12757  node_added = false;
12758  node_added_to_the_left = false;
12759  node_added_to_the_right = false;
12760  // Get the current edge
12761  edge = edges[iproc][jproc][iiedge];
12762  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12763 
12764  // We need to ensure to connect with edges that share
12765  // the same bound id or with those that has no boundary
12766  // id associated (the default -1 value), may apply
12767  // exclusively to internal boundaries
12768  if (!edge_done[edge] &&
12769  (edge_bound_id == root_edge_bound_id))
12770  {
12771  // Get each individual node
12772  Node* left_node_pt = edge.first;
12773  Node* right_node_pt = edge.second;
12774 
12775  // Pointer to the new added node
12776  Node* new_added_node_pt = 0;
12777 
12778  // Is the node to be added to the left?
12779  if (left_node_pt == first_node_pt &&
12780  !connection_to_the_left)
12781  {
12782  // Push front the new node
12783  sorted_nodes.push_front(right_node_pt);
12784  // Update the new added node and the first node
12785  new_added_node_pt = first_node_pt = right_node_pt;
12786  // Set the node added flag to true
12787  node_added = true;
12788  // Indicate the node was added to the left
12789  node_added_to_the_left = true;
12790  }
12791  // Is the node to be added to the right?
12792  else if (left_node_pt == last_node_pt &&
12793  !connection_to_the_right)
12794  {
12795  // Push back the new node
12796  sorted_nodes.push_back(right_node_pt);
12797  // Update the new added node and the last node
12798  new_added_node_pt = last_node_pt = right_node_pt;
12799  // Set the node added flag to true
12800  node_added = true;
12801  // Indicate the node was added to the right
12802  node_added_to_the_right = true;
12803  }
12804  // Is the node to be added to the left?
12805  else if (right_node_pt == first_node_pt &&
12806  !connection_to_the_left)
12807  {
12808  // Push front the new node
12809  sorted_nodes.push_front(left_node_pt);
12810  // Update the new added node and the first node
12811  new_added_node_pt = first_node_pt = left_node_pt;
12812  // Set the node added flag to true
12813  node_added = true;
12814  // Indicate the node was added to the left
12815  node_added_to_the_left = true;
12816  }
12817  // Is the node to be added to the right?
12818  else if (right_node_pt == last_node_pt &&
12819  !connection_to_the_right)
12820  {
12821  // Push back the new node
12822  sorted_nodes.push_back(left_node_pt);
12823  // Update the new added node and the last node
12824  new_added_node_pt = last_node_pt = left_node_pt;
12825  // Set the node added flag to true
12826  node_added = true;
12827  // Indicate the node was added to the right
12828  node_added_to_the_right = true;
12829  }
12830 
12831  // If we added a new node then we need to check if
12832  // that node has been already added in other shared
12833  // boundaries (which may define a connection)
12834  if (node_added)
12835  {
12836  // Mark as done only if one of its nodes has been
12837  // added to the list
12838  edge_done[edge] = true;
12839  nsorted_edges++;
12840 
12841  // Get the degree of the added node
12842  const unsigned added_node_degree =
12843  global_shared_node_degree[new_added_node_pt];
12844 
12845  if (node_added_to_the_left)
12846  {
12847  // Add the bulk elements
12848  tmp_boundary_element_pt.push_front(
12849  edge_element_pt[iproc][jproc][iiedge][1]);
12850  tmp_boundary_element_pt.push_front(
12851  edge_element_pt[iproc][jproc][iiedge][0]);
12852  // Add the face elements
12853  tmp_face_index_element.push_front(
12854  edge_element_face[iproc][jproc][iiedge][1]);
12855  tmp_face_index_element.push_front(
12856  edge_element_face[iproc][jproc][iiedge][0]);
12857  }
12858 
12859  if (node_added_to_the_right)
12860  {
12861  // Add the bulk elements
12862  tmp_boundary_element_pt.push_back(
12863  edge_element_pt[iproc][jproc][iiedge][0]);
12864  tmp_boundary_element_pt.push_back(
12865  edge_element_pt[iproc][jproc][iiedge][1]);
12866  // Add the face elements
12867  tmp_face_index_element.push_back(
12868  edge_element_face[iproc][jproc][iiedge][0]);
12869  tmp_face_index_element.push_back(
12870  edge_element_face[iproc][jproc][iiedge][1]);
12871  }
12872 
12873  // Based on which side the node was added, look for
12874  // connections on that side
12875 
12876  // Verify for connections to the left (we need to
12877  // check for the connection variable too, since
12878  // after a connection has been done we no longer
12879  // need to verify for this condition)
12880  if (node_added_to_the_left && !connection_to_the_left)
12881  {
12882  // Check for connection
12883  bound_id_connection_to_the_left =
12884  check_connections_of_polyline_nodes(
12885  element_in_processor_pt,
12886  root_edge_bound_id,
12887  overlapped_edge,
12888  node_on_bnd_not_overlapped_by_shd_bnd,
12889  sorted_nodes,
12890  shared_bnd_id_to_sorted_list_node_pt,
12891  added_node_degree,
12892  new_added_node_pt);
12893 
12894  // If there is a connection then set the
12895  // corresponding flag
12896  // (-1): No connection
12897  // (-2): Connection with itself
12898  // (other value): Boundary id
12899  if (bound_id_connection_to_the_left != -1)
12900  {
12901  connection_to_the_left = true;
12902  } // if (bound_id_connection_to_the_left != -1)
12903 
12904  } // if (node_added_to_the_left &&
12905  // !connection_to_the_left)
12906 
12907  // Verify for connections to the right (we need to
12908  // check for the connection variable too, since
12909  // after a connection has been done we no longer
12910  // need to verify for this condition)
12911  if (node_added_to_the_right && !connection_to_the_right)
12912  {
12913  // Check for connection
12914  bound_id_connection_to_the_right =
12915  check_connections_of_polyline_nodes(
12916  element_in_processor_pt,
12917  root_edge_bound_id,
12918  overlapped_edge,
12919  node_on_bnd_not_overlapped_by_shd_bnd,
12920  sorted_nodes,
12921  shared_bnd_id_to_sorted_list_node_pt,
12922  added_node_degree,
12923  new_added_node_pt);
12924 
12925  // If there is a connection then set the
12926  // corresponding flag
12927  // (-1): No connection
12928  // (-2): Connection with itself
12929  // (other value): Boundary id
12930  if (bound_id_connection_to_the_right != -1)
12931  {
12932  connection_to_the_right = true;
12933  } // if (bound_id_connection_to_the_right != -1)
12934 
12935  } // if (node_added_to_the_right &&
12936  // !connection_to_the_right)
12937 
12938  // If the current shared boundary has connections
12939  // at both ends then stop the adding of nodes
12940  if (connection_to_the_left && connection_to_the_right)
12941  {current_polyline_has_connections_at_both_ends = true;}
12942 
12943  // Break the for and re-start to look more edges to
12944  // the left or right
12945  break;
12946 
12947  } // if (node_added)
12948 
12949  } // if (!edge_done[edge])
12950  } // for (iiedge < nedges)
12951 
12952  } // while(node_added && (nsorted_edges < nedges)
12953  // && !current_polyline_has_connections_at_both_ends)
12954 
12955  // ------------------------------------------------------------
12956  // If the sorted nodes of the shared polyline create a loop
12957  // it is necessary to break it by creating as many
12958  // polylines as required
12959 
12960  // Change the list to a vector representation of the
12961  // boundary elements and the face indexes
12962 
12963  // Get the number of boundary elements
12964  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
12965 
12966  // Storage for the boundary elements and face indexes
12967  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
12968  Vector<int> tmp_face_idx_ele(n_bnd_ele);
12969  // Helper counter
12970  unsigned help_counter = 0;
12971  // Fill the data structures
12972  for (std::list<FiniteElement*>::iterator it_bnd_ele =
12973  tmp_boundary_element_pt.begin();
12974  it_bnd_ele != tmp_boundary_element_pt.end();
12975  it_bnd_ele++)
12976  {
12977  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
12978  }
12979 
12980  // Restart counter
12981  help_counter = 0;
12982  for (std::list<int>::iterator it_face_idx =
12983  tmp_face_index_element.begin();
12984  it_face_idx != tmp_face_index_element.end();
12985  it_face_idx++)
12986  {
12987  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
12988  }
12989 
12990  // Store the nodes for the new shared polylines without
12991  // loops
12992  Vector<std::list<Node*> > final_sorted_nodes_pt;
12993  // Store the boundary elements of the shared polyline
12994  // without loops
12995  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
12996  // Face indexes of the boundary elements without loops
12997  Vector<Vector<int> > final_face_index_element;
12998  // Connection flags (to the left) of the shared boundaries
12999  // without loops
13000  Vector<int> final_bound_id_connection_to_the_left;
13001  // Connection flags (to the right) of the shared boundaries
13002  // without loops
13003  Vector<int> final_bound_id_connection_to_the_right;
13004 
13005  // Break any possible loop created by the shared polyline
13006  break_loops_on_shared_polyline_helper(
13007  shared_boundary_id_start,
13008  sorted_nodes,
13009  tmp_bnd_ele_pt, tmp_face_idx_ele,
13010  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
13011  final_sorted_nodes_pt,
13012  final_boundary_element_pt, final_face_index_element,
13013  final_bound_id_connection_to_the_left,
13014  final_bound_id_connection_to_the_right);
13015 
13016  // Get the number of final sorted nodes
13017  const unsigned n_final_sorted_nodes =
13018  final_sorted_nodes_pt.size();
13019 
13020  // Loop over the list of final sorted nodes
13021  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13022  {
13023  // --------------------------------------------------------
13024  // Associate the list of sorted nodes with the boundary id
13025  // of the shared boundary that is going to be crated
13026  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13027  final_sorted_nodes_pt[i];
13028 
13029  // Create the shared polyline and fill the data
13030  // structured associated to it
13031  create_shared_polyline(my_rank, shared_boundary_id_start,
13032  iproc, jproc, final_sorted_nodes_pt[i],
13033  root_edge_bound_id,
13034  final_boundary_element_pt[i],
13035  final_face_index_element[i],
13036  unsorted_polylines_pt,
13037  final_bound_id_connection_to_the_left[i],
13038  final_bound_id_connection_to_the_right[i]);
13039 
13040  // Increase the register for the number of created shared
13041  // polylines
13042  npolylines_counter++;
13043 
13044  // Increase the boundary id (the one that will be used by
13045  // the next shared boundary)
13046  shared_boundary_id_start++;
13047 
13048  } // for (i < n_final_sorted_nodes)
13049 
13050  } // while(nsorted_edges < nedges);
13051 
13052  } // for (jproc < nproc)
13053 
13054  // We already have all the shared polylines (shared boundaries)
13055  // of processor iproc with processor jproc. Now we sort them so
13056  // that they be contiguous and can create polygons.
13057 
13058  // If there are polylines to be sorted then sort them
13059  if (unsorted_polylines_pt[iproc].size() > 0)
13060  {
13061  // Now that we have all the new unsorted polylines on "iproc"
13062  // processor it is time to sort them so they be all contiguous
13063  sort_polylines_helper(unsorted_polylines_pt[iproc],
13064  output_polylines_pt[iproc]);
13065  }
13066 
13067 #ifdef PARANOID
13068  const unsigned nunsorted_polylines_iproc =
13069  unsorted_polylines_pt[iproc].size();
13070 
13071  // Verify that all the polylines have been sorted
13072  unsigned tmp_ntotal_polylines = 0;
13073  // Count the total number of sorted polylines
13074  for (unsigned ii = 0 ; ii < output_polylines_pt[iproc].size(); ii++)
13075  {tmp_ntotal_polylines+= output_polylines_pt[iproc][ii].size();}
13076  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13077  {
13078  std::ostringstream error_message;
13079  error_message
13080  <<" The total number of unsorted polylines ("
13081  << nunsorted_polylines_iproc << ") in common with\nprocessor ("
13082  << iproc<< ") is different from the total number of sorted "
13083  << "polylines (" << tmp_ntotal_polylines << ") with\nthe same "
13084  << "proessor\n";
13085  throw OomphLibError(error_message.str(),
13086  OOMPH_CURRENT_FUNCTION,
13087  OOMPH_EXCEPTION_LOCATION);
13088  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13089 #endif
13090 
13091  } // for (iproc < nproc)
13092 
13093  // Establish the last used boundary id
13094  this->Final_shared_boundary_id = shared_boundary_id_start;
13095 
13096  }
13097 
13098  // ======================================================================
13099  // \short Break any possible loop created by the sorted list of nodes
13100  // that is used to create a new shared polyline
13101  // ======================================================================
13102  template<class ELEMENT>
13104  const unsigned &initial_shd_bnd_id,
13105  std::list<Node*> &input_nodes,
13106  Vector<FiniteElement*> &input_boundary_element_pt,
13107  Vector<int> &input_face_index_element,
13108  const int &input_connect_to_the_left,
13109  const int &input_connect_to_the_right,
13110  Vector<std::list<Node*> > &output_sorted_nodes_pt,
13111  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
13112  Vector<Vector<int> > &output_face_index_element,
13113  Vector<int> &output_connect_to_the_left,
13114  Vector<int> &output_connect_to_the_right)
13115  {
13116  // Get the left and right node of the current list of sorted nodes
13117  Node* left_node_pt = input_nodes.front();
13118  Node* right_node_pt = input_nodes.back();
13119 
13120  // Temporary storage for list of nodes, boundary elements and face
13121  // element's indexes
13122  Vector<std::list<Node*> > tmp_sub_nodes;
13123  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
13124  Vector<Vector<int> > tmp_sub_face_idx_ele;
13125 
13126  // Iterator for the list of input nodes
13127  std::list<Node*>::iterator it = input_nodes.begin();
13128 
13129  // Counter
13130  unsigned counter = 0;
13131 
13132  // Loop while not all nodes have been done
13133  while(it != input_nodes.end())
13134  {
13135  // Check if the current node is the final one
13136  it++;
13137  // Is the current node the final node?
13138  if (it == input_nodes.end())
13139  {
13140  // Break, add no more nodes
13141  break;
13142  }
13143  else
13144  {
13145  // Restore the iterator
13146  it--;
13147  }
13148 
13149  // Get a list of nonrepeated nodes
13150  std::list<Node*> sub_nodes;
13151  // The temporary vector of boundary elements associated with the
13152  // nodes
13153  Vector<FiniteElement*> sub_bnd_ele_pt;
13154  // The temporary vector of face indexes associated with the
13155  // boundary elements
13156  Vector<int> sub_face_idx_ele;
13157 
13158  // Add the current node to the list
13159  sub_nodes.push_back(*it);
13160 
13161  // Add nodes until found a repeated node (the left or right
13162  // node) or until reaching the end of the list of nodes
13163  do
13164  {
13165  // Go to the next node
13166  ++it;
13167 
13168  // Add the new node
13169  sub_nodes.push_back((*it));
13170 
13171  // Add the boundary elements
13172  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13173  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter+1]);
13174 
13175  // Add the face indexes
13176  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13177  sub_face_idx_ele.push_back(input_face_index_element[counter+1]);
13178 
13179  // Increase the counter
13180  counter+=2;
13181 
13182  // Continue adding until reaching a repeated node or the end
13183  // of the list of nodes
13184  }while((*it) != left_node_pt &&
13185  (*it) != right_node_pt &&
13186  it != input_nodes.end());
13187 
13188  // Add the sub-set of nodes to the temporary storage
13189  tmp_sub_nodes.push_back(sub_nodes);
13190  // Add the face elements to the temporary storage
13191  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13192  // Add the face indexes to the temporary storage
13193  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13194 
13195  } // while((*it) != input_nodes.end())
13196 
13197  // --------------------------------------------------
13198  // Now create as many shared boundaries as required
13199 
13200  // Get the number of sub-list of nodes created
13201  const unsigned n_sub_list = tmp_sub_nodes.size();
13202 
13203 #ifdef PARANOID
13204  if (n_sub_list > 3)
13205  {
13206  std::stringstream error_message;
13207  error_message
13208  << "The number of sub-list of nodes created from the shared\n"
13209  << "polyline with loops was (" << n_sub_list << ").\n"
13210  << "We can only handle up to three sub-list of nodes\n";
13211  throw OomphLibError(error_message.str(),
13212  OOMPH_CURRENT_FUNCTION,
13213  OOMPH_EXCEPTION_LOCATION);
13214  }
13215 #endif
13216 
13217  // If there is only one list it may be because there are no loops or
13218  // there is only one loop (a circle)
13219  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13220  {
13221  // There are no loops, return just after filling the data
13222  // structures
13223 
13224  // This is the base case used most of the times
13225 
13226  // Set the vector of lists of nodes
13227  output_sorted_nodes_pt = tmp_sub_nodes;
13228  // Set the vector of boundary elements
13229  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13230  // Set the vector of face indexes
13231  output_face_index_element = tmp_sub_face_idx_ele;
13232 
13233  // Set the connection flags, change them by the proper connection
13234  // flag
13235 
13236 #ifdef PARANOID
13237  if (input_connect_to_the_left == -2)
13238  {
13239  std::stringstream error_message;
13240  error_message
13241  << "The connection flag to the left ("
13242  << input_connect_to_the_left << ") indicates a connection\n"
13243  << "with the same polyline.\n However, only one sub-polyline was "
13244  << "found and no loop\nwas identified\n\n";
13245  throw OomphLibError(error_message.str(),
13246  OOMPH_CURRENT_FUNCTION,
13247  OOMPH_EXCEPTION_LOCATION);
13248  }
13249 #endif
13250 
13251  // The left connection flag
13252  if (input_connect_to_the_left == -3)
13253  {
13254  output_connect_to_the_left.push_back(-1);
13255  }
13256  else
13257  {
13258  output_connect_to_the_left.push_back(input_connect_to_the_left);
13259  }
13260 
13261 #ifdef PARANOID
13262  if (input_connect_to_the_right == -2)
13263  {
13264  std::stringstream error_message;
13265  error_message
13266  << "The connection flag to the right ("
13267  << input_connect_to_the_right << ") indicates a connection\n"
13268  << "with the same polyline.\n However, only one sub-polyline was "
13269  << "found and no loop\nwas identified\n\n";
13270  throw OomphLibError(error_message.str(),
13271  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13272  OOMPH_EXCEPTION_LOCATION);
13273  }
13274 #endif
13275 
13276  // The right connection flag
13277  if (input_connect_to_the_right == -3)
13278  {
13279  output_connect_to_the_right.push_back(-1);
13280  }
13281  else
13282  {
13283  output_connect_to_the_right.push_back(input_connect_to_the_right);
13284  }
13285 
13286  // Return inmediately
13287  return;
13288  }
13289 
13290  // The temporary storage for the shared boundary id
13291  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13292 
13293  // -----------------------------------------------------------------
13294  // Check all the sub-list of nodes and create two shared boundaries
13295  // from those that make a loop (circle)
13296 
13297  // -----------------------------------------------------------
13298  // Get the left and right node of the first sub-list of nodes
13299  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13300  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13301 
13302  // Check if the sub-list of nodes creates a loop (circle)
13303  if (left_sub_node_pt == right_sub_node_pt)
13304  {
13305  // We need to create two shared polylines and therefore increase
13306  // the shared boundary id by two
13307 
13308  // The first and second half of nodes
13309  std::list<Node*> first_half_node_pt;
13310  std::list<Node*> second_half_node_pt;
13311  // The first and second half of boundary elements
13312  Vector<FiniteElement*> first_half_ele_pt;
13313  Vector<FiniteElement*> second_half_ele_pt;
13314  // The first and second half of face indexes
13315  Vector<int> first_half_face_idx;
13316  Vector<int> second_half_face_idx;
13317 
13318  // Get the number of sub-nodes in the sub-list of nodes
13319  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13320 
13321  // The number of sub-nodes for the first half of the shared
13322  // boundary
13323  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13324 
13325  // Copy as many sub-nodes for the first half of the sub-polyline
13326 
13327  // Iterator to loop over the nodes
13328  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13329 
13330  // Add the first node
13331  first_half_node_pt.push_back(*it_sub);
13332 
13333  // Skip the first node
13334  it_sub++;
13335 
13336  // Counter
13337  unsigned counter_nodes = 0;
13338  unsigned counter2 = 0;
13339 
13340  // Loop to copy the nodes
13341  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13342  {
13343  // Add the sub-node to the first half
13344  first_half_node_pt.push_back(*it_sub);
13345 
13346  // Add the boundary elements of the first half
13347  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13348  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13349  // Add the face indexes of the first half
13350  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13351  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13352 
13353  // Increase the counter of added nodes
13354  counter_nodes++;
13355 
13356  // Increase the other counter
13357  counter2+=2;
13358 
13359  if (counter_nodes == n_sub_nodes_half)
13360  {
13361  // Stop adding to the first half of nodes
13362  break;
13363  }
13364 
13365  } // Copy the first half of nodes
13366 
13367  // The second half
13368 
13369  // Add the first node of the second half
13370  second_half_node_pt.push_back(*it_sub);
13371 
13372  // Skip the first node of the second half
13373  it_sub++;
13374 
13375  // Loop to copy the nodes
13376  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13377  {
13378  // Add the sub-node to the first half
13379  second_half_node_pt.push_back(*it_sub);
13380 
13381  // Add the boundary elements of the first half
13382  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13383  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13384  // Add the face indexes of the first half
13385  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13386  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13387 
13388  // Increase the other counter
13389  counter2+=2;
13390 
13391  } // Copy the second half of nodes
13392 
13393  // Add the sub-list of nodes to the vector of lists of nodes
13394  output_sorted_nodes_pt.push_back(first_half_node_pt);
13395  output_sorted_nodes_pt.push_back(second_half_node_pt);
13396  // Add the sub-vector of elements to the vector of boundary
13397  // elements
13398  output_boundary_element_pt.push_back(first_half_ele_pt);
13399  output_boundary_element_pt.push_back(second_half_ele_pt);
13400  // Add the sub-vector of face indexes to the vector of face
13401  // indexes
13402  output_face_index_element.push_back(first_half_face_idx);
13403  output_face_index_element.push_back(second_half_face_idx);
13404 
13405  // Set the connection flags, change them by the proper connection
13406  // flag
13407 
13408  // ----------------------------------------------------------------
13409  // Connections flags for the first half
13410 
13411  // The left connection flag
13412 
13413  // Connected with nothing but required to stop adding nodes
13414  if (input_connect_to_the_left == -3)
13415  {
13416  // Set connected to nothing
13417  output_connect_to_the_left.push_back(-1);
13418  }
13419  // Connected with itself
13420  else if (input_connect_to_the_left == -2)
13421  {
13422  // Set connected to nothing, this is the base node
13423  output_connect_to_the_left.push_back(-1);
13424  }
13425  else
13426  {
13427  // Any other value keep it
13428  output_connect_to_the_left.push_back(input_connect_to_the_left);
13429  }
13430 
13431  // The right connection flag
13432 
13433  // Set connected to nothing, this is the base node
13434  output_connect_to_the_right.push_back(-1);
13435 
13436  // Increase the shared boundary id
13437  tmp_shd_bnd_id++;
13438 
13439  // ----------------------------------------------------------------
13440  // Connections flags for the second half
13441 
13442  // The left connection flag
13443 
13444  // Set connected to the previous boundary
13445  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13446 
13447  // The right connection flag
13448 
13449  // Are we in the last sub-list of nodes, if that is the case we
13450  // need to respect the flag assigned to the right
13451  if (n_sub_list == 1)
13452  {
13453  if (input_connect_to_the_right == -3)
13454  {
13455  // Set connected to the previous shared boundary id
13456  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13457  }
13458  else if (input_connect_to_the_right == -2)
13459  {
13460  // Set connected to the previous shared boundary id
13461  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13462  }
13463  else if (input_connect_to_the_right == -1)
13464  {
13465  // Set connected to the previous shared boundary id
13466  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13467  }
13468  else
13469  {
13470  // Any other value keep it
13471  output_connect_to_the_right.push_back(input_connect_to_the_right);
13472  }
13473  } // if (n_sub_list == 1)
13474  else
13475  {
13476  // Set connected to the previous shared boundary id
13477  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13478  }
13479 
13480  // Increase the shared boundary id
13481  tmp_shd_bnd_id++;
13482 
13483  } // if (left_sub_node_pt == right_sub_node_pt)
13484  else
13485  {
13486  // No need to create two boundaries, create only one with the
13487  // sub-list of nodes
13488 
13489  // Add the sub-list of nodes to the vector of lists of nodes
13490  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13491  // Add the sub-vector of elements to the vector of boundary
13492  // elements
13493  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13494  // Add the sub-vector of face indexes to the vector of face
13495  // indexes
13496  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13497 
13498  // Set the connection flags, change them by the proper connection
13499  // flag
13500 
13501  // The left connection flag
13502 
13503  // Connected with nothing but required to stop adding nodes
13504  if (input_connect_to_the_left == -3)
13505  {
13506  // Set to connected to nothing
13507  output_connect_to_the_left.push_back(-1);
13508  }
13509  // Connected with itself
13510  else if (input_connect_to_the_left == -2)
13511  {
13512  // Set connected to the next shared polyline id
13513  output_connect_to_the_left.push_back(tmp_shd_bnd_id+1);
13514  }
13515  else
13516  {
13517  // Any other value keep it
13518  output_connect_to_the_left.push_back(input_connect_to_the_left);
13519  }
13520 
13521  // The right connection flag
13522 
13523  // Set connected to the next shared polyline id
13524  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13525 
13526  // Increase the shared boundary id by one
13527  tmp_shd_bnd_id++;
13528 
13529  } // else if (left_sub_node_pt == right_sub_node_pt)
13530 
13531  // At least two sub-list of nodes were created
13532  if (n_sub_list > 1)
13533  {
13534  // ------------------------------------------------------------
13535  // Get the left and right node of the second sub-list of nodes
13536  left_sub_node_pt = tmp_sub_nodes[1].front();
13537  right_sub_node_pt = tmp_sub_nodes[1].back();
13538 
13539  // Check if the sub-list of nodes creates a loop (circle)
13540  if (left_sub_node_pt == right_sub_node_pt)
13541  {
13542  // We need to create two shared polylines and therefore increase
13543  // the shared boundary id by two
13544 
13545  // The first and second half of nodes
13546  std::list<Node*> first_half_node_pt;
13547  std::list<Node*> second_half_node_pt;
13548  // The first and second half of boundary elements
13549  Vector<FiniteElement*> first_half_ele_pt;
13550  Vector<FiniteElement*> second_half_ele_pt;
13551  // The first and second half of face indexes
13552  Vector<int> first_half_face_idx;
13553  Vector<int> second_half_face_idx;
13554 
13555  // Get the number of sub-nodes in the sub-list of nodes
13556  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13557 
13558  // The number of sub-nodes for the first half of the shared
13559  // boundary
13560  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13561 
13562  // Copy as many sub-nodes for the first half of the sub-polyline
13563 
13564  // Iterator to loop over the nodes
13565  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13566 
13567  // Add the first node
13568  first_half_node_pt.push_back(*it_sub);
13569 
13570  // Skip the first node
13571  it_sub++;
13572 
13573  // Counter
13574  unsigned counter_nodes = 0;
13575  unsigned counter2 = 0;
13576 
13577  // Loop to copy the nodes
13578  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13579  {
13580  // Add the sub-node to the first half
13581  first_half_node_pt.push_back(*it_sub);
13582  // Add the boundary elements of the first half
13583  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13584  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13585  // Add the face indexes of the first half
13586  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13587  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13588 
13589  // Increase the counter of added nodes
13590  counter_nodes++;
13591 
13592  // Increase the other counter
13593  counter2+=2;
13594 
13595  if (counter_nodes == n_sub_nodes_half)
13596  {
13597  // Stop adding to the first half of nodes
13598  break;
13599  }
13600 
13601  } // Copy the first half of nodes
13602 
13603  // The second half
13604 
13605  // Add the first node of the second half
13606  second_half_node_pt.push_back(*it_sub);
13607 
13608  // Skip the first node of the second half
13609  it_sub++;
13610 
13611  // Loop to copy the nodes
13612  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13613  {
13614  // Add the sub-node to the first half
13615  second_half_node_pt.push_back(*it_sub);
13616  // Add the boundary elements of the first half
13617  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13618  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13619  // Add the face indexes of the first half
13620  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13621  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13622 
13623  // Increase the other counter
13624  counter2+=2;
13625 
13626  } // Copy the second half of nodes
13627 
13628  // Add the sub-list of nodes to the vector of lists of nodes
13629  output_sorted_nodes_pt.push_back(first_half_node_pt);
13630  output_sorted_nodes_pt.push_back(second_half_node_pt);
13631  // Add the sub-vector of elements to the vector of boundary
13632  // elements
13633  output_boundary_element_pt.push_back(first_half_ele_pt);
13634  output_boundary_element_pt.push_back(second_half_ele_pt);
13635  // Add the sub-vector of face indexes to the vector of face
13636  // indexes
13637  output_face_index_element.push_back(first_half_face_idx);
13638  output_face_index_element.push_back(second_half_face_idx);
13639 
13640  // Set the connection flags, change them by the proper
13641  // connection flag
13642 
13643  // --------------------------------------
13644  // Connections flags for the first half
13645 
13646  // The left connection flag
13647 
13648  // Connected to the previous boundary
13649  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13650 
13651  // The right connection flag
13652 
13653  // Set connected to nothing, this is the base node
13654  output_connect_to_the_right.push_back(-1);
13655 
13656  // Increase the shared boundary id
13657  tmp_shd_bnd_id++;
13658 
13659  // --------------------------------------
13660  // Connections flags for the second half
13661 
13662  // The left connection flag
13663 
13664  // Set connected to the previous boundary
13665  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13666 
13667  // The right connection flag
13668 
13669  // Are we in the last sub-list of nodes, if that is the case we
13670  // need to respect the flag assigned to the right
13671  if (n_sub_list == 2)
13672  {
13673  // Connected with nothing
13674  if (input_connect_to_the_right == -1)
13675  {
13676  // Set connected to the previous shared boundary
13677  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13678  }
13679  // Connected with the same boundary
13680  else if (input_connect_to_the_right == -2)
13681  {
13682  // Set connected to the previous shared boundary
13683  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13684  }
13685  // Connetted with nothing but stop adding nodes
13686  else if (input_connect_to_the_right == -3)
13687  {
13688  // Set connected to the previous shared boundary
13689  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13690  }
13691  else
13692  {
13693  // Any other value keep it
13694  output_connect_to_the_right.push_back(input_connect_to_the_right);
13695  }
13696 
13697  // Increase the shared boundary id
13698  tmp_shd_bnd_id++;
13699 
13700  } // if (n_sub_list == 2)
13701 #ifdef PARANOID
13702  else
13703  {
13704  std::stringstream error_message;
13705  error_message
13706  << "The second sub-list of nodes creates a loop but this is not\n"
13707  << "the last list of sub-nodes.\n"
13708  << "This configuration is not supported\n";
13709  throw OomphLibError(error_message.str(),
13710  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13711  OOMPH_EXCEPTION_LOCATION);
13712  }
13713 #endif
13714 
13715  } // if (left_sub_node_pt == right_sub_node_pt)
13716  else
13717  {
13718  // No need to create two boundaries, create only one with the
13719  // sub-list of nodes
13720 
13721  // Add the sub-list of nodes to the vector of lists of nodes
13722  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13723  // Add the sub-vector of elements to the vector of boundary
13724  // elements
13725  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13726  // Add the sub-vector of face indexes to the vector of face
13727  // indexes
13728  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13729 
13730  // Set the connection flags, change them by the proper connection
13731  // flag
13732 
13733  // The left connection flag
13734 
13735  // Set connected to the previous shared boundary id
13736  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13737 
13738  // The right connection flag
13739 
13740  // Are we in the last sub-list of nodes, if that is the case we
13741  // need to respect the flag assigned to the right
13742  if (n_sub_list == 2)
13743  {
13744  // Connected with nothing but required to stop adding nodes
13745  if (input_connect_to_the_right == -3)
13746  {
13747  // Set to connected to nothing
13748  output_connect_to_the_right.push_back(-1);
13749  }
13750 #ifdef PARANOID
13751  // Connected with itself
13752  else if (input_connect_to_the_right == -2)
13753  {
13754  std::stringstream error_message;
13755  error_message
13756  << "The connection flag to the right ("
13757  << input_connect_to_the_right << ") indicates a connection\n"
13758  << "with the same polyline.\n However, the second sub-list of\n"
13759  << "nodes was found not making a loop so no connection with\n"
13760  << "itself should be marked\n\n";
13761  throw OomphLibError(error_message.str(),
13762  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13763  OOMPH_EXCEPTION_LOCATION);
13764  }
13765 #endif
13766  else
13767  {
13768  // Any other value keep it
13769  output_connect_to_the_right.push_back(input_connect_to_the_right);
13770  }
13771  } // if (n_sub_list == 2)
13772  else
13773  {
13774  // Set connected to the next shared boundary id
13775  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13776  } // else if (n_sub_list == 2)
13777 
13778  // Increase the shared boundary id by one
13779  tmp_shd_bnd_id++;
13780 
13781  } // if (left_sub_node_pt == right_sub_node_pt)
13782 
13783  } // if (n_sub_list > 1)
13784 
13785  // Three sub-list of nodes were created
13786  if (n_sub_list > 2)
13787  {
13788  // ------------------------------------------------------------
13789  // Get the left and right node of the third sub-list of nodes
13790  left_sub_node_pt = tmp_sub_nodes[2].front();
13791  right_sub_node_pt = tmp_sub_nodes[2].back();
13792 
13793  // Check if the sub-list of nodes creates a loop (circle)
13794  if (left_sub_node_pt == right_sub_node_pt)
13795  {
13796  // We need to create two shared polylines and therefore increase
13797  // the shared boundary id by two
13798 
13799  // The first and second half of nodes
13800  std::list<Node*> first_half_node_pt;
13801  std::list<Node*> second_half_node_pt;
13802  // The first and second half of boundary elements
13803  Vector<FiniteElement*> first_half_ele_pt;
13804  Vector<FiniteElement*> second_half_ele_pt;
13805  // The first and second half of face indexes
13806  Vector<int> first_half_face_idx;
13807  Vector<int> second_half_face_idx;
13808 
13809  // Get the number of sub-nodes in the sub-list of nodes
13810  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13811 
13812  // The number of sub-nodes for the first half of the shared
13813  // boundary
13814  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13815 
13816  // Copy as many sub-nodes for the first half of the sub-polyline
13817 
13818  // Iterator to loop over the nodes
13819  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13820 
13821  // Add the first node
13822  first_half_node_pt.push_back(*it_sub);
13823 
13824  // Skip the first node
13825  it_sub++;
13826 
13827  // Counter
13828  unsigned counter_nodes = 0;
13829  unsigned counter2 = 0;
13830 
13831  // Loop to copy the nodes
13832  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13833  {
13834  // Add the sub-node to the first half
13835  first_half_node_pt.push_back(*it_sub);
13836  // Add the boundary elements of the first half
13837  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13838  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13839  // Add the face indexes of the first half
13840  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13841  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13842 
13843  // Increase the counter of added nodes
13844  counter_nodes++;
13845 
13846  // Increase the other counter
13847  counter2+=2;
13848 
13849  if (counter_nodes == n_sub_nodes_half)
13850  {
13851  // Stop adding to the first half of nodes
13852  break;
13853  }
13854 
13855  } // Copy the first half of nodes
13856 
13857  // The second half
13858 
13859  // Add the first node of the second half
13860  second_half_node_pt.push_back(*it_sub);
13861 
13862  // Skip the first node of the second half
13863  it_sub++;
13864 
13865  // Loop to copy the nodes
13866  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13867  {
13868  // Add the sub-node to the first half
13869  second_half_node_pt.push_back(*it_sub);
13870  // Add the boundary elements of the first half
13871  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13872  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13873  // Add the face indexes of the first half
13874  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13875  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13876 
13877  // Increase the other counter
13878  counter2+=2;
13879 
13880  } // Copy the second half of nodes
13881 
13882  // Add the sub-list of nodes to the vector of lists of nodes
13883  output_sorted_nodes_pt.push_back(first_half_node_pt);
13884  output_sorted_nodes_pt.push_back(second_half_node_pt);
13885  // Add the sub-vector of elements to the vector of boundary
13886  // elements
13887  output_boundary_element_pt.push_back(first_half_ele_pt);
13888  output_boundary_element_pt.push_back(second_half_ele_pt);
13889  // Add the sub-vector of face indexes to the vector of face
13890  // indexes
13891  output_face_index_element.push_back(first_half_face_idx);
13892  output_face_index_element.push_back(second_half_face_idx);
13893 
13894  // --------------------------------------
13895  // Connections flags for the first half
13896 
13897  // The left connection flag
13898 
13899  // Connected to the previous shared boundary
13900  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13901 
13902  // The right connection flag
13903 
13904  // Set connected to nothing, this is the base node
13905  output_connect_to_the_right.push_back(-1);
13906 
13907  // Increase the shared boundary id
13908  tmp_shd_bnd_id++;
13909 
13910  // --------------------------------------
13911  // Connections flags for the second half
13912 
13913  // The left connection flag
13914 
13915  // Set connected to the previous boundary
13916  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13917 
13918  // The right connection flag
13919 
13920  if (input_connect_to_the_right == -3)
13921  {
13922  // Set connected to the previous shared boundary id
13923  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13924  }
13925  else if (input_connect_to_the_right == -2)
13926  {
13927  // Set connected to the previous shared boundary id
13928  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13929  }
13930  else if (input_connect_to_the_right == -1)
13931  {
13932  // Set connected to the previous shared boundary id
13933  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13934  }
13935  else
13936  {
13937  // Any other value keep it
13938  output_connect_to_the_right.push_back(input_connect_to_the_right);
13939  }
13940 
13941  // Increase the shared boundary id
13942  tmp_shd_bnd_id++;
13943 
13944  } // if (left_sub_node_pt == right_sub_node_pt)
13945  else
13946  {
13947  // No need to create two boundaries, create only one with the
13948  // sub-list of nodes
13949 
13950  // Add the sub-list of nodes to the vector of lists of nodes
13951  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
13952  // Add the sub-vector of elements to the vector of boundary
13953  // elements
13954  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
13955  // Add the sub-vector of face indexes to the vector of face
13956  // indexes
13957  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
13958 
13959  // Set the connection flags, change them by the proper
13960  // connection flag
13961 
13962  // The left connection flag
13963 
13964  // Set connected to the previous shared boundary id
13965  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13966 
13967  // The right connection flag
13968 
13969  // Connected with nothing but required to stop adding nodes
13970  if (input_connect_to_the_right == -3)
13971  {
13972  std::stringstream error_message;
13973  error_message
13974  << "The connection flag to the right ("
13975  << input_connect_to_the_right << ") indicates 'no connection and\n"
13976  << "stop adding nodes'.\n However, the thrid sub-list of\n"
13977  << "nodes must have a connection to the right with the same\n"
13978  << "shared polyline or with any other polyline\n\n";
13979  throw OomphLibError(error_message.str(),
13980  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13981  OOMPH_EXCEPTION_LOCATION);
13982  }
13983  else if (input_connect_to_the_right == -1)
13984  {
13985  std::stringstream error_message;
13986  error_message
13987  << "The connection flag to the right ("
13988  << input_connect_to_the_right << ") indicates 'no connection.\n"
13989  << "However, the thrid sub-list of nodes must have a connection\n"
13990  << "to the right with the same shared polyline or with any other\n"
13991  << "polyline\n\n";
13992  throw OomphLibError(error_message.str(),
13993  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13994  OOMPH_EXCEPTION_LOCATION);
13995  }
13996  // Connected with itself
13997  else if (input_connect_to_the_right == -2)
13998  {
13999  // Set connected to the previous shared boundary id
14000  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14001  }
14002  else
14003  {
14004  // Any other value keep it
14005  output_connect_to_the_right.push_back(input_connect_to_the_right);
14006  }
14007 
14008  // Increase the shared boundary id by one
14009  tmp_shd_bnd_id++;
14010 
14011  } // if (left_sub_node_pt == right_sub_node_pt)
14012 
14013  } // if (n_sub_list > 2)
14014 
14015  }
14016 
14017  // ======================================================================
14018  // \short Break any possible loop created by the sorted list of nodes
14019  // that is used to create a new shared polyline
14020  // ======================================================================
14021  template<class ELEMENT>
14024  const unsigned &initial_shd_bnd_id,
14025  std::list<Node*> &input_nodes,
14026  Vector<FiniteElement*> &input_boundary_element_pt,
14027  Vector<FiniteElement*> &input_boundary_face_element_pt,
14028  Vector<int> &input_face_index_element,
14029  const int &input_connect_to_the_left,
14030  const int &input_connect_to_the_right,
14031  Vector<std::list<Node*> > &output_sorted_nodes_pt,
14032  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
14033  Vector<Vector<FiniteElement*> > &output_boundary_face_element_pt,
14034  Vector<Vector<int> > &output_face_index_element,
14035  Vector<int> &output_connect_to_the_left,
14036  Vector<int> &output_connect_to_the_right)
14037  {
14038  // Get the left and right node of the current list of sorted nodes
14039  Node* left_node_pt = input_nodes.front();
14040  Node* right_node_pt = input_nodes.back();
14041 
14042  // Temporary storage for list of nodes, boundary elements, boundary
14043  // face elements and face element's indexes
14044  Vector<std::list<Node*> > tmp_sub_nodes;
14045  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
14046  Vector<Vector<FiniteElement*> > tmp_sub_bnd_face_ele_pt;
14047  Vector<Vector<int> > tmp_sub_face_idx_ele;
14048 
14049  // Iterator for the list of input nodes
14050  std::list<Node*>::iterator it = input_nodes.begin();
14051 
14052  // Counter
14053  unsigned counter = 0;
14054 
14055  // Loop while not all nodes have been done
14056  while(it != input_nodes.end())
14057  {
14058  // Check if the current node is the final one
14059  it++;
14060  // Is the current node the final node?
14061  if (it == input_nodes.end())
14062  {
14063  // Break, add no more nodes
14064  break;
14065  }
14066  else
14067  {
14068  // Restore the iterator
14069  it--;
14070  }
14071 
14072  // Get a list of nonrepeated nodes
14073  std::list<Node*> sub_nodes;
14074  // The temporary vector of boundary elements associated with the
14075  // nodes
14076  Vector<FiniteElement*> sub_bnd_ele_pt;
14077  // The temporary vector of boundary face elements associated with
14078  // the nodes
14079  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14080  // The temporary vector of face indexes associated with the
14081  // boundary elements
14082  Vector<int> sub_face_idx_ele;
14083 
14084  // Add the current node to the list
14085  sub_nodes.push_back(*it);
14086 
14087  // Add nodes until found a repeated node (the left or right
14088  // node) or until reaching the end of the list of nodes
14089  do
14090  {
14091  // Go to the next node
14092  ++it;
14093 
14094  // Add the new node
14095  sub_nodes.push_back((*it));
14096 
14097  // Add the boundary elements
14098  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14099 
14100  // Add the boundary face elements
14101  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14102 
14103  // Add the face indexes
14104  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14105 
14106  // Increase the counter
14107  counter++;
14108 
14109  // Continue adding until reaching a repeated node or the end
14110  // of the list of nodes
14111  }while((*it) != left_node_pt &&
14112  (*it) != right_node_pt &&
14113  it != input_nodes.end());
14114 
14115  // Add the sub-set of nodes to the temporary storage
14116  tmp_sub_nodes.push_back(sub_nodes);
14117 
14118  // Add the boundary elements to the temporary storage
14119  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14120  // Add the boundary face elements to the temporary storage
14121  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14122  // Add the face indexes to the temporary storage
14123  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14124 
14125  } // while((*it) != input_nodes.end())
14126 
14127  // --------------------------------------------------
14128  // Now create as many shared boundaries as required
14129 
14130  // Get the number of sub-list of nodes created
14131  const unsigned n_sub_list = tmp_sub_nodes.size();
14132 
14133 #ifdef PARANOID
14134  if (n_sub_list > 1)
14135  {
14136  std::stringstream error_message;
14137  error_message
14138  << "The number of sub-list of nodes created from the shared\n"
14139  << "polyline with loops was (" << n_sub_list << ").\n"
14140  << "We can only handle one list which may still contain loops\n"
14141  << "(or repeated nodes)\n";
14142  throw OomphLibError(error_message.str(),
14143  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14144  OOMPH_EXCEPTION_LOCATION);
14145  }
14146 #endif
14147 
14148  // If there is only one list it may be because there are no loops or
14149  // there is only one loop (a circle)
14150  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14151  {
14152  // There are no loops, return just after filling the data
14153  // structures
14154 
14155  // This is the base case used most of the times
14156 
14157  // Set the vector of lists of nodes
14158  output_sorted_nodes_pt = tmp_sub_nodes;
14159  // Set the vector of boundary elements
14160  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14161  // Set the vector of boundary face elements
14162  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14163  // Set the vector of face indexes
14164  output_face_index_element = tmp_sub_face_idx_ele;
14165 
14166  // Set the connection flags, change them by the proper connection
14167  // flag
14168 
14169 #ifdef PARANOID
14170  if (input_connect_to_the_left == -2)
14171  {
14172  std::stringstream error_message;
14173  error_message
14174  << "The connection flag to the left ("
14175  << input_connect_to_the_left << ") indicates a connection\n"
14176  << "with the same polyline.\n However, only one sub-polyline was "
14177  << "found and no loops\nwere identified\n\n";
14178  throw OomphLibError(error_message.str(),
14179  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14180  OOMPH_EXCEPTION_LOCATION);
14181  }
14182 #endif
14183 
14184  // The left connection flag
14185  if (input_connect_to_the_left == -3)
14186  {
14187  output_connect_to_the_left.push_back(-1);
14188  }
14189  else
14190  {
14191  output_connect_to_the_left.push_back(input_connect_to_the_left);
14192  }
14193 
14194 #ifdef PARANOID
14195  if (input_connect_to_the_right == -2)
14196  {
14197  std::stringstream error_message;
14198  error_message
14199  << "The connection flag to the right ("
14200  << input_connect_to_the_right << ") indicates a connection\n"
14201  << "with the same polyline.\n However, only one sub-polyline was "
14202  << "found and no loops\nwere identified\n\n";
14203  throw OomphLibError(error_message.str(),
14204  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14205  OOMPH_EXCEPTION_LOCATION);
14206  }
14207 #endif
14208 
14209  // The right connection flag
14210  if (input_connect_to_the_right == -3)
14211  {
14212  output_connect_to_the_right.push_back(-1);
14213  }
14214  else
14215  {
14216  output_connect_to_the_right.push_back(input_connect_to_the_right);
14217  }
14218 
14219  // Return immediately
14220  return;
14221  }
14222 
14223  // The temporary storage for the shared boundary id
14224  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14225 
14226  // -----------------------------------------------------------------
14227  // Check all the sub-list of nodes and create two shared boundaries
14228  // from those that make a loop (circle)
14229 
14230  // -----------------------------------------------------------
14231  // Get the left and right node of the first sub-list of nodes
14232  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14233  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14234 
14235  // Check if the sub-list of nodes creates a loop (circle)
14236  if (left_sub_node_pt == right_sub_node_pt)
14237  {
14238  // We need to create two shared polylines and therefore increase
14239  // the shared boundary id by two
14240 
14241  // The first and second half of nodes
14242  std::list<Node*> first_half_node_pt;
14243  std::list<Node*> second_half_node_pt;
14244  // The first and second half of boundary elements
14245  Vector<FiniteElement*> first_half_ele_pt;
14246  Vector<FiniteElement*> second_half_ele_pt;
14247  // The first and second half of boundary face elements
14248  Vector<FiniteElement*> first_half_ele_face_pt;
14249  Vector<FiniteElement*> second_half_ele_face_pt;
14250  // The first and second half of face indexes
14251  Vector<int> first_half_face_idx;
14252  Vector<int> second_half_face_idx;
14253 
14254  // Get the number of sub-nodes in the sub-list of nodes
14255  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14256 
14257  // The number of sub-nodes for the first half of the shared
14258  // boundary
14259  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
14260 
14261  // Copy as many sub-nodes for the first half of the sub-polyline
14262 
14263  // Iterator to loop over the nodes
14264  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14265 
14266  // Add the first node
14267  first_half_node_pt.push_back(*it_sub);
14268 
14269  // Skip the first node
14270  it_sub++;
14271 
14272  // Counter
14273  unsigned counter_nodes = 0;
14274  unsigned counter2 = 0;
14275 
14276  // Loop to copy the nodes
14277  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14278  {
14279  // Add the sub-node to the first half
14280  first_half_node_pt.push_back(*it_sub);
14281 
14282  // Add the boundary elements of the first half
14283  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14284  // Add the boundary face elements of the first half
14285  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14286  // Add the face indexes of the first half
14287  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14288 
14289  // Increase the counter of added nodes
14290  counter_nodes++;
14291 
14292  // Increase the other counter (of the elements/face)
14293  counter2++;
14294 
14295  if (counter_nodes == n_sub_nodes_half)
14296  {
14297  // Stop adding to the first half of nodes
14298  break;
14299  }
14300 
14301  } // Copy the first half of nodes
14302 
14303  // The second half
14304 
14305  // Add the first node of the second half
14306  second_half_node_pt.push_back(*it_sub);
14307 
14308  // Skip the first node of the second half
14309  it_sub++;
14310 
14311  // Loop to copy the nodes
14312  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14313  {
14314  // Add the sub-node to the first half
14315  second_half_node_pt.push_back(*it_sub);
14316 
14317  // Add the boundary elements of the first half
14318  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14319  // Add the boundary face elements of the first half
14320  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14321  // Add the face indexes of the first half
14322  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14323 
14324  // Increase the other counter
14325  counter2++;
14326 
14327  } // Copy the second half of nodes
14328 
14329  // Add the sub-list of nodes to the vector of lists of nodes
14330  output_sorted_nodes_pt.push_back(first_half_node_pt);
14331  output_sorted_nodes_pt.push_back(second_half_node_pt);
14332  // Add the sub-vector of elements to the vector of boundary
14333  // elements
14334  output_boundary_element_pt.push_back(first_half_ele_pt);
14335  output_boundary_element_pt.push_back(second_half_ele_pt);
14336  // Add the sub-vector of face elements to the vector of boundary
14337  // elements
14338  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14339  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14340  // Add the sub-vector of face indexes to the vector of face
14341  // indexes
14342  output_face_index_element.push_back(first_half_face_idx);
14343  output_face_index_element.push_back(second_half_face_idx);
14344 
14345  // Set the connection flags, change them by the proper connection
14346  // flag
14347 
14348  // ----------------------------------------------------------------
14349  // Connections flags for the first half
14350 
14351  // The left connection flag
14352 
14353  // Connected with nothing but required to stop adding nodes
14354  if (input_connect_to_the_left == -3)
14355  {
14356  // Set connected to nothing
14357  output_connect_to_the_left.push_back(-1);
14358  }
14359  // Connected with itself
14360  else if (input_connect_to_the_left == -2)
14361  {
14362  // Set connected to nothing, this is the base node
14363  output_connect_to_the_left.push_back(-1);
14364  }
14365  else
14366  {
14367  // Any other value keep it
14368  output_connect_to_the_left.push_back(input_connect_to_the_left);
14369  }
14370 
14371  // The right connection flag
14372 
14373  // Set connected to nothing, this is the base node
14374  output_connect_to_the_right.push_back(-1);
14375 
14376  // Increase the shared boundary id
14377  tmp_shd_bnd_id++;
14378 
14379  // ----------------------------------------------------------------
14380  // Connections flags for the second half
14381 
14382  // The left connection flag
14383 
14384  // Set connected to the previous boundary
14385  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
14386 
14387  // The right connection flag
14388 
14389  // Are we in the last sub-list of nodes, if that is the case we
14390  // need to respect the flag assigned to the right
14391  if (n_sub_list == 1)
14392  {
14393  if (input_connect_to_the_right == -3)
14394  {
14395  // Set connected to the previous shared boundary id
14396  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14397  }
14398  else if (input_connect_to_the_right == -2)
14399  {
14400  // Set connected to the previous shared boundary id
14401  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14402  }
14403  else if (input_connect_to_the_right == -1)
14404  {
14405  // Set connected to the previous shared boundary id
14406  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14407  }
14408  else
14409  {
14410  // Any other value keep it
14411  output_connect_to_the_right.push_back(input_connect_to_the_right);
14412  }
14413  } // if (n_sub_list == 1)
14414  else
14415  {
14416  // Set connected to the previous shared boundary id
14417  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14418  }
14419 
14420  // Increase the shared boundary id
14421  tmp_shd_bnd_id++;
14422 
14423  } // if (left_sub_node_pt == right_sub_node_pt)
14424 #ifdef PARANOID
14425  else
14426  {
14427  std::stringstream error_message;
14428  error_message
14429  << "The initial and final node in the current shared polyline are not\n"
14430  << "the same and the number of sublists is ("<< n_sub_list << ").\n"
14431  << "We can not handle more than one sublist in the method to break\n"
14432  << "loops at the load balance stage\n\n";
14433  throw OomphLibError(error_message.str(),
14434  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14435  OOMPH_EXCEPTION_LOCATION);
14436  }
14437 #endif
14438 
14439  }
14440 
14441  // ======================================================================
14442  // \short Create the shared polyline and fill the data structured
14443  // that keep all the information associated with the creationg of the
14444  // shared boundary
14445  // ======================================================================
14446  template<class ELEMENT>
14448  create_shared_polyline(const unsigned &my_rank,
14449  const unsigned &shd_bnd_id,
14450  const unsigned &iproc,
14451  const unsigned &jproc,
14452  std::list<Node*> &sorted_nodes,
14453  const int &root_edge_bnd_id,
14454  Vector<FiniteElement*> &bulk_bnd_ele_pt,
14455  Vector<int> &face_index_ele,
14457  &unsorted_polylines_pt,
14458  const int &connect_to_the_left_flag,
14459  const int &connect_to_the_right_flag)
14460  {
14461  // ----------------------------------------------------------------
14462  // Associate the shared boundary with the respective processors
14463  // ----------------------------------------------------------------
14464 
14465  // Setup the global look-up scheme, where all processors know the
14466  // associations of others processors and the shared boundaries they
14467  // created
14468 
14469  // Set up the boundary shared by "iproc" with "jproc" processor
14470  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14471 
14472  // Set up the boundary shared by "jproc" with "iproc" processor
14473  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14474 
14475  // Specify the processors involved on the creation of the shared
14476  // boundary
14477  Vector<unsigned> processors(2);
14478  processors[0] = iproc;
14479  processors[1] = jproc;
14480  Shared_boundary_from_processors[shd_bnd_id] = processors;
14481 
14482  // ----------------------------------------------------------------
14483  // If one of the processor associated with the shared boundary is
14484  // the current processor then it needs to create a polyline from the
14485  // input sorted nodes, other processors can skip this part
14486  if (iproc == my_rank || jproc == my_rank)
14487  {
14488  // ------------------------------------------------------------
14489  // Create a vertices representation from the sorted nodes list
14490  // ------------------------------------------------------------
14491 
14492  // Get the number of nodes on the list
14493  const unsigned n_nodes = sorted_nodes.size();
14494  // The vector to store the vertices (assign space)
14495  Vector<Vector<double> > vertices(n_nodes);
14496 
14497  // Copy the vertices from the nodes
14498  unsigned counter = 0;
14499 
14500  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14501  it != sorted_nodes.end(); it++)
14502  {
14503  vertices[counter].resize(2);
14504  vertices[counter][0] = (*it)->x(0);
14505  vertices[counter][1] = (*it)->x(1);
14506  counter++;
14507  }
14508 
14509  // ---------------------------------------------
14510  // Create the polyline from the input vertices
14511  // ---------------------------------------------
14512  TriangleMeshPolyLine *polyline_pt =
14513  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14514 
14515  // ---------------------------------------------
14516  // Establish the internal boundary information
14517  // ---------------------------------------------
14518 
14519  // Check if the shared boundary is overlapping (or is part) of an
14520  // internal boundary
14521  if (root_edge_bnd_id != -1)
14522  {
14523  // If the shared boundary is part of an internal boundary then
14524  // mark the shared boundary
14525  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14526  static_cast<unsigned>(root_edge_bnd_id);
14527  } // if (root_edge_bnd_id != -1)
14528 
14529  // ---------------------------------------------
14530  // Store the boundary elements and face indexes
14531  // ---------------------------------------------
14532 
14533  // Store the shared boundary elements
14534  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14535 #ifdef PARANOID
14536  // Check that the number of shared boundy elements is the same as
14537  // the number of face indexes
14538  const unsigned n_face_index = face_index_ele.size();
14539  if (n_shared_boundary_elements != n_face_index)
14540  {
14541  std::ostringstream error_message;
14542  error_message
14543  << "The number of shared boundary elements is different from the\n"
14544  << "number of face indexes associated to the shared boundary\n"
14545  << "elements\n"
14546  << "Number of shared boundary elements: ("
14547  << n_shared_boundary_elements << ")\n"
14548  << "Number of face indexes: (" << n_face_index << ")\n\n";
14549  throw OomphLibError(error_message.str(),
14550  "TriangleMesh::create_shared_polyline()",
14551  OOMPH_EXCEPTION_LOCATION);
14552  } // if (n_shared_boundary_elements != n_face_index)
14553 #endif
14554 
14555  // Add the shared boundary elements and their respective face
14556  // indexes to their permanent containers
14557  for (unsigned i = 0 ; i < n_shared_boundary_elements; i++)
14558  {
14559  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14560  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14561  } // for (i < nshared_boundary_elements)
14562 
14563  // Store the shared boundary nodes
14564  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14565  it != sorted_nodes.end(); it++)
14566  {
14567  add_shared_boundary_node(shd_bnd_id, (*it));
14568  } // for (it != sorted_nodes.end())
14569 
14570  // ----------------------------------------------------------
14571  // Create additional look-up schemes for the shared boundary
14572  // ----------------------------------------------------------
14573 
14574  // Updates bnd_id <---> curve section map
14575  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14576 
14577  // Check the size of the unsorted_polylines_pt structure. This
14578  // will have n_procs = 1 when it was called from the
14579  // create_new_shared_boundaries() methods
14580  const unsigned n_procs = unsorted_polylines_pt.size();
14581  if (n_procs > 1)
14582  {
14583  // Add the new created polyline to the list of unsorted
14584  // polylines
14585  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14586 
14587  // ... do this on both processors involved in the creation of
14588  // the shared boundary
14589  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14590  }
14591  else
14592  {
14593  // Add the new created polyline to the list of unsorted
14594  // polylines
14595  unsorted_polylines_pt[0].push_back(polyline_pt);
14596  }
14597 
14598  // Mark the polyline for deletion (when calling destructor)
14599  this->Free_curve_section_pt.insert(polyline_pt);
14600 
14601  // ----------------------------
14602  // Set connection information
14603  // ----------------------------
14604 
14605  // Check that the flags are correct, no connection or the boundary
14606  // id of the boundary to connect
14607 #ifdef PARANOID
14608  // Is the shared polyline not connected to the left
14609  if (connect_to_the_left_flag < 0)
14610  {
14611  // If not connected then should be specified by -1
14612  if (connect_to_the_left_flag != -1)
14613  {
14614  std::ostringstream error_message;
14615  error_message
14616  << "The only accepted values for the connection flags are:\n"
14617  << "POSITIVE values or -1, any other value is rejected, please\n"
14618  << "check that you previously called the methods to deal with\n"
14619  << "other flag values\n"
14620  << "The current flag value for connection to the left is: ("
14621  << connect_to_the_left_flag<<")\n\n";
14622  throw OomphLibError(error_message.str(),
14623  "TriangleMesh::create_shared_polyline()",
14624  OOMPH_EXCEPTION_LOCATION);
14625  } // if (connect_to_the_left_flag != -1)
14626  } // if (connect_to_the_left_flag < 0)
14627 
14628  // Is the shared polyline not connected to the right
14629  if (connect_to_the_right_flag < 0)
14630  {
14631  // If not connected then should be specified by -1
14632  if (connect_to_the_right_flag != -1)
14633  {
14634  std::ostringstream error_message;
14635  error_message
14636  << "The only accepted values for the connection flags are:\n"
14637  << "POSITIVE values or -1, any other value is rejected, please\n"
14638  << "check that you previously called the methods to deal with\n"
14639  << "other flag values\n"
14640  << "The current flag value for connection to the right is: ("
14641  << connect_to_the_right_flag<<")\n\n";
14642  throw OomphLibError(error_message.str(),
14643  "TriangleMesh::create_shared_polyline()",
14644  OOMPH_EXCEPTION_LOCATION);
14645  } // if (connect_to_the_right_flag != -1)
14646  } // if (connect_to_the_right_flag < 0)
14647 #endif
14648 
14649  // Set the connection to the left
14650  if (connect_to_the_left_flag != -1)
14651  {
14652  // Get the unsigned version of the boundary id to the left
14653  const unsigned bnd_id_connection_to_the_left =
14654  static_cast<unsigned>(connect_to_the_left_flag);
14655  // Set the initial vertex as connected
14656  polyline_pt->set_initial_vertex_connected();
14657  // Set the initial vertex connected boundary id
14658  polyline_pt->initial_vertex_connected_bnd_id() =
14659  bnd_id_connection_to_the_left;
14660  // Set the chunk number to zero
14661  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14662 
14663  } // if (connect_to_the_left_flag != -1)
14664 
14665  // Set the connection to the right
14666  if (connect_to_the_right_flag != -1)
14667  {
14668  // Get the unsigned version of the boundary id to the right
14669  const unsigned bnd_id_connection_to_the_right =
14670  static_cast<unsigned>(connect_to_the_right_flag);
14671  // Set the final vertex as connected
14672  polyline_pt->set_final_vertex_connected();
14673  // Set the final vertex connected boundary id
14674  polyline_pt->final_vertex_connected_bnd_id() =
14675  bnd_id_connection_to_the_right;
14676  // Set the chunk number to zero
14677  polyline_pt->final_vertex_connected_n_chunk() = 0;
14678 
14679  } // if (connect_to_the_right_flag != -1)
14680 
14681  } // if (iproc == my_rank || jproc == my_rank)
14682 
14683  }
14684 
14685  //======================================================================
14686  /// \short Reset the boundary elements info. after load balance have
14687  /// taken place
14688  //======================================================================
14689  template <class ELEMENT>
14693  &ntmp_boundary_elements_in_region,
14694  Vector<FiniteElement*> &deleted_elements)
14695  {
14696  // Get the number of boundaries
14697  const unsigned nbound = this->nboundary();
14698 
14699  // Are there regions?
14700  const unsigned n_regions = this->nregion();
14701 
14702  // Loop over the boundaries
14703  for (unsigned b = 0; b < nbound; b++)
14704  {
14705  // Get the boundary elements and back them up
14706  // -----------------------------------------------------------------
14707  // Get the number of boundary elements (mixed with the old and new)
14708  const unsigned nbound_ele = this->nboundary_element(b);
14709  // Back-up the boundary elements
14710  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14711  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14712  for (unsigned e = 0; e < nbound_ele; e++)
14713  {
14714  // Get the old boundary element
14715  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14716  // Get the old face index
14717  backed_up_face_index_at_boundary[e] =
14718  this->face_index_at_boundary(b, e);
14719  } // for (n < nold_boundary_elements)
14720 
14721  // Back up the elements in boundary for each region
14723  backed_up_boundary_region_element_pt(n_regions);
14724  Vector<Vector<int> > backed_up_face_index_at_boundary_region(n_regions);
14725 
14726  // Loop over the regions and back up the boundary elements in
14727  // regions
14728  for (unsigned ir = 0; ir < n_regions; ir++)
14729  {
14730  // Get the region id
14731  const unsigned region_id =
14732  static_cast<unsigned>(this->region_attribute(ir));
14733  // Get the number of boundary region elements (mixed old and new)
14734  const unsigned nbnd_region_ele =
14735  this->nboundary_element_in_region(b, region_id);
14736 
14737  // Loop over the elements in the region
14738  for (unsigned e = 0; e < nbnd_region_ele; e++)
14739  {
14740  // Get the old boundary region element
14741  backed_up_boundary_region_element_pt[ir][e] =
14742  this->boundary_element_in_region_pt(b, region_id, e);
14743 
14744  // Get the old face index
14745  backed_up_face_index_at_boundary_region[ir][e] =
14746  this->face_index_at_boundary_in_region(b, region_id, e);
14747  } // for (e < nbnd_region_ele)
14748 
14749  } // for (ir < n_regions)
14750 
14751  // Clean all previous storages
14752  this->Boundary_element_pt[b].clear();
14753  this->Face_index_at_boundary[b].clear();
14754  if (n_regions > 0)
14755  {
14756  this->Boundary_region_element_pt[b].clear();
14757  this->Face_index_region_at_boundary[b].clear();
14758  }
14759 
14760  // -------------------------------------------------------------------
14761  // Now copy only the elements that are still alive, from those before
14762  // the re-establishment of halo and haloed elements
14763  // -------------------------------------------------------------------
14764  // Start with the boundary elements
14765  // Get the old number of boundary elements
14766  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14767  // Loop over the boundary elements and check those still alive
14768  for (unsigned e = 0; e < nold_bnd_ele; e++)
14769  {
14770  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14771  // Include only those elements still alive
14773  std::find(deleted_elements.begin(),
14774  deleted_elements.end(),
14775  tmp_ele_pt);
14776  // Only copy thoes elements not found on the deleted elements
14777  // container
14778  if (it == deleted_elements.end())
14779  {
14780  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14781  this->Boundary_element_pt[b].push_back(add_ele_pt);
14782  const int face_index = backed_up_face_index_at_boundary[e];
14783  this->Face_index_at_boundary[b].push_back(face_index);
14784  } // if (tmp_ele_pt != 0)
14785 
14786  } // for (n < nold_bnd_ele)
14787 
14788  // ... continue with the boundary elements in specific regions
14789 
14790  // Loop over the regions
14791  for (unsigned ir = 0; ir < n_regions; ir++)
14792  {
14793  // Get the region id
14794  const unsigned region_id =
14795  static_cast<unsigned>(this->region_attribute(ir));
14796 
14797  // Get the old number of boundary elements in region
14798  const unsigned nold_bnd_region_ele =
14799  ntmp_boundary_elements_in_region[b][ir];
14800 
14801  // Loop over the boundary region elements and check those still
14802  // alive
14803  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14804  {
14805  // Get the element
14806  FiniteElement* tmp_ele_pt =
14807  backed_up_boundary_region_element_pt[ir][e];
14808  // Include only those elements still alive
14810  std::find(deleted_elements.begin(),
14811  deleted_elements.end(),
14812  tmp_ele_pt);
14813  // Only copy those elements not found on the deleted elements
14814  // container
14815  if (it == deleted_elements.end())
14816  {
14817  FiniteElement* add_ele_pt =
14818  backed_up_boundary_region_element_pt[ir][e];
14819  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14820  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14821  this->Face_index_region_at_boundary[b][region_id].
14822  push_back(face_index);
14823  } // if (tmp_ele_pt != 0)
14824 
14825  } // for (n < nbound_ele)
14826 
14827  } // for (ir < n_regions)
14828 
14829  // ----------------------------------------------------------------
14830  // Now copy all those elements created after the re-establishment
14831  // of halo and haloed elements
14832  // ----------------------------------------------------------------
14833  // Loop over the boundary elements
14834  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
14835  {
14836  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14837  this->Boundary_element_pt[b].push_back(add_ele_pt);
14838  const int face_index = backed_up_face_index_at_boundary[e];
14839  this->Face_index_at_boundary[b].push_back(face_index);
14840  } // for (e < nbound_ele)
14841 
14842  // Now add the boundary elements in regions
14843 
14844  // Loop over the regions
14845  for (unsigned ir = 0; ir < n_regions; ir++)
14846  {
14847  // Get the region id
14848  const unsigned region_id =
14849  static_cast<unsigned>(this->region_attribute(ir));
14850 
14851  // Get the old number of boundary elements in region
14852  const unsigned nold_bnd_region_ele =
14853  ntmp_boundary_elements_in_region[b][ir];
14854 
14855  // Get the new number of boundary elements in region
14856  const unsigned nbnd_region_ele =
14857  this->nboundary_element_in_region(b, region_id);
14858 
14859  // Loop over the boundary region elements and check those still
14860  // alive
14861  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
14862  {
14863  FiniteElement* add_ele_pt = backed_up_boundary_region_element_pt[ir][e];
14864  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14865  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14866  this->Face_index_region_at_boundary[b][region_id].push_back(face_index);
14867  } // for (e < nbnd_region_ele)
14868 
14869  } // for (ir < n_regions)
14870 
14871  } // for (b < nbound)
14872 
14873  // Lookup scheme has now been setup yet
14874  Lookup_for_elements_next_boundary_is_setup=true;
14875 
14876  }
14877 
14878 #endif // OOMPH_HAS_MPI
14879 
14880 #ifdef OOMPH_HAS_TRIANGLE_LIB
14881 
14882 //========================================================================
14883 /// Build a new TriangulateIO object based on target areas specified
14884 //========================================================================
14885 template <class ELEMENT>
14887  TriangulateIO& triangulate_io,
14888  const Vector<double>& target_area,
14889  struct TriangulateIO& triangle_refine)
14890  {
14891 
14892  // Initialize
14894 
14895  // Store the global number of vertices and segments
14896  // in the list
14897  unsigned n_points = triangulate_io.numberofpoints;
14898  triangle_refine.numberofpoints=n_points;
14899 
14900  unsigned n_segments=triangulate_io.numberofsegments;
14901  triangle_refine.numberofsegments=n_segments;
14902 
14903  // Initialization of the TriangulateIO objects to store the values
14904  triangle_refine.pointlist =
14905  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
14906  triangle_refine.pointmarkerlist =
14907  (int *) malloc(triangulate_io.numberofpoints * sizeof(int));
14908  triangle_refine.segmentlist =
14909  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
14910  triangle_refine.segmentmarkerlist =
14911  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
14912 
14913  // Storing the point's coordinates in the list
14914  // and in two vectors with x and y coordinates
14915  Vector<double> x_coord (n_points);
14916  Vector<double> y_coord (n_points);
14917 
14918  for(unsigned count_point=0;count_point<n_points*2;count_point++)
14919  {
14920  triangle_refine.pointlist[count_point]=
14921  triangulate_io.pointlist[count_point];
14922 
14923  // Even vaules represent the x coordinate
14924  // Odd values represent the y coordinate
14925  if (count_point%2==0)
14926  {
14927  x_coord[count_point/2] = triangulate_io.pointlist[count_point];
14928  }
14929  else
14930  {
14931  y_coord[(count_point-1)/2] = triangulate_io.pointlist[count_point];
14932  }
14933  }
14934 
14935  // Store the point's markers in the list
14936  for(unsigned count_marker=0;count_marker<n_points;count_marker++)
14937  {
14938  triangle_refine.pointmarkerlist[count_marker]=
14939  triangulate_io.pointmarkerlist[count_marker];
14940  }
14941 
14942  // Storing the segment's edges in the list
14943  for(unsigned count_seg=0;count_seg<n_segments*2;count_seg++)
14944  {
14945  triangle_refine.segmentlist[count_seg]=
14946  triangulate_io.segmentlist[count_seg];
14947  }
14948 
14949  // Store the segment's markers in the list
14950  for(unsigned count_markers=0;count_markers<n_segments;count_markers++)
14951  {
14952  triangle_refine.segmentmarkerlist[count_markers]=
14953  triangulate_io.segmentmarkerlist[count_markers];
14954  }
14955 
14956  // Store the hole's center coordinates
14957  unsigned n_holes = triangulate_io.numberofholes;
14958  triangle_refine.numberofholes = n_holes;
14959 
14960  triangle_refine.holelist =
14961  (double*) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
14962 
14963  // Loop over the holes to get centre coords
14964  for(unsigned count_hole=0;count_hole<n_holes*2;count_hole++)
14965  {
14966  triangle_refine.holelist[count_hole] = triangulate_io.holelist[count_hole];
14967  }
14968 
14969  // Store the triangles values
14970  unsigned n_triangles = triangulate_io.numberoftriangles;
14971  triangle_refine.numberoftriangles = n_triangles;
14972 
14973 #ifdef PARANOID
14974  if (n_triangles!=target_area.size())
14975  {
14976  std::stringstream err;
14977  err << "Number of triangles in triangulate_io="
14978  << n_triangles << " doesn't match\n"
14979  << "size of target area vector ("
14980  << target_area.size() << ")\n";
14981  throw OomphLibError(
14982  err.str(),
14983  OOMPH_CURRENT_FUNCTION,
14984  OOMPH_EXCEPTION_LOCATION);
14985  }
14986 #endif
14987 
14988  unsigned n_corners = triangulate_io.numberofcorners;
14989  triangle_refine.numberofcorners = n_corners;
14990 
14991  triangle_refine.trianglelist =
14992  (int *) malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
14993 
14994  // Store the triangle's corners in the list and get element sizes
14995  for(unsigned count_tri=0;count_tri<n_triangles*3;count_tri++)
14996  {
14997  triangle_refine.trianglelist[count_tri]=
14998  triangulate_io.trianglelist[count_tri];
14999  }
15000 
15001  // Store the triangle's area in the list
15002  triangle_refine.trianglearealist =
15003  (double *) malloc(triangulate_io.numberoftriangles * sizeof(double));
15004  for(unsigned count_area=0;count_area<n_triangles;count_area++)
15005  {
15006  triangle_refine.trianglearealist[count_area]=target_area[count_area];
15007  }
15008 
15009  // Store the triangles attributes in the list
15010  triangle_refine.numberoftriangleattributes =
15011  triangulate_io.numberoftriangleattributes;
15012 
15013  triangle_refine.triangleattributelist =
15014  (double *) malloc(
15015  triangulate_io.numberoftriangles *
15016  triangulate_io.numberoftriangleattributes * sizeof(double));
15017  for(unsigned count_attribute=0;
15018  count_attribute<(n_triangles*triangulate_io.numberoftriangleattributes);
15019  count_attribute++)
15020  {
15021  triangle_refine.triangleattributelist[count_attribute] =
15022  triangulate_io.triangleattributelist[count_attribute];
15023  }
15024 
15025  }
15026 
15027 #ifdef OOMPH_HAS_MPI
15028 
15029  // ===================================================================
15030  // The comparison class for the map that sorts the nodes on the
15031  // shared boundary (using a lexicographic order)
15032  // ===================================================================
15033  struct classcomp
15034  {
15035 
15036  // Tolerance for lower-left comparison
15037  static double Tol;
15038 
15039 
15040  // Comparison operator for "lower left" ordering
15041  bool operator() (const std::pair<double, double> &lhs,
15042  const std::pair<double, double> &rhs) const
15043  {
15044  double diff_y=lhs.second-rhs.second;
15045  if (diff_y<-Tol) // (lhs.second < rhs.second)
15046  {
15047  return true;
15048  }
15049  else
15050  {
15051  // Are they "equal" with 1.0e-14 tolerance?
15052  if (diff_y<Tol) // (lhs.second == rhs.second)
15053  {
15054 #ifdef PARANOID
15055  double diff_x=lhs.first-rhs.first;
15056  if (fabs(diff_x)<Tol)
15057  {
15058  std::ostringstream warning_message;
15059  warning_message
15060  << "Dodgy \"lower left\" (lexicographic) comparison "
15061  << "of points with cooordinates: "
15062  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15063  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15064  << "x and y coordinates differ by less than tolerance!\n"
15065  << "diff_x = " << diff_x << "\n"
15066  << "diff_y = " << diff_y << "\n"
15067  << "Tol = " << Tol << "\n";
15068  OomphLibError(warning_message.str(),
15069  OOMPH_CURRENT_FUNCTION,
15070  OOMPH_EXCEPTION_LOCATION);
15071  }
15072 #endif
15073  if (lhs.first < rhs.first)
15074  {
15075  return true;
15076  }
15077  else
15078  {
15079  return false;
15080  }
15081  }
15082  else
15083  {
15084  return false;
15085  }
15086  }
15087 
15088 
15089 
15090  // if (lhs.second < rhs.second)
15091  // {
15092  // return true;
15093  // }
15094  // else
15095  // {
15096  // // // Are "equal" with 1.0e-14 tolerance
15097  // // if (lhs.second - rhs.second < 1.0e-14)
15098  // // Are equal?
15099  // if (lhs.second == rhs.second)
15100  // {
15101  // if (lhs.first < rhs.first)
15102  // {
15103  // return true;
15104  // }
15105  // else
15106  // {
15107  // return false;
15108  // }
15109  // }
15110  // else
15111  // {
15112  // return false;
15113  // }
15114  // }
15115 
15116 
15117  }
15118 
15119  } Bottom_left_sorter; // struct classcomp
15120 
15121 
15122  // Assign value for tolerance
15123  double classcomp::Tol=1.0e-14;
15124 
15125 
15126  //======================================================================
15127  // Sort the nodes on shared boundaries so that the processors that share
15128  // a boundary agree with the order of the nodes on the boundary
15129  //======================================================================
15130  template <class ELEMENT>
15132  {
15133  // Get the shared boundaries in this processor
15134  Vector<unsigned> my_rank_shared_boundaries_ids;
15135  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15136 
15137  // Get the number of shared boundaries
15138  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15139 
15140  // Loop over the shared boundaries
15141  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15142  {
15143  // A map is used to sort the nodes using their coordinates as the key
15144  // of the map
15145  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15146  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15147 
15148 
15149 #ifdef PARANOID
15150 
15151  // Check min distance between nodes; had better be less than the
15152  // tolerance used for the bottom left sorting
15153  double min_distance_squared=DBL_MAX;
15154 
15155 #endif
15156 
15157  // Get the boundary id
15158  const unsigned b = my_rank_shared_boundaries_ids[i];
15159 
15160  // Get the number of nodes on the current boundary
15161  const unsigned nbnd_node = this->nshared_boundary_node(b);
15162 
15163  // Go through all the nodes on the boundary and temporarily store
15164  // them on the map container
15165  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15166  {
15167  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15168  std::pair<double, double> vertex = std::make_pair(node_pt->x(0),
15169  node_pt->x(1));
15170  sorted_nodes_pt[vertex] = node_pt;
15171 
15172 
15173 
15174 #ifdef PARANOID
15175 
15176  // Check for minimum distance
15177  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15178  {
15179  if (i_node!=j_node)
15180  {
15181  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15182 
15183  // Squared distance
15184  double squared_distance=0.0;
15185  for (unsigned ii=0;ii<2;ii++)
15186  {
15187  squared_distance+=
15188  (node_pt->x(ii)-node2_pt->x(ii))*
15189  (node_pt->x(ii)-node2_pt->x(ii));
15190  }
15191  if (squared_distance<min_distance_squared)
15192  {
15193  min_distance_squared=squared_distance;
15194  }
15195  }
15196  }
15197 
15198  if (sqrt(min_distance_squared)<Bottom_left_sorter.Tol)
15199  {
15200  std::ostringstream warning_message;
15201  warning_message
15202  << "Minimum distance between nodes on boundary " << b << "\n"
15203  << "is " << sqrt(min_distance_squared) << " which is less than "
15204  << "Bottom_left_sorter.Tol = " << Bottom_left_sorter.Tol << "\n"
15205  << "This may screw up the ordering of the nodes on shared boundaries\n";
15206  OomphLibWarning(warning_message.str(),
15207  OOMPH_CURRENT_FUNCTION,
15208  OOMPH_EXCEPTION_LOCATION);
15209  }
15210 
15211 #endif
15212 
15213  }
15214 
15215  unsigned counter = 0;
15216  // Resize the sorted shared boundary node vector
15217  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15218 
15219  // Now go through the map container, get the elements and store their
15220  // members on the Sorted_shared_boundary_node_pt container
15221  // The map has already sorted the nodes, now they keep the same sorting
15222  // on all processors
15223  for (std::map<std::pair<double, double>, Node*>::iterator it_map
15224  = sorted_nodes_pt.begin(); it_map != sorted_nodes_pt.end(); it_map++)
15225  {
15226  // Store the pointer to the node
15227  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15228  }
15229 
15230  } // for (i < nmy_rank_shd_bnd)
15231 
15232  }
15233 
15234  //========================================================================
15235  // Re-establish the shared boundary elements after the adaptation
15236  // process (the updating of shared nodes is optional and performed by
15237  // default)
15238  //========================================================================
15239  template <class ELEMENT>
15242  const bool update_elements,
15243  const bool flush_nodes,
15244  const bool update_nodes)
15245  {
15246  // Get the rank of the current processor
15247  const unsigned my_rank = this->communicator_pt()->my_rank();
15248 
15249  // Go through the boundaries know as shared boundaries and copy the
15250  // elements to the corresponding storage
15251 
15252  // Get the initial shared boundary id
15253  const unsigned initial_id = this->initial_shared_boundary_id();
15254 
15255  // Get the final shared boundary id
15256  const unsigned final_id = this->final_shared_boundary_id();
15257 
15258  if (flush_elements)
15259  {
15260  // Flush the shared boundaries storage for elements
15261  this->flush_shared_boundary_element();
15262  // .. and also flush the face indexes associated with the element
15263  this->flush_face_index_at_shared_boundary();
15264  } // if (flush_elements)
15265 
15266  if (flush_nodes)
15267  {
15268  // Flush the shared boundaries storage for nodes
15269  this->flush_shared_boundary_node();
15270  } // if (flush_nodes)
15271 
15272  for (unsigned b = initial_id; b < final_id; b++)
15273  {
15274  // Check if the boundary is on the current processor
15275  Vector<unsigned> procs_from_shrd_bnd;
15276  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15277  bool current_processor_has_b_boundary = false;
15278  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15279  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15280  {
15281  if (procs_from_shrd_bnd[p] == my_rank)
15282  {
15283  current_processor_has_b_boundary = true;
15284  break; // break for (p < n_procs_from_shrd_bnd)
15285  }
15286  } // for (p < n_procs_from_shrd_bnd)
15287 
15288  if (current_processor_has_b_boundary)
15289  {
15290  if (update_elements)
15291  {
15292  const unsigned nboundary_ele = this->nboundary_element(b);
15293  for (unsigned e = 0; e < nboundary_ele; e++)
15294  {
15295  // Get the boundary element and add it to the shared
15296  // boundary elements structure
15297  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15298  this->add_shared_boundary_element(b, bnd_ele_pt);
15299  // ... do the same with the face index information
15300  int face_index = this->face_index_at_boundary(b, e);
15301  this->add_face_index_at_shared_boundary(b, face_index);
15302  } // for (e < nboundary_element)
15303  } // if (update_elements)
15304 
15305  if (update_nodes)
15306  {
15307 
15308 
15309  const unsigned nboundary_node = this->nboundary_node(b);
15310  for (unsigned n = 0; n < nboundary_node; n++)
15311  {
15312  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15313  this->add_shared_boundary_node(b, bnd_node_pt);
15314  } // for (n < nboundary_node)
15315  } // if (update_nodes)
15316 
15317  } // if (current_processor_has_b_boundary)
15318  } // for (b < final_id)
15319 
15320  }
15321 
15322  //======================================================================
15323  // Sort the nodes on shared boundaries so that the processors that share
15324  // a boundary agree with the order of the nodes on the boundary
15325  //======================================================================
15326  template <class ELEMENT>
15328  {
15329  // Get the number of processors
15330  unsigned nproc = this->communicator_pt()->nproc();
15331  // Get the rank of the current processor
15332  unsigned my_rank = this->communicator_pt()->my_rank();
15333 
15334  // Get some timings
15335  double tt_start = 0.0;
15336  double tt_end=0.0;
15338  {
15339  tt_start=TimingHelpers::timer();
15340  }
15341 
15342  // -------------------------------------------------------------------
15343  // BEGIN: Get the node names and the shared nodes
15344  // -------------------------------------------------------------------
15345 
15346  // Container where to store the nodes on shared boundaries no
15347  // associated with the processor that receives the elements/nodes
15348  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15350  other_proc_shd_bnd_node_pt(nproc);
15351  // Resize the container
15352  for (unsigned iproc = 0; iproc < nproc; iproc++)
15353  {
15354  // Resize the container
15355  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15356  for (unsigned jproc = 0; jproc < nproc; jproc++)
15357  {
15358  // Get the number of shared boundaries
15359  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15360  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15361  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15362  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15363  } // for (jproc < nproc)
15364 
15365  } // for (iproc < nproc)
15366 
15367  // Store the global node names
15368  // global_node_name[x][ ][ ] Global node number
15369  // global_node_name[ ][x][ ] Global node names
15370  // global_node_name[ ][ ][x] Global node info.
15371  Vector<Vector<Vector<unsigned> > > global_node_names;
15372 
15373  // Creates a map between the node name and the index of the global
15374  // node so we can access all its node names
15375  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15376 
15377  // Store the global shared nodes pointers
15378  Vector<Node*> global_shared_node_pt;
15379 
15380  // Get the time for computation of global nodes names and shared
15381  // nodes
15382  double t_start_global_node_names_and_shared_nodes =
15384 
15385  // Compute all the names of the nodes and fill in the
15386  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15387  // on this processor (my_rank) by looking over all their names
15388  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15389  global_node_names,
15390  node_name_to_global_index,
15391  global_shared_node_pt);
15392 
15393  // Compute the number of elements before adding new ones
15394  const unsigned n_ele = this->nelement();
15395 
15396  if (Print_timings_level_adaptation>1)
15397  {
15398  // The total time for computation of global nodes names and
15399  // shared nodes
15400  double t_final_global_node_names_and_shared_nodes =
15401  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15402  oomph_info << "CPU for computing global node names and shared nodes "
15403  << "[n_ele="<< n_ele << "]: "
15404  << t_final_global_node_names_and_shared_nodes << std::endl;
15405  }
15406 
15407  // -------------------------------------------------------------------
15408  // END: Get the node names and the shared nodes
15409  // -------------------------------------------------------------------
15410 
15411  // -------------------------------------------------------------------
15412  // BEGIN: Using the global node names each processor sends info. of
15413  // the nodes shared with other processors regarding whether they are
15414  // on an original boundary or not. This is required so that at the
15415  // re-generation of halo(ed) elements stage they have the updated
15416  // information
15417  // -------------------------------------------------------------------
15418 
15419  // Get the time for sending info. of shared nodes on original
15420  // boundaries
15421  double t_start_send_info_shd_nodes_on_original_bnds =
15423 
15424  // Send the boundary node info. of nodes on shared boundaries across
15425  // processors
15426  send_boundary_node_info_of_shared_nodes(global_node_names,
15427  node_name_to_global_index,
15428  global_shared_node_pt);
15429 
15430  if (Print_timings_level_adaptation>1)
15431  {
15432  // The total time for sending info. of shared nodes lying on
15433  // original boundaries
15434  oomph_info
15435  <<"CPU for sending info. of shared nodes on original boundaries: "
15436  <<TimingHelpers::timer()-t_start_send_info_shd_nodes_on_original_bnds
15437  <<std::endl;
15438  }
15439 
15440  // -------------------------------------------------------------------
15441  // END: Using the global node names each processor sends info. of
15442  // the nodes shared with other processors regarding whether they are
15443  // on an original boundary or not. This is required so that at the
15444  // re-generation of halo(ed) elements stage they have the updated
15445  // information
15446  // -------------------------------------------------------------------
15447 
15448  // -------------------------------------------------------------------
15449  // BEGIN: Identify the elements of the mesh that have nodes on the
15450  // shared boundaries
15451  // -------------------------------------------------------------------
15452 
15453  // Store the elements that have a node on a shared boundary with
15454  // other processors
15455  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15456  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15457  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15458  // boundary with iproc
15459  Vector<Vector<Vector<FiniteElement*> > > ele_with_node_on_shd_bnd_pt(nproc);
15460  // Resize the container with the number of shared boundaries within
15461  // each processor
15462 
15463  // loop over the processors
15464  for (unsigned iproc = 0; iproc < nproc; iproc++)
15465  {
15466  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15467  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15468  } // for (iproc < nproc)
15469 
15470  // Go through all the elements and check whether any of their nodes
15471  // lies on any of the shared boundaries
15472 
15473  // loop over the elements
15474  for (unsigned e = 0; e < n_ele; e++)
15475  {
15476  // Get the element
15477  FiniteElement* ele_pt = this->finite_element_pt(e);
15478  // Get the number of nodes
15479  const unsigned n_nodes = ele_pt->nnode();
15480  // loop over the nodes and check whether any of them lies on a
15481  // shared boundary
15482  for (unsigned n = 0; n < n_nodes; n++)
15483  {
15484  // Get the node
15485  Node* node_pt = ele_pt->node_pt(n);
15486 
15487  // Now check whether the current node lies on a shared boundary
15488  // within any other processor
15489 
15490  // loop over the processors
15491  for (unsigned iproc = 0; iproc < nproc; iproc++)
15492  {
15493  // The number of boundaries shared with the current processor
15494  // (if iproc==my_rank then there are no shared boundaries
15495  // between them)
15496  const unsigned n_shd_bnd_iproc =
15497  this->nshared_boundaries(my_rank, iproc);
15498 
15499  // There are no info. with myself
15500  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15501  {
15502  // Get the boundaries ids of the shared boundaries with
15503  // iproc processor
15504  Vector<unsigned> shd_bnd_ids =
15505  this->shared_boundaries_ids(my_rank, iproc);
15506 
15507  // Loop over shd bnds with processor "iproc"
15508  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15509  {
15510  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15511  const unsigned n_ele_shd_bnd =
15512  this->nshared_boundary_element(shd_bnd_id);
15513 
15514  // Check if the node is on this boundary only if there are
15515  // elements on it
15516  if (n_ele_shd_bnd > 0 &&
15517  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15518  {
15519  // Add the element into those that have a
15520  // node on the current shared boundary
15521  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15522 
15523  } // Are there elements on the boundary and the node lies
15524  // on this boundary
15525 
15526  } // for (isb < n_shd_bnd_iproc)
15527 
15528  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15529 
15530  } // for (iproc < nproc)
15531 
15532  } // for (n < n_nodes)
15533 
15534  } // for (e < n_ele)
15535 
15536  // -------------------------------------------------------------------
15537  // END: Identify the elements of the mesh that have nodes on the
15538  // shared boundaries
15539  // -------------------------------------------------------------------
15540 
15541  // -------------------------------------------------------------------
15542  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15543  // the shared boundaries within each processor. Get the elements on
15544  // the shared boundaries, mark them as haloed in this processor and
15545  // as halo on the element that will receive the info.
15546  // -------------------------------------------------------------------
15547 
15548  // ********************************************************************
15549  // General strategy:
15550  // 1) Go through all the elements on the shared boundaries, mark these
15551  // elements as haloed, same as their nodes.
15552  // 2) Package the info. of the nodes and the elements.
15553  // 3) Send and receive the info across processors
15554  // 4) Unpackage it and create halo elements and nodes as indicated by
15555  // the received info.
15556  // ********************************************************************
15557 
15558  // Keep track of the currently created nodes within each
15559  // processor. We need to keep track of these nodes so they can be
15560  // referred at a second stage.
15561  Vector<Vector<Node*> > iproc_currently_created_nodes_pt(nproc);
15562 
15563  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15564  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15566 
15567  // Go through all processors
15568  for (unsigned iproc = 0; iproc < nproc; iproc++)
15569  {
15570  // Send and receive info. to/from other processors
15571  if (iproc != my_rank)
15572  {
15573  // Get the number of boundaries shared with the send proc (iproc)
15574  const unsigned nshared_boundaries_with_iproc =
15575  this->nshared_boundaries(my_rank, iproc);
15576 
15577  if (nshared_boundaries_with_iproc > 0)
15578  {
15579  // ******************************************************************
15580  // Stage 1
15581  // ******************************************************************
15582  // Step (1) Mark the elements adjacent to the shared boundaries as
15583  // haloed, mark the nodes on these elements as haloed nodes
15584  // Step (2) Create packages of information indicating the generation
15585  // of halo elements and nodes
15586  // ******************************************************************
15587 
15588  // Clean send and receive buffers
15589  Flat_packed_unsigneds.clear();
15590  Flat_packed_doubles.clear();
15591 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15593 #endif
15594 
15595  // Get the boundaries ids shared with "iproc"
15596  Vector<unsigned> bound_shared_with_iproc;
15597  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15598 
15599  // Loop over shared boundaries with processor "iproc"
15600  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15601  {
15602  const unsigned bnd_id = bound_shared_with_iproc[bs];
15603 // DEBP(bnd_id);
15604  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15605 // DEBP(nel_bnd);
15606 
15607  // Container to store the elements marked as haloed
15608  Vector<FiniteElement*> haloed_element;
15609 
15610  // All the elements adjacent to the boundary should be
15611  // marked as haloed elements
15612  if (nel_bnd > 0)
15613  {
15614  // Map to know which element have been already added
15615  std::map<FiniteElement*,bool> already_added;
15616 
15617  // Loop over the elements adjacent to boundary "bnd_id"
15618  for (unsigned e = 0; e < nel_bnd; e++)
15619  {
15620  // Get pointer to the element adjacent to boundary bnd_id
15621  FiniteElement* ele_pt =
15622  this->shared_boundary_element_pt(bnd_id, e);
15623 
15624  // Check if the element has been already added. Elemets
15625  // are repeated if they have two faces on the shared
15626  // boundary
15627  if (!already_added[ele_pt])
15628  {
15629  // Add the element to the container of haloed elements
15630  haloed_element.push_back(ele_pt);
15631  // Mark the element as already added
15632  already_added[ele_pt] = true;
15633  }
15634 
15635  } // for (e < nel_bnd)
15636 
15637  // In addition to the elements on the boundary we also
15638  // need to mark (as haloed) any element on the mesh with a
15639  // node on the shared boundary
15640 
15641  // Get the number of elements with a node on the current
15642  // shared boundary
15643  const unsigned n_ele_with_node_on_shd_bnd =
15644  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15645  // loop and add the elements that have a node on the
15646  // current shared boundary with the current processor
15647  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15648  {
15649  // Get the element
15650  FiniteElement* ele_pt =
15651  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15652  // Check if it has not been already added
15653  if (!already_added[ele_pt])
15654  {
15655  // Add it!!
15656  haloed_element.push_back(ele_pt);
15657  // Mark it as done
15658  already_added[ele_pt] = true;
15659  } // if (!already_added[ele_pt])
15660 
15661  } // for (iele < n_ele_with_node_on_shd_bnd)
15662 
15663  } // if (nel_bnd > 0)
15664 
15665  // Get the total number of haloed elements
15666  const unsigned nhaloed_ele = haloed_element.size();
15667  // DEBP(nhaloed_ele);
15668  // DEBP(my_rank);
15669  // DEBP(iproc);
15670  // The very first data of the flat packed is the number of haloed
15671  // elements, this will be the number of halo element to create on
15672  // the receiver processor
15673  Flat_packed_unsigneds.push_back(nhaloed_ele);
15674 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15675  std::stringstream junk;
15676  junk << "Number of haloed elements " << nhaloed_ele;
15677  Flat_packed_unsigneds_string.push_back(junk.str());
15678 #endif
15679 
15680  // Loop over the marked haloed elements
15681  for (unsigned e = 0; e < nhaloed_ele; e++)
15682  {
15683  // Get pointer to the marked haloed element
15684  FiniteElement* ele_pt = haloed_element[e];
15685  const unsigned nroot_haloed_ele =
15686  this->nroot_haloed_element(iproc);
15687 
15688  // Check if the element has been already added to the
15689  // halo(ed) scheme
15690  GeneralisedElement *gen_ele_pt = ele_pt;
15691  const unsigned haloed_ele_index =
15692  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15693 
15694  // Was the element added or only returned the index of the
15695  // element
15696  if (nroot_haloed_ele == haloed_ele_index)
15697  {
15698  Flat_packed_unsigneds.push_back(1);
15699 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15700  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
15701 #endif
15702 
15703  // Get additional info. related with the haloed element
15704  get_required_elemental_information_helper(iproc, ele_pt);
15705 
15706  // Get the nodes on the element
15707  const unsigned nnodes = ele_pt->nnode();
15708  for (unsigned j = 0; j < nnodes; j++)
15709  {
15710  Node* node_pt = ele_pt->node_pt(j);
15711 
15712  // Package the info. of the nodes
15713  // The destination processor goes in the arguments
15714  add_haloed_node_helper(iproc, node_pt);
15715 
15716  } // for (j < nnodes)
15717  } // add the element and send its nodes
15718  else // The haloed element already exists
15719  {
15720  Flat_packed_unsigneds.push_back(0);
15721 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15722  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
15723 #endif
15724  Flat_packed_unsigneds.push_back(haloed_ele_index);
15725 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15726  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
15727 #endif
15728  } // else (next_haloed_ele == external_haloed_ele_index)
15729  } // for (e < nel_bnd)
15730 
15731  } // for (bs < nshared_boundaries_with_iproc)
15732 
15733  // *******************************************************************
15734  // Stage (2)
15735  // *******************************************************************
15736  // Step (1) Send and receive the data to create halo elements and
15737  // nodes
15738  // *******************************************************************
15739  // The processor to which send the elements
15740  int send_proc = static_cast<int>(iproc);
15741  // The processor from which receive the elements
15742  int recv_proc = static_cast<int>(iproc);
15743  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15744 
15745  // *******************************************************************
15746  // Stage (3)
15747  // *******************************************************************
15748  // Step (1) Unpackage the info and create the halo elements and nodes
15749  // *******************************************************************
15750 
15751  // Reset the counters
15754 
15755  // Loop over shared boundaries with processor "iproc"
15756  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15757  {
15758  // Get the number of halo element to be created
15759  const unsigned nhaloed_ele =
15761 
15762 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15764  << " Number of elements need to be constructed "
15766  << std::endl;
15767 #endif
15768 
15769  // Loop over boundaries shared with processor "urecv_proc"
15770  for (unsigned e = 0; e < nhaloed_ele; e++)
15771  {
15772  // Create halo element from received info. of "iproc"
15773  // processor on the current processor
15774  create_halo_element(iproc,
15775  iproc_currently_created_nodes_pt[iproc],
15776  other_proc_shd_bnd_node_pt,
15777  global_node_names,
15778  node_name_to_global_index,
15779  global_shared_node_pt);
15780 
15781  } // for (e < nhaloed_ele)
15782 
15783  } // for (bs < nshared_boundaries_with_iproc)
15784 
15785  } // if (nshared_bound_recv_proc > 0)
15786 
15787  } // if (iproc != my_rank)
15788 
15789  } // for (iproc < nproc) (general loop to send and receive info.)
15790 
15791  if (Print_timings_level_adaptation>1)
15792  {
15793  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15794  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15795  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_first_stage;
15796 
15797  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15798  << "(first stage) [n_ele="<< n_ele << "]: "
15799  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15800  << std::endl;
15801  }
15802 
15803  // -------------------------------------------------------------------
15804  // END: Create the halo(ed) elements. Loop over the processors and
15805  // the shared boundaries within each processor. Get the elements on
15806  // the shared boundaries, mark them as haloed in this processor and
15807  // as halo on the element that will receive the info.
15808  // -------------------------------------------------------------------
15809 
15810  // -------------------------------------------------------------------
15811  // BEGIN: Create any additional haloed element, those that dont lie
15812  // on a shared boundary but that shared a node with other processor
15813  // -------------------------------------------------------------------
15814 
15815  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15816  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15818 
15819  // Create any additional halo(ed) elements between processors that
15820  // have no shared boundaries but that have shared nodes
15821  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15822  iproc_currently_created_nodes_pt,
15823  global_node_names,
15824  node_name_to_global_index,
15825  global_shared_node_pt);
15826 
15827  if (Print_timings_level_adaptation>1)
15828  {
15829  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15830  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
15831  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_second_stage;
15832 
15833  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15834  << "(second stage) [n_ele="<< n_ele << "]: "
15835  << t_final_regenerate_halo_ed_elements_nodes_second_stage
15836  << std::endl;
15837  }
15838 
15839  // -------------------------------------------------------------------
15840  // END: Create any additional haloed element, those that dont lie on
15841  // a shared boundary but that shared a node with other processor
15842  // -------------------------------------------------------------------
15843 
15844  // Clean send and receive buffers
15845  Flat_packed_unsigneds.clear();
15846  Flat_packed_doubles.clear();
15847 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15849 #endif
15850 
15851  // Document the timings for reseting halo and haloed scheme (without
15852  // classification of halo and haloed nodes)
15853  if (Print_timings_level_adaptation>1)
15854  {
15855  tt_end = TimingHelpers::timer();
15856  oomph_info
15857  << "CPU for resetting halo-haloed scheme (without classification of halo and haloed nodes): "
15858  << tt_end-tt_start << std::endl;
15859  }
15860 
15861  // ------------------------------------------------------------------
15862  // BEGIN: Classify halo(ed) elements and nodes
15863  // ------------------------------------------------------------------
15864  const bool report_stats = true;
15865  DocInfo tmp_doc_info;
15866  tmp_doc_info.disable_doc();
15867 
15868  // Classify nodes
15869  this->classify_halo_and_haloed_nodes(tmp_doc_info,report_stats);
15870 
15871  // Document the timings for reseting halo and haloed scheme (with
15872  // classification of halo and haloed nodes)
15873  if (Print_timings_level_adaptation>1)
15874  {
15875  tt_end = TimingHelpers::timer();
15876  oomph_info
15877  << "CPU for resetting halo-haloed scheme (with classification of halo and haloed nodes): "
15878  << tt_end-tt_start << std::endl;
15879  }
15880 
15881  // ------------------------------------------------------------------
15882  // END: Classify halo(ed) elements and nodes
15883  // ------------------------------------------------------------------
15884 
15885  }
15886 
15887 //======================================================================
15888 // \short Compute the alias of the nodes on shared boundaries in this
15889 // (my_rank) processor with other processors. Also compute the alias
15890 // of nodes on shared boundaries of other processors with other
15891 // processors (useful when there is an element that requires to be
15892 // sent to this (my_rank) processor because there is a shared node
15893 // between this (my_rank) and other processors BUT there is not a
15894 // shared boundary between this and the other processor
15895 // ======================================================================
15896 template <class ELEMENT>
15899  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
15900  &other_proc_shd_bnd_node_pt,
15901  Vector<Vector<Vector<unsigned> > > &global_node_names,
15902  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
15903  Vector<Node*> &global_shared_node_pt)
15904 {
15905  // Get the number of processors
15906  const unsigned nproc = this->communicator_pt()->nproc();
15907  // Get the rank of the current processor
15908  const unsigned my_rank = this->communicator_pt()->my_rank();
15909  // Get the communicator of the mesh
15910  OomphCommunicator* comm_pt = this->communicator_pt();
15911 
15912  // ---------------------------------------------------------------
15913  // BEGIN: Get the elements adjacent to shared boundaries and give
15914  // a unique node number to the nodes on the shared boundaries in
15915  // this processor
15916  // ---------------------------------------------------------------
15917 
15918  // Counter for the nodes on shared boundaries in this (my_rank)
15919  // processor
15920  unsigned counter_nodes = 0;
15921  // Keep track of visited nodes
15922  std::map<Node*, bool> done_node;
15923  // ... and its local node number
15924  std::map<Node*, unsigned> local_node_number;
15925  // ... and the inverted relation from local node number to node_pt
15926  Vector<Node*> local_node_pt;
15927 
15928  // Stores the j-th node name associated with the i-th local node
15929  // on shared boundaries in this processor (my_rank)
15930  // local_node_names[i][j][0] = my_rank (this processor)
15931  // local_node_names[i][j][1] = iproc (the processor with which there
15932  // is a shared boundary)
15933  // local_node_names[i][j][2] = the shared boundary id between this
15934  // (my_rank) processor and iproc
15935  // processor
15936  // local_node_names[i][j][3] = the node index on the shared boundary
15937  // local_node_names[i][j][4] = the local node index (i). This may
15938  // be unnecessary since we alread know the
15939  // index but we also send this info. to
15940  // the root processor that is why we store
15941  // them here
15942  Vector<Vector<Vector<unsigned> > > local_node_names;
15943 
15944  // loop over the processors
15945  for (unsigned iproc = 0; iproc < nproc; iproc++)
15946  {
15947  // There are not shared boundaries with myself
15948  if (iproc != my_rank)
15949  {
15950  // Get the number of shared boundaries with iproc
15951  const unsigned n_shd_bnds_with_iproc =
15952  this->nshared_boundaries(my_rank, iproc);
15953 
15954  // Get the boundaries ids shared with iproc
15955  Vector<unsigned> bnd_shd_with_iproc =
15956  this->shared_boundaries_ids(my_rank, iproc);
15957 
15958  // Loop over the shared boundaries with processor iproc
15959  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
15960  {
15961  // Keep track of visited nodes with this shared boundary
15962  std::map<Node*,bool> done_node_shd_bnd;
15963  // The boundary id
15964  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
15965  // Get the number of element on the shared boundary
15966  const unsigned n_shd_bnd_ele =
15967  this->nshared_boundary_element(shd_bnd_id);
15968 
15969  // loop over the elements adjacent to the shared boundary
15970  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
15971  {
15972  // Get the element
15973  FiniteElement* ele_pt =
15974  this->shared_boundary_element_pt(shd_bnd_id, e);
15975 
15976  // Get the number of nodes on the element
15977  const unsigned n_nodes = ele_pt->nnode();
15978 
15979  // loop over the nodes of the current element
15980  for (unsigned n = 0; n < n_nodes; n++)
15981  {
15982  // Get the node
15983  Node* node_pt = ele_pt->node_pt(n);
15984 
15985  // Has the node been visited with this shared boundary?
15986  // And, is this a node on the shd_bnd_id shared boundary
15987  // with processor iproc?
15988  if (!done_node_shd_bnd[node_pt] &&
15989  this->is_node_on_shared_boundary(shd_bnd_id,
15990  node_pt))
15991  {
15992  // Mark the done as done with this shared boundary
15993  done_node_shd_bnd[node_pt] = true;
15994 
15995  // Get the index of the node on the shared boundary
15996  // -------------------------------------------------
15997  // Get the number of nodes on the shared boundary
15998  const unsigned n_nodes_shd_bnd =
15999  nsorted_shared_boundary_node(shd_bnd_id);
16000 
16001  // The index
16002  unsigned index = 0;
16003 
16004 #ifdef PARANOID
16005  // Flag to know if the node has been found
16006  bool found_node_on_shared_boundary = false;
16007 #endif
16008  // Loop over the nodes on the shared boundary to find
16009  // the node
16010  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16011  {
16012  // Get the k-th node on the shared boundary
16013  Node* shd_bnd_node_pt =
16014  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16015 
16016  // Is the same node?
16017  if (shd_bnd_node_pt == node_pt)
16018  {
16019  // This is the index
16020  index = k;
16021 #ifdef PARANOID
16022  // Mark as found
16023  found_node_on_shared_boundary = true;
16024 #endif
16025  break; // break
16026 
16027  } // if (shd_bnd_node_pt == node_pt)
16028 
16029  } // for (k < n_nodes_shd_bnd)
16030 
16031 #ifdef PARANOID
16032  if (!found_node_on_shared_boundary)
16033  {
16034  std::ostringstream error_message;
16035  error_message
16036  <<"The index of the node on boundary ("<<shd_bnd_id
16037  <<") was not found.\n"
16038  <<"These are the node coordinates\n"
16039  <<"("<<node_pt->x(0)<<","<<node_pt->x(1)<<").\n";
16040  throw OomphLibError(error_message.str(),
16041  OOMPH_CURRENT_FUNCTION,
16042  OOMPH_EXCEPTION_LOCATION);
16043  }
16044 #endif
16045 
16046  // Create the node name
16047  Vector<unsigned> node_name(5);
16048  node_name[0] = my_rank;
16049  node_name[1] = iproc;
16050  node_name[2] = shd_bnd_id;
16051  node_name[3] = index;
16052  // The node number is filled in the following if/else
16053  //node_name[4] = ?;
16054 
16055  // Has the node already been visited?
16056  if (!done_node[node_pt])
16057  {
16058  // If not ...
16059 
16060  // Add the node to the local nodes
16061  local_node_pt.push_back(node_pt);
16062 
16063  // Assign a local node number to the node
16064  local_node_number[node_pt] = counter_nodes;
16065  // Store the local node number
16066  node_name[4] = counter_nodes;
16067  // Increase the counter of nodes
16068  counter_nodes++;
16069  // ... and mark it as visited
16070  done_node[node_pt] = true;
16071 
16072  // Push back the node name (the first
16073  // one found for this node)
16074  Vector<Vector<unsigned> > first_node_name(1);
16075  first_node_name[0] = node_name;
16076  local_node_names.push_back(first_node_name);
16077  }
16078  else
16079  {
16080  // If yes ...
16081 
16082  // Get the local node number
16083  unsigned node_number = local_node_number[node_pt];
16084 
16085  // Store the local node number
16086  node_name[4] = node_number;
16087 
16088  // Push back the node name for the
16089  // node number
16090  local_node_names[node_number].push_back(node_name);
16091 
16092  }
16093 
16094  } // Is on shared boundary?
16095 
16096  } // for (n < nnodes)
16097 
16098  } // for (e < n_shd_bnd_ele)
16099 
16100  } // for (ishd < n_shd_bnds_with_iproc)
16101 
16102  } // if (iproc != my_rank)
16103 
16104  } // for (iproc < nproc)
16105 
16106  // ---------------------------------------------------------------
16107  // END: Get the elements adjacent to shared boundaries and give
16108  // a unique node number to the nodes on the shared boundaries in
16109  // this processor
16110  // ---------------------------------------------------------------
16111 
16112  // ---------------------------------------------------------------
16113  // BEGIN: Package the names of the local nodes
16114  // ---------------------------------------------------------------
16115  // Counter for the number of names of the nodes
16116  unsigned n_total_local_names = 0;
16117  // Get the number of local nodes
16118  const unsigned n_local_nodes = local_node_names.size();
16119  // loop over the number of local nodes and get the number of names
16120  // of each node
16121  for (unsigned i = 0; i < n_local_nodes; i++)
16122  {
16123  // Get the number of names of the i-th local node
16124  const unsigned n_inode_names = local_node_names[i].size();
16125  // ... and add them to the total number of local names
16126  n_total_local_names+=n_inode_names;
16127  } // for (i < n_local_nodes)
16128 
16129  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16130  // where node# is the node number on this processor (my_rank)
16131  const unsigned n_info_per_node_name = 5;
16132  // Storage for the flat package
16133  Vector<unsigned> flat_packed_send_udata(n_total_local_names*n_info_per_node_name);
16134  // A counter
16135  unsigned counter = 0;
16136  // loop over the local nodes
16137  for (unsigned i = 0; i < n_local_nodes; i++)
16138  {
16139  // Get the number of names of the i-th local node
16140  const unsigned n_inode_names = local_node_names[i].size();
16141  // loop over the names of the i-th local node
16142  for (unsigned j = 0 ; j < n_inode_names; j++)
16143  {
16144  // Store this processor id (my_rank)
16145  flat_packed_send_udata[counter++]=local_node_names[i][j][0];
16146  // Store the processor with which the shared boundary exist
16147  flat_packed_send_udata[counter++]=local_node_names[i][j][1];
16148  // Store the shared boundary id
16149  flat_packed_send_udata[counter++]=local_node_names[i][j][2];
16150  // Store the index of the node on the shared boundary
16151  flat_packed_send_udata[counter++]=local_node_names[i][j][3];
16152  // Store the local node number on this processor (my_rank)
16153  flat_packed_send_udata[counter++]=local_node_names[i][j][4];
16154  } // for (j < n_inode_names)
16155 
16156  } // for (i < n_local_nodes)
16157 
16158  // Reset the counter
16159  counter = 0;
16160 
16161  // The number of data that will be sent to root from this
16162  // (my_rank) processor
16163  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16164 
16165  // ---------------------------------------------------------------
16166  // END: Package the names of the local nodes
16167  // ---------------------------------------------------------------
16168  // ---------------------------------------------------------------
16169  // BEGIN: Send the data to the root processor
16170  // ---------------------------------------------------------------
16171 
16172  // The root processor is in charge of computing all the node names
16173  // of the nodes on the shared boundaries
16174 
16175  // Choose the root processor
16176  const unsigned root_processor = 0;
16177 
16178  // The vector where the root processor receives how many names
16179  // will receive from the other processors
16180  Vector<unsigned> root_n_names_per_processor(nproc);
16181 
16182  // Send the number of names that the root processor will receive
16183  // from each processor
16184  MPI_Gather(&n_total_local_names, 1, MPI_UNSIGNED,
16185  &root_n_names_per_processor[0], 1, MPI_UNSIGNED,
16186  root_processor, comm_pt->mpi_comm());
16187 
16188  // Get the total number of data to receive from all processor in
16189  // root
16190  unsigned root_n_total_udata_receive = 0;
16191  Vector<int> root_n_udata_to_receive(nproc,0);
16192  for (unsigned iproc = 0; iproc < nproc; iproc++)
16193  {
16194  root_n_udata_to_receive[iproc]=
16195  root_n_names_per_processor[iproc]*n_info_per_node_name;
16196  root_n_total_udata_receive+=root_n_udata_to_receive[iproc];
16197  }
16198 
16199  // Stores and compute the offsets (in root) for the data received
16200  // from each processor
16201  Vector<int> root_uoffsets_receive(nproc,0);
16202  root_uoffsets_receive[0] = 0;
16203  for (unsigned iproc = 1; iproc < nproc; iproc++)
16204  {
16205  // Compute the offset to obtain the data from each processor
16206  root_uoffsets_receive[iproc] =
16207  root_uoffsets_receive[iproc-1] + root_n_udata_to_receive[iproc-1];
16208 
16209  }
16210 
16211  // Create at least one entry so we don't get a seg fault below
16212  if (flat_packed_send_udata.size()==0)
16213  {
16214  flat_packed_send_udata.resize(1);
16215  }
16216 
16217  // Vector where to receive the info on root from all processors
16218  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16219  // Only root receive data, the others dont, then resize the
16220  // container to have at least one entry
16221  if (my_rank!=root_processor)
16222  {
16223  // Create at least one entry so we don't get a seg fault below
16224  if (root_flat_packed_receive_udata.size()==0)
16225  {
16226  root_flat_packed_receive_udata.resize(1);
16227  }
16228  } // if (my_rank!=root_processor)
16229 
16230  // Send the info. to the root processor
16231  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16232  // info. from each
16233  // processor
16234  n_udata_send_to_root, // Total number of data send
16235  // from each processor to root
16236  MPI_UNSIGNED,
16237  &root_flat_packed_receive_udata[0], // Container where
16238  // to receive the
16239  // info. from all
16240  // processors
16241  &root_n_udata_to_receive[0], // Number of data to
16242  // receive from each
16243  // processor
16244  &root_uoffsets_receive[0], // The offset to store the
16245  // info. from each
16246  // processor
16247  MPI_UNSIGNED,
16248  root_processor, //The processor that receives all the
16249  //info.
16250  comm_pt->mpi_comm());
16251 
16252  // Clear and resize the flat package to send
16253  flat_packed_send_udata.clear();
16254  flat_packed_send_udata.resize(0);
16255  // ---------------------------------------------------------------
16256  // END: Send the data to the root processor
16257  // ---------------------------------------------------------------
16258 
16259  // Container where root stores the info. that will be sent to all
16260  // processors. This includes the number of global nodes, the
16261  // number of names for each global node and the names
16262  Vector<unsigned> flat_packed_root_send_receive_udata;
16263 
16264  // ---------------------------------------------------------------
16265  // BEGIN: Unpackage the info. received on root. Compute the alias
16266  // of the nodes
16267  // ---------------------------------------------------------------
16268  if (my_rank == root_processor)
16269  {
16270  // Compute all the names of a node
16271  // root_global_node_name[x][ ][ ] Global node number
16272  // root_global_node_name[ ][x][ ] Global node names
16273  // root_global_node_name[ ][ ][x] Global node info.
16274  Vector<Vector<Vector<unsigned> > > root_global_node_names;
16275 
16276  // Store the info. extracted from the flat package sent to
16277  // root
16278  // root_local_node_names[x][ ] Node name
16279  // root_local_node_names[ ][x] Node info
16280  Vector<Vector<unsigned> > root_local_node_names;
16281 
16282  // Extract all the node names
16283  unsigned rcounter = 0;
16284  // loop over the processors
16285  for (unsigned iproc = 0; iproc < nproc; iproc++)
16286  {
16287  // Get the number of node names received from iproc
16288  const unsigned n_local_names_iproc =
16289  root_n_names_per_processor[iproc];
16290  for (unsigned i = 0; i < n_local_names_iproc; i++)
16291  {
16292  // Get the i-thnode name from iproc
16293  Vector<unsigned> node_name(n_info_per_node_name);
16294  for (unsigned j = 0; j < n_info_per_node_name; j++)
16295  {node_name[j] = root_flat_packed_receive_udata[rcounter++];}
16296 
16297  // Add the i-th node name
16298  root_local_node_names.push_back(node_name);
16299 
16300  } // for (i < n_local_names_iproc)
16301 
16302  } // for (iproc < nproc)
16303 
16304  // Get the number of node names received
16305  const unsigned n_root_local_node_names =
16306  root_local_node_names.size();
16307 
16308  // For each name of the node identify the position of its
16309  // counter-part
16310 
16311  // Given a node name on the iproc,
16312  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16313  // its counter part must live in jproc, so we look for the
16314  // node name
16315  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16316 
16317  // Store the index of the node name counter-part
16318  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16319 
16320  // Keep track of the names of nodes already done
16321  std::map<Vector<unsigned>, bool> done_name;
16322 
16323  // loop over the names of the nodes received from all
16324  // processors
16325  for (unsigned i = 0; i < n_root_local_node_names; i++)
16326  {
16327  // Get the i-th node name
16328  Vector<unsigned> node_name = root_local_node_names[i];
16329 
16330  // Check if this name node has been already done
16331  if (!done_name[node_name])
16332  {
16333  // Mark it as done
16334  done_name[node_name] = true;
16335 #ifdef PARANOID
16336  // Flag to indicate the counter-part name node was
16337  // found
16338  bool found_both_names_node = false;
16339 #endif
16340  // Find the counter-part name node (start from j+1
16341  // since all previous have been found, otherwise we
16342  // would not be here)
16343  for (unsigned j = i+1; j < n_root_local_node_names; j++)
16344  {
16345  Vector<unsigned> node_name_r = root_local_node_names[j];
16346 
16347  // Check if this name node has been already done
16348  if (!done_name[node_name_r])
16349  {
16350  // Check whether this node is the
16351  // counter-part of the current name node
16352  if (node_name[0] == node_name_r[1] &&
16353  node_name[1] == node_name_r[0] &&
16354  node_name[2] == node_name_r[2] &&
16355  node_name[3] == node_name_r[3])
16356  {
16357  // Mark the name as node
16358  done_name[node_name_r] = true;
16359  // Store the index of the counter-part of
16360  // the current node name
16361  node_name_counter_part[i] = j;
16362  // ... and indicate the current node name
16363  // as the index of the counter-part
16364  node_name_counter_part[j] = i;
16365 #ifdef PARANOID
16366  // The node has been found
16367  found_both_names_node = true;
16368 #endif
16369  // Break the loop to find the
16370  // counter-part
16371  break;
16372  }
16373 
16374  } // if (!done_name[node_name_r])
16375 
16376  } // for (j < n_root_local_node_names)
16377 #ifdef PARANOID
16378  // Check whether the node counter-part was found
16379  if (!found_both_names_node)
16380  {
16381  std::ostringstream error_message;
16382  error_message
16383  <<"The counter-part of the current name node was "
16384  <<"not found,\nthe current node name is:\n"
16385  <<"iproc:("<<node_name[0]<<")\n"
16386  <<"jproc:("<<node_name[1]<<")\n"
16387  <<"ishd_bnd:("<<node_name[2]<<")\n"
16388  <<"index:("<<node_name[3]<<")\n";
16389  throw OomphLibError(error_message.str(),
16390  OOMPH_CURRENT_FUNCTION,
16391  OOMPH_EXCEPTION_LOCATION);
16392  } // if (!found_both_names_node)
16393 #endif
16394 
16395  } // if (!done_name[node_name])
16396 
16397  } // for (i < n_root_local_node_names)
16398 
16399  // -----------------------------------------------------------
16400  // Look for all the names of each node received and store them
16401  // in the "global node names" container
16402 
16403  // Keep track of the names of nodes already done
16404  done_name.clear();
16405  // loop over the names of the nodes received from all
16406  // processors
16407  for (unsigned i = 0; i < n_root_local_node_names; i++)
16408  {
16409  // Get the i-th node name
16410  Vector<unsigned> node_name = root_local_node_names[i];
16411 
16412  // Check if this name node has been already done
16413  if (!done_name[node_name])
16414  {
16415  // Store all the names of the current node
16416  Vector<Vector<unsigned> > all_node_names;
16417 
16418  // Add the name of the node as the initial node name
16419  all_node_names.push_back(node_name);
16420 
16421  // Get the index of the counter-part
16422  unsigned idx_c = node_name_counter_part[i];
16423  // Get the counter-part of the node name
16424  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16425 
16426  // Add the name of the counter-part of the node
16427  all_node_names.push_back(node_name_r);
16428  // We do not mark it as done since we are interested in
16429  // the names that the counter-part may generate
16430 
16431  // Get the number of names for the current node (two at
16432  // the first time)
16433  unsigned n_current_names = all_node_names.size();
16434  // Counter to ensure to visit all the names of the current
16435  // node
16436  unsigned icounter = 0;
16437 
16438  // Visit all the names of the current node
16439  while(icounter < n_current_names)
16440  {
16441  // Get the current node name
16442  Vector<unsigned> current_node_name = all_node_names[icounter];
16443 
16444  // Search for other names for the current name of the
16445  // node, but first check if this has been already
16446  // visited
16447  if (!done_name[current_node_name])
16448  {
16449  // Mark it as done
16450  done_name[current_node_name] = true;
16451 
16452  // loop over the names of the nodes (start from the
16453  // j+1 position, all previous node names have all
16454  // their names already assigned)
16455  for (unsigned j=i+1;j<n_root_local_node_names;j++)
16456  {
16457  // Get the j-th node name
16458  Vector<unsigned> other_node_name = root_local_node_names[j];
16459 
16460  // Is this name node already done
16461  if (!done_name[other_node_name])
16462  {
16463  // Is this another name for the current name node?
16464  if ((current_node_name[0] == other_node_name[0]) &&
16465  (current_node_name[4] == other_node_name[4]))
16466  {
16467  // Mark it as done. If we search again using the
16468  // "other_node_name" as the current node name we
16469  // are not going to find new nodes to add
16470  done_name[other_node_name] = true;
16471  // Before adding it check that it is not already
16472  // part of the names of the node
16473  Vector<Vector<unsigned> >::iterator it
16474  = std::find(all_node_names.begin(),
16475  all_node_names.end(),
16476  other_node_name);
16477  if (it==all_node_names.end())
16478  {
16479  all_node_names.push_back(other_node_name);
16480  // Get the index of the counter-part
16481  unsigned k = node_name_counter_part[j];
16482  // Get the counter-part of the node name
16483  Vector<unsigned> other_node_name_r =
16484  root_local_node_names[k];
16485  // Add the name of the counter-part of the
16486  // node only if it has not been previously
16487  // done
16488  if (!done_name[other_node_name_r])
16489  {
16490  all_node_names.push_back(other_node_name_r);
16491  }
16492 
16493  }
16494 
16495  } // // Is this another name for the current name
16496  // node?
16497 
16498  } // if (!done_name[other_node_name])
16499 
16500  } // for (j < n_root_local_node_names)
16501 
16502  } // if (!done_name[current_node_name])
16503 
16504  // Get the number of names
16505  n_current_names = all_node_names.size();
16506  // Increase the icounter to indicate we have visited the
16507  // current name of the node
16508  icounter++;
16509 
16510  } // while(icounter < n_current_names)
16511 
16512  // We now have all the names for the i-th global node
16513  root_global_node_names.push_back(all_node_names);
16514 
16515  } // if (!done_name[node_name])
16516 
16517  } // for (i < n_root_local_node_names)
16518 
16519  // -------------------------------------------------------------
16520  // Prepare the info to be sent to all processors. The number
16521  // of global nodes, the number of names for each global node,
16522  // and their respective names
16523  // -------------------------------------------------------------
16524 
16525  // Clear the container
16526  flat_packed_root_send_receive_udata.clear();
16527  // Get the number of global nodes
16528  const unsigned n_global_nodes = root_global_node_names.size();
16529  // ... and store this info. to be sent from root to all
16530  // processors
16531  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16532 
16533  // loop over the nodes
16534  for (unsigned i = 0; i < n_global_nodes; i++)
16535  {
16536  // Get the names of the i-th global node
16537  Vector<Vector<unsigned> > global_inode_names =
16538  root_global_node_names[i];
16539  // Get the number of names for the i-th global node
16540  const unsigned n_names_global_inode = global_inode_names.size();
16541  // ... and store this info. to be sent from root to all
16542  // processors
16543  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16544  // loop over the names of the global i-th node
16545  for (unsigned j = 0; j < n_names_global_inode; j++)
16546  {
16547  // loop over the info. associated with each name
16548  for (unsigned k = 0; k < n_info_per_node_name; k++)
16549  {
16550  // Store the name info. of the current name in the
16551  // container to be sent from root to all processors
16552  flat_packed_root_send_receive_udata.
16553  push_back(global_inode_names[j][k]);
16554  } // for (k < n_info_per_node_name)
16555 
16556  } // for (j < n_names_inode)
16557 
16558  } // for (i < n_global_nodes)
16559 
16560  } // if (my_rank == root_processor)
16561 
16562  // ----------------------------------------------------------------
16563  // END: Unpackage the info. received on root. Compute the alias
16564  // of the nodes and prepare the info. to be sent back from
16565  // root to all processors
16566  // ----------------------------------------------------------------
16567 
16568  // ---------------------------------------------------------------
16569  // BEGIN: Send the info. back to all processors, unpackage the
16570  // info. and create the map from node name to global node
16571  // index
16572  // ---------------------------------------------------------------
16573  // The number of data that root send to other processors.
16574  unsigned root_n_udata_sent_to_all_proc =
16575  flat_packed_root_send_receive_udata.size();
16576 
16577  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16578  // receive
16579  1, MPI_UNSIGNED, root_processor,
16580  comm_pt->mpi_comm());
16581 
16582  // Resize the container if this is a processor that receives data
16583  if (my_rank != root_processor)
16584  {
16585  flat_packed_root_send_receive_udata.
16586  resize(root_n_udata_sent_to_all_proc);
16587  }
16588 
16589  // Send the info. from root and receive it on all processors
16590  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16591  // from root to
16592  // all
16593  // processors
16594  root_n_udata_sent_to_all_proc, // Number of data sent
16595  // from root to each
16596  // procesor
16597  MPI_UNSIGNED,
16598  root_processor, // The processor that sends all the info.
16599  comm_pt->mpi_comm());
16600 
16601  // Counter to extract the info.
16602  counter = 0;
16603  // Read the number of global nodes
16604  const unsigned n_global_nodes =
16605  flat_packed_root_send_receive_udata[counter++];
16606  // Store the global names of the nodes
16607  // global_node_name[x][ ][ ] Global node number
16608  // global_node_name[ ][x][ ] Global node names
16609  // global_node_name[ ][ ][x] Global node info.
16610  //Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16611  // Resize the input vector
16612  global_node_names.resize(n_global_nodes);
16613  // Now loop until all global nodes info. has been read
16614  unsigned n_read_global_nodes = 0;
16615  while (n_read_global_nodes < n_global_nodes)
16616  {
16617  // Read the number of names for the current global node
16618  const unsigned n_names_global_inode =
16619  flat_packed_root_send_receive_udata[counter++];
16620  // Counter for the global node
16621  const unsigned i = n_read_global_nodes;
16622  // Resize the container
16623  global_node_names[i].resize(n_names_global_inode);
16624  // loop over the names of the global inode
16625  for (unsigned j = 0; j < n_names_global_inode; j++)
16626  {
16627  // Resize the container
16628  global_node_names[i][j].resize(n_info_per_node_name);
16629  // loop over the info. of the j-th node name of the i-th
16630  // global node
16631  for (unsigned k = 0; k < n_info_per_node_name; k++)
16632  {
16633  // Read the k-th node info. from the j-th node name of
16634  // the i-th global node
16635  global_node_names[i][j][k] =
16636  flat_packed_root_send_receive_udata[counter++];
16637 
16638  } // for (k < n_info_per_node_name)
16639 
16640  // Create the map from the node name to the global node
16641  // index
16642  Vector<unsigned> node_name(n_info_per_node_name-1);
16643  node_name[0] = global_node_names[i][j][0];
16644  node_name[1] = global_node_names[i][j][1];
16645  node_name[2] = global_node_names[i][j][2];
16646  node_name[3] = global_node_names[i][j][3];
16647  // Do not add the local index since it will not longer be
16648  // used. Additionally, we will not know the local node
16649  // index outside this method
16650  // node_name[4] = global_node_names[i][j][4];
16651  node_name_to_global_index[node_name] = i;
16652 
16653  } // for (j < n_names_global_inode)
16654 
16655  // Increase the counter for read global nodes
16656  n_read_global_nodes++;
16657 
16658  } // while (n_read_global_nodes < n_global_nodes)
16659 
16660 #ifdef PARANOID
16661  // Check we have read all the info.
16662  if (counter != root_n_udata_sent_to_all_proc)
16663  {
16664  std::ostringstream error_stream;
16665  error_stream
16666  <<"The info. received from root regarding the global names of "
16667  <<"the nodes\nwas not completely read.\n"
16668  << "The number of data sent/received from root is: ("
16669  <<root_n_udata_sent_to_all_proc<<")\n"
16670  <<"The number of data read from the received info. is: ("
16671  <<counter<<")\n\n";
16672  throw OomphLibError(error_stream.str(),
16673  OOMPH_CURRENT_FUNCTION,
16674  OOMPH_EXCEPTION_LOCATION);
16675  } // if (counter != root_n_udata_sent_to_all_proc)
16676 #endif
16677 
16678  // ---------------------------------------------------------------
16679  // END: Send the info. back to all processors, unpackage the info.
16680  // and create the map from node name to global node index
16681  // ---------------------------------------------------------------
16682 
16683  // ---------------------------------------------------------------
16684  // BEGIN: Add the info. from the global node names into the
16685  // info. of the local node names. We do this because the
16686  // local node names have pointers to the nodes.
16687  // Additionally, create a map from the node name to the
16688  // index of its global node
16689  // ---------------------------------------------------------------
16690 
16691  // Resize the global shared node pointers container
16692  global_shared_node_pt.resize(n_global_nodes, 0);
16693 
16694  // loop over the number of global nodes
16695  for (unsigned i = 0; i < n_global_nodes; i++)
16696  {
16697  // Flag to indicate that the iglobal node is part of the nodes
16698  // on the current processor
16699  bool is_this_a_local_node_name = false;
16700  unsigned local_node_number;
16701  // Get the number of names of the i-th global node
16702  const unsigned n_names_global_inode = global_node_names[i].size();
16703  // loop over the names of the i-th global node
16704  for (unsigned j = 0; j < n_names_global_inode; j++)
16705  {
16706  // Get the node name info.
16707  const unsigned iproc = global_node_names[i][j][0];
16708  local_node_number = global_node_names[i][j][4];
16709 
16710  // Check if this node name lives on this processor
16711  if (my_rank == iproc)
16712  {
16713  // The node is part of the local node names
16714  is_this_a_local_node_name = true;
16715  // Break
16716  break;
16717  } // if (my_rank == iproc)
16718 
16719  } // for (j < n_names_global_inode)
16720 
16721  // If the node is part of the local nodes then add the
16722  // additional names of the node in the local container
16723  if (is_this_a_local_node_name)
16724  {
16725 #ifdef PARANOID
16726  // Check that the global node include at least all the names
16727  // of the node on this processor
16728  const unsigned n_names_local_node =
16729  local_node_names[local_node_number].size();
16730  unsigned n_names_found_on_global_name_node = 0;
16731 #endif
16732 
16733  // Add the pointer of the node into the global shared node
16734  // pointers container
16735  global_shared_node_pt[i] = local_node_pt[local_node_number];
16736 
16737  // Add all the global names of the node onto the local node
16738  // names
16739 
16740  // loop again over the names of the i-th global node
16741  for (unsigned j = 0; j < n_names_global_inode; j++)
16742  {
16743  // Get the node name info.
16744  const unsigned iproc = global_node_names[i][j][0];
16745 
16746  // Is this a node name on this processor?
16747  if (iproc != my_rank)
16748  {
16749  // Add the name
16750  local_node_names[local_node_number].
16751  push_back(global_node_names[i][j]);
16752  }
16753 #ifdef PARANOID
16754  else
16755  {
16756  const unsigned jproc = global_node_names[i][j][1];
16757  const unsigned ishd_bnd = global_node_names[i][j][2];
16758  const unsigned idx = global_node_names[i][j][3];
16759  const unsigned n_local_node = global_node_names[i][j][4];
16760  // loop over the names of the local node
16761  for (unsigned k = 0; k < n_names_local_node; k++)
16762  {
16763  if ((local_node_names[local_node_number][k][0] == iproc) &&
16764  (local_node_names[local_node_number][k][1] == jproc) &&
16765  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16766  (local_node_names[local_node_number][k][3] == idx) &&
16767  (local_node_names[local_node_number][k][4] == n_local_node))
16768  {
16769  // Increase the number of local nodes found on the
16770  // global nodes
16771  n_names_found_on_global_name_node++;
16772  } // found global node on local nodes
16773 
16774  } // for (k < n_names_local_node)
16775 
16776  } // if (iproc != my_rank)
16777 #endif
16778 
16779  } // for (j < n_names_global_inode)
16780 
16781 #ifdef PARANOID
16782  // The number of local nodes names must be the same as the the
16783  // number of global nodes names associated with this processor
16784  // (my_rank, that start with iproc = my_rank)
16785  if (n_names_local_node != n_names_found_on_global_name_node)
16786  {
16787  std::ostringstream error_stream;
16788  error_stream
16789  <<"The local node names corresponding to the local "
16790  <<"node ("<< local_node_number << ") were\n"
16791  <<"not found on the global node names.\n\n"
16792  << "These are the names of the local node\n"
16793  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16794  for (unsigned k = 0; k < n_names_local_node; k++)
16795  {
16796  error_stream<<"Name("<<k<<"): "
16797  <<local_node_names[local_node_number][k][0]
16798  <<", "<<local_node_names[local_node_number][k][1]
16799  <<", "<<local_node_names[local_node_number][k][2]
16800  <<", "<<local_node_names[local_node_number][k][3]
16801  <<", "<<local_node_names[local_node_number][k][4]
16802  <<"\n";
16803  }
16804 
16805  error_stream
16806  << "\n\nThese are the names of the global node\n"
16807  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16808  for (unsigned k = 0; k < n_names_global_inode; k++)
16809  {
16810  error_stream<<"Name("<<k<<"): "
16811  <<global_node_names[i][k][0] <<", "
16812  <<global_node_names[i][k][1] <<", "
16813  <<global_node_names[i][k][2] <<", "
16814  <<global_node_names[i][k][3] <<", "
16815  <<global_node_names[i][k][4] <<"\n";
16816  }
16817 
16818  throw OomphLibError(error_stream.str(),
16819  OOMPH_CURRENT_FUNCTION,
16820  OOMPH_EXCEPTION_LOCATION);
16821  }
16822 #endif
16823 
16824  } // if (is_this_a_local_node_name)
16825 
16826  } // for (i < n_global_nodes)
16827 
16828  // ---------------------------------------------------------------
16829  // END: Add the info. from the global node names into the info.
16830  // of the local node names. We do this because the local
16831  // node names have pointers to the nodes
16832  // ---------------------------------------------------------------
16833 
16834  // ---------------------------------------------------------------
16835  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
16836  // the local nodes.
16837  // ---------------------------------------------------------------
16838 
16839  // Loop over the local nodes and fill the
16840  // other_proc_shd_bnd_node_pt container with the corresponding
16841  // info. NOTE: We are using the old size of the local node names,
16842  // before adding the names of the global nodes so we only loop
16843  // over the local nodes and not global.
16844 
16845  // Compute the local shared boudary id
16846  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
16847 
16848  // loop over the local nodes names
16849  for (unsigned i = 0 ; i < n_local_nodes; i++)
16850  {
16851  // Get the number of names for the i-th local node
16852  const unsigned n_names = local_node_names[i].size();
16853  // Get a pointer to the first name of the node found on this
16854  // processor (this ensures that the node lives on this
16855  // processor)
16856  Node* node_pt = local_node_pt[i];
16857  // loop over the names of the i-th local node and add an entry
16858  // to the other_proc_shd_bnd_node_pt structure
16859  for (unsigned j = 0; j < n_names; j++)
16860  {
16861  // Get the node name info.
16862  const unsigned iproc = local_node_names[i][j][0];
16863  const unsigned jproc = local_node_names[i][j][1];
16864  const unsigned ishd_bnd =
16865  local_node_names[i][j][2] - initial_shd_bnd_id;
16866  const unsigned index = local_node_names[i][j][3];
16867  // We can ignore the last entry, it was just used to compute
16868  // the global node number by the root processor
16869 
16870  // Get the smallest processor number
16871  if (iproc < jproc)
16872  {
16873  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]=node_pt;
16874  }
16875  else
16876  {
16877  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]=node_pt;
16878  }
16879 
16880  } // for (j < n_names)
16881 
16882  } // for (i < n_local_node_names)
16883 
16884  // ---------------------------------------------------------------
16885  // END: Fill the data structure other_proc_shd_bnd_node_pt with
16886  // the local nodes.
16887  // ---------------------------------------------------------------
16888 
16889 }
16890 
16891  //======================================================================
16892  // \short Get the original boundaries to which is associated each
16893  // shared node, and send the info. to the related processors. We
16894  // need to do this so that at the reset of halo(ed) info. stage,
16895  // the info. is updated
16896 template <class ELEMENT>
16899  Vector<Vector<Vector<unsigned> > > &global_node_names,
16900  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
16901  Vector<Node*> &global_shared_node_pt)
16902 {
16903  // Get the rank and number of processors
16904  const unsigned nproc = this->communicator_pt()->nproc();
16905  const unsigned my_rank = this->communicator_pt()->my_rank();
16906 
16907  // The number of nodes on shared boundaries
16908  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
16909  // ---------------------------------------------------------
16910  // BEGIN: Get the shared nodes between each of processors
16911  // ---------------------------------------------------------
16912 
16913  // Store the nodes on shared boundaries in this processor with other
16914  // processors
16915  Vector<std::set<Node*> > node_on_shd_bnd_pt(nproc);
16916 
16917  // A map to get access to the global shared node number from the
16918  // node pointer
16919  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
16920 
16921  // loop over the global nodes names and get only those in this
16922  // processor
16923  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
16924  {
16925  // Get the number of names of the current node on shared
16926  // boundaries
16927  const unsigned n_names = global_node_names[i].size();
16928  // loop over the names
16929  for (unsigned j = 0; j < n_names; j++)
16930  {
16931  // Store the node name
16932  Vector<unsigned> node_name(4);
16933  node_name[0] = global_node_names[i][j][0];
16934  node_name[1] = global_node_names[i][j][1];
16935  node_name[2] = global_node_names[i][j][2];
16936  node_name[3] = global_node_names[i][j][3];
16937 
16938  // Check whether the node is in the current processor
16939  if (node_name[0]==my_rank)
16940  {
16941  // Check with which processor the node is shared
16942  const unsigned jproc = node_name[1];
16943 
16944 #ifdef PARANOID
16945  std::map<Vector<unsigned>, unsigned>::iterator it =
16946  node_name_to_global_index.find(node_name);
16947  if (it!=node_name_to_global_index.end())
16948  {
16949  // Check whether the global node index correspond with that
16950  // of the current global node name
16951  if (i!=(*it).second)
16952  {
16953  std::ostringstream error_message;
16954  error_message
16955  <<"The global node number "<<(*it).second
16956  <<") obtained from the current node\n"
16957  <<"name is not the same as the current node number ("
16958  <<i<<").\n\n"
16959  <<"Node name:\n"
16960  <<"iproc:"<<node_name[0]<<"\n"
16961  <<"jproc:"<<node_name[1]<<"\n"
16962  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16963  <<"index:"<<node_name[3]<<"\n\n";
16964  throw OomphLibError(error_message.str(),
16965  OOMPH_CURRENT_FUNCTION,
16966  OOMPH_EXCEPTION_LOCATION);
16967  }
16968 
16969  }
16970  else
16971  {
16972  std::ostringstream error_message;
16973  error_message
16974  <<"The node name is not registerd as living in this processor.\n"
16975  <<"Node name:\n"
16976  <<"iproc:"<<node_name[0]<<"\n"
16977  <<"jproc:"<<node_name[1]<<"\n"
16978  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16979  <<"index:"<<node_name[3]<<"\n\n";
16980  throw OomphLibError(error_message.str(),
16981  OOMPH_CURRENT_FUNCTION,
16982  OOMPH_EXCEPTION_LOCATION);
16983  }
16984 
16985 #endif // #ifdef PARANOID
16986 
16987  // Get the node pointer
16988  Node* node_pt = global_shared_node_pt[i];
16989 
16990 #ifdef PARANOID
16991  if (node_pt == 0)
16992  {
16993  std::ostringstream error_message;
16994  error_message
16995  <<"There is not global shared node within this\n"
16996  <<"global node number ("<<i<<"). The global shared\n"
16997  <<"node pointer is null\n\n";
16998  throw OomphLibError(error_message.str(),
16999  OOMPH_CURRENT_FUNCTION,
17000  OOMPH_EXCEPTION_LOCATION);
17001  }
17002 #endif // #ifdef PARANOID
17003 
17004  // Add the node to the nodes on shared boundaries in this
17005  // processor
17006  node_on_shd_bnd_pt[jproc].insert(node_pt);
17007 
17008  // And store the global node index
17009  node_pt_to_global_shd_bnd_index[node_pt] = i;
17010 
17011  } // if (node_name[0]==my_rank)
17012  else if (node_name[1]==my_rank)
17013  {
17014  // Check with which processor the node is shared
17015  const unsigned jproc = node_name[0];
17016 
17017 #ifdef PARANOID
17018  std::map<Vector<unsigned>, unsigned>::iterator it =
17019  node_name_to_global_index.find(node_name);
17020  if (it!=node_name_to_global_index.end())
17021  {
17022  // Check whether the global node index correspond with that
17023  // of the current global node name
17024  if (i!=(*it).second)
17025  {
17026  std::ostringstream error_message;
17027  error_message
17028  <<"The global node number "<<(*it).second
17029  <<") obtained from the current node\n"
17030  <<"name is not the same as the current node number ("
17031  <<i<<").\n\n"
17032  <<"Node name:\n"
17033  <<"iproc:"<<node_name[0]<<"\n"
17034  <<"jproc:"<<node_name[1]<<"\n"
17035  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17036  <<"index:"<<node_name[3]<<"\n\n";
17037  throw OomphLibError(error_message.str(),
17038  OOMPH_CURRENT_FUNCTION,
17039  OOMPH_EXCEPTION_LOCATION);
17040  }
17041 
17042  }
17043  else
17044  {
17045  std::ostringstream error_message;
17046  error_message
17047  <<"The node name is not registerd as living in this processor.\n"
17048  <<"Node name:\n"
17049  <<"iproc:"<<node_name[0]<<"\n"
17050  <<"jproc:"<<node_name[1]<<"\n"
17051  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17052  <<"index:"<<node_name[3]<<"\n\n";
17053  throw OomphLibError(error_message.str(),
17054  OOMPH_CURRENT_FUNCTION,
17055  OOMPH_EXCEPTION_LOCATION);
17056  }
17057 
17058 #endif // #ifdef PARANOID
17059 
17060  // Get the node pointer
17061  Node* node_pt = global_shared_node_pt[i];
17062 
17063 #ifdef PARANOID
17064  if (node_pt == 0)
17065  {
17066  std::ostringstream error_message;
17067  error_message
17068  <<"There is not global shared node within this\n"
17069  <<"global node number ("<<i<<"). The global shared\n"
17070  <<"node pointer is null\n\n";
17071  throw OomphLibError(error_message.str(),
17072  OOMPH_CURRENT_FUNCTION,
17073  OOMPH_EXCEPTION_LOCATION);
17074  }
17075 #endif // #ifdef PARANOID
17076 
17077  // Add the node to the nodes on shared boundaries in this
17078  // processor
17079  node_on_shd_bnd_pt[jproc].insert(node_pt);
17080 
17081  // And store the global node index
17082  node_pt_to_global_shd_bnd_index[node_pt] = i;
17083 
17084  }
17085 
17086  } // for (j < n_names)
17087 
17088  } // for (i < n_nodes_on_shd_bnds)
17089 
17090  // ---------------------------------------------------------
17091  // END: Get the shared nodes between each of processors
17092  // ---------------------------------------------------------
17093 
17094  // ---------------------------------------------------------
17095  // BEGIN: Get the original boundaries associated to each
17096  // node on a shared boundary
17097  // ---------------------------------------------------------
17098 
17099  // Store the global shared node number
17100  Vector<Vector<unsigned> > global_node_on_shared_bound(nproc);
17101  // Store the boundaries associated with the global shared node
17102  // number
17103  Vector<Vector<Vector<unsigned> > > global_node_original_boundaries(nproc);
17104  // Store the zeta boundary coordinate of the nodes on original
17105  // boundaries
17106  Vector<Vector<Vector<double> > > global_node_zeta_coordinate(nproc);
17107 
17108  // loop over the processors
17109  for (unsigned iproc = 0; iproc < nproc; iproc++)
17110  {
17111  // Get the nodes added to be shared with the iproc processor
17112  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17113 
17114  // loop over the nodes
17115  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17116  it!=nodes_shared_pt.end(); it++)
17117  {
17118  // Get the node
17119  Node* node_pt = (*it);
17120  // Store the boundaries on which it is stored
17121  Vector<unsigned> on_original_boundaries;
17122  // For each boundary get the corresponding z value of the node
17123  // on the boundary
17124  Vector<double> zeta_coordinate;
17125  // Get the number of boudandaries
17126  const unsigned n_bnd=this->initial_shared_boundary_id();
17127  // loop over the boundaries and register the boundaries to which
17128  // it is associated
17129  for (unsigned bb = 0; bb < n_bnd; bb++)
17130  {
17131  // Is the node on original boundary bb?
17132  if (node_pt->is_on_boundary(bb))
17133  {
17134  // Then save it as being on boundary bb
17135  on_original_boundaries.push_back(bb);
17136  // Get the boundary coordinate
17137  Vector<double> zeta(1);
17138  node_pt->get_coordinates_on_boundary(bb, zeta);
17139  // Save the boundary coordinate
17140  zeta_coordinate.push_back(zeta[0]);
17141  }
17142 
17143  } // for (bb < n_bnd)
17144 
17145  // Is the node on an original boundary
17146  if (on_original_boundaries.size()>0)
17147  {
17148  // Get the global shared node number
17149  std::map<Node*,unsigned>::iterator it_index =
17150  node_pt_to_global_shd_bnd_index.find(node_pt);
17151 #ifdef PARANOID
17152  if (it_index==node_pt_to_global_shd_bnd_index.end())
17153  {
17154  std::ostringstream error_message;
17155  error_message
17156  <<"We could not find the global shared node index associated\n"
17157  <<"with the node pointer with vertices coordinates:\n"
17158  <<"("<<node_pt->x(0)<<", "<<node_pt->x(1)<<")\n\n";
17159  throw OomphLibError(error_message.str(),
17160  OOMPH_CURRENT_FUNCTION,
17161  OOMPH_EXCEPTION_LOCATION);
17162  }
17163 #endif
17164  // The global shared node index
17165  const unsigned global_shared_node_number = (*it_index).second;
17166  // Store the global shared node number
17167  global_node_on_shared_bound[iproc].push_back(global_shared_node_number);
17168  // And store the original boundaries to which it is associated
17169  global_node_original_boundaries[iproc].
17170  push_back(on_original_boundaries);
17171  // and the corresponding zeta coordinate
17172  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17173  }
17174 
17175  } // loop over nodes on shared boundaries with iproc
17176 
17177  } // for (iproc < nproc)
17178 
17179  // ---------------------------------------------------------
17180  // END: Get the original boundaries associated to each
17181  // node on a shared boundary
17182  // ---------------------------------------------------------
17183 
17184  // ---------------------------------------------------------
17185  // BEGIN: Send the info. to the corresponding processors,
17186  // package the info, send it and receive it in the
17187  // corresponding processor, unpackage and set the
17188  // boundaries associated with the received nodes
17189  // ---------------------------------------------------------
17190 
17191  // Get the communicator of the mesh
17192  OomphCommunicator* comm_pt = this->communicator_pt();
17193 
17194  // Set MPI info
17195  MPI_Status status;
17196  MPI_Request request;
17197 
17198  // loop over the processors
17199  for (unsigned iproc = 0; iproc < nproc; iproc++)
17200  {
17201  // The number of nodes shared between the pair of processors
17202  const unsigned n_shd_nodes_my_rank_iproc =
17203  node_on_shd_bnd_pt[iproc].size();
17204 
17205  // Are there shared nodes between these pair of processors
17206  // (my_rank, iproc)? Also ensure not to send info. within myself
17207  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17208  {
17209  // The flat package to send the info, to the iproc processor
17210  Vector<unsigned> flat_package_unsigned_send;
17211  // The very first entry is the number of nodes shared by the
17212  // pair of processors (my_rank, iproc)
17213  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17214 
17215  // Get the number of shared nodes on original boundaries
17216  const unsigned n_global_shared_node_on_original_boundary =
17217  global_node_on_shared_bound[iproc].size();
17218 
17219  // The second data is the number of shared nodes on original
17220  // boundaries
17221  flat_package_unsigned_send.
17222  push_back(n_global_shared_node_on_original_boundary);
17223 
17224  // ... also send the zeta coordinates associated with the
17225  // original boundaries
17226  Vector<double> flat_package_double_send;
17227 
17228  // loop over the nodes shared between this pair of processors
17229  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17230  {
17231  // Get the global shared node index
17232  const unsigned global_shared_node_index =
17233  global_node_on_shared_bound[iproc][i];
17234 
17235  // Put in the package the shared node index of the current
17236  // node
17237  flat_package_unsigned_send.push_back(global_shared_node_index);
17238 
17239  // Get the original boundaries to which the node is associated
17240  Vector<unsigned> on_original_boundaries =
17241  global_node_original_boundaries[iproc][i];
17242 
17243  // Get the associated zeta boundary coordinates
17244  Vector<double> zeta_coordinate =
17245  global_node_zeta_coordinate[iproc][i];
17246 
17247  // Get the number of original boundaries to which the node is
17248  // associated
17249  const unsigned n_original_boundaries =
17250  on_original_boundaries.size();
17251 
17252  // Put in the package the number of original boundaries the
17253  // node is associated
17254  flat_package_unsigned_send.push_back(n_original_boundaries);
17255 
17256  // loop over the original boundaries ids and include them in
17257  // the package
17258  for (unsigned j = 0; j < n_original_boundaries; j++)
17259  {
17260  // Put in the package each of the original boundaries to
17261  // which it is associated
17262  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17263  // The zeta coordinate on the boundary
17264  flat_package_double_send.push_back(zeta_coordinate[j]);
17265  } // for (j < n_original_boundaries)
17266 
17267  } // for (i < n_global_shared_node_on_original_boundary)
17268 
17269  // Send data UNSIGNED -----------------------------------------
17270  // Get the size of the package to communicate to the iproc
17271  // processor
17272  const unsigned n_udata_send = flat_package_unsigned_send.size();
17273  int n_udata_send_int = n_udata_send;
17274 
17275  // Send/receive data to/from iproc processor
17276  MPI_Isend(&n_udata_send_int,1,MPI_UNSIGNED,
17277  iproc,1,comm_pt->mpi_comm(), &request);
17278 
17279  int n_udata_received_int = 0;
17280  MPI_Recv(&n_udata_received_int,1,MPI_UNSIGNED,
17281  iproc,1,comm_pt->mpi_comm(),&status);
17282  MPI_Wait(&request,MPI_STATUS_IGNORE);
17283 
17284  if (n_udata_send!=0)
17285  {
17286  MPI_Isend(&flat_package_unsigned_send[0],
17287  n_udata_send,MPI_UNSIGNED,
17288  iproc,2,comm_pt->mpi_comm(),&request);
17289  }
17290 
17291  const unsigned n_udata_received =
17292  static_cast<unsigned>(n_udata_received_int);
17293 
17294  // Where to receive the data from the iproc processor
17295  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17296 
17297  if (n_udata_received!=0)
17298  {
17299  MPI_Recv(&flat_package_unsigned_receive[0],
17300  n_udata_received,MPI_UNSIGNED,
17301  iproc,2,comm_pt->mpi_comm(),&status);
17302  }
17303 
17304  if (n_udata_send!=0)
17305  {
17306  MPI_Wait(&request,MPI_STATUS_IGNORE);
17307  }
17308 
17309  // Send data DOUBLE -----------------------------------------
17310  // Get the size of the package to communicate to the iproc
17311  // processor
17312  const unsigned n_ddata_send = flat_package_double_send.size();
17313  int n_ddata_send_int = n_ddata_send;
17314 
17315  // Send/receive data to/from iproc processor
17316  MPI_Isend(&n_ddata_send_int,1,MPI_UNSIGNED,
17317  iproc,1,comm_pt->mpi_comm(), &request);
17318 
17319  int n_ddata_received_int = 0;
17320  MPI_Recv(&n_ddata_received_int,1,MPI_UNSIGNED,
17321  iproc,1,comm_pt->mpi_comm(),&status);
17322  MPI_Wait(&request,MPI_STATUS_IGNORE);
17323 
17324  if (n_ddata_send!=0)
17325  {
17326  MPI_Isend(&flat_package_double_send[0],
17327  n_ddata_send,MPI_DOUBLE,
17328  iproc,2,comm_pt->mpi_comm(),&request);
17329  }
17330 
17331  const unsigned n_ddata_received =
17332  static_cast<unsigned>(n_ddata_received_int);
17333 
17334  // Where to receive the data from the iproc processor
17335  Vector<double> flat_package_double_receive(n_ddata_received);
17336 
17337  if (n_ddata_received!=0)
17338  {
17339  MPI_Recv(&flat_package_double_receive[0],
17340  n_ddata_received,MPI_DOUBLE,
17341  iproc,2,comm_pt->mpi_comm(),&status);
17342  }
17343 
17344  if (n_ddata_send!=0)
17345  {
17346  MPI_Wait(&request,MPI_STATUS_IGNORE);
17347  }
17348 
17349  // Unpackage -------------------------------------------------
17350  // ... and associate the nodes to the corresponding original
17351  // boundaries
17352 
17353  // The number of nodes to be received
17354  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17355 
17356  // Increase and decrease the number of received shared nodes to
17357  // avoid the warning when compiling without PARANOID
17358  n_shared_nodes_received++;
17359  n_shared_nodes_received--;
17360 
17361 #ifdef PARANOID
17362  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17363  {
17364  std::ostringstream error_message;
17365  error_message
17366  <<"The number of shared nodes between the pair of processors is\n"
17367  <<"not the same\n"
17368  <<"N.shared nodes proc ("<<my_rank<<") with proc ("<<iproc<<"): ("
17369  <<n_shd_nodes_my_rank_iproc<<"\n"
17370  <<"N.shared nodes proc ("<<iproc<<") with proc ("<<my_rank<<"): ("
17371  <<n_shared_nodes_received<<"\n\n"
17372  <<"You should have got the same error in proc: ("<<iproc<<")\n\n";
17373  throw OomphLibError(error_message.str(),
17374  OOMPH_CURRENT_FUNCTION,
17375  OOMPH_EXCEPTION_LOCATION);
17376  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17377 #endif
17378 
17379  // Skip the number of nodes on shared boundaries on original
17380  // boundaries received (that is why next lines are commented)
17381 
17382  // The number of nodes on shared boundaries on original
17383  // boundaries
17384  //const unsigned n_shared_nodes_on_original_boundaries_received =
17385  // flat_package_unsigned_receive[1];
17386 
17387  // loop over the received info.
17388  unsigned current_index_data = 2;
17389  unsigned current_index_ddata = 0;
17390  while(current_index_data < n_udata_received)
17391  {
17392  // The global shared node number
17393  const unsigned global_shared_node_index =
17394  flat_package_unsigned_receive[current_index_data++];
17395 
17396  // The pointer to the node
17397  Node* node_pt = 0;
17398 
17399  // The number of original boundaries the node is associated
17400  // with
17401  const unsigned n_original_boundaries =
17402  flat_package_unsigned_receive[current_index_data++];
17403 
17404  // Get the node pointer
17405  node_pt = global_shared_node_pt[global_shared_node_index];
17406 #ifdef PARANOID
17407  if (node_pt == 0)
17408  {
17409  std::ostringstream error_message;
17410  error_message
17411  <<"The global shared node ("<<global_shared_node_index<<") "
17412  <<"could not be found in this processor!!!\n"
17413  <<"However, it was found in processor ("<<iproc<<"). The "
17414  <<"data may be no synchronised,\ntherefore "
17415  <<"we may be looking for a global shared node number that "
17416  <<"do not\ncorrespond with the one that was sent by "
17417  <<"processor ("<<iproc<<")\n\n";
17418  throw OomphLibError(error_message.str(),
17419  OOMPH_CURRENT_FUNCTION,
17420  OOMPH_EXCEPTION_LOCATION);
17421  }
17422 #endif // #ifdef PARANOID
17423 
17424  // loop over the number of original boundaries and associate
17425  // the node to each of those boundaries
17426  for (unsigned i = 0; i < n_original_boundaries; i++)
17427  {
17428  // Get the original boundary to which the node is associated
17429  // with
17430  const unsigned original_bound_id =
17431  flat_package_unsigned_receive[current_index_data++];
17432 
17433  // Associate the node with the boundary
17434  this->add_boundary_node(original_bound_id, node_pt);
17435 
17436  // Get the zeta boundary coordinate
17437  Vector<double> zeta(1);
17438  zeta[0] = flat_package_double_receive[current_index_ddata++];
17439  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17440  }
17441 
17442  } // while(current_data < n_data_received)
17443 
17444  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17445 
17446  } // for (iproc < nproc)
17447 
17448  // ---------------------------------------------------------
17449  // END: Send the info. to the corresponding processors,
17450  // package the info, send it and receive it in the
17451  // corresponding processor, unpackage and set the
17452  // boundaries associated with the received nodes
17453  // ---------------------------------------------------------
17454 
17455 }
17456 
17457  //======================================================================
17458  // \short In charge of creating additional halo(ed) elements on those
17459  // processors that have no shared boundaries in common but have
17460  // shared nodes
17461  // ======================================================================
17462 template <class ELEMENT>
17464  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
17465  &other_proc_shd_bnd_node_pt,
17466  Vector<Vector<Node *> > &iproc_currently_created_nodes_pt,
17467  Vector<Vector<Vector<unsigned> > > &global_node_names,
17468  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
17469  Vector<Node*> &global_shared_node_pt)
17470  {
17471  // Get the rank and number of processors
17472  const unsigned nproc = this->communicator_pt()->nproc();
17473  const unsigned my_rank = this->communicator_pt()->my_rank();
17474 
17475  // ---------------------------------------------------------------
17476  // BEGIN: Create a map to check whether a node is on the global
17477  // shared nodes. Also set a map to obtain the global
17478  // shared node index (this index is the same as the global
17479  // node name)
17480  // ---------------------------------------------------------------
17481  std::map<Node*, bool> is_global_shared_node;
17482  std::map<Node*, unsigned> global_shared_node_index;
17483 
17484  // Get the number of global shared nodes
17485  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17486  // loop over the global shared nodes
17487  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17488  {
17489  // Get the node
17490  Node* node_pt = global_shared_node_pt[i];
17491  // Indicate this is a shared global node
17492  is_global_shared_node[node_pt] = true;
17493  // Set the map to obtain the index of the global shared node
17494  global_shared_node_index[node_pt] = i;
17495 
17496  } // for (i < n_global_shared_nodes)
17497 
17498  // ---------------------------------------------------------------
17499  // END: Create a map to check whether a node is on the global
17500  // shared nodes. Also set a map to obtain the global
17501  // shared node index (this index is the same as the global
17502  // node name)
17503  // ---------------------------------------------------------------
17504 
17505  // ---------------------------------------------------------------
17506  // BEGIN: Loop over the haloed elements and check whether the nodes
17507  // on the haloed elements are part of the global shared
17508  // nodes. If that is the case then check whether the
17509  // element should be sent to the processors with which the
17510  // node is shared
17511  // ---------------------------------------------------------------
17512 
17513  // Elements that may be sent to other processors
17514  Vector<std::set<GeneralisedElement*> > additional_elements_pt(nproc);
17515 
17516  // loop over the processors
17517  for (unsigned iproc = 0; iproc < nproc; iproc++)
17518  {
17519  if (iproc!=my_rank)
17520  {
17521  // Get the haloed element with iproc
17522  Vector<GeneralisedElement*> haloed_ele_pt =
17523  this->root_haloed_element_pt(iproc);
17524 
17525  // Get the number of haloed elements
17526  const unsigned n_haloed_ele =
17527  this->nroot_haloed_element(iproc);
17528 
17529  // loop over the haloed elements with iproc
17530  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17531  {
17532  // A pointer to the generalised element
17533  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17534  // Get the finite element representation of the element
17535  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17536  // Get the number of nodes
17537  const unsigned n_nodes = ele_pt->nnode();
17538  // loop over the nodes of the element
17539  for (unsigned n = 0; n < n_nodes; n++)
17540  {
17541  // Get the node
17542  Node* node_pt = ele_pt->node_pt(n);
17543  // Is the node a global shared node?
17544  if (is_global_shared_node[node_pt])
17545  {
17546  // Get the index of the global shared node
17547  const unsigned global_index = global_shared_node_index[node_pt];
17548  // Get the global names of the node
17549  Vector<Vector<unsigned> > iglobal_names =
17550  global_node_names[global_index];
17551 
17552  // Get the number of names
17553  const unsigned n_names = iglobal_names.size();
17554  // loop over the names and check which processors share
17555  // this node (the processors to which the element may be
17556  // sent
17557  for (unsigned j = 0; j < n_names; j++)
17558  {
17559  // Get the processors to which the element should be
17560  // sent
17561  const unsigned proc1 = iglobal_names[j][0];
17562  const unsigned proc2 = iglobal_names[j][1];
17563  // Add the element to the set of additional elements to
17564  // sent from proc1 to proc2
17565  additional_elements_pt[proc1].insert(gele_pt);
17566  additional_elements_pt[proc2].insert(gele_pt);
17567 
17568  } // for (j < n_names)
17569 
17570  } // if (is_global_shared_node[node_pt])
17571 
17572  } // for (n < n_nodes)
17573 
17574  } // for (ihd < n_haloed_ele)
17575 
17576  } // if (iproc!=my_rank)
17577 
17578  } // for (iproc < nproc)
17579 
17580  // ---------------------------------------------------------------
17581  // Now check whether the element should really be sent to the
17582  // indicated processors
17583 
17584  // The elements from this (my_rank) processor that will be sent to
17585  // other processors
17586  Vector<Vector<FiniteElement*> > send_haloed_ele_pt(nproc);
17587 
17588  // loop over the processors
17589  for (unsigned iproc = 0; iproc < nproc; iproc++)
17590  {
17591  if (iproc!=my_rank)
17592  {
17593  // Get the set of element that may be sent to the iproc
17594  // processor
17595  std::set<GeneralisedElement*> iproc_ele_pt =
17596  additional_elements_pt[iproc];
17597  // loop over the element that may be sent to the iproc
17598  // processor
17599  for (std::set<GeneralisedElement*>::iterator it =
17600  iproc_ele_pt.begin(); it!=iproc_ele_pt.end(); it++)
17601  {
17602  // Get a pointer to the element
17603  GeneralisedElement* gele_pt = (*it);
17604 
17605  // Get the haloed element with iproc
17606  Vector<GeneralisedElement*> haloed_ele_pt =
17607  this->root_haloed_element_pt(iproc);
17608 
17609  // Get the number of haloed elements
17610  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17611 
17612  // Flag to indicate whether the element has been already sent
17613  // to the iproc processor
17614  bool send_ele_to_iproc_processor = true;
17615  // loop over the haloed elements with iproc and check whether
17616  // the element has been already sent to iproc (if it is
17617  // already a haloed element with iproc then it has been
17618  // already sent)
17619  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17620  {
17621  // A pointer to the generalised element
17622  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17623  if (gele_pt == ghd_ele_pt)
17624  {
17625  // Mark the element as not required to be sent
17626  send_ele_to_iproc_processor = false;
17627  // Break the loop that searchs for the element on the
17628  // haloed elements with iproc
17629  break;
17630  }
17631 
17632  } // for (ihd < n_haloed_ele)
17633 
17634  // Do we need to sent the element?
17635  if (send_ele_to_iproc_processor)
17636  {
17637  // Get the finite element representation of the element
17638  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17639  // Add the element to those that will be sent to the iproc
17640  // processor
17641  send_haloed_ele_pt[iproc].push_back(ele_pt);
17642  }
17643 
17644  } // loop over the elements that may be sent to the iproc
17645  // processor
17646 
17647  } // if (iproc!=my_rank)
17648 
17649  } // for (iproc < nproc)
17650 
17651  // ---------------------------------------------------------------
17652  // END: Loop over the haloed element and check whether the nodes
17653  // on the haloed elements are part of the global shared
17654  // nodes. If that is the case then check whether the element
17655  // should be sent to the processors with which the node is
17656  // shared
17657  // ---------------------------------------------------------------
17658 
17659  // ============================================================
17660  // Now send the additional elements
17661  // ============================================================
17662  // Loop over the processors to send data
17663  for (unsigned iproc = 0; iproc < nproc; iproc++)
17664  {
17665  // There are no elements to send with myself
17666  if (iproc != my_rank)
17667  {
17668  // Get the number of additional haloed elements to send
17669  const unsigned n_additional_haloed_ele =
17670  send_haloed_ele_pt[iproc].size();
17671 
17672  // Clear send and receive buffers
17673  Flat_packed_unsigneds.clear();
17674  Flat_packed_doubles.clear();
17675 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17677 #endif
17678 
17679  // The very first data of the flat packed is the number of
17680  // additional haloed elements, this will be the number of
17681  // additional halo elements to create on the receiver processor
17682  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17683 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17684  std::stringstream junk;
17685  junk << "Number of haloed elements " << nhaloed_ele;
17686  Flat_packed_unsigneds_string.push_back(junk.str());
17687 #endif
17688 
17689  // Loop over the additioanl haloed elements
17690  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17691  {
17692  // Get pointer to the additional haloed element
17693  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17694  const unsigned nroot_haloed_ele =
17695  this->nroot_haloed_element(iproc);
17696 
17697  // Check if the element has been already added to the
17698  // halo(ed) scheme
17699 
17700  // Get the generalised version of the element
17701  GeneralisedElement *gen_ele_pt = ele_pt;
17702  // Try to add the haloed element
17703  const unsigned haloed_ele_index =
17704  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17705 
17706  // Was the element added or only returned the index of the
17707  // element
17708  if (nroot_haloed_ele == haloed_ele_index)
17709  {
17710  Flat_packed_unsigneds.push_back(1);
17711 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17712  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
17713 #endif
17714 
17715  // Get additional info. related with the haloed element
17716  get_required_elemental_information_helper(iproc, ele_pt);
17717 
17718  // Get the nodes on the element
17719  const unsigned nnodes = ele_pt->nnode();
17720  for (unsigned j = 0; j < nnodes; j++)
17721  {
17722  Node* node_pt = ele_pt->node_pt(j);
17723 
17724  // Package the info. of the nodes
17725  // The destination processor goes in the arguments
17726  add_haloed_node_helper(iproc, node_pt);
17727 
17728  } // for (j < nnodes)
17729 
17730  } // add the element and send its nodes
17731  else // The haloed element already exists
17732  {
17733  Flat_packed_unsigneds.push_back(0);
17734 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17735  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
17736 #endif
17737  Flat_packed_unsigneds.push_back(haloed_ele_index);
17738 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17739  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
17740 #endif
17741  } // else (next_haloed_ele == external_haloed_ele_index)
17742 
17743  } // for (e < n_additional_haloed_ele)
17744 
17745  // Send and received the additional haloed elements (all
17746  // processors send and receive)
17747 
17748  // The processor to which send the elements
17749  int send_proc = static_cast<int>(iproc);
17750  // The processor from which receive the elements
17751  int recv_proc = static_cast<int>(iproc);
17752  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17753 
17754  // Reset the counters
17757 
17758  // Get the number of additional halo element to be created
17759  const unsigned n_additional_halo_ele =
17761 
17762 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17764  << " Number of elements need to be constructed "
17766  << std::endl;
17767 #endif
17768 
17769  // Create the additional halo elements
17770  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17771  {
17772  // Create halo element from received info. of "iproc"
17773  // processor on the current processor
17774  create_halo_element(iproc,
17775  iproc_currently_created_nodes_pt[iproc],
17776  other_proc_shd_bnd_node_pt,
17777  global_node_names,
17778  node_name_to_global_index,
17779  global_shared_node_pt);
17780 
17781  } // for (e < n_additional_halo_ele)
17782 
17783  } // if (iproc != my_rank)
17784 
17785  } // for (iproc < nproc)
17786 
17787  }
17788 
17789  // *********************************************************************
17790  // Start communication functions
17791  // *********************************************************************
17792 
17793  //========start of get_required_elemental_information_helper==============
17794  /// \short Helper function to get the required elemental information from
17795  /// an haloed element. This info. involves the association of the element
17796  /// to a boundary or region.
17797  //========================================================================
17798  template<class ELEMENT>
17801  FiniteElement* ele_pt)
17802  {
17803  // Check if the element is associated with the original boundaries
17804  const unsigned nbound = this->initial_shared_boundary_id();
17805 
17806  // ------------------------------------------------------------------
17807  // Stores the information regarding the boundaries associated to the
17808  // element (it that is the case)
17809  Vector<unsigned> associated_boundaries;
17810  Vector<unsigned> face_index_on_boundary;
17811 
17812  unsigned counter_face_indexes = 0;
17813 
17814  for (unsigned b = 0; b < nbound; b++)
17815  {
17816  // Get the number of elements associated to boundary i
17817  const unsigned nboundary_ele = nboundary_element(b);
17818  for (unsigned e = 0; e < nboundary_ele; e++)
17819  {
17820  if (ele_pt == this->boundary_element_pt(b,e))
17821  {
17822  // Keep track of the boundaries associated to the element
17823  associated_boundaries.push_back(b);
17824  // Get the face index
17825  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
17826  counter_face_indexes++;
17827 #ifdef PARANOID
17828  if (counter_face_indexes > 2)
17829  {
17830  std::stringstream error_message;
17831  error_message
17832  << "A triangular element can not have more than two of its faces "
17833  << "on a boundary!!!\n\n";
17834  throw OomphLibError(error_message.str(),
17835  OOMPH_CURRENT_FUNCTION,
17836  OOMPH_EXCEPTION_LOCATION);
17837  }
17838 #else
17839  // Already found 2 face indexes on the same boundary?
17840  if (counter_face_indexes==2) {break;}
17841 #endif // #ifdef PARANOID
17842 
17843  } // if (ele_pt == this->boundary_element_pt(b,e))
17844 
17845  } // (e < nboundary_ele)
17846 
17847  } // (b < nbound)
17848 
17849  // If the element is associated to any boundary then package all the
17850  // relevant info
17851  const unsigned nassociated_boundaries = associated_boundaries.size();
17852  if (nassociated_boundaries > 0)
17853  {
17854  Flat_packed_unsigneds.push_back(1);
17855 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17856  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
17857 #endif
17858  Flat_packed_unsigneds.push_back(nassociated_boundaries);
17859 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17860  std::stringstream junk;
17861  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
17862  Flat_packed_unsigneds_string.push_back(junk.str());
17863 #endif
17864 
17865  // Package the ids of the associated boundaries and the
17866  // corresponding face index for each boundary (if the element is a
17867  // corner element, it will have two faces associated to the
17868  // boundary)
17869  for (unsigned i = 0; i < nassociated_boundaries; i++)
17870  {
17871  unsigned b = associated_boundaries[i];
17872  Flat_packed_unsigneds.push_back(b);
17873 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17874  std::stringstream junk;
17875  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
17876  Flat_packed_unsigneds_string.push_back(junk.str());
17877 #endif
17878  unsigned f = face_index_on_boundary[i];
17879  Flat_packed_unsigneds.push_back(f);
17880 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17881  std::stringstream junk2;
17882  junk2 << "Face index " << f << " for associated boundary " << b;
17883  Flat_packed_unsigneds_string.push_back(junk2.str());
17884 #endif
17885  }
17886 
17887  // If the element is associated to any boundary then we should
17888  // check if the mesh has regions, if that is the case then we need
17889  // to check to which region the boundary element does belong
17890 
17891  // If the mesh has regions we should look for the element
17892  // associated to a boundary and a specified region
17893  Vector<Vector<unsigned> > associated_boundaries_and_regions;
17894  Vector<unsigned> face_index_on_boundary_and_region;
17895 
17896  // Now check for the case when we have regions in the mesh
17897  const unsigned n_regions = this->nregion();
17898  if (n_regions > 1)
17899  {
17900  // Used to count the number of faces associated with
17901  // boundary-regions
17902  unsigned counter_face_indexes_in_regions = 0;
17903  // Loop over the boundaries
17904  for (unsigned b = 0; b < nbound; b++)
17905  {
17906  // Go through each region by getting the region id
17907  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
17908  {
17909  // Get thre region id associated with the (i_reg)-th region
17910  const unsigned region_id =
17911  static_cast<unsigned>(this->Region_attribute[i_reg]);
17912 
17913  // Loop over all elements associated with the current boundary
17914  // and the i_reg-th region and check if the element is part of
17915  // any region
17916  const unsigned nele_in_region =
17917  this->nboundary_element_in_region(b, region_id);
17918  for (unsigned ee = 0; ee < nele_in_region; ee++)
17919  {
17920  // Check if the boundary-region element is the same as the
17921  // element
17922  if (ele_pt ==
17923  this->boundary_element_in_region_pt(b, region_id, ee))
17924  {
17925  // Storage for the boundary and region associated to the
17926  // element
17927  Vector<unsigned> bound_and_region(2);
17928 
17929  // Keep track of the boundaries associated to the element
17930  bound_and_region[0] = b;
17931  // Keep track of the regions associated to the element
17932  bound_and_region[1] = region_id;
17933  // Add the boundaries and regions in the storage to be
17934  // sent to other processors
17935  associated_boundaries_and_regions.push_back(bound_and_region);
17936  // Get the face index and keep track of it
17937  face_index_on_boundary_and_region.push_back(
17938  this->face_index_at_boundary_in_region(b,region_id,ee));
17939 
17940  // Increase the number of faces of the element associated
17941  // to boundary-regions
17942  counter_face_indexes_in_regions++;
17943 
17944 #ifdef PARANOID
17945  if (counter_face_indexes_in_regions > 2)
17946  {
17947  std::stringstream error_message;
17948  error_message
17949  << "A triangular element can not have more than two of its\n"
17950  << "faces on a boundary!!!\n\n";
17951  throw OomphLibError(error_message.str(),
17952  OOMPH_CURRENT_FUNCTION,
17953  OOMPH_EXCEPTION_LOCATION);
17954  } // if (counter_face_indexes_in_regions > 2)
17955 #endif
17956 
17957  } // The element is a boundary-region element
17958 
17959  } // for (ee < nele_in_region)
17960 
17961  } // for (i_reg < n_regions)
17962 
17963  } // for (b < nbound)
17964 
17965  } // if (n_regions > 1)
17966 
17967  // Now package the info. to be sent to other processors
17968  const unsigned nassociated_boundaries_and_regions =
17969  associated_boundaries_and_regions.size();
17970  if (nassociated_boundaries_and_regions > 0)
17971  {
17972  Flat_packed_unsigneds.push_back(1);
17973 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17974  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
17975 #endif
17976 
17977  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
17978 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17979  std::stringstream junk;
17980  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
17981  Flat_packed_unsigneds_string.push_back(junk.str());
17982 #endif
17983 
17984  // Package the ids of the associated boundaries, regions and the
17985  // corresponding face index for each boundary-region (if the
17986  // element is a corner element, it will have two faces
17987  // associated to the boundary-region)
17988  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
17989  {
17990  const unsigned b = associated_boundaries_and_regions[i][0];
17991  Flat_packed_unsigneds.push_back(b);
17992 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17993  std::stringstream junk;
17994  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
17995  Flat_packed_unsigneds_string.push_back(junk.str());
17996 #endif
17997 
17998  const unsigned r = associated_boundaries_and_regions[i][1];
17999  Flat_packed_unsigneds.push_back(r);
18000 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18001  std::stringstream junk2;
18002  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
18003  Flat_packed_unsigneds_string.push_back(junk2.str());
18004 #endif
18005 
18006  const unsigned f = face_index_on_boundary_and_region[i];
18007  Flat_packed_unsigneds.push_back(f);
18008 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18009  std::stringstream junk3;
18010  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
18011  Flat_packed_unsigneds_string.push_back(junk3.str());
18012 #endif
18013  } // for (i < nassociated_boundaries_and_regions)
18014  } // if (nassociated_boundaries_and_regions > 0)
18015  else
18016  {
18017  Flat_packed_unsigneds.push_back(0);
18018 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18019  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
18020 #endif
18021  } // else if (nassociated_boundaries_and_regions > 0)
18022 
18023  }
18024  else
18025  {
18026  Flat_packed_unsigneds.push_back(0);
18027 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18028  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
18029 #endif
18030  }
18031 
18032  // ------------------------------------------------------------
18033  // Now review if the element is associated to a shared boundary
18034 
18035  // Store the shared boundaries, and therefore the face indexes
18036  // associated to the element
18037  Vector<unsigned> associated_shared_boundaries;
18038  Vector<unsigned> face_index_on_shared_boundary;
18039 
18040  // Get the shared boundaries in this processor
18041  Vector<unsigned> my_rank_shared_boundaries_ids;
18042  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18043 
18044  // Get the number of shared boundaries
18045  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18046  // Loop over the shared boundaries
18047  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18048  {
18049  // Get the boundary id
18050  const unsigned sb = my_rank_shared_boundaries_ids[i];
18051 
18052  // Get the number of elements associated to shared boundary sb
18053  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18054  for (unsigned e = 0; e < nboundary_ele; e++)
18055  {
18056  if (ele_pt == this->shared_boundary_element_pt(sb,e))
18057  {
18058  // Keep track of the boundaries associated to the element
18059  associated_shared_boundaries.push_back(sb);
18060  // Get the face index
18061  face_index_on_shared_boundary.push_back(
18062  this->face_index_at_shared_boundary(sb, e));
18063  }
18064  } // (e < nboundary_ele)
18065  } // (i < nmy_rank_shd_bnd)
18066 
18067  // If the element is associated to a shared boundary then package
18068  // all the relevant info
18069  const unsigned nassociated_shared_boundaries =
18070  associated_shared_boundaries.size();
18071  if (nassociated_shared_boundaries > 0)
18072  {
18073  Flat_packed_unsigneds.push_back(3);
18074 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18075  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
18076 #endif
18077  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18078 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18079  std::stringstream junk;
18080  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
18081  Flat_packed_unsigneds_string.push_back(junk.str());
18082 #endif
18083 
18084  // Package the ids of the associated boundaries
18085  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18086  {
18087  const unsigned b = associated_shared_boundaries[i];
18088  Flat_packed_unsigneds.push_back(b);
18089 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18090  std::stringstream junk;
18091  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
18092  Flat_packed_unsigneds_string.push_back(junk.str());
18093 #endif
18094 
18095  const unsigned f = face_index_on_shared_boundary[i];
18096  Flat_packed_unsigneds.push_back(f);
18097 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18098  std::stringstream junk2;
18099  junk2 << "Face index " << f << " for associated shared boundary " << b;
18100  Flat_packed_unsigneds_string.push_back(junk2.str());
18101 #endif
18102  }
18103  }
18104  else
18105  {
18106  Flat_packed_unsigneds.push_back(0);
18107 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18108  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
18109 #endif
18110  }
18111 
18112  }
18113 
18114  //========start of get_required_nodal_information_helper==================
18115  /// Helper function to get the required nodal information from an
18116  /// haloed node so that a fully-functional halo node (and therefore element)
18117  /// can be created on the receiving process
18118  //========================================================================
18119  template<class ELEMENT>
18122  Node* nod_pt)
18123  {
18124  unsigned my_rank = this->communicator_pt()->my_rank();
18125  const unsigned nproc = this->communicator_pt()->nproc();
18126 
18127  // Tell the halo copy of this node how many values there are
18128  // [NB this may be different for nodes within the same element, e.g.
18129  // when using Lagrange multipliers]
18130  unsigned n_val=nod_pt->nvalue();
18131  Flat_packed_unsigneds.push_back(n_val);
18132 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18133  Flat_packed_unsigneds_string.push_back("Number of values");
18134 #endif
18135 
18136  unsigned n_dim=nod_pt->ndim();
18137 
18138  // Default number of previous values to 1
18139  unsigned n_prev=1;
18140  if (this->Time_stepper_pt!=0)
18141  {
18142  // Add number of history values to n_prev
18143  n_prev=this->Time_stepper_pt->ntstorage();
18144  }
18145 
18146  // -----------------------------------------------------
18147  // Is the node on an original boundary?
18148  // Store the original boundaries where the node may be
18149  Vector<unsigned> original_boundaries;
18150  // Loop over the original boundaries of the mesh and check if live
18151  // on one of them
18152  const unsigned n_bnd = this->initial_shared_boundary_id();
18153  for (unsigned bb=0;bb<n_bnd;bb++)
18154  {
18155  // Which boundaries (could be more than one) is it on?
18156  if (nod_pt->is_on_boundary(bb))
18157  {
18158  original_boundaries.push_back(bb);
18159  }
18160 
18161  }
18162 
18163  const unsigned n_original_boundaries = original_boundaries.size();
18164  // Is the node on any original boundary?
18165  if (n_original_boundaries > 0)
18166  {
18167  // Indicate that the node is on an original boundary
18168  Flat_packed_unsigneds.push_back(2);
18169 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18170  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
18171 #endif
18172 
18173  Flat_packed_unsigneds.push_back(n_original_boundaries);
18174 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18175  std::stringstream junk;
18176  junk << "Node is on "<< n_original_boundaries << " original boundaries";
18177  Flat_packed_unsigneds_string.push_back(junk.str());
18178 #endif
18179 
18180  // Loop over the original boundaries the node is on
18181  for (unsigned i=0;i<n_original_boundaries;i++)
18182  {
18183  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18184 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18185  std::stringstream junk;
18186  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
18187  Flat_packed_unsigneds_string.push_back(junk.str());
18188 #endif
18189  // Get the boundary coordinate of the node
18190  Vector<double> zeta(1);
18191  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
18192  Flat_packed_doubles.push_back(zeta[0]);
18193  }
18194  }
18195  else
18196  {
18197  // Indicate that the node is NOT on an original boundary
18198  Flat_packed_unsigneds.push_back(0);
18199 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18200  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
18201 #endif
18202  }
18203 
18204  // -------------------------------------------------------
18205  // Is the node on shared boundaries?
18206  bool node_on_shared_boundary = false;
18207  // Loop over the shared boundaries with the iproc processors and
18208  // check if live on one of them
18209  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18210  for (unsigned bb=0;bb<n_shd_bnd;bb++)
18211  {
18212  // Get the boundary id
18213  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18214  // Which boundaries (could be more than one) is it on?
18215  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18216  {
18217  node_on_shared_boundary = true;
18218  break;
18219  }
18220  }
18221 
18222  // If the node live on any of the shared boundaries with the iproc
18223  // processor then just get the node number according to the
18224  // sorted_shared_boundary_node_pt() scheme and send it accross
18225  if (node_on_shared_boundary)
18226  {
18227  Flat_packed_unsigneds.push_back(1);
18228 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18229  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18230 #endif
18231 
18232  // Store the shared boundaries where the node is on
18233  Vector<unsigned> shd_boundaries;
18234  // Loop over the shared boundaries with the iproc processor
18235  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18236  {
18237  // Get the boundary id
18238  const unsigned i_bnd =
18239  this->shared_boundaries_ids(my_rank, iproc, bb);
18240  // Which boundaries (could be more than one) is it on?
18241  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18242  {
18243  shd_boundaries.push_back(i_bnd);
18244  }
18245  }
18246 
18247  // Get the number of shared boundaries the node is on
18248  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18249  // Send the number of shared boundaries the node is on
18250  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18251 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18252  std::stringstream junk;
18253  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
18254  Flat_packed_unsigneds_string.push_back(junk.str());
18255 #endif
18256 
18257  // Loop over the shared boundaries to send their ids
18258  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
18259  {
18260  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18261 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18262  std::stringstream junk;
18263  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18264  Flat_packed_unsigneds_string.push_back(junk.str());
18265 #endif
18266  }
18267 
18268  // Given that the node is on at least one boundary get the index
18269  // of the node in one of the boundaries and send this index
18270  unsigned shared_boundary_id = shd_boundaries[0];
18271  // Get the number of nodes on the given shared boundary
18272  const unsigned n_nodes_on_shared_boundary =
18273  nsorted_shared_boundary_node(shared_boundary_id);
18274  // Store the index of the node on the shared boundary
18275  unsigned index_node_on_shared_boundary;
18276 #ifdef PARANOID
18277  // Flag to know if the node has been found
18278  bool found_index_node_on_shared_boundary = false;
18279 #endif
18280  // Loop over the nodes on the shared boundary to find the node
18281  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18282  {
18283  // Get the i-th node on the shared boundary
18284  Node* shared_node_pt =
18285  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18286  // Is the node we are looking for
18287  if (shared_node_pt == nod_pt)
18288  {
18289  // Store the index
18290  index_node_on_shared_boundary = i;
18291 #ifdef PARANOID
18292  // Mark as found
18293  found_index_node_on_shared_boundary = true;
18294 #endif
18295  break; // break
18296  }
18297 
18298  } // for (i < nnodes_on_shared_boundary)
18299 
18300 #ifdef PARANOID
18301  if (!found_index_node_on_shared_boundary)
18302  {
18303  std::ostringstream error_message;
18304  error_message
18305  <<"The index of the node on boundary ("
18306  <<shared_boundary_id<<") was not found.\n"
18307  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18308  <<nod_pt->x(1)<<").\n";
18309  throw OomphLibError(
18310  error_message.str(),
18311  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18312  OOMPH_EXCEPTION_LOCATION);
18313  }
18314 #endif
18315  // Send the index of the node on the shared boundary
18316  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18317 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18318  std::stringstream junk2;
18319  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
18320  <<index_node_on_shared_boundary;
18321  Flat_packed_unsigneds_string.push_back(junk2.str());
18322 #endif
18323 
18324  } // if (node_on_shared_boundary)
18325  else
18326  {
18327  // The node is not on a shared boundary
18328  Flat_packed_unsigneds.push_back(0);
18329 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18330  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
18331 #endif
18332  }
18333 
18334  // ----------------------------------------------------------------
18335  // Is the node on any shared boundary where the receiver processor
18336  // is not involved?
18337 
18338  // Now check if the node is on a shared boundary created by the
18339  // current processor (my_rank) and other processor different that
18340  // the iproc processor. This info. will help to complete the sending
18341  // of halo(ed) information between processors
18342 
18343  // Flag to know if the node is on a shared boundary with other
18344  // processor
18345  bool node_on_shared_boundary_with_other_processors = false;
18346  // Count the number of other shared boundaries it could be on
18347  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18348 
18349  // Loop over the shared boundaries of the sent processor (my_rank)
18350  // and other processors (jproc)
18351  for (unsigned jproc = 0; jproc < nproc; jproc++)
18352  {
18353  // Do not search with the iproc processor , that was done before
18354  // above because we are sending info to that processor
18355  if (jproc != iproc)
18356  {
18357  // Get the number of shared boundaries with the jproc processor
18358  const unsigned n_jshd_bnd =
18359  this->nshared_boundaries(my_rank, jproc);
18360  // Loop over the shared boundaries
18361  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
18362  {
18363  // Get the boundary id
18364  const unsigned j_shd_bnd =
18365  this->shared_boundaries_ids(my_rank, jproc, bb);
18366  // Is the node part of this boundary?
18367  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18368  {
18369 // DEBP("Sending to");
18370 // DEBP(iproc);
18371 // DEBP("Pair of procs where other shared");
18372 // DEBP(my_rank);
18373 // DEBP(jproc);
18374 // DEBP(i_bnd);
18375  node_on_shared_boundary_with_other_processors = true;
18376  // Increase the counter for the number of shared boundaries
18377  // with other processors the node is on
18378  nshared_boundaries_with_other_processors_have_node++;
18379  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18380 
18381  } // for (bb<n_jshd_bnd)
18382 
18383  } // if (jproc != iproc)
18384 
18385  } // for (jproc < nproc)
18386 
18387  // If the node is on a shared boundary with another processor
18388  // (my_rank, jproc), then send the flag and look for the info.
18389  if (node_on_shared_boundary_with_other_processors)
18390  {
18391  Flat_packed_unsigneds.push_back(4);
18392 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18393  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
18394 #endif
18395 
18396  // The number of packages of information that will be sent to the
18397  // "iproc" processor. This helps to know how many packages of data
18398  // read from the received processor
18399  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
18400 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18401  std::stringstream junk;
18402  junk << "Number of other shared boundaries that the node is on: "
18403  << nshared_boundaries_with_other_processors_have_node;
18404  Flat_packed_unsigneds_string.push_back(junk.str());
18405 #endif
18406 
18407  // Counter to ensure that the correct number of data has been sent
18408  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18409  // Loop over the shared boundaries with other processors and get:
18410  // 1) The processors defining the shared boundary
18411  // 2) The shared boundary id
18412  // 3) The index of the node on the shared boundary
18413  Vector<unsigned> other_processor_1;
18414  Vector<unsigned> other_processor_2;
18415  Vector<unsigned> shd_bnd_ids;
18416  Vector<unsigned> indexes;
18417  // Loop over the processors again
18418  for (unsigned jproc = 0; jproc < nproc; jproc++)
18419  {
18420  // Do not search with the iproc processor, that was done before
18421  // above
18422  if (jproc != iproc)
18423  {
18424  // Get the number of shared boundaries with the jproc
18425  // processor
18426  const unsigned n_jshd_bnd =
18427  this->nshared_boundaries(my_rank, jproc);
18428  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18429  {
18430  // Get the boundary id
18431  const unsigned j_shd_bnd =
18432  this->shared_boundaries_ids(my_rank, jproc, bb);
18433  // Is the node part of this boundary?
18434  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18435  {
18436  // Include the first processor
18437  other_processor_1.push_back(my_rank);
18438  // Include the second processor
18439  other_processor_2.push_back(jproc);
18440  // Include the shared boundary id
18441  shd_bnd_ids.push_back(j_shd_bnd);
18442  // Increase the counter for found shared boundaries with
18443  // other processors
18444  counter_shd_bnd_with_other_procs_have_node++;
18445  }
18446 
18447  } // for (bb < nshared_bnd)
18448 
18449  } // if (jproc != iproc)
18450 
18451  } // for (jproc < nproc)
18452 
18453  // Get the indexes of the node on all the shared boundaries where
18454  // it was found
18455  const unsigned n_other_processors = other_processor_1.size();
18456  // Loop over the processors where the node was found
18457  for (unsigned i = 0; i < n_other_processors; i++)
18458  {
18459  // Get the shared boundary id
18460  unsigned shd_bnd_id = shd_bnd_ids[i];
18461  // Get the number of nodes on that shared boundary
18462  const unsigned n_nodes_on_shd_bnd =
18463  nsorted_shared_boundary_node(shd_bnd_id);
18464 
18465 #ifdef PARANOID
18466  bool found_index_node_on_shared_boundary = false;
18467 #endif
18468  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18469  {
18470  // Get the i-th shared boundary node
18471  Node* shared_node_pt =
18472  sorted_shared_boundary_node_pt(shd_bnd_id, i);
18473  // Is the same node?
18474  if (shared_node_pt == nod_pt)
18475  {
18476 // DEBP(i_node);
18477 // DEBP(nod_pt->x(0));
18478 // DEBP(nod_pt->x(1));
18479  // Include the index of the node
18480  indexes.push_back(i);
18481 #ifdef PARANOID
18482  // Mark as found the node
18483  found_index_node_on_shared_boundary = true;
18484 #endif
18485  break;
18486  } // if (shared_node_pt == nod_pt)
18487 
18488  } // for (i < n_nodes_on_shd_bnd)
18489 
18490 #ifdef PARANOID
18491  if (!found_index_node_on_shared_boundary)
18492  {
18493  std::ostringstream error_message;
18494  error_message
18495  <<"The index of the node on boundary ("
18496  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
18497  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18498  <<nod_pt->x(1)<<").\n";
18499  throw OomphLibError(
18500  error_message.str(),
18501  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18502  OOMPH_EXCEPTION_LOCATION);
18503  }
18504 #endif
18505  } // for (i < n_other_processors)
18506 
18507  // Now send the info. but first check that the number of found
18508  // nodes be the same that the previously found shared boundaries
18509  // with the node
18510 #ifdef PARANOID
18511  if (counter_shd_bnd_with_other_procs_have_node !=
18512  nshared_boundaries_with_other_processors_have_node)
18513  {
18514  std::ostringstream error_message;
18515  error_message
18516  <<"The number of shared boundaries where the node is on "
18517  <<"is different:\n"
18518  << "nshared_boundaries_with_other_processors_have_node: ("
18519  << nshared_boundaries_with_other_processors_have_node
18520  << ")\n"
18521  << "counter_shd_bnd_with_other_procs_have_node: ("
18522  << counter_shd_bnd_with_other_procs_have_node
18523  << ")\n";
18524  throw OomphLibError(
18525  error_message.str(),
18526  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18527  OOMPH_EXCEPTION_LOCATION);
18528  } // if (counter_shd_bnd_with_other_procs_have_node !=
18529  // nshared_boundaries_with_other_processors_have_node)
18530 #endif
18531 
18532  // Loop over the info. to send it
18533  for (unsigned i = 0; i < n_other_processors; i++)
18534  {
18535  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18536 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18537  std::stringstream junk1;
18538  junk1 << "Processor where the other shared boundary "
18539  << "has the node: " << other_processor_1[i];
18540  Flat_packed_unsigneds_string.push_back(junk1.str());
18541 #endif
18542 
18543  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18544 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18545  std::stringstream junk2;
18546  junk2 << "Processor where the other shared boundary "
18547  << "has the node: " << other_processor_2[i];
18548  Flat_packed_unsigneds_string.push_back(junk2.str());
18549 #endif
18550 
18551  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18552 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18553  std::stringstream junk3;
18554  junk3 << "Other shared boundary id where the node is on"
18555  << boundaries[i];
18556  Flat_packed_unsigneds_string.push_back(junk3.str());
18557 #endif
18558 
18559  Flat_packed_unsigneds.push_back(indexes[i]);
18560 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18561  std::stringstream junk4;
18562  junk4 << "Node index on other shared boundary "
18563  <<boundaries[i] << " is "
18564  << indexes[i];
18565  Flat_packed_unsigneds_string.push_back(junk4.str());
18566 #endif
18567 
18568  } // for (i < n_other_processors)
18569 
18570  } // if (node_on_shared_boundary_with_other_processors)
18571  else
18572  {
18573  Flat_packed_unsigneds.push_back(0);
18574 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18575  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
18576 #endif
18577  } // else if (node_on_shared_boundary_with_other_processors)
18578 
18579  // Now check if it is required to send the info. of the node. If the
18580  // node is not on a shared boundary with the iproc processor then we
18581  // need to send the info.
18582 
18583  if (!node_on_shared_boundary)
18584  {
18585  // Send all the info. to create it
18586 
18587  // Is the Node algebraic? If so, send its ref values and
18588  // an indication of its geometric objects if they are stored
18589  // in the algebraic mesh
18590  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
18591  if (alg_nod_pt!=0)
18592  {
18593  // The external mesh should be algebraic
18594  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
18595 
18596  // Get default node update function ID
18597  unsigned update_id=alg_nod_pt->node_update_fct_id();
18598  Flat_packed_unsigneds.push_back(update_id);
18599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18600  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18601 #endif
18602 
18603  // Get reference values at default...
18604  unsigned n_ref_val=alg_nod_pt->nref_value();
18605  Flat_packed_unsigneds.push_back(n_ref_val);
18606 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18607  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18608 #endif
18609  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
18610  {
18611  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18612  }
18613 
18614  // Access geometric objects at default...
18615  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
18616  Flat_packed_unsigneds.push_back(n_geom_obj);
18617 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18618  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18619 #endif
18620  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
18621  {
18622  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
18623 
18624  // Check this against the stored geometric objects in mesh
18625  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
18626 
18627  // Default found index to zero
18628  unsigned found_geom_object=0;
18629  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
18630  {
18631  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
18632  {
18633  found_geom_object=i_list;
18634  }
18635  }
18636  Flat_packed_unsigneds.push_back(found_geom_object);
18637 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18638  Flat_packed_unsigneds_string.push_back("Found geom object");
18639 #endif
18640  }
18641  } // (if alg_nod_pt!=0)
18642 
18643  // Is it a SolidNode?
18644  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
18645  if (solid_nod_pt!=0)
18646  {
18647  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
18648  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
18649  {
18650  for (unsigned t=0;t<n_prev;t++)
18651  {
18652  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
18653  value(t,i_val));
18654  }
18655  }
18656 
18657  Vector<double> values_solid_node;
18658  solid_nod_pt->add_values_to_vector(values_solid_node);
18659  const unsigned nvalues_solid_node = values_solid_node.size();
18660  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18661 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18662  std::stringstream junk;
18663  junk << "Number of values solid node: "
18664  << nvalues_solid_node;
18665  Flat_packed_unsigneds_string.push_back(junk.str());
18666 #endif
18667  for (unsigned i = 0; i < nvalues_solid_node; i++)
18668  {
18669  Flat_packed_doubles.push_back(values_solid_node[i]);
18670  }
18671  }
18672 
18673  // Finally copy info required for all node types
18674  for (unsigned i_val=0;i_val<n_val;i_val++)
18675  {
18676  for (unsigned t=0;t<n_prev;t++)
18677  {
18678  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
18679  }
18680  }
18681 
18682  // Now do positions
18683  for (unsigned idim=0;idim<n_dim;idim++)
18684  {
18685  for (unsigned t=0;t<n_prev;t++)
18686  {
18687  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
18688  }
18689  }
18690 
18691  } // if (!node_on_shared_boundary)
18692 
18693  }
18694 
18695  //==========start of add_haloed_node_helper===============================
18696  /// Helper to add external haloed node that is not a master
18697  //========================================================================
18698  template<class ELEMENT>
18700  add_haloed_node_helper(unsigned& iproc, Node* nod_pt)
18701  {
18702  // Attempt to add this node as a haloed node
18703  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18704  const unsigned haloed_node_index =
18705  this->try_to_add_haloed_node_pt(iproc,nod_pt);
18706 
18707  // If it was added then the new index should match the size of the storage
18708  if (haloed_node_index==n_haloed_nod)
18709  {
18710  Flat_packed_unsigneds.push_back(1);
18711 
18712 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18713  std::stringstream junk;
18714  junk << "Node needs to be constructed [size="
18715  << Flat_packed_unsigneds.size() << "]; last entry: "
18717  Flat_packed_unsigneds_string.push_back(junk.str());
18718 #endif
18719 
18720  // This helper function gets all the required information for the
18721  // specified node and stores it into MPI-sendable information
18722  // so that a halo copy can be made on the receiving process
18724  }
18725  else // It was already added
18726  {
18727  Flat_packed_unsigneds.push_back(0);
18728 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18729  std::stringstream junk;
18730  junk << "Node was already added [size="
18731  << Flat_packed_unsigneds.size() << "]; last entry: "
18733 
18734  Flat_packed_unsigneds_string.push_back(junk.str());
18735 #endif
18736 
18737  // This node is already a haloed node, so tell
18738  // the other process its index in the equivalent halo storage
18739  Flat_packed_unsigneds.push_back(haloed_node_index);
18740 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18741  Flat_packed_unsigneds_string.push_back("haloed node index");
18742 #endif
18743  }
18744 
18745  }
18746 
18747  //================= send_and_receive_haloed_info =======================
18748  /// Send the information of the elements that will be created on the other
18749  /// processor
18750  //======================================================================
18751  template<class ELEMENT>
18753  send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
18754  {
18755  // Get the communicator of the mesh
18756  OomphCommunicator* comm_pt = this->communicator_pt();
18757 
18758  // Set MPI info
18759  MPI_Status status;
18760  MPI_Request request;
18761 
18762  // Prepare vectors to receive information
18763  Vector<double> received_double_values;
18764  Vector<unsigned> received_unsigned_values;
18765 
18766  // Send the double values associated with halo(ed) elements and nodes
18767  //-------------------------------------------------------------------
18768  unsigned send_count_double_values=Flat_packed_doubles.size();
18769  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
18770  send_proc,1,comm_pt->mpi_comm(),&request);
18771 
18772  int receive_count_double_values=0;
18773  MPI_Recv(&receive_count_double_values,1,MPI_INT,
18774  recv_proc,1,comm_pt->mpi_comm(),&status);
18775  MPI_Wait(&request,MPI_STATUS_IGNORE);
18776 
18777  if (send_count_double_values!=0)
18778  {
18779  MPI_Isend(&Flat_packed_doubles[0],send_count_double_values,MPI_DOUBLE,
18780  send_proc,2,comm_pt->mpi_comm(),&request);
18781  }
18782  if (receive_count_double_values!=0)
18783  {
18784  received_double_values.resize(receive_count_double_values);
18785  MPI_Recv(&received_double_values[0],receive_count_double_values,
18786  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
18787  }
18788  if (send_count_double_values!=0)
18789  {
18790  MPI_Wait(&request,MPI_STATUS_IGNORE);
18791  }
18792 
18793  // Now send unsigned values associated with halo(ed) elements and nodes
18794  //---------------------------------------------------------------------
18795  unsigned send_count_unsigned_values=Flat_packed_unsigneds.size();
18796 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18797  unsigned send_count_unsigned_string=Flat_packed_unsigneds_string.size();
18798 #ifdef PARANOID
18799  if (send_count_unsigned_string != send_count_unsigned_values)
18800  {
18801  std::ostringstream error_message;
18802  error_message
18803  << "The number of unsigned values to send to processor ("
18804  << send_proc << ") is different from the\nnumber of annotated strings "
18805  << "for the communication\n\n";
18806  throw OomphLibError(error_message.str(),
18807  OOMPH_CURRENT_FUNCTION,
18808  OOMPH_EXCEPTION_LOCATION);
18809  }
18810 #endif // #ifdef PARANOID
18811 #endif
18812  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
18813  send_proc,14,comm_pt->mpi_comm(),&request);
18814 
18815  int receive_count_unsigned_values=0;
18816  MPI_Recv(&receive_count_unsigned_values,1,MPI_INT,recv_proc,14,
18817  comm_pt->mpi_comm(),&status);
18818 
18819  MPI_Wait(&request,MPI_STATUS_IGNORE);
18820 
18821  if (send_count_unsigned_values!=0)
18822  {
18823  MPI_Isend(&Flat_packed_unsigneds[0],send_count_unsigned_values,
18824  MPI_UNSIGNED,send_proc,15,comm_pt->mpi_comm(),&request);
18825 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18826  for (unsigned i=0;i<send_count_unsigned_values;i++)
18827  {
18828  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc
18829  << " " << Flat_packed_unsigneds_string[i]
18830  << ": " << Flat_packed_unsigneds[i] << std::endl;
18831  }
18832 #endif
18833  }
18834  if (receive_count_unsigned_values!=0)
18835  {
18836  received_unsigned_values.resize(receive_count_unsigned_values);
18837  MPI_Recv(&received_unsigned_values[0],receive_count_unsigned_values,
18838  MPI_UNSIGNED,recv_proc,15,comm_pt->mpi_comm(),&status);
18839  }
18840 
18841  if (send_count_unsigned_values!=0)
18842  {
18843  MPI_Wait(&request,MPI_STATUS_IGNORE);
18844  }
18845 
18846  // Copy across into original containers -- these can now
18847  //------------------------------------------------------
18848  // be processed by create_external_halo_elements() to generate
18849  //------------------------------------------------------------
18850  // external halo elements
18851  //------------------------
18852  Flat_packed_doubles.resize(receive_count_double_values);
18853  for (int ii=0;ii<receive_count_double_values;ii++)
18854  {
18855  Flat_packed_doubles[ii]=received_double_values[ii];
18856  }
18857  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
18858  for (int ii=0;ii<receive_count_unsigned_values;ii++)
18859  {
18860  Flat_packed_unsigneds[ii]=received_unsigned_values[ii];
18861  }
18862 
18863  }
18864 
18865  //=====================================================================
18866  /// Creates (halo) element on the loop process based on the
18867  /// information received from each processor
18868  //=====================================================================
18869  template<class ELEMENT>
18871  create_halo_element(unsigned& iproc,
18872  Vector<Node*> &new_nodes_on_domain,
18873  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
18874  &other_proc_shd_bnd_node_pt,
18876  &global_node_names,
18877  std::map<Vector<unsigned>, unsigned>
18878  &node_name_to_global_index,
18879  Vector<Node*> &global_shared_node_pt)
18880  {
18881 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18883  << " Bool: New element needs to be constructed "
18885  << std::endl;
18886 #endif
18887 
18889  {
18890  // Create a new element from the communicated values
18891  // and coords from the process that located zeta
18892  GeneralisedElement *new_el_pt= new ELEMENT;
18893 
18894  // Add the element, it is a new element in the mesh
18895  this->add_element_pt(new_el_pt);
18896 
18897  // Add halo element to this mesh
18898  this->add_root_halo_element_pt(iproc, new_el_pt);
18899 
18900  // Cast to the FE pointer
18901  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
18902 
18903  // Check if new element is associated to any boundary
18904  this->add_halo_element_helper(iproc,f_el_pt);
18905 
18906  // Now we add nodes to the new element
18907  unsigned n_node=f_el_pt->nnode();
18908 
18909  for (unsigned j=0;j<n_node;j++)
18910  {
18911  Node* new_nod_pt=0;
18912 
18913  // Call the add halo node helper function
18914  add_halo_node_helper(new_nod_pt,
18915  new_nodes_on_domain,
18916  other_proc_shd_bnd_node_pt,
18917  iproc, j, f_el_pt,
18918  global_node_names,
18919  node_name_to_global_index,
18920  global_shared_node_pt);
18921 
18922  } // for (j<n_nod)
18923 
18924  }
18925  else // the element already exists as halo
18926  {
18927 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18928  oomph_info
18929  << "Rec:" << Counter_for_flat_packed_unsigneds
18930  << " Index of existing halo element "
18932  << std::endl;
18933 #endif
18934  // The index itself is in Flat_packed_unsigneds[...]
18935  unsigned halo_ele_index=
18937 
18938  // Use this index to get the element
18939  FiniteElement* f_el_pt=
18940  dynamic_cast<FiniteElement*>(this->root_halo_element_pt(iproc,
18941  halo_ele_index));
18942 
18943  //If it's not a finite element die
18944  if(f_el_pt==0)
18945  {
18946  throw OomphLibError("Halo element is not a FiniteElement\n",
18947  OOMPH_CURRENT_FUNCTION,
18948  OOMPH_EXCEPTION_LOCATION);
18949  }
18950 
18951  } // else the element already exists as halo
18952 
18953  }
18954 
18955  //========start of add_halo_element_helper==============================
18956  /// \short Helper function to create (halo) elements on the loop
18957  /// process based on the info received in send_and_received_located_info
18958  /// This function is in charge of verify if the element is associated to
18959  /// a boundary
18960  //======================================================================
18961  template<class ELEMENT>
18963  add_halo_element_helper(unsigned& iproc, FiniteElement* ele_pt)
18964  {
18965 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18967  << " Bool: Element is associated to an original boundary "
18969  << std::endl;
18970 #endif
18971 
18973  {
18974 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18975  oomph_info
18976  << "Rec:" << Counter_for_flat_packed_unsigneds
18977  << " How many boundaries are associated with the element "
18979  << std::endl;
18980 #endif
18981  const unsigned nassociated_boundaries =
18983 
18984  for (unsigned b = 0; b < nassociated_boundaries; b++)
18985  {
18986 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18987  oomph_info
18988  << "Rec:" << Counter_for_flat_packed_unsigneds
18989  << " Boundary associated to the element "
18991  << std::endl;
18992 #endif
18993  const unsigned bnd =
18995 
18996 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18997  oomph_info
18998  << "Rec:" << Counter_for_flat_packed_unsigneds
18999  << " Face index of the element "
19001  << std::endl;
19002 #endif
19003  const unsigned face_index =
19005 
19006  // Associate the element with the boundary and establish as many
19007  // face indexes it has
19008  this->Boundary_element_pt[bnd].push_back(ele_pt);
19009  this->Face_index_at_boundary[bnd].push_back(face_index);
19010 
19011  } // (b < nassociated_boundaries)
19012 
19013  // Here read the info. regarding the boundary-region of the element
19014 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19016  << " Bool: Element is associated to a boundary-region "
19018  << std::endl;
19019 #endif
19020 
19022  {
19023 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19024  oomph_info
19025  << "Rec:" << Counter_for_flat_packed_unsigneds
19026  << " How many boundaries-regions are associated with the element "
19028  << std::endl;
19029 #endif
19030  const unsigned nassociated_boundaries_and_regions =
19032 
19033  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19034  {
19035 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19036  oomph_info
19037  << "Rec:" << Counter_for_flat_packed_unsigneds
19038  << " Boundary associated to the element "
19040  << std::endl;
19041 #endif
19042  const unsigned bnd =
19044 
19045 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19046  oomph_info
19047  << "Rec:" << Counter_for_flat_packed_unsigneds
19048  << " Region associated to the element "
19050  << std::endl;
19051 #endif
19052  const unsigned region =
19054 
19055 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19056  oomph_info
19057  << "Rec:" << Counter_for_flat_packed_unsigneds
19058  << " Face index of the element in boundary-region "
19060  << std::endl;
19061 #endif
19062  const unsigned face_index =
19064 
19065  // Associate the element with the boundary-regions and establish
19066  // as many face indexes it has
19067  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19068  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
19069 
19070  } // for (br < nassociated_boundaries_and_regions)
19071 
19072  } // Is the element associated with a boundary-region?
19073 
19074  }
19075 
19076  // Now check if the element is associated to a shared boundary
19077 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19079  << " Bool: Element is associated to a shared boundary "
19081  << std::endl;
19082 #endif
19084  {
19085 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19086  oomph_info
19087  << "Rec:" << Counter_for_flat_packed_unsigneds
19088  << " How many shared boundaries are associated with the element "
19090  << std::endl;
19091 #endif
19092  const unsigned nassociated_shared_boundaries =
19094 
19095  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19096  {
19097 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19098  oomph_info
19099  << "Rec:" << Counter_for_flat_packed_unsigneds
19100  << " Shared boundary associated to the element "
19102  << std::endl;
19103 #endif
19104  const unsigned bnd =
19106 
19107 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19108  oomph_info
19109  << "Rec:" << Counter_for_flat_packed_unsigneds
19110  << " Face index of the element associated to the shared boundary "
19112  << std::endl;
19113 #endif
19114 
19115  const unsigned face_index =
19117 
19118  this->add_shared_boundary_element(bnd, ele_pt);
19119  this->add_face_index_at_shared_boundary(bnd, face_index);
19120 
19121  } // (b < nassociated_shared_boundaries)
19122 
19123  } // The element is associted with a shared boundary
19124 
19125  }
19126 
19127  //========start of add_halo_node_helper==========================
19128  /// Helper function to add halo node
19129  //===============================================================
19130  template<class ELEMENT>
19132  (Node* &new_nod_pt,
19133  Vector<Node*> &new_nodes_on_domain,
19134  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19135  &other_proc_shd_bnd_node_pt,
19136  unsigned& iproc,
19137  unsigned& node_index,
19138  FiniteElement* const &new_el_pt,
19139  Vector<Vector<Vector<unsigned> > > &global_node_names,
19140  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19141  Vector<Node*> &global_shared_node_pt)
19142  {
19143  // Given the node, received information about them from process
19144  // iproc, construct them on the current process
19145 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19147  << " Bool: New node needs to be constructed "
19149  << std::endl;
19150 #endif
19152  {
19153  // Construct a new node based upon sent information, or copy a node
19154  // from one of the shared boundaries
19155  construct_new_halo_node_helper(new_nod_pt, new_nodes_on_domain,
19156  other_proc_shd_bnd_node_pt,
19157  iproc, node_index, new_el_pt,
19158  global_node_names,
19159  node_name_to_global_index,
19160  global_shared_node_pt);
19161  }
19162  else
19163  {
19164 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19166  << " Index of existing halo node "
19168  << std::endl;
19169 #endif
19170 
19171  // Copy node from received location
19172  new_nod_pt = new_nodes_on_domain[
19174 
19175  new_el_pt->node_pt(node_index)=new_nod_pt;
19176 
19177  }
19178 
19179  }
19180 
19181  //========start of construct_new_halo_node_helper=================
19182  //Helper function which constructs a new external halo node (on new element)
19183  //with the required information sent from the haloed process
19184  //========================================================================
19185  template<class ELEMENT>
19187  (Node* &new_nod_pt,
19188  Vector<Node*> &new_nodes_on_domain,
19189  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19190  &other_proc_shd_bnd_node_pt,
19191  unsigned& iproc, unsigned& node_index,
19192  FiniteElement* const &new_el_pt,
19193  Vector<Vector<Vector<unsigned> > > &global_node_names,
19194  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19195  Vector<Node*> &global_shared_node_pt)
19196  {
19197  //The first entry indicates the number of values at this new Node
19198  //(which may be different across the same element e.g. Lagrange multipliers)
19199 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19201  << " Number of values of external halo node "
19203  << std::endl;
19204 #endif
19206 
19207  // Null TimeStepper for now
19208  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
19209  // Default number of previous values to 1
19210  unsigned n_prev=time_stepper_pt->ntstorage();
19211 
19212  // ------------------------------------------------------
19213  // Check if the node is on an original boundary
19214 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19216  << " Is the node on an original boundary "
19218  << std::endl;
19219 #endif
19220 
19221  // Flag to indicate if the node is on original boundaries
19222  const unsigned node_on_original_boundaries =
19224 
19225  // Store the original boundaries where the node is on
19226  Vector<unsigned> original_boundaries_node_is_on;
19227  // Store the zeta coordinates of the node on the original boundaries
19228  Vector<double> zeta_coordinates;
19229  // Store the number of original boundaries the node is on
19230  unsigned n_original_boundaries_node_is_on = 0;
19231 
19232  if (node_on_original_boundaries==2)
19233  {
19234  // How many original boundaries does the node live on?
19235 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19237  << " Number of boundaries the node is on: "
19239  << std::endl;
19240 #endif
19241  n_original_boundaries_node_is_on =
19243 
19244  // Resize the containers
19245  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19246  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19247 
19248  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
19249  {
19250  // Boundary number
19251 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19253  << " Node is on boundary "
19255  << std::endl;
19256 #endif
19257  original_boundaries_node_is_on[i] =
19259  zeta_coordinates[i] =
19261  }
19262 
19263  } // if (node_on_original_boundaries==2)
19264 #ifdef PARANOID
19265  else
19266  {
19267  if (node_on_original_boundaries != 0)
19268  {
19269  std::ostringstream error_message;
19270  error_message
19271  <<"The current node is not on an original boundary, this should\n"
19272  <<"be indicated by a zero flag. However, the read value for\n"
19273  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
19274  throw OomphLibError(
19275  error_message.str(),
19276  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19277  OOMPH_EXCEPTION_LOCATION);
19278  } // if (node_on_original_boundaries != 0)
19279  }
19280 #endif
19281 
19282  // --------------------------------------------------------------
19283  // Check if the node was on a shared boundary with the iproc
19284  // processor
19285 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19287  << " Is node on shared boundary? "
19289  << std::endl;
19290 #endif
19291  const unsigned is_node_on_shared_boundary =
19293  if (is_node_on_shared_boundary == 1)
19294  {
19295  // How many shared boundaries does the node live on?
19296 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19298  << " Number of boundaries the node is on: "
19300  << std::endl;
19301 #endif
19302  const unsigned n_shd_bnd_node_is_on =
19304  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19305  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
19306  {
19307  // Shared boundary number
19308 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19310  << " Node is on boundary "
19312  << std::endl;
19313 #endif
19314  shd_bnds_node_is_on[i] =
19316  }
19317 
19318  // Get the index of the node on the shared boundary
19319 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19321  << " Index of node on boundary "
19323  << std::endl;
19324 #endif
19325  // Get the node index of the node on the shared boundary
19326  unsigned node_index_on_shared_boundary =
19328 
19329  // Get the pointer to the node with the received info.
19330  new_nod_pt =
19331  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
19332  node_index_on_shared_boundary);
19333 
19334  } // if (is_node_on_shared_boundary == 1)
19335 #ifdef PARANOID
19336  else
19337  {
19338  if (is_node_on_shared_boundary != 0)
19339  {
19340  std::ostringstream error_message;
19341  error_message
19342  <<"The current node is not on a shared boundary, this should\n"
19343  <<"be indicated by a zero flag. However, the read value for\n"
19344  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
19345  throw OomphLibError(
19346  error_message.str(),
19347  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19348  OOMPH_EXCEPTION_LOCATION);
19349  } // if (node_on_shared_boundary != 0)
19350  }
19351 #endif
19352 
19353  // ------------------------------------------------------------
19354  // Is the node on a shared boundary with other processor?
19355 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19357  << " Is the node on shared boundaries with other processors "
19359  << std::endl;
19360 #endif
19361 
19362  // Is the node in shared boundaries no associated with the
19363  // receiver processor
19364  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19366 
19367  // The containers where to store the info.
19368  Vector<unsigned> other_processor_1;
19369  Vector<unsigned> other_processor_2;
19370  Vector<unsigned> other_shared_boundaries;
19371  Vector<unsigned> other_indexes;
19372 
19373  // How many shared bounaries with other processors the node lives on
19374  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19375 
19376  // Is the node on shared boundaries with other processors
19377  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19378  {
19379 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19381  << " In how many shared boundaries with other "
19382  << "processors is the node "
19384  << std::endl;
19385 #endif
19386 
19387  // How many nodes on other shared boundaries were found
19388  n_shd_bnd_with_other_procs_have_node =
19390 
19391  // Resize the containers
19392  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19393  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19394  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19395  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19396 
19397  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19398  {
19399 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19401  << " Processor where the other shared boundary"
19402  << "has the node"
19404  << std::endl;
19405 #endif
19406  // Read the other processor 1
19407  other_processor_1[i] =
19409 
19410 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19412  << " Processor where the other shared boundary"
19413  << "has the node"
19415  << std::endl;
19416 #endif
19417  // Read the other processor 2
19418  other_processor_2[i] =
19420 
19421 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19423  << " Other shared boundary id where the node is on: "
19425  << std::endl;
19426 #endif
19427 
19428  // Read the other shared boundary id
19429  other_shared_boundaries[i] =
19431 
19432 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19434  << " Node index on the other shared boundary "
19436  << std::endl;
19437 #endif
19438 
19439  // Read the node index on the other shared boundary
19440  other_indexes[i] =
19442 
19443  } // for (i < n_shd_bnd_with_other_procs_have_node)
19444 
19445  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19446 #ifdef PARANOID
19447  else
19448  {
19449  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19450  {
19451  std::ostringstream error_message;
19452  error_message
19453  <<"The current node is not on a shared boundary with\n"
19454  <<"other processors, this should be indicated by a zero flag.\n"
19455  <<"However, the read value for that flag is ("
19456  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
19457  throw OomphLibError(
19458  error_message.str(),
19459  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19460  OOMPH_EXCEPTION_LOCATION);
19461  }
19462  }
19463 #endif
19464 
19465  // Now we have all the info. to decide whether the node should be
19466  // created or not
19467 
19468  // First check if the node is a shared boundary node
19469  if (is_node_on_shared_boundary == 1)
19470  {
19471  // We already have the node, we do not need to create it
19472 
19473  // Only check if we need to add boundary info. to the node
19474  if (node_on_original_boundaries==2)
19475  {
19476  // The node is a boundary node, add the boundary info. before
19477  // adding it to the domain
19478 
19479  // Associate the node to the given boundaries
19480  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19481  {
19482  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19483  // Establish the boundary coordinates for the node
19484  Vector<double> zeta(1);
19485  zeta[0] = zeta_coordinates[i];
19486  new_nod_pt->set_coordinates_on_boundary(
19487  original_boundaries_node_is_on[i],zeta);
19488  }
19489 
19490  } // if (node_on_original_boundaries==2)
19491 
19492  // Add the node to the domain
19493  new_nodes_on_domain.push_back(new_nod_pt);
19494 
19495  // Add the node to the element
19496  new_el_pt->node_pt(node_index) = new_nod_pt;
19497 
19498  } // if (is_node_on_shared_boundary == 1)
19499 
19500  // Now check if the node is on a shared boundary with another
19501  // processor, if that is the case try to find the node that may have
19502  // been already sent by the other processors
19503 
19504  // This flags indicates if the node was found, and then decide if it
19505  // is required to create the node
19506  bool found_node_in_other_shared_boundaries = false;
19507  // Flag to indicate whether the node should be created as a boundary
19508  // node or not. If the node lies on a shared boundary with other
19509  // processor the we create it as a boundary node. The processor from
19510  // which we are receiving info. (iproc) may not know that the node
19511  // lies on an original boundary. If the node lies on an original
19512  // boundary then its info. will be sent by another processor, then
19513  // we can set its boundary info. since the node was constructed as a
19514  // boundary node
19515  bool build_node_as_boundary_node = false;
19516 
19517  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19518  {
19519  // Build the node as a boundary node
19520  build_node_as_boundary_node = true;
19521 
19522  // Try to get the node pointer in case that the node has been
19523  // already sent by the other processors
19524 
19525  // Get the number of initial shared boundaries to correct the
19526  // index of the shared boundary
19527  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19528 
19529  // Add the found nodes in the container
19530  Vector<Node*> found_node_pt;
19531 
19532  // Now try to find the node in any of the other shared boundaries
19533  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19534  {
19535  // We always check with the lower processor number. The
19536  // info. is only stored in one direction. More importantly,
19537  // this is done with the hope that the info. has been already
19538  // received from the other processor given that its info. was
19539  // processed before the current processor (iproc). NOTE that
19540  // it is not always the case that this info. has been received
19541  // from the other processors since it may have not require to
19542  // send the elements (and nodes) on the shared boundary with
19543  // the current processor (iproc).
19544  unsigned oproc1 = other_processor_1[i];
19545  unsigned oproc2 = other_processor_2[i];
19546  if (other_processor_1[i] > other_processor_2[i])
19547  {
19548  oproc1 = other_processor_2[i];
19549  oproc2 = other_processor_1[i];
19550  } // if (other_processor_1[i] > other_processor_2[i])
19551 
19552  // Re-compute the shared boundary id between the other
19553  // processors
19554  const unsigned shd_bnd_id =
19555  other_shared_boundaries[i] - initial_shd_bnd_id;
19556 
19557  // Read the index
19558  const unsigned index = other_indexes[i];
19559 
19560  // Check if there are nodes received from the other processor
19561  // and with the given shared boundary
19562  const unsigned n_nodes_on_other_processor =
19563  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19564 
19565  if (n_nodes_on_other_processor > 0)
19566  {
19567  // Check if we can find the index of the node in that
19568  // other processor and shared boundary id
19569  std::map<unsigned, Node*>::iterator it =
19570  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
19571  find(index);
19572 
19573  // If the index exist then get the node pointer
19574  if (it!=
19575  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19576  {
19577  // Mark the node as found
19578  found_node_in_other_shared_boundaries = true;
19579  // Get the node pointer
19580  Node* tmp_node_pt = (*it).second;
19581 
19582  // Push back the node pointer
19583  found_node_pt.push_back(tmp_node_pt);
19584 
19585  } // if (it!=
19586  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19587 
19588  } // if (n_nodes_on_other_processor > 0)
19589 
19590  } // for (i < n_shd_bnd_with_other_procs_have_node)
19591 
19592  // If the node was found, then all their instances should be the
19593  // same but better check
19594  if (found_node_in_other_shared_boundaries)
19595  {
19596 #ifdef PARANOID
19597  const unsigned n_times_node_found = found_node_pt.size();
19598  for (unsigned j = 1; j < n_times_node_found; j++)
19599  {
19600  if (found_node_pt[j-1] != found_node_pt[j])
19601  {
19602  std::ostringstream error_message;
19603  error_message
19604  <<"The instances of the node that was found on\n"
19605  <<"shared boundaries with other processors (but not\n"
19606  <<"on shared boundaries with this processor) are not\n"
19607  <<"the same.\n"
19608  <<"These are the coordinates of the instances of the\n"
19609  <<"nodes:\n"
19610  <<"(" << found_node_pt[j-1]->x(0) << ", "
19611  << found_node_pt[j-1]->x(1) << ")\n"
19612  <<"(" << found_node_pt[j]->x(0) << ", "
19613  << found_node_pt[j]->x(1) << ")\n"
19614  <<"Dont be surprised if they are the same since the "
19615  << "node is\nrepeated.\n";
19616  throw OomphLibError(error_message.str(),
19617  OOMPH_CURRENT_FUNCTION,
19618  OOMPH_EXCEPTION_LOCATION);
19619 
19620  } // if (found_node_pt[j-1] != found_node_pt[j])
19621 
19622  } // for (j < ntimes_node_found)
19623 #endif // #ifdef PARANOID
19624 
19625  // Check if the node is a shared boundary node from the
19626  // current processor and the iproc processor, if that is the
19627  // case, and the node is also on a shared boundary with other
19628  // processor, then the pointer should be the same!!!
19629  if (is_node_on_shared_boundary == 1)
19630  {
19631  //const unsigned n_times_node_found = found_node_pt.size();
19632  // The pointer to the node is already assigned, it was
19633  // assigned when the node was found to be on a shared
19634  // boundary with the sending processor (iproc). Check that
19635  // any previous instances of the node have been copied
19636  // from the shared boundary, if that is not the case then
19637  // there is a problem
19638  if (found_node_pt[0] != new_nod_pt)
19639  {
19640  std::ostringstream error_message;
19641  error_message
19642  <<"The pointer of the node that was found to be on a\n"
19643  <<"shared boundary with other processor(s) and the pointer\n"
19644  <<"of the node on shared boundary with the receiver\n"
19645  <<"processor (iproc) are not the same. This means we have a\n"
19646  << "repeated node)\n"
19647  <<"The coordinates for the nodes are:\n"
19648  <<"(" << found_node_pt[0]->x(0) << ", "
19649  << found_node_pt[0]->x(1) << ")\n"
19650  <<"(" << new_nod_pt->x(0) << ", "
19651  << new_nod_pt->x(1) << ")\n"
19652  <<"Dont be surprised if they are the same since the "
19653  << "node is\nrepeated.\n";
19654  throw OomphLibError(error_message.str(),
19655  OOMPH_CURRENT_FUNCTION,
19656  OOMPH_EXCEPTION_LOCATION);
19657 
19658  } // if (found_node_pt[i] != new_nod_pt)
19659 
19660  } // if (is_node_on_shared_boundary == 1)
19661  else
19662  {
19663  // Take the first instance of the node in case that it was
19664  // found and is not on a shared boundary with the iproc
19665  // processor (the processor from which we are receiving
19666  // the info.)
19667  new_nod_pt = found_node_pt[0];
19668 
19669  }
19670 
19671  } // if (found_node_in_other_shared_boundaries)
19672 
19673  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19674 
19675  // -----------------------------------------------------------------
19676  // Create the node or read the received info if the node is not on a
19677  // shared boundary with the iproc processor
19678  if (is_node_on_shared_boundary != 1)
19679  {
19680  // If the node is on a shared boundary with other processor we
19681  // need to read all the info. since the processor that sent the
19682  // info. did not know that the node is part of another shared
19683  // boundary
19684 
19685  // If the node is not on a shared boundary (with any processor),
19686  // or if this is the first time that the info. of the node is
19687  // received from any of the processors with which it has a shared
19688  // boundary, then we create the node
19689 
19690  // Is the node a boundary node or should it be build as a boundary
19691  // node because it is on a shared boundary with other processors
19692  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
19693  {
19694  // Check if necessary to create the node, or if it has been
19695  // already found in shared boundaries with other processors
19696  if (!found_node_in_other_shared_boundaries)
19697  {
19698  // Construct a boundary node
19699  if (time_stepper_pt!=0)
19700  {
19701  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
19702  time_stepper_pt);
19703  }
19704  else
19705  {
19706  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
19707  }
19708 
19709  } // if (!found_node_in_other_shared_boundaries)
19710  else
19711  {
19712  // If the node was found then assign the node to the element
19713  new_el_pt->node_pt(node_index) = new_nod_pt;
19714 
19715  } // else if (!found_node_in_other_shared_boundaries)
19716 
19717  // Associate the node to the given boundaries
19718  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19719  {
19720  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19721  // Establish the boundary coordinates for the node
19722  Vector<double> zeta(1);
19723  zeta[0] = zeta_coordinates[i];
19724  new_nod_pt->set_coordinates_on_boundary(
19725  original_boundaries_node_is_on[i],zeta);
19726  }
19727 
19728  } // if (node is on an original boundary)
19729  else
19730  {
19731  // Check if necessary to create the node, or if it has been
19732  // already found in shared boundaries with other processors
19733  if (!found_node_in_other_shared_boundaries)
19734  {
19735  // Construct an ordinary (non-boundary) node
19736  if (time_stepper_pt!=0)
19737  {
19738  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
19739  }
19740  else
19741  {
19742  new_nod_pt=new_el_pt->construct_node(node_index);
19743  }
19744  } // if (!found_node_in_other_shared_boundaries)
19745  else
19746  {
19747  // If the node was found then assign the node to the element
19748  new_el_pt->node_pt(node_index) = new_nod_pt;
19749  } // else if (!found_node_in_other_shared_boundaries)
19750 
19751  } // else (the node is not a boundary node)
19752 
19753  // ... and gather all its information
19754 
19755  // If the node was found or not in other shared boundaries, this
19756  // is the first time the node is received from this processor
19757  // (iproc), therefore it is added to the vector of nodes received
19758  // from this processor (iproc)
19759  new_nodes_on_domain.push_back(new_nod_pt);
19760 
19761  // Check if necessary to state all the info. to the node if it has
19762  // been already found in shared boundaries with other processors
19763  if (!found_node_in_other_shared_boundaries)
19764  {
19765  // Add the node to the general node storage
19766  this->add_node_pt(new_nod_pt);
19767  } // if (!found_node_in_other_shared_boundaries)
19768 
19769  // Is the new constructed node Algebraic?
19770  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
19771  (new_nod_pt);
19772 
19773  // If it is algebraic, its node update functions will
19774  // not yet have been set up properly
19775  if (new_alg_nod_pt!=0)
19776  {
19777  // The AlgebraicMesh is the external mesh
19778  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
19779 
19780  /// The first entry of All_alg_nodal_info contains
19781  /// the default node update id
19782  /// e.g. for the quarter circle there are
19783  /// "Upper_left_box", "Lower right box" etc...
19784 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19786  << " Alg node update id "
19788  << std::endl;
19789 #endif
19790 
19791  unsigned update_id=Flat_packed_unsigneds
19793 
19794  Vector<double> ref_value;
19795 
19796  // The size of this vector is in the next entry
19797  // of All_alg_nodal_info
19798 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19800  << " Alg node # of ref values "
19802  << std::endl;
19803 #endif
19804  unsigned n_ref_val=Flat_packed_unsigneds
19806 
19807  // The reference values themselves are in
19808  // All_alg_ref_value
19809  ref_value.resize(n_ref_val);
19810  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
19811  {
19812  ref_value[i_ref]=Flat_packed_doubles
19814  }
19815 
19816  Vector<GeomObject*> geom_object_pt;
19817  /// again we need the size of this vector as it varies
19818  /// between meshes; we also need some indication
19819  /// as to which geometric object should be used...
19820 
19821  // The size of this vector is in the next entry
19822  // of All_alg_nodal_info
19823 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19825  << " Alg node # of geom objects "
19827  << std::endl;
19828 #endif
19829  unsigned n_geom_obj=Flat_packed_unsigneds
19831 
19832  // The remaining indices are in the rest of
19833  // All_alg_nodal_info
19834  geom_object_pt.resize(n_geom_obj);
19835  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
19836  {
19837 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19839  << " Alg node: geom object index "
19841  << std::endl;
19842 #endif
19843  unsigned geom_index=Flat_packed_unsigneds
19845  // This index indicates which of the AlgebraicMesh's
19846  // stored geometric objects should be used
19847  // (0 is a null pointer; everything else should have
19848  // been filled in by the specific Mesh). If it
19849  // hasn't been filled in then the update_node_update
19850  // call should fix it
19851  geom_object_pt[i_geom]=alg_mesh_pt->
19852  geom_object_list_pt(geom_index);
19853  }
19854 
19855  // Check if necessary to state all the info. to the node if it has
19856  // been already found in shared boundaries with other processors
19857  if (!found_node_in_other_shared_boundaries)
19858  {
19859  /// For the received update_id, ref_value, geom_object
19860  /// call add_node_update_info
19861  new_alg_nod_pt->add_node_update_info
19862  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
19863 
19864  /// Now call update_node_update
19865  alg_mesh_pt->update_node_update(new_alg_nod_pt);
19866 
19867  } // if (!found_node_in_other_shared_boundaries)
19868 
19869  } // if (new_alg_nod_pt!=0)
19870 
19871  // Check if necessary to state all the info. to the node if it has
19872  // been already found in shared boundaries with other processors
19873  if (!found_node_in_other_shared_boundaries)
19874  {
19875  // Is the node a MacroElementNodeUpdateNode?
19876  MacroElementNodeUpdateNode* macro_nod_pt=
19877  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
19878 
19879  if (macro_nod_pt!=0)
19880  {
19881  // Need to call set_node_update_info; this requires
19882  // a Vector<GeomObject*> (taken from the mesh)
19883  Vector<GeomObject*> geom_object_vector_pt;
19884 
19885  // Access the required geom objects from the
19886  // MacroElementNodeUpdateMesh
19887  MacroElementNodeUpdateMesh* macro_mesh_pt=
19888  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
19889  geom_object_vector_pt=
19890  macro_mesh_pt->geom_object_vector_pt();
19891 
19892  // Get local coordinate of node in new element
19893  Vector<double> s_in_macro_node_update_element;
19894  new_el_pt->local_coordinate_of_node
19895  (node_index,s_in_macro_node_update_element);
19896 
19897  // Set node update info for this node
19898  macro_nod_pt->set_node_update_info
19899  (new_el_pt,s_in_macro_node_update_element,
19900  geom_object_vector_pt);
19901  }
19902 
19903  } // if (!found_node_in_other_shared_boundaries)
19904 
19905  // If there are additional values, resize the node
19906  unsigned n_new_val=new_nod_pt->nvalue();
19907 
19908  // Check if necessary to state all the info. to the node if it has
19909  // been already found in shared boundaries with other processors
19910  if (!found_node_in_other_shared_boundaries)
19911  {
19912  if (n_val>n_new_val)
19913  {
19914  // If it has been necessary to resize then it may be becuse
19915  // the node is on a FSI boundary, if that is the case we need
19916  // to set a map for these external values
19917 
19918  // Cast to a boundary node
19919  BoundaryNodeBase *bnod_pt =
19920  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
19921 
19922  // Create storage, if it doesn't already exist, for the map
19923  // that will contain the position of the first entry of
19924  // this face element's additional values,
19926  {
19928  new std::map<unsigned, unsigned>;
19929  }
19930 
19931  // Get pointer to the map
19932  std::map<unsigned, unsigned>* map_pt=
19934 
19935  // The id of the face to which this node belong in the bulk
19936  // element
19937  const unsigned id_face = 0;
19938  // We only resize the node values Vector if we haven't done it yet
19939  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
19940 
19941  // If this node hasn't been resized for current id
19942  if(p==map_pt->end())
19943  {
19944  // assign the face element id and the position of the
19945  //first entry to the boundary node
19946  (*map_pt)[id_face] = n_new_val;
19947 
19948  // resize the node vector of values
19949  new_nod_pt->resize(n_val);
19950  }
19951 
19952  } // if (n_val>n_new_val)
19953 
19954  } // if (!found_node_in_other_shared_boundaries)
19955 
19956  // Is the new node a SolidNode?
19957  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
19958  if (solid_nod_pt!=0)
19959  {
19960  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
19961  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
19962  {
19963  for (unsigned t=0;t<n_prev;t++)
19964  {
19965  double read_data =
19967 
19968  // Check if necessary to state all the info. to the node if it has
19969  // been already found in shared boundaries with other processors
19970  if (!found_node_in_other_shared_boundaries)
19971  {
19972  solid_nod_pt->variable_position_pt()->
19973  set_value(t, i_val, read_data);
19974  } // if (!found_node_in_other_shared_boundaries)
19975 
19976  }
19977 
19978  }
19979 
19980 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19982  << " Number of values solid node: "
19984  << std::endl;
19985 #endif
19986  const unsigned nvalues_solid_node =
19988  Vector<double> values_solid_node(nvalues_solid_node);
19989  for (unsigned i = 0; i < nvalues_solid_node; i++)
19990  {
19991  values_solid_node[i] =
19993  }
19994 
19995  // Check if necessary to state all the info. to the node if it has
19996  // been already found in shared boundaries with other processors
19997  if (!found_node_in_other_shared_boundaries)
19998  {
19999  unsigned index = 0;
20000  solid_nod_pt->read_values_from_vector(values_solid_node, index);
20001  }
20002 
20003  }
20004 
20005  // Get copied history values
20006  // unsigned n_val=new_nod_pt->nvalue();
20007  for (unsigned i_val=0;i_val<n_val;i_val++)
20008  {
20009  for (unsigned t=0;t<n_prev;t++)
20010  {
20011  double read_data =
20013 
20014  // Check if necessary to state all the info. to the node if it
20015  // has been already found in shared boundaries with other
20016  // processors
20017  if (!found_node_in_other_shared_boundaries)
20018  {
20019  new_nod_pt->set_value(t, i_val, read_data);
20020  } // if (!found_node_in_other_shared_boundaries)
20021 
20022  }
20023 
20024  }
20025 
20026  // Get copied history values for positions
20027  unsigned n_dim=new_nod_pt->ndim();
20028  for (unsigned idim=0;idim<n_dim;idim++)
20029  {
20030  for (unsigned t=0;t<n_prev;t++)
20031  {
20032  double read_data =
20034 
20035  // Check if necessary to state all the info. to the node if it
20036  // has been already found in shared boundaries with other
20037  // processors
20038  if (!found_node_in_other_shared_boundaries)
20039  {
20040  // Copy to coordinate
20041  new_nod_pt->x(t,idim) = read_data;
20042 
20043  } // if (!found_node_in_other_shared_boundaries)
20044  }
20045  }
20046 
20047  } // if (is_node_on_shared_boundary != 1)
20048 
20049  // If the node was not found in other shared boundaries (possibly
20050  // because it is the first time the node has been sent) then copy
20051  // the node to the shared boundaries where it should be, use the
20052  // special container for this cases
20053  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20054  // shared
20055  // boundaries with
20056  // other processors
20057  !found_node_in_other_shared_boundaries) // The node has not
20058  // been previously
20059  // set as
20060  // shared with
20061  // other processors
20062  // (first time)
20063  {
20064  // Update the node pointer in all the (references) of the node
20065  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20066  other_proc_shd_bnd_node_pt,
20067  other_processor_1,
20068  other_processor_2,
20069  other_shared_boundaries,
20070  other_indexes,
20071  global_node_names,
20072  node_name_to_global_index,
20073  global_shared_node_pt);
20074 
20075  } // if (!found_node_in_other_shared_boundaries)
20076 
20077  }
20078 
20079 //========start of update_other_proc_shd_bnd_node_helper=================
20080 //Helper function that assigns/updates the references to the node so
20081 //that it can be found with any other reference
20082 //========================================================================
20083 template<class ELEMENT>
20086 (Node* &new_node_pt,
20087  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
20088  &other_proc_shd_bnd_node_pt,
20089  Vector<unsigned> &other_processor_1,
20090  Vector<unsigned> &other_processor_2,
20091  Vector<unsigned> &other_shared_boundaries,
20092  Vector<unsigned> &other_indexes,
20093  Vector<Vector<Vector<unsigned> > > &global_node_names,
20094  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
20095  Vector<Node*> &global_shared_node_pt)
20096 {
20097  // Get the number of initial shared boundaries to correct the index
20098  // of the shared boundary
20099  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20100 
20101 #ifdef PARANOID
20102  // Get the number of instances of the node on other shared
20103  // boundaries with other processors
20104  const unsigned n_data = other_processor_1.size();
20105 #endif // #ifdef PARANOID
20106 
20107  // Create the first node name
20108  Vector<unsigned> node_name(4);
20109  node_name[0] = other_processor_1[0];
20110  node_name[1] = other_processor_2[0];
20111  node_name[2] = other_shared_boundaries[0];
20112  node_name[3] = other_indexes[0];
20113 
20114 #ifdef PARANOID
20115  // Get the global node index, and all the names of the node
20116  std::map<Vector<unsigned>, unsigned>::iterator it =
20117  node_name_to_global_index.find(node_name);
20118  if (it==node_name_to_global_index.end())
20119  {
20120  std::ostringstream error_stream;
20121  error_stream
20122  <<"The node name does not exist in the global node names\n"
20123  <<"This is the name of the node\n"
20124  << "Name: iproc, jproc, ishd_bnd, idx\n"
20125  <<"Name: " << node_name[0] <<", " << node_name[1] <<", "
20126  << node_name[2] <<", " << node_name[3] <<"\n";
20127  throw OomphLibError(error_stream.str(),
20128  OOMPH_CURRENT_FUNCTION,
20129  OOMPH_EXCEPTION_LOCATION);
20130  } // if (it!=node_name_to_global_index.end())
20131 #endif // #ifdef PARANOID
20132 
20133  // Get the global node index
20134  const unsigned iglobal_node = node_name_to_global_index[node_name];
20135  // Add the node to the global shared node container
20136  global_shared_node_pt[iglobal_node] = new_node_pt;
20137  // Get the names
20138  Vector<Vector<unsigned> > inode_names = global_node_names[iglobal_node];
20139  // Get the number of names of the node
20140  const unsigned n_names = inode_names.size();
20141 
20142 #ifdef PARANOID
20143  // Check that the received names of the node are part of the global
20144  // node names
20145  unsigned n_found_node_names_on_global_node_name = 0;
20146  // loop over the input node names
20147  for (unsigned j = 0; j < n_data; j++)
20148  {
20149  // loop over the inode_names
20150  for (unsigned k = 0; k < n_names; k++)
20151  {
20152  // Is this input name part of the global node names?
20153  if (inode_names[k][0] == other_processor_1[j] &&
20154  inode_names[k][1] == other_processor_2[j] &&
20155  inode_names[k][2] == other_shared_boundaries[j] &&
20156  inode_names[k][3] == other_indexes[j])
20157  {
20158  // Increase the number of found input node names in the
20159  // global node names
20160  n_found_node_names_on_global_node_name++;
20161  }
20162 
20163  } // for (k < n_names)
20164 
20165  } // for (j < n_data)
20166 
20167  // Were all the input node names found on the global node names?
20168  if (n_found_node_names_on_global_node_name != n_data)
20169  {
20170  std::ostringstream error_stream;
20171  error_stream
20172  <<"Not all the node names of the current node were found on the\n"
20173  <<"global node names. This happened when adding the node pointer\n"
20174  <<"to the data structure that keeps tracks of nodes on shared\n"
20175  <<"boundaries with other processors\n\n"
20176  << "These are the names of the current node\n"
20177  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20178  for (unsigned j = 0; j < n_data; j++)
20179  {
20180  error_stream<<"Name("<<j<<"): "
20181  <<other_processor_1[j] <<", "
20182  <<other_processor_2[j] <<", "
20183  <<other_shared_boundaries[j] <<", "
20184  <<other_indexes[j] <<"\n";
20185  }
20186 
20187  error_stream
20188  << "\n\nThese are the names of the global node\n"
20189  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20190  for (unsigned k = 0; k < n_names; k++)
20191  {
20192  error_stream<<"Name("<<k<<"): "
20193  <<inode_names[k][0] <<", "
20194  <<inode_names[k][1] <<", "
20195  <<inode_names[k][2] <<", "
20196  <<inode_names[k][3] <<"\n";
20197  }
20198 
20199  throw OomphLibError(error_stream.str(),
20200  OOMPH_CURRENT_FUNCTION,
20201  OOMPH_EXCEPTION_LOCATION);
20202  }
20203 #endif // #ifdef PARANOID
20204 
20205  // Set the node pointer in all of its names
20206  for (unsigned j = 0; j < n_names; j++)
20207  {
20208  // Get the j-th node name
20209  const unsigned iproc = inode_names[j][0];
20210  const unsigned jproc = inode_names[j][1];
20211  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20212  const unsigned index = inode_names[j][3];
20213 
20214  // The info. is stored only in one direction
20215  // Get the smallest processor number
20216  if (iproc < jproc)
20217  {
20218  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]
20219  = new_node_pt;
20220  }
20221  else
20222  {
20223  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]
20224  = new_node_pt;
20225  }
20226 
20227  } // for (j < n_names)
20228 
20229 }
20230 
20231  // *********************************************************************
20232  // End communication functions
20233  // *********************************************************************
20234 
20235  // *********************************************************************
20236  // BEGIN: Methods to perform load balance
20237  // *********************************************************************
20238 
20239  //======================================================================
20240  /// \short Performs the load balancing for unstructured meshes, the
20241  /// load balancing strategy is based on mesh migration
20242  //======================================================================
20243  template <class ELEMENT>
20246  target_domain_for_local_non_halo_element)
20247  {
20248  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20249 
20250  // This method can only be called when the mesh has been already
20251  // distributed
20252  if (!this->is_mesh_distributed())
20253  {
20254  std::ostringstream warning_message;
20255  warning_message
20256  << "\n===============================================================\n"
20257  << "The load balancing can only be performed in distributed meshes,\n"
20258  << "your mesh has not been distributed.\n"
20259  << "===============================================================\n\n";
20260  OomphLibWarning(warning_message.str(),
20261  OOMPH_CURRENT_FUNCTION,
20262  OOMPH_EXCEPTION_LOCATION);
20263  // Return
20264  return;
20265  }
20266 
20267  // Get the number of processors
20268  const unsigned nproc = this->communicator_pt()->nproc();
20269  // Get the rank of the current processors
20270  const unsigned my_rank = this->communicator_pt()->my_rank();
20271 
20272  // Check that there are at least two processors
20273  if (nproc == 1)
20274  {
20275  std::ostringstream warning_message;
20276  warning_message
20277  << "\n===============================================================\n"
20278  << "The load balancing can only be performed when there are at least\n"
20279  << "two procesors, the current number of processors is one.\n"
20280  << "===============================================================\n\n";
20281  OomphLibWarning(warning_message.str(),
20282  OOMPH_CURRENT_FUNCTION,
20283  OOMPH_EXCEPTION_LOCATION);
20284  // Return
20285  return;
20286  }
20287 
20288  // Get the time before load balance
20289  double t_start_overall_load_balance=0.0;
20290  if (Print_timings_level_load_balance>1)
20291  {
20292  t_start_overall_load_balance=TimingHelpers::timer();
20293  }
20294 
20295  // Get the number of elements in the mesh before load balance
20296  const unsigned nelement_before_load_balance = this->nelement();
20297 
20298 #ifdef PARANOID
20299  // The number of elements in the mesh and the number of target
20300  // domains for the local non halo elements in the mesh should match
20301  if (nnon_halo_element() !=
20302  target_domain_for_local_non_halo_element.size())
20303  {
20304  std::ostringstream error_message;
20305  error_message
20306  << "The number of non halo elements in the current mesh ("
20307  << nnon_halo_element() << ") and the number\n"
20308  << "of target areas for the local non halo elements ("
20309  << target_domain_for_local_non_halo_element.size()
20310  << ") is different\n\n";
20311  throw OomphLibError(error_message.str(),
20312  OOMPH_CURRENT_FUNCTION,
20313  OOMPH_EXCEPTION_LOCATION);
20314  }
20315 #endif
20316 
20317  // Backup pointers to elements in this mesh
20318  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20319  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20320  {
20321  backed_up_ele_pt[e] = this->finite_element_pt(e);
20322  }
20323 
20324  // =====================================================================
20325  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20326  // =====================================================================
20327 
20328  // Get the time to get the domains of halo elements
20329  double tt_start_get_domains_halo_elements=0.0;
20330  if (Print_timings_level_load_balance>1)
20331  {
20332  tt_start_get_domains_halo_elements=TimingHelpers::timer();
20333  }
20334 
20335  // Get the new domains for the halo elements
20336 
20337  // Send the new domains for the current haloed elements, and receive
20338  // the new domains for the current halo elements
20339  // -- 1) On the current processor get the new domains for the
20340  // haloed elements
20341  // -- 2) Then send this info. to all the processor that have a
20342  // halo copy of the element
20343 
20344  // The storing for the new domains of the haloed elements (sent to
20345  // other processors)
20346  Vector<Vector<unsigned> > new_domains_haloed_elements(nproc);
20347  // The storing for the new domains of the halo elements (received
20348  // from other processors)
20349  Vector<Vector<unsigned> > new_domains_halo_elements(nproc);
20350 
20351  // First resize the containers by getting the current number of
20352  // halo/haloed elements within each processor
20353  for (unsigned iproc = 0; iproc < nproc; iproc++)
20354  {
20355  // There are no halo/haloed elements with myself (my_rank
20356  // processor)
20357  if (iproc != my_rank)
20358  {
20359  // Get the number of halo elements with iproc processor
20360  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20361  // Resize the container
20362  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20363 
20364  // Get the number of haloed elements with iproc processor
20365  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20366  // Resize the container
20367  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20368  } // if (iproc != my_rank)
20369  } // for (iproc < nproc)
20370 
20371 #ifdef PARANOID
20372  // Count the number of found haloed elements
20373  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20374 #endif
20375 
20376  // Go through all the haloed elements and find their new domain
20377 
20378  // Get the haloed elements with in each processor and check if the
20379  // element is haloed with the processor
20380  for (unsigned iproc = 0; iproc < nproc; iproc++)
20381  {
20382  // There are no halo/haloed elements with myself (my_rank
20383  // processor)
20384  if (iproc != my_rank)
20385  {
20386  // Get the number of haloed elements with iproc processor
20387  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20388 
20389  // Loop over the haloed elements
20390  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20391  {
20392  // Get the ihd-th haloed element with "iproc" processor
20393  GeneralisedElement* haloed_ele_pt =
20394  this->root_haloed_element_pt(iproc, ihd);
20395 
20396  // The counter for the nonhalo elements
20397  unsigned nh_count4 = 0;
20398  // Find the element in the general elements container
20399  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20400  {
20401  // Get the e-th element
20402  GeneralisedElement* ele_pt = this->element_pt(e);
20403  // Check if the element is a nonhalo element
20404  if (!ele_pt->is_halo())
20405  {
20406  // Increase the counter for nonhalo elements, in case the
20407  // haloed element is found get the (nh_count4-1) position
20408  // in the target domains vector
20409  nh_count4++;
20410 
20411  if (ele_pt == haloed_ele_pt)
20412  {
20413  // Get the new domain for this element
20414  const unsigned element_domain =
20415  target_domain_for_local_non_halo_element[nh_count4-1];
20416  // Here decrease the counter ---------------------^
20417 
20418  // Set the new domain for the haloed element in the
20419  // special container
20420  new_domains_haloed_elements[iproc][ihd] = element_domain;
20421 #ifdef PARANOID
20422  // Increase the counter
20423  counter_for_found_haloed_elements[iproc]++;
20424 #endif
20425  // ... and break the "for" with the general
20426  // elements. Continue with the next haloed element
20427  break;
20428 
20429  } // if (ele_pt == haloed_ele_pt))
20430 
20431  } // if (!ele_pt->is_halo())
20432 
20433  } // for (e < nelement_before_load_balance)
20434 
20435  } // for (ihd < n_haloed_iproc)
20436 
20437  } // if (iproc != my_rank)
20438 
20439  } // for (iproc < nproc)
20440 
20441 #ifdef PARANOID
20442  // Check that all the haloed elements with all processors have been
20443  // found
20444  for (unsigned iproc = 0; iproc < nproc; iproc++)
20445  {
20446  // There are no halo/haloed elements with myself (my_rank
20447  // processor)
20448  if (iproc != my_rank)
20449  {
20450  // Get the number of haloed elements with "iproc" processor
20451  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20452 
20453  // Compare the number of found haloed elements with the current
20454  // number of haloed elements
20455  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20456  {
20457  std::ostringstream error_message;
20458  error_message
20459  << "The independent counting of found haloed elements ("
20460  << counter_for_found_haloed_elements[iproc] << ") with processor ("
20461  << iproc << ") is not equal to the number of haloed elements ("
20462  << n_haloed_iproc << ") with processor (" << iproc << ")\n";
20463  throw OomphLibError(error_message.str(),
20464  OOMPH_CURRENT_FUNCTION,
20465  OOMPH_EXCEPTION_LOCATION);
20466  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20467 
20468  } // if (iproc != my_rank)
20469 
20470  } // for (iproc < nproc)
20471 #endif
20472 
20473  // Now we have the new domains for the haloed elements
20474 
20475  // Send this info. to the processor with a halo copy of the haloed
20476  // elements and set the new domains in the halo copies
20477 
20478  // First put all the info. in a flat package array
20479  Vector<unsigned> new_domains_haloed_flat_unsigned;
20480  // Put in a vector the number of haloed elements within each
20481  // processor
20482  Vector<int> nhaloed_elements_with_iproc(nproc);
20483  for (unsigned iproc = 0; iproc < nproc; iproc++)
20484  {
20485  // There are no halo/haloed elements with myself (my_rank
20486  // processor)
20487  if (iproc != my_rank)
20488  {
20489  // Get the number of haloed elements with "iproc" processor
20490  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20491  // Copy the number of haloed elements with "iproc" processor
20492  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20493  // Copy the new domains of the haloed elements in the flat
20494  // package
20495  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20496  {
20497  new_domains_haloed_flat_unsigned.push_back(
20498  new_domains_haloed_elements[iproc][i]);
20499  } // for (i < n_haloed_ele_iproc)
20500 
20501  } // if (iproc != my_rank)
20502 
20503  } // for (iproc < nproc)
20504 
20505  // The offsets of the flat package within each processor
20506  Vector<int> offset_haloed_elements_with_iproc(nproc);
20507  offset_haloed_elements_with_iproc[0] = 0;
20508  for (unsigned ip = 1; ip < nproc; ip++)
20509  {
20510  // Compute the offset to send the values to each processor
20511  offset_haloed_elements_with_iproc[ip] =
20512  offset_haloed_elements_with_iproc[ip-1] +
20513  nhaloed_elements_with_iproc[ip-1];
20514  } // for (ip < nproc)
20515 
20516  // Prepare to receive the data
20517 
20518  // Compute the number of data (halo elements) to receive from each
20519  // processor and the displacements within each processor
20520 
20521  // Counter for the total number of halo elements within all processors
20522  unsigned counter_halo_ele_with_all_procs = 0;
20523 
20524  // Put in a vector the number of halo elements expected to receive
20525  // from each processor
20526  Vector<int> nhalo_elements_with_iproc(nproc);
20527  // Compute the number of total halo elements of (my_rank) this
20528  // processor with all other processors
20529  for (unsigned iproc = 0; iproc < nproc; iproc++)
20530  {
20531  // There are no halo/haloed elements with myself (my_rank
20532  // processor)
20533  if (iproc != my_rank)
20534  {
20535  // Get the number of halo elements with "iproc" processor
20536  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20537  // Copy the number of halo elements with "iproc" processor
20538  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20539  // Add the number of elements with this processor
20540  counter_halo_ele_with_all_procs+= n_halo_ele_iproc;
20541  } // if (iproc != my_rank)
20542 
20543  } // for (iproc < nproc)
20544 
20545  // The offsets of the flat package within each processor
20546  Vector<int> offset_halo_elements_with_iproc(nproc);
20547  offset_halo_elements_with_iproc[0] = 0;
20548  for (unsigned ip = 1; ip < nproc; ip++)
20549  {
20550  // Compute the offset to receive the values from each processor
20551  offset_halo_elements_with_iproc[ip] =
20552  offset_halo_elements_with_iproc[ip-1] +
20553  nhalo_elements_with_iproc[ip-1];
20554  } // for (ip < nproc)
20555 
20556  // The flat container to receive the new domains of the halo
20557  // elements in the current processor
20558 
20559  // The flat package where all the info. will be gather from the
20560  // other processors (the halo flat package)
20562  new_domains_halo_flat_unsigned(counter_halo_ele_with_all_procs);
20563 
20564  // Perform the sending and receiving of information to and from all
20565  // processors
20566  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20567  &nhaloed_elements_with_iproc[0], // int *sendcnts
20568  &offset_haloed_elements_with_iproc[0], // int *sdispls
20569  MPI_UNSIGNED, // MPI_Datatype sendtype
20570  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20571  &nhalo_elements_with_iproc[0], // int *recvcnts
20572  &offset_halo_elements_with_iproc[0], // int *rdispls
20573  MPI_UNSIGNED, // MPI_Datatype recvtype
20574  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20575 
20576  // Once received the new domains for the halo elements, copy the
20577  // domains back to an easier to handle container (from the flat
20578  // package to the one with the different halo elements domains
20579  // within each processor)
20580  unsigned counter_new_domains_halo_ele = 0;
20581  for (unsigned iproc = 0; iproc < nproc; iproc++)
20582  {
20583  // There are no halo/haloed elements with myself (my_rank
20584  // processor)
20585  if (iproc != my_rank)
20586  {
20587  // Get the number of halo elements with "iproc"
20588  const unsigned ntmp_halo_elements_with_iproc =
20589  nhalo_elements_with_iproc[iproc];
20590  // Loop over the number of halo elements within "iproc" and copy
20591  // the elements from the flat package
20592  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20593  {
20594  // Copy the new domain of the halo elements from the flat
20595  // package to an easier to use container
20596  new_domains_halo_elements[iproc][i] =
20597  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20598  }
20599  } // if (iproc != my_rank)
20600  } // for (iproc < nproc)
20601 
20602  // The time to get domains of halo elements
20603  if (Print_timings_level_load_balance>1)
20604  {
20605  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20606  <<TimingHelpers::timer()-tt_start_get_domains_halo_elements
20607  << std::endl;
20608  }
20609 
20610  // =====================================================================
20611  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20612  // =====================================================================
20613 
20614  // =====================================================================
20615  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20616  // ELEMENTS
20617  // =====================================================================
20618 
20619  // Get the time to get FiniteElement versions from Generalised
20620  // halo(ed) elements
20621  double tt_start_get_fe_version_from_ge_halo_ed=0.0;
20622  if (Print_timings_level_load_balance>1)
20623  {
20624  tt_start_get_fe_version_from_ge_halo_ed=TimingHelpers::timer();
20625  }
20626 
20627  // The finite element storage for the halo elements
20628  Vector<Vector<FiniteElement*> > f_halo_element_pt(nproc);
20629  // The finite element storage for the haloed elements
20630  Vector<Vector<FiniteElement*> > f_haloed_element_pt(nproc);
20631  // Loop over the processors
20632  for (unsigned iproc = 0; iproc < nproc; iproc++)
20633  {
20634  // There are no halo(ed) elements with myself
20635  if (iproc != my_rank)
20636  {
20637  // Get the number of halo elements with the "iproc" processor
20638  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20639  // Get the halo elements with the "iproc" processor
20640  Vector<GeneralisedElement*> halo_element_pt_iproc =
20641  this->root_halo_element_pt(iproc);
20642  // Resize the finite element container
20643  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20644  // Loop over the halo elements
20645  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20646  {
20647  // Get the finite element
20648  FiniteElement* ele_pt =
20649  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20650  // Store the finite element version of the element
20651  f_halo_element_pt[iproc][ih] = ele_pt;
20652  } // for (ih < nhalo_ele_iproc)
20653 
20654  // Get the number of haloed elements with the "iproc" processor
20655  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20656  // Get the haloed elements with the "iproc" processor
20657  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20658  this->root_haloed_element_pt(iproc);
20659  // Resize the finite element container
20660  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20661  // Loop over the haloed elements
20662  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20663  {
20664  // Get the finite element
20665  FiniteElement* ele_pt =
20666  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20667  // Store the finite element version of the element
20668  f_haloed_element_pt[iproc][ihd] = ele_pt;
20669  } // for (ih < nhaloed_ele_iproc)
20670 
20671  } // if (iproc != my_rank)
20672 
20673  } // for (iproc < nproc)
20674 
20675  // The time to get FiniteElement versions from Generalised halo(ed)
20676  // elements
20677  if (Print_timings_level_load_balance>1)
20678  {
20679  oomph_info << "CPU for getting finite element versions from generalised halo(ed) elements (load balance) [2]: "
20680  <<TimingHelpers::timer()-tt_start_get_fe_version_from_ge_halo_ed
20681  << std::endl;
20682  }
20683 
20684  // =====================================================================
20685  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20686  // ELEMENTS
20687  // =====================================================================
20688 
20689  // =====================================================================
20690  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20691  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20692  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20693  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20694  // =====================================================================
20695 
20696  // Get the time to prepare elements to send to other processors
20697  double tt_start_prepare_element_to_send=0.0;
20698  if (Print_timings_level_load_balance>1)
20699  {
20700  tt_start_prepare_element_to_send=TimingHelpers::timer();
20701  }
20702 
20703  // Store the elements that will be sent to other processors
20704  Vector<Vector<FiniteElement*> > elements_to_send_pt(nproc);
20705 
20706  // Associate the nodes of each element with the processor the
20707  // element will live on
20708  std::map<Data*,std::set<unsigned> >
20709  processors_associated_with_data_before_load_balance;
20710 
20711  // Compute the elements that will be sent to other processor and
20712  // associate the nodes with the processor the element will live on
20713  unsigned nh_count3 = 0;
20714  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20715  {
20716  // Get the element
20717  FiniteElement *ele_pt = this->finite_element_pt(e);
20718  // Only work with nonhalo elements
20719  if (!(ele_pt->is_halo()))
20720  {
20721  // Get the new domain for the elment
20722  const unsigned element_domain =
20723  target_domain_for_local_non_halo_element[nh_count3++];
20724 
20725  // Include the element in the corresponding vector
20726  elements_to_send_pt[element_domain].push_back(ele_pt);
20727 
20728  // Get the number of nodes on the element
20729  const unsigned n_nodes = ele_pt->nnode();
20730  // Loop over the nodes
20731  for (unsigned j = 0; j < n_nodes; j++)
20732  {
20733  // Get each node of the element
20734  Node* node_pt = ele_pt->node_pt(j);
20735  // ... and associate it with element domains
20736  processors_associated_with_data_before_load_balance[node_pt].
20737  insert(element_domain);
20738 
20739  } // for (j < n_nodes)
20740 
20741  } // if (!(ele_pt->is_halo()))
20742 
20743  } // for (e < nelement_before_load_balance)
20744 
20745  // ... do the same for the halo elements (but do not add them to the
20746  // sending container since only the processor with the haloed
20747  // counterparts is in charge of that). Associate the nodes of the
20748  // halo elements with the processor they will live on
20749  for (unsigned iproc = 0; iproc < nproc; iproc++)
20750  {
20751  // There is no halo elements with myself
20752  if (iproc != my_rank)
20753  {
20754  // Get the number of halo elements with the "iproc" processor
20755  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20756  // Get the halo elements with the "iproc" processor
20757  Vector<GeneralisedElement*> halo_element_pt_iproc =
20758  this->root_halo_element_pt(iproc);
20759  // Loop over the halo elements with iproc
20760  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20761  {
20762  // Get the new domain for the halo element
20763  const unsigned element_domain =
20764  new_domains_halo_elements[iproc][ih];
20765 
20766  // Get the finite element
20767  FiniteElement* ele_pt =
20768  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20769 
20770  // Get the number of nodes on the halo element
20771  const unsigned n_nodes = ele_pt->nnode();
20772  // Loop over the nodes
20773  for (unsigned j = 0; j < n_nodes; j++)
20774  {
20775  // Get each node of the halo element
20776  Node* node_pt = ele_pt->node_pt(j);
20777 
20778  // ... and associate it with element domains
20779  processors_associated_with_data_before_load_balance[node_pt].
20780  insert(element_domain);
20781 
20782  } // for (j < n_nodes)
20783 
20784  } // for (ih < nhalo_ele_iproc)
20785 
20786  } // if (iproc != my_rank)
20787 
20788  } // for (iproc < nproc)
20789 
20790  // The time to prepare elements to send to other processors
20791  if (Print_timings_level_load_balance>1)
20792  {
20793  oomph_info << "CPU for preparing elements to send to other processors (load balance) [3]: "
20794  <<TimingHelpers::timer()-tt_start_prepare_element_to_send
20795  << std::endl;
20796  }
20797 
20798  // Now all the nodes are associated with the processor where the
20799  // element will live on. This is performed for the nonhalo and halo
20800  // elements
20801 
20802  // =====================================================================
20803  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20804  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20805  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20806  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20807  // =====================================================================
20808 
20809  // =====================================================================
20810  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
20811  // CURRENT PROCESSOR
20812  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
20813  // =====================================================================
20814 
20815  // Get the time to compute new local halo elements within all
20816  // processors
20817  double tt_start_compute_new_local_halo_elements=0.0;
20818  if (Print_timings_level_load_balance>1)
20819  {
20820  tt_start_compute_new_local_halo_elements=TimingHelpers::timer();
20821  }
20822 
20823  // Before sending the elements across compute the new local
20824  // halo/haloed elements of each processor. Each processor could have
20825  // elements that will be part of the new halo/haloed elements of
20826  // another processors, then these processors need to compute the
20827  // relations that may happen among these other processors
20828 
20829  // Example:
20830  // Processor 1 may have elements that will be sent to processor 3
20831  // and 4. These processors need to know about the new halo elements
20832  // betweeen them but at this moment only processor 1 can compute that
20833  // info., since it is the only one that currently has that info.
20834 
20835  // Store the new local-halo elements of each processor, the HALOED
20836  // elements are also stored in the container, only needs to INVERT
20837  // the indexes. For example, the HALO elements of processor 2 with
20838  // processor 3 are stored in new_local_halo_element_pt[2][3], and
20839  // the HALOED elements of processor 2 with processor 3 are stored in
20840  // new_local_halo_element_pt[3][2]. Notice that these are also the
20841  // halo elements of processor 3 with 2
20842 
20843  // How to identify the new local halo/haloed element: 1) Loop over
20844  // the element; 2) Only work with nonhalo elements; 3) If the
20845  // element is not assigned to the current processor (iproc) then
20846  // check; 4) Is one of its nodes assiociated to the iproc processor?
20847  // 5) If yes the element is a halo in the iproc processor whose
20848  // nonhalo counter part (haloed) lives in the domain assigned to the
20849  // element
20850  Vector<Vector<Vector<FiniteElement*> > > new_local_halo_element_pt(nproc);
20851 
20852  // Loop over the processors
20853  for (unsigned iproc = 0; iproc < nproc; iproc++)
20854  {
20855  // Resize the container
20856  new_local_halo_element_pt[iproc].resize(nproc);
20857 
20858  // Boolean to know which elements have been already added to the
20859  // new local halo scheme in "iproc"
20860  Vector<std::map<FiniteElement*,bool> > new_local_halo_already_added(nproc);
20861 
20862  // Go through all the elements and identify the new local halo
20863  // elements of "iproc"
20864  unsigned nh_count5 = 0;
20865  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20866  {
20867  // Get the element
20868  FiniteElement *ele_pt = this->finite_element_pt(e);
20869  // Only work with nonhalo elements
20870  if (!(ele_pt->is_halo()))
20871  {
20872  // Get the domain to which the current element is associated
20873  const unsigned ele_domain =
20874  target_domain_for_local_non_halo_element[nh_count5++];
20875  // If the current element is not associated to the "iproc"
20876  // processor then it could be a halo element
20877  if (ele_domain != iproc)
20878  {
20879  // Get the number of nodes
20880  const unsigned nnodes = ele_pt->nnode();
20881  // Loop over the nodes
20882  for (unsigned j = 0; j < nnodes; j++)
20883  {
20884  Node* node_pt = ele_pt->node_pt(j);
20885  // Check if the node is associated with the current
20886  // "iproc" processor
20887  std::set<unsigned>::iterator it =
20888  processors_associated_with_data_before_load_balance[node_pt].
20889  find(iproc);
20890  // If it is found then the element is a halo-element
20891  if (it!=
20892  processors_associated_with_data_before_load_balance[node_pt].
20893  end())
20894  {
20895  // Add the element as new local-halo element with the
20896  // "ele_domain" processor. The non-halo counterpart will
20897  // be located on "ele_domain" processor after sending
20898  // elements across
20899  if (!new_local_halo_already_added[ele_domain][ele_pt])
20900  {
20901  // The element is a halo element on "iproc" with
20902  // "ele_domain"
20903  new_local_halo_element_pt[iproc][ele_domain].
20904  push_back(ele_pt);
20905  // Mark as done
20906  new_local_halo_already_added[ele_domain][ele_pt] = true;
20907  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
20908  } // One of the nodes lies on an element on the current
20909  // "iproc" processor
20910  } // for (j < nnodes)
20911  } // if (ele_domain != iproc)
20912  } // if (!(ele_pt->is_halo()))
20913  } // for (e < nelement_before_load_balance)
20914 
20915  // Now do the same with the halo elements, we need to find those
20916  // halo elements that continue being halo elements but possibly
20917  // with/on another processor. The pair of processors where a
20918  // possible shared boundary is created needs to be notified.
20919 
20920  // Example
20921  //
20922  // ---------------* *---------------
20923  // | |* *| |
20924  // | |* *| |
20925  // | New domain |* *| New domain | * Mark the position
20926  // | proc 1 |* *| proc 3 | of halo elements
20927  // | |* *| |
20928  // | |* *| |
20929  // ---------------* *---------------
20930  // Proc 1 Proc 2
20931 
20932  // Processor 1: The halo elements on processor 1 continue being halo ON
20933  // PROCESSOR 1, but now WITH PROCESSOR 3
20934 
20935  // Processor 2: The halo elements on processor 2 continue being
20936  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
20937 
20938  // The current processor (my_rank) also needs to consider the halo
20939  // elements that will be halo elements of other processor with
20940  // another processor. The case of processor 2
20941 
20942  // Loop over all the halo elements in the current processor and
20943  // check if they will be halo with the "iproc" processor
20944  for (unsigned jproc = 0; jproc < nproc; jproc++)
20945  {
20946  // There are no halo elements with myself (the old halo elements
20947  // were halo in the "my_rank" processor)
20948  if (jproc != my_rank)
20949  {
20950  // Get the number of halo elements with the "jproc" processor
20951  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
20952  // Get the halo elements with the "jproc" processor
20953  Vector<GeneralisedElement*> halo_element_pt_jproc =
20954  this->root_halo_element_pt(jproc);
20955  // ... and check if any of those elements is a new halo
20956  // element with the "iproc" processor
20957  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
20958  {
20959  // Get the new domain for the halo element
20960  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
20961 
20962  // If the current element is not associated to the "iproc"
20963  // processor then it could be a halo element on "iproc" with
20964  // "ele_domain".
20965 
20966  // NOTE OUTDATE: Check if the halo element is going to be
20967  // sent to this processor (my_rank), if that is the case
20968  // then we don't need to add it to the set of new halo
20969  // elements with any other processor since any possible
20970  // shared boundary will be created when checking for the
20971  // intersection of the sent and received elements
20972 
20973  //if (ele_domain != iproc && ele_domain != my_rank)
20974 
20975  // NOTE UPDATE: Only check if the halo element is not going
20976  // to be part of the iproc processor, not required to avoid
20977  // those halo elements whose domain is the current rank
20978  // (my_rank). When the shared boundaries are computed, these
20979  // last elements can not create a shared boundary since no
20980  // haloed elements (that shared an edge) are found for
20981  // them. By considering also those halo elements whose new
20982  // domain is the current one (commenting "ele_domain !=
20983  // my_rank") the current processor can compute shared
20984  // boundaries with the iproc processor with help of its old
20985  // halo elements but that will become nonhalo elements, in
20986  // fact they will become haloed elements The halo element is
20987  // not sent to the "element_domain" processor and is not
20988  // passed to the array used to create the new shared
20989  // boundaries "new_shared_boundary_element_pt" because of
20990  // its halo condition
20991  if (ele_domain != iproc)
20992  {
20993  // Get the finite element
20994  FiniteElement* ele_pt =
20995  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
20996  // Get the number of nodes on the halo element
20997  const unsigned nnodes = ele_pt->nnode();
20998  // Loop over the nodes
20999  for (unsigned j = 0; j < nnodes; j++)
21000  {
21001  // Get each node of the halo element
21002  Node* node_pt = ele_pt->node_pt(j);
21003 
21004  // Check if the node is associated with the "iproc"
21005  // processor
21006  std::set<unsigned>::iterator it =
21007  processors_associated_with_data_before_load_balance[node_pt].
21008  find(iproc);
21009  // If it is found then the element is a halo-element
21010  if (it!=
21011  processors_associated_with_data_before_load_balance[node_pt].end())
21012  {
21013  // Add the element as new local-halo element with
21014  // the "ele_domain" processor. The non-halo
21015  // counterpart will be located on "ele_domain"
21016  // processor. Because this is a old-halo element it
21017  // will not be sent to the "element_domain" processor
21018  if (!new_local_halo_already_added[ele_domain][ele_pt])
21019  {
21020  // The element is a halo element on "iproc" with
21021  // "ele_domain"
21022  new_local_halo_element_pt[iproc][ele_domain].
21023  push_back(ele_pt);
21024  new_local_halo_already_added[ele_domain][ele_pt] = true;
21025 
21026  // Break the for of the nodes, the element has been
21027  // already added to the new_local_halo_element_pt
21028  // structure
21029  break;
21030 
21031  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21032 
21033  } // One of the nodes lies on an element belonging to
21034  // "iproc" processor
21035 
21036  } // for (j < nnodes)
21037 
21038  } // if (ele_domain != iproc)
21039 
21040  } // for (jh < n_halo_ele_jproc)
21041 
21042  } // if (jproc != my_rank) // The old halo elements are halo
21043  // with other processors except with "my_rank"
21044 
21045  } // for (jproc < nproc): This is the one that goes for the halo
21046  // elements in the current processor to find the new halo
21047  // elements
21048 
21049  } // for (iproc < nproc)
21050 
21051  // Get the time to compute new local halo elements within all
21052  // processors
21053  if (Print_timings_level_load_balance>1)
21054  {
21055  oomph_info << "CPU for computing new local halo elements (load balance) [4]: "
21056  <<TimingHelpers::timer()-tt_start_compute_new_local_halo_elements
21057  << std::endl;
21058  }
21059 
21060  // =====================================================================
21061  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21062  // CURRENT PROCESSOR
21063  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21064  // =====================================================================
21065 
21066  // =====================================================================
21067  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21068  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21069  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21070  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21071  // ELEMENTS IN THE RECEIVED PROCESSOR
21072  // =====================================================================
21073 
21074  // Get the time to compute new local shared boundary elements
21075  double tt_start_compute_new_local_shd_bnd_ele=0.0;
21076  if (Print_timings_level_load_balance>1)
21077  {
21078  tt_start_compute_new_local_shd_bnd_ele=TimingHelpers::timer();
21079  }
21080 
21081  // Store the new local-shared boundary elements and the face indexes
21082  // The halo elements and halo face indexes
21084  new_local_halo_shared_boundary_element_pt(nproc);
21086  new_local_halo_shared_boundary_element_face_index(nproc);
21087 
21088  // Allocate enough memory for the containers
21089  for (unsigned iproc = 0; iproc < nproc; iproc++)
21090  {
21091  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21092  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21093  } // for (iproc < nproc)
21094 
21095  // Get the elements that create the new local-halo-shared
21096  // boundaries, mark them and identify the face that lies on the
21097  // shared boundary. The new local-halo-shared boundary elements are
21098  // actually a sub-set of the halo elements of each processor with in
21099  // each processor
21100  for (unsigned iproc = 0; iproc < nproc; iproc++)
21101  {
21102  // Star from jproc = iproc + 1 to avoid double creation of shared
21103  // boundary elements, any shared boundary element identified
21104  // between processor "iproc" and "jproc" is also established as
21105  // shared boundary element between processor "jproc" and "iproc"
21106  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21107  {
21108  this->get_shared_boundary_elements_and_face_indexes(
21109  new_local_halo_element_pt[iproc][jproc],
21110  new_local_halo_element_pt[jproc][iproc],
21111  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21112  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21113  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21114  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21115  } // for (jproc < nproc)
21116  } // for (iproc < nproc)
21117 
21118  // The time to compute new local shared boundary elements
21119  if (Print_timings_level_load_balance>1)
21120  {
21121  oomph_info << "CPU for computing new local shared boundary elements (load balance) [5]: "
21122  <<TimingHelpers::timer()-tt_start_compute_new_local_shd_bnd_ele
21123  << std::endl;
21124  }
21125 
21126  // =====================================================================
21127  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21128  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21129  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21130  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21131  // THE RECEIVED PROCESSOR
21132  // =====================================================================
21133 
21134  // =====================================================================
21135  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21136  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21137  // =====================================================================
21138 
21139  // Get the time to send the elements to their new processor in
21140  // charge
21141  double tt_start_send_elements_to_other_processors=0.0;
21142  if (Print_timings_level_load_balance>1)
21143  {
21144  tt_start_send_elements_to_other_processors=TimingHelpers::timer();
21145  }
21146 
21147  // Sort the nodes on shared boundaries so that they have the same
21148  // order on all the shared boundaries, this is required to know the
21149  // possible shared nodes among processors
21150  this->sort_nodes_on_shared_boundaries();
21151 
21152  // Store the received elements from each processor
21153  Vector<Vector<FiniteElement*> > received_elements_pt(nproc);
21154 
21155  // The haloed elements and haloed face indexes, these store the
21156  // haloed elements received from "iproc" but that are haloed with
21157  // "jproc". The elements are received from "iproc" which was the
21158  // processor that computed the haloed relation of the "my_rank"
21159  // processor with "jproc"
21161  new_received_haloed_shared_boundary_element_pt(nproc);
21163  new_received_haloed_shared_boundary_element_face_index(nproc);
21164 
21165  // Container where to store the nodes on shared boundaries not
21166  // associated with the processor that receives the elements/nodes
21167  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21169  other_proc_shd_bnd_node_pt(nproc);
21170  // Resize the container
21171  for (unsigned iproc = 0; iproc < nproc; iproc++)
21172  {
21173  // Resize the container
21174  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21175  for (unsigned jproc = 0; jproc < nproc; jproc++)
21176  {
21177  // Get the number of shared boundaries (OLD shared boundaries)
21178  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21179  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21180  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21181  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21182  } // for (jproc < nproc)
21183 
21184  } // for (iproc < nproc)
21185 
21186  // Store the global node names
21187  // global_node_name[x][ ][ ] Global node number
21188  // global_node_name[ ][x][ ] Global node names
21189  // global_node_name[ ][ ][x] Global node info.
21190  Vector<Vector<Vector<unsigned> > > global_node_names;
21191 
21192  // Creates a map between the node name and the index of the global
21193  // node so we can access all its node names
21194  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21195 
21196  // Store the global shared nodes pointers
21197  Vector<Node*> global_shared_node_pt;
21198 
21199  // Compute all the names of the nodes and fill in the
21200  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21201  // on this processor (my_rank) by looking over all their names
21202  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21203  global_node_names,
21204  node_name_to_global_index,
21205  global_shared_node_pt);
21206 
21207  // From the elements received from each processor, store the haloed
21208  // information of the element, it means, the processor with which it
21209  // is haloed and the haloed index with that processor
21211  received_old_haloed_element_pt(nproc);
21212  // [x][][] : The receiver processor (the original processor)
21213  // [][x][] : The processor with which the receiver processor has
21214  // haloed elements
21215  // [][][x]: The haloed element number
21216 
21217  // Resize the container
21218  for (unsigned iproc = 0; iproc < nproc; iproc++)
21219  {
21220  received_old_haloed_element_pt[iproc].resize(nproc);
21221  } // for (iproc < nproc)
21222 
21223  // Go through all processors and send the corresponding elements to
21224  // each one
21225  for (unsigned iproc = 0; iproc < nproc; iproc++)
21226  {
21227  if (iproc != my_rank)
21228  {
21229  // -----------------------------------------------------------
21230  // Send (package) information of the elements
21231  // -----------------------------------------------------------
21232 
21233  // Keep track of the currently sent elements
21234  Vector<FiniteElement*> currently_sent_elements;
21235  // Keep track of the currently sent nodes to the iproc processor
21236  Vector<Node*> currently_sent_nodes;
21237 
21238  // Clear send and receive buffers
21239  Flat_packed_unsigneds.clear();
21240  Flat_packed_doubles.clear();
21241 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21243 #endif
21244 
21245  // Get the number of elements to send to iproc processor
21246  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21247 
21248  // The very first data of the flat package sent to processor
21249  // iproc is the number of elements that will be sent, this data
21250  // is used by the receiver processor to loop over the number of
21251  // expected elements to receive
21252  Flat_packed_unsigneds.push_back(nelements_to_send);
21253 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21254  std::stringstream junk;
21255  junk << "Number of elements to send from processor " << my_rank
21256  << " to processor " << iproc << ": ("
21257  << nelements_to_send << ")";
21258  Flat_packed_unsigneds_string.push_back(junk.str());
21259 #endif
21260 
21261  // Loop over the elements to sent
21262  for (unsigned e = 0; e < nelements_to_send; e++)
21263  {
21264  // Get the element to send
21265  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21266 
21267  // Get the current number of sent elements
21268  const unsigned ncurrently_sent_elements =
21269  currently_sent_elements.size();
21270 
21271  // Try to add the element
21272  const unsigned index_ele = try_to_add_element_pt_load_balance(
21273  currently_sent_elements, send_ele_pt);
21274 
21275  // Element needs to be added
21276  if (index_ele == ncurrently_sent_elements)
21277  {
21278  Flat_packed_unsigneds.push_back(1);
21279 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21280  Flat_packed_unsigneds_string.push_back("Element needs to be constructed");
21281 #endif
21282 
21283  // Get required info. related with the element
21284  get_required_elemental_information_load_balance_helper(
21285  iproc,
21286  f_haloed_element_pt,
21287  send_ele_pt);
21288 
21289  // Get the number of nodes in the element
21290  const unsigned nnodes = send_ele_pt->nnode();
21291 
21292  // Loop over the nodes in the element
21293  for (unsigned j = 0; j < nnodes; j++)
21294  {
21295  Node* node_pt = send_ele_pt->node_pt(j);
21296 
21297  // Package the info. of the nodes
21298  add_node_load_balance_helper(iproc, // The destination process
21299  f_halo_element_pt,
21300  currently_sent_nodes,
21301  node_pt);
21302 
21303  } // for (j < nnodes)
21304 
21305  } // if (index_ele == ncurrently_sent_elements)
21306  else
21307  {
21308  Flat_packed_unsigneds.push_back(0);
21309 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21310  Flat_packed_unsigneds_string.push_back("Element already exists");
21311 #endif
21312  Flat_packed_unsigneds.push_back(index_ele);
21313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21314  Flat_packed_unsigneds_string.push_back("Index of existing element");
21315 #endif
21316  } // else if (index_ele == ncurrently_sent_elements)
21317 
21318  } // for (e < nelements_to_send)
21319 
21320  // After storing the info. of the elements identify the indexes
21321  // of the "new_local_halo_shared_boundary_elements" in the
21322  // "currently_send_elements" vector, these elements will be
21323  // identified as "new_received_haloed_shared_boundary_elements"
21324  // on the "receiver" processor
21325 
21326  // Each processor has information of every other processor so we
21327  // need to send all the corresponding info. to the other
21328  // processors. Processor 1 may have information of the relation
21329  // (halo elements) between processor 3 and 4 say, so processor 1
21330  // needs to let know processor 3 and 4 what this relation is
21331  // (which are the shared-elements among these processors)
21332 
21333  for (unsigned jproc = 0; jproc < nproc; jproc++)
21334  {
21335  // Get the number of new local-halo shared boundary elements
21336  // between processor "jproc" and "iproc" (we invert the index
21337  // since we really want the haloed elements, those elements
21338  // that we have just sent)
21339  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21340  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21341 
21342  // The vector with the info. of the indexes
21343  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21344 
21345  // The number of found shared boundary elements in the sent
21346  // container (only consider the nonhalo elements)
21347  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21348  // The number of nonhalo elements in the new local halo shared
21349  // boundary elements
21350  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21351 
21352  // Loop over the local halo shared boundary elements between
21353  // processor jproc and iproc
21354  for (unsigned e = 0;
21355  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21356  {
21357  // Get the shared boundary element
21358  FiniteElement* shared_ele_pt =
21359  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21360 
21361  // Only consider the nonhalo elements since the halo
21362  // elements were no considered for sending
21363  if (!shared_ele_pt->is_halo())
21364  {
21365  nnon_halo_new_local_halo_shared_bound_ele++;
21366 
21367  // Now find the index on the currently sent elements
21368 
21369  // Get the current number of sent elements
21370  const unsigned ncurrently_sent_elements =
21371  currently_sent_elements.size();
21372  // Loop over the sent elements
21373  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21374  {
21375  FiniteElement* currently_sent_ele_pt =
21376  currently_sent_elements[ics];
21377 
21378  // Is this the element?
21379  if (currently_sent_ele_pt == shared_ele_pt)
21380  {
21381  // Store the index on the sent elements of the local
21382  // halo shared boundary element
21383  new_local_halo_shared_boundary_ele_index.push_back(ics);
21384  // Increase the number of found new local halo shared
21385  // bound element index
21386  nfound_new_local_halo_shared_bound_ele_index++;
21387  // We have found it, no need to further search
21388  break;
21389  } // if (currently_sent_ele_pt == shared_ele_pt)
21390 
21391  } // for (ics < ncurrently_sent_elements)
21392 
21393  } // if (!shared_ele_pt->is_halo())
21394 
21395  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21396 
21397 #ifdef PARANOID
21398  if (nfound_new_local_halo_shared_bound_ele_index !=
21399  nnon_halo_new_local_halo_shared_bound_ele)
21400  {
21401  std::ostringstream error_message;
21402  error_message
21403  << "Was only possible to identify ("
21404  << nfound_new_local_halo_shared_bound_ele_index << ") of ("
21405  << nnon_halo_new_local_halo_shared_bound_ele << ") shared "
21406  << "elements between\nprocessor ("<<iproc<<") and ("<<jproc<<") "
21407  << "when sending elements to processor ("<<iproc<<")\n\n";
21408  throw OomphLibError(error_message.str(),
21409  OOMPH_CURRENT_FUNCTION,
21410  OOMPH_EXCEPTION_LOCATION);
21411  }
21412 #endif
21413 
21414  // Send a flag for synchronisation issues
21415  Flat_packed_unsigneds.push_back(9999);
21416 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21417  std::stringstream junk;
21418  junk << "Flag for synchronisation 9999";
21419  Flat_packed_unsigneds_string.push_back(junk.str());
21420 #endif
21421 
21422  // Send the number of nonhalo new local-shared boundary
21423  // elements of processor "iproc" with processor "jproc"
21424  Flat_packed_unsigneds.push_back(nnon_halo_new_local_halo_shared_bound_ele);
21425 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21426  std::stringstream junk2;
21427  junk2 << "Number of new local halo shared boundary elements "
21428  << nnon_halo_new_local_halo_shared_bound_ele;
21429  Flat_packed_unsigneds_string.push_back(junk2.str());
21430 #endif
21431 
21432  // Send the indexes and the face indexes of the shared
21433  // boundary elements
21434  unsigned counter_nonhalo_sent = 0;
21435  // Loop over the local halo shared boundary elements between
21436  // processor jproc and iproc
21437  for (unsigned e = 0;
21438  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21439  {
21440  // Get the shared boundary element
21441  FiniteElement* shared_ele_pt =
21442  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21443 
21444  // Only consider the nonhalo elements since the halo
21445  // elements were no considered for sending
21446  if (!shared_ele_pt->is_halo())
21447  {
21448  // Get the index on the sent elements of the current
21449  // nonhalo shared boundary element
21450  const unsigned ele_index =
21451  new_local_halo_shared_boundary_ele_index[counter_nonhalo_sent++];
21452  // ... and get the face index
21453  const unsigned face_index =
21454  new_local_halo_shared_boundary_element_face_index[jproc][iproc][e];
21455 
21456  // Send the index on the sent elements of the new local
21457  // halo shared boundary element
21458  Flat_packed_unsigneds.push_back(ele_index);
21459 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21460  std::stringstream junk;
21461  junk << "The index of the halo shared boundary element "
21462  << ele_index;
21463  Flat_packed_unsigneds_string.push_back(junk.str());
21464 #endif
21465 
21466  // Send the face index of the new local halo shared boundary
21467  // element
21468  Flat_packed_unsigneds.push_back(face_index);
21469 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21470  std::stringstream junk2;
21471  junk2 << "The face index of the halo shared boundary element "
21472  << face_index;
21473  Flat_packed_unsigneds_string.push_back(junk2.str());
21474 #endif
21475 
21476  } // if (!shared_ele_pt->is_halo())
21477 
21478  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21479 
21480  } // for (jproc < nproc)
21481 
21482  // ----------------------------------------------------------
21483  // Send the info. perform the communications
21484  // ----------------------------------------------------------
21485  // Processor to which send the info.
21486  int send_proc = static_cast<int>(iproc);
21487  // Processor from which receive the info.
21488  int recv_proc = static_cast<int>(iproc);
21489  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21490 
21491  // ----------------------------------------------------------
21492  // Receive (unpackage) the info of the elements
21493  // ----------------------------------------------------------
21494 
21495  // Keep track of the currently created elements
21496  Vector<FiniteElement*> currently_created_elements;
21497  // Keep track of the currently created nodes
21498  Vector<Node*> currently_created_nodes;
21499 
21500  // Reset the counters
21503 
21504 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21506  << " Number of elements need to be constructed "
21508  << std::endl;
21509 #endif
21510 
21511  // Read the number of elements that need to be created
21512  const unsigned nelements_to_create =
21514 
21515  for (unsigned e = 0; e < nelements_to_create; e++)
21516  {
21517  // Create the element from received info. of "iproc"
21518  // processor on the current processor
21519  create_element_load_balance_helper(iproc,
21520  f_haloed_element_pt,
21521  received_old_haloed_element_pt,
21522  currently_created_elements,
21523  currently_created_nodes,
21524  other_proc_shd_bnd_node_pt,
21525  global_node_names,
21526  node_name_to_global_index,
21527  global_shared_node_pt);
21528  }
21529 
21530  // Copy the received elements from "iproc" processor
21531 
21532  // Number of received elements
21533  const unsigned nreceived_elements = currently_created_elements.size();
21534  received_elements_pt[iproc].resize(nreceived_elements);
21535  for (unsigned e = 0; e < nreceived_elements; e++)
21536  {received_elements_pt[iproc][e] = currently_created_elements[e];}
21537 
21538  // Go for the haloed elements received from processor "iproc"
21539  // but haloed with "jproc"
21540 
21541  // Allocate memory for the containers
21542  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21543  new_received_haloed_shared_boundary_element_face_index[iproc].resize(nproc);
21544 
21545  // Loop over the processors
21546  for (unsigned jproc = 0; jproc < nproc; jproc++)
21547  {
21548  // Read the synchronisation flag
21549  const unsigned synchronisation_flag =
21551 
21552  if (synchronisation_flag != 9999)
21553  {
21554  std::ostringstream error_message;
21555  error_message
21556  << "The synchronisation flag was not read, the\n"
21557  << "information sent between processor (" << my_rank << ") "
21558  << "and ("<< iproc << ")\nis no longer synchronised\n\n";
21559  throw OomphLibError(error_message.str(),
21560  OOMPH_CURRENT_FUNCTION,
21561  OOMPH_EXCEPTION_LOCATION);
21562  }
21563 
21564  // Read the number of elements that will be part of the new
21565  // received haloed shared boundary elements received from "iproc"
21566  // and haloed with "jproc"
21567  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21569 
21570  // Loop over the new received haloed shared boundary elements
21571  for (unsigned e = 0;
21572  e < niproc_jproc_new_received_haloed_shared_boundary_ele; e++)
21573  {
21574  // Read the index of the new received haloed shared boundary
21575  // ele with "jproc"
21576  const unsigned ele_index =
21578  // Read the face index for the new received haloed shared
21579  // boundary element
21580  const unsigned face_index =
21582 
21583  // Get the element
21584  FiniteElement* shared_ele_pt =
21585  currently_created_elements[ele_index];
21586 
21587  // Add the element to the new received-haloed shared
21588  // boundary elements. Received from "iproc" but haloed with
21589  // "jproc" processor
21590  new_received_haloed_shared_boundary_element_pt[iproc][jproc].
21591  push_back(shared_ele_pt);
21592  // Store the face index
21593  new_received_haloed_shared_boundary_element_face_index[iproc][jproc].
21594  push_back(face_index);
21595 
21596  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21597 
21598  } // for (jproc < nproc)
21599 
21600  } // if (iproc != my_rank)
21601 
21602  } // for (iproc < nproc)
21603 
21604  // The time to send the elements to their new processor in charge
21605  if (Print_timings_level_load_balance>1)
21606  {
21607  oomph_info << "CPU for sending elements to their new processors (load balance) [6]: "
21608  <<TimingHelpers::timer()-tt_start_send_elements_to_other_processors
21609  << std::endl;
21610  }
21611 
21612  // =====================================================================
21613  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21614  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21615  // =====================================================================
21616 
21617  // =====================================================================
21618  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21619  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21620  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21621  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21622  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21623  // ELEMENTS)
21624  // =====================================================================
21625 
21626  // Get the time to compute any additional shared boundary
21627  double tt_start_compute_additional_shared_boundaries=0.0;
21628  if (Print_timings_level_load_balance>1)
21629  {
21630  tt_start_compute_additional_shared_boundaries=TimingHelpers::timer();
21631  }
21632 
21633  // Store any additional elements that may create a shared boundary,
21634  // after sending elements from one to other processor check for any
21635  // new possible shared boundaries
21637  tmp_group1_shared_boundary_element_pt(nproc);
21639  tmp_group1_shared_boundary_element_face_index(nproc);
21641  tmp_group2_shared_boundary_element_pt(nproc);
21643  tmp_group2_shared_boundary_element_face_index(nproc);
21644 
21645  // Compute any additional shared boundaries by checking the
21646  // intersection between the received elements from each processor
21647  // and the elements just sent to that processor, the lowest
21648  // processors number loops over its received elements and the
21649  // highest loops over its sent elements (halo elements that have
21650  // become part of the domain now can create shared boundaries with
21651  // other processor)
21652 
21653  // Note: These additional shared boundaries may be created by the
21654  // elements that previously were halo but now have become part of
21655  // the processor (the received elements), and the elements that were
21656  // previously part of the processor but now have become halo (a
21657  // subset of the sent-elements)
21658 
21659  // Then these new shared boundaries come from the intersection of
21660  // the new-haloed elements (received elements) and the new-halo
21661  // elements (sent elements). These could be computed previously (in
21662  // the computing of the local new-halo and local new-haloed elements
21663  // usign the info. of the new domains for the old halo elements),
21664  // however, it was decided to perform the computation here in order to
21665  // avoid the identification of the old halo element that was part of a
21666  // shared boundary in the set of just received elements
21667  for (unsigned iproc = 0; iproc < nproc; iproc++)
21668  {
21669  if (my_rank < iproc)
21670  {
21671  // Lowest processor loops over the received elements
21672  this->get_shared_boundary_elements_and_face_indexes(
21673  received_elements_pt[iproc], elements_to_send_pt[iproc],
21674  tmp_group1_shared_boundary_element_pt[iproc],
21675  tmp_group1_shared_boundary_element_face_index[iproc],
21676  tmp_group2_shared_boundary_element_pt[iproc],
21677  tmp_group2_shared_boundary_element_face_index[iproc]);
21678 
21679  } // if (my_rank < iproc)
21680  else if (my_rank > iproc)
21681  {
21682  // Highest processor loops over the sent elements
21683  this->get_shared_boundary_elements_and_face_indexes(
21684  elements_to_send_pt[iproc], received_elements_pt[iproc],
21685  tmp_group1_shared_boundary_element_pt[iproc],
21686  tmp_group1_shared_boundary_element_face_index[iproc],
21687  tmp_group2_shared_boundary_element_pt[iproc],
21688  tmp_group2_shared_boundary_element_face_index[iproc]);
21689 
21690  } // else if (my_rank > iproc)
21691 
21692  } // for (iproc < nproc)
21693 
21694  // The time to compute any additional shared boundary
21695  if (Print_timings_level_load_balance>1)
21696  {
21697  oomph_info << "CPU for computing additional shared boundaries (load balance) [7]: "
21698  <<TimingHelpers::timer()-tt_start_compute_additional_shared_boundaries
21699  << std::endl;
21700  }
21701 
21702  // =====================================================================
21703  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21704  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21705  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21706  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21707  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21708  // ELEMENTS)
21709  // =====================================================================
21710 
21711  // =====================================================================
21712  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21713  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21714  // =====================================================================
21715 
21716  // Get the time to sort shared boundaries
21717  double tt_start_sort_shared_boundaries=0.0;
21718  if (Print_timings_level_load_balance>1)
21719  {
21720  tt_start_sort_shared_boundaries=TimingHelpers::timer();
21721  }
21722 
21723  // Once computed the elements that create the shared boundaries,
21724  // sort them so that the shared boundaries are created at the same
21725  // order in both processors that define the shared boundary
21726 
21727  // The order is like this
21728 
21729  // Lowest processors
21730  // 1) Shared boundary elements received from processors (local in
21731  // other processors)
21732  // 2) Local shared boundary elements (do not include halo elements)
21733  // 3) Shared boundary elements by intersection (already sorted)
21734 
21735  // Highest processors
21736  // 1) Local shared boundary elements (do not include halo elements)
21737  // 2) Shared boundary elements received from processors (local in
21738  // other processors)
21739  // 3) Shared boundary elements by intersection (already sorted)
21740 
21741  Vector<Vector<FiniteElement*> > new_shared_boundary_element_pt(nproc);
21742  Vector<Vector<unsigned> > new_shared_boundary_element_face_index(nproc);
21743  for (unsigned iproc = 0; iproc < nproc; iproc++)
21744  {
21745  // Lower processor
21746  if (my_rank < iproc)
21747  {
21748  // Copy the elements received from processor "jproc" but that
21749  // are haloed with "iproc" processor
21750  for (unsigned jproc = 0; jproc < nproc; jproc++)
21751  {
21752  // Can not receive elements from itself
21753  if (jproc != my_rank)
21754  {
21755  // Get the number of elements to copy from received processors
21756  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21757  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21758  for (unsigned e = 0;
21759  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21760  {
21761  // Get the element
21762  FiniteElement* ele_pt =
21763  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21764  // Get the face index
21765  const unsigned face_index =
21766  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21767 
21768  // Add the elements to the containers
21769  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21770  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21771 
21772  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
21773 
21774  } // if (jproc != my_rank)
21775 
21776  } // for (jproc < nproc)
21777 
21778  // Then the local shared haloed (invert the indexes to get the
21779  // haloed elements)
21780  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21781  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21782  for (unsigned e = 0;
21783  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21784  {
21785  // Get the element
21786  FiniteElement* ele_pt =
21787  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21788  // Get the face index
21789  const unsigned face_index =
21790  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21791 
21792  // Only include the element if it is nonhalo (this may be an
21793  // old halo element that helped to indentify a shared boundary
21794  // with iproc)
21795  if (!ele_pt->is_halo())
21796  {
21797  // Add the elements to the containers
21798  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21799  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21800  } // if (!ele_pt->is_halo())
21801 
21802  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21803 
21804  // ... and finally any additional shared boundary elements from
21805  // tmp_group1
21806  const unsigned ntmp_group1_shared_bound_ele_iproc =
21807  tmp_group1_shared_boundary_element_pt[iproc].size();
21808  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
21809  {
21810  // Get the element
21811  FiniteElement* ele_pt =
21812  tmp_group1_shared_boundary_element_pt[iproc][e];
21813  // Get the face index
21814  const unsigned face_index =
21815  tmp_group1_shared_boundary_element_face_index[iproc][e];
21816 
21817  // Add the elements to the containers
21818  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21819  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21820 
21821  } // for (e < ntmp_group1_shared_bound_ele_iproc)
21822 
21823  } // if (my_rank < iproc)
21824  // Highest processor
21825  else if (my_rank > iproc)
21826  {
21827  // Get the haloed elements first and then the elements received
21828  // from processor "jproc" but that are haloed with "iproc"
21829  // processor
21830 
21831  // Get the number of elements to copy from local elements
21832  // (invert the indexes to get the haloed elements)
21833  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21834  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21835  for (unsigned e = 0;
21836  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21837  {
21838  // Get the element
21839  FiniteElement* ele_pt =
21840  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21841  // Get the face index
21842  const unsigned face_index =
21843  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21844 
21845  // Only include the element if it is nonhalo (this may be an
21846  // old halo element that helped to indentify a shared boundary
21847  // with iproc)
21848  if (!ele_pt->is_halo())
21849  {
21850  // Add the elements to the containers
21851  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21852  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21853  } // if (!ele_pt->is_halo())
21854 
21855  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21856 
21857  for (unsigned jproc = 0; jproc < nproc; jproc++)
21858  {
21859  // Can not receive elements from itself
21860  if (jproc != my_rank)
21861  {
21862  // Then the received shared elements from "jproc" but haloed
21863  // with "iproc"
21864  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21865  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21866  for (unsigned e = 0;
21867  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21868  {
21869  // Get the element
21870  FiniteElement* ele_pt =
21871  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21872  // Get the face index
21873  const unsigned face_index =
21874  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21875 
21876  // Add the elements to the containers
21877  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21878  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21879 
21880  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
21881 
21882  } // if (jproc != my_rank)
21883 
21884  } // for (jproc < nproc)
21885 
21886  // ... and finally any additional shared boundary elements from
21887  // tmp_group2
21888  const unsigned ntmp_group2_shared_bound_ele_iproc =
21889  tmp_group2_shared_boundary_element_pt[iproc].size();
21890  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
21891  {
21892  // Get the element
21893  FiniteElement* ele_pt =
21894  tmp_group2_shared_boundary_element_pt[iproc][e];
21895  // Get the face index
21896  const unsigned face_index =
21897  tmp_group2_shared_boundary_element_face_index[iproc][e];
21898 
21899  // Add the elements to the containers
21900  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21901  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21902 
21903  } // for (e < ntmp_group2_shared_bound_ele_iproc)
21904 
21905  } // else if (my_rank > iproc)
21906 
21907  } // for (iproc < nproc)
21908 
21909  // The time to sort shared boundaries
21910  if (Print_timings_level_load_balance>1)
21911  {
21912  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
21913  <<TimingHelpers::timer()-tt_start_sort_shared_boundaries
21914  << std::endl;
21915  }
21916 
21917  // =====================================================================
21918  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21919  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21920  // =====================================================================
21921 
21922  // =====================================================================
21923  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
21924  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
21925  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
21926  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
21927  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
21928  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
21929  // THE ORIGINAL BOUNDARIES
21930  // =====================================================================
21931  // Finally, create the new shared boundaries
21932 
21933  // Get the time to create the new shared boundaries
21934  double tt_start_create_new_shared_boundaries=0.0;
21935  if (Print_timings_level_load_balance>1)
21936  {
21937  tt_start_create_new_shared_boundaries=TimingHelpers::timer();
21938  }
21939 
21940  // Compute the elements that will remain after deletion in the
21941  // curent processor. This is required to check if the new shared
21942  // boundaries crete a connection with any node of the elements in
21943  // the boundaries
21944 
21945  // Try to use as much information as possible
21946 
21947  // Storage for the elements in the processor
21948  std::set<FiniteElement*> element_in_processor_pt;
21949 
21950  // Loop over the old elements, those before sending/received
21951  // elements to/from other processors
21952  unsigned nh_count6 = 0;
21953  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21954  {
21955  // Get the element
21956  FiniteElement* ele_pt = backed_up_ele_pt[e];
21957  // Only work with nonhalo elements
21958  if (!(ele_pt->is_halo()))
21959  {
21960  // Is the element part of the new domain
21961  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
21962  {
21963  // Add the element to the set of elements in the processor
21964  element_in_processor_pt.insert(ele_pt);
21965 
21966  }
21967 
21968  } // if (!(ele_pt->is_halo()))
21969 
21970  } // for (e < nelement_before_load_balance)
21971 
21972  // Now include the received elements from the other processors
21973  // Loop over the processors
21974  for (unsigned iproc = 0; iproc < nproc; iproc++)
21975  {
21976  // No elements received from myself
21977  if (iproc != my_rank)
21978  {
21979  // Get the number of received elements with the "iproc"
21980  // processor
21981  const unsigned n_received_ele = received_elements_pt[iproc].size();
21982  for (unsigned ie = 0; ie < n_received_ele; ie++)
21983  {
21984  // Get the ie-th received element from processor iproc
21985  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
21986 
21987  // Include it in the set of elements in the processor
21988  element_in_processor_pt.insert(ele_pt);
21989 
21990  } // for (ie < nreceived_ele)
21991 
21992  } // if (iproc != my_rank)
21993 
21994  } // for (iproc < nproc)
21995 
21996  // Now create the shared boundaries
21997  create_new_shared_boundaries(element_in_processor_pt,
21998  new_shared_boundary_element_pt,
21999  new_shared_boundary_element_face_index);
22000 
22001  // The time to create the new shared boundaries
22002  if (Print_timings_level_load_balance>1)
22003  {
22004  oomph_info << "CPU for creating new shared boundaries (load balance) [9]: "
22005  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries
22006  << std::endl;
22007  }
22008 
22009  // =====================================================================
22010  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22011  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22012  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22013  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22014  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22015  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22016  // THE ORIGINAL BOUNDARIES
22017  // =====================================================================
22018 
22019  // =====================================================================
22020  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22021  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22022  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22023  // =====================================================================
22024 
22025  // Get the time to delete elements no longer belonging to the
22026  // processor
22027  double tt_start_delete_elements=0.0;
22028  if (Print_timings_level_load_balance>1)
22029  {
22030  tt_start_delete_elements=TimingHelpers::timer();
22031  }
22032 
22033  // Once computed the new shared boundaries delete the elements that
22034  // no longer belong to the processor (including the old halo
22035  // elements)
22036 
22037  // The procedure is similar to the one performed at the distribution
22038  // stage (src/generic/mesh.cc -- distribute() method)
22039 
22040  // Clean the storage for halo(ed) elements/nodes
22041  this->Halo_node_pt.clear();
22042  this->Root_halo_element_pt.clear();
22043 
22044  this->Haloed_node_pt.clear();
22045  this->Root_haloed_element_pt.clear();
22046 
22047  // Mark all the nodes as obsolete
22048  const unsigned nnodes = this->nnode();
22049  for (unsigned j = 0; j < nnodes; j++)
22050  {
22051  this->node_pt(j)->set_obsolete();
22052  }
22053 
22054  // Flush the mesh storage
22055  this->flush_element_storage();
22056 
22057  // Delete any storage of external elements and nodes
22058  this->delete_all_external_storage();
22059 
22060  // Clear external storage
22061  this->External_halo_node_pt.clear();
22062  this->External_halo_element_pt.clear();
22063 
22064  this->External_haloed_node_pt.clear();
22065  this->External_haloed_element_pt.clear();
22066 
22067  // Keep track of the deleted elements
22068  Vector<FiniteElement*> deleted_elements;
22069 
22070  // Delete the elements that no longer belong to the processor
22071  unsigned nh_count7 = 0;
22072  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22073  {
22074  FiniteElement* ele_pt = backed_up_ele_pt[e];
22075  // Only work with nonhalo elements
22076  if (!(ele_pt->is_halo()))
22077  {
22078  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22079  {
22080  // Add the element to the mesh
22081  this->add_element_pt(ele_pt);
22082  // Get the number of nodes on the element
22083  const unsigned nele_nodes = ele_pt->nnode();
22084  // Loop over the nodes of the element
22085  for (unsigned j = 0; j < nele_nodes; j++)
22086  {
22087  // Mark the node as non-obsolete
22088  ele_pt->node_pt(j)->set_non_obsolete();
22089  } // for (j < nele_nodes)
22090 
22091  } // The element belongs to the domain
22092  else
22093  {
22094  // Delete the element, but keep track of it
22095  deleted_elements.push_back(ele_pt);
22096  // Delete and point to null
22097  delete ele_pt;
22098  ele_pt = 0;
22099  }
22100 
22101  } // if (!(ele_pt->is_halo()))
22102  else
22103  {
22104  // If the element is halo, delete if but keep track of it
22105  deleted_elements.push_back(ele_pt);
22106  // Delete and point to null
22107  delete ele_pt;
22108  ele_pt = 0;
22109  }
22110 
22111  } // for (e < nelement_before_load_balance)
22112 
22113  // Now add the received elements from each processor
22114  for (unsigned iproc = 0; iproc < nproc; iproc++)
22115  {
22116  if (iproc != my_rank)
22117  {
22118  // Get the number of received elements with the "iproc"
22119  // processor
22120  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22121  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22122  {
22123  // Get the element and add it to the mesh
22124  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22125  // Add the element to the mesh
22126  this->add_element_pt(ele_pt);
22127  // Get the number of nodes on the element
22128  const unsigned nele_nodes = ele_pt->nnode();
22129  // Loop over the nodes of the element
22130  for (unsigned j = 0; j < nele_nodes; j++)
22131  {
22132  // Mark the node as non-obsolete
22133  ele_pt->node_pt(j)->set_non_obsolete();
22134  } // for (j < nele_nodes)
22135 
22136  } // for (ie < nreceived_ele)
22137 
22138  } // if (iproc != my_rank)
22139 
22140  } // for (iproc < nproc)
22141 
22142  // Now remove the obsolete nodes
22143  this->prune_dead_nodes();
22144 
22145  // The time to delete elements no longer belonging to the processor
22146  if (Print_timings_level_load_balance>1)
22147  {
22148  oomph_info << "CPU for deleting elements no longer belonging to this processor (load balance) [10]: "
22149  <<TimingHelpers::timer()-tt_start_delete_elements
22150  << std::endl;
22151  }
22152 
22153  // =====================================================================
22154  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22155  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22156  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22157  // =====================================================================
22158 
22159  // =====================================================================
22160  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22161  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22162  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22163  // ON EACH BOUNDARY
22164  // =====================================================================
22165 
22166  // Get the time to re-establish the halo(ed) information
22167  double tt_start_re_etablish_halo_ed_info=0.0;
22168  if (Print_timings_level_load_balance>1)
22169  {
22170  tt_start_re_etablish_halo_ed_info=TimingHelpers::timer();
22171  }
22172 
22173  // Prepare the data to re-establish the halo(ed) scheme
22174 
22175  // Sort the nodes on the new shared boundaries so that they have the
22176  // same order on all processors
22177  this->sort_nodes_on_shared_boundaries();
22178 
22179  // Before re-establish the halo and haloed elements save the number
22180  // of current elements in the boundaries, this will be useful to
22181  // re-establish the boundary elements. Notice that there may be
22182  // boundary elements with null pointers, since the element may no
22183  // longer belong to the current processor
22184  const unsigned tmp_nboundary = this->nboundary();
22185  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22186 
22187  // If there are regions, save the number of boundary-region elements
22188  Vector<Vector<unsigned> > ntmp_boundary_elements_in_region(tmp_nboundary);
22189  // Are there regions?
22190  const unsigned n_regions = this->nregion();
22191 
22192  // Loop over the boundaries
22193  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22194  {
22195  // Get the number of boundary elements
22196  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22197 
22198  // Resize the container
22199  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22200 
22201  // Loop over the regions
22202  for (unsigned rr = 0 ; rr < n_regions; rr++)
22203  {
22204  // Get the region id
22205  const unsigned region_id =
22206  static_cast<unsigned>(this->region_attribute(rr));
22207 
22208  // Store the number of element in the region (notice we are
22209  // using the region index not the region id to refer to the
22210  // region)
22211  ntmp_boundary_elements_in_region[ib][rr] =
22212  this->nboundary_element_in_region(ib, region_id);
22213 
22214  } // for (rr < n_regions)
22215 
22216  } // for (ib < tmp_nboundary)
22217 
22218  // Re-establish the halo(ed) scheme
22219  this->reset_halo_haloed_scheme();
22220 
22221  // Get the number of elements in the mesh after load balance
22222  const unsigned nelement_after_load_balance = this->nelement();
22223 
22224  // We need to reset boundary elements because we need to get rid of
22225  // the old boundary elements and stay only with the new ones
22226  this->reset_boundary_element_info(ntmp_boundary_elements,
22227  ntmp_boundary_elements_in_region,
22228  deleted_elements);
22229 
22230  // There is no need to re-set boundary coordinates since the
22231  // load-balanced mesh already has the correct information (the
22232  // boundary coordinate for each node was sent with the node
22233  // information)
22234 
22235  // We need to re-compute the number of segments on each boundary
22236  // after load balance. It may be possible that the boundary is now
22237  // split in more segments, or that previous gaps between the
22238  // segments have now dissapeared because the received elements
22239  // filled those gaps
22240 
22241  // In order to re-set the number of segments it is required to get
22242  // the face elements, attach them to create a contiguous
22243  // representation of the boundary (in segments possibly) and then
22244  // counter the number of segments. This can only be done after
22245  // restoring the boundary elements scheme (which has been done
22246  // above)
22247 
22248  // Set the number of segments for the boundaries with geom objects
22249  // associated. The correct value is not on the original mesh since
22250  // it is computed only when calling then
22251  // setup_boundary_coordinates() method (called only for those
22252  // boundaries with no geom object associated)
22253  for (unsigned b = 0; b < tmp_nboundary; b++)
22254  {
22255  if (this->boundary_geom_object_pt(b)!=0)
22256  {
22257  // Clear the boundary segment nodes storage
22258  this->flush_boundary_segment_node(b);
22259 
22260  // Dummy vector of nodes on segments
22261  Vector<Vector<Node*> > dummy_segment_node_pt;
22262 
22263  // Compute the new number of segments in the boundary
22264  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22265 
22266  // Get the number of segments from the vector of nodes
22267  const unsigned nsegments = dummy_segment_node_pt.size();
22268 
22269  // Set the number of segments for the storing of the nodes
22270  // associated to the segments
22271  this->set_nboundary_segment_node(b, nsegments);
22272  } // if (this->boundary_geom_object_pt(b)!=0)
22273 
22274  } // for (b < n_boundary)
22275 
22276  // The time to re-establish the halo(ed) information
22277  if (Print_timings_level_load_balance>1)
22278  {
22279  oomph_info << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22280  <<TimingHelpers::timer()-tt_start_re_etablish_halo_ed_info
22281  << std::endl;
22282  }
22283 
22284  // =====================================================================
22285  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22286  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22287  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22288  // BOUNDARY
22289  // =====================================================================
22290 
22291  if (Print_timings_level_load_balance>1)
22292  {
22293  oomph_info <<"CPU for load balance [n_ele_before="
22294  <<nelement_before_load_balance<<", n_ele_after="
22295  <<nelement_after_load_balance<<"]: "
22296  <<TimingHelpers::timer()-t_start_overall_load_balance
22297  << std::endl;
22298  }
22299 
22300  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22301 
22302  }
22303 
22304  //======================================================================
22305  /// Use the first and second group of elements to find the
22306  /// intersection between them to get the shared boundary
22307  /// elements from the first and second group
22308  //======================================================================
22309  template <class ELEMENT>
22312  const Vector<FiniteElement*> &first_element_pt,
22313  const Vector<FiniteElement*> &second_element_pt,
22314  Vector<FiniteElement*> &first_shared_boundary_element_pt,
22315  Vector<unsigned> &first_shared_boundary_element_face_index,
22316  Vector<FiniteElement*> &second_shared_boundary_element_pt,
22317  Vector<unsigned> &second_shared_boundary_element_face_index)
22318  {
22319  // 1) Compare their faces (nodes) and if they match then they are
22320  // part of a shared boundary
22321  // 2) Save the first and second group of elements that give rise to
22322  // the shared boundary, also include the face index
22323 
22324  // Get the number of elements on the first group
22325  const unsigned nfirst_element = first_element_pt.size();
22326  // Loop over the elements in the first group
22327  for (unsigned ef = 0; ef < nfirst_element; ef++)
22328  {
22329  // Get the element
22330  FiniteElement* fele_pt = first_element_pt[ef];
22331  // Check if the element is halo
22332  bool first_ele_is_halo = false;
22333  if (fele_pt->is_halo())
22334  {
22335  first_ele_is_halo = true;
22336  }
22337  // Get each of the faces
22338  for (unsigned ifface = 0; ifface < 3; ifface++)
22339  {
22340  Vector<Node*> first_face(2);
22341  if (ifface == 0)
22342  {
22343  first_face[0] = fele_pt->node_pt(1);
22344  first_face[1] = fele_pt->node_pt(2);
22345  }
22346  else if (ifface == 1)
22347  {
22348  first_face[0] = fele_pt->node_pt(2);
22349  first_face[1] = fele_pt->node_pt(0);
22350  }
22351  else if (ifface == 2)
22352  {
22353  first_face[0] = fele_pt->node_pt(0);
22354  first_face[1] = fele_pt->node_pt(1);
22355  }
22356 
22357  // Now check each of the faces with the faces on the second
22358  // elements
22359 
22360  // Get the number of elements on the second group
22361  const unsigned nsecond_element = second_element_pt.size();
22362  // Loop over the elements in the second group
22363  for (unsigned es = 0; es < nsecond_element; es++)
22364  {
22365  // Get the element
22366  FiniteElement* sele_pt = second_element_pt[es];
22367  // Check if the element is halo
22368  bool second_ele_is_halo = false;
22369  if (sele_pt->is_halo())
22370  {
22371  second_ele_is_halo = true;
22372  }
22373  // Now check whether both elements are halo, if that is the
22374  // case then we go for the next elements. We can not look for
22375  // shared boundaries between halo elements since other
22376  // processors, those with the nonhalo counterpart of the
22377  // elements, are in charge of creating those shared boundaries
22378  if (!(first_ele_is_halo && second_ele_is_halo))
22379  {
22380  // Get each of the faces
22381  for (unsigned isface = 0; isface < 3; isface++)
22382  {
22383  Vector<Node*> second_face(2);
22384  if (isface == 0)
22385  {
22386  second_face[0] = sele_pt->node_pt(1);
22387  second_face[1] = sele_pt->node_pt(2);
22388  }
22389  else if (isface == 1)
22390  {
22391  second_face[0] = sele_pt->node_pt(2);
22392  second_face[1] = sele_pt->node_pt(0);
22393  }
22394  else if (isface == 2)
22395  {
22396  second_face[0] = sele_pt->node_pt(0);
22397  second_face[1] = sele_pt->node_pt(1);
22398  }
22399 
22400  // Now check for any intersection among first and second
22401  // faces
22402  if (first_face[0] == second_face[0] &&
22403  first_face[1] == second_face[1])
22404  {
22405  // Save the elements on the corresponding containers
22406  first_shared_boundary_element_pt.push_back(fele_pt);
22407  // .. and the face index
22408  first_shared_boundary_element_face_index.push_back(ifface);
22409 
22410  // Save the elements on the corresponding containers
22411  second_shared_boundary_element_pt.push_back(sele_pt);
22412  // .. and the face index
22413  second_shared_boundary_element_face_index.push_back(isface);
22414 
22415  // Break the loop over the faces of the first elements
22416  // and the first elements, we need to continue looking
22417  // on the next face of the first elements
22418 
22419  // Increase the indexes to force breaking the loop
22420  isface = 3;
22421  es = nsecond_element;
22422 
22423  }
22424  // Check for intersection with the reversed case too
22425  else if (first_face[0] == second_face[1] &&
22426  first_face[1] == second_face[0])
22427  {
22428  // Save the elements on the corresponding containers
22429  first_shared_boundary_element_pt.push_back(fele_pt);
22430  // .. and the face index
22431  first_shared_boundary_element_face_index.push_back(ifface);
22432 
22433  // Save the elements on the corresponding containers
22434  second_shared_boundary_element_pt.push_back(sele_pt);
22435  // .. and the face index
22436  second_shared_boundary_element_face_index.push_back(isface);
22437 
22438  // Break the loop over the faces of the first elements
22439  // and the first elements, we need to continue looking
22440  // on the next face of the first elements
22441 
22442  // Increase the indexes to force breaking the loop
22443  isface = 3;
22444  es = nsecond_element;
22445  }
22446 
22447  } // for (isface < 3)
22448 
22449  } // if (!(first_ele_is_halo && second_ele_is_halo))
22450 
22451  } // for (es < nsecond_element)
22452 
22453  } // for (ifface < 3)
22454 
22455  } // for (ef < nfirst_element)
22456 
22457  }
22458 
22459  //======================================================================
22460  /// \short Creates the new shared boundaries, this method is also in
22461  /// charge of computing the shared boundaries ids of each processor
22462  /// and send that info. to all the processors
22463  //======================================================================
22464  template <class ELEMENT>
22466  create_new_shared_boundaries(std::set<FiniteElement*>
22467  &element_in_processor_pt,
22469  &new_shared_boundary_element_pt,
22471  &new_shared_boundary_element_face_index)
22472  {
22473  // Get the number of processors
22474  const unsigned nproc = this->communicator_pt()->nproc();
22475  // Get the rank of the current processor
22476  const unsigned my_rank = this->communicator_pt()->my_rank();
22477 
22478  // ================================================================
22479  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22480  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22481  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22482  // SAME EDGE (INTERNAL BOUNDARIES)
22483  // ================================================================
22484 
22485  // Get the time to get edges from shared boundary face elements
22486  double tt_start_get_edges_from_shd_bnd_face_ele=0.0;
22487  if (Print_timings_level_load_balance>2)
22488  {
22489  tt_start_get_edges_from_shd_bnd_face_ele=TimingHelpers::timer();
22490  }
22491 
22492  // Face elements that create the shared boundaries (unsorted)
22493  Vector<Vector<FiniteElement*> > tmp_unsorted_face_ele_pt(nproc);
22494  // The elements from where the face element was created
22495  Vector<Vector<FiniteElement*> > tmp_unsorted_ele_pt(nproc);
22496  // The face index of the bulk element from where was created the
22497  // face element
22498  Vector<Vector<int> > tmp_unsorted_face_index_ele(nproc);
22499 
22500  // Store the current edges lying on boundaries (this will help for
22501  // any edge of a shared boundary lying on an internal boundary)
22502  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22503 
22504  // Compute the edges on the other boundaries
22505  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22506 
22507  // Mark those edges (pair of nodes overlapped by a shared boundary)
22508  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
22509 
22510  // Associate every found edge (face element) on the shared boundary
22511  // with an original boundary only if the edge (face element) lies
22512  // (overlaps) on an original boundary, it may happen only for
22513  // internal boundaries
22514  Vector<Vector<int> > tmp_edge_boundary(nproc);
22515 
22516  // Get the face elements from the shared boundary elements with in
22517  // each processor
22518  for (unsigned iproc = 0; iproc < nproc; iproc++)
22519  {
22520  // There are no shared boundary elements with myself
22521  if (iproc != my_rank)
22522  {
22523  // Get the number of shared boundary elements with in "iproc"
22524  // processor
22525  const unsigned n_shared_bound_ele =
22526  new_shared_boundary_element_pt[iproc].size();
22527 
22528  // Avoid to create repeated face elements, compare the nodes on
22529  // the edges of the face elements
22530  Vector<std::pair<Node*, Node*> > done_faces;
22531 
22532  // Count the number of repeated faces
22533  unsigned nrepeated_faces = 0;
22534 
22535  // Loop over the shared boundary elements with the iproc
22536  // processor
22537  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22538  {
22539  // Get the bulk element
22540  FiniteElement* bulk_ele_pt =
22541  new_shared_boundary_element_pt[iproc][iele];
22542 
22543  // Get the face index
22544  int face_index =
22545  static_cast<int>(new_shared_boundary_element_face_index[iproc][iele]);
22546 
22547  // Create the face element
22548  FiniteElement* tmp_ele_pt =
22549  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
22550 
22551  // Before adding the face element to the vector check that is
22552  // not has been previously created
22553  bool done_face = false;
22554 
22555  // Get the number of nodes on the face element and get the first
22556  // and last node
22557  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22558  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22559  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22560 
22561  // Get the number of already done face elements
22562  const unsigned ndone_faces = done_faces.size();
22563  // Loop over the already visited face elements
22564  for (unsigned n = 0; n < ndone_faces; n++)
22565  {
22566  Node* first_done_face_node_pt = done_faces[n].first;
22567  Node* second_done_face_node_pt = done_faces[n].second;
22568  if (first_face_node_pt == first_done_face_node_pt &&
22569  last_face_node_pt == second_done_face_node_pt)
22570  {
22571  done_face = true;
22572  nrepeated_faces++;
22573  break;
22574  }
22575  // Check for the reversed case
22576  else if (first_face_node_pt == second_done_face_node_pt &&
22577  last_face_node_pt == first_done_face_node_pt)
22578  {
22579  done_face = true;
22580  nrepeated_faces++;
22581  break;
22582  }
22583 
22584  } // for (n < ndone_faces)
22585 
22586  // Only include the faces that are not repeated
22587  if (!done_face)
22588  {
22589  // Add the face element in the vector
22590  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22591  // Add the bulk element to the vector
22592  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22593  // Add the face index to the vector
22594  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22595  // Include the nodes in the done nodes vector
22596  std::pair<Node*, Node*> tmp_edge =
22597  std::make_pair(first_face_node_pt, last_face_node_pt);
22598  // Push the edge
22599  done_faces.push_back(tmp_edge);
22600 
22601  // Associate the face element with a boundary (if that is
22602  // the case)
22603  int edge_boundary_id = -1;
22604  std::map<std::pair<Node*,Node*>, unsigned >::iterator it;
22605  it = elements_edges_on_boundary.find(tmp_edge);
22606  // If the edges lie on a boundary then get the boundary id
22607  // on which the edges lie
22608  if (it != elements_edges_on_boundary.end())
22609  {
22610  // Assign the internal boundary id associated with the
22611  // edge
22612  edge_boundary_id = (*it).second;
22613  // Mark the edge as overlapped
22614  overlapped_edge[tmp_edge] = true;
22615  // Also include the reversed version of the edge
22616  std::pair<Node*, Node*> rev_tmp_edge =
22617  std::make_pair(last_face_node_pt, first_face_node_pt);
22618  // Mark the reversed version of the edge as overlapped
22619  overlapped_edge[rev_tmp_edge] = true;
22620  }
22621  else
22622  {
22623  // Look for the reversed version
22624  std::pair<Node*,Node*> rtmp_edge =
22625  std::make_pair(last_face_node_pt, first_face_node_pt);
22626  it = elements_edges_on_boundary.find(rtmp_edge);
22627  if (it != elements_edges_on_boundary.end())
22628  {
22629  // Assign the internal boundary id associated with the
22630  // edge
22631  edge_boundary_id = (*it).second;
22632  // Mark the edge as overlapped
22633  overlapped_edge[rtmp_edge] = true;
22634  // Mark the reversed version (normal) of the edge as
22635  // overlapped
22636  overlapped_edge[tmp_edge] = true;
22637  }
22638  }
22639  // Associate the edge with a boundary
22640  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22641  } // if (!done_face)
22642  else
22643  {
22644  // Delete the repeated face elements
22645  delete tmp_ele_pt;
22646  tmp_ele_pt = 0;
22647  }
22648 
22649  } // for (iele < n_shared_bound_ele)
22650 
22651  } // if (iproc != my_rank)
22652 
22653  } // for (iproc < nproc)
22654 
22655  // The time to get edges from shared boundary face elements
22656  if (Print_timings_level_load_balance>2)
22657  {
22658  oomph_info << "CPU for getting edges from shared boundary face elements (load balance) [9.1]: "
22659  <<TimingHelpers::timer()-tt_start_get_edges_from_shd_bnd_face_ele
22660  << std::endl;
22661  }
22662 
22663  // ================================================================
22664  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22665  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22666  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22667  // SAME EDGE (INTERNAL BOUNDARIES)
22668  // ================================================================
22669 
22670  // ================================================================
22671  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22672  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22673  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22674  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22675  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22676  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22677  // ================================================================
22678 
22679  // Get the time to sort shared face elements
22680  double tt_start_sort_shared_face_elements=0.0;
22681  if (Print_timings_level_load_balance>2)
22682  {
22683  tt_start_sort_shared_face_elements=TimingHelpers::timer();
22684  }
22685 
22686  // -----------------------------------------------------------------
22687  // Before continuing we need to ensured that the face elements are
22688  // stored in the same order in all processors. Sort them starting
22689  // from the face element with the bottom-left node coordinate
22690 
22691  // Face elements that create the shared boundaries (unsorted)
22692  Vector<Vector<FiniteElement*> > unsorted_face_ele_pt(nproc);
22693  // The elements from where the face element was created
22694  Vector<Vector<FiniteElement*> > unsorted_ele_pt(nproc);
22695  // The face index of the bulk element from where was created the
22696  // face element
22697  Vector<Vector<int> > unsorted_face_index_ele(nproc);
22698  // Associate every found edge on the shared boundary with an
22699  // original boundary only if the edge lies on an original boundary,
22700  // it may happen only for internal boundaries
22701  Vector<Vector<int> > edge_boundary(nproc);
22702 
22703  // For each face element, mark if the element should be considered
22704  // in its inverted way to fullfill with the bottom-left node to be
22705  // the first (left) node. First get the status of each element and
22706  // when they get sorted copy the values across
22707  std::vector<std::vector<bool> > tmp_treat_as_inverted(nproc);
22708  // Vector to store the status of the sorted face elements based on
22709  // the bottom-left condition
22710  std::vector<std::vector<bool> > treat_as_inverted(nproc);
22711 
22712  // Get the bottom-left node of each face element and sort them
22713  // starting from the face element with the bottom-left node
22714 
22715  // Loop over the processors
22716  for (unsigned iproc = 0; iproc < nproc; iproc++)
22717  {
22718  // There are no shared face elements with myself
22719  if (iproc != my_rank)
22720  {
22721  // Get the number of unsorted face elements
22722  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22723  // Store the centroid of the face element. Perform the sorting
22724  // based on the bottom-left centroid of each face element
22725  Vector<Vector<double> > centroid_vertices(n_face_ele);
22726 
22727  // Resize the storage for the treating as inverted face element
22728  // storage
22729  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22730 
22731  // Loop over the face elements associated with the iproc
22732  // processor
22733  for (unsigned e = 0; e < n_face_ele; e++)
22734  {
22735  // Get the face element
22736  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22737  // Get the number of nodes of the face element
22738  const unsigned n_node = face_ele_pt->nnode();
22739  Vector<double> bottom_left(2);
22740  // Assign as the bottom-left node the first node
22741  // Get the node
22742  Node* node_pt = face_ele_pt->node_pt(0);
22743  bottom_left[0] = node_pt->x(0);
22744  bottom_left[1] = node_pt->x(1);
22745  // Set as not treat as inverted element
22746  tmp_treat_as_inverted[iproc][e] = false;
22747  // Loop over the nodes to get the bottom-left vertex of all
22748  // the nodes
22749  for (unsigned n = 1; n < n_node; n++)
22750  {
22751  // Get the node
22752  Node* node_pt = face_ele_pt->node_pt(n);
22753  if (node_pt->x(1) < bottom_left[1])
22754  {
22755  bottom_left[0] = node_pt->x(0);
22756  bottom_left[1] = node_pt->x(1);
22757  // The first node is no longer the bottom-left node, we
22758  // need to treat the element as inverted
22759  tmp_treat_as_inverted[iproc][e] = true;
22760  } // if (node_pt->x(1) < bottom_left[1])
22761  else if (node_pt->x(1) == bottom_left[1])
22762  {
22763  if (node_pt->x(0) < bottom_left[0])
22764  {
22765  bottom_left[0] = node_pt->x(0);
22766  bottom_left[1] = node_pt->x(1);
22767  // The first node is no longer the bottom-left node, we
22768  // need to treat the element as inverted
22769  tmp_treat_as_inverted[iproc][e] = true;
22770  } // if (node_pt->x(0) < bottom_left[0])
22771  } // else if (node_pt->x(1) == bottom_left[1])
22772 
22773  } // for (n < n_node
22774 
22775  // Resize the container
22776  centroid_vertices[e].resize(2);
22777  // Add the centroid of the face element
22778  centroid_vertices[e][0] =
22779  (face_ele_pt->node_pt(0)->x(0) +
22780  face_ele_pt->node_pt(n_node-1)->x(0))*0.5;
22781  centroid_vertices[e][1] =
22782  (face_ele_pt->node_pt(0)->x(1) +
22783  face_ele_pt->node_pt(n_node-1)->x(1))*0.5;
22784 
22785  } // for (e < n_face_ele)
22786 
22787  // Sort the face elements based on their bottom-left node
22788  unsigned n_sorted_bottom_left = 0;
22789  // Keep track of the already sorted face elements
22790  std::vector<bool> done_face(n_face_ele, false);
22791 
22792  // Loop until all face elements have been sorted
22793  while (n_sorted_bottom_left < n_face_ele)
22794  {
22795  // The index of the next bottom-left face element
22796  unsigned index = 0;
22797  Vector<double> current_bottom_left(2);
22798  for (unsigned e = 0; e < n_face_ele; e++)
22799  {
22800  // Get the first not done face element
22801  if (!done_face[e])
22802  {
22803  // Store the first not done
22804  current_bottom_left[0] = centroid_vertices[e][0];
22805  current_bottom_left[1] = centroid_vertices[e][1];
22806  // Set the index
22807  index = e;
22808  // Break
22809  break;
22810  } // if (!done_face[e])
22811 
22812  } // for (e < n_face_ele)
22813 
22814  // Loop over all the other nondone face elements
22815  for (unsigned e = index + 1; e < n_face_ele; e++)
22816  {
22817  // Get the first not done face element
22818  if (!done_face[e])
22819  {
22820  if (centroid_vertices[e][1] < current_bottom_left[1])
22821  {
22822  // Re-set the current bottom left vertex
22823  current_bottom_left[0] = centroid_vertices[e][0];
22824  current_bottom_left[1] = centroid_vertices[e][1];
22825  // Re-assign the index
22826  index = e;
22827  } // if (centroid_vertices[e][1] < current_bottom_left[1])
22828  else if (centroid_vertices[e][1] == current_bottom_left[1])
22829  {
22830  if (centroid_vertices[e][0] < current_bottom_left[0])
22831  {
22832  // Re-set the current bottom left vertex
22833  current_bottom_left[0] = centroid_vertices[e][0];
22834  current_bottom_left[1] = centroid_vertices[e][1];
22835  // Re-assign the index
22836  index = e;
22837  } // if (centroid_vertices[e][0] < current_bottom_left[0])
22838 
22839  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
22840 
22841  } // if (!done_face[e])
22842 
22843  } // for (e < n_face_ele)
22844 
22845  // The face element
22846  unsorted_face_ele_pt[iproc].
22847  push_back(tmp_unsorted_face_ele_pt[iproc][index]);
22848  // The boundary element
22849  unsorted_ele_pt[iproc].
22850  push_back(tmp_unsorted_ele_pt[iproc][index]);
22851  // The face index
22852  unsorted_face_index_ele[iproc].
22853  push_back(tmp_unsorted_face_index_ele[iproc][index]);
22854  // The edge boundary associated to the face element
22855  edge_boundary[iproc].
22856  push_back(tmp_edge_boundary[iproc][index]);
22857  // The treat as inverted condition
22858  treat_as_inverted[iproc].
22859  push_back(tmp_treat_as_inverted[iproc][index]);
22860 
22861  // Mark the face element as sorted (done or visited)
22862  done_face[index] = true;
22863 
22864  // Increase the number of sorted bottom-left face elements
22865  n_sorted_bottom_left++;
22866 
22867  } // while (n_sorted_bottom_left < n_face_ele)
22868 
22869 #ifdef PARANOID
22870  // Get the number of face elements sorted with the bottom-left
22871  // condition
22872  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
22873 
22874  if (tmp_n_face_ele != n_face_ele)
22875  {
22876  std::ostringstream error_stream;
22877  error_stream
22878  << "The number of face elements before sorting them starting\n"
22879  << "from their bottom-left vertex is different from the number\n"
22880  << "of face elements after the sorting\n"
22881  << "N. ele before sorting: (" << n_face_ele << ")\n"
22882  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
22883  throw OomphLibError(error_stream.str(),
22884  "RefineableTriangleMesh::create_new_shared_boundaries()",
22885  OOMPH_EXCEPTION_LOCATION);
22886  }
22887 #endif
22888 
22889  } // if (iproc != my_rank)
22890 
22891  } // for (iproc < nproc)
22892 
22893  // The time to sort shared face elements
22894  if (Print_timings_level_load_balance>2)
22895  {
22896  oomph_info << "CPU for sorting shared boundary face elements (load balance) [9.2]: "
22897  <<TimingHelpers::timer()-tt_start_sort_shared_face_elements
22898  << std::endl;
22899  }
22900 
22901  // ================================================================
22902  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
22903  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
22904  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
22905  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
22906  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22907  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22908  // ================================================================
22909 
22910  // ================================================================
22911  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22912  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22913  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22914  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22915  // IS THE CASE)
22916  // ================================================================
22917 
22918  // Get the time to compute the valency of each node
22919  double tt_start_compute_valency_of_nodes=0.0;
22920  if (Print_timings_level_load_balance>2)
22921  {
22922  tt_start_compute_valency_of_nodes=TimingHelpers::timer();
22923  }
22924 
22925  // Stores the global-degree of each node
22926  std::map<Node*, unsigned> global_node_degree;
22927 
22928  // Get the global degree (valency) of each node
22929  compute_shared_node_degree_helper(unsorted_face_ele_pt,
22930  global_node_degree);
22931 
22932  // The time to compute the valency of each node
22933  if (Print_timings_level_load_balance>2)
22934  {
22935  oomph_info << "CPU for computing the valency of nodes (load balance) [9.3]: "
22936  <<TimingHelpers::timer()-tt_start_compute_valency_of_nodes
22937  << std::endl;
22938  }
22939 
22940  // ================================================================
22941  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22942  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22943  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22944  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22945  // IS THE CASE)
22946  // ================================================================
22947 
22948  // ================================================================
22949  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
22950  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
22951  // ================================================================
22952 
22953  // Get the time to compute nodes on non overlapped shared boundaries
22954  double tt_start_nodes_on_non_overlapped_shd_bnd=0.0;
22955  if (Print_timings_level_load_balance>2)
22956  {
22957  tt_start_nodes_on_non_overlapped_shd_bnd=TimingHelpers::timer();
22958  }
22959 
22960  // Mark the nodes on original boundaries not overlapped by shared
22961  // boundaries
22962  std::map<unsigned, std::map<Node*, bool> >
22963  node_on_bnd_not_overlapped_by_shd_bnd;
22964 
22965  // Loop over the edges of the original boundaries
22966  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
22967  elements_edges_on_boundary.begin();
22968  it_map != elements_edges_on_boundary.end(); it_map++)
22969  {
22970  // Get the edge
22971  std::pair<Node*,Node*> edge_pair = (*it_map).first;
22972  // Is the edge overlaped by a shared boundary
22973  if (!overlapped_edge[edge_pair])
22974  {
22975  // Mark the nodes of the edge as being on an edge not overlaped
22976  // by a shared boundary on the boundary the edge is
22977  unsigned b = (*it_map).second;
22978 
22979  // Get the left node
22980  Node* left_node_pt = edge_pair.first;
22981  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
22982 
22983  // Get the right node
22984  Node* right_node_pt = edge_pair.second;
22985  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
22986 
22987  } // if (!overlapped_edge[edge_pair])
22988 
22989  } // Loop over edges to mark those nodes on overlaped edge by
22990  // shared boundaries
22991 
22992  // The time to compute nodes on non overlapped shared boundaries
22993  if (Print_timings_level_load_balance>2)
22994  {
22995  oomph_info << "CPU for computing nodes on non overlapped shared boundaries (load balance) [9.4]: "
22996  <<TimingHelpers::timer()-tt_start_nodes_on_non_overlapped_shd_bnd
22997  << std::endl;
22998  }
22999 
23000  // ================================================================
23001  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23002  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23003  // ================================================================
23004 
23005  // ==================================================================
23006  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23007  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23008  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23009  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23010  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23011  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23012  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23013  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23014  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23015  // ==================================================================
23016 
23017  // Get the time to sort shared boundaries face elements to create a
23018  // continuous representation of the boundary
23019  double tt_start_join_shd_bnd_face_ele=0.0;
23020  if (Print_timings_level_load_balance>2)
23021  {
23022  tt_start_join_shd_bnd_face_ele=TimingHelpers::timer();
23023  }
23024 
23025  // Face elements that create the shared boundaries (sorted)
23026  Vector<Vector<Vector<FiniteElement*> > > sorted_face_ele_pt(nproc);
23027 
23028  // Bulk elements that create the shared boundaries (sorted)
23029  Vector<Vector<Vector<FiniteElement*> > > sorted_ele_pt(nproc);
23030 
23031  // Face indexes of the bulk elements that create the shared
23032  // boundaries (sorted)
23033  Vector<Vector<Vector<int> > > sorted_face_index_ele(nproc);
23034 
23035  // Store the edge boundary id associated with a shared boundary (if
23036  // any, this apply for shared boundaries lying on internal
23037  // boundaries, then the shared boundary is marked as overlaping an
23038  // internal boundary)
23039  Vector<Vector<int> > edge_boundary_id(nproc);
23040 
23041  // Store the connection information obtained when joining the face
23042  // elements (used for connection purposes only)
23043  Vector<Vector<Vector<int> > > sorted_connection_info(nproc);
23044 
23045  // Store the local shared boundary id associated to the elements
23046  // that will give rise to the shared boundaries (used to compute the
23047  // global shared boundary id from the local shared boundary id)
23048  Vector<Vector<unsigned> > proc_local_shared_boundary_id(nproc);
23049 
23050  // Map that associates the local shared boundary id with the list of
23051  // nodes that create it
23052  std::map<unsigned, std::list<Node*> >
23053  local_shd_bnd_id_to_sorted_list_node_pt;
23054 
23055  // Local shared bouonday id (used to locally identify the lists of
23056  // nodes that create shared boundaries, it is also useful to
23057  // identify connections with shared boundaries)
23058  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23059 
23060  // Sort the face elements, using the nodes at its ends
23061 
23062  // Mark the done elements
23063  std::map<FiniteElement*, bool> done_ele;
23064 
23065  // Mark the inverted elements
23066  std::map<FiniteElement*, bool> is_inverted;
23067 
23068  // Sort the face elements to get the number of shared boundaries
23069  // with in each processor
23070  for (unsigned iproc = 0; iproc < nproc; iproc++)
23071  {
23072  // No face elements with myself
23073  if (iproc != my_rank)
23074  {
23075  // Get the number of unsorted face elements with the iproc
23076  // processor
23077  const unsigned nunsorted_face_ele =
23078  unsorted_face_ele_pt[iproc].size();
23079  // Count the number of sorted face elements
23080  unsigned nsorted_face_ele = 0;
23081 
23082  // Iterate until all the face elements have been sorted
23083  while (nsorted_face_ele < nunsorted_face_ele)
23084  {
23085  // Take the first nonsorted element an use it as root element,
23086  // add elements to the left and right until no more elements
23087  // left or until a stop condition is reached (connection,
23088  // boundary node)
23089 
23090 #ifdef PARANOID
23091  // Flag to indicate if a root element was found
23092  bool found_root_element = false;
23093 #endif
23094 
23095  // Index of the found root element
23096  unsigned root_index = 0;
23097 
23098  // List that contains the sorted face elements
23099  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23100 
23101  // List that contains the sorted elements
23102  std::list<FiniteElement*> tmp_sorted_ele_pt;
23103 
23104  // List that contains the sorted face indexes of the bulk
23105  // elements
23106  std::list<int> tmp_sorted_face_index_ele;
23107 
23108  // Storing for the sorting nodes extracted from the face
23109  // elements. The sorted nodes are used to identify connections
23110  // among new shared boundaries or original boundaries
23111  std::list<Node*> tmp_sorted_nodes_pt;
23112  // Clear the storage (just in case)
23113  tmp_sorted_nodes_pt.clear();
23114 
23115  // The initial and final nodes
23116  Node* initial_node_pt = 0;
23117  Node* final_node_pt = 0;
23118 
23119  // Store the original boundary id related with the root face
23120  // element (if there is one)
23121  int root_edge_bound_id = -1;
23122 
23123  // Loop over the unsorted face elements until a root element
23124  // is found
23125  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23126  {
23127  // Get a root element
23128  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23129  // Is the element already done?
23130  if (!done_ele[root_ele_pt])
23131  {
23132  // Get the edge boundary id associated with the edge (if
23133  // there is one)
23134  root_edge_bound_id = edge_boundary[iproc][e];
23135  // Add the face element to the list of sorted face
23136  // elements
23137  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23138  // Add the bulk element to the list of sorted elements
23139  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23140  // Add the face index to the list of sorted face index
23141  // elements
23142  tmp_sorted_face_index_ele.push_back(
23143  unsorted_face_index_ele[iproc][e]);
23144 
23145  // Get the nodes and state them as initial and final
23146  const unsigned nnodes = root_ele_pt->nnode();
23147  // Check if the face element should be treated as inverted
23148  if (!treat_as_inverted[iproc][e])
23149  {
23150  initial_node_pt = root_ele_pt->node_pt(0);
23151  final_node_pt = root_ele_pt->node_pt(nnodes-1);
23152  }
23153  else
23154  {
23155  initial_node_pt = root_ele_pt->node_pt(nnodes-1);
23156  final_node_pt = root_ele_pt->node_pt(0);
23157  }
23158  // Add both nodes to the list of sorted nodes
23159  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23160  tmp_sorted_nodes_pt.push_back(final_node_pt);
23161 
23162  // Mark the element as done
23163  done_ele[root_ele_pt] = true;
23164  // Check if the face element should be treated as inverted
23165  if (!treat_as_inverted[iproc][e])
23166  {
23167  // Mark the element as not inverted
23168  is_inverted[root_ele_pt] = false;
23169  }
23170  else
23171  {
23172  // Mark the element as inverted
23173  is_inverted[root_ele_pt] = true;
23174  }
23175  // Increase the counter for sorted face elements
23176  nsorted_face_ele++;
23177  // Set the root index
23178  root_index = e;
23179 #ifdef PARANOID
23180  // Set the flag of found root element
23181  found_root_element = true;
23182 #endif
23183  // Break the loop
23184  break;
23185 
23186  } // if (!done_ele[root_ele_pt])
23187 
23188  } // for (e < nunsorted_face_ele)
23189 
23190 #ifdef PARANOID
23191  if (!found_root_element)
23192  {
23193  std::ostringstream error_stream;
23194  error_stream
23195  << "It was not possible the found the root element\n\n";
23196  throw OomphLibError(error_stream.str(),
23197  OOMPH_CURRENT_FUNCTION,
23198  OOMPH_EXCEPTION_LOCATION);
23199  }
23200 #endif
23201 
23202  // New element added. Continue adding elements -- or nodes --
23203  // to the list of shared boundary elements while a new element
23204  // has been added to the list (we have just added the root
23205  // element)
23206  bool new_element_added = true;
23207 
23208  // Similarly that in the
23209  // "create_polylines_from_halo_elements_helper() method, we
23210  // extract the nodes (in order) that will create the shared
23211  // polyline, and also check for connections with the just
23212  // added face elements (nodes)
23213 
23214  // Flags to indicate at which end (of the sorted list of
23215  // boundary elements) the element was added (left or right)
23216  bool element_added_to_the_left = false;
23217  bool element_added_to_the_right = false;
23218 
23219  // Flag to indicate that the "left" node of the element added
23220  // to the left was found to be shared with another boundary
23221  bool connection_to_the_left = false;
23222 
23223  // Flag to indicate that the "right" node of the element added
23224  // to the right was found to be shared with another boundary
23225  bool connection_to_the_right = false;
23226 
23227  // Flag to stop the adding of elements (and nodes) to the
23228  // current shared boundary (because there are connections at
23229  // both ends)
23230  bool current_polyline_has_connections_at_both_ends = false;
23231 
23232  // Store the boundary ids of the polylines to connect (only
23233  // used when the polyline was found to have a connection)
23234  // -1: Indicates no connection
23235  // -2: Indicates connection with itself
23236  // -3: Indicates no connection BUT STOP adding elements
23237  // -because the node is a boundary node whose boundary is no
23238  // -currently part of the domain. Think in one of the corner
23239  // -nodes of a triangle touchin a boundary that does no longer
23240  // -exist
23241  // Any other value: Boundary id to connect
23242  int bound_id_connection_to_the_left = -1;
23243  int bound_id_connection_to_the_right = -1;
23244 
23245  // Get the global degree of the node (notice the local degree
23246  // has been updated to global degree)
23247  const unsigned initial_node_degree =
23248  global_node_degree[initial_node_pt];
23249 
23250  // Flag to indicate we are calling the method from a load
23251  // balance sub-rutine
23252  const bool called_for_load_balance=true;
23253 
23254  // Check if the nodes of the root element have connections
23255  // ... to the left
23256  bound_id_connection_to_the_left =
23257  this->check_connections_of_polyline_nodes(
23258  element_in_processor_pt,
23259  root_edge_bound_id,
23260  overlapped_edge,
23261  node_on_bnd_not_overlapped_by_shd_bnd,
23262  tmp_sorted_nodes_pt,
23263  local_shd_bnd_id_to_sorted_list_node_pt,
23264  initial_node_degree,
23265  initial_node_pt,
23266  called_for_load_balance);
23267 
23268  // If there is a stop condition then set the corresponding
23269  // flag
23270  if (bound_id_connection_to_the_left != -1)
23271  {
23272  connection_to_the_left = true;
23273  } // if (bound_id_connection_to_the_left != -1)
23274 
23275  // Get the global degree of the node (notice the local degree
23276  // has been updated to global degree)
23277  const unsigned final_node_degree =
23278  global_node_degree[final_node_pt];
23279 
23280  // ... and to the right
23281  bound_id_connection_to_the_right =
23282  this->check_connections_of_polyline_nodes(
23283  element_in_processor_pt,
23284  root_edge_bound_id,
23285  overlapped_edge,
23286  node_on_bnd_not_overlapped_by_shd_bnd,
23287  tmp_sorted_nodes_pt,
23288  local_shd_bnd_id_to_sorted_list_node_pt,
23289  final_node_degree,
23290  final_node_pt,
23291  called_for_load_balance);
23292 
23293  // If there is a stop condition then set the corresponding
23294  // flag
23295  if (bound_id_connection_to_the_right != -1)
23296  {
23297  connection_to_the_right = true;
23298  } // if (bound_id_connection_to_the_right != -1)
23299 
23300  // If the current shared boundary has connections at both ends
23301  // then stop the adding of elements (and nodes)
23302  if (connection_to_the_left && connection_to_the_right)
23303  {current_polyline_has_connections_at_both_ends = true;}
23304 
23305  // Continue searching for more elements to add if
23306  // 1) A new element was added at the left or right of the list
23307  // 2) There are more possible elements to add
23308  // 3) The nodes at the edges of the added element (left or
23309  // right) are not part of any other previous shared
23310  // boundary
23311  while(new_element_added &&
23312  (nsorted_face_ele < nunsorted_face_ele)
23313  && !current_polyline_has_connections_at_both_ends)
23314  {
23315  // Loop over the remaining elements and try to create a
23316  // contiguous set of face elements, start looking from the
23317  // root index. Any previous element should have been already
23318  // visited
23319  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23320  {
23321  // Reset the flags for added elements, to the left and right
23322  new_element_added = false;
23323  element_added_to_the_left = false;
23324  element_added_to_the_right = false;
23325 
23326  // Get the "e"-th element on the vector
23327  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23328  // Get the boundary id associated with the edge (if any)
23329  const int edge_bound_id = edge_boundary[iproc][e];
23330  // Check if the element has been already sorted and the
23331  // related edge bound id is the same as the root edge (if
23332  // any)
23333  if (!done_ele[tmp_ele_pt]
23334  && (edge_bound_id == root_edge_bound_id))
23335  {
23336  // Get the number of nodes on the current element
23337  const unsigned nnodes = tmp_ele_pt->nnode();
23338  // Get the first and last node of the element
23339  // Check if the face element should be treated as inverted
23340  Node* first_node_pt = 0;
23341  Node* last_node_pt = 0;
23342  if (!treat_as_inverted[iproc][e])
23343  {
23344  first_node_pt = tmp_ele_pt->node_pt(0);
23345  last_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23346  }
23347  else
23348  {
23349  first_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23350  last_node_pt = tmp_ele_pt->node_pt(0);
23351  }
23352 
23353  // A pointer to the node at the left or right of the
23354  // just added element, the most left or the most right
23355  // node
23356  Node* new_added_node_pt = 0;
23357 
23358  // Check if the element goes to the left
23359  if (initial_node_pt == last_node_pt &&
23360  !connection_to_the_left)
23361  {
23362  // Update the initial node and the just added node
23363  new_added_node_pt = initial_node_pt = first_node_pt;
23364  // Add the most left node
23365  tmp_sorted_nodes_pt.push_front(first_node_pt);
23366  // Add the face element to the list of sorted face
23367  // elements
23368  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23369  // Add the bulk element to the list of sorted elements
23370  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23371  // Add the face index to the list of sorted face index
23372  // elements
23373  tmp_sorted_face_index_ele.push_front(
23374  unsorted_face_index_ele[iproc][e]);
23375  if (!treat_as_inverted[iproc][e])
23376  {
23377  // Mark the element as not inverted
23378  is_inverted[tmp_ele_pt] = false;
23379  }
23380  else
23381  {
23382  // Mark the element as inverted
23383  is_inverted[tmp_ele_pt] = true;
23384  }
23385  // Set the flag to indicate a new element was added
23386  new_element_added = true;
23387  // Set the flag to indicate the element was added to
23388  // the left
23389  element_added_to_the_left = true;
23390  }
23391  // Check if the element goes to the left (but inverted)
23392  else if (initial_node_pt == first_node_pt &&
23393  !connection_to_the_left)
23394  {
23395  // Update the initial node and the just added node
23396  new_added_node_pt = initial_node_pt = last_node_pt;
23397  // Add the most left node
23398  tmp_sorted_nodes_pt.push_front(last_node_pt);
23399  // Add the face element to the list of sorted face
23400  // elements
23401  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23402  // Add the bulk element to the list of sorted elements
23403  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23404  // Add the face index to the list of sorted face index
23405  // elements
23406  tmp_sorted_face_index_ele.push_front(
23407  unsorted_face_index_ele[iproc][e]);
23408  if (!treat_as_inverted[iproc][e])
23409  {
23410  // Mark the element as inverted
23411  is_inverted[tmp_ele_pt] = true;
23412  }
23413  else
23414  {
23415  // Mark the element as not inverted
23416  is_inverted[tmp_ele_pt] = false;
23417  }
23418  // Set the flag to indicate a new element was added
23419  new_element_added = true;
23420  // Set the flag to indicate the element was added to
23421  // the left
23422  element_added_to_the_left = true;
23423  }
23424  // Check if the elements goes to the right
23425  else if (final_node_pt == first_node_pt
23426  && !connection_to_the_right)
23427  {
23428  // Update the final node and the just added node
23429  new_added_node_pt = final_node_pt = last_node_pt;
23430  // Add the most right node
23431  tmp_sorted_nodes_pt.push_back(last_node_pt);
23432  // Add the face element to the list of sorted face
23433  // elements
23434  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23435  // Add the bulk element to the list of sorted elements
23436  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23437  // Add the face index to the list of sorted face index
23438  // elements
23439  tmp_sorted_face_index_ele.push_back(
23440  unsorted_face_index_ele[iproc][e]);
23441  if (!treat_as_inverted[iproc][e])
23442  {
23443  // Mark the element as not inverted
23444  is_inverted[tmp_ele_pt] = false;
23445  }
23446  else
23447  {
23448  // Mark the element as inverted
23449  is_inverted[tmp_ele_pt] = true;
23450  }
23451  // Set the flag to indicate a new element was added
23452  new_element_added = true;
23453  // Set the flag to indicate the element was added to
23454  // the right
23455  element_added_to_the_right = true;
23456  }
23457  // Check if the elements goes to the right (but inverted)
23458  else if (final_node_pt == last_node_pt &&
23459  !connection_to_the_right)
23460  {
23461  // Update the final node and the just added node
23462  new_added_node_pt = final_node_pt = first_node_pt;
23463  // Add the most right node
23464  tmp_sorted_nodes_pt.push_back(first_node_pt);
23465  // Add the face element to the list of sorted face
23466  // elements
23467  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23468  // Add the bulk element to the list of sorted elements
23469  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23470  // Add the face index to the list of sorted face index
23471  // elements
23472  tmp_sorted_face_index_ele.push_back(
23473  unsorted_face_index_ele[iproc][e]);
23474  if (!treat_as_inverted[iproc][e])
23475  {
23476  // Mark the element as inverted
23477  is_inverted[tmp_ele_pt] = true;
23478  }
23479  else
23480  {
23481  // Mark the element as not inverted
23482  is_inverted[tmp_ele_pt] = false;
23483  }
23484  // Set the flag to indicate a new elements was added
23485  new_element_added = true;
23486  // Set the flag to indicate the element was added to
23487  // the right
23488  element_added_to_the_right = true;
23489  }
23490 
23491  // Do additional stuff if the element was added
23492  if (new_element_added)
23493  {
23494  // Mark the element as done
23495  done_ele[tmp_ele_pt] = true;
23496  // Increase the counter for sorted face elements
23497  nsorted_face_ele++;
23498 
23499  // Get the global degree of the node (notice the
23500  // local degree has been updated to global degree)
23501  const unsigned new_added_node_degree =
23502  global_node_degree[new_added_node_pt];
23503 
23504  // Based on which side the element was added, look for
23505  // connections on that side
23506 
23507  // Verify for connections to the left (we need to
23508  // check for the connection variable too, since
23509  // after a connection has been done we no longer
23510  // need to verify for this condition)
23511  if (element_added_to_the_left && !connection_to_the_left)
23512  {
23513  // Check for connection
23514  bound_id_connection_to_the_left =
23515  this->check_connections_of_polyline_nodes(
23516  element_in_processor_pt,
23517  root_edge_bound_id,
23518  overlapped_edge,
23519  node_on_bnd_not_overlapped_by_shd_bnd,
23520  tmp_sorted_nodes_pt,
23521  local_shd_bnd_id_to_sorted_list_node_pt,
23522  new_added_node_degree,
23523  new_added_node_pt,
23524  called_for_load_balance);
23525 
23526  // If there is a stop condition then set the
23527  // corresponding flag
23528  if (bound_id_connection_to_the_left != -1)
23529  {
23530  connection_to_the_left = true;
23531  } // if (bound_id_connection_to_the_left != -1)
23532 
23533  } // if (node_added_to_the_left &&
23534  // !connection_to_the_left)
23535 
23536  // Verify for connections to the right (we need to
23537  // check for the connection variable too, since
23538  // after a connection has been done we no longer
23539  // need to verify for this condition)
23540  if (element_added_to_the_right && !connection_to_the_right)
23541  {
23542  // Check for connection
23543  bound_id_connection_to_the_right =
23544  this->check_connections_of_polyline_nodes(
23545  element_in_processor_pt,
23546  root_edge_bound_id,
23547  overlapped_edge,
23548  node_on_bnd_not_overlapped_by_shd_bnd,
23549  tmp_sorted_nodes_pt,
23550  local_shd_bnd_id_to_sorted_list_node_pt,
23551  new_added_node_degree,
23552  new_added_node_pt,
23553  called_for_load_balance);
23554 
23555  // If there is a stop condition then set the
23556  // corresponding flag
23557  if (bound_id_connection_to_the_right != -1)
23558  {
23559  connection_to_the_right = true;
23560  } // if (bound_id_connection_to_the_right != -1)
23561 
23562  } // if (node_added_to_the_right &&
23563  // !connection_to_the_right)
23564 
23565  // If the current shared boundary has connections at
23566  // both ends then stop the adding of elements (and
23567  // nodes)
23568  if (connection_to_the_left && connection_to_the_right)
23569  {current_polyline_has_connections_at_both_ends = true;}
23570 
23571  // Break the for (looping over unsorted face
23572  // elements) and re-start looking for more elements
23573  // that fit to the left or right
23574  break;
23575 
23576  } // if (new_element_added)
23577 
23578  } // if (!done_ele[tmp_ele_pt])
23579 
23580  } // for (e < nunsorted_face_ele)
23581 
23582  } // while(new_element_added &&
23583  // (nsorted_face_ele < nunsorted_face_ele)
23584  // && !current_polyline_has_connections_at_both_ends)
23585 
23586  // ------------------------------------------------------------
23587  // Before assigning a local shared boundary id to the list of
23588  // nodes and boundary elements, check for any loop that the
23589  // shared boundary may be creating
23590 
23591  // The vector of the elements
23592  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23593  // Store the list of elements on a vector of elements
23594  for (std::list<FiniteElement*>::iterator it =
23595  tmp_sorted_ele_pt.begin(); it != tmp_sorted_ele_pt.end(); it++)
23596  {
23597  tmp_vector_sorted_ele_pt.push_back((*it));
23598  }
23599 
23600  // The vector of the face elements
23601  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23602  // Store the list of face elements on a vector of face
23603  // elements
23604  for (std::list<FiniteElement*>::iterator it =
23605  tmp_sorted_face_ele_pt.begin();
23606  it != tmp_sorted_face_ele_pt.end(); it++)
23607  {
23608  tmp_vector_sorted_face_ele_pt.push_back((*it));
23609  }
23610 
23611  // The vector of the face indexes
23612  Vector<int> tmp_vector_sorted_face_index_ele;
23613  // Store the list of elements on a vector of elements
23614  for (std::list<int>::iterator it =
23615  tmp_sorted_face_index_ele.begin();
23616  it != tmp_sorted_face_index_ele.end(); it++)
23617  {
23618  tmp_vector_sorted_face_index_ele.push_back((*it));
23619  }
23620 
23621  // Store the nodes for the new shared polylines without loops
23622  Vector<std::list<Node*> > final_sorted_nodes_pt;
23623  // Store the boundary elements of the shared polyline without
23624  // loops
23625  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
23626  // Store the boundary face elements of the shared polyline
23627  // without loops
23628  Vector<Vector<FiniteElement*> > final_boundary_face_element_pt;
23629  // Face indexes of the boundary elements without loops
23630  Vector<Vector<int> > final_face_index_element;
23631  // Connection flags (to the left) of the shared boundaries
23632  // without loops
23633  Vector<int> final_bound_id_connection_to_the_left;
23634  // Connection flags (to the right) of the shared boundaries
23635  // without loops
23636  Vector<int> final_bound_id_connection_to_the_right;
23637 
23638  // Break any possible loop created by the shared polyline
23639  this->break_loops_on_shared_polyline_load_balance_helper(
23640  local_shd_bnd_id,
23641  tmp_sorted_nodes_pt,
23642  tmp_vector_sorted_ele_pt,
23643  tmp_vector_sorted_face_ele_pt, tmp_vector_sorted_face_index_ele,
23644  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
23645  final_sorted_nodes_pt,
23646  final_boundary_element_pt,
23647  final_boundary_face_element_pt, final_face_index_element,
23648  final_bound_id_connection_to_the_left,
23649  final_bound_id_connection_to_the_right);
23650 
23651  // Get the number of final sorted nodes
23652  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23653 
23654  // Loop over the list of final sorted nodes
23655  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23656  {
23657  // Store the list of nodes that gave rise to the shared
23658  // boundary
23659  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23660  final_sorted_nodes_pt[i];
23661 
23662  // Store the local shared boundary id assigned to the
23663  // elements that will create the shared boundary
23664  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23665 
23666  // Increase the shared boundary id (note that this is only
23667  // used to keep track of the list of nodes that create the
23668  // shared boundaries in the current processor)
23669  local_shd_bnd_id++;
23670 
23671  // Include the vector of elements to the sorted vector
23672  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23673 
23674  // Include the vector of face elements to the sorted vector
23675  sorted_face_ele_pt[iproc].
23676  push_back(final_boundary_face_element_pt[i]);
23677 
23678  // Include the vector of elements to the sorted vector
23679  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23680 
23681  // Include the possible associated boundary id to the vector
23682  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23683 
23684  // Include the connection information associated with the
23685  // current set of face elements (that will give rise to a
23686  // shared polyline
23687  // The temporal storage for the boundary connections ids
23688  Vector<int> bnd_connections_ids(2);
23689  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23690  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23691  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23692 
23693  } // for (i < n_final_sorted_nodes)
23694 
23695  } // while (nsorted_face_ele < nunsorted_face_ele)
23696 
23697  } // if (iproc != my_rank)
23698 
23699  } // for (iproc < nproc)
23700 
23701  // The time to sort shared boundaries face elements to create a
23702  // continuous representation of the boundary
23703  if (Print_timings_level_load_balance>2)
23704  {
23705  oomph_info << "CPU for joining shared boundary face elements (load balance) [9.5]: "
23706  <<TimingHelpers::timer()-tt_start_join_shd_bnd_face_ele
23707  << std::endl;
23708  }
23709 
23710  // ==================================================================
23711  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23712  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23713  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23714  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23715  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23716  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23717  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23718  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23719  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23720  // ==================================================================
23721 
23722  // ==================================================================
23723  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23724  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23725  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23726  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23727  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23728  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23729  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23730  // ALSO COMPUTED
23731  // ==================================================================
23732 
23733  // Get the time to compute new shared boundaries ids
23734  double tt_start_get_new_shared_boundaries_ids=0.0;
23735  if (Print_timings_level_load_balance>2)
23736  {
23737  tt_start_get_new_shared_boundaries_ids=TimingHelpers::timer();
23738  }
23739 
23740  // Get the number of shared boundaries with in each processor
23741  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23742  // Loop over the processors
23743  for (unsigned iproc = 0; iproc < nproc; iproc++)
23744  {
23745  // No shared boundaries with myself
23746  if (iproc != my_rank)
23747  {
23748  // Store the number of shared boundaries of the current
23749  // processor (my_rank) with the iproc processor
23750  nshared_boundaries_with_processor[iproc] =
23751  sorted_face_ele_pt[iproc].size();
23752 
23753  } // if (iproc != my_rank)
23754 
23755  } // for (iproc < nproc)
23756 
23757  // Each processor sends the number of shared boundaries that it has
23758  // with in each other processor to the "root_processor" which will
23759  // be in charge of checking and computing the global shared
23760  // boundaries ids
23761  const unsigned root_processor = 0;
23762 
23763  // Get the communicator of the mesh
23764  OomphCommunicator* comm_pt = this->communicator_pt();
23765 
23766  // Container where to store the info. received from other processor
23767  // in root. It receives from all processors the number of shared
23768  // boundaries that each one has with any other processor
23769  Vector<unsigned> flat_unsigned_root_received_data(nproc*nproc);
23770 
23771  // Gather the info. in the "root_processor"
23772  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
23773  // each processor
23774  nproc, // Total number of data to send from each
23775  // processor
23776  MPI_UNSIGNED,
23777  &flat_unsigned_root_received_data[0], // Container where
23778  // to receive the
23779  // info. from all
23780  // the processors
23781  nproc, // Number of data to receive from each processor
23782  MPI_UNSIGNED,
23783  root_processor, // The processor that receives all the
23784  // info.
23785  comm_pt->mpi_comm());
23786 
23787  // Container where root store the info. that will be sent back to
23788  // all processor, because root performs a Broadcast operation then
23789  // the info. is received in the same container
23790  Vector<unsigned> flat_unsigned_root_send_receive_data;
23791 
23792  // Compute the new initial and final shared boundary id (they are
23793  // based on the global number of shared boundaries)
23794  unsigned new_initial_shared_boundary_id = 0;
23795  unsigned new_final_shared_boundary_id = 0;
23796 
23797  // Compute the boundaries ids for the shared boundaries
23798  if (my_rank == root_processor)
23799  {
23800  // Change the representation of the data received from all
23801  // processors to a matrix representation for ease access
23802  Vector<Vector<unsigned> > root_nshared_bound_proc_with_proc(nproc);
23803  // Loop over the processors and get the number of shared
23804  // boundaries of processor iproc with jproc
23805  for (unsigned iproc = 0; iproc < nproc; iproc++)
23806  {
23807  // Resize the vector to store the data
23808  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
23809  // Loop over the processors and get the number of shared
23810  // boundaries of processor iproc with jproc
23811  for (unsigned jproc = 0; jproc < nproc; jproc++)
23812  {
23813  root_nshared_bound_proc_with_proc[iproc][jproc] =
23814  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
23815 
23816  } // for (jproc < nproc)
23817 
23818  } // for (iproc < nproc)
23819 
23820 #ifdef PARANOID
23821  // Check that the same number of boundaries are shared by two
23822  // specific processors
23823  for (unsigned iproc = 0; iproc < nproc; iproc++)
23824  {
23825  for (unsigned jproc = 0; jproc < iproc; jproc++)
23826  {
23827  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
23828  root_nshared_bound_proc_with_proc[jproc][iproc])
23829  {
23830  std::ostringstream error_stream;
23831  error_stream
23832  << "ROOT PROCESSOR ERROR\n\n"
23833  << "The number of shared boundaries between processor ("
23834  << iproc << ") and (" << jproc << ") is not the same:\n"
23835  << "Shared boundaries of processor (" << iproc
23836  << ") with processor (" << jproc << "): ("
23837  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
23838  << "Shared boundaries of processor (" << jproc
23839  << ") with processor (" << iproc << "): ("
23840  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
23841  throw OomphLibError(error_stream.str(),
23842  OOMPH_CURRENT_FUNCTION,
23843  OOMPH_EXCEPTION_LOCATION);
23844 
23845  } // The number of shared boundaries between processors
23846  // "iproc" and "jproc" is not the same
23847 
23848  } // for (jproc < iproc)
23849 
23850  } // for (iproc < nproc)
23851 #endif
23852 
23853  // The enumeration of the shared boundaries starts from the lowest
23854  // processor number to the highest processor number
23855 
23856  // Two processors share the same boundaries ids, the lowest
23857  // processor number is the one in charge of computing the shared
23858  // boundaries ids
23859  Vector<Vector<unsigned> > start_shared_bound_id_proc_with_proc(nproc);
23860  // Resize the vector, we can not do it when storing the
23861  // info. because of the strategy to save the info.
23862  for (unsigned iproc = 0; iproc < nproc; iproc++)
23863  {start_shared_bound_id_proc_with_proc[iproc].resize(nproc);}
23864 
23865  // The shared boundaries ids start from the current number of
23866  // original boundaries
23867  unsigned shared_bound_id = this->nboundary();
23868 
23869  // Set the new initial shared boundary id
23870  new_initial_shared_boundary_id = shared_bound_id;
23871 
23872  // Assign the global shared boundary id for the shared boundaries
23873  for (unsigned iproc = 0; iproc < nproc; iproc++)
23874  {
23875  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
23876  {
23877  // Are there shared boundaries between the pair of processors
23878  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23879  {
23880  // Set the start boundary id of processor "iproc" with
23881  // processor "jproc" and viceversa
23882  start_shared_bound_id_proc_with_proc[iproc][jproc] = shared_bound_id;
23883  start_shared_bound_id_proc_with_proc[jproc][iproc] = shared_bound_id;
23884  // Increase the shared boundary id counter with as many
23885  // shared boundaries there are between the iproc and jproc
23886  // processor
23887  shared_bound_id+= root_nshared_bound_proc_with_proc[iproc][jproc];
23888  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23889 
23890  } // for (jproc < iproc)
23891 
23892  } // for (iproc < nproc)
23893 
23894  // Set the new final shared boundary id
23895  new_final_shared_boundary_id = shared_bound_id;
23896 
23897  // Prepare the info. to send back to each processor
23898  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc*nproc);
23899 
23900  // Copy the info. to the storage to send the info. back to other
23901  // processors
23902  for (unsigned iproc = 0; iproc < nproc; iproc++)
23903  {
23904  for (unsigned jproc = 0; jproc < nproc; jproc++)
23905  {
23906  // Get the initial shared boundary id between each pair of
23907  // processors (iproc, jproc)
23908  const unsigned initial_shd_bnd_id =
23909  start_shared_bound_id_proc_with_proc[iproc][jproc];
23910  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
23911 
23912  // .. then copy the number of shared boundaries that there are
23913  // between processor iproc and jproc
23914  const unsigned nshared_bnd_iproc_jproc =
23915  root_nshared_bound_proc_with_proc[iproc][jproc];
23916  flat_unsigned_root_send_receive_data.push_back(nshared_bnd_iproc_jproc);
23917 
23918  } // for (jproc < nproc)
23919 
23920  } // for (iproc < nproc)
23921 
23922  // .. at the end of the data to send include the global initial
23923  // shared boundary id
23924  flat_unsigned_root_send_receive_data.
23925  push_back(new_initial_shared_boundary_id);
23926 
23927  // ... and the global final shared boundary id
23928  flat_unsigned_root_send_receive_data.
23929  push_back(new_final_shared_boundary_id);
23930 
23931  } // if (my_rank == root_processor)
23932 
23933  // Send the initial shared boundaries ids and the number of shared
23934  // boundaries between all procesors to all processors. All
23935  // processors need to know this info.
23936 
23937  // The number of data that will be sent by root to other processors
23938  // and the number of data that other processors receive from root,
23939  // it is the same because it is performed via a Broadcast
23940  unsigned root_ndata_sent_to_all_proc =
23941  flat_unsigned_root_send_receive_data.size();
23942 
23943  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
23944  1, MPI_UNSIGNED, root_processor,
23945  comm_pt->mpi_comm());
23946 
23947  // Resize the container if this is a processor that receives data
23948  if (my_rank != root_processor)
23949  {
23950  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
23951  }
23952 
23953  // Send back the start boundaries ids for the shared boundaries
23954  // Scatter the info. from the "root_processor"
23955  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
23956  // each
23957  // processor
23958  root_ndata_sent_to_all_proc, // Total number of data to
23959  // send to each processor
23960  MPI_UNSIGNED,
23961  root_processor, // The processor that sends all the info.
23962  comm_pt->mpi_comm());
23963 
23964  // The container to store the initial shared boundaries ids between
23965  // each pair of processors
23966  Vector<Vector<unsigned> > initial_shared_bound_id_proc_with_proc(nproc);
23967 
23968  // All processors need to know how many shared boundaries there are
23969  // between each pair of processors
23970 
23971  // The number of shared boundaries between each pair of processors
23972  Vector<Vector<unsigned> > nshared_bound_proc_with_proc(nproc);
23973 
23974  unsigned iflat_counter = 0;
23975  // Fill the containers with the received info. from root processor
23976  for (unsigned iproc = 0; iproc < nproc; iproc++)
23977  {
23978  // Resize the containers
23979  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
23980  nshared_bound_proc_with_proc[iproc].resize(nproc);
23981 
23982  // Loop over the processors
23983  for (unsigned jproc = 0; jproc < nproc; jproc++)
23984  {
23985  // Get the initial shared boundary id between each pair of
23986  // processors (iproc, jproc)
23987  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
23988  flat_unsigned_root_send_receive_data[iflat_counter++];
23989 
23990  // .. and copy the number of shared boundaries that there are
23991  // between processor iproc and jproc
23992  nshared_bound_proc_with_proc[iproc][jproc] =
23993  flat_unsigned_root_send_receive_data[iflat_counter++];
23994 
23995  } // for (jproc < nproc)
23996 
23997  } // for (iproc < nproc)
23998 
23999  // Read the new initial shared boundary id
24000  new_initial_shared_boundary_id =
24001  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-2];
24002 
24003  // Read the new final shared boundary id
24004  new_final_shared_boundary_id =
24005  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-1];
24006 
24007  // The time to compute new shared boundaries ids
24008  if (Print_timings_level_load_balance>2)
24009  {
24010  oomph_info << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24011  <<TimingHelpers::timer()-tt_start_get_new_shared_boundaries_ids
24012  << std::endl;
24013  }
24014 
24015  // ==================================================================
24016  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24017  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24018  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24019  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24020  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24021  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24022  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24023  // ==================================================================
24024 
24025  // ==================================================================
24026  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24027  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24028  // SHARED BOUNDARIES INFO.
24029  // ==================================================================
24030 
24031  // Get the time to create new shared boundaries representations
24032  double tt_start_create_new_shared_boundaries_polylines=0.0;
24033  if (Print_timings_level_load_balance>2)
24034  {
24035  tt_start_create_new_shared_boundaries_polylines=TimingHelpers::timer();
24036  }
24037 
24038  // Create the shared boundaries and establish all the related info.
24039  // - Create Polylines
24040  // - Store shared boundary elements
24041  // - Fill data structures to know which shared boundaries belong to
24042  // which processor
24043 
24044  // Resize the shared polylines container
24045  this->flush_shared_boundary_polyline_pt();
24046  this->Shared_boundary_polyline_pt.resize(nproc);
24047 
24048  // Resize for the boundaries ids shared with all processors
24049  this->Shared_boundaries_ids.clear();
24050  this->Shared_boundaries_ids.resize(nproc);
24051  for (unsigned iproc = 0; iproc < nproc; iproc++)
24052  {
24053  this->Shared_boundaries_ids[iproc].clear();
24054  this->Shared_boundaries_ids[iproc].resize(nproc);
24055  } // for (iproc < nproc)
24056 
24057  // Clear data
24058  this->Shared_boundary_from_processors.clear();
24059  this->Shared_boundary_overlaps_internal_boundary.clear();
24060  this->Boundary_was_splitted.clear();
24061  this->Boundary_subpolylines.clear();
24062  this->Boundary_marked_as_shared_boundary.clear();
24063 
24064  // Flush data
24065  this->flush_shared_boundary_element();
24066  this->flush_face_index_at_shared_boundary();
24067  this->flush_shared_boundary_node();
24068  this->flush_sorted_shared_boundary_node();
24069 
24070  // Store the old local inital shared boundary id (used to map from
24071  // local shared boundary id to global shared boundary id)
24072  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24073 
24074  // Update the initial and final shared boundary id
24075  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24076  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24077 
24078  // Storage for the new created polylines between the current
24079  // processor (my_rank) and the other processors, unsorted polylines
24080  Vector<TriangleMeshPolyLine *> unsorted_polylines_pt;
24081 
24082  // Map to get the global shared boundary id from the local shared
24083  // boundary id. Note that this is only used to get the global shared
24084  // boundary id when the shared boundary that is being created has
24085  // connections
24086  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24087 
24088  // Each processor knows the boundaries ids for each of the shared
24089  // boundaries it has, establish that info. in the proper containers
24090  // Additionally, store the shared boundaries of ALL processors with
24091  // ALL processors, but only create the shared boundaries (and their
24092  // respective polylines) of the current processor (my_rank)
24093  for (unsigned iproc = 0; iproc < nproc; iproc++)
24094  {
24095  // Avoid creating double shared boundaries, the shared boundaries
24096  // created between processor "iproc" and processor "jproc" are the
24097  // same than those created between processor "jproc" and processor
24098  // "iproc"
24099  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24100  {
24101  // If we are working with the current processor (my_rank) then
24102  // create the shared boundaries, if that is not the case then
24103  // only fill the info. on the proper containers
24104  if (iproc == my_rank || jproc == my_rank)
24105  {
24106  // Check the condition that made it get here
24107  unsigned ref_proc = 0;
24108  if (iproc == my_rank)
24109  {ref_proc = jproc;}
24110  else if (jproc == my_rank)
24111  {ref_proc = iproc;}
24112 
24113  // Get the number of shared boundaries between processor iproc
24114  // and processor jproc
24115  const unsigned nshared_bound_iproc_jproc =
24116  nshared_bound_proc_with_proc[iproc][jproc];
24117 
24118  // Loop over the number of shared boundaries
24119  for (unsigned counter = 0;
24120  counter < nshared_bound_iproc_jproc;
24121  counter++)
24122  {
24123  // Compute the shared boundary id for the shared boundary
24124  const unsigned shd_bnd_id =
24125  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24126  // Set up the shared boundaries between "iproc" (my_rank)
24127  // and "jproc"
24128  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24129  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24130 
24131  // Specify the processors involved for the creation of the
24132  // shared boundary
24133  Vector<unsigned> processors(2);
24134  processors[0] = iproc;
24135  processors[1] = jproc;
24136  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24137 
24138  // Get the possible root edge id associated to the shared
24139  // boundary (useful when the shared boundary overlaps an
24140  // original boundary)
24141  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24142  // Check if the shared boundary is overlapping (or is part)
24143  // of an internal boundary
24144  if (root_edge_bound_id != -1)
24145  {
24146  // If the shared boundary is part of an internal boundary then
24147  // mark the shared boundary
24148  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24149  static_cast<unsigned>(root_edge_bound_id);
24150  } // if (root_edge_bound_id != -1)
24151 
24152  // Storing for the nodes of the polyline (these are different
24153  // from the nodes on the face elements -- it is actually a
24154  // sub-set -- since the polyline is created from the first and
24155  // last nodes on the face elements)
24156  Vector<Node*> node_pt_to_create_shared_polyline;
24157 
24158  // Add the first node for the very first face element. In
24159  // the loop we will only add the last node of the face
24160  // element
24161  FiniteElement* first_face_ele_pt =
24162  sorted_face_ele_pt[ref_proc][counter][0];
24163 
24164  // Get the number of nodes on the first face element
24165  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24166  if (!is_inverted[first_face_ele_pt])
24167  {
24168  // Get the first node
24169  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24170  // Add the node to create the polyline
24171  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24172  // Add the first node to the shared boundary
24173  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24174  }
24175  else
24176  {
24177  // Get the first node in the inverted face element
24178  Node* first_node_pt =
24179  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24180  // Add the node to create the polyline
24181  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24182  // Add the first node to the shared boundary
24183  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24184  }
24185 
24186  // ... and extract only the last nodes of the face elements
24187  // in the next loop and add them in the vector of nodes to
24188  // create polylines (node_pt_to_create_shared_polyline)
24189 
24190  // Get the number of elements
24191  const unsigned nshared_boundary_elements =
24192  sorted_face_ele_pt[ref_proc][counter].size();
24193 
24194  // Store the shared boundary elements, nodes and get the
24195  // sorted nodes to create the polyline
24196  for (unsigned ie = 0 ; ie < nshared_boundary_elements; ie++)
24197  {
24198  // Get the bulk element version of the face element
24199  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24200 
24201  // Add the shared boundary element and associate it to the
24202  // "shd_bnd_id"
24203  this->add_shared_boundary_element(shd_bnd_id,
24204  bulk_ele_pt);
24205 
24206  // Get the face index from which the face element was
24207  // created from the bulk element
24208  const int face_index =
24209  sorted_face_index_ele[ref_proc][counter][ie];
24210 
24211  // Add the face index to the face indexes of the shared
24212  // boundary
24213  this->add_face_index_at_shared_boundary(shd_bnd_id,
24214  face_index);
24215 
24216  // Get the face element to obtain the last node
24217  FiniteElement* face_ele_pt =
24218  sorted_face_ele_pt[ref_proc][counter][ie];
24219 
24220  // Get the number of nodes
24221  const unsigned nnodes = face_ele_pt->nnode();
24222  if (!is_inverted[face_ele_pt])
24223  {
24224  // We have already added the first node, then start from
24225  // the second one
24226  for (unsigned n = 1; n < nnodes; n++)
24227  {
24228  // Get the node to be added
24229  Node* node_pt = face_ele_pt->node_pt(n);
24230  // Add the node and associate it to the shared boundary
24231  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24232  } // for (n < nnodes)
24233 
24234  // Add the last node of the face element to the vector of
24235  // nodes to create the polyline
24236  // Get the last node
24237  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24238  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24239  } // if (!is_inverted[face_ele_pt])
24240  else
24241  {
24242  // We have already added the first node, then start from
24243  // the second one (in reverse order)
24244  for (int n = nnodes-2; n >= 0; n--)
24245  {
24246  // Get the node to be added
24247  Node* node_pt = face_ele_pt->node_pt(n);
24248  // Add the node and associate it to the shared boundary
24249  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24250  } // for (n < nnodes)
24251 
24252  // Add the last node of the face element to the vector of
24253  // nodes to create the polyline
24254  // Get the last node
24255  Node* last_node_pt = face_ele_pt->node_pt(0);
24256  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24257 
24258  } // else if (!is_inverted[face_ele_pt])
24259 
24260  } // for (ie < nshared_boundary_elements)
24261 
24262  // The number of nodes for the shared boundary polyline
24263  const unsigned nnodes_to_create_shared_boundary =
24264  node_pt_to_create_shared_polyline.size();
24265 
24266  // Get the vertices that create the shared boundary polyline
24267  Vector<Vector<double> > vertices(nnodes_to_create_shared_boundary);
24268  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24269  {
24270  vertices[n].resize(2);
24271  // Get the node
24272  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24273  // Get the vertices
24274  vertices[n][0] = tmp_node_pt->x(0);
24275  vertices[n][1] = tmp_node_pt->x(1);
24276  } // for (n < nnodes_to_create_shared_boundary)
24277 
24278  // Create the polyline
24279  TriangleMeshPolyLine *polyline_pt =
24280  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24281 
24282  // Updates bnd_id<--->curve section map
24283  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24284 
24285  // Add the new created polyline to the list of unsorted
24286  // polylines
24287  unsorted_polylines_pt.push_back(polyline_pt);
24288 
24289  // Mark the polyline for deletion (when calling destructor)
24290  this->Free_curve_section_pt.insert(polyline_pt);
24291 
24292  // Now assign the connection information
24293  // ---------------------------------------------------------
24294  // Get the local shared boundary id associated to the
24295  // elements that gave rise to this shared boundary
24296  const unsigned local_shd_bnd_id =
24297  proc_local_shared_boundary_id[ref_proc][counter];
24298 
24299  // Associate the local shared boundary to the global shared
24300  // boundary
24301  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24302 
24303  // Get the correct shared boundaries ids, from the local
24304  // shared boundaries ids established at the identification
24305  // of the conections
24306 
24307  // Get the local bnd id for the connection to the left
24308  int tmp_bnd_id_connection_to_the_left =
24309  sorted_connection_info[ref_proc][counter][0];
24310  // Get the local bnd id for the connection to the right
24311  int tmp_bnd_id_connection_to_the_right =
24312  sorted_connection_info[ref_proc][counter][1];
24313 
24314  // The global shared boundaries ids for connections to the
24315  // left or right
24316  int bnd_id_connection_to_the_left = -1;
24317  int bnd_id_connection_to_the_right = -1;
24318 
24319  // To the left
24320  // --------------
24321 
24322  // If the connection is with the same shared boundary then
24323  // set the current boundary id
24324  if (tmp_bnd_id_connection_to_the_left == -2)
24325  {
24326  // Set the current shared boundary id
24327  bnd_id_connection_to_the_left = shd_bnd_id;
24328  } // if (tmp_bnd_id_connection_to_the_left == -2)
24329 
24330  // Check if the connection was a stop adding nodes condition
24331  if (tmp_bnd_id_connection_to_the_left == -3)
24332  {
24333  // Set as no connected
24334  bnd_id_connection_to_the_left = -1;
24335  } // if (tmp_bnd_id_connection_to_the_left == -3)
24336 
24337  // There is a connection with another boundary, check if it
24338  // is a shared boundary or an original boundary
24339  if (tmp_bnd_id_connection_to_the_left >=
24340  static_cast<int>(old_local_shd_bnd_id))
24341  {
24342  // The connection is with a shared boundary, get the
24343  // global shared boundary id and set the connection
24344 #ifdef PARANOID
24345  std::map<unsigned, unsigned>::iterator it =
24346  local_to_global_shd_bnd_id.find(
24347  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24348  // If the global shared boundary id was not found we
24349  // are in trouble
24350  if (it==local_to_global_shd_bnd_id.end())
24351  {
24352  std::stringstream error_message;
24353  error_message
24354  << "The global shared boundary id was not found for\n"
24355  << "the local shared boundary shared with processor ("
24356  << ref_proc <<").\n"
24357  << "This processor: (" << my_rank << ")\n"
24358  << "Boundary shared with processor: (" << ref_proc << ")\n"
24359  << "Local shared boundary: ("
24360  << tmp_bnd_id_connection_to_the_left << ")\n";
24361  throw OomphLibError(error_message.str(),
24362  OOMPH_CURRENT_FUNCTION,
24363  OOMPH_EXCEPTION_LOCATION);
24364  } // if (it==local_to_global_shd_bnd_id.end())
24365 #endif
24366 
24367  // Get the global shared boundary id
24368  bnd_id_connection_to_the_left =
24369  local_to_global_shd_bnd_id[
24370  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left)];
24371 
24372  }
24373  else
24374  {
24375  // The connection is with an original boundary, copy
24376  // the boundary id
24377  bnd_id_connection_to_the_left =
24378  tmp_bnd_id_connection_to_the_left;
24379 
24380  } // else (connection with a shared boundary)
24381 
24382  // To the right
24383  // --------------
24384 
24385  // If the connection is with the same shared boundary then
24386  // set the current boundary id
24387  if (tmp_bnd_id_connection_to_the_right == -2)
24388  {
24389  // Set the current shared boundary id
24390  bnd_id_connection_to_the_right = shd_bnd_id;
24391  } // if (tmp_bnd_id_connection_to_the_right == -2)
24392 
24393  // Check if the connection was a stop adding nodes condition
24394  if (tmp_bnd_id_connection_to_the_right == -3)
24395  {
24396  // Set as no connected
24397  bnd_id_connection_to_the_right = -1;
24398  } // if (tmp_bnd_id_connection_to_the_right == -3)
24399 
24400  // There is a connection with another boundary, check if it
24401  // is a shared boundary or an original boundary
24402  if (tmp_bnd_id_connection_to_the_right >=
24403  static_cast<int>(old_local_shd_bnd_id))
24404  {
24405  // The connection is with a shared boundary, get the
24406  // global shared boundary id and set the connection
24407 #ifdef PARANOID
24408  std::map<unsigned, unsigned>::iterator it =
24409  local_to_global_shd_bnd_id.find(
24410  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24411  // If the global shared boundary id was not found we
24412  // are in trouble
24413  if (it==local_to_global_shd_bnd_id.end())
24414  {
24415  std::stringstream error_message;
24416  error_message
24417  << "The global shared boundary id was not found for\n"
24418  << "the local shared boundary shared with processor ("
24419  << ref_proc <<").\n"
24420  << "This processor: (" << my_rank << ")\n"
24421  << "Boundary shared with processor: (" << ref_proc << ")\n"
24422  << "Local shared boundary: ("
24423  << tmp_bnd_id_connection_to_the_right << ")\n";
24424  throw OomphLibError(error_message.str(),
24425  OOMPH_CURRENT_FUNCTION,
24426  OOMPH_EXCEPTION_LOCATION);
24427  } // if (it==local_to_global_shd_bnd_id.end())
24428 #endif
24429  // Get the global shared boundary id
24430  bnd_id_connection_to_the_right =
24431  local_to_global_shd_bnd_id[
24432  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right)];
24433 
24434  }
24435  else
24436  {
24437  // The connection is with an original boundary, copy the
24438  // boundary id
24439  bnd_id_connection_to_the_right =
24440  tmp_bnd_id_connection_to_the_right;
24441 
24442  } // else (connection with a shared boundary)
24443 
24444  // --------------------------------
24445  // Set the connection to the left
24446  if (bnd_id_connection_to_the_left != -1)
24447  {
24448  // Get the unsigned version of the boundary id to the left
24449  const unsigned ubnd_id_connection_to_the_left =
24450  static_cast<unsigned>(bnd_id_connection_to_the_left);
24451  // Set the initial vertex as connected
24452  polyline_pt->set_initial_vertex_connected();
24453  // Set the initial vertex connected boundary id
24454  polyline_pt->initial_vertex_connected_bnd_id() =
24455  ubnd_id_connection_to_the_left;
24456  // Set the chunk number to zero
24457  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24458 
24459  } // if (bnd_id_connection_to_the_left != -1)
24460 
24461  // ---------------------------------
24462  // Set the connection to the right
24463  if (bnd_id_connection_to_the_right != -1)
24464  {
24465  // Get the unsigned version of the boundary id to the
24466  // right
24467  const unsigned ubnd_id_connection_to_the_right =
24468  static_cast<unsigned>(bnd_id_connection_to_the_right);
24469  // Set the final vertex as connected
24470  polyline_pt->set_final_vertex_connected();
24471  // Set the final vertex connected boundary id
24472  polyline_pt->final_vertex_connected_bnd_id() =
24473  ubnd_id_connection_to_the_right;
24474  // Set the chunk number to zero
24475  polyline_pt->final_vertex_connected_n_chunk() = 0;
24476 
24477  } // if (bnd_id_connection_to_the_right != -1)
24478 
24479  } // for (counter < nshared_bound_iproc_jproc)
24480 
24481  } // if (iproc == my_rank || jproc == my_rank)
24482  else
24483  {
24484  // We are not working with the current processor, then we only
24485  // need to fill the containers
24486 
24487  // Get the number of shared boundaries between processor iproc
24488  // and processor jproc
24489  const unsigned nshared_bound_iproc_jproc =
24490  nshared_bound_proc_with_proc[iproc][jproc];
24491  // Loop over the number of shared boundaries
24492  for (unsigned counter = 0;
24493  counter < nshared_bound_iproc_jproc;
24494  counter++)
24495  {
24496  // Compute the shared boundary id for the shared boundary
24497  const unsigned shd_bnd_id =
24498  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24499 
24500  // Set up the shared boundaries between "iproc" and "jproc"
24501  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24502  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24503 
24504  // Specify the processors involved for the creation of the
24505  // shared boundary
24506  Vector<unsigned> processors(2);
24507  processors[0] = iproc;
24508  processors[1] = jproc;
24509  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24510 
24511  } // for (counter < nshared_bound_iproc_jproc)
24512 
24513  } // else if (iproc == my_rank || jproc == my_rank)
24514 
24515  } // for (jproc < nproc)
24516 
24517  } // for (iproc < nproc)
24518 
24519  // Get the time to create new shared boundaries representations
24520  if (Print_timings_level_load_balance>2)
24521  {
24522  oomph_info << "CPU for creating new shared boundaries representations (load balance) [9.7]: "
24523  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries_polylines
24524  << std::endl;
24525  }
24526 
24527  // ==================================================================
24528  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24529  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24530  // SHARED BOUNDARIES INFO.
24531  // ==================================================================
24532 
24533  // ==================================================================
24534  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24535  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24536  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24537  // ELEMENTS
24538  // ==================================================================
24539 
24540  // Get the time to create the new shared curves
24541  double tt_start_create_new_shared_curves=0.0;
24542  if (Print_timings_level_load_balance>2)
24543  {
24544  tt_start_create_new_shared_curves=TimingHelpers::timer();
24545  }
24546 
24547  // Sort the polylines and find if they create a contiguous open
24548  // curve
24549  if (unsorted_polylines_pt.size() > 0)
24550  {
24551  // Now that we have all the new unsorted polylines on "my_rank"x
24552  // processor it is time to sort them so they be all contiguous
24553  this->sort_polylines_helper(unsorted_polylines_pt,
24554  this->Shared_boundary_polyline_pt[my_rank]);
24555  }
24556 
24557  // Free the memory allocated for the face elements
24558  for (unsigned iproc = 0; iproc < nproc; iproc++)
24559  {
24560  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24561  for (unsigned e = 0; e < nface_ele; e++)
24562  {
24563  delete unsorted_face_ele_pt[iproc][e];
24564  unsorted_face_ele_pt[iproc][e] = 0;
24565  } // for (e < nface_ele)
24566 
24567  } // for (iproc < nproc)
24568 
24569  // The time to create the new shared curves
24570  if (Print_timings_level_load_balance>2)
24571  {
24572  oomph_info << "CPU for creating the new shared curves (load balance) [9.8]: "
24573  <<TimingHelpers::timer()-tt_start_create_new_shared_curves
24574  << std::endl;
24575  }
24576 
24577  // ==================================================================
24578  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24579  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24580  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24581  // ELEMENTS
24582  // ==================================================================
24583 
24584  }
24585 
24586  //======================================================================
24587  // Computes the degree of the nodes on the shared boundaries, the
24588  // degree of the node is computed from the global graph created by the
24589  // shared boundaries of all processors
24590  //======================================================================
24591  template <class ELEMENT>
24594  &unsorted_face_ele_pt,
24595  std::map<Node*, unsigned>
24596  &global_node_degree)
24597  {
24598  // Get the rank and number of processors
24599  const unsigned nproc = this->communicator_pt()->nproc();
24600  const unsigned my_rank = this->communicator_pt()->my_rank();
24601 
24602  // Store a temporary sorting of the nodes, starting from the
24603  // lower-left position
24604  Vector<Vector<Node*> > tmp_sorted_shared_node_pt(nproc);
24605 
24606  // Store the alias of the node, it may be shared by more than two
24607  // processors, they should know that the node is the same
24608  // [0] iproc, processor with which the current processor shared the node
24609  // [1] node #, number of node in the number of nodes shared with iproc
24610  // processor
24611  std::map<Node*, Vector<Vector<unsigned> > > node_alias;
24612 
24613  // Stores the local adjacency matrix
24614  // (nproc*n_shared_nodes*n_shared_nodes)
24615  Vector<Vector<Vector<unsigned> > > local_adjacency_matrix(nproc);
24616 
24617  // Sort the nodes and create the adjacency matrix of each sub-graph
24618  // created by the shared edges
24619  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24620  tmp_sorted_shared_node_pt,
24621  node_alias,
24622  local_adjacency_matrix);
24623 
24624  // Prepare the info. to be sent to the root processor, which will be
24625  // in charge of updating the nodes degree by combining the info. of
24626  // all the processors
24627 
24628  // The flat package with the info. to send to root
24629  Vector<unsigned> package_unsigned_send_data_to_root;
24630 
24631  // Encode the info. that will be sent to the root processor
24632 
24633  // Loop over the temporary sorted nodes between each pair of
24634  // processors
24635  for (unsigned iproc = 0; iproc < nproc; iproc++)
24636  {
24637  // Send the processor index
24638  package_unsigned_send_data_to_root.push_back(iproc);
24639 
24640  // Get the number of nodes shared between the processors
24641  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24642 
24643  // Send the number of nodes shared with the iproc processor
24644  package_unsigned_send_data_to_root.push_back(n_nodes);
24645 
24646  // Loop over the nodes
24647  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24648  {
24649  // Get the node
24650  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24651 
24652  // Get the alias info.
24653  Vector<Vector<unsigned> > alias_node_info = node_alias[shd_node_pt];
24654 
24655  // Get the number of alias for the node
24656  const unsigned n_alias = alias_node_info.size();
24657 
24658  // Send the number of alias assigned to the node
24659  package_unsigned_send_data_to_root.push_back(n_alias);
24660 
24661  // Loop over the alias to include them in the package
24662  for (unsigned i = 0; i < n_alias; i++)
24663  {
24664  // Send the alias info.
24665  // The current processor
24666  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24667  // The prociesso with which is shared
24668  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24669  // The index of the node
24670  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24671  } // for (i < n_alias)
24672 
24673  } // for (ishd < n_nodes)
24674 
24675  // Now send the adjacency matrix
24676  for (unsigned i = 0; i < n_nodes; i++)
24677  {
24678  for (unsigned j = 0; j < n_nodes; j++)
24679  {
24680  // Package the adjacency matrix
24681  package_unsigned_send_data_to_root.
24682  push_back(local_adjacency_matrix[iproc][i][j]);
24683 
24684  } // for (j < n_nodes)
24685 
24686  } // for (i < n_nodes)
24687 
24688  } // for (iproc < nproc)
24689 
24690  // Define the root processor
24691  const unsigned root_processor = 0;
24692 
24693  // Get the communicator of the mesh
24694  OomphCommunicator* comm_pt = this->communicator_pt();
24695 
24696  // Number of data send. from this processor to root processor
24697  unsigned n_unsigned_data_send_to_root =
24698  package_unsigned_send_data_to_root.size();
24699 
24700  // Store the number of data to receive from each processor in root
24701  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24702 
24703  // Send the number of data that each processor will send to root
24704  // Gather the info. in the "root_processor"
24705  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24706  // each processor
24707  1, // Total number of data to send from each processor
24708  MPI_UNSIGNED,
24709  &n_unsigned_data_received_in_root[0], // Container where
24710  // to receive the
24711  // info. from all
24712  // the processors
24713  1, // Number of data to receive from each processor
24714  MPI_UNSIGNED,
24715  root_processor, // The processor that receives all the
24716  // info.
24717  comm_pt->mpi_comm());
24718 
24719  // Compute the total number of data to receive from all processors
24720  unsigned n_unsigned_total_data_receive_in_root = 0;
24721  for (unsigned iproc = 0; iproc < nproc; iproc++)
24722  {
24723  // Add the number of data to receive from each processor
24724  n_unsigned_total_data_receive_in_root+=
24725  n_unsigned_data_received_in_root[iproc];
24726  }
24727 
24728  // Compute the offsets from each processor
24729  Vector<int> root_unsigned_offsets_receive(nproc,0);
24730  root_unsigned_offsets_receive[0] = 0;
24731  for (unsigned iproc = 1; iproc < nproc; iproc++)
24732  {
24733  // Compute the offset to store the values received from each
24734  // processor
24735  root_unsigned_offsets_receive[iproc] =
24736  root_unsigned_offsets_receive[iproc-1] +
24737  n_unsigned_data_received_in_root[iproc-1];
24738  }
24739 
24740  // Create at least one entry so we don't get a seg fault below
24741  if (package_unsigned_send_data_to_root.size()==0)
24742  {
24743  package_unsigned_send_data_to_root.resize(1);
24744  }
24745 
24746  // Vector where to receive the data sent from each processor
24748  package_unsigned_data_received_root(n_unsigned_total_data_receive_in_root);
24749  if (my_rank!=root_processor)
24750  {
24751  // Create at least one entry so we don't get a seg fault below
24752  if (package_unsigned_data_received_root.size()==0)
24753  {
24754  package_unsigned_data_received_root.resize(1);
24755  }
24756  } // if (my_rank!=root_processor)
24757 
24758  // Gather the info. from all processors
24759  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
24760  // to send
24761  // info. from
24762  // each
24763  // processor
24764  n_unsigned_data_send_to_root, // Total number of data to
24765  // send from each
24766  // processor
24767  MPI_UNSIGNED,
24768  &package_unsigned_data_received_root[0], // Container
24769  // where to
24770  // receive the
24771  // info. from
24772  // all the
24773  // processors
24774  &n_unsigned_data_received_in_root[0], // Number of data
24775  // to receive from
24776  // each processor
24777  &root_unsigned_offsets_receive[0], // The offset to
24778  // store the
24779  // info. from each
24780  // processor
24781  MPI_UNSIGNED,
24782  root_processor, //The processor that receives all the
24783  //info.
24784  comm_pt->mpi_comm());
24785 
24786  // Store the info. to be sent by root to other processors
24787  Vector<unsigned> package_unsigned_data_sent_from_root;
24788  // Total data sent to each processor from root
24789  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
24790 
24791  // The root processor now has all the info. regarding the shared
24792  // nodes and the adjacency matrix of each pair of processors
24793  if (my_rank == root_processor)
24794  {
24795  // Decode the info. received from all processors
24796  // Counter to decode the info.
24797  unsigned decode_counter = 0;
24798 
24799  // Store the local alias of the nodes in each processor
24800  // [x][][][][] iproc
24801  // [][x][][][] jproc
24802  // [][][x][][] inode
24803  // [][][][x][] ialias
24804  // [][][][][x] alias_data
24806  local_node_alias(nproc);
24807  // Store the local adjacency matrix of each processor
24808  Vector<Vector<Vector<Vector<unsigned> > > > local_adjacency_matrix(nproc);
24809 
24810  // Loop over all the processors
24811  for (unsigned iproc = 0; iproc < nproc; iproc++)
24812  {
24813  local_node_alias[iproc].resize(nproc);
24814 
24815  // Resize the local adjacency matrix to store the info. sent
24816  // from all processors
24817  local_adjacency_matrix[iproc].resize(nproc);
24818 
24819  if (n_unsigned_data_received_in_root[iproc] > 0)
24820  {
24821  // Loop over all the processors to decode the info. received
24822  // from each one
24823  for (unsigned jproc = 0; jproc < nproc; jproc++)
24824  {
24825  // Read the processor number to which the info. correspond
24826  const unsigned read_jproc =
24827  package_unsigned_data_received_root[decode_counter++];
24828 
24829  // The read processor must be the same as the jproc, if that
24830  // is not the case then there is a synchronisation issue
24831  if (read_jproc != jproc)
24832  {
24833  std::ostringstream error_stream;
24834  error_stream
24835  << "The read processor is different from the jproc, this is\n"
24836  << "a synchronisation issue. The data are not read in the\n"
24837  << "sameorder as the were packaged\n"
24838  << "Read processor: (" << read_jproc << ")\n"
24839  << "Current jproc: (" << jproc << ")\n\n";
24840  throw OomphLibError(error_stream.str(),
24841  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24842  OOMPH_EXCEPTION_LOCATION);
24843  }
24844 
24845  // Read the number of nodes in the shared boundaries between
24846  // iproc and jproc
24847  const unsigned read_n_shd_nodes_iproc_jproc =
24848  package_unsigned_data_received_root[decode_counter++];
24849 
24850  // Resize the container
24851  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
24852 
24853  // Loop over the number of nodes shared between iproc and
24854  // jproc
24855  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
24856  {
24857  // Read the number of alias of the current ishd node
24858  const unsigned read_n_alias_node_iproc_jproc =
24859  package_unsigned_data_received_root[decode_counter++];
24860 
24861  // Resize the container
24862  local_node_alias[iproc][jproc][ishd].
24863  resize(read_n_alias_node_iproc_jproc);
24864 
24865  for (unsigned ialias = 0;
24866  ialias < read_n_alias_node_iproc_jproc; ialias++)
24867  {
24868  // Resize the container, we know there are three data to
24869  // define the alias of a node
24870  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
24871 
24872  // The 1st processor with which is shared
24873  local_node_alias[iproc][jproc][ishd][ialias][0] =
24874  package_unsigned_data_received_root[decode_counter++];
24875 
24876  // The 2nd processor with which is shared
24877  local_node_alias[iproc][jproc][ishd][ialias][1] =
24878  package_unsigned_data_received_root[decode_counter++];
24879 
24880  // The index of the node in the interaction iproc-jproc
24881  local_node_alias[iproc][jproc][ishd][ialias][2] =
24882  package_unsigned_data_received_root[decode_counter++];
24883 
24884  } // for (ialias < read_n_alias_node_iproc_jproc)
24885 
24886  } // for (ishd < read_n_shd_nodes_iproc_jproc)
24887 
24888  // Resize the local adjacency matrix
24889  local_adjacency_matrix[iproc][jproc].
24890  resize(read_n_shd_nodes_iproc_jproc);
24891  // Read the adjacency matrix sent to root processor
24892  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
24893  {
24894  // Resize the local adjacency matrix
24895  local_adjacency_matrix[iproc][jproc][i].
24896  resize(read_n_shd_nodes_iproc_jproc);
24897  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
24898  {
24899  // Read the adjacency matrix entry
24900  local_adjacency_matrix[iproc][jproc][i][j] =
24901  package_unsigned_data_received_root[decode_counter++];
24902  } // for (j < read_n_shd_nodes_iproc_jproc)
24903 
24904  } // for (i < read_n_shd_nodes_iproc_jproc)
24905 
24906  } // for (jproc < nproc)
24907 
24908  } // for (iproc < nproc)
24909 
24910  } // for (iproc < nproc)
24911 
24912 #ifdef PARANOID
24913  if (decode_counter != n_unsigned_total_data_receive_in_root)
24914  {
24915  std::ostringstream error_stream;
24916  error_stream
24917  << "The number of data decoded in root received from others\n"
24918  << "processors is different from the total number of data received\n"
24919  << "Data decoded: (" << decode_counter << ")\n"
24920  << "Data received: ("<<n_unsigned_total_data_receive_in_root<<")\n\n"
24921  << "This is a synchronisation issue so you are probably sending\n"
24922  << "more or less info. than the one that is being decoded\n\n";
24923  throw OomphLibError(error_stream.str(),
24924  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24925  OOMPH_EXCEPTION_LOCATION);
24926  }
24927 #endif
24928 
24929  // Assign a unique id to the nodes (uses the alias information to
24930  // identify the repetition of a node in other processors). The
24931  // global node id is given by the position (index) in the global
24932  // node alias
24933 
24934  // Keep track of those alias already assigned a unique id
24935  std::map<Vector<unsigned>, bool> alias_done;
24936 
24937  // Store all the alias associated to each node
24938  Vector<Vector<Vector<unsigned> > > global_node_alias;
24939 
24940  // Loop over all the processors
24941  for (unsigned iproc = 0; iproc < nproc; iproc++)
24942  {
24943  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24944  {
24945  // Read the number of nodes shared between the processors
24946  const unsigned n_shd_nodes_iproc_jproc =
24947  local_node_alias[iproc][jproc].size();
24948 #ifdef PARANOID
24949  // Read the number of nodes shared in the other direction
24950  const unsigned n_shd_nodes_jproc_iproc =
24951  local_node_alias[jproc][iproc].size();
24952 
24953  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24954  {
24955  std::ostringstream error_stream;
24956  error_stream
24957  << "The number of nodes shared between iproc and jproc is\n"
24958  << "different from the number of nodes shared between jproc\n"
24959  << "and iproc\n"
24960  << "Nodes shared between processor (" << iproc << ") and "
24961  << "processor ("<<jproc<<"): ("<<n_shd_nodes_iproc_jproc<<")\n"
24962  << "Nodes shared between processor (" << jproc << ") and "
24963  << "processor ("<<iproc<<"): ("<<n_shd_nodes_jproc_iproc<<")\n\n";
24964  throw OomphLibError(error_stream.str(),
24965  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24966  OOMPH_EXCEPTION_LOCATION);
24967  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24968 #endif
24969 
24970  // Loop over the nodes shared between the processors
24971  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
24972  {
24973  // Get the number of alias associated to the node on each
24974  // processor
24975  const unsigned n_alias_iproc_jproc =
24976  local_node_alias[iproc][jproc][ishd].size();
24977  const unsigned n_alias_jproc_iproc =
24978  local_node_alias[jproc][iproc][ishd].size();
24979 
24980  // Store all the found alias to the node
24981  Vector<Vector<unsigned> > node_alias;
24982 
24983  // Flag to indicate if a new alias has been added
24984  bool new_alias_added = false;
24985 
24986  // Start by adding the "direct" alias of the node
24987  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
24988  {
24989  // Get the alias of the node
24990  Vector<unsigned> current_alias =
24991  local_node_alias[iproc][jproc][ishd][ialias];
24992  // Check if already done
24993  if (!alias_done[current_alias])
24994  {
24995  // Add the alias of the node
24996  node_alias.push_back(current_alias);
24997  // Set the flag to indicate a new alias has been added
24998  new_alias_added = true;
24999  // Mark the alias as done
25000  alias_done[current_alias] = true;
25001  } // if (!alias_done[i_alias])
25002 
25003  } // for (ialias < n_alias_iproc_jproc)
25004 
25005  // Start by adding the "direct" alias of the node
25006  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25007  {
25008  // Get the alias of the node
25009  Vector<unsigned> current_alias =
25010  local_node_alias[jproc][iproc][ishd][ialias];
25011 
25012  // Check if already done
25013  if (!alias_done[current_alias])
25014  {
25015  // Add the alias of the node
25016  node_alias.push_back(current_alias);
25017  // Set the flag to indicate a new alias has been added
25018  new_alias_added = true;
25019  // Mark the alias as done
25020  alias_done[current_alias] = true;
25021  } // if (!alias_done[i_alias])
25022 
25023  } // for (ialias < n_alias_jproc_iproc)
25024 
25025  unsigned counter_alias = 0;
25026  // Visit the alias of the node and add any new found
25027  // alias, end until all its alias have been included
25028 
25029  unsigned n_current_alias = node_alias.size();
25030  while(new_alias_added || counter_alias < n_current_alias)
25031  //while(new_alias_added) // we need to check all the alias, including those added during the process
25032  {
25033  new_alias_added = false;
25034  // Store the current visited alias
25035  Vector<unsigned> current_alias = node_alias[counter_alias];
25036 
25037  // Get the alias associated with the current alias
25038  Vector<Vector<unsigned> > alias_of_current_alias =
25039  local_node_alias[current_alias[0]]
25040  [current_alias[1]]
25041  [current_alias[2]];
25042 
25043  // Get all the alias associated with the alias of the
25044  // current alias
25045  const unsigned n_alias = alias_of_current_alias.size();
25046 
25047  // Loop over the new alias and check if require to add
25048  // them
25049  for (unsigned k = 0; k < n_alias; k++)
25050  {
25051  // Get the alias of the node
25052  Vector<unsigned> add_alias =
25053  alias_of_current_alias[k];
25054 
25055  // Check if already done
25056  if (!alias_done[add_alias])
25057  {
25058  // Add the alias of the node
25059  node_alias.push_back(add_alias);
25060  // Set the flag to indicate a new alias has been
25061  // added
25062  new_alias_added = true;
25063  // Mark the alias ad done
25064  alias_done[add_alias] = true;
25065  } // if (!alias_done[i_alias])
25066 
25067  } // for (k < n_alias)
25068 
25069  // Get the alias associated with the current alias (in the
25070  // other direction)
25071  Vector<Vector<unsigned> > alias_of_current_alias2 =
25072  local_node_alias[current_alias[1]]
25073  [current_alias[0]]
25074  [current_alias[2]];
25075 
25076  // Get all the alias associated with the current alias
25077  // (in the other direction)
25078  const unsigned n_alias2 = alias_of_current_alias2.size();
25079 
25080  // Loop over the new alias and check if require to add
25081  // them
25082  for (unsigned k = 0; k < n_alias2; k++)
25083  {
25084  // Get the alias of the node
25085  Vector<unsigned> add_alias =
25086  alias_of_current_alias2[k];
25087 
25088  // Check if already done
25089  if (!alias_done[add_alias])
25090  {
25091  // Add the alias of the node
25092  node_alias.push_back(add_alias);
25093  // Set the flag to indicate a new alias has been
25094  // added
25095  new_alias_added = true;
25096  // Mark the alias ad done
25097  alias_done[add_alias] = true;
25098  } // if (!alias_done[i_alias])
25099 
25100  } // for (k < n_alias)
25101 
25102  // Go for the next alias
25103  counter_alias++;
25104 
25105  // Update the number of alias so that the while stops when
25106  // all the alias have been visited and no new alias was
25107  // added
25108  n_current_alias = node_alias.size();
25109 
25110  } // while(new_alias_added || counter_alias < n_current_alias)
25111 
25112  // If the node has not been previously added, then include
25113  // all its alias
25114  if (node_alias.size() > 0)
25115  {
25116  // Add all the found alias of the node to the global alias
25117  // storage
25118  global_node_alias.push_back(node_alias);
25119  }
25120 
25121  } // for (ishd < n_shd_nodes_iproc_jproc)
25122 
25123  } // for (jproc < nproc)
25124 
25125  } // for (iproc < nproc)
25126 
25127  // We now have the global number of nodes, each with its own id
25128  // (the index in the global_node_alias vector)
25129 
25130  // Get the number of global shared nodes
25131  const unsigned n_global_shared_nodes = global_node_alias.size();
25132 
25133  // Create matrix from local to global shared node id
25134  Vector<Vector<Vector<int> > > local_to_global_shared_node(nproc);
25135 
25136  // Loop over all the processors to resize
25137  for (unsigned iproc = 0; iproc < nproc; iproc++)
25138  {
25139  // Resize the map matrix
25140  local_to_global_shared_node[iproc].resize(nproc);
25141  } // for (iproc < nproc)
25142 
25143  // Loop over all the processors to resize (the third direction,
25144  // required if we want to loop over the half of the matrix only)
25145  for (unsigned iproc = 0; iproc < nproc; iproc++)
25146  {
25147  // Loop over the half of the matrix to resize
25148  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25149  {
25150  // Read the number of nodes shared between the processors
25151  const unsigned n_shd_nodes =
25152  local_node_alias[iproc][jproc].size();
25153 
25154  // Resize the map matrix
25155  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes,-1);
25156 
25157  // ... and resize the other half map matrix
25158  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes,-1);
25159 
25160  } // for (jproc < nproc)
25161 
25162  } // for (iproc < nproc)
25163 
25164  // Fill the matrix for mapping from local to global node id
25165 
25166  // Loop over the global nodes, and for each alias assign the
25167  // corresponding global node id
25168  for (unsigned k = 0 ; k < n_global_shared_nodes; k++)
25169  {
25170  // Get the number of alias associated to the current global node
25171  const unsigned n_alias_global_node = global_node_alias[k].size();
25172  // Loop over the alias and assign the global node id
25173  for (unsigned l = 0; l < n_alias_global_node; l++)
25174  {
25175  // Get the 1st processor
25176  const unsigned iproc = global_node_alias[k][l][0];
25177  // Get the 2nd processor
25178  const unsigned jproc = global_node_alias[k][l][1];
25179  // Get the node number
25180  const unsigned ishd = global_node_alias[k][l][2];
25181  // Assign the global node id
25182  local_to_global_shared_node[iproc][jproc][ishd] = k;
25183 
25184  } // for (l < n_alias_global_node)
25185 
25186  } // for (k < n_global_shared_nodes)
25187 
25188  // Create the global adjacency matrix
25189  Vector<Vector<unsigned> > global_adjacency_matrix(n_global_shared_nodes);
25190  // Resize the global adjacency matrix
25191  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25192  {
25193  // Resize
25194  global_adjacency_matrix[k].resize(n_global_shared_nodes,0);
25195  } // for (k < n_global_shared_nodes)
25196 
25197  // Add the entries to the global adjacency matrix and compute the
25198  // degree of each node
25199 
25200  // Store the degree of the global nodes
25201  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25202 
25203  // Loop over the processors
25204  for (unsigned iproc = 0; iproc < nproc; iproc++)
25205  {
25206  // Loop over the half of the matrix to resize
25207  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25208  {
25209  // Get the number of nodes shared between the processors
25210  const unsigned n_shd_nodes =
25211  local_node_alias[iproc][jproc].size();
25212 
25213  // Search for entries in the local adjacency matrix that set a
25214  // connection among the nodes
25215 
25216  // Loop over the shared nodes in the current pair of
25217  // processors
25218  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25219  {
25220  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25221  {
25222  // Are the nodes associated
25223  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25224  {
25225  // Get the global nodes id
25226 
25227  // Get the "left-node" global id
25228  const int global_shd_node_left =
25229  local_to_global_shared_node[iproc][jproc][ishd];
25230 
25231  // Get the "right-node" global id
25232  const int global_shd_node_right =
25233  local_to_global_shared_node[iproc][jproc][jshd];
25234 
25235 #ifdef PARANOID
25236  // Check if the local nodes have a global node
25237  // associated
25238  if (global_shd_node_left == -1)
25239  {
25240  std::ostringstream error_stream;
25241  error_stream
25242  << "The local node in processors iproc and jproc has no\n"
25243  << "global node assigned\n"
25244  << "iproc processor: (" << iproc << ")\n"
25245  << "jproc processor: ("<<jproc<<")\n"
25246  << "Local node: (" << ishd << ")\n\n";
25247  throw OomphLibError(error_stream.str(),
25248  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25249  OOMPH_EXCEPTION_LOCATION);
25250  }
25251 
25252  // Check if the local nodes have a global node
25253  // associated
25254  if (global_shd_node_right == -1)
25255  {
25256  std::ostringstream error_stream;
25257  error_stream
25258  << "The local node in processors iproc and jproc has no\n"
25259  << "global node assigned\n"
25260  << "iproc processor: (" << iproc << ")\n"
25261  << "jproc processor: ("<<jproc<<")\n"
25262  << "Local node: (" << jshd << ")\n\n";
25263  throw OomphLibError(error_stream.str(),
25264  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25265  OOMPH_EXCEPTION_LOCATION);
25266  }
25267 #endif
25268  // Get the unsigned version of the indexes
25269  const unsigned uleft =
25270  static_cast<unsigned>(global_shd_node_left);
25271  const unsigned uright =
25272  static_cast<unsigned>(global_shd_node_right);
25273 
25274  // Add the entry in the global adjacency matrix
25275  global_adjacency_matrix[uleft][uright]++;
25276 
25277  // ... and in the other direction too
25278  global_adjacency_matrix[uright][uleft]++;
25279 
25280  // Add on to the degree of the left node
25281  global_node_degree[uleft]++;
25282 
25283  // Add on to the degree of the right node
25284  global_node_degree[uright]++;
25285 
25286  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25287 
25288  } // // for (jshd < n_shd_nodes)
25289 
25290  } // for (ishd < n_shd_nodes)
25291 
25292  } // for (jproc < nproc)
25293 
25294  } // for (iproc < nproc)
25295 
25296  // Assign the global degree to the shared nodes between each pair
25297  // of processors
25298  Vector<Vector<Vector<unsigned> > > root_local_node_degree(nproc);
25299  // Resize the container
25300  for (unsigned iproc = 0; iproc < nproc; iproc++)
25301  {
25302  root_local_node_degree[iproc].resize(nproc);
25303  }
25304 
25305  // Loop over the processors and visited their shared nodes
25306  for (unsigned iproc = 0; iproc < nproc; iproc++)
25307  {
25308  // Only visit the half of the data
25309  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25310  {
25311  // Get the number of shared nodes between this pair of
25312  // processors (iproc, jproc)
25313  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25314 
25315  // Resize the container to store the local degree of the nodes
25316  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25317  // ... and in the other way too
25318  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25319 
25320  // Loop over the number of nodes shared between the pair of
25321  // processors
25322  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25323  {
25324  // Get the global node id for the current shared node
25325  const int global_shd_node_id =
25326  local_to_global_shared_node[iproc][jproc][ishd];
25327 
25328 #ifdef PARANOID
25329  // Check if the local nodes have a global node associated
25330  if (global_shd_node_id == -1)
25331  {
25332  std::ostringstream error_stream;
25333  error_stream
25334  << "The local node in processors iproc and jproc has no\n"
25335  << "global node assigned\n"
25336  << "iproc processor: (" << iproc << ")\n"
25337  << "jproc processor: ("<<jproc<<")\n"
25338  << "Local node: (" << ishd << ")\n\n";
25339  throw OomphLibError(error_stream.str(),
25340  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25341  OOMPH_EXCEPTION_LOCATION);
25342  }
25343 #endif
25344 
25345  // Get the unsigned version of the global index
25346  const unsigned uglobal_shd_node_id =
25347  static_cast<unsigned>(global_shd_node_id);
25348 
25349  // Get the degree of the node
25350  const unsigned node_degree =
25351  global_node_degree[uglobal_shd_node_id];
25352 
25353  // Set the degree in the container for the degree of the
25354  // nodes in the local interaction between processors
25355  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25356  // ... and in the other way too
25357  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25358 
25359  } // for (ishd < n_shd_nodes)
25360 
25361  } // for (jproc < nproc)
25362 
25363  } // for (iproc < nproc)
25364 
25365  // Clear the container where the info. will be sent back to each
25366  // processor
25367  package_unsigned_data_sent_from_root.clear();
25368 
25369  // Prepare the data to sent it back to each processor (encode the
25370  // info. to sent to all processors)
25371  for (unsigned iproc = 0; iproc < nproc; iproc++)
25372  {
25373  // Count the number of data sent to iproc processor
25374  unsigned count_n_data_sent_to_iproc = 0;
25375  for (unsigned jproc = 0; jproc < nproc; jproc++)
25376  {
25377  // No shared nodes between the same processor
25378  if (iproc != jproc)
25379  {
25380  // Get the number of nodes shared between the processors
25381  const unsigned n_shd_nodes =
25382  root_local_node_degree[iproc][jproc].size();
25383 
25384  // Add the number of data sent to iproc processor
25385  count_n_data_sent_to_iproc+=n_shd_nodes;
25386 
25387  // Loop over the nodes shared between the pair of processors
25388  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25389  {
25390  package_unsigned_data_sent_from_root.
25391  push_back(root_local_node_degree[iproc][jproc][ishd]);
25392  } // for (ishd < n_shd_nodes)
25393 
25394  } // if (iproc != jproc)
25395 
25396  } // for (jproc < nproc)
25397 
25398  // Set the number of data sent to iproc processor
25399  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25400 
25401  } // for (iproc < nproc)
25402 
25403  } // if (my_rank == root_processor)
25404 
25405  // Total data received from root to this processor
25406  int n_unsigned_data_received_from_root = 0;
25407 
25408  // Get the number of data that each processor receives from root
25409  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25410  // root to each
25411  // processor
25412  1, // The number of data sent from root to each
25413  // processor
25414  MPI_UNSIGNED,
25415  &n_unsigned_data_received_from_root, // Store the
25416  // info. received
25417  // from root
25418  1, // The number of data received from root
25419  MPI_UNSIGNED,
25420  root_processor, // The processor that sends the
25421  // info.
25422  comm_pt->mpi_comm());
25423 
25424  // Receive the info. sent by root
25426  package_unsigned_data_received_from_root(n_unsigned_data_received_from_root);
25427 
25428  // Compute the offsets to each processor
25429  Vector<int> root_unsigned_offsets_sent(nproc,0);
25430  root_unsigned_offsets_sent[0] = 0;
25431  for (unsigned iproc = 1; iproc < nproc; iproc++)
25432  {
25433  // Compute the offset to send the values to each processor
25434  root_unsigned_offsets_sent[iproc] =
25435  root_unsigned_offsets_sent[iproc-1] +
25436  n_unsigned_data_sent_from_root[iproc-1];
25437  }
25438 
25439  if (my_rank!=root_processor)
25440  {
25441  // Create at least one entry so we don't get a seg fault below
25442  if (package_unsigned_data_sent_from_root.size()==0)
25443  {
25444  package_unsigned_data_sent_from_root.resize(1);
25445  }
25446  } // if (my_rank!=root_processor)
25447 
25448  // Create at least one entry so we don't get a seg fault below
25449  if (package_unsigned_data_received_from_root.size()==0)
25450  {
25451  package_unsigned_data_received_from_root.resize(1);
25452  }
25453 
25454  // Get the data from root
25455  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25456  // info. sent
25457  // from root
25458  // to others
25459  // processors
25460  &n_unsigned_data_sent_from_root[0], // The number of
25461  // data sent from
25462  // root to others
25463  // processors
25464  &root_unsigned_offsets_sent[0], // The offsets to each
25465  // processors
25466  MPI_UNSIGNED,
25467  &package_unsigned_data_received_from_root[0], // The
25468  // storage
25469  // in the
25470  // processor
25471  // that
25472  // receives
25473  // the
25474  // info.
25475  n_unsigned_data_received_from_root, // The number of
25476  // data that the
25477  // current
25478  // processor
25479  // receives from
25480  // root
25481  MPI_UNSIGNED,
25482  root_processor, // The root processors
25483  comm_pt->mpi_comm());
25484 
25485  // Decode the info.
25486 
25487  // Keep track of the already nodes done
25488  std::map<Node*, bool> node_done;
25489 
25490  // Read the global degree assigned to the shared nodes between the
25491  // current processors and the other processors
25492  int decode_counter = 0;
25493  // Store the global degree of the local nodes
25494  Vector<Vector<unsigned> > local_node_degree(nproc);
25495  // Loop over the processors
25496  for (unsigned iproc = 0; iproc < nproc; iproc++)
25497  {
25498  // There are no shared nodes with the current processor itself
25499  if (iproc != my_rank)
25500  {
25501  // Get the number of nodes shared with the iproc processor
25502  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25503 
25504  // Read the global degree of the node
25505  package_unsigned_send_data_to_root.push_back(n_nodes);
25506 
25507  // Loop over the nodes
25508  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25509  {
25510  // Get the node degree assigned to the ishd node in between
25511  // the interaction of the iproc and the current processor
25512  const unsigned node_degree =
25513  package_unsigned_data_received_from_root[decode_counter++];
25514 
25515  // Get the node
25516  Node* shd_node_pt =
25517  tmp_sorted_shared_node_pt[iproc][ishd];
25518 
25519  // Has the node been assigned a global degree
25520  if (!node_done[shd_node_pt])
25521  {
25522  // Assign the global degree to the node
25523  global_node_degree[shd_node_pt] = node_degree;
25524  // Mark the node as done
25525  node_done[shd_node_pt] = true;
25526  }
25527 #ifdef PARANOID
25528  else
25529  {
25530  // The node has been already done, check that the node
25531  // degree is the same as the already assigned
25532  if (global_node_degree[shd_node_pt] != node_degree)
25533  {
25534  std::ostringstream error_stream;
25535  error_stream
25536  << "The local node has already assigned a global degree,\n"
25537  << "however, a different degree for the same node has been\n"
25538  << "read from the data sent from root processor\n"
25539  << "iproc processor: (" << iproc << ")\n"
25540  << "Local node: (" << ishd << ")\n"
25541  << "---------------------------------------------------------\n"
25542  << "Already assigned degree: ("
25543  << global_node_degree[shd_node_pt] << ")\n"
25544  << "New found degree: (" << node_degree << ")\n"
25545  << "---------------------------------------------------------\n"
25546  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25547  << shd_node_pt->x(1) << ")\n\n";
25548  throw OomphLibError(error_stream.str(),
25549  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25550  OOMPH_EXCEPTION_LOCATION);
25551  }
25552 
25553  } // else if (!node_done[shd_node_pt])
25554 #endif // #ifdef PARANOID
25555 
25556  } // for (ishd < n_nodes)
25557 
25558  } // if (iproc != my_rank)
25559 
25560  } // for (iproc < nproc)
25561 
25562 #ifdef PARANOID
25563  // Ensure that all the info. sent from root processor has been read
25564  if (decode_counter != n_unsigned_data_received_from_root)
25565  {
25566  std::ostringstream error_stream;
25567  error_stream
25568  << "The number of data decoded received from root processor is\n"
25569  << "different from the total number of data received from the root\n"
25570  << "processor\n"
25571  << "Data decoded: (" << decode_counter << ")\n"
25572  << "Data received: ("<<n_unsigned_data_received_from_root<<")\n\n"
25573  << "This is a synchronisation issue so you are probably sending\n"
25574  << "more or less info. than the one that is being decoded\n\n";
25575  throw OomphLibError(error_stream.str(),
25576  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25577  OOMPH_EXCEPTION_LOCATION);
25578  }
25579 #endif
25580 
25581  }
25582 
25583  //======================================================================
25584  // Sort the nodes on the new shared boundaries (after load balancing),
25585  // computes the alias of the nodes and creates the adjacency matrix
25586  // that represent the graph created by the shared edges between each
25587  // pair of processors
25588  // ======================================================================
25589  template <class ELEMENT>
25592  Vector<Vector<FiniteElement*> > &unsorted_face_ele_pt,
25593  Vector<Vector<Node*> > &tmp_sorted_shared_node_pt,
25594  std::map<Node*, Vector<Vector<unsigned> > > &node_alias,
25595  Vector<Vector<Vector<unsigned> > > &adjacency_matrix)
25596  {
25597  // Get the number of processors and the rank
25598  const unsigned nproc = this->communicator_pt()->nproc();
25599  const unsigned my_rank = this->communicator_pt()->my_rank();
25600 
25601  // Assign a unique id to each node shared between each pair of
25602  // processors, in this case the current processor and the iproc
25603 
25604  // ... also compute the alias of each node (processor and index of
25605  // the node in all processors where it appears)
25606 
25607  // Clear the alias info
25608  node_alias.clear();
25609 
25610  // Temporary storage for the index of the nodes
25611  Vector<std::map<Node*, unsigned> > tmp_node_index(nproc);
25612 
25613  // Loop over the processors
25614  for (unsigned iproc = 0; iproc < nproc; iproc++)
25615  {
25616  // There is no shared elements between the same processor
25617  if (iproc != my_rank)
25618  {
25619  // Map to mark those nodes already visited
25620  std::map<Node*, bool> done_node;
25621 
25622  // A map is used to sort the nodes using their coordinates as
25623  // the key of the map
25624  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25625  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25626 
25627  // Get the number of unsorted face elements
25628  const unsigned n_unsorted_face_ele =
25629  unsorted_face_ele_pt[iproc].size();
25630 
25631  // Loop over the unsorted elements
25632  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25633  {
25634  // Get a root element
25635  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25636  // Get the left node of the face element
25637  Node* left_node_pt = face_ele_pt->node_pt(0);
25638 
25639  // Check if the node has been already sorted in the
25640  // interaction between the current processor and iproc
25641  // processor
25642  if (!done_node[left_node_pt])
25643  {
25644  std::pair<double, double> vertex =
25645  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25646  sorted_nodes_pt[vertex] = left_node_pt;
25647  // Mark the node as done
25648  done_node[left_node_pt] = true;
25649  }
25650 
25651  // Get the number of nodes of the face element
25652  const unsigned n_nodes = face_ele_pt->nnode();
25653  // Get the right node of the face element
25654  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25655 
25656  // Check if the node has been already sorted in the
25657  // interaction between the current processor and iproc
25658  // processor
25659  if (!done_node[right_node_pt])
25660  {
25661  std::pair<double, double> vertex =
25662  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25663  sorted_nodes_pt[vertex] = right_node_pt;
25664  // Mark the node as done
25665  done_node[right_node_pt] = true;
25666  }
25667 
25668  } // for (e < nunsorted_face_ele)
25669 
25670  // The nodes are already sorted, we need to return them in the
25671  // proper container
25672 
25673  // The counter to enumerate the nodes
25674  unsigned counter = 0;
25675 
25676  // Go through the map container which already have the nodes
25677  // sorted they have the same sorting on all processors
25678  for (std::map<std::pair<double, double>, Node*>::iterator it
25679  = sorted_nodes_pt.begin(); it != sorted_nodes_pt.end(); it++)
25680  {
25681  // Get the node
25682  Node* node_pt = (*it).second;
25683  // Store the node at the corresponding index
25684  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25685 
25686  // Create the temporary access to the node index
25687  tmp_node_index[iproc][node_pt] = counter;
25688 
25689  // Fill the info. for the node alias
25690  Vector<unsigned> alias(3);
25691  // The current processor
25692  alias[0] = my_rank;
25693  // The processor with which is shared
25694  alias[1] = iproc;
25695  // The index with that processor
25696  alias[2] = counter++;
25697 
25698  // Store the info. of the alias
25699  node_alias[node_pt].push_back(alias);
25700 
25701  } // Loop map
25702 
25703  } // if (iproc != my_rank)
25704 
25705  } // for (iproc < nproc)
25706 
25707  // Loop over the processors to resize and initialize the adjacency
25708  // matrix
25709  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25710  {
25711  // Get the number of nodes shared with iproc
25712  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25713  // Resize the adjacency matrix
25714  adjacency_matrix[iproc].resize(n_shd_nodes);
25715  for (unsigned i = 0; i < n_shd_nodes; i++)
25716  {
25717  // Resize the adjacency matrix
25718  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25719 
25720  // Initialize the
25721  for (unsigned j = 0; j < n_shd_nodes; j++)
25722  {
25723  adjacency_matrix[iproc][i][j] = 0;
25724  } // for (j < n_shd_nodes)
25725 
25726  } // for (i < n_shd_nodes)
25727 
25728  } // for (iproc < nproc)
25729 
25730  // Loop over the processors to fill the adjacency matrix
25731  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25732  {
25733  // There is no shared elements between the same processor
25734  if (iproc != my_rank)
25735  {
25736  // Get the number of unsorted face elements
25737  const unsigned n_unsorted_face_ele =
25738  unsorted_face_ele_pt[iproc].size();
25739 
25740  // Loop over the unsorted elements
25741  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25742  {
25743  // Get a root element
25744  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25745  // Get the left node of the face element
25746  Node* left_node_pt = face_ele_pt->node_pt(0);
25747 
25748  // Get the number of nodes of the face element
25749  const unsigned n_nodes = face_ele_pt->nnode();
25750  // Get the right node of the face element
25751  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25752 
25753  // Get the index of each of the nodes
25754  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
25755  const unsigned right_node_index = tmp_node_index[iproc][right_node_pt];
25756 
25757  // Add an entry to the adjacency matrix to indicate the
25758  // association of left and right node
25759  adjacency_matrix[iproc][left_node_index][right_node_index]++;
25760  // ... both directions
25761  adjacency_matrix[iproc][right_node_index][left_node_index]++;
25762 
25763  } // for (e < n_unsorted_face_ele)
25764 
25765  } // if (iproc != my_rank)
25766 
25767  } // for (iproc < nproc)
25768 
25769  }
25770 
25771  //======================================================================
25772  /// \short Get the nodes on the shared boundary (b), these are stored
25773  /// in the segment they belong
25774  //======================================================================
25775  template <class ELEMENT>
25778  const unsigned &shd_bnd_id, Vector<Vector<Node*> > &tmp_segment_nodes)
25779  {
25780  // Clear the data structure were to return the nodes
25781  tmp_segment_nodes.clear();
25782 
25783  // Get the face elements that created the shared boundary from the
25784  // bulk shared boundary elements
25785 
25786 #ifdef PARANOID
25787  // The temporary storage for the halo face elements
25788  Vector<FiniteElement*> halo_shared_face_ele_pt;
25789 #endif
25790  // The temporary storage for the nonhalo face elements
25791  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
25792 
25793  // Get the number of shared boundary elements associated with the
25794  // current shared boundary
25795  const unsigned nshared_bound_ele =
25796  this->nshared_boundary_element(shd_bnd_id);
25797 
25798  // Loop over the elements in the shared boundary to create the face
25799  // elements
25800  for (unsigned e = 0; e < nshared_bound_ele; e++)
25801  {
25802  // Get the shared boundary element
25803  FiniteElement* bulk_ele_pt =
25804  this->shared_boundary_element_pt(shd_bnd_id, e);
25805 
25806  // Get the face index
25807  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
25808 
25809  // Before adding the new element we need to ensure that the edge
25810  // that this element represents has not been already added
25811  FiniteElement* face_ele_pt =
25812  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
25813 
25814  // Nonhalo element
25815  if (!bulk_ele_pt->is_halo())
25816  {
25817  // Add nonhalo shared face element to the container
25818  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
25819  }
25820 #ifdef PARANOID
25821  else // halo element
25822  {
25823  // Add halo shared face element to the container
25824  halo_shared_face_ele_pt.push_back(face_ele_pt);
25825  }
25826 #endif
25827 
25828  } // for (e < nshared_bound_ele)
25829 
25830  // Mark the face elements already used
25831  std::map<FiniteElement*, bool> shared_face_done;
25832 
25833  // Get the number of nonhalo face elements
25834  const unsigned nnonhalo_face_shared_ele =
25835  nonhalo_shared_face_ele_pt.size();
25836 
25837  // If we are in PARANOID mode check that there is one halo element
25838  // for each nonhalo element
25839 #ifdef PARANOID
25840  // Get the number of halo face elements
25841  const unsigned nhalo_face_shared_ele =
25842  halo_shared_face_ele_pt.size();
25843 
25844  // The number of nonhalo shared face boundary elements must be the
25845  // half of the total number of shared boundary elements
25846  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
25847  {
25848  std::ostringstream error_message;
25849  error_message
25850  << "The number of shared boundary elements (" << nshared_bound_ele
25851  << ") is not the double\nof the number of unsorted nonhalo shared "
25852  << "face boundary elements (" << nnonhalo_face_shared_ele
25853  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25854  throw OomphLibError(error_message.str(),
25855  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25856  OOMPH_EXCEPTION_LOCATION);
25857  }
25858 
25859  // The number of halo shared face boundary elements must be the
25860  // half of the total number of shared boundary elements
25861  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
25862  {
25863  std::ostringstream error_message;
25864  error_message
25865  << "The number of shared boundary elements (" << nshared_bound_ele
25866  << ") is not the double\nof the number of unsorted halo shared "
25867  << "face boundary elements (" << nhalo_face_shared_ele
25868  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25869  throw OomphLibError(error_message.str(),
25870  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25871  OOMPH_EXCEPTION_LOCATION);
25872  }
25873 
25874  // ------------------------------------------------------------------
25875  // Loop over the nonhalo face elements and look for the halo face
25876  // element at the other side of the shared boundary
25877  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
25878  {
25879  // Get the inh-th face element
25880  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
25881 
25882  // Get the number of nodes on the face element
25883  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
25884  // Get the first and last node on the element
25885  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
25886  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
25887 
25888  // Now find the (halo) face element at the other side of the
25889  // shared boundary
25890  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
25891  {
25892  // Get the ih-th face element
25893  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
25894 
25895  // Check that the face element has not been done
25896  if (!shared_face_done[halo_face_ele_pt])
25897  {
25898  // Get the number of nodes on the face element
25899  const unsigned nnodes_h = halo_face_ele_pt->nnode();
25900  // Get the first and last node on the element
25901  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
25902  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
25903 
25904  // If the nodes are the same then we have found the (halo)
25905  // face element at the other side of the shared boundary
25906  if (nh_first_node_pt == h_first_node_pt &&
25907  nh_last_node_pt == h_last_node_pt)
25908  {
25909  // Mark the face elements as done
25910  shared_face_done[nonhalo_face_ele_pt] = true;
25911  shared_face_done[halo_face_ele_pt] = true;
25912 
25913  // Break the loop for (ih < nhalo_face_shared_ele)
25914  break;
25915  } // if (nh_first_node_pt == h_first_node_pt &&
25916  // nh_last_node_pt == h_last_node_pt)
25917  else if (nh_first_node_pt == h_last_node_pt &&
25918  nh_last_node_pt == h_first_node_pt)
25919  {
25920  // Mark the face elements as done
25921  shared_face_done[nonhalo_face_ele_pt] = true;
25922  shared_face_done[halo_face_ele_pt] = true;
25923 
25924  // Break the loop for (ih < nhalo_face_shared_ele)
25925  break;
25926  } // else if (nh_first_node_pt == h_last_node_pt &&
25927  // nh_last_node_pt == h_first_node_pt)
25928 
25929  } // if (face_done[halo_face_ele_pt])
25930 
25931  } // for (ih < nhalo_face_shared_ele)
25932 
25933  } // for (inh < nnonhalo_face_shared_ele)
25934 
25935  // The number of done shared face elements MUST be the same as the
25936  // sum of the nonhalo and halo shared boundary face elements
25937  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
25938  shared_face_done.size())
25939  {
25940  std::ostringstream error_message;
25941  error_message
25942  << "The number of DONE shared boundary face elements ("
25943  << shared_face_done.size() << ") is not the same\n as the sum of"
25944  << "the nonhalo face shared boundary elements ("
25945  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
25946  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
25947  << "current boundary (" << shd_bnd_id << ")\n\n";
25948  throw OomphLibError(error_message.str(),
25949  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25950  OOMPH_EXCEPTION_LOCATION);
25951  }
25952 #endif // #ifdef PARANOID
25953 
25954  // -------------------------------------------------------------
25955  // Now sort the face elements
25956  // -------------------------------------------------------------
25957 
25958  // We already have the shared face elements that make the shared
25959  // boundary now sort them to create a contiguous boundary
25960 
25961  // Clear the already done face elements
25962  shared_face_done.clear();
25963 
25964  unsigned nsorted_face_ele = 0;
25965 
25966  // Storing for the sorting nodes extracted from the face elements
25967  std::list<Node*> sorted_nodes;
25968 
25969  // Get the root face element
25970  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
25971  nsorted_face_ele++;
25972 
25973  // Mark face as done
25974  shared_face_done[root_face_ele_pt] = true;
25975 
25976  // The initial and final node on the list
25977  const unsigned nnodes_root = root_face_ele_pt->nnode();
25978  Node *first_node_pt = root_face_ele_pt->node_pt(0);
25979  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
25980 
25981  // Push back on the list the new nodes
25982  sorted_nodes.push_back(first_node_pt);
25983  sorted_nodes.push_back(last_node_pt);
25984 
25985  // Sort the face elements
25986  while (nsorted_face_ele < nnonhalo_face_shared_ele)
25987  {
25988  // Flag to indicate when a node was added
25989  bool node_added = false;
25990 
25991  // Start from the next edge since we have already added the
25992  // previous one as the initial face element
25993  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
25994  {
25995  FiniteElement* tmp_shared_face_ele_pt =
25996  nonhalo_shared_face_ele_pt[iface];
25997 
25998  // If face has not been sorted
25999  if (!shared_face_done[tmp_shared_face_ele_pt])
26000  {
26001  // Get the number of nodes for the current face element
26002  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
26003 
26004  // Get each individual node
26005  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26006  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
26007 
26008  if (left_node_pt == first_node_pt)
26009  {
26010  // Push front the new node
26011  sorted_nodes.push_front(right_node_pt);
26012  first_node_pt = right_node_pt;
26013  node_added = true;
26014  }
26015  else if (left_node_pt == last_node_pt)
26016  {
26017  // Push back the new node
26018  sorted_nodes.push_back(right_node_pt);
26019  last_node_pt = right_node_pt;
26020  node_added = true;
26021  }
26022  else if (right_node_pt == first_node_pt)
26023  {
26024  // Push front the new node
26025  sorted_nodes.push_front(left_node_pt);
26026  first_node_pt = left_node_pt;
26027  node_added = true;
26028  }
26029  else if (right_node_pt == last_node_pt)
26030  {
26031  // Push back the new node
26032  sorted_nodes.push_back(left_node_pt);
26033  last_node_pt = left_node_pt;
26034  node_added = true;
26035  }
26036 
26037  if (node_added)
26038  {
26039  // Mark as done only if one of its nodes has been added to
26040  // the list
26041  shared_face_done[tmp_shared_face_ele_pt] = true;
26042  nsorted_face_ele++;
26043 
26044  // Break the for
26045  break;
26046  }
26047 
26048  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26049 
26050  } // for (iface < nnonhalo_face_shared_ele)
26051 
26052  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26053 
26054  // Here we can safely delete the face elements, they are no longer
26055  // required
26056 
26057  // First the nonhalo face elements
26058  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26059  {
26060  delete nonhalo_shared_face_ele_pt[inh];
26061  nonhalo_shared_face_ele_pt[inh] = 0;
26062  } // for (inh < nnonhalo_face_shared_ele)
26063 
26064 #ifdef PARANOID
26065  // ... then the halo face elements
26066  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26067  {
26068  delete halo_shared_face_ele_pt[ih];
26069  halo_shared_face_ele_pt[ih] = 0;
26070  } // for (inh < nhalo_face_shared_ele)
26071 #endif
26072 
26073  // ------------------------------------------------
26074  // Now copy the nodes to the output container
26075  // ------------------------------------------------
26076  // Get the number of nodes in the container
26077  const unsigned n_nodes = sorted_nodes.size();
26078 
26079  // First resize the container
26080  tmp_segment_nodes.resize(1);
26081  tmp_segment_nodes[0].resize(n_nodes);
26082 
26083  // Counter
26084  unsigned counter = 0;
26085 
26086  // Loop over the list of nodes and copy them in the output container
26087  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26088  it != sorted_nodes.end(); it++)
26089  {
26090  tmp_segment_nodes[0][counter] = (*it);
26091  counter++;
26092  } // Loop over sorted nodes
26093 
26094  }
26095 
26096  //=====start of get_required_elemental_information_load_balance_helper====
26097  /// \short Helper function to get the required elemental information from
26098  /// the element that will be sent to iproc processor.
26099  /// This info. involves the association of the element to a boundary or
26100  /// region.
26101  //========================================================================
26102  template<class ELEMENT>
26105  unsigned& iproc,
26106  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
26107  FiniteElement* ele_pt)
26108  {
26109  // Check if the element is associated with the original boundaries
26110  const unsigned nbound = this->initial_shared_boundary_id();
26111 
26112  // Get the number of processors
26113  const unsigned nproc = this->communicator_pt()->nproc();
26114 
26115  // ------------------------------------------------------------------
26116  // Stores the information regarding the boundaries associated to the
26117  // element (it that is the case)
26118  Vector<unsigned> associated_boundaries;
26119  Vector<unsigned> face_index_on_boundary;
26120 
26121  unsigned counter_face_indexes = 0;
26122 
26123  for (unsigned b = 0; b < nbound; b++)
26124  {
26125  // Get the number of elements associated to boundary i
26126  const unsigned nboundary_ele = nboundary_element(b);
26127  for (unsigned e = 0; e < nboundary_ele; e++)
26128  {
26129  if (ele_pt == this->boundary_element_pt(b,e))
26130  {
26131  // Keep track of the boundaries associated to the element
26132  associated_boundaries.push_back(b);
26133  // Get the face index
26134  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
26135  counter_face_indexes++;
26136 #ifdef PARANOID
26137  if (counter_face_indexes > 2)
26138  {
26139  std::stringstream error_message;
26140  error_message
26141  << "A triangular element can not have more than two of its faces "
26142  << "on a boundary!!!\n\n";
26143  throw OomphLibError(error_message.str(),
26144  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26145  OOMPH_EXCEPTION_LOCATION);
26146  }
26147 #else
26148  // Already found 2 face indexes on the same boundary?
26149  if (counter_face_indexes==2) {break;}
26150 #endif // #ifdef PARANOID
26151 
26152  } // if (ele_pt == this->boundary_element_pt(b,e))
26153 
26154  } // (e < nboundary_ele)
26155 
26156  } // (b < nbound)
26157 
26158  // If the element is associated to any boundary then package all the
26159  // relevant info
26160  const unsigned nassociated_boundaries = associated_boundaries.size();
26161  if (nassociated_boundaries > 0)
26162  {
26163  Flat_packed_unsigneds.push_back(1);
26164 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26165  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
26166 #endif
26167  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26168 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26169  std::stringstream junk;
26170  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
26171  Flat_packed_unsigneds_string.push_back(junk.str());
26172 #endif
26173 
26174  // Package the ids of the associated boundaries and the
26175  // corresponding face index for each boundary (if the element is a
26176  // corner element, it will have two faces associated to the
26177  // boundary)
26178  for (unsigned i = 0; i < nassociated_boundaries; i++)
26179  {
26180  unsigned b = associated_boundaries[i];
26181  Flat_packed_unsigneds.push_back(b);
26182 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26183  std::stringstream junk;
26184  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
26185  Flat_packed_unsigneds_string.push_back(junk.str());
26186 #endif
26187  unsigned f = face_index_on_boundary[i];
26188  Flat_packed_unsigneds.push_back(f);
26189 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26190  std::stringstream junk2;
26191  junk2 << "Face index " << f << " for associated boundary " << b;
26192  Flat_packed_unsigneds_string.push_back(junk2.str());
26193 #endif
26194  }
26195 
26196  // If the element is associated to any boundary then we should
26197  // check if the mesh has regions, if that is the case then we need
26198  // to check to which region the boundary element does belong
26199 
26200  // If the mesh has regions we should look for the element
26201  // associated to a boundary and a specified region
26202  Vector<Vector<unsigned> > associated_boundaries_and_regions;
26203  Vector<unsigned> face_index_on_boundary_and_region;
26204 
26205  // Now check for the case when we have regions in the mesh
26206  const unsigned n_regions = this->nregion();
26207  if (n_regions > 1)
26208  {
26209  // Used to count the number of faces associated with
26210  // boundary-regions
26211  unsigned counter_face_indexes_in_regions = 0;
26212  // Loop over the boundaries
26213  for (unsigned b = 0; b < nbound; b++)
26214  {
26215  // Go through each region by getting the region id
26216  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
26217  {
26218  // Get thre region id associated with the (i_reg)-th region
26219  const unsigned region_id =
26220  static_cast<unsigned>(this->Region_attribute[i_reg]);
26221 
26222  // Loop over all elements associated with the current boundary
26223  // and the i_reg-th region and check if the element is part of
26224  // any region
26225  const unsigned nele_in_region =
26226  this->nboundary_element_in_region(b, region_id);
26227  for (unsigned ee = 0; ee < nele_in_region; ee++)
26228  {
26229  // Check if the boundary-region element is the same as the
26230  // element
26231  if (ele_pt ==
26232  this->boundary_element_in_region_pt(b, region_id, ee))
26233  {
26234  // Storage for the boundary and region associated to the
26235  // element
26236  Vector<unsigned> bound_and_region(2);
26237 
26238  // Keep track of the boundaries associated to the element
26239  bound_and_region[0] = b;
26240  // Keep track of the regions associated to the element
26241  bound_and_region[1] = region_id;
26242  // Add the boundaries and regions in the storage to be
26243  // sent to other processors
26244  associated_boundaries_and_regions.push_back(bound_and_region);
26245  // Get the face index and keep track of it
26246  face_index_on_boundary_and_region.push_back(
26247  this->face_index_at_boundary_in_region(b,region_id,ee));
26248 
26249  // Increase the number of faces of the element associated
26250  // to boundary-regions
26251  counter_face_indexes_in_regions++;
26252 
26253 #ifdef PARANOID
26254  if (counter_face_indexes_in_regions > 2)
26255  {
26256  std::stringstream error_message;
26257  error_message
26258  << "A triangular element can not have more than two of its\n"
26259  << "faces on a boundary!!!\n\n";
26260  throw OomphLibError(error_message.str(),
26261  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26262  OOMPH_EXCEPTION_LOCATION);
26263  } // if (counter_face_indexes_in_regions > 2)
26264 #endif
26265 
26266  } // The element is a boundary-region element
26267 
26268  } // for (ee < nele_in_region)
26269 
26270  } // for (i_reg < n_regions)
26271 
26272  } // for (b < nbound)
26273 
26274  } // if (n_regions > 1)
26275 
26276  // Now package the info. to be sent to other processors
26277  const unsigned nassociated_boundaries_and_regions =
26278  associated_boundaries_and_regions.size();
26279  if (nassociated_boundaries_and_regions > 0)
26280  {
26281  Flat_packed_unsigneds.push_back(1);
26282 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26283  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
26284 #endif
26285 
26286  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26287 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26288  std::stringstream junk;
26289  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
26290  Flat_packed_unsigneds_string.push_back(junk.str());
26291 #endif
26292 
26293  // Package the ids of the associated boundaries, regions and the
26294  // corresponding face index for each boundary-region (if the
26295  // element is a corner element, it will have two faces
26296  // associated to the boundary-region)
26297  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26298  {
26299  const unsigned b = associated_boundaries_and_regions[i][0];
26300  Flat_packed_unsigneds.push_back(b);
26301 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26302  std::stringstream junk;
26303  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26304  Flat_packed_unsigneds_string.push_back(junk.str());
26305 #endif
26306 
26307  const unsigned r = associated_boundaries_and_regions[i][1];
26308  Flat_packed_unsigneds.push_back(r);
26309 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26310  std::stringstream junk2;
26311  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26312  Flat_packed_unsigneds_string.push_back(junk2.str());
26313 #endif
26314 
26315  const unsigned f = face_index_on_boundary_and_region[i];
26316  Flat_packed_unsigneds.push_back(f);
26317 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26318  std::stringstream junk3;
26319  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
26320  Flat_packed_unsigneds_string.push_back(junk3.str());
26321 #endif
26322  } // for (i < nassociated_boundaries_and_regions)
26323  } // if (nassociated_boundaries_and_regions > 0)
26324  else
26325  {
26326  Flat_packed_unsigneds.push_back(0);
26327 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26328  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
26329 #endif
26330  } // else if (nassociated_boundaries_and_regions > 0)
26331 
26332  }
26333  else
26334  {
26335  Flat_packed_unsigneds.push_back(0);
26336 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26337  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
26338 #endif
26339  }
26340 
26341  // ------------------------------------------------------------
26342  // Now review if the element is associated to a shared boundary
26343 
26344  // Store the shared boundaries, and therefore the face indexes
26345  // associated to the element
26346  Vector<unsigned> associated_shared_boundaries;
26347  Vector<unsigned> face_index_on_shared_boundary;
26348 
26349  // Get the shared boundaries in this processor
26350  Vector<unsigned> my_rank_shared_boundaries_ids;
26351  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26352 
26353  // Get the number of shared boundaries
26354  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26355  // Loop over the shared boundaries
26356  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26357  {
26358  // Get the boundary id
26359  const unsigned sb = my_rank_shared_boundaries_ids[i];
26360 
26361  // Get the number of elements associated to shared boundary sb
26362  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26363  for (unsigned e = 0; e < nboundary_ele; e++)
26364  {
26365  if (ele_pt == this->shared_boundary_element_pt(sb,e))
26366  {
26367  // Keep track of the boundaries associated to the element
26368  associated_shared_boundaries.push_back(sb);
26369  // Get the face index
26370  face_index_on_shared_boundary.push_back(
26371  this->face_index_at_shared_boundary(sb, e));
26372  }
26373  } // (e < nboundary_ele)
26374  } // (i < nmy_rank_shd_bnd)
26375 
26376  // If the element is associated to a shared boundary then package
26377  // all the relevant info
26378  const unsigned nassociated_shared_boundaries =
26379  associated_shared_boundaries.size();
26380  if (nassociated_shared_boundaries > 0)
26381  {
26382  Flat_packed_unsigneds.push_back(3);
26383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26384  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
26385 #endif
26386  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26387 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26388  std::stringstream junk;
26389  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
26390  Flat_packed_unsigneds_string.push_back(junk.str());
26391 #endif
26392 
26393  // Package the ids of the associated boundaries
26394  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26395  {
26396  const unsigned b = associated_shared_boundaries[i];
26397  Flat_packed_unsigneds.push_back(b);
26398 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26399  std::stringstream junk;
26400  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
26401  Flat_packed_unsigneds_string.push_back(junk.str());
26402 #endif
26403 
26404  const unsigned f = face_index_on_shared_boundary[i];
26405  Flat_packed_unsigneds.push_back(f);
26406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26407  std::stringstream junk2;
26408  junk2 << "Face index " << f << " for associated shared boundary " << b;
26409  Flat_packed_unsigneds_string.push_back(junk2.str());
26410 #endif
26411  }
26412  }
26413  else
26414  {
26415  Flat_packed_unsigneds.push_back(0);
26416 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26417  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
26418 #endif
26419  }
26420 
26421  // Now check if the element is haloed with any processor
26422 
26423  // Store the index of the haloed element with the jproc
26424  Vector<Vector<unsigned> > index_haloed(nproc);
26425 
26426  // Loop over the processors
26427  for (unsigned jproc = 0; jproc < nproc; jproc++)
26428  {
26429  // Get the number of haloed elements with jproc
26430  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26431  // Loop over the haloed elements with jproc
26432  for (unsigned ihd =0; ihd < n_haloed_jproc; ihd++)
26433  {
26434  // Is a haloed element?
26435  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26436  {
26437  // Store the haloed index with the jproc processor
26438  index_haloed[jproc].push_back(ihd);
26439  // Break the searching with the jproc processor
26440  break;
26441  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26442 
26443  } // for (ihd < n_haloed_jproc)
26444 
26445  } // for (jproc < nproc)
26446 
26447  // Send the haloed info.
26448  // Loop over the processors
26449  for (unsigned jproc = 0; jproc < nproc; jproc++)
26450  {
26451  // Is the element haloed with the jproc processor
26452  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26453  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26454 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26455  Flat_packed_unsigneds_string.push_back("The number of haloed indexes the element is with processor jproc");
26456 #endif
26457  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26458  {
26459  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26460 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26461  Flat_packed_unsigneds_string.push_back("The haloed index of the element with jproc");
26462 #endif
26463  } // for (ihd < n_index_haloed_jproc)
26464 
26465  } // for (jproc < nproc)
26466 
26467  }
26468 
26469  //======================================================================
26470  /// \short Helper function to add nodes on a new domain as a result of
26471  /// load balance
26472  //======================================================================
26473  template <class ELEMENT>
26476  Vector<Vector<FiniteElement*> >&f_halo_ele_pt,
26477  Vector<Node*> &new_nodes_on_domain,
26478  Node* nod_pt)
26479  {
26480  // Attempt to add this node to the new domain
26481  const unsigned nnew_nodes_on_domain= new_nodes_on_domain.size();
26482  const unsigned new_added_node_index =
26483  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26484 
26485  // If it was added then the new index should match the size of the storage
26486  if (new_added_node_index == nnew_nodes_on_domain)
26487  {
26488  Flat_packed_unsigneds.push_back(1);
26489 
26490 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26491  std::stringstream junk;
26492  junk << "Node needs to be constructed [size="
26493  << Flat_packed_unsigneds.size() << "]; last entry: "
26495  Flat_packed_unsigneds_string.push_back(junk.str());
26496 #endif
26497 
26498  // This helper function gets all the required information for the
26499  // specified node and stores it into MPI-sendable information
26500  // so that a new copy can be made on the receiving process
26501  get_required_nodal_information_load_balance_helper(f_halo_ele_pt,
26502  iproc,
26503  nod_pt);
26504  }
26505  else // It was already added
26506  {
26507  Flat_packed_unsigneds.push_back(0);
26508 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26509  std::stringstream junk;
26510  junk << "Node was already added [size="
26511  << Flat_packed_unsigneds.size() << "]; last entry: "
26513 
26514  Flat_packed_unsigneds_string.push_back(junk.str());
26515 #endif
26516 
26517  // This node has been already added, so tell the other process
26518  // its index in the equivalent storage
26519  Flat_packed_unsigneds.push_back(new_added_node_index);
26520 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26521  Flat_packed_unsigneds_string.push_back("new added node index");
26522 #endif
26523  }
26524 
26525  }
26526 
26527  //======start of get_required_nodal_information_load_balance_helper=======
26528  /// Helper function to get the required nodal information from an
26529  /// haloed node so that a fully-functional halo node (and therefore element)
26530  /// can be created on the receiving process
26531  //========================================================================
26532  template<class ELEMENT>
26535  Vector<Vector<FiniteElement*> > &f_halo_ele_pt,
26536  unsigned& iproc,
26537  Node* nod_pt)
26538  {
26539  unsigned my_rank = this->communicator_pt()->my_rank();
26540  const unsigned nproc = this->communicator_pt()->nproc();
26541 
26542  // Tell the halo copy of this node how many values there are
26543  // [NB this may be different for nodes within the same element, e.g.
26544  // when using Lagrange multipliers]
26545  unsigned n_val=nod_pt->nvalue();
26546  Flat_packed_unsigneds.push_back(n_val);
26547 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26548  Flat_packed_unsigneds_string.push_back("Number of values");
26549 #endif
26550 
26551  unsigned n_dim=nod_pt->ndim();
26552 
26553  // Default number of previous values to 1
26554  unsigned n_prev=1;
26555  if (this->Time_stepper_pt!=0)
26556  {
26557  // Add number of history values to n_prev
26558  n_prev=this->Time_stepper_pt->ntstorage();
26559  }
26560 
26561  // -----------------------------------------------------
26562  // Is the node on an original boundary?
26563  // Store the original boundaries where the node may be
26564  Vector<unsigned> original_boundaries;
26565  // Loop over the original boundaries of the mesh and check if live
26566  // on one of them
26567  const unsigned n_bnd = this->initial_shared_boundary_id();
26568  for (unsigned bb=0;bb<n_bnd;bb++)
26569  {
26570  // Which boundaries (could be more than one) is it on?
26571  if (nod_pt->is_on_boundary(bb))
26572  {
26573  original_boundaries.push_back(bb);
26574  }
26575 
26576  }
26577 
26578  const unsigned n_original_boundaries = original_boundaries.size();
26579  // Is the node on any original boundary?
26580  if (n_original_boundaries > 0)
26581  {
26582  // Indicate that the node is on an original boundary
26583  Flat_packed_unsigneds.push_back(2);
26584 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26585  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
26586 #endif
26587 
26588  Flat_packed_unsigneds.push_back(n_original_boundaries);
26589 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26590  std::stringstream junk;
26591  junk << "Node is on "<< n_original_boundaries << " original boundaries";
26592  Flat_packed_unsigneds_string.push_back(junk.str());
26593 #endif
26594 
26595  // Loop over the original boundaries the node is on
26596  for (unsigned i=0;i<n_original_boundaries;i++)
26597  {
26598  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26600  std::stringstream junk;
26601  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
26602  Flat_packed_unsigneds_string.push_back(junk.str());
26603 #endif
26604  // Get the boundary coordinate of the node
26605  Vector<double> zeta(1);
26606  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
26607  Flat_packed_doubles.push_back(zeta[0]);
26608  }
26609  }
26610  else
26611  {
26612  // Indicate that the node is NOT on an original boundary
26613  Flat_packed_unsigneds.push_back(0);
26614 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26615  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
26616 #endif
26617  }
26618 
26619  // -------------------------------------------------------
26620  // Is the node on shared boundaries?
26621  bool node_on_shared_boundary = false;
26622  // Loop over the shared boundaries with the iproc processors and
26623  // check if live on one of them
26624  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26625  for (unsigned bb=0;bb<n_shd_bnd;bb++)
26626  {
26627  // Get the boundary id
26628  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26629  // Which boundaries (could be more than one) is it on?
26630  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26631  {
26632  node_on_shared_boundary = true;
26633  break;
26634  }
26635  }
26636 
26637  // If the node live on any of the shared boundaries with the iproc
26638  // processor then just get the node number according to the
26639  // sorted_shared_boundary_node_pt() scheme and send it accross
26640  if (node_on_shared_boundary)
26641  {
26642  Flat_packed_unsigneds.push_back(1);
26643 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26644  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26645 #endif
26646 
26647  // Store the shared boundaries where the node is on
26648  Vector<unsigned> shd_boundaries;
26649  // Loop over the shared boundaries with the iproc processor
26650  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26651  {
26652  // Get the boundary id
26653  const unsigned i_bnd =
26654  this->shared_boundaries_ids(my_rank, iproc, bb);
26655  // Which boundaries (could be more than one) is it on?
26656  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26657  {
26658  shd_boundaries.push_back(i_bnd);
26659  }
26660  }
26661 
26662  // Get the number of shared boundaries the node is on
26663  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26664  // Send the number of shared boundaries the node is on
26665  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26666 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26667  std::stringstream junk;
26668  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
26669  Flat_packed_unsigneds_string.push_back(junk.str());
26670 #endif
26671 
26672  // Loop over the shared boundaries to send their ids
26673  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
26674  {
26675  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26676 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26677  std::stringstream junk;
26678  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26679  Flat_packed_unsigneds_string.push_back(junk.str());
26680 #endif
26681  }
26682 
26683  // Given that the node is on at least one boundary get the index
26684  // of the node in one of the boundaries and send this index
26685  unsigned shared_boundary_id = shd_boundaries[0];
26686  // Get the number of nodes on the given shared boundary
26687  const unsigned n_nodes_on_shared_boundary =
26688  nsorted_shared_boundary_node(shared_boundary_id);
26689  // Store the index of the node on the shared boundary
26690  unsigned index_node_on_shared_boundary;
26691 #ifdef PARANOID
26692  // Flag to know if the node has been found
26693  bool found_index_node_on_shared_boundary = false;
26694 #endif
26695  // Loop over the nodes on the shared boundary to find the node
26696  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26697  {
26698  // Get the i-th node on the shared boundary
26699  Node* shared_node_pt =
26700  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26701  // Is the node we are looking for
26702  if (shared_node_pt == nod_pt)
26703  {
26704  // Store the index
26705  index_node_on_shared_boundary = i;
26706 #ifdef PARANOID
26707  // Mark as found
26708  found_index_node_on_shared_boundary = true;
26709 #endif
26710  break; // break
26711  }
26712 
26713  } // for (i < nnodes_on_shared_boundary)
26714 
26715 #ifdef PARANOID
26716  if (!found_index_node_on_shared_boundary)
26717  {
26718  std::ostringstream error_message;
26719  error_message
26720  <<"The index of the node on boundary ("
26721  <<shared_boundary_id<<") was not found.\n"
26722  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26723  <<nod_pt->x(1)<<").\n";
26724  throw OomphLibError(
26725  error_message.str(),
26726  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26727  OOMPH_EXCEPTION_LOCATION);
26728  }
26729 #endif
26730  // Send the index of the node on the shared boundary
26731  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
26732 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26733  std::stringstream junk2;
26734  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
26735  <<index_node_on_shared_boundary;
26736  Flat_packed_unsigneds_string.push_back(junk2.str());
26737 #endif
26738 
26739  } // if (node_on_shared_boundary)
26740  else
26741  {
26742  // The node is not on a shared boundary
26743  Flat_packed_unsigneds.push_back(0);
26744 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26745  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
26746 #endif
26747  }
26748 
26749  // ----------------------------------------------------------------
26750  // Is the node on any shared boundary where the receiver processor
26751  // is not involved?
26752 
26753  // Now check if the node is on a shared boundary created by the
26754  // current processor (my_rank) and other processor different that
26755  // the iproc processor. This info. will help to complete the sending
26756  // of halo(ed) information between processors
26757 
26758  // Flag to know if the node is on a shared boundary with other
26759  // processor
26760  bool node_on_shared_boundary_with_other_processors = false;
26761  // Count the number of other shared boundaries it could be on
26762  unsigned nshared_boundaries_with_other_processors_have_node = 0;
26763 
26764  // Loop over the shared boundaries of the sent processor (my_rank)
26765  // and other processors (jproc)
26766  for (unsigned jproc = 0; jproc < nproc; jproc++)
26767  {
26768  // Do not search with the iproc processor, that was done before
26769  // above
26770  if (jproc != iproc)
26771  {
26772  // Get the number of shared boundaries with the jproc processor
26773  const unsigned n_jshd_bnd =
26774  this->nshared_boundaries(my_rank, jproc);
26775  // Loop over the shared boundaries
26776  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
26777  {
26778  // Get the boundary id
26779  const unsigned j_shd_bnd =
26780  this->shared_boundaries_ids(my_rank, jproc, bb);
26781  // Is the node part of this boundary?
26782  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26783  {
26784 // DEBP("Sending to");
26785 // DEBP(iproc);
26786 // DEBP("Pair of procs where other shared");
26787 // DEBP(my_rank);
26788 // DEBP(jproc);
26789 // DEBP(i_bnd);
26790  node_on_shared_boundary_with_other_processors = true;
26791  // Increase the counter for the number of shared boundaries
26792  // with other processors the node is on
26793  nshared_boundaries_with_other_processors_have_node++;
26794  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
26795 
26796  } // for (bb<n_jshd_bnd)
26797 
26798  } // if (jproc != iproc)
26799 
26800  } // for (jproc < nproc)
26801 
26802  // If the node is on a shared boundary with another processor
26803  // (my_rank, jproc), then send the flag and look for the info.
26804  if (node_on_shared_boundary_with_other_processors)
26805  {
26806  Flat_packed_unsigneds.push_back(4);
26807 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26808  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
26809 #endif
26810 
26811  // The number of packages of information that will be sent to the
26812  // "iproc" processor. This helps to know how many packages of data
26813  // read from the received processor
26814  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
26815 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26816  std::stringstream junk;
26817  junk << "Number of other shared boundaries that the node is on: "
26818  << nshared_boundaries_with_other_processors_have_node;
26819  Flat_packed_unsigneds_string.push_back(junk.str());
26820 #endif
26821 
26822  // Counter to ensure that the correct number of data has been sent
26823  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
26824  // Loop over the shared boundaries with other processors and get:
26825  // 1) The processors defining the shared boundary
26826  // 2) The shared boundary id
26827  // 3) The index of the node on the shared boundary
26828  Vector<unsigned> other_processor_1;
26829  Vector<unsigned> other_processor_2;
26830  Vector<unsigned> shd_bnd_ids;
26831  Vector<unsigned> indexes;
26832  // Loop over the processors again
26833  for (unsigned jproc = 0; jproc < nproc; jproc++)
26834  {
26835  // Do not search with the iproc processor, that was done before
26836  // above
26837  if (jproc != iproc)
26838  {
26839  // Get the number of shared boundaries with the jproc
26840  // processor
26841  const unsigned n_jshd_bnd =
26842  this->nshared_boundaries(my_rank, jproc);
26843  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
26844  {
26845  // Get the boundary id
26846  const unsigned j_shd_bnd =
26847  this->shared_boundaries_ids(my_rank, jproc, bb);
26848  // Is the node part of this boundary?
26849  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26850  {
26851  // Include the first processor
26852  other_processor_1.push_back(my_rank);
26853  // Include the second processor
26854  other_processor_2.push_back(jproc);
26855  // Include the shared boundary id
26856  shd_bnd_ids.push_back(j_shd_bnd);
26857  // Increase the counter for found shared boundaries with
26858  // other processors
26859  counter_shd_bnd_with_other_procs_have_node++;
26860  }
26861 
26862  } // for (bb < nshared_bnd)
26863 
26864  } // if (jproc != iproc)
26865 
26866  } // for (jproc < nproc)
26867 
26868  // Get the indexes of the node on all the shared boundaries where
26869  // it was found
26870  const unsigned n_other_processors = other_processor_1.size();
26871  // Loop over the processors where the node was found
26872  for (unsigned i = 0; i < n_other_processors; i++)
26873  {
26874  // Get the shared boundary id
26875  unsigned shd_bnd_id = shd_bnd_ids[i];
26876  // Get the number of nodes on that shared boundary
26877  const unsigned n_nodes_on_shd_bnd =
26878  nsorted_shared_boundary_node(shd_bnd_id);
26879 
26880 #ifdef PARANOID
26881  bool found_index_node_on_shared_boundary = false;
26882 #endif
26883  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
26884  {
26885  // Get the i-th shared boundary node
26886  Node* shared_node_pt =
26887  sorted_shared_boundary_node_pt(shd_bnd_id, i);
26888  // Is the same node?
26889  if (shared_node_pt == nod_pt)
26890  {
26891 // DEBP(i_node);
26892 // DEBP(nod_pt->x(0));
26893 // DEBP(nod_pt->x(1));
26894  // Include the index of the node
26895  indexes.push_back(i);
26896 #ifdef PARANOID
26897  // Mark as found the node
26898  found_index_node_on_shared_boundary = true;
26899 #endif
26900  break;
26901  } // if (shared_node_pt == nod_pt)
26902 
26903  } // for (i < n_nodes_on_shd_bnd)
26904 
26905 #ifdef PARANOID
26906  if (!found_index_node_on_shared_boundary)
26907  {
26908  std::ostringstream error_message;
26909  error_message
26910  <<"The index of the node on boundary ("
26911  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
26912  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26913  <<nod_pt->x(1)<<").\n";
26914  throw OomphLibError(
26915  error_message.str(),
26916  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26917  OOMPH_EXCEPTION_LOCATION);
26918  }
26919 #endif
26920  } // for (i < n_other_processors)
26921 
26922  // Now send the info. but first check that the number of found
26923  // nodes be the same that the previously found shared boundaries
26924  // with the node
26925 #ifdef PARANOID
26926  if (counter_shd_bnd_with_other_procs_have_node !=
26927  nshared_boundaries_with_other_processors_have_node)
26928  {
26929  std::ostringstream error_message;
26930  error_message
26931  <<"The number of shared boundaries where the node is on "
26932  <<"is different:\n"
26933  << "nshared_boundaries_with_other_processors_have_node: ("
26934  << nshared_boundaries_with_other_processors_have_node
26935  << ")\n"
26936  << "counter_shd_bnd_with_other_procs_have_node: ("
26937  << counter_shd_bnd_with_other_procs_have_node
26938  << ")\n";
26939  throw OomphLibError(
26940  error_message.str(),
26941  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26942  OOMPH_EXCEPTION_LOCATION);
26943  } // if (counter_shd_bnd_with_other_procs_have_node !=
26944  // nshared_boundaries_with_other_processors_have_node)
26945 #endif
26946 
26947  // Loop over the info. to send it
26948  for (unsigned i = 0; i < n_other_processors; i++)
26949  {
26950  Flat_packed_unsigneds.push_back(other_processor_1[i]);
26951 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26952  std::stringstream junk1;
26953  junk1 << "Processor where the other shared boundary "
26954  << "has the node: " << other_processor_1[i];
26955  Flat_packed_unsigneds_string.push_back(junk1.str());
26956 #endif
26957 
26958  Flat_packed_unsigneds.push_back(other_processor_2[i]);
26959 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26960  std::stringstream junk2;
26961  junk2 << "Processor where the other shared boundary "
26962  << "has the node: " << other_processor_2[i];
26963  Flat_packed_unsigneds_string.push_back(junk2.str());
26964 #endif
26965 
26966  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
26967 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26968  std::stringstream junk3;
26969  junk3 << "Other shared boundary id where the node is on"
26970  << boundaries[i];
26971  Flat_packed_unsigneds_string.push_back(junk3.str());
26972 #endif
26973 
26974  Flat_packed_unsigneds.push_back(indexes[i]);
26975 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26976  std::stringstream junk4;
26977  junk4 << "Node index on other shared boundary "
26978  <<boundaries[i] << " is "
26979  << indexes[i];
26980  Flat_packed_unsigneds_string.push_back(junk4.str());
26981 #endif
26982 
26983  } // for (i < n_other_processors)
26984 
26985  } // if (node_on_shared_boundary_with_other_processors)
26986  else
26987  {
26988  Flat_packed_unsigneds.push_back(0);
26989 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26990  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
26991 #endif
26992  } // else if (node_on_shared_boundary_with_other_processors)
26993 
26994  // It may still be possible that the node be shared with the
26995  // processor that receives the info. but it is neither on shared
26996  // boundary with the receiver processor nor on a shared boundary
26997  // with others processors. Think in the next case:
26998 
26999  // |-----|-----| - The elements in processor 3 need to be sent to
27000  // | 4 | 3 | processor 1, and that is all
27001  // |-----*-----| - When processor 1 receives the data from node (*)
27002  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
27003  // |-----|-----| that the node is also on the shared boundary that
27004  // processor 1 and 2 or processor 1 and 4 share.
27005 
27006  // This problem become even worse if there would be more processors
27007  // between processor 3 and 2, or/and processor 3 and 4. Think in
27008  // triangles sharing the node (*)
27009 
27010  // To solve this check if the node that we are trying to send is
27011  // part of the halo elements of the curreent processor (my_rank)
27012  // with any other processor (we need to check with all the
27013  // processors and not just with the processors to which we will send
27014  // to cover more cases)
27015 
27016  // Store the halo element number with jproc where the node was found
27017  Vector<Vector<unsigned> > halo_element_number(nproc);
27018  // Store the node number on the halo element where the node was found
27019  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27020 
27021  // Loop over the processor
27022  for (unsigned jproc = 0; jproc < nproc; jproc++)
27023  {
27024  // Get the number of halo elements with the jproc processor
27025  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27026  // Loop over the halo elements
27027  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27028  {
27029  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27030  // Get the number of nodes of the halo element
27031  const unsigned n_node = halo_ele_pt->nnode();
27032  // Loop over the nodes
27033  for (unsigned n = 0; n < n_node; n++)
27034  {
27035  // Is the node part of the ih-th halo element with jproc
27036  if (nod_pt == halo_ele_pt->node_pt(n))
27037  {
27038  halo_element_number[jproc].push_back(jh);
27039  halo_node_number_in_halo_element[jproc].push_back(n);
27040  // break with the nodes, no need to look for more nodes in
27041  // the element
27042  break;
27043  } // if (nod_pt == halo_ele_pt->node_pt(n))
27044 
27045  } // for (n < n_node)
27046 
27047  } // for (jh < n_halo_jproc)
27048 
27049  } // for (jproc < nproc)
27050 
27051  // Send the info. related with if the node is on halo elements with
27052  // any processor
27053 
27054  // Loop over the processors
27055  for (unsigned jproc = 0; jproc < nproc; jproc++)
27056  {
27057  // Get the number of halo elements with jproc processor where the
27058  // node is
27059  const unsigned n_jproc_halo_ele_node_is_on =
27060  halo_element_number[jproc].size();
27061  // Send the number of halo elements with jproc where the node is
27062  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27063 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27064  std::stringstream junk5;
27065  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27066  << "elements with " << jproc << "-th processor";
27067  Flat_packed_unsigneds_string.push_back(junk5.str());
27068 #endif
27069  // Send the halo elements indexes (which will be haloed elements
27070  // indexes in the receiver processor), and the indexes of the
27071  // nodes in each halo element
27072  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27073  {
27074  // The halo element index
27075  const unsigned halo_element_index = halo_element_number[jproc][i];
27076  Flat_packed_unsigneds.push_back(halo_element_index);
27077 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27078  std::stringstream junk6;
27079  junk6 << "Halo element index is ("<<halo_element_index
27080  <<") with processor ("<<jproc<<")";
27081  Flat_packed_unsigneds_string.push_back(junk6.str());
27082 #endif
27083  // The node index on the halo element
27084  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27085  Flat_packed_unsigneds.push_back(node_index);
27086 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27087  std::stringstream junk7;
27088  junk7 << "The node index on the halo element index is ("
27089  << node_index;
27090  Flat_packed_unsigneds_string.push_back(junk7.str());
27091 #endif
27092 
27093  } // for (i < n_jproc_halo_ele_node_is_on)
27094 
27095  } // for (jproc < nproc)
27096 
27097  // Now check if it is required to send the info. of the node. If the
27098  // node is not on a shared boundary with the iproc processor then we
27099  // need to send the info.
27100 
27101  // Flag to indicate if it is on a halo element with the iproc
27102  // processor. If this flag is true then there is no need to send the
27103  // info. to create the node, in the receiver processor the info is
27104  // copied from the indicated haloed element-node
27105  bool on_halo_element_with_iproc_processor = false;
27106  if (halo_element_number[iproc].size() > 0)
27107  {
27108  on_halo_element_with_iproc_processor = true;
27109  } // if (halo_element_number[iproc].size() > 0)
27110 
27111  // if (!node_on_shared_boundary)
27112  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27113  {
27114  // Send all the info. to create it
27115 
27116  // Is the Node algebraic? If so, send its ref values and
27117  // an indication of its geometric objects if they are stored
27118  // in the algebraic mesh
27119  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
27120  if (alg_nod_pt!=0)
27121  {
27122  // The external mesh should be algebraic
27123  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
27124 
27125  // Get default node update function ID
27126  unsigned update_id=alg_nod_pt->node_update_fct_id();
27127  Flat_packed_unsigneds.push_back(update_id);
27128 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27129  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27130 #endif
27131 
27132  // Get reference values at default...
27133  unsigned n_ref_val=alg_nod_pt->nref_value();
27134  Flat_packed_unsigneds.push_back(n_ref_val);
27135 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27136  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27137 #endif
27138  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
27139  {
27140  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27141  }
27142 
27143  // Access geometric objects at default...
27144  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
27145  Flat_packed_unsigneds.push_back(n_geom_obj);
27146 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27147  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27148 #endif
27149  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
27150  {
27151  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
27152 
27153  // Check this against the stored geometric objects in mesh
27154  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
27155 
27156  // Default found index to zero
27157  unsigned found_geom_object=0;
27158  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
27159  {
27160  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
27161  {
27162  found_geom_object=i_list;
27163  }
27164  }
27165  Flat_packed_unsigneds.push_back(found_geom_object);
27166 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27167  Flat_packed_unsigneds_string.push_back("Found geom object");
27168 #endif
27169  }
27170  } // (if alg_nod_pt!=0)
27171 
27172  // Is it a SolidNode?
27173  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
27174  if (solid_nod_pt!=0)
27175  {
27176  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
27177  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
27178  {
27179  for (unsigned t=0;t<n_prev;t++)
27180  {
27181  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
27182  value(t,i_val));
27183  }
27184  }
27185 
27186  Vector<double> values_solid_node;
27187  solid_nod_pt->add_values_to_vector(values_solid_node);
27188  const unsigned nvalues_solid_node = values_solid_node.size();
27189  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27190 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27191  std::stringstream junk;
27192  junk << "Number of values solid node: "
27193  << nvalues_solid_node;
27194  Flat_packed_unsigneds_string.push_back(junk.str());
27195 #endif
27196  for (unsigned i = 0; i < nvalues_solid_node; i++)
27197  {
27198  Flat_packed_doubles.push_back(values_solid_node[i]);
27199  }
27200  }
27201 
27202  // Finally copy info required for all node types
27203  for (unsigned i_val=0;i_val<n_val;i_val++)
27204  {
27205  for (unsigned t=0;t<n_prev;t++)
27206  {
27207  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
27208  }
27209  }
27210 
27211  // Now do positions
27212  for (unsigned idim=0;idim<n_dim;idim++)
27213  {
27214  for (unsigned t=0;t<n_prev;t++)
27215  {
27216  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
27217 // DEBP(nod_pt->x(t,idim));
27218  }
27219  }
27220 
27221  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27222 
27223  }
27224 
27225  //======================================================================
27226  /// \short Helper function to create elements on the loop
27227  /// process based on the info received in
27228  /// send_and_received_elements_nodes_info
27229  //======================================================================
27230  template <class ELEMENT>
27232  unsigned& iproc,
27233  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27234  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27235  &received_old_haloed_element_pt,
27236  Vector<FiniteElement*> &new_elements_on_domain,
27237  Vector<Node*> &new_nodes_on_domain,
27238  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27239  &other_proc_shd_bnd_node_pt,
27240  Vector<Vector<Vector<unsigned> > > &global_node_names,
27241  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27242  Vector<Node*> &global_shared_node_pt)
27243  {
27244 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27246  << " Bool: New element needs to be constructed "
27248  << std::endl;
27249 #endif
27250 
27252  {
27253  // Create a new element from the communicated values
27254  // and coords from the process that located zeta
27255  GeneralisedElement *new_el_pt= new ELEMENT;
27256 
27257  // Add the new element to the mesh - Do not add the element yet
27258  // since no retained elements still need to be deleted
27259  // this->add_element_pt(new_el_pt);
27260 
27261  // Cast to the FE pointer
27262  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
27263 
27264  // Add the element to the new elements in the domain container
27265  new_elements_on_domain.push_back(f_el_pt);
27266 
27267  // Set any additional information for the element
27268  this->add_element_load_balance_helper(iproc,
27269  received_old_haloed_element_pt,
27270  f_el_pt);
27271 
27272  // Add nodes to the new element
27273  unsigned n_node=f_el_pt->nnode();
27274  for (unsigned j=0;j<n_node;j++)
27275  {
27276  Node* new_nod_pt=0;
27277 
27278  // Call the add halo node helper function
27279  add_received_node_load_balance_helper(new_nod_pt,
27280  f_haloed_ele_pt,
27281  received_old_haloed_element_pt,
27282  new_nodes_on_domain,
27283  other_proc_shd_bnd_node_pt,
27284  iproc, j, f_el_pt,
27285  global_node_names,
27286  node_name_to_global_index,
27287  global_shared_node_pt);
27288  }
27289  }
27290  else // the element already exists
27291  {
27292 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27293  oomph_info
27294  << "Rec:" << Counter_for_flat_packed_unsigneds
27295  << " Index of existing element "
27297  << std::endl;
27298 #endif
27299 
27300  // Incrase the index, we do anything else with the element
27302 
27303  } // else the element already exists
27304 
27305  }
27306 
27307  //========start of add_element_load_balance_helper=====================
27308  /// \short Helper function to create elements on the loop
27309  /// process based on the info received in
27310  /// send_and_received_elements_nodes_info
27311  /// This function is in charge of verify if the element is associated
27312  /// to a boundary and associate to it if that is the case
27313  //======================================================================
27314  template<class ELEMENT>
27316  add_element_load_balance_helper(const unsigned &iproc,
27317  Vector<Vector<std::map<
27318  unsigned,FiniteElement*> > >
27319  &received_old_haloed_element_pt,
27320  FiniteElement* ele_pt)
27321  {
27322  // Get the number of processors
27323  const unsigned nproc = this->communicator_pt()->nproc();
27324 
27325 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27327  << " Bool: Element is associated to a boundary "
27329  << std::endl;
27330 #endif
27331 
27332  // Is on an original boundary?
27333  const unsigned is_on_original_boundary =
27335  if (is_on_original_boundary == 1)
27336  {
27337 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27338  oomph_info
27339  << "Rec:" << Counter_for_flat_packed_unsigneds
27340  << " How many boundaries are associated with the element "
27342  << std::endl;
27343 #endif
27344  // Number of boundaries the element is associated with
27345  const unsigned nassociated_boundaries =
27347 
27348  // Loop over the associated boundaries
27349  for (unsigned b = 0; b < nassociated_boundaries; b++)
27350  {
27351 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27352  oomph_info
27353  << "Rec:" << Counter_for_flat_packed_unsigneds
27354  << " Boundary associated to the element "
27356  << std::endl;
27357 #endif
27358 
27359  // The boundary id
27360  const unsigned bnd =
27362 
27363 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27364  oomph_info
27365  << "Rec:" << Counter_for_flat_packed_unsigneds
27366  << " Face index of the element "
27368  << std::endl;
27369 #endif
27370 
27371  // The face index
27372  const unsigned face_index =
27374 
27375  // Associate the element with the boundary and establish as many
27376  // face indexes it has
27377  this->Boundary_element_pt[bnd].push_back(ele_pt);
27378  this->Face_index_at_boundary[bnd].push_back(face_index);
27379 
27380  } // (b < nassociated_boundaries)
27381 
27382  // Here read the info. regarding the boundary-region of the element
27383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27385  << " Bool: Element is associated to a boundary-region "
27387  << std::endl;
27388 #endif
27389 
27390  // Is the element associated to a boundary-region?
27392  {
27393 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27394  oomph_info
27395  << "Rec:" << Counter_for_flat_packed_unsigneds
27396  << " How many boundaries-regions are associated with the element "
27398  << std::endl;
27399 #endif
27400  // Number of boundary-regions the element is associated
27401  const unsigned nassociated_boundaries_and_regions =
27403 
27404  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27405  {
27406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27407  oomph_info
27408  << "Rec:" << Counter_for_flat_packed_unsigneds
27409  << " Boundary associated to the element "
27411  << std::endl;
27412 #endif
27413  // The boundary id
27414  const unsigned bnd =
27416 
27417 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27418  oomph_info
27419  << "Rec:" << Counter_for_flat_packed_unsigneds
27420  << " Region associated to the element "
27422  << std::endl;
27423 #endif
27424  // The region id
27425  const unsigned region =
27427 
27428 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27429  oomph_info
27430  << "Rec:" << Counter_for_flat_packed_unsigneds
27431  << " Face index of the element in boundary-region "
27433  << std::endl;
27434 #endif
27435  const unsigned face_index =
27437 
27438  // Associate the element with the boundary-regions and establish
27439  // as many face indexes it has
27440  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27441  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
27442 
27443  } // for (br < nassociated_boundaries_and_regions)
27444 
27445  } // Is the element associated with a boundary-region?
27446 
27447  } // The element is associated with an original boundary
27448 #ifdef PARANOID
27449  else
27450  {
27451  if (is_on_original_boundary != 0)
27452  {
27453  std::ostringstream error_message;
27454  error_message
27455  <<"The current element is not on an original boundary, this should\n"
27456  <<"be indicated by a zero flag. However, the read value for\n"
27457  <<"that flag is ("<<is_on_original_boundary<<").\n\n";
27458  throw OomphLibError(
27459  error_message.str(),
27460  "RefineableTriangleMesh::add_element_load_balance_helper()",
27461  OOMPH_EXCEPTION_LOCATION);
27462  } // if (is_on_shared_boundary != 0)
27463  }
27464 #endif
27465 
27466 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27468  << " Bool: Element is associated to a shared boundary "
27470  << std::endl;
27471 #endif
27472 
27473  // Is the element a shared boundary element?
27474  const unsigned is_on_shared_boundary =
27476  if (is_on_shared_boundary == 3)
27477  {
27478 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27479  oomph_info
27480  << "Rec:" << Counter_for_flat_packed_unsigneds
27481  << " How many shared boundaries are associated with the element "
27483  << std::endl;
27484 #endif
27485 
27486  // The number of shared boundaries the element is associated
27487  const unsigned nassociated_shared_boundaries =
27489 
27490  // Loop over the associated shared boundaries
27491  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27492  {
27493 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27494  oomph_info
27495  << "Rec:" << Counter_for_flat_packed_unsigneds
27496  << " Shared boundary associated to the element "
27498  << std::endl;
27499 #endif
27500  const unsigned bnd =
27502 
27503 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27504  oomph_info
27505  << "Rec:" << Counter_for_flat_packed_unsigneds
27506  << " Face index of the element associated to the shared boundary "
27508  << std::endl;
27509 #endif
27510 
27511  const unsigned face_index =
27513 
27514  this->add_shared_boundary_element(bnd, ele_pt);
27515  this->add_face_index_at_shared_boundary(bnd, face_index);
27516 
27517  } // (b < nassociated_shared_boundaries)
27518 
27519  } // The element is associted with a shared boundary
27520 #ifdef PARANOID
27521  else
27522  {
27523  if (is_on_shared_boundary != 0)
27524  {
27525  std::ostringstream error_message;
27526  error_message
27527  <<"The current element is not on a shared boundary, this should\n"
27528  <<"be indicated by a zero flag. However, the read value for\n"
27529  <<"that flag is ("<<is_on_shared_boundary<<").\n\n";
27530  throw OomphLibError(
27531  error_message.str(),
27532  "RefineableTriangleMesh::add_element_load_balance_helper()",
27533  OOMPH_EXCEPTION_LOCATION);
27534  } // if (is_on_shared_boundary != 0)
27535  }
27536 #endif
27537 
27538  // Now check if the element is a haloed element in the sender
27539  // processor with any other processor
27540 
27541  // Loop over the processors
27542  for (unsigned jproc = 0; jproc < nproc; jproc++)
27543  {
27544 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27546  << " Bool: Number of haloed indexes of the element with the "
27547  << jproc << " processor: "
27549  << std::endl;
27550 #endif
27551  // Is the element haloed with the jproc processor
27552  const unsigned n_index_haloed_jproc =
27554  // Loop over the number of haloed indexes
27555  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27556  {
27557 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27559  << " Bool: The haloed element index with the "
27560  << jproc << " processor: "
27562  << std::endl;
27563 #endif
27564  const unsigned haloed_index =
27566 
27567  // Set the halod element in the proper storage
27568  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27569 
27570  } // for (ihd < n_index_haloed_jproc)
27571 
27572  } // for (jproc < nproc)
27573 
27574  }
27575 
27576  //======================================================================
27577  /// \short Helper function to add a new node from load balance
27578  //======================================================================
27579  template <class ELEMENT>
27583  &f_haloed_ele_pt,
27584  Vector<Vector<std::map<
27585  unsigned,FiniteElement*> > >
27586  &received_old_haloed_element_pt,
27587  Vector<Node*> &new_nodes_on_domain,
27589  std::map<unsigned, Node*> > > >
27590  &other_proc_shd_bnd_node_pt,
27591  unsigned& iproc,
27592  unsigned& node_index,
27593  FiniteElement* const &new_el_pt,
27595  &global_node_names,
27596  std::map<Vector<unsigned>, unsigned>
27597  &node_name_to_global_index,
27598  Vector<Node*> &global_shared_node_pt)
27599  {
27600  // Given the node, received information about it from processor
27601  // iproc, construct it on the current process
27602 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27604  << " Bool: New node needs to be constructed "
27606  << std::endl;
27607 #endif
27609  {
27610  // Construct a new node based upon sent information, or copy a node
27611  // from one of the shared boundaries
27612  construct_new_node_load_balance_helper(new_nod_pt,
27613  f_haloed_ele_pt,
27614  received_old_haloed_element_pt,
27615  new_nodes_on_domain,
27616  other_proc_shd_bnd_node_pt,
27617  iproc,
27618  node_index,
27619  new_el_pt,
27620  global_node_names,
27621  node_name_to_global_index,
27622  global_shared_node_pt);
27623  }
27624  else
27625  {
27626 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27628  << " Index of existing halo node "
27630  << std::endl;
27631 #endif
27632  // The node already exist, copy it from the indicated position
27633 
27634  // Get the node's index, and copy it
27635  new_nod_pt = new_nodes_on_domain[
27637 
27638  // Set the node in the current element
27639  new_el_pt->node_pt(node_index) = new_nod_pt;
27640 
27641  }
27642 
27643  }
27644 
27645  //============start_of_construct_new_node_load_balance_helper()=========
27646  /// \short Helper function which constructs a new node (on an
27647  /// element) with the information sent from the load balance
27648  /// process
27649  //======================================================================
27650  template<class ELEMENT>
27653  Node* &new_nod_pt,
27654  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27655  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27656  &received_old_haloed_element_pt,
27657  Vector<Node*> &new_nodes_on_domain,
27658  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27659  &other_proc_shd_bnd_node_pt,
27660  unsigned& iproc, unsigned& node_index,
27661  FiniteElement* const &new_el_pt,
27662  Vector<Vector<Vector<unsigned> > > &global_node_names,
27663  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27664  Vector<Node*> &global_shared_node_pt)
27665  {
27666  // Get the number of processors
27667  const unsigned nproc = this->communicator_pt()->nproc();
27668  // Get the rank of the current processor
27669  const unsigned my_rank = this->communicator_pt()->my_rank();
27670 
27671  //The first entry indicates the number of values at this new Node
27672  //(which may be different across the same element e.g. Lagrange multipliers)
27673 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27675  << " Number of values of external halo node "
27677  << std::endl;
27678 #endif
27680 
27681  // Null TimeStepper for now
27682  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
27683  // Default number of previous values to 1
27684  unsigned n_prev=time_stepper_pt->ntstorage();
27685 
27686  // ------------------------------------------------------
27687  // Check if the node is on an original boundary
27688 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27690  << " Is the node on an original boundary "
27692  << std::endl;
27693 #endif
27694 
27695  // Flag to indicate if the node is on original boundaries
27696  const unsigned node_on_original_boundaries =
27698 
27699  // Store the original boundaries where the node is on
27700  Vector<unsigned> original_boundaries_node_is_on;
27701  // Store the zeta coordinates of the node on the original boundaries
27702  Vector<double> zeta_coordinates;
27703  // Store the number of original boundaries the node is on
27704  unsigned n_original_boundaries_node_is_on = 0;
27705 
27706  if (node_on_original_boundaries==2)
27707  {
27708  // How many original boundaries does the node live on?
27709 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27711  << " Number of boundaries the node is on: "
27713  << std::endl;
27714 #endif
27715  n_original_boundaries_node_is_on =
27717 
27718  // Resize the containers
27719  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27720  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27721 
27722  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
27723  {
27724  // Boundary number
27725 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27727  << " Node is on boundary "
27729  << std::endl;
27730 #endif
27731  original_boundaries_node_is_on[i] =
27733  zeta_coordinates[i] =
27735  }
27736 
27737  } // if (node_on_original_boundaries==2)
27738 #ifdef PARANOID
27739  else
27740  {
27741  if (node_on_original_boundaries != 0)
27742  {
27743  std::ostringstream error_message;
27744  error_message
27745  <<"The current node is not on an original boundary, this should\n"
27746  <<"be indicated by a zero flag. However, the read value for\n"
27747  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
27748  throw OomphLibError(
27749  error_message.str(),
27750  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27751  OOMPH_EXCEPTION_LOCATION);
27752  } // if (node_on_original_boundaries != 0)
27753  }
27754 #endif
27755 
27756  // --------------------------------------------------------------
27757  // Check if the node was on a shared boundary with the iproc
27758  // processor
27759 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27761  << " Is node on shared boundary? "
27763  << std::endl;
27764 #endif
27765  const unsigned is_node_on_shared_boundary =
27767  if (is_node_on_shared_boundary == 1)
27768  {
27769  // How many shared boundaries does the node live on?
27770 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27772  << " Number of boundaries the node is on: "
27774  << std::endl;
27775 #endif
27776  const unsigned n_shd_bnd_node_is_on =
27778  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
27779  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
27780  {
27781  // Shared boundary number
27782 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27784  << " Node is on boundary "
27786  << std::endl;
27787 #endif
27788  shd_bnds_node_is_on[i] =
27790  }
27791 
27792  // Get the index of the node on the shared boundary
27793 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27795  << " Index of node on boundary "
27797  << std::endl;
27798 #endif
27799  // Get the node index of the node on the shared boundary
27800  unsigned node_index_on_shared_boundary =
27802 
27803  // Get the pointer to the node with the received info.
27804  new_nod_pt =
27805  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
27806  node_index_on_shared_boundary);
27807 
27808  } // if (is_node_on_shared_boundary == 1)
27809 #ifdef PARANOID
27810  else
27811  {
27812  if (is_node_on_shared_boundary != 0)
27813  {
27814  std::ostringstream error_message;
27815  error_message
27816  <<"The current node is not on a shared boundary, this should\n"
27817  <<"be indicated by a zero flag. However, the read value for\n"
27818  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
27819  throw OomphLibError(
27820  error_message.str(),
27821  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27822  OOMPH_EXCEPTION_LOCATION);
27823  } // if (node_on_shared_boundary != 0)
27824  }
27825 #endif
27826 
27827  // ------------------------------------------------------------
27828  // Is the node on a shared boundary with other processor?
27829 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27831  << " Is the node on shared boundaries with other processors "
27833  << std::endl;
27834 #endif
27835 
27836  // Is the node in shared boundaries no associated with the
27837  // receiver processor
27838  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
27840 
27841  // The containers where to store the info.
27842  Vector<unsigned> other_processor_1;
27843  Vector<unsigned> other_processor_2;
27844  Vector<unsigned> other_shared_boundaries;
27845  Vector<unsigned> other_indexes;
27846 
27847  // How many shared bounaries with other processors the node lives on
27848  unsigned n_shd_bnd_with_other_procs_have_node = 0;
27849 
27850  // Is the node on shared boundaries with other processors
27851  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27852  {
27853 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27855  << " In how many shared boundaries with other "
27856  << "processors is the node "
27858  << std::endl;
27859 #endif
27860 
27861  // How many nodes on other shared boundaries were found
27862  n_shd_bnd_with_other_procs_have_node =
27864 
27865  // Resize the containers
27866  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
27867  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
27868  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
27869  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
27870 
27871  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
27872  {
27873 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27875  << " Processor where the other shared boundary"
27876  << "has the node"
27878  << std::endl;
27879 #endif
27880  // Read the other processor 1
27881  other_processor_1[i] =
27883 
27884 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27886  << " Processor where the other shared boundary"
27887  << "has the node"
27889  << std::endl;
27890 #endif
27891  // Read the other processor 2
27892  other_processor_2[i] =
27894 
27895 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27897  << " Other shared boundary id where the node is on: "
27899  << std::endl;
27900 #endif
27901 
27902  // Read the other shared boundary id
27903  other_shared_boundaries[i] =
27905 
27906 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27908  << " Node index on the other shared boundary "
27910  << std::endl;
27911 #endif
27912 
27913  // Read the node index on the other shared boundary
27914  other_indexes[i] =
27916 
27917  } // for (i < n_shd_bnd_with_other_procs_have_node)
27918 
27919  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27920 #ifdef PARANOID
27921  else
27922  {
27923  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
27924  {
27925  std::ostringstream error_message;
27926  error_message
27927  <<"The current node is not on a shared boundary with\n"
27928  <<"other processors, this should be indicated by a zero flag.\n"
27929  <<"However, the read value for that flag is ("
27930  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
27931  throw OomphLibError(
27932  error_message.str(),
27933  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
27934  OOMPH_EXCEPTION_LOCATION);
27935  }
27936  }
27937 #endif
27938 
27939  // ------------------------------------------------------------
27940  // Receive the info. to check if the node is on a haloed element
27941  // with any processor
27942 
27943  // Store the halo element number with jproc where the node was found
27944  Vector<Vector<unsigned> > halo_element_number(nproc);
27945  // Store the node number on the halo element where the node was found
27946  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27947 
27948  // Loop over the processors
27949  for (unsigned jproc = 0; jproc < nproc; jproc++)
27950  {
27951 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27953  << " The node is on "
27955  << " halo elements with " << jproc << " processor"
27956  << std::endl;
27957 #endif
27958  // Get the number of halo elements with jproc processor where the
27959  // node was found
27960  const unsigned n_jproc_halo_ele_node_is_on =
27962 
27963  // Resize the containers
27964  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
27965  halo_node_number_in_halo_element[jproc].resize(n_jproc_halo_ele_node_is_on);
27966 
27967  // Read halo elements indexes (which are indexes of the halo
27968  // elements of the sender processor (iproc) with other processors
27969  // (included my_rank)
27970  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27971  {
27972  // Get the halo element index in the jproc processor
27973 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27975  << " The halo element index where the node is on "
27977  << std::endl;
27978 #endif
27979  // Get the node index on the halo element
27980  const unsigned halo_ele_index =
27982 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27984  << " The node index on the halo element where the node "
27985  << "is on "
27987  << std::endl;
27988 #endif
27989  const unsigned node_index_on_halo_ele =
27991 
27992  // Store the halo element number
27993  halo_element_number[jproc][i] = halo_ele_index;
27994  // Store the index of on the haloed element
27995  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
27996 
27997  } // for (i < n_jproc_halo_ele_node_is_on)
27998 
27999  } // for (jproc < nproc)
28000 
28001  // Store the node pointers obtained from the indicated halo elements
28002  // (use a set to check for the case when the node pointer is
28003  // different)
28004  std::set<Node*> set_haloed_node_pt;
28005 
28006  // Store the node pointer obtained from the haloed elements
28007  Node* haloed_node_pt = 0;
28008 
28009  // Flag to indicate if it is on a haloed element of the current
28010  // processor with the iproc processor. If this flag is true then
28011  // there is no need to read the info. to create the node, only copy
28012  // the node from the indicated haloed element-node
28013  bool on_haloed_element_with_iproc_processor = false;
28014  if (halo_element_number[my_rank].size() > 0)
28015  {
28016  // The node is part of the haloed element in the current processor
28017  // (my_rank) with the receiver processor
28018  on_haloed_element_with_iproc_processor = true;
28019 
28020  // Get the number of haloed elements in the current processor
28021  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28022  // Loop over the different haloed indexes, and get the nodes
28023  // instances from all the indicated haloed elements (all of them
28024  // should be the same)
28025  for (unsigned i = 0; i < n_haloed_indexes; i++)
28026  {
28027  // Get the haloed element numbers where the node is on
28028  const unsigned haloed_index = halo_element_number[my_rank][i];
28029  // Get the node index on the haloed element
28030  const unsigned haloed_node_index =
28031  halo_node_number_in_halo_element[my_rank][i];
28032 
28033  // Get the haloed element (with iproc)
28034  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28035  // Get the node on the indicated node number
28036  Node* tmp_haloed_node_pt = tmp_haloed_ele_pt->node_pt(haloed_node_index);
28037 
28038  // Set the pointer for the obtained haloed node
28039  haloed_node_pt = tmp_haloed_node_pt;
28040 
28041  // Add the node to the set of node pointers
28042  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28043 
28044 #ifdef PARANOID
28045  if (set_haloed_node_pt.size() > 1)
28046  {
28047  std::ostringstream error_message;
28048  error_message
28049  <<"When adding the " << haloed_node_index << " node of the "
28050  << haloed_index << "-th haloed element\n"
28051  << "in the currrent processor with the " << iproc << " processor"
28052  << "it was found that\nthe node pointer is different from the other"
28053  << "instances of the node.\nIt means we have a repeated node."
28054  << "This are the node coordinates of the previous node instances\n"
28055  << "The last entry is for the just added node with a different node\n"
28056  << "pointer\n";
28057  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28058  it != set_haloed_node_pt.end(); it++)
28059  {
28060  error_message
28061  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28062  }
28063  error_message << "\n";
28064  throw OomphLibError(
28065  error_message.str(),
28066  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28067  OOMPH_EXCEPTION_LOCATION);
28068  }
28069 #endif
28070 
28071  } // for (i < n_haloed_indexes)
28072 
28073  } // if (halo_element_number[iproc].size() > 0)
28074 
28075  // Flag to indicate if the node has been found on a haloed element
28076  // of other processor with the iproc processor
28077  bool found_on_haloed_element_with_other_processor = false;
28078  // Loop over the processors (only until the iproc since no info. of
28079  // higher processors has been received)
28080  for (unsigned jproc = 0; jproc < iproc; jproc++)
28081  {
28082  // Is the node on a halo element with the jproc processor
28083  if (halo_element_number[jproc].size() > 0)
28084  {
28085  // Get the number of halo elements with the jproc processor
28086  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28087  // Loop over the different halo indexes, and get the nodes
28088  // instances from all the indicated halo elements (all of them
28089  // should be the same)
28090  for (unsigned i = 0; i < n_halo_indexes; i++)
28091  {
28092  // Get the haloed element numbers where the node is on
28093  const unsigned haloed_index = halo_element_number[jproc][i];
28094  // Get the node index on the haloed element
28095  const unsigned haloed_node_index =
28096  halo_node_number_in_halo_element[jproc][i];
28097 
28098  // Have we received the indicated element? (Get the haloed
28099  // element on jproc with the iproc processor)
28100  std::map<unsigned,FiniteElement*>::iterator it_map =
28101  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28102  // Have we received the indicated element?
28103  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28104  {
28105  // Set the flag of found element in other processors haloed
28106  // element, in this case in haloed elements of processor
28107  // jproc wiht iproc processor
28108  found_on_haloed_element_with_other_processor = true;
28109 
28110  // Get the element
28111  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28112  // Get the node on the indicated node number
28113  Node* tmp_haloed_node_pt =
28114  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28115 
28116  // Set the pointer for the obtained haloed node
28117  haloed_node_pt = tmp_haloed_node_pt;
28118 
28119  // Add the node to the set of node pointers
28120  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28121 
28122 #ifdef PARANOID
28123  if (set_haloed_node_pt.size() > 1)
28124  {
28125  std::ostringstream error_message;
28126  error_message
28127  <<"When adding the " << haloed_node_index << " node of the "
28128  << haloed_index << "-th haloed element "
28129  << "of the " << jproc << " processor\nwith the "
28130  << iproc << " processor, it was found that\n"
28131  << "the node pointer is different from the other\n"
28132  << "instances of the node.\nThis means we have a repeated node.\n"
28133  << "These are the node coordinates of the previous node "
28134  << "instances\n"
28135  << "The last entry is for the just added node with a different\n"
28136  << "node pointer\n";
28137  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28138  it != set_haloed_node_pt.end(); it++)
28139  {
28140  error_message
28141  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28142  }
28143  error_message << "\n";
28144  throw OomphLibError(
28145  error_message.str(),
28146  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28147  OOMPH_EXCEPTION_LOCATION);
28148  }
28149 #endif
28150 
28151  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28152  // Have we received the element?
28153 
28154  } // for (i < n_haloed_indexes)
28155 
28156  } // if (halo_element_number[iproc].size() > 0)
28157 
28158  } // for (jproc < nproc)
28159 
28160  // If the node was found in the haloed elements of the current
28161  // processor with the iproc processor, or in the haloed elements of
28162  // any other processor with the iproc processor then copy the node
28163  // pointer (no problem if we overwrite the node info. it should be
28164  // the same node pointer)
28165  if (on_haloed_element_with_iproc_processor ||
28166  found_on_haloed_element_with_other_processor)
28167  {
28168  // Set the node pointer
28169  new_nod_pt = haloed_node_pt;
28170  }
28171 
28172  // Now we have all the info. to decide if the node should be created
28173  // or not
28174 
28175  // First check if the node is a shared boundary node, or if it has
28176  // been found on haloed elements
28177  if (is_node_on_shared_boundary == 1 ||
28178  (on_haloed_element_with_iproc_processor))
28179  {
28180  // We already have the node, we do not need to create it
28181 
28182  // Only check if we need to add boundary info. to the node
28183  if (node_on_original_boundaries==2)
28184  {
28185  // The node is a boundary node, add the boundary info. before
28186  // adding it to the domain
28187 
28188  // Associate the node to the given boundaries
28189  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28190  {
28191  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28192  // Establish the boundary coordinates for the node
28193  Vector<double> zeta(1);
28194  zeta[0] = zeta_coordinates[i];
28195  new_nod_pt->set_coordinates_on_boundary(
28196  original_boundaries_node_is_on[i],zeta);
28197  }
28198 
28199  } // if (node_on_original_boundaries==2)
28200 
28201  // Add the node to the domain
28202  new_nodes_on_domain.push_back(new_nod_pt);
28203 
28204  // Add the node to the element
28205  new_el_pt->node_pt(node_index) = new_nod_pt;
28206 
28207  } // if (is_node_on_shared_boundary == 1)
28208 
28209  // Now check if the node is on a shared boundary with another
28210  // processor, if that is the case try to find the node that may have
28211  // been already sent by the other processors
28212 
28213  // This flags indicates if the node was found, and then decide if it
28214  // is required to create the node
28215  bool found_node_in_other_shared_boundaries = false;
28216  // Flag to indicate whether the node should be created as a boundary
28217  // node or not. If the node lies on a shared boundary with other
28218  // processor the we create it as a boundary node. The processor from
28219  // which we are receiving info. (iproc) may not know that the node
28220  // lies on an original boundary. If the node lies on an original
28221  // boundary then its info. will be sent by another processor, then
28222  // we can set its boundary info. since the node was constructed as a
28223  // boundary node
28224  bool build_node_as_boundary_node = false;
28225 
28226  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28227  {
28228  // Build the node as a boundary node
28229  build_node_as_boundary_node = true;
28230 
28231  // Try to get the node pointer in case that the node has been
28232  // already sent by the other processors
28233 
28234  // Get the number of initial shared boundaries to correct the
28235  // index of the shared boundary
28236  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28237 
28238  // Add the found nodes in the container, should be the same but
28239  // better check
28240  Vector<Node*> found_node_pt;
28241 
28242  // Now try to find the node in any of the other shared boundaries
28243  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28244  {
28245  unsigned oproc1 = other_processor_1[i];
28246  unsigned oproc2 = other_processor_2[i];
28247 
28248  // Check that we always check with the lower processors number
28249  // first
28250  if (oproc1 > oproc2)
28251  {
28252  oproc2 = oproc1;
28253  oproc1 = other_processor_2[i];
28254  } // if (oproc1 > oproc2)
28255 
28256  // Re-compute the shared boundary id between the other
28257  // processors
28258  const unsigned shd_bnd_id =
28259  other_shared_boundaries[i] - initial_shd_bnd_id;
28260  // Read the index
28261  const unsigned index = other_indexes[i];
28262 
28263  // Check if there are nodes received from the other processor
28264  // and with the given shared boundary
28265  const unsigned n_nodes_on_other_processor =
28266  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28267 
28268  if (n_nodes_on_other_processor > 0)
28269  {
28270  // Check if we can find the index of the node in that other
28271  // processor and shared boundary id
28272  std::map<unsigned, Node*>::iterator it =
28273  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
28274  find(index);
28275 
28276  // If the index exist then get the node pointer
28277  if (it!=
28278  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28279  {
28280  // Mark the node as found
28281  found_node_in_other_shared_boundaries = true;
28282  // Get the node pointer
28283  Node* tmp_node_pt =
28284  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28285  found_node_pt.push_back(tmp_node_pt);
28286  } // if (it!=
28287  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28288 
28289  } // if (n_nodes_on_other_processor > 0)
28290 
28291  } // for (i < n_shd_bnd_with_other_procs_have_node)
28292 
28293  // If the node was found, then all their instances should be the
28294  // same but better check
28295  if (found_node_in_other_shared_boundaries)
28296  {
28297 #ifdef PARANOID
28298  const unsigned ntimes_node_found = found_node_pt.size();
28299  for (unsigned j = 1; j < ntimes_node_found; j++)
28300  {
28301  if (found_node_pt[j-1] != found_node_pt[j])
28302  {
28303  std::ostringstream error_message;
28304  error_message
28305  <<"The instances of the node that was found to be on a\n"
28306  <<"shared boundary with other processors are not the same,\n"
28307  <<"the coordinates for the nodes are these:\n"
28308  <<"(" << found_node_pt[j-1]->x(0) << ", "
28309  << found_node_pt[j-1]->x(1) << ")\n"
28310  <<"(" << found_node_pt[j]->x(0) << ", "
28311  << found_node_pt[j]->x(1) << ")\n"
28312  <<"Not be surprised if they are the same since the node is\n"
28313  <<"repeated!!!\n";
28314  throw OomphLibError(
28315  error_message.str(),
28316  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28317  OOMPH_EXCEPTION_LOCATION);
28318 
28319  } // if (found_node_pt[j-1] != found_node_pt[j])
28320 
28321  } // for (j < ntimes_node_found)
28322 #endif
28323 
28324  // Check if the node is a shared boundary node from the current
28325  // processor and the iproc processor, if that is the case, and
28326  // the node is also on a shared boundary with other processor,
28327  // then the pointer should be the same!!!
28328  if (is_node_on_shared_boundary == 1)
28329  {
28330  // The pointer to the node is already assigned, it was
28331  // assigned when thenode was found to be on a shared boundary
28332  // with the iproc processor
28333  if (found_node_pt[0] != new_nod_pt)
28334  {
28335  std::ostringstream error_message;
28336  error_message
28337  <<"The pointer of the node that was found to be on a\n"
28338  <<"shared boundary with other processor(s) and the pointer\n"
28339  <<"of the node on shared boundary with the receiver\n"
28340  <<"processor (iproc) are not the same. This means we have a\n"
28341  << "repeated node)\n"
28342  <<"The coordinates for the nodes are:\n"
28343  <<"(" << found_node_pt[0]->x(0) << ", "
28344  << found_node_pt[0]->x(1) << ")\n"
28345  <<"(" << new_nod_pt->x(0) << ", "
28346  << new_nod_pt->x(1) << ")\n"
28347  <<"Not to be surprised if they are the same since the node is\n"
28348  <<"repeated!!!\n";
28349  throw OomphLibError(
28350  error_message.str(),
28351  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28352  OOMPH_EXCEPTION_LOCATION);
28353  } // if (found_node_pt[0] != new_nod_pt)
28354 
28355  } // if (is_node_on_shared_boundary == 1)
28356  else
28357  {
28358  // Take the first instance of the node in case that it was
28359  // found and is not on a shared boundary with the iproc
28360  // processor
28361  new_nod_pt = found_node_pt[0];
28362  }
28363 
28364  } // if (found_node_in_other_shared_boundaries)
28365 
28366  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28367 
28368  // -----------------------------------------------------------------
28369  // Create the node or read the received info if the node is not on a
28370  // shared boundary with the iproc processor and if the node is not
28371  // part of the haloed elements with the iproc processor in the
28372  // current processors
28373  if (is_node_on_shared_boundary != 1 &&
28374  !on_haloed_element_with_iproc_processor)
28375  {
28376  // If the node is on a shared boundary with other processor we
28377  // need to read all the info. since the processor that sent the
28378  // info. did not know that the node is part of another shared
28379  // boundary
28380 
28381  // If the node is not a shared boundary (with any processor), or
28382  // if this is the first time that the info. of the node is
28383  // received from any of the processors with which is has a shared
28384  // boundary, then we create the node
28385 
28386  // Is the node a boundary node or should it be build as a boundary
28387  // node because it is on a shared boundary with other processors
28388  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
28389  {
28390  // Check if necessary to create the node, or if it has been
28391  // already found in shared boundaries with other processors or
28392  // in the haloed elements with of other processors with the
28393  // iproc processor
28394  if (!found_node_in_other_shared_boundaries ||
28395  !found_on_haloed_element_with_other_processor)
28396  {
28397  // Construct a boundary node
28398  if (time_stepper_pt!=0)
28399  {
28400  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
28401  time_stepper_pt);
28402  }
28403  else
28404  {
28405  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
28406  }
28407 
28408  } // if (!found_node_in_other_shared_boundaries ||
28409  // !found_on_haloed_element_with_other_processor)
28410  else
28411  {
28412  // If the node was found then assign the node to the element
28413  new_el_pt->node_pt(node_index) = new_nod_pt;
28414  } // else if (!found_node_in_other_shared_boundaries ||
28415  // !found_on_haloed_element_with_other_processor)
28416 
28417  // Associate the node to the given boundaries
28418  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28419  {
28420  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28421  // Establish the boundary coordinates for the node
28422  Vector<double> zeta(1);
28423  zeta[0] = zeta_coordinates[i];
28424  new_nod_pt->set_coordinates_on_boundary(
28425  original_boundaries_node_is_on[i],zeta);
28426  }
28427 
28428  } // if (node is on an original boundary)
28429  else
28430  {
28431  // Check if necessary to create the node, or if it has been
28432  // already found in shared boundaries with other processors or
28433  // in the haloed elements with of other processors with the
28434  // iproc processor
28435  if (!found_node_in_other_shared_boundaries ||
28436  !found_on_haloed_element_with_other_processor)
28437  {
28438  // Construct an ordinary (non-boundary) node
28439  if (time_stepper_pt!=0)
28440  {
28441  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
28442  }
28443  else
28444  {
28445  new_nod_pt=new_el_pt->construct_node(node_index);
28446  }
28447  } // if (!found_node_in_other_shared_boundaries ||
28448  // !found_on_haloed_element_with_other_processor)
28449  else
28450  {
28451  // If the node was found then assign the node to the element
28452  new_el_pt->node_pt(node_index) = new_nod_pt;
28453  } // else // if (!found_node_in_other_shared_boundaries ||
28454  // !found_on_haloed_element_with_other_processor)
28455 
28456  } // else (the node is not a boundary node)
28457 
28458  // ... and gather all its information
28459 
28460  // If the node was found or not in other shared boundaries, this
28461  // is the first time the node is received from this processor
28462  // (iproc), therefore it is added to the vector of nodes received
28463  // from this processor (iproc)
28464  new_nodes_on_domain.push_back(new_nod_pt);
28465 
28466  // Check if necessary to state all the info. to the node if it has
28467  // been already found in shared boundaries with other processors
28468  // or in the haloed elements with of other processors with the
28469  // iproc processor
28470  if (!found_node_in_other_shared_boundaries ||
28471  !found_on_haloed_element_with_other_processor)
28472  {
28473  // Add the node to the general node storage
28474  this->add_node_pt(new_nod_pt);
28475  } // if (!found_node_in_other_shared_boundaries ||
28476  // !found_on_haloed_element_with_other_processor)
28477 
28478  // Is the new constructed node Algebraic?
28479  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
28480  (new_nod_pt);
28481 
28482  // If it is algebraic, its node update functions will
28483  // not yet have been set up properly
28484  if (new_alg_nod_pt!=0)
28485  {
28486  // The AlgebraicMesh is the external mesh
28487  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
28488 
28489  /// The first entry of All_alg_nodal_info contains
28490  /// the default node update id
28491  /// e.g. for the quarter circle there are
28492  /// "Upper_left_box", "Lower right box" etc...
28493 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28495  << " Alg node update id "
28497  << std::endl;
28498 #endif
28499 
28500  unsigned update_id=Flat_packed_unsigneds
28502 
28503  Vector<double> ref_value;
28504 
28505  // The size of this vector is in the next entry
28506  // of All_alg_nodal_info
28507 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28509  << " Alg node # of ref values "
28511  << std::endl;
28512 #endif
28513  unsigned n_ref_val=Flat_packed_unsigneds
28515 
28516  // The reference values themselves are in
28517  // All_alg_ref_value
28518  ref_value.resize(n_ref_val);
28519  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
28520  {
28521  ref_value[i_ref]=Flat_packed_doubles
28523  }
28524 
28525  Vector<GeomObject*> geom_object_pt;
28526  /// again we need the size of this vector as it varies
28527  /// between meshes; we also need some indication
28528  /// as to which geometric object should be used...
28529 
28530  // The size of this vector is in the next entry
28531  // of All_alg_nodal_info
28532 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28534  << " Alg node # of geom objects "
28536  << std::endl;
28537 #endif
28538  unsigned n_geom_obj=Flat_packed_unsigneds
28540 
28541  // The remaining indices are in the rest of
28542  // All_alg_nodal_info
28543  geom_object_pt.resize(n_geom_obj);
28544  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
28545  {
28546 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28548  << " Alg node: geom object index "
28550  << std::endl;
28551 #endif
28552  unsigned geom_index=Flat_packed_unsigneds
28554  // This index indicates which of the AlgebraicMesh's
28555  // stored geometric objects should be used
28556  // (0 is a null pointer; everything else should have
28557  // been filled in by the specific Mesh). If it
28558  // hasn't been filled in then the update_node_update
28559  // call should fix it
28560  geom_object_pt[i_geom]=alg_mesh_pt->
28561  geom_object_list_pt(geom_index);
28562  }
28563 
28564  // Check if necessary to state all the info. to the node if it
28565  // has been already found in shared boundaries with other
28566  // processors or in the haloed elements with of other processors
28567  // with the iproc processor
28568  if (!found_node_in_other_shared_boundaries ||
28569  !found_on_haloed_element_with_other_processor)
28570  {
28571  /// For the received update_id, ref_value, geom_object
28572  /// call add_node_update_info
28573  new_alg_nod_pt->add_node_update_info
28574  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
28575 
28576  /// Now call update_node_update
28577  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28578 
28579  } // if (!found_node_in_other_shared_boundaries ||
28580  // !found_on_haloed_element_with_other_processor)
28581 
28582  } // if (new_alg_nod_pt!=0)
28583 
28584  // Check if necessary to state all the info. to the node if it has
28585  // been already found in shared boundaries with other processors
28586  // or in the haloed elements with of other processors with the
28587  // iproc processor
28588  if (!found_node_in_other_shared_boundaries ||
28589  !found_on_haloed_element_with_other_processor)
28590  {
28591  // Is the node a MacroElementNodeUpdateNode?
28592  MacroElementNodeUpdateNode* macro_nod_pt=
28593  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28594 
28595  if (macro_nod_pt!=0)
28596  {
28597  // Need to call set_node_update_info; this requires
28598  // a Vector<GeomObject*> (taken from the mesh)
28599  Vector<GeomObject*> geom_object_vector_pt;
28600 
28601  // Access the required geom objects from the
28602  // MacroElementNodeUpdateMesh
28603  MacroElementNodeUpdateMesh* macro_mesh_pt=
28604  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28605  geom_object_vector_pt=
28606  macro_mesh_pt->geom_object_vector_pt();
28607 
28608  // Get local coordinate of node in new element
28609  Vector<double> s_in_macro_node_update_element;
28610  new_el_pt->local_coordinate_of_node
28611  (node_index,s_in_macro_node_update_element);
28612 
28613  // Set node update info for this node
28614  macro_nod_pt->set_node_update_info
28615  (new_el_pt,s_in_macro_node_update_element,
28616  geom_object_vector_pt);
28617  }
28618 
28619  } // if (!found_node_in_other_shared_boundaries ||
28620  // !found_on_haloed_element_with_other_processor)
28621 
28622  // If there are additional values, resize the node
28623  unsigned n_new_val=new_nod_pt->nvalue();
28624 
28625  // Check if necessary to state all the info. to the node if it has
28626  // been already found in shared boundaries with other processors
28627  // or in the haloed elements with of other processors with the
28628  // iproc processor
28629  if (!found_node_in_other_shared_boundaries ||
28630  !found_on_haloed_element_with_other_processor)
28631  {
28632  if (n_val>n_new_val)
28633  {
28634  // If it has been necessary to resize then it may be becuse
28635  // the node is on a FSI boundary, if that is the case we need
28636  // to set a map for these external values
28637 
28638  // Cast to a boundary node
28639  BoundaryNodeBase *bnod_pt =
28640  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28641 
28642  // Create storage, if it doesn't already exist, for the map
28643  // that will contain the position of the first entry of
28644  // this face element's additional values,
28646  {
28648  new std::map<unsigned, unsigned>;
28649  }
28650 
28651  // Get pointer to the map
28652  std::map<unsigned, unsigned>* map_pt=
28654 
28655  // The id of the face to which this node belong in the bulk
28656  // element
28657  const unsigned id_face = 0;
28658  // We only resize the node values Vector if we haven't done it yet
28659  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
28660 
28661  // If this node hasn't been resized for current id
28662  if(p==map_pt->end())
28663  {
28664  // assign the face element id and the position of the
28665  //first entry to the boundary node
28666  (*map_pt)[id_face] = n_new_val;
28667 
28668  // resize the node vector of values
28669  new_nod_pt->resize(n_val);
28670  }
28671 
28672  } // if (n_val>n_new_val)
28673 
28674  } // if (!found_node_in_other_shared_boundaries ||
28675  // !found_on_haloed_element_with_other_processor)
28676 
28677  // Is the new node a SolidNode?
28678  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
28679  if (solid_nod_pt!=0)
28680  {
28681  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
28682  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
28683  {
28684  for (unsigned t=0;t<n_prev;t++)
28685  {
28686  double read_data =
28688 
28689  // Check if necessary to state all the info. to the node if
28690  // it has been already found in shared boundaries with other
28691  // processors or in the haloed elements with of other
28692  // processors with the iproc processor
28693  if (!found_node_in_other_shared_boundaries ||
28694  !found_on_haloed_element_with_other_processor)
28695  {
28696  solid_nod_pt->variable_position_pt()->
28697  set_value(t, i_val, read_data);
28698  } // if (!found_node_in_other_shared_boundaries ||
28699  // !found_on_haloed_element_with_other_processor)
28700 
28701  }
28702 
28703  }
28704 
28705 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28707  << " Number of values solid node: "
28709  << std::endl;
28710 #endif
28711  const unsigned nvalues_solid_node =
28713  Vector<double> values_solid_node(nvalues_solid_node);
28714  for (unsigned i = 0; i < nvalues_solid_node; i++)
28715  {
28716  values_solid_node[i] =
28718  }
28719 
28720  // Check if necessary to state all the info. to the node if it
28721  // has been already found in shared boundaries with other
28722  // processors or in the haloed elements with of other processors
28723  // with the iproc processor
28724  if (!found_node_in_other_shared_boundaries ||
28725  !found_on_haloed_element_with_other_processor)
28726  {
28727  unsigned index = 0;
28728  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28729  } // if (!found_node_in_other_shared_boundaries ||
28730  // !found_on_haloed_element_with_other_processor)
28731 
28732  }
28733 
28734  // Get copied history values
28735  // unsigned n_val=new_nod_pt->nvalue();
28736  for (unsigned i_val=0;i_val<n_val;i_val++)
28737  {
28738  for (unsigned t=0;t<n_prev;t++)
28739  {
28740  double read_data =
28742 
28743  // Check if necessary to state all the info. to the node if it
28744  // has been already found in shared boundaries with other
28745  // processors or in the haloed elements with of other
28746  // processors with the iproc processor
28747  if (!found_node_in_other_shared_boundaries ||
28748  !found_on_haloed_element_with_other_processor)
28749  {
28750  new_nod_pt->set_value(t, i_val, read_data);
28751  } // if (!found_node_in_other_shared_boundaries ||
28752  // !found_on_haloed_element_with_other_processor)
28753 
28754  }
28755 
28756  }
28757 
28758  // Get copied history values for positions
28759  unsigned n_dim=new_nod_pt->ndim();
28760  for (unsigned idim=0;idim<n_dim;idim++)
28761  {
28762  for (unsigned t=0;t<n_prev;t++)
28763  {
28764  double read_data =
28766 
28767  // Check if necessary to state all the info. to the node if it
28768  // has been already found in shared boundaries with other
28769  // processors or in the haloed elements with of other
28770  // processors with the iproc processor
28771  if (!found_node_in_other_shared_boundaries ||
28772  !found_on_haloed_element_with_other_processor)
28773  {
28774  // Copy to coordinate
28775  new_nod_pt->x(t,idim) = read_data;
28776 // DEBP(new_nod_pt->x(t,idim));
28777  } // if (!found_node_in_other_shared_boundaries ||
28778  // !found_on_haloed_element_with_other_processor)
28779  }
28780  }
28781 
28782  } // if (is_node_on_shared_boundary != 1)
28783 
28784  // If the node was not found in other shared boundaries (possibly
28785  // because it is the first time the node has been sent) then copy
28786  // the node to the shared boundaries where it should be, use the
28787  // special container for this cases
28788  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
28789  // shared
28790  // boundaries with
28791  // other processors
28792  !found_node_in_other_shared_boundaries) // The node has not
28793  // been previously
28794  // set as with
28795  // shared with
28796  // other processors
28797  // (first time)
28798  {
28799 
28800  // Update the node pointer in all the references of the node
28801  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
28802  other_proc_shd_bnd_node_pt,
28803  other_processor_1,
28804  other_processor_2,
28805  other_shared_boundaries,
28806  other_indexes,
28807  global_node_names,
28808  node_name_to_global_index,
28809  global_shared_node_pt);
28810 
28811  } // if (!found_node_in_other_shared_boundaries)
28812 
28813  }
28814 
28815 #endif // #ifdef OOMPH_HAS_MPI
28816 
28817  //======================================================================
28818  /// \short Get the nodes on the boundary (b), these are stored in the
28819  /// segment they belong (also used by the load balance method to
28820  /// re-set the number of segments per boundary after load balance has
28821  /// taken place)
28822  //======================================================================
28823  template <class ELEMENT>
28825  const unsigned &b, Vector<Vector<Node*> > &tmp_segment_nodes)
28826  {
28827  // Clear the data structure were to return the nodes
28828  tmp_segment_nodes.clear();
28829 
28830  // Temporary storage for face elements
28831  Vector<FiniteElement*> face_el_pt;
28832 
28833  // Temporary storage for number of elements adjacent to the boundary
28834  unsigned nel = 0;
28835 
28836  // Temporary storage for elements adjacent to the boundary that have
28837  // a common edge (related with internal boundaries)
28838  unsigned n_repeated_ele = 0;
28839 
28840  // Get the number of regions
28841  const unsigned n_regions = this->nregion();
28842 
28843  // Temporary storage for already visited pair of nodes (edges)
28844  Vector < std::pair<Node*, Node *> > done_nodes_pt;
28845 
28846  // Are there more than one region?
28847  if (n_regions > 1)
28848  {
28849  for (unsigned rr = 0 ; rr < n_regions; rr++)
28850  {
28851  const unsigned region_id =
28852  static_cast<unsigned>(this->Region_attribute[rr]);
28853 
28854  // Loop over all elements on boundaries in region rr
28855  const unsigned nel_in_region =
28856  this->nboundary_element_in_region(b, region_id);
28857 
28858  // Number of repeated element in region
28859  unsigned nel_repeated_in_region = 0;
28860 
28861  // Only bother to do anything else, if there are elements
28862  // associated with the boundary and the current region
28863  if (nel_in_region > 0)
28864  {
28865  // Flag that activates when a repeated face element is found,
28866  // possibly because we are dealing with an internal boundary
28867  bool repeated = false;
28868 
28869  // Loop over the bulk elements adjacent to boundary b
28870  for (unsigned e = 0; e < nel_in_region; e++)
28871  {
28872  // Get pointer to the bulk element that is adjacent to boundary b
28873  FiniteElement* bulk_elem_pt =
28874  this->boundary_element_in_region_pt(b, region_id, e);
28875 
28876 #ifdef OOMPH_HAS_MPI
28877  // In a distributed mesh only work with nonhalo elements
28878  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28879  {
28880  // Increase the number of repeated elements
28881  n_repeated_ele++;
28882  // Go for the next element
28883  continue;
28884  }
28885 #endif
28886 
28887  //Find the index of the face of element e along boundary b
28888  int face_index =
28889  this->face_index_at_boundary_in_region(b, region_id, e);
28890 
28891  // Before adding the new element we need to be sure that the
28892  // edge that this element represents has not been already
28893  // added
28894  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28895  bulk_elem_pt, face_index);
28896 
28897  // Number of nodes in the face element
28898  const unsigned n_nodes = tmp_ele_pt->nnode();
28899 
28900  std::pair<Node*, Node*> tmp_pair =
28901  std::make_pair(tmp_ele_pt->node_pt(0),
28902  tmp_ele_pt->node_pt(n_nodes - 1));
28903 
28904  std::pair<Node*, Node*> tmp_pair_inverse =
28905  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
28906  tmp_ele_pt->node_pt(0));
28907 
28908  // Search for repeated nodes
28909  unsigned n_done_nodes = done_nodes_pt.size();
28910  for (unsigned l = 0; l < n_done_nodes; l++)
28911  {
28912  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
28913  == done_nodes_pt[l])
28914  {
28915  nel_repeated_in_region++;
28916  repeated = true;
28917  break;
28918  }
28919 
28920  } // for (l < n_done_nodes)
28921 
28922  // Create new face element?
28923  if (!repeated)
28924  {
28925  // Add the pair of nodes (edge) to the node dones
28926  done_nodes_pt.push_back(tmp_pair);
28927  // Add the face element to the storage
28928  face_el_pt.push_back(tmp_ele_pt);
28929  }
28930  else
28931  {
28932  // Clean up
28933  delete tmp_ele_pt;
28934  tmp_ele_pt = 0;
28935  }
28936 
28937  // Re-start
28938  repeated = false;
28939 
28940  } // for (e < nel_in_region)
28941 
28942  // Add on the number of elements in the boundary with the
28943  // current region
28944  nel += nel_in_region;
28945 
28946  // Add on the number of repeated elements
28947  n_repeated_ele += nel_repeated_in_region;
28948 
28949  } // if (nel_in_region > 0)
28950 
28951  } // for (rr < n_regions)
28952 
28953  } // if (n_regions > 1)
28954  //Otherwise it's just the normal boundary functions
28955  else
28956  {
28957  // Assign the number of boundary elements
28958  nel = this->nboundary_element(b);
28959 
28960  //Only bother to do anything else, if there are elements
28961  if (nel > 0)
28962  {
28963  // Flag that activates when a repeated face element is found,
28964  // possibly because we are dealing with an internal boundary
28965  bool repeated = false;
28966 
28967  // Loop over the bulk elements adjacent to boundary b
28968  for (unsigned e = 0; e < nel; e++)
28969  {
28970  // Get pointer to the bulk element that is adjacent to boundary b
28971  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
28972 
28973 #ifdef OOMPH_HAS_MPI
28974  // In a distributed mesh only work with nonhalo elements
28975  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28976  {
28977  // Increase the number of repeated elements
28978  n_repeated_ele++;
28979  // Go for the next element
28980  continue;
28981  }
28982 #endif
28983 
28984  //Find the index of the face of element e along boundary b
28985  int face_index = this->face_index_at_boundary(b, e);
28986 
28987  // Before adding the new element we need to be sure that the
28988  // edge that this element represent has not been already added
28989  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28990  bulk_elem_pt, face_index);
28991 
28992  // Number of nodes in the face element
28993  const unsigned n_nodes = tmp_ele_pt->nnode();
28994 
28995  std::pair<Node*, Node*> tmp_pair =
28996  std::make_pair(tmp_ele_pt->node_pt(0),
28997  tmp_ele_pt->node_pt(n_nodes - 1));
28998 
28999  std::pair<Node*, Node*> tmp_pair_inverse =
29000  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
29001  tmp_ele_pt->node_pt(0));
29002 
29003  // Search for repeated nodes
29004  unsigned n_done_nodes = done_nodes_pt.size();
29005  for (unsigned l = 0; l < n_done_nodes; l++)
29006  {
29007  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
29008  == done_nodes_pt[l])
29009  {
29010  n_repeated_ele++;
29011  repeated = true;
29012  break;
29013  }
29014 
29015  } // for (l < n_done_nodes)
29016 
29017  // Create new face element
29018  if (!repeated)
29019  {
29020  // Add the pair of nodes (edge) to the node dones
29021  done_nodes_pt.push_back(tmp_pair);
29022  // Add the face element to the storage
29023  face_el_pt.push_back(tmp_ele_pt);
29024  }
29025  else
29026  {
29027  // Free the repeated bulk element!!
29028  delete tmp_ele_pt;
29029  tmp_ele_pt = 0;
29030  }
29031 
29032  // Re-start
29033  repeated = false;
29034 
29035  } // for (e < nel)
29036 
29037  } // if (nel > 0)
29038 
29039  } // else if (n_regions > 1)
29040 
29041  // Substract the repeated elements
29042  nel -= n_repeated_ele;
29043 
29044 #ifdef PARANOID
29045  if (nel!=face_el_pt.size())
29046  {
29047  std::ostringstream error_message;
29048  error_message
29049  << "The independet counting of face elements ("<<nel<<") for "
29050  << "boundary ("<<b<<") is different\n"
29051  << "from the real number of face elements in the container ("
29052  << face_el_pt.size() <<")\n";
29053  throw OomphLibError(error_message.str(),
29054  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29055  OOMPH_EXCEPTION_LOCATION);
29056  }
29057 #endif
29058 
29059  //Only bother to do anything else, if there are elements
29060  if (nel > 0)
29061  {
29062  // Assign the number of nonhalo face elements
29063  const unsigned nnon_halo_face_elements = nel;
29064 
29065  // The vector of list to store the "segments" that compound the
29066  // boundary (segments may appear only in a distributed mesh)
29067  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
29068 
29069  // Number of already sorted face elements (only nonhalo face
29070  // elements for a distributed mesh)
29071  unsigned nsorted_face_elements = 0;
29072 
29073  // Keep track of who's done (in a distributed mesh this apply to
29074  // nonhalo only)
29075  std::map<FiniteElement*, bool> done_ele;
29076 
29077  // Keep track of which element is inverted (in distributed mesh
29078  // the elements may be inverted with respect to the segment they
29079  // belong)
29080  std::map<FiniteElement*, bool> is_inverted;
29081 
29082  // Iterate until all possible segments have been created. In a non
29083  // distributed mesh there is only one segment which defines the
29084  // complete boundary
29085  while(nsorted_face_elements < nnon_halo_face_elements)
29086  {
29087  // The ordered list of face elements (in a distributed mesh a
29088  // collection of continuous face elements define a segment)
29089  std::list<FiniteElement*> sorted_el_pt;
29090 
29091 #ifdef PARANOID
29092  // Select an initial element for the segment
29093  bool found_initial_face_element = false;
29094 #endif
29095 
29096  FiniteElement* ele_face_pt = 0;
29097 
29098  unsigned iface = 0;
29099 #ifdef OOMPH_HAS_MPI
29100  if (this->is_mesh_distributed())
29101  {
29102  for (iface = 0; iface < nel; iface++)
29103  {
29104  ele_face_pt = face_el_pt[iface];
29105  // If not done then take it as initial face element
29106  if (!done_ele[ele_face_pt])
29107  {
29108 #ifdef PARANOID
29109  // Set the flag to indicate the initial element was
29110  // found
29111  found_initial_face_element = true;
29112 #endif
29113  // Increase the number of sorted face elements
29114  nsorted_face_elements++;
29115  // Set the index to the next face element
29116  iface++;
29117  // Add the face element in the container
29118  sorted_el_pt.push_back(ele_face_pt);
29119  // Mark as done
29120  done_ele[ele_face_pt] = true;
29121  break;
29122  } // if (!done_el[ele_face_pt])
29123  } // for (iface < nel)
29124  } // if (this->is_mesh_distributed())
29125  else
29126  {
29127 #endif // #ifdef OOMPH_HAS_MPI
29128 
29129  // When the mesh is not distributed just take the first
29130  // element and put it in the ordered list
29131  ele_face_pt = face_el_pt[0];
29132 #ifdef PARANOID
29133  // Set the flag to indicate the initial element was found
29134  found_initial_face_element = true;
29135 #endif
29136  // Increase the number of sorted face elements
29137  nsorted_face_elements++;
29138  // Set the index to the next face element
29139  iface = 1;
29140  // Add the face element in the container
29141  sorted_el_pt.push_back(ele_face_pt);
29142  // Mark as done
29143  done_ele[ele_face_pt] = true;
29144 #ifdef OOMPH_HAS_MPI
29145  } // else if (this->is_mesh_distributed())
29146 #endif
29147 
29148 #ifdef PARANOID
29149  if (!found_initial_face_element)
29150  {
29151  std::ostringstream error_message;
29152  error_message
29153  <<"Could not find an initial face element for the current segment\n";
29154  throw OomphLibError(error_message.str(),
29155  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29156  OOMPH_EXCEPTION_LOCATION);
29157  }
29158 #endif
29159 
29160  // Number of nodes in the face element
29161  const unsigned nnod = ele_face_pt->nnode();
29162 
29163  // Left and rightmost nodes (the left and right nodes of the
29164  // current face element)
29165  Node* left_node_pt = ele_face_pt->node_pt(0);
29166  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29167 
29168  // Continue iterating if a new face element has been added to
29169  // the list
29170  bool face_element_added = false;
29171 
29172  // While a new face element has been added to the set of sorted
29173  // face elements continue iterating
29174  do
29175  {
29176  // Start from the next face element since we have already
29177  // added the previous one as the initial face element (any
29178  // previous face element had to be added on previous
29179  // iterations)
29180  for (unsigned iiface=iface;iiface<nel;iiface++)
29181  {
29182  // Re-start flag
29183  face_element_added = false;
29184 
29185  // Get the candidate element
29186  ele_face_pt = face_el_pt[iiface];
29187 
29188  // Check that the candidate element has not been done and is
29189  // not a halo element
29190  if (!done_ele[ele_face_pt])
29191  {
29192  // Get the left and right nodes of the current element
29193  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29194  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29195 
29196  // New element fits at the left of segment and is not inverted
29197  if (left_node_pt == local_right_node_pt)
29198  {
29199  left_node_pt = local_left_node_pt;
29200  sorted_el_pt.push_front(ele_face_pt);
29201  is_inverted[ele_face_pt] = false;
29202  face_element_added = true;
29203  }
29204  // New element fits at the left of segment and is inverted
29205  else if (left_node_pt == local_left_node_pt)
29206  {
29207  left_node_pt = local_right_node_pt;
29208  sorted_el_pt.push_front(ele_face_pt);
29209  is_inverted[ele_face_pt] = true;
29210  face_element_added = true;
29211  }
29212  // New element fits on the right of segment and is not inverted
29213  else if (right_node_pt == local_left_node_pt)
29214  {
29215  right_node_pt = local_right_node_pt;
29216  sorted_el_pt.push_back(ele_face_pt);
29217  is_inverted[ele_face_pt] = false;
29218  face_element_added = true;
29219  }
29220  // New element fits on the right of segment and is inverted
29221  else if (right_node_pt == local_right_node_pt)
29222  {
29223  right_node_pt = local_left_node_pt;
29224  sorted_el_pt.push_back(ele_face_pt);
29225  is_inverted[ele_face_pt] = true;
29226  face_element_added = true;
29227  }
29228 
29229  if (face_element_added)
29230  {
29231  // Mark the face element as done
29232  done_ele[ele_face_pt] = true;
29233  nsorted_face_elements++;
29234  break;
29235  }
29236 
29237  } // if (!done_el[ele_face_pt])
29238 
29239  } // for (iiface<nnon_halo_face_element)
29240 
29241  }while(face_element_added &&
29242  (nsorted_face_elements < nnon_halo_face_elements));
29243 
29244  // Store the created segment in the vector of segments
29245  segment_sorted_ele_pt.push_back(sorted_el_pt);
29246 
29247  } // while(nsorted_face_elements < nnon_halo_face_elements);
29248 
29249  // The number of boundary segments in this processor
29250  const unsigned nsegments = segment_sorted_ele_pt.size();
29251 
29252 #ifdef PARANOID
29253  if (nnon_halo_face_elements > 0 && nsegments == 0)
29254  {
29255  std::ostringstream error_message;
29256  error_message
29257  << "The number of segments is zero, but the number of nonhalo\n"
29258  << "elements is: (" << nnon_halo_face_elements << ")\n";
29259  throw OomphLibError(error_message.str(),
29260  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29261  OOMPH_EXCEPTION_LOCATION);
29262  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29263 #endif
29264 
29265  // Go through all the segments, visit each face element in order
29266  // and get the nodes based that represent the boundary segment
29267 
29268  // Resize the container to store the nodes with the required
29269  // number of segments
29270  tmp_segment_nodes.resize(nsegments);
29271 
29272  for (unsigned is = 0; is < nsegments; is++)
29273  {
29274 #ifdef PARANOID
29275  if (segment_sorted_ele_pt[is].size() == 0)
29276  {
29277  std::ostringstream error_message;
29278  error_message
29279  << "The (" << is << ")-th segment has no elements\n";
29280  throw OomphLibError(error_message.str(),
29281  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29282  OOMPH_EXCEPTION_LOCATION);
29283  } // if (segment_sorted_ele_pt[is].size() == 0)
29284 #endif
29285 
29286  // Get access to the first element on the segment
29287  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29288 
29289  // Number of nodes
29290  const unsigned nnod = first_ele_pt->nnode();
29291 
29292  // Get the first node of the current segment
29293  Node *first_node_pt = first_ele_pt->node_pt(0);
29294  if (is_inverted[first_ele_pt])
29295  {
29296  first_node_pt = first_ele_pt->node_pt(nnod-1);
29297  }
29298 
29299  // Add the node to the corresponding segment
29300  tmp_segment_nodes[is].push_back(first_node_pt);
29301 
29302  // Now loop over face elements in order to get the nodes
29303  for (std::list<FiniteElement*>::iterator it =
29304  segment_sorted_ele_pt[is].begin();
29305  it != segment_sorted_ele_pt[is].end(); it++)
29306  {
29307  // Get element
29308  FiniteElement* ele_pt = *it;
29309 
29310  // The last node pointer
29311  Node* last_node_pt = 0;
29312 
29313  // Get the last node
29314  if (!is_inverted[ele_pt])
29315  {
29316  last_node_pt = ele_pt->node_pt(nnod-1);
29317  }
29318  else
29319  {
29320  last_node_pt = ele_pt->node_pt(0);
29321  }
29322 
29323  // Add the node to the corresponding segment
29324  tmp_segment_nodes[is].push_back(last_node_pt);
29325 
29326  } // iterator over the elements in the segment
29327 
29328  } // for (is < nsegments)
29329 
29330  } // for (if (nel > 0))
29331 
29332  // Free memory allocation
29333  for (unsigned e = 0; e < nel; e++)
29334  {
29335  delete face_el_pt[e];
29336  face_el_pt[e] = 0;
29337  } // for (e < nel)
29338 
29339  }
29340 
29341 //======================================================================
29342 /// Adapt problem based on specified elemental error estimates
29343 /// This function implement serial and parallel mesh adaptation, the
29344 /// sections for parallel mesh adaptation are clearly identified by
29345 /// checking whether the mesh is distributed or not
29346 //======================================================================
29347  template <class ELEMENT>
29349  const Vector<double>& elem_error)
29350  {
29351  double t_start_overall=TimingHelpers::timer();
29352 
29353  // ==============================================================
29354  // BEGIN: Compute target areas
29355  // ==============================================================
29356 
29357  // Get refinement targets
29358  Vector<double> target_area(elem_error.size());
29359  double min_angle=compute_area_target(elem_error,
29360  target_area);
29361 
29362  // Post-process to allow only quantised target areas
29363  // in an attempt to more closely mimick the structured
29364  // case and limit the diffusion of small elements.
29365  bool quantised_areas=true;
29366  if (quantised_areas)
29367  {
29368  unsigned n=target_area.size();
29369  double total_area=0;
29370  // If the mesh is distributed then we need to get the contribution
29371  // of all processors to compute the total areas
29372  // ------------------------------------------
29373  // DISTRIBUTED MESH: BEGIN
29374  // ------------------------------------------
29375 #ifdef OOMPH_HAS_MPI
29376  if (this->is_mesh_distributed())
29377  {
29378  // When working in parallel we get the total area from the sum
29379  // of the the sub-areas of all the meshes
29380  double sub_area = 0.0;
29381 
29382  // Only add the area of nonhalo elements
29383  for (unsigned e=0;e<n;e++)
29384  {
29385  // Get the pointer to the element
29386  FiniteElement* ele_pt = this->finite_element_pt(e);
29387  if (!ele_pt->is_halo())
29388  {
29389  sub_area+=ele_pt->size();
29390  }
29391  } // for (e<n)
29392 
29393  // Get the communicator of the mesh
29394  OomphCommunicator* comm_pt = this->communicator_pt();
29395 
29396  // Get the total area
29397  MPI_Allreduce(&sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM,
29398  comm_pt->mpi_comm());
29399  }
29400  else
29401  {
29402  for (unsigned e=0;e<n;e++)
29403  {
29404  total_area+=this->finite_element_pt(e)->size();
29405  }
29406  }
29407  // ------------------------------------------
29408  // DISTRIBUTED MESH: END
29409  // ------------------------------------------
29410 #else // #ifdef OOMPH_HAS_MPI
29411  for (unsigned e=0;e<n;e++)
29412  {
29413  total_area+=this->finite_element_pt(e)->size();
29414  }
29415 #endif // #ifdef OOMPH_HAS_MPI
29416 
29417  for (unsigned e=0;e<n;e++)
29418  {
29419  unsigned level=
29420  unsigned(ceil(log(target_area[e]/total_area)/log(1.0/3.0)))-1;
29421  double new_target_area=total_area*pow(1.0/3.0,int(level));
29422  target_area[e]=new_target_area;
29423  }
29424 
29425  }
29426 
29427  // std::ofstream tmp;
29428  // tmp.open((Global_string_for_annotation:: String[0]+"overall_target_areas"+
29429  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29430 
29431  // Get maximum target area
29432  unsigned n=target_area.size();
29433  double max_area=0.0;
29434  double min_area=DBL_MAX;
29435  for (unsigned e=0;e<n;e++)
29436  {
29437  if (target_area[e]>max_area) max_area=target_area[e];
29438  if (target_area[e]<min_area) min_area=target_area[e];
29439 
29440  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29441  // finite_element_pt(e)->node_pt(1)->x(0)+
29442  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29443  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29444  // finite_element_pt(e)->node_pt(1)->x(1)+
29445  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29446  // << target_area[e] << " "
29447  // << finite_element_pt(e)->size() << " "
29448  // << elem_error[e] << " " << std::endl;
29449  }
29450 
29451  //tmp.close();
29452 
29453  oomph_info << "Maximum target area: " << max_area << std::endl;
29454  oomph_info << "Minimum target area: " << min_area << std::endl;
29455  oomph_info << "Number of elements to be refined: "
29456  << this->Nrefined << std::endl;
29457  oomph_info << "Number of elements to be unrefined: "
29458  << this->Nunrefined << std::endl;
29459  oomph_info << "Min. angle: " << min_angle << std::endl;
29460 
29461  double orig_max_area, orig_min_area;
29462  this->max_and_min_element_size(orig_max_area, orig_min_area);
29463  oomph_info << "Max./min. element size in original mesh: "
29464  << orig_max_area << " "
29465  << orig_min_area << std::endl;
29466 
29467  // ==============================================================
29468  // END: Compute target areas
29469  // ==============================================================
29470 
29471  // Check if boundaries need to be updated (regardless of
29472  // requirements of bulk error estimator) but don't do anything!
29473  bool check_only=true;
29474  bool outer_boundary_update_necessary= false;
29475  bool inner_boundary_update_necessary= false;
29476  bool inner_open_boundary_update_necessary=false;
29477 
29478  // Get the number of outer boundaries and check if they require
29479  // update
29480  const unsigned nouter=this->Outer_boundary_pt.size();
29481 
29482  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29483  {
29484  // loop over the outer boundaries
29485  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29486  {
29487  outer_boundary_update_necessary=
29488  this->update_polygon_using_face_mesh(this->Outer_boundary_pt[i_outer],
29489  check_only);
29490  // Break the loop if at least one needs updating
29491  if (outer_boundary_update_necessary) break;
29492  }
29493 
29494  // Do not waste time if we already know that it is necessary an update
29495  // on the boundary representation
29496  if (!outer_boundary_update_necessary)
29497  {
29498  // Check if we need to generate a new 1D mesh representation of
29499  // the inner hole boundaries
29500  const unsigned nhole=this->Internal_polygon_pt.size();
29501  Vector<Vector<double> > internal_point_coord(nhole);
29502  inner_boundary_update_necessary=
29503  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29504  check_only);
29505 
29506  // If there was not necessary a change even on the internal closed
29507  // curve then finally check for the open curves as well
29508  if (!inner_boundary_update_necessary)
29509  {
29510  const unsigned n_open_polyline =
29511  this->Internal_open_curve_pt.size();
29512  // loop over the open polylines
29513  for (unsigned i = 0; i < n_open_polyline; i++)
29514  {
29515  inner_open_boundary_update_necessary=
29516  this->update_open_curve_using_face_mesh(
29517  this->Internal_open_curve_pt[i], check_only);
29518  // If at least one needs modification then break the for loop
29519  if (inner_open_boundary_update_necessary) break;
29520  }
29521  }
29522  }
29523  }
29524 
29525  // Flag to indicate whether we need to adapt or not (for parallel
29526  // mesh adaptation only)
29527  int adapt_all = 0;
29528  // ------------------------------------------
29529  // DISTRIBUTED MESH: BEGIN
29530  // ------------------------------------------
29531 #ifdef OOMPH_HAS_MPI
29532  // When working in distributed meshes we need to ensure that all the
29533  // processors take part on the adaptation process. If at least one
29534  // of the processors requires adaptation then all processor take
29535  // part on the adaptation process.
29536  int adapt_this_processor = 0;
29537  if (this->is_mesh_distributed())
29538  {
29539  // Do this processor requires adaptation?
29540  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29541  (min_angle < min_permitted_angle())
29542  || (outer_boundary_update_necessary)
29543  || (inner_boundary_update_necessary)
29544  || (inner_open_boundary_update_necessary) )
29545  {adapt_this_processor = 1;}
29546 
29547  // Get the communicator of the mesh
29548  OomphCommunicator* comm_pt = this->communicator_pt();
29549 
29550  // Verify if at least one processor needs mesh adaptation
29551  MPI_Allreduce(&adapt_this_processor, &adapt_all, 1, MPI_INT, MPI_SUM,
29552  comm_pt->mpi_comm());
29553  }
29554 #endif
29555  // ------------------------------------------
29556  // DISTRIBUTED MESH: END
29557  // ------------------------------------------
29558 
29559  // Should we bother to adapt?
29560  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29561  (min_angle < min_permitted_angle()) || (outer_boundary_update_necessary)
29562  || (inner_boundary_update_necessary)
29563  || (inner_open_boundary_update_necessary) || (adapt_all) )
29564  {
29565  if (! ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ) )
29566  {
29567 
29568  if ( (outer_boundary_update_necessary)
29569  || (inner_boundary_update_necessary)
29570  || (inner_open_boundary_update_necessary) )
29571  {
29572  oomph_info
29573  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29574  << "representation; setting Nrefined to number of elements.\n"
29575  << "outer_boundary_update_necessary : "
29576  << outer_boundary_update_necessary << "\n"
29577  << "inner_boundary_update_necessary : "
29578  << inner_boundary_update_necessary << "\n"
29579  << "inner_open_boundary_update_necessary: "
29580  << inner_open_boundary_update_necessary << "\n";
29581  Nrefined=nelement();
29582  }
29583  else
29584  {
29585  oomph_info
29586  << "Mesh regeneration triggered by min angle criterion;\n"
29587  << "setting Nrefined to number of elements.\n";
29588  Nrefined=nelement();
29589  }
29590  }
29591 
29592  // ------------------------------------------
29593  // DISTRIBUTED MESH: BEGIN
29594  // ------------------------------------------
29595 #ifdef OOMPH_HAS_MPI
29596  else if (this->is_mesh_distributed() &&
29597  adapt_this_processor == 0 && adapt_all > 0)
29598  {
29599  oomph_info
29600  << "Mesh regeneration triggered by (" << adapt_all << ") processor(s) "
29601  << "that require(s)\n adaptation\n";
29602  }
29603 #endif
29604  // ------------------------------------------
29605  // DISTRIBUTED MESH: END
29606  // ------------------------------------------
29607 
29608  // ==============================================================
29609  // BEGIN: Updating of boundaries representation (unrefinement and
29610  // refinement of polylines)
29611  // ==============================================================
29612 
29613  // Add the initial and final vertices of the polylines that
29614  // present connections to a list of non-delete-able vertices. The
29615  // vertices where the connections are performed cannot be deleted
29616  add_vertices_for_non_deletion();
29617 
29618  // ------------------------------------------
29619  // DISTRIBUTED MESH: BEGIN
29620  // ------------------------------------------
29621 #ifdef OOMPH_HAS_MPI
29622  // Synchronise connections for shared boundaries among
29623  // processors. This is required since one of the processor may noy
29624  // know that some of its shared boundaries have connections, thus
29625  // the vertices receiving the connections cannot be deleted
29626  if (this->is_mesh_distributed())
29627  {
29628  synchronize_shared_boundary_connections();
29629  }
29630 #endif // #ifdef OOMPH_HAS_MPI
29631  // ------------------------------------------
29632  // DISTRIBUTED MESH: END
29633  // ------------------------------------------
29634 
29635  // Are we allowing automatic insertion of vertices on boundaries?
29636  // If YES then Triangle automatically insert points along
29637  // boundaries, if NOT, then points are inserted along the
29638  // boundaries based on the target areas of boundary elements. When
29639  // the mesh is distributed the automatic insertion of vertices by
29640  // Triangle along the boundaries is not allowed
29641  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29642  {
29643  //Generate a new 1D mesh representation of the inner hole boundaries
29644  unsigned nhole=this->Internal_polygon_pt.size();
29645  Vector<Vector<double> > internal_point_coord(nhole);
29646  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29647 
29648  //Update the representation of the outer boundary
29649  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29650  {
29651  this->update_polygon_using_face_mesh(
29652  this->Outer_boundary_pt[i_outer]);
29653  }
29654 
29655  // After updating outer and internal closed boundaries it is also
29656  // necessary to update internal boundaries.
29657  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29658  for (unsigned i = 0; i < n_open_polyline; i++)
29659  {
29660  this->update_open_curve_using_face_mesh(
29661  this->Internal_open_curve_pt[i]);
29662  }
29663 
29664  }
29665  else
29666  {
29667  // Update the representation of the internal boundaries using
29668  // the element's target area
29669 
29670  // Get the number of interal polygons
29671  const unsigned ninternal=this->Internal_polygon_pt.size();
29672  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29673  {
29674  this->update_polygon_using_elements_area(
29675  this->Internal_polygon_pt[i_internal], target_area);
29676  }
29677 
29678  // Update the representation of the outer boundaries using the
29679  // element's target area
29680  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29681  {
29682  this->update_polygon_using_elements_area(
29683  this->Outer_boundary_pt[i_outer], target_area);
29684  }
29685 
29686  // Update the representation of the internal open boundaries
29687  // using the element's target areas
29688  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29689  for (unsigned i = 0; i < n_open_polyline; i++)
29690  {
29691  this->update_open_curve_using_elements_area(
29692  this->Internal_open_curve_pt[i], target_area);
29693  }
29694 
29695  // ------------------------------------------
29696  // DISTRIBUTED MESH: BEGIN
29697  // ------------------------------------------
29698 
29699  // When working with a distributed mesh we require to update the
29700  // boundary representation of the shared boundaries, this is
29701  // based on the target areas of the elements adjaced to the
29702  // shared boundaries
29703 #ifdef OOMPH_HAS_MPI
29704  // Update shared boundaries if the mesh is distributed
29705  if (this->is_mesh_distributed())
29706  {
29707  // Get the rank of the current processor
29708  const unsigned my_rank = this->communicator_pt()->my_rank();
29709 
29710  // Get the number of shared curves
29711  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29712  // Loop over the shared curves in the current processor
29713  for (unsigned nc = 0; nc < n_curves; nc ++)
29714  {
29715  // Update the shared polyline
29716  this->update_shared_curve_using_elements_area(
29717  this->Shared_boundary_polyline_pt[my_rank][nc],//shared_curve,
29718  target_area);
29719  }
29720 
29721  } // if (this->is_mesh_distributed())
29722 #endif
29723 
29724  // ------------------------------------------
29725  // DISTRIBUTED MESH: END
29726  // ------------------------------------------
29727 
29728  } // else if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29729 
29730  // ==============================================================
29731  // END: Updating of boundaries representation (unrefinement and
29732  // refinement of polylines)
29733  // ==============================================================
29734 
29735  // ==============================================================
29736  // BEGIN: Reset boundary coordinates for boundaries with no
29737  // associated GeomObject
29738  // ==============================================================
29739 
29740  //If there is not a geometric object associated with the boundary
29741  //then reset the boundary coordinates so that the lengths are
29742  //consistent in the new mesh and the old mesh.
29743  const unsigned n_boundary = this->nboundary();
29744 
29745  const double t_start_first_stage_segments_connectivity =
29747 
29748  // ------------------------------------------
29749  // DISTRIBUTED MESH: BEGIN
29750  // ------------------------------------------
29751 #ifdef OOMPH_HAS_MPI
29752  // Clear storage for assignment of initial zeta values for
29753  // boundaries
29754  if (this->is_mesh_distributed())
29755  {
29756  this->Assigned_segments_initial_zeta_values.clear();
29757  }
29758 #endif // #ifdef OOMPH_HAS_MPI
29759  // ------------------------------------------
29760  // DISTRIBUTED MESH: END
29761  // ------------------------------------------
29762 
29763  // Loop over the boundaries to assign boundary coordinates
29764  for(unsigned b=0;b<n_boundary;++b)
29765  {
29766  // ------------------------------------------
29767  // DISTRIBUTED MESH: BEGIN
29768  // ------------------------------------------
29769 #ifdef OOMPH_HAS_MPI
29770  if (this->is_mesh_distributed())
29771  {
29772  // In a distributed mesh, the boundaries may have been split
29773  // across processors during the distribution process, thus we
29774  // need to compute the connectivity among the segments of the
29775  // boundary to correctly assign its boundary coordinates
29776  this->
29777  compute_boundary_segments_connectivity_and_initial_zeta_values(b);
29778  }
29779 #endif
29780  // ------------------------------------------
29781  // DISTRIBUTED MESH: END
29782  // ------------------------------------------
29783 
29784  // Does the boundary has an associated GeomObject
29785  if(this->boundary_geom_object_pt(b)==0)
29786  {
29787  this->template setup_boundary_coordinates<ELEMENT>(b);
29788  }
29789 
29790  // ------------------------------------------
29791  // DISTRIBUTED MESH: BEGIN
29792  // ------------------------------------------
29793 #ifdef OOMPH_HAS_MPI
29794  if (this->is_mesh_distributed())
29795  {
29796  // Synchronise boundary coordinates for internal open curves,
29797  // also establish the boundary coordinates for the nodes on
29798  // the corners of elements not on the boundary
29799  this->synchronize_boundary_coordinates(b);
29800  }
29801 #endif
29802  // ------------------------------------------
29803  // DISTRIBUTED MESH: END
29804  // ------------------------------------------
29805 
29806  } // for (b<n_boundary)
29807 
29808  const double t_total_first_stage_segments_connectivity =
29809  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
29810 
29811  // ==============================================================
29812  // END: Reset boundary coordinates for boundaries with no
29813  // associated GeomObject
29814  // ==============================================================
29815 
29816  // ------------------------------------------
29817  // DISTRIBUTED MESH: BEGIN
29818  // ------------------------------------------
29819 #ifdef OOMPH_HAS_MPI
29820  // ==============================================================
29821  // BEGIN: Create the new representation of the domain by joining
29822  // the original boundaries and the shared boundaries.
29823  // ==============================================================
29824 
29825  // Storage for the new temporary polygons "closed" by the shared
29826  // boundaries
29827  Vector<TriangleMeshPolygon *> tmp_outer_polygons_pt;
29828 
29829  // Storage for the new temporary open curves, could be the
29830  // original open curves or "chunks" of the original open curves
29831  // not overlapped by shared boundaries
29832  Vector<TriangleMeshOpenCurve *> tmp_open_curves_pt;
29833 
29834  if (this->is_mesh_distributed())
29835  {
29836  // Create the new polygons and open curves with help of the
29837  // original polylines and shared polylines
29838  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
29839  tmp_open_curves_pt);
29840 
29841  // Create the connections of the temporary domain representations
29842  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
29843  tmp_open_curves_pt);
29844  }
29845  // ==============================================================
29846  // END: Create the new representation of the domain by joining
29847  // the original boundaries and the shared boundaries.
29848  // ==============================================================
29849 #endif
29850  // ------------------------------------------
29851  // DISTRIBUTED MESH: END
29852  // ------------------------------------------
29853 
29854  // Re-establish polylines' connections. The boundary
29855  // representation has changed (new polylines), therefore we need
29856  // to update the connection information
29857  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
29858  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
29859  restore_boundary_connections(resume_initial_connection_polyline_pt,
29860  resume_final_connection_polyline_pt);
29861 
29862  // Update the region information by setting the coordinates from the
29863  // centroid of the first element in each region (which should allow
29864  // automatic updates when the regions deform)
29865  {
29866  unsigned n_region = this->nregion();
29867  if(n_region > 1)
29868  {
29869  for(std::map<unsigned, Vector<double> >::iterator it =
29870  this->Regions_coordinates.begin();
29871  it!=this->Regions_coordinates.end(); ++it)
29872  {
29873  //Storage for the approximate centroid
29874  Vector<double> centroid(2,0.0);
29875 
29876  //Get the region id
29877  unsigned region_id = it->first;
29878 
29879  //Report information
29880  oomph_info << "Region " << region_id << ": "
29881  << it->second[0] << " " << it->second[1] << " ";
29882 
29883  //Check that there is at least one element in the region
29884  unsigned n_region_element = this->nregion_element(region_id);
29885  if(n_region_element > 0)
29886  {
29887  //Cache pointer to the first element
29888  FiniteElement* const elem_pt = this->region_element_pt(region_id,0);
29889 
29890  //Loop over the corners of the triangle and average
29891  for(unsigned n=0;n<3;n++)
29892  {
29893  Node* const nod_pt = elem_pt->node_pt(n);
29894  for(unsigned i=0;i<2;i++) {centroid[i] += nod_pt->x(i);}
29895  }
29896  for(unsigned i=0;i<2;i++) {centroid[i] /= 3;}
29897  //Now we have the centroid set it
29898  it->second = centroid;
29899 
29900  oomph_info << " , " <<
29901  it->second[0] << " " << it->second[1] << std::endl;
29902  } //end of case when there is at least one element
29903 
29904  } // loop over regions coordinates
29905 
29906  } // if(n_region > 1)
29907 
29908  } // Updating region info.
29909 
29910  // ==============================================================
29911  // BEGIN: Create background mesh
29912  // ==============================================================
29913 
29914  // Are we dealing with a solid mesh?
29915  SolidMesh* solid_mesh_pt=dynamic_cast<SolidMesh*>(this);
29916 
29917  // Build temporary uniform background mesh
29918  //----------------------------------------
29919  // with area set by maximum required area
29920  //---------------------------------------
29921  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt=0;
29922 
29923  // The storage for the new temporary boundaries representation to
29924  // create the background mesh
29925  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
29927  Vector<TriangleMeshOpenCurve*> open_curves_pt;
29928 
29929 #ifdef OOMPH_HAS_MPI
29930  if (!this->is_mesh_distributed())
29931 #endif
29932  {
29933  // Copy the outer boundaries
29934  closed_curve_pt.resize(nouter);
29935  for (unsigned i = 0; i < nouter; i++)
29936  {
29937  closed_curve_pt[i] = this->Outer_boundary_pt[i];
29938  }
29939 
29940  // Copy the internal closed boundaries (may be holes)
29941  const unsigned n_holes = this->Internal_polygon_pt.size();
29942  hole_pt.resize(n_holes);
29943  for (unsigned i = 0; i < n_holes; i++)
29944  {
29945  hole_pt[i] = this->Internal_polygon_pt[i];
29946  }
29947 
29948  // Copy the internal open curves
29949  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
29950  open_curves_pt.resize(n_open_curves);
29951  for (unsigned i = 0; i < n_open_curves; i++)
29952  {
29953  open_curves_pt[i] = this->Internal_open_curve_pt[i];
29954  }
29955  }
29956  // ------------------------------------------
29957  // DISTRIBUTED MESH: BEGIN
29958  // ------------------------------------------
29959 #ifdef OOMPH_HAS_MPI
29960  else
29961  {
29962  // Copy the new representation of the outer/internal closed
29963  // boundaries
29964  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
29965  closed_curve_pt.resize(n_tmp_outer);
29966  for (unsigned i = 0; i < n_tmp_outer; i++)
29967  {
29968  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
29969  }
29970 
29971  // Copy the new representation of the internal open curves
29972  const unsigned n_open_curves = tmp_open_curves_pt.size();
29973  open_curves_pt.resize(n_open_curves);
29974  for (unsigned i = 0; i < n_open_curves; i++)
29975  {
29976  open_curves_pt[i] = tmp_open_curves_pt[i];
29977  }
29978 
29979  }
29980 #endif
29981  // ------------------------------------------
29982  // DISTRIBUTED MESH: END
29983  // ------------------------------------------
29984 
29985  // ----------------------------------------------------------------
29986  // Gather all the information and use the TriangleMeshParameters
29987  // object which help us on the manage of all TriangleMesh object's
29988  // information
29989 
29990  // Create the TriangleMeshParameters objects with the outer boundary
29991  // as the only one parameter
29992  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
29993 
29994  // Pass information about the holes
29995  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
29996 
29997  // Pass information about the internal open boundaries
29998  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
29999 
30000  // Set the element area
30001  triangle_mesh_parameters.element_area() = max_area;
30002 
30003  // Pass information about the extra holes (not defined with closed
30004  // boundaries)
30005  triangle_mesh_parameters.extra_holes_coordinates() =
30006  this->Extra_holes_coordinates;
30007 
30008  //Pass information about regions
30009  triangle_mesh_parameters.regions_coordinates() =
30010  this->Regions_coordinates;
30011 
30012  //Pass information about the using of regions
30013  if (this->Use_attributes)
30014  {
30015  triangle_mesh_parameters.enable_use_attributes();
30016  }
30017 
30018  //Pass information about allowing the creation of new points
30019  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30020  {
30021  triangle_mesh_parameters.disable_automatic_creation_of_vertices_on_boundaries();
30022  }
30023 
30024  // When the mesh is distributed we need to create a distributed
30025  // background mesh
30026 #ifdef OOMPH_HAS_MPI
30027  if (this->is_mesh_distributed())
30028  {
30029  // Mark the mesh to be created as distributed by passing a
30030  // pointer to the communicator
30031  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30032  }
30033 #endif
30034 
30035  // ----------------------------------------------------------
30036  // Build the background mesh using Triangle
30037  // ----------------------------------------------------------
30038  const double t_start_building_background_mesh =
30040 
30041  if (solid_mesh_pt!=0)
30042  {
30043  tmp_new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30044  (triangle_mesh_parameters, this->Time_stepper_pt);
30045  }
30046  else
30047  {
30048  tmp_new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30049  (triangle_mesh_parameters, this->Time_stepper_pt);
30050  }
30051 
30052  if (Print_timings_level_adaptation>2)
30053  {
30054  oomph_info << "CPU for building background mesh: "
30055  <<TimingHelpers::timer()-t_start_building_background_mesh
30056  << std::endl;
30057  }
30058 
30059  // Pass the info. regarding the maximum and minimum element size
30060  // from the old mesh to the background mesh
30061  const double this_max_element_size = this->max_element_size();
30062  const double this_min_element_size = this->min_element_size();
30063  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30064  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30065 
30066  // ... also copy the minimum permitted angle
30067  const double this_min_permitted_angle = this->min_permitted_angle();
30068  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30069 
30070  // ------------------------------------------
30071  // DISTRIBUTED MESH: BEGIN
30072  // ------------------------------------------
30073 #ifdef OOMPH_HAS_MPI
30074  // If the mesh is distributed we need to pass and set the
30075  // information of internal boundaries overlaped by shared
30076  // boundaries
30077  if (this->is_mesh_distributed())
30078  {
30079  // Check if necessary to fill boundary elements for those
30080  // internal boundaries that overlap shared boundaries
30081  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30082  {
30083  // Copy the data structures that indicates which shared
30084  // boundaries are part of an internal boundary
30085  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30086  this->shared_boundary_overlaps_internal_boundary();
30087 
30088  // Copy the data structure that indicates which are the shared
30089  // boundaries in each processor
30090  tmp_new_mesh_pt->shared_boundaries_ids() =
30091  this->shared_boundaries_ids();
30092 
30093  // Fill the structures for the boundary elements and face indexes
30094  // of the boundary elements
30095  tmp_new_mesh_pt->
30096  fill_boundary_elements_and_nodes_for_internal_boundaries();
30097 
30098  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30099 
30100  } // if (this->is_mesh_distributed())
30101 #endif // #ifdef OOMPH_HAS_MPI
30102  // ------------------------------------------
30103  // DISTRIBUTED MESH: END
30104  // ------------------------------------------
30105 
30106  // Snap to curvilinear boundaries (some code duplication as this
30107  // is repeated below but helper function would take so many
30108  // arguments that it's nearly as messy...
30109 
30110  //Pass the boundary geometric objects to the new mesh
30111  tmp_new_mesh_pt->boundary_geom_object_pt() =
30112  this->boundary_geom_object_pt();
30113 
30114  //Reset the boundary coordinates if there is
30115  //a geometric object associated with the boundary
30116  tmp_new_mesh_pt->boundary_coordinate_limits() =
30117  this->boundary_coordinate_limits();
30118 
30119  const double t_start_second_stage_segments_connectivity =
30121 
30122  for (unsigned b=0;b<n_boundary;b++)
30123  {
30124  // ------------------------------------------
30125  // DISTRIBUTED MESH: BEGIN
30126  // ------------------------------------------
30127 #ifdef OOMPH_HAS_MPI
30128  if (this->is_mesh_distributed())
30129  {
30130  // Identify the segments of the new mesh with the ones of the
30131  // original mesh
30132  tmp_new_mesh_pt->
30133  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30134  }
30135 #endif
30136  // ------------------------------------------
30137  // DISTRIBUTED MESH: END
30138  // ------------------------------------------
30139 
30140  // Setup boundary coordinates for boundaries with GeomObject
30141  // associated
30142  if(tmp_new_mesh_pt->boundary_geom_object_pt(b)!=0)
30143  {
30144  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30145  }
30146 
30147  }
30148 
30149  const double t_total_second_stage_segments_connectivity =
30150  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30151 
30152  const double t_start_snap_nodes_bg_mesh=TimingHelpers::timer();
30153  //Move the nodes on the new boundary onto the old curvilinear
30154  //boundary. If the boundary is straight this will do precisely
30155  //nothing but will be somewhat inefficient
30156  for(unsigned b=0;b<n_boundary;b++)
30157  {
30158  this->snap_nodes_onto_boundary(tmp_new_mesh_pt,b);
30159  }
30160 
30161  const double t_total_snap_nodes_bg_mesh=
30162  TimingHelpers::timer()-t_start_snap_nodes_bg_mesh;
30163 
30164  if (Print_timings_level_adaptation>2)
30165  {
30166  oomph_info<< "CPU for snapping nodes onto boundaries "
30167  << "(background mesh): "
30168  << t_total_snap_nodes_bg_mesh << std::endl;
30169  }
30170 
30171  // Update mesh further?
30172  if(Mesh_update_fct_pt!=0)
30173  {
30174  Mesh_update_fct_pt(tmp_new_mesh_pt);
30175  }
30176 
30177  //If we have a continuation problem
30178  //any problem in which the timestepper is a "generalisedtimestepper",
30179  //which will have been set by the problem, then ensure
30180  //all data in the new mesh has the appropriate timestepper
30181  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30182  {
30183  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30184  this->Time_stepper_pt);
30185  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30186  }*/
30187 
30188 
30189  //tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30190  //this->output("existing_mesh.dat");
30191 
30192  // ==============================================================
30193  // END: Create background mesh
30194  // ==============================================================
30195 
30196  // ==============================================================
30197  // BEGIN: Transferring of target areas and creation of new mesh
30198  // ==============================================================
30199 
30200  // Get the TriangulateIO object associated with that mesh
30201  TriangulateIO tmp_new_triangulateio =
30202  tmp_new_mesh_pt->triangulateio_representation();
30203  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30204 
30205  // If the mesh is a solid mesh then do the mapping based on the
30206  // Eulerian coordinates
30207  bool use_eulerian_coords=false;
30208  if (solid_mesh_pt!=0)
30209  {
30210  use_eulerian_coords=true;
30211  }
30212 
30213 
30214 #ifdef OOMPH_HAS_CGAL
30215 
30216  // Make cgal-based bin
30217  CGALSamplePointContainerParameters cgal_params(this);
30218  if (use_eulerian_coords)
30219  {
30221  }
30222  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&cgal_params);
30223 
30224 #else
30225 
30226  // Make nonrefineable bin
30227  NonRefineableBinArrayParameters params(this);
30228  if (use_eulerian_coords)
30229  {
30231  }
30232  Vector<unsigned> bin_dim(2);
30233  bin_dim[0]=Nbin_x_for_area_transfer;
30234  bin_dim[1]=Nbin_y_for_area_transfer;
30235  params.dimensions_of_bin_array()=bin_dim;
30236  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&params);
30237 
30238 #endif
30239 
30240  // Set up a map from pointer to element to its number
30241  // in the mesh
30242  std::map<GeneralisedElement*,unsigned> element_number;
30243  unsigned nelem=this->nelement();
30244  for (unsigned e=0;e<nelem;e++)
30245  {
30246  element_number[this->element_pt(e)]=e;
30247  }
30248 
30249 #ifndef OOMPH_HAS_CGAL
30250 
30251  // Create a vector to store the min target area of each bin (at
30252  // this stage the number of bins should not be that large, so it
30253  // should be safe to build a vector for the total number of bins)
30254  Vector<double> bin_min_target_area;
30255 
30256  // Get pointer to sample point container
30257  NonRefineableBinArray* bin_array_pt=
30258  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt->
30259  sample_point_container_pt());
30260  if (bin_array_pt==0)
30261  {
30262  throw OomphLibError(
30263  "Sample point container has to be NonRefineableBinArray",
30264  OOMPH_CURRENT_FUNCTION,
30265  OOMPH_EXCEPTION_LOCATION);
30266  }
30267 
30268  {
30269  unsigned n_bin=0;
30270  unsigned max_n_entry=0;
30271  unsigned min_n_entry=UINT_MAX;
30272  unsigned tot_n_entry=0;
30273  unsigned n_empty=0;
30274  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30275  tot_n_entry,n_empty);
30276 
30277  oomph_info << "Before bin diffusion:"
30278  << " nbin:("<<n_bin<<")"
30279  << " nempty:("<<n_empty<<")"
30280  << " min:("<<min_n_entry<<")"
30281  << " max:("<<max_n_entry<<")"
30282  << " average entries:("
30283  << double(tot_n_entry)/double(n_bin)<<")"
30284  << std::endl;
30285  }
30286 
30287  // Fill bin by diffusion
30288  double t0_bin_diff=TimingHelpers::timer();
30289  oomph_info << "Going into diffusion bit...\n";
30290  bin_array_pt->fill_bin_by_diffusion();
30291  oomph_info << "Back from diffusion bit...\n";
30292  oomph_info << "Time for bin diffusion: "
30293  << TimingHelpers::timer()-t0_bin_diff
30294  << std::endl;
30295 
30296  // Do some stats
30297  {
30298  unsigned n_bin=0;
30299  unsigned max_n_entry=0;
30300  unsigned min_n_entry=UINT_MAX;
30301  unsigned tot_n_entry=0;
30302  unsigned n_empty=0;
30303  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30304  tot_n_entry,n_empty);
30305 
30306  oomph_info << "After bin diffusion:"
30307  << " nbin:("<<n_bin<<")"
30308  << " nempty:("<<n_empty<<")"
30309  << " min:("<<min_n_entry<<")"
30310  << " max:("<<max_n_entry<<")"
30311  << " average entries:("
30312  << double(tot_n_entry)/double(n_bin)<<")"
30313  << std::endl;
30314  }
30315 
30316 
30317  // For each bin, compute the minimum of the target areas in the bin
30318 
30319  // Timing for map
30320  double t_total_map=0.0;
30321 
30322  // Counter for map
30323  unsigned counter_map = 0;
30324 
30325  // Get access to the bins (we need access to the content of the
30326  // bins to compute the minimum of the target areas of the elements
30327  // in each bin)
30328  const std::map<unsigned,Vector<std::pair<FiniteElement*,
30329  Vector<double> > > >*
30330  bins_pt=bin_array_pt->get_all_bins_content();
30331 
30332  // Get the number of bins
30333  const unsigned n_bin=bins_pt->size();
30334 
30335  // Create a vector to store the min target area of each bin (at
30336  // this stage the number of bins should not be that large, so it
30337  // should be safe to build a vector for the total number of bins)
30338  bin_min_target_area.resize(n_bin);
30339  for (unsigned u=0;u<n_bin;u++)
30340  {
30341  bin_min_target_area[u]=0.0;
30342  }
30343  // loop over the bins, get their elements and compute the minimum
30344  // target area of all of them
30345  typedef std::map<unsigned,
30346  Vector<std::pair<FiniteElement*,
30347  Vector<double> > > >::const_iterator IT;
30348  for (IT it=bins_pt->begin();it!=bins_pt->end();it++)
30349  {
30350  // The bin number
30351  unsigned ib=(*it).first;
30352 
30353  // Get the number of elements in the bin
30354  const unsigned n_ele_bin = (*it).second.size();
30355 
30356  // loop over the elements in the bin
30357  for (unsigned ee=0;ee<n_ele_bin;ee++)
30358  {
30359  // Get ee-th element (in currrent mesh) in ib-th bin
30360  GeneralisedElement* ele_pt=(*it).second[ee].first;
30361  double t_map=TimingHelpers::timer();
30362  const unsigned ele_number = element_number[ele_pt];
30363  t_total_map+=TimingHelpers::timer()-t_map;
30364 
30365  // Increase the number of calls to map
30366  counter_map++;
30367 
30368  // Go for smallest target area of any element in this bin to
30369  // force "one level" of refinement (the one-level-ness is
30370  // enforced below by limiting the actual reduction in area
30371  if (bin_min_target_area[ib]!=0)
30372  {
30373  bin_min_target_area[ib]=
30374  std::min(bin_min_target_area[ib], target_area[ele_number]);
30375  }
30376  else
30377  {
30378  bin_min_target_area[ib]=target_area[ele_number];
30379  }
30380 
30381  } // for (ee<n_ele_bin)
30382 
30383  } // for (it!=bins.end())
30384 
30385  oomph_info << "CPU for map[counter="<<counter_map<<"]: "
30386  << t_total_map << std::endl;
30387 
30388 
30389  // Optional output for debugging (keep it around!)
30390  const bool output_bins=false;
30391  if (output_bins)
30392  {
30393  unsigned length=bin_min_target_area.size();
30394  for (unsigned u = 0;u<length;u++)
30395  {
30396  oomph_info << "Bin n" << u << ",target area: "
30397  << bin_min_target_area[u]<<std::endl;
30398  }
30399  }
30400 
30401 #endif
30402 
30403 
30404  // Now start iterating to refine mesh recursively
30405  //-----------------------------------------------
30406  bool done=false;
30407  unsigned iter=0;
30408 #ifdef OOMPH_HAS_MPI
30409  // The number of elements that require (un)refinement
30410  unsigned n_ele_need_refinement = 0;
30411 #endif
30412 
30413  // The timing for the third stage of segments connectivity
30414  double t_total_third_stage_segments_connectivity = 0.0;
30415 
30416  // The timing for the transfering target areas
30417  double t_total_transfer_target_areas = 0.0;
30418 
30419  // The timing for the copying of target areas
30420  double t_total_limit_target_areas = 0.0;
30421 
30422  // The timing to create the new mesh
30423  double t_total_create_new_adapted_mesh = 0.0;
30424 
30425  // The timing for the snapping of the nodes on the new meshes
30426  double t_total_snap_nodes = 0.0;
30427 
30428  // The timing to check whether other processors need to adapt
30429  double t_total_wait_other_processors = 0.0;
30430  double t_iter=TimingHelpers::timer();
30431  while (!done)
30432  {
30433  // Accept by default but overwrite if things go wrong below
30434  done=true;
30435 
30436  double t_start_transfer_target_areas=TimingHelpers::timer();
30437  double t0_loop_int_pts=TimingHelpers::timer();
30438 
30439  // Loop over elements in new (tmp) mesh and visit all
30440  // its integration points. Check where it's located in the bin
30441  // structure of the current mesh and pass the target area
30442  // to the new element
30443  nelem=tmp_new_mesh_pt->nelement();
30444 
30445  // Store the target areas for elements in the temporary
30446  // TriangulateIO mesh
30447  Vector<double> new_transferred_target_area(nelem,0.0);
30448  for (unsigned e=0;e<nelem;e++)
30449  { // start loop el
30450  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30451  unsigned nint=el_pt->integral_pt()->nweight();
30452  for (unsigned ipt=0;ipt<nint;ipt++)
30453  {
30454  // Get the coordinate of current point
30455  Vector<double> s(2);
30456  for(unsigned i=0;i<2;i++)
30457  {
30458  s[i] = el_pt->integral_pt()->knot(ipt,i);
30459  }
30460 
30461  Vector<double> x(2);
30462  el_pt->interpolated_x(s,x);
30463 
30464 #if OOMPH_HAS_CGAL
30465 
30466  // Try the five nearest sample points for Newton search
30467  // then just settle on the nearest one
30468  GeomObject* geom_obj_pt=0;
30469  unsigned max_sample_points=
30470  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30471  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt->
30472  sample_point_container_pt())->
30473  limited_locate_zeta(x,max_sample_points,
30474  geom_obj_pt,s);
30475 #ifdef PARANOID
30476  if (geom_obj_pt==0)
30477  {
30478  std::stringstream error_message;
30479  error_message
30480  << "Limited locate zeta failed for zeta = [ "
30481  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30482  throw OomphLibError(error_message.str(),
30483  OOMPH_CURRENT_FUNCTION,
30484  OOMPH_EXCEPTION_LOCATION);
30485  }
30486  else
30487  {
30488 #endif
30489  FiniteElement* fe_pt=dynamic_cast<FiniteElement*>(geom_obj_pt);
30490 #ifdef PARANOID
30491  if (fe_pt==0)
30492  {
30493  std::stringstream error_message;
30494  error_message
30495  << "Cast to FE for GeomObject returned by limited locate zeta failed for zeta = [ "
30496  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30497  throw OomphLibError(error_message.str(),
30498  OOMPH_CURRENT_FUNCTION,
30499  OOMPH_EXCEPTION_LOCATION);
30500  }
30501  else
30502  {
30503 #endif
30504  // What's the target area of the element that contains this point
30505  double tg_area=target_area[element_number[fe_pt]];
30506 
30507  // Go for smallest target area over all integration
30508  // points in new element
30509  // to force "one level" of refinement (the one-level-ness
30510  // is enforced below by limiting the actual reduction in
30511  // area
30512  if (new_transferred_target_area[e]!=0)
30513  {
30514  new_transferred_target_area[e]=
30515  std::min(new_transferred_target_area[e],
30516  tg_area);
30517  }
30518  else
30519  {
30520  new_transferred_target_area[e]=tg_area;
30521  }
30522 #ifdef PARANOID
30523  }
30524  }
30525 #endif
30526 
30527 #else
30528 
30529  // Find the bin that contains that point and its contents
30530  int bin_number=0;
30531  bin_array_pt->get_bin(x,bin_number);
30532 
30533  // Did we find it?
30534  if (bin_number<0)
30535  {
30536  // Not even within bin boundaries... odd
30537  std::stringstream error_message;
30538  error_message
30539  << "Very odd -- we're looking for a point[ "
30540  << x[0] << " " << x[1] << " ] that's not even \n"
30541  << "located within the bin boundaries.\n";
30542  throw OomphLibError(error_message.str(),
30543  "RefineableTriangleMesh::adapt()",
30544  OOMPH_EXCEPTION_LOCATION);
30545  } // if (bin_number<0)
30546  else
30547  {
30548  // Go for smallest target area of any element in this bin
30549  // to force "one level" of refinement (the one-level-ness
30550  // is enforced below by limiting the actual reduction in
30551  // area
30552  if (new_transferred_target_area[e]!=0)
30553  {
30554  new_transferred_target_area[e]=
30555  std::min(new_transferred_target_area[e],
30556  bin_min_target_area[bin_number]);
30557  }
30558  else
30559  {
30560  new_transferred_target_area[e]=bin_min_target_area[bin_number];
30561  }
30562 
30563  }
30564 
30565 #endif
30566 
30567  } // for (ipt<nint)
30568 
30569  } // for (e<nelem)
30570 
30571 
30572  // do some output (keep it alive!)
30573  const bool output_target_areas=false;
30574  if (output_target_areas)
30575  {
30576  unsigned length=new_transferred_target_area.size();
30577  for (unsigned u = 0; u < length;u++)
30578  {
30579  oomph_info << "Element" << u << ",target area: "
30580  << new_transferred_target_area[u] << std::endl;
30581  }
30582  }
30583  oomph_info << "Time for loop over integration points in new mesh: "
30584  << TimingHelpers::timer()-t0_loop_int_pts
30585  << std::endl;
30586 
30587 
30588  // {
30589  // tmp.open((Global_string_for_annotation:: String[0]+"binned_target_areas"+
30590  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30591 
30592  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > > bin_content=
30593  // mesh_geom_obj_pt->bin_content();
30594  // unsigned nbin=bin_content.size();
30595  // for (unsigned b=0;b<nbin;b++)
30596  // {
30597  // unsigned nentry=bin_content[b].size();
30598  // for (unsigned entry=0;entry<nentry;entry++)
30599  // {
30600  // FiniteElement* el_pt=bin_content[b][entry].first;
30601  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30602  // Vector<double> s=bin_content[b][entry].second;
30603  // Vector<double> x(2);
30604  // el_pt->interpolated_x(s,x);
30605  // unsigned e_current=element_number[gen_el_pt];
30606  // tmp << x[0] << " " << x[1] << " "
30607  // << target_area[e_current] << " "
30608  // << el_pt->size() << " "
30609  // << std::endl;
30610  // }
30611  // }
30612  // tmp.close();
30613  // }
30614 
30615  const double t_sub_total_transfer_target_areas =
30616  TimingHelpers::timer()-t_start_transfer_target_areas;
30617 
30618  if (Print_timings_level_adaptation>2)
30619  {
30620  // Get the number of elements in the old mesh (this)
30621  const unsigned n_element = this->nelement();
30622  // Get the number of elements in the background mesh
30623  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30624 
30625  oomph_info << "CPU for transfer of target areas "
30626  << "[n_ele_old_mesh="
30627  << n_element <<", n_ele_background_mesh="
30628  << n_element_background<<"] (iter "<< iter << "): "
30629  << t_sub_total_transfer_target_areas<< std::endl;
30630  }
30631 
30632  // Add the timing for tranfer of target areas
30633  t_total_transfer_target_areas+=t_sub_total_transfer_target_areas;
30634 
30635  // // Output mesh
30636  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30637  // StringConversion::to_string(iter)+".dat").c_str());
30638 
30639  // tmp.open((Global_string_for_annotation:: String[0]+"target_areas_intermediate_mesh_iter"+
30640  // StringConversion::to_string(iter)+"_"+
30641  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30642 
30643  const double t_start_limit_target_areas = TimingHelpers::timer();
30644 
30645  // Now copy into target area for temporary mesh but limit to
30646  // the equivalent of one sub-division per iteration
30647 #ifdef OOMPH_HAS_MPI
30648  unsigned n_ele_need_refinement_iter = 0;
30649 #endif
30650 
30651 
30652  // Don't delete! Keep these around for debugging
30653  // ofstream tmp_mesh_file;
30654  // tmp_mesh_file.open("tmp_mesh_file.dat");
30655  // tmp_new_mesh_pt->output(tmp_mesh_file);
30656  // tmp_mesh_file.close();
30657  // ofstream target_areas_file;
30658  // target_areas_file.open("target_areas_file.dat");
30659 
30660  const unsigned nel_new=tmp_new_mesh_pt->nelement();
30661  Vector<double> new_target_area(nel_new);
30662  for (unsigned e=0;e<nel_new;e++)
30663  {
30664  // The finite element
30665  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30666 
30667  // Transferred target area
30668  const double new_area=new_transferred_target_area[e];
30669  if (new_area<=0.0)
30670  {
30671  std::ostringstream error_stream;
30672  error_stream << "This shouldn't happen! Element whose centroid is at "
30673  << (f_ele_pt->node_pt(0)->x(0)+
30674  f_ele_pt->node_pt(1)->x(0)+
30675  f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30676  << (f_ele_pt->node_pt(0)->x(1)+
30677  f_ele_pt->node_pt(1)->x(1)+
30678  f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30679  << " has no target area assigned\n";
30680  throw OomphLibError(error_stream.str(),
30681  OOMPH_CURRENT_FUNCTION,
30682  OOMPH_EXCEPTION_LOCATION);
30683  }
30684  else
30685  {
30686 
30687 
30688  // Limit target area to the equivalent of uniform refinement
30689  // during this stage of the iteration
30690  new_target_area[e]=new_area;
30691  if (new_target_area[e]<f_ele_pt->size()/3.0)
30692  {
30693  new_target_area[e]=f_ele_pt->size()/3.0;
30694 
30695  // We'll need to give it another go later
30696  done=false;
30697 
30698  }
30699 
30700  // Don't delete! Keep around for debugging
30701  // target_areas_file
30702  // << (f_ele_pt->node_pt(0)->x(0)+
30703  // f_ele_pt->node_pt(1)->x(0)+
30704  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30705  // << (f_ele_pt->node_pt(0)->x(1)+
30706  // f_ele_pt->node_pt(1)->x(1)+
30707  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30708  // << new_area << " "
30709  // << new_target_area[e] << std::endl;
30710 
30711 
30712 
30713 #ifdef OOMPH_HAS_MPI
30714  // Keep track of the elements that require (un)refinement
30715  n_ele_need_refinement_iter++;
30716 #endif
30717 
30718  } // else if (new_area <= 0.0)
30719 
30720  } // for (e < nel_new)
30721 
30722 
30723  // Don't delete! Keep around for debugging
30724  // target_areas_file.close();
30725 
30726  const double t_sub_total_limit_target_areas =
30727  TimingHelpers::timer() - t_start_limit_target_areas;
30728 
30729  // Add the timing for copying target areas
30730  t_total_limit_target_areas+=t_sub_total_limit_target_areas;
30731 
30732  if (Print_timings_level_adaptation>2)
30733  {
30734  // Get the number of elements in the old mesh (this)
30735  const unsigned n_element = this->nelement();
30736  // Get the number of elements in the background mesh
30737  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30738 
30739  oomph_info << "CPU for limiting target areas "
30740  << "[n_ele_old_mesh="
30741  << n_element <<", n_ele_background_mesh="
30742  << n_element_background<<"] (iter "<< iter << "): "
30743  << t_sub_total_limit_target_areas<< std::endl;
30744  }
30745 
30746  if (done)
30747  {
30748  oomph_info
30749  << "All area adjustments accommodated by max. permitted area"
30750  << " reduction \n";
30751  }
30752  else
30753  {
30754  oomph_info
30755  << "NOT all area adjustments accommodated by max. "
30756  << "permitted area reduction \n";
30757  }
30758 
30759  //tmp.close();
30760  //pause("doced binned_target_areas.dat and intermediate mesh targets");
30761 
30762  // Now create the new mesh from TriangulateIO structure
30763  //-----------------------------------------------------
30764  // associated with uniform background mesh and the
30765  //------------------------------------------------
30766  // associated target element sizes.
30767  //---------------------------------
30768 
30769  const double t_start_create_new_adapted_mesh =
30771 
30772  // Solid mesh?
30773  if (solid_mesh_pt!=0)
30774  {
30775  new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30776  (new_target_area,
30777  tmp_new_triangulateio,
30778  this->Time_stepper_pt,
30779  this->Use_attributes,
30780  this->Allow_automatic_creation_of_vertices_on_boundaries,
30781  this->communicator_pt());
30782  }
30783  // No solid mesh
30784  else
30785  {
30786  new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30787  (new_target_area,
30788  tmp_new_triangulateio,
30789  this->Time_stepper_pt,
30790  this->Use_attributes,
30791  this->Allow_automatic_creation_of_vertices_on_boundaries,
30792  this->communicator_pt());
30793  }
30794 
30795  // Sub-total to create new adapted mesh
30796  const double t_sub_total_create_new_adapted_mesh =
30797  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
30798 
30799  // Add the time to the total snap nodes time
30800  t_total_create_new_adapted_mesh+=t_sub_total_create_new_adapted_mesh;
30801 
30802  if (Print_timings_level_adaptation>2)
30803  {
30804  // Get the number of elements of the new adapted mesh
30805  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
30806 
30807  oomph_info << "CPU for creation of new adapted mesh "
30808  << t_sub_total_create_new_adapted_mesh
30809  << "[nele="<<n_element_new_adapted_mesh
30810  << "] (iter "<< iter << "): "
30811  << t_sub_total_create_new_adapted_mesh << std::endl;
30812  }
30813 
30814 #ifdef OOMPH_HAS_MPI
30815  // ------------------------------------------
30816  // DISTRIBUTED MESH: BEGIN
30817  // ------------------------------------------
30818 
30819  // This section is only required if we are dealing with
30820  // distributed meshes, otherwise there are not shared boundaries
30821  // overlapping internal boundaries
30822 
30823  // Check if necessary to fill boundary elements for those internal
30824  // boundaries that overlap shared boundaries
30825  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30826  {
30827  // Copy the data structures that indicate which shared
30828  // boundaries are part of an internal boundary
30830  this->shared_boundary_overlaps_internal_boundary();
30831 
30832  // Copy the data structure that indicates which are the shared
30833  // boundaries in each processor
30834  new_mesh_pt->shared_boundaries_ids() =
30835  this->shared_boundaries_ids();
30836 
30837  // Fill the structures for the boundary elements and face indexes
30838  // of the boundary elements
30839  new_mesh_pt->
30840  fill_boundary_elements_and_nodes_for_internal_boundaries();
30841  }
30842  // ------------------------------------------
30843  // DISTRIBUTED MESH: END
30844  // ------------------------------------------
30845 #endif // #ifdef OOMPH_HAS_MPI
30846 
30847  // Snap to curvilinear boundaries (some code duplication as this
30848  // is repeated below but helper function would take so many
30849  // arguments that it's nearly as messy...
30850 
30851  //Pass the boundary geometric objects to the new mesh
30852  new_mesh_pt->boundary_geom_object_pt() =
30853  this->boundary_geom_object_pt();
30854 
30855  // Reset the boundary coordinates if there is
30856  // a geometric object associated with the boundary
30857  new_mesh_pt->boundary_coordinate_limits() =
30858  this->boundary_coordinate_limits();
30859 
30860  const double t_start_third_stage_segments_connectivity =
30862 
30863  for (unsigned b=0;b<n_boundary;b++)
30864  {
30865  // ------------------------------------------
30866  // DISTRIBUTED MESH: BEGIN
30867  // ------------------------------------------
30868 
30869  // Before setting up boundary coordinates for the new mesh we
30870  // require to identify the segments with the old mesh to
30871  // assign initial zeta values
30872 #ifdef OOMPH_HAS_MPI
30873  if (this->is_mesh_distributed())
30874  {
30875  // Identify the segments of the new mesh with the ones of
30876  // the original mesh
30877  new_mesh_pt->
30878  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30879  }
30880 #endif
30881  // ------------------------------------------
30882  // DISTRIBUTED MESH: END
30883  // ------------------------------------------
30884 
30885  // Setup boundary coordinates for boundaries with GeomObject
30886  // associated
30887  if(new_mesh_pt->boundary_geom_object_pt(b)!=0)
30888  {
30889  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30890  }
30891 
30892  }
30893 
30894  t_total_third_stage_segments_connectivity+=
30895  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
30896 
30897  const double t_start_snap_nodes_new_mesh=TimingHelpers::timer();
30898  //Move the nodes on the new boundary onto the old curvilinear
30899  //boundary. If the boundary is straight this will do precisely
30900  //nothing but will be somewhat inefficient
30901  for(unsigned b=0;b<n_boundary;b++)
30902  {
30903  this->snap_nodes_onto_boundary(new_mesh_pt,b);
30904  }
30905 
30906  const double t_sub_total_snap_nodes_new_mesh =
30907  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
30908 
30909  // Add the time to the total snap nodes time
30910  t_total_snap_nodes+=t_sub_total_snap_nodes_new_mesh;
30911 
30912  if (Print_timings_level_adaptation>2)
30913  {
30914  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
30915  << "(iter "<<iter<<"): "
30916  << t_sub_total_snap_nodes_new_mesh<< std::endl;
30917  }
30918 
30919  // Update mesh further?
30920  if (Mesh_update_fct_pt!=0)
30921  {
30922  Mesh_update_fct_pt(new_mesh_pt);
30923  }
30924 
30925  //If we have a continuation problem
30926  //any problem in which the timestepper is a "generalisedtimestepper",
30927  //which will have been set by the problem, then ensure
30928  //all data in the new mesh has the appropriate timestepper
30929  if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30930  {
30932  this->Time_stepper_pt,false);
30933  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,false);
30934  }
30935 
30936  // Not done: get ready for another iteration
30937  iter++;
30938  delete tmp_new_mesh_pt;
30939 
30940 #ifdef OOMPH_HAS_MPI
30941  // Check whether the number of elements that need (un)refinement
30942  // from the previous iteration is the same, if that is the case
30943  // then we mark this processor as done
30944  if (n_ele_need_refinement_iter == n_ele_need_refinement)
30945  {done = true;}
30946  // Update the number of elements that require further
30947  // (un)refinement
30948  n_ele_need_refinement = n_ele_need_refinement_iter;
30949 #endif // #ifdef OOMPH_HAS_MPI
30950 
30951  // ------------------------------------------
30952  // DISTRIBUTED MESH: BEGIN
30953  // ------------------------------------------
30954 
30955  // We can only finish the iteration adaptation process if ALL
30956  // the involved processor are marked as done, otherwise, ALL
30957  // processor need to go for another iteration
30958 #ifdef OOMPH_HAS_MPI
30959  if (this->is_mesh_distributed())
30960  {
30961  // Time to check whether other processors have finish to adapt
30962  const double t_start_wait_other_processors = TimingHelpers::timer();
30963 
30964  // In case that the mesh is distributed it is necessary to
30965  // verify that no processor requires further refinement. If at
30966  // least one processor needs more refinement then all
30967  // processors need to go for another iteration to participate
30968  // in the communications
30969  unsigned this_processor_requires_another_iteration = 1;
30970 
30971  // Is this processor done?
30972  if (done){this_processor_requires_another_iteration = 0;}
30973  int nproc_not_done = this_processor_requires_another_iteration;
30974  // Get the communicator of the mesh
30975  OomphCommunicator* comm_pt = this->communicator_pt();
30976  // Communicate with all procesoors to check whether we need to
30977  // re-iterate
30978  MPI_Allreduce(&this_processor_requires_another_iteration,
30979  &nproc_not_done,1,
30980  MPI_UNSIGNED,MPI_SUM,comm_pt->mpi_comm());
30981  // Are all processors done?
30982  if (nproc_not_done > 0)
30983  {
30984  oomph_info << "At least one processors requires further refinement. "
30985  << "Go for another iteration." << std::endl;
30986  done = false;
30987  }
30988 
30989  // Total to check whether other processors have finish to
30990  // adapt
30991  const double t_sub_total_wait_other_processors =
30992  TimingHelpers::timer() - t_start_wait_other_processors;
30993 
30994  // Add to the total timings to check whether other processors
30995  // need to adapt
30996  t_total_wait_other_processors+=t_sub_total_wait_other_processors;
30997 
30998  if (Print_timings_level_adaptation>2)
30999  {
31000  oomph_info << "CPU for waiting other processors "
31001  << "(iter "<<iter<<"): "
31002  << t_sub_total_wait_other_processors
31003  << std::endl;
31004  }
31005 
31006  } // if (this->is_mesh_distributed())
31007 #endif
31008  // ------------------------------------------
31009  // DISTRIBUTED MESH: END
31010  // ------------------------------------------
31011 
31012  if (!done)
31013  {
31014  oomph_info << "Going for another iteration. Current iteration ("
31015  << iter << ")" << std::endl;
31016 
31017  // Use the new mesh as the tmp mesh
31018  tmp_new_mesh_pt=new_mesh_pt;
31019  tmp_new_triangulateio=new_mesh_pt->triangulateio_representation();
31020  }
31021 
31022  } // end of iteration (while (!done))
31023 
31024  //Delete the temporary geometric object representation of the
31025  //current mesh
31026  delete mesh_geom_obj_pt;
31027 
31028  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31029  << TimingHelpers::timer()-t_iter
31030  << std::endl;
31031 
31032  if (Print_timings_level_adaptation>1)
31033  {
31034  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31035  << t_total_create_new_adapted_mesh << std::endl;
31036 
31037  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31038  << t_total_limit_target_areas << std::endl;
31039 
31040  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31041  << t_total_transfer_target_areas << std::endl;
31042 
31043  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31044  << t_total_wait_other_processors << std::endl;
31045  }
31046 
31047  // ==============================================================
31048  // END: Transferring of target areas and creation of new mesh
31049  // ==============================================================
31050 
31051  // ==============================================================
31052  // BEGIN: Project solution from the old to the new mesh
31053  // ==============================================================
31054 
31055  // Check that the projection step is not disabled
31056  if (!Disable_projection)
31057  {
31058  // Take the time for the projection step
31059  double tt_start_projection=TimingHelpers::timer();
31060 
31061  // Print info. for tranfering target areas
31062  if (Print_timings_projection)
31063  {
31064  // Switch timings and stats on
31068  }
31069 
31070  double t_proj=TimingHelpers::timer();
31071  oomph_info << "About to begin projection.\n";
31072 
31073  // Project current solution onto new mesh
31074  //---------------------------------------
31075  ProjectionProblem<ELEMENT>* project_problem_pt=
31077 
31078  // Projection requires to be enabled as distributed if working
31079  // with a distributed mesh
31080 #ifdef OOMPH_HAS_MPI
31081  if (this->is_mesh_distributed())
31082  {
31083  // ------------------------------------------
31084  // DISTRIBUTED MESH: BEGIN
31085  // ------------------------------------------
31086 
31087  // We need to back up the time stepper object since the
31088  // projection class creates a new one
31089  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31090 
31091  // Set the projection problem as distributed
31092  project_problem_pt->enable_problem_distributed();
31093 
31094  // Pass the time stepper to the projection problem (used when
31095  // setting multi_domain_interation)
31096  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31097 
31098  // Set the mesh used for the projection object
31099  project_problem_pt->mesh_pt()=new_mesh_pt;
31100  //project_problem_pt->disable_suppress_output_during_projection();
31101 
31102  // Use iterative solver for projection? By default, an iterative
31103  // solver is used for the projection stage
31104  if(!this->use_iterative_solver_for_projection())
31105  {
31106  project_problem_pt->disable_use_iterative_solver_for_projection();
31107  }
31108 
31109  // Do the projection
31110  project_problem_pt->project(this);
31111 
31112  // Reset the time stepper object (only affects distributed meshes)
31113  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31114 
31115  // ------------------------------------------
31116  // DISTRIBUTED MESH: END
31117  // ------------------------------------------
31118 
31119  } // if (this->is_mesh_distributed())
31120  else
31121 #endif // #ifdef OOMPH_HAS_MPI
31122  {
31123  // Set the mesh used for the projection object
31124  project_problem_pt->mesh_pt()=new_mesh_pt;
31125 
31126  // project_problem_pt->disable_suppress_output_during_projection();
31127 
31128  // Use iterative solver for projection? By default, an iterative
31129  // solver is used for the projection stage
31130  if(!this->use_iterative_solver_for_projection())
31131  {
31132  project_problem_pt->disable_use_iterative_solver_for_projection();
31133  }
31134 
31135  // Do the projection
31136  project_problem_pt->project(this);
31137  }
31138 
31139  // Reset printing info. for projection
31140  if (Print_timings_projection)
31141  {
31142  // Switch timings and stats off
31146  }
31147 
31148  // Get the total time for projection
31149  const double tt_projection = TimingHelpers::timer()-tt_start_projection;
31150 
31151  if (Print_timings_level_adaptation>1)
31152  {
31153  // Get the number of elements in the old mesh (this)
31154  const unsigned n_element = this->nelement();
31155  // Get the number of elements in the new mesh
31156  const unsigned n_element_new = new_mesh_pt->nelement();
31157  oomph_info << "CPU for projection (in mesh adaptation) "
31158  << "[n_ele_old_mesh="<< n_element
31159  <<", n_ele_new_mesh="<< n_element_new<<"]: "
31160  << tt_projection << std::endl;
31161 
31162  // ------------------------------------------
31163  // DISTRIBUTED MESH: BEGIN
31164  // ------------------------------------------
31165 #ifdef OOMPH_HAS_MPI
31166  if (this->is_mesh_distributed())
31167  {
31168  // The maximum number of elements in the mesh (over all
31169  // processors)
31170  unsigned n_this_element_new = n_element_new;
31171  unsigned n_max_element_new_global = 0;
31172  // Get the maximum number of elements over all processors
31173  MPI_Reduce(&n_this_element_new, &n_max_element_new_global,
31174  1, MPI_UNSIGNED, MPI_MAX, 0,
31175  this->communicator_pt()->mpi_comm());
31176 
31177  // The time for projection for this processor
31178  double tt_this_projection = tt_projection;
31179  double tt_global_min_projection = 0.0;
31180  double tt_global_max_projection = 0.0;
31181 
31182  // Get the minimum and maximum time for projection
31183  MPI_Reduce(&tt_this_projection, &tt_global_min_projection,
31184  1, MPI_DOUBLE, MPI_MIN, 0,
31185  this->communicator_pt()->mpi_comm());
31186  MPI_Reduce(&tt_this_projection, &tt_global_max_projection,
31187  1, MPI_DOUBLE, MPI_MAX, 0,
31188  this->communicator_pt()->mpi_comm());
31189 
31190  if (this->communicator_pt()->my_rank() == 0)
31191  {
31192  oomph_info << "CPU for projection global (MIN): "
31193  << tt_global_min_projection << std::endl;
31194  oomph_info << "CPU for projection global (MAX) "
31195  << "[n_max_ele_new_global="
31196  << n_max_element_new_global<<"]: "
31197  << tt_global_max_projection << std::endl;
31198 
31199  std::cerr << "CPU for projection global (MIN): "
31200  << tt_global_min_projection << std::endl;
31201  std::cerr << "CPU for projection global (MAX): "
31202  << "[n_max_ele_new_global="
31203  << n_max_element_new_global<<"]: "
31204  << tt_global_max_projection << std::endl;
31205 
31206  }
31207 
31208  }
31209 #endif // #ifdef OOMPH_HAS_MPI
31210  // ------------------------------------------
31211  // DISTRIBUTED MESH: END
31212  // ------------------------------------------
31213 
31214  } // if (Print_timings_level_adaptation>1)
31215 
31216  oomph_info << "CPU for projection of solution onto new mesh: "
31217  << TimingHelpers::timer()-t_proj
31218  << std::endl;
31219 
31220  // Delete the projection problem
31221  delete project_problem_pt;
31222 
31223  } // if (!Disable_projection)
31224  else
31225  {
31226  oomph_info << "Projection disabled! The new mesh will contain zeros"
31227  << std::endl;
31228  }
31229 
31230  // ==============================================================
31231  // END: Project solution from the old to the new mesh
31232  // ==============================================================
31233 
31234  double t_rest=TimingHelpers::timer();
31235 
31236  //Flush the old mesh
31237  unsigned nnod=nnode();
31238  for(unsigned j=nnod;j>0;j--)
31239  {
31240  delete Node_pt[j-1];
31241  Node_pt[j-1] = 0;
31242  }
31243  unsigned nel=nelement();
31244  for(unsigned e=nel;e>0;e--)
31245  {
31246  delete Element_pt[e-1];
31247  Element_pt[e-1] = 0;
31248  }
31249 
31250  // Now copy back to current mesh
31251  //------------------------------
31252  nnod=new_mesh_pt->nnode();
31253  Node_pt.resize(nnod);
31254  nel=new_mesh_pt->nelement();
31255  Element_pt.resize(nel);
31256  for(unsigned j=0;j<nnod;j++)
31257  {
31258  Node_pt[j] = new_mesh_pt->node_pt(j);
31259  }
31260  for(unsigned e=0;e<nel;e++)
31261  {
31262  Element_pt[e] = new_mesh_pt->element_pt(e);
31263  }
31264 
31265  // Copy the boundary elements information from the new mesh to the
31266  // original mesh
31267  unsigned nbound = 0;
31268 
31269 #ifdef OOMPH_HAS_MPI
31270  // If working with a distributed mesh we need to change the number
31271  // of boundaries so that shared boundaries information is also
31272  // copied from the old to the new mesh
31273  if (this->is_mesh_distributed())
31274  {
31275  // The boundaries to be copied include those new ones in the new
31276  // mesh (shared boundaries). This info. is required to
31277  // re-establish the halo/haloed scheme
31278  nbound = new_mesh_pt->nboundary();
31279  // After halo and haloed scheme has been re-established the
31280  // number of boundaries is changed to the original number of
31281  // boundaries
31282  }
31283  else
31284 #endif
31285  {
31286  // The original number of boundaries
31287  nbound = n_boundary;
31288  }
31289 
31290  Boundary_element_pt.resize(nbound);
31291  Face_index_at_boundary.resize(nbound);
31292  Boundary_node_pt.resize(nbound);
31293  for (unsigned b=0;b<nbound;b++)
31294  {
31295  unsigned nel=new_mesh_pt->nboundary_element(b);
31296  Boundary_element_pt[b].resize(nel);
31297  Face_index_at_boundary[b].resize(nel);
31298  for (unsigned e=0;e<nel;e++)
31299  {
31300  Boundary_element_pt[b][e]=new_mesh_pt->boundary_element_pt(b,e);
31301  Face_index_at_boundary[b][e]=new_mesh_pt->face_index_at_boundary(b,e);
31302  }
31303  unsigned nnod=new_mesh_pt->nboundary_node(b);
31304  Boundary_node_pt[b].resize(nnod);
31305  for (unsigned j=0;j<nnod;j++)
31306  {
31307  Boundary_node_pt[b][j]=new_mesh_pt->boundary_node_pt(b,j);
31308  }
31309  }
31310 
31311  //Also copy over the new boundary and region information
31312  unsigned n_region = new_mesh_pt->nregion();
31313  // Only bother if we have regions
31314  if(n_region > 1)
31315  {
31316  //Deal with the region information first
31317  this->Region_attribute.resize(n_region);
31318  for(unsigned r=0;r<n_region;r++)
31319  {
31320  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31321  // Get the region id
31322  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31323  //Find the number of elements in the region
31324  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31325  this->Region_element_pt[r_id].resize(n_region_element);
31326  for(unsigned e=0;e<n_region_element;e++)
31327  {
31328  this->Region_element_pt[r_id][e] =
31329  new_mesh_pt->region_element_pt(r_id,e);
31330  }
31331  }
31332 
31333  //Now the boundary region information
31334  this->Boundary_region_element_pt.resize(nbound);
31335  this->Face_index_region_at_boundary.resize(nbound);
31336 
31337  //Now loop over the boundaries
31338  for(unsigned b=0;b<nbound;++b)
31339  {
31340  for (unsigned rr = 0 ; rr < n_region; rr++)
31341  {
31342  // The region id
31343  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31344 
31345  unsigned n_boundary_el_in_region =
31346  new_mesh_pt->nboundary_element_in_region(b,r);
31347 
31348  if(n_boundary_el_in_region > 0)
31349  {
31350  //Allocate storage in the map
31351  this->Boundary_region_element_pt[b][r].
31352  resize(n_boundary_el_in_region);
31353  this->Face_index_region_at_boundary[b][r].
31354  resize(n_boundary_el_in_region);
31355 
31356  //Copy over the information
31357  for(unsigned e=0;e<n_boundary_el_in_region;++e)
31358  {
31359  this->Boundary_region_element_pt[b][r][e]
31360  = new_mesh_pt->boundary_element_in_region_pt(b,r,e);
31361  this->Face_index_region_at_boundary[b][r][e]
31362  = new_mesh_pt->face_index_at_boundary_in_region(b,r,e);
31363  }
31364  }
31365  }
31366  } //End of loop over boundaries
31367 
31368  } //End of case when more than one region
31369 
31370  // ------------------------------------------
31371  // DISTRIBUTED MESH: BEGIN
31372  // ------------------------------------------
31373 
31374  // Re-generate halo(ed) information (only for distributed meshes)
31375 #ifdef OOMPH_HAS_MPI
31376  if (this->is_mesh_distributed())
31377  {
31378  // Delete halo(ed) information in the original mesh, the new
31379  // halo(ed) information is generated usign the info. of the new
31380  // mesh
31381  if (this->is_mesh_distributed())
31382  {
31383  this->Halo_node_pt.clear();
31384  this->Root_halo_element_pt.clear();
31385 
31386  this->Haloed_node_pt.clear();
31387  this->Root_haloed_element_pt.clear();
31388 
31389  this->External_halo_node_pt.clear();
31390  this->External_halo_element_pt.clear();
31391 
31392  this->External_haloed_node_pt.clear();
31393  this->External_haloed_element_pt.clear();
31394  }
31395 
31396  // Re-establish the shared boundary elements and nodes scheme
31397  // before re-establish halo(ed) information
31398  this->reset_shared_boundary_elements_and_nodes();
31399 
31400  // -------------------------------------------------------------
31401  // Remove shared boundary elements and nodes from original
31402  // boundary elements and boundary nodes containers. Shared
31403  // boundary elements and nodes are stored in a special
31404  // container.
31405 
31406  // Get the shared boundaries in this processor with any other
31407  // processor
31408  Vector<unsigned> my_rank_shared_boundaries_ids;
31409  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
31410 
31411  // Get the number of shared boundaries
31412  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31413  // Loop over the shared boundaries marked as original boundaries
31414  // in tmp_new_mesh
31415  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31416  {
31417  // Get the boundary id
31418  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31419  // Flush any previous relation of shared boundary elements
31420  // marked as original boundary elements in tmp_new_mesh
31421  this->Boundary_element_pt[shd_bnd_id].clear();
31422 
31423  // Get the number of nodes associated with the original
31424  // boundary in tmp_new_mesh that is a shared boundary
31425  const unsigned tmp_nnodes =
31426  this->nshared_boundary_node(shd_bnd_id);
31427  for (unsigned n = 0; n < tmp_nnodes; n++)
31428  {
31429  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31430  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31431  } // for (n < nnodes)
31432 
31433  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31434 
31435  // Re-set the number of boundaries to the original one
31436  this->set_nboundary(n_boundary);
31437 
31438  // Sort the nodes on the boundaries so that they have the same
31439  // order on all the boundaries
31440  this->sort_nodes_on_shared_boundaries();
31441 
31442  // Re-set the halo(ed) scheme
31443  this->reset_halo_haloed_scheme();
31444 
31445  // Set the correct number of segments for the boundaries with
31446  // geom objects associated
31447  for (unsigned b = 0; b < n_boundary; b++)
31448  {
31449  if (this->boundary_geom_object_pt(b)!=0)
31450  {
31451  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31452  this->set_nboundary_segment_node(b, nsegments);
31453  }
31454  }
31455 
31456  // Resume the connections in boundaries were it was suspended
31457  resume_boundary_connections(resume_initial_connection_polyline_pt,
31458  resume_final_connection_polyline_pt);
31459 
31460  } // if (this->is_mesh_distributed())
31461 
31462 #endif // #ifdef OOMPH_HAS_MPI
31463 
31464  // ------------------------------------------
31465  // DISTRIBUTED MESH: END
31466  // ------------------------------------------
31467 
31468  //Snap the newly created nodes onto any geometric objects
31469  this->snap_nodes_onto_geometric_objects();
31470 
31471  // Copy the IDs of the vertex nodes
31472  this->Oomph_vertex_nodes_id=new_mesh_pt->oomph_vertex_nodes_id();
31473 
31474  // Copy TriangulateIO representation
31475  TriangleHelper::clear_triangulateio(this->Triangulateio);
31476  bool quiet=true;
31477  this->Triangulateio=
31479  new_mesh_pt->triangulateio_representation(),quiet);
31480 
31481  // Flush the mesh
31482  new_mesh_pt->flush_element_and_node_storage();
31483 
31484  // Delete the mesh
31485  delete new_mesh_pt;
31486 
31487  // Resume of timings
31488  if (Print_timings_level_adaptation>2)
31489  {
31490  // Report timings related with setting boundary coordinates of
31491  // nodes on segments
31492  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31493  << t_total_first_stage_segments_connectivity << std::endl;
31494  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31495  << t_total_second_stage_segments_connectivity << std::endl;
31496  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31497  << t_total_third_stage_segments_connectivity << std::endl;
31498  }
31499 
31500  if (Print_timings_level_adaptation>1)
31501  {
31502  const double t_total_segments_connectivity =
31503  t_total_first_stage_segments_connectivity +
31504  t_total_second_stage_segments_connectivity +
31505  t_total_third_stage_segments_connectivity;
31506 
31507  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31508  << t_total_segments_connectivity << std::endl;
31509 
31510  if (Print_timings_level_adaptation>2)
31511  {
31512  // Report timings for snapping of nodes onto boundaries
31513  oomph_info << "CPU for snapping nodes onto boundaries "
31514  << "(new mesh): "
31515  << t_total_snap_nodes << std::endl;
31516  }
31517 
31518  t_total_snap_nodes+=t_total_snap_nodes_bg_mesh;
31519  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31520  << t_total_snap_nodes << std::endl;
31521  }
31522 
31523  double max_area=0.0;
31524  double min_area=0.0;
31525 
31526  this->max_and_min_element_size(max_area, min_area);
31527  oomph_info << "Max/min element size in adapted mesh: "
31528  << max_area << " "
31529  << min_area << std::endl;
31530 
31531  oomph_info << "CPU time for final bits [sec]: "
31532  << TimingHelpers::timer()-t_rest
31533  << std::endl;
31534  }
31535  else
31536  {
31537  oomph_info << "Not enough benefit in adaptation.\n";
31538  Nrefined=0;
31539  Nunrefined=0;
31540  }
31541 
31542  double CPU_for_adaptation = TimingHelpers::timer()-t_start_overall;
31543  oomph_info <<"CPU time for adaptation [sec]: "
31544  << CPU_for_adaptation << std::endl;
31545 
31546  // ------------------------------------------
31547  // DISTRIBUTED MESH: BEGIN
31548  // ------------------------------------------
31549 #ifdef OOMPH_HAS_MPI
31550  if (this->is_mesh_distributed())
31551  {
31552  // Get the communicator
31553  OomphCommunicator* comm_pt = this->communicator_pt();
31554  // Get the total number of processors to compute the average
31555  const unsigned n_proc = comm_pt->nproc();
31556  if (Print_timings_level_adaptation>1 && n_proc>1)
31557  {
31558  double global_min_CPU_for_adaptation = 0.0;
31559  double global_max_CPU_for_adaptation = 0.0;
31560  double global_average_CPU_for_adaptation = 0.0;
31561 
31562  // Get the maximum and minimum of the adaptation times
31563  MPI_Reduce(&CPU_for_adaptation, &global_min_CPU_for_adaptation,
31564  1, MPI_DOUBLE, MPI_MIN, 0, comm_pt->mpi_comm());
31565  MPI_Reduce(&CPU_for_adaptation, &global_max_CPU_for_adaptation,
31566  1, MPI_DOUBLE, MPI_MAX, 0, comm_pt->mpi_comm());
31567  MPI_Reduce(&CPU_for_adaptation, &global_average_CPU_for_adaptation,
31568  1, MPI_DOUBLE, MPI_SUM, 0, comm_pt->mpi_comm());
31569 
31570  // Get the rank of the processor
31571  const unsigned my_rank = comm_pt->my_rank();
31572  if (my_rank==0)
31573  {
31574  oomph_info << "CPU for adaptation (MIN): "
31575  << global_min_CPU_for_adaptation << std::endl;
31576  oomph_info << "CPU for adaptation (MAX): "
31577  << global_max_CPU_for_adaptation << std::endl;
31578  oomph_info << "CPU for adaptation (AVERAGE): "
31579  << global_average_CPU_for_adaptation/n_proc << std::endl;
31580  } // if (my_rank==0)
31581 
31582  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31583 
31584  } // if (this->is_mesh_distributed())
31585 
31586  // ------------------------------------------
31587  // DISTRIBUTED MESH: END
31588  // ------------------------------------------
31589 
31590 #endif // #ifdef OOMPH_HAS_MPI
31591 
31592 
31593 
31594  }
31595 
31596 //=========================================================================
31597  /// \ short Mark the vertices that are not allowed for deletion by
31598  /// the unrefienment/refinement polyline methods. In charge of
31599  /// filling the Boundary_connections_pt structure
31600  //=========================================================================
31601  template<class ELEMENT>
31603  {
31604  // Clear any previous information
31605  //Boundary_chunk_connections_pt.clear();
31606  Boundary_connections_pt.clear();
31607 
31608  // Loop over the boundaries in the domain (outer, internal -- closed
31609  // and open ---, and shared) and get the boundaries ids with
31610  // connections (have or receive)
31611 
31612  // Store the boundaries ids that have or receive connection
31613  std::set<unsigned> boundary_id_with_connections;
31614 
31615  // ------------------------------------------------------------------
31616  // Outer boundaries
31617  // ------------------------------------------------------------------
31618 
31619  // Get the number of outer boundaries (closed boundaries)
31620  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31621 
31622  // Loop over the outer boundaries
31623  for (unsigned i = 0; i < n_outer_boundaries; i++)
31624  {
31625  // Get a temporary polygon representation
31626  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31627  // Get the number of polylines associated to the current outer
31628  // boundary
31629  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31630  // Loop over the polylines
31631  for (unsigned p = 0; p < n_polyline; p++)
31632  {
31633  // Get a temporary representation of the polyline
31634  TriangleMeshPolyLine* tmp_polyline_pt =
31635  tmp_polygon_pt->polyline_pt(p);
31636 
31637  // Is the initial vertex connected?
31638  if (tmp_polyline_pt->is_initial_vertex_connected())
31639  {
31640  // Get the boundary id of the current polyline
31641  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31642 
31643  // Include the boundary id to the set of boundaries with
31644  // connections
31645  boundary_id_with_connections.insert(bnd_id);
31646 
31647  // Boundary id to which the curve is connecte
31648  const unsigned dst_bnd_id =
31649  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31650 
31651  // Include the destination boundary id to the set of
31652  // boundaries with connections
31653  boundary_id_with_connections.insert(dst_bnd_id);
31654 
31655  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31656 
31657  // Is the final vertex connected?
31658  if (tmp_polyline_pt->is_final_vertex_connected())
31659  {
31660  // Get the boundary id of the current polyline
31661  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31662 
31663  // Include the boundary id to the set of boundaries with
31664  // connections
31665  boundary_id_with_connections.insert(bnd_id);
31666 
31667  // Boundary id to which the curve is connected
31668  const unsigned dst_bnd_id =
31669  tmp_polyline_pt->final_vertex_connected_bnd_id();
31670 
31671  // Include the destination boundary id to the set of
31672  // boundaries with connections
31673  boundary_id_with_connections.insert(dst_bnd_id);
31674 
31675  } // if (tmp_polyline_pt->is_final_vertex_connected())
31676 
31677  } // for (p < n_polyline)
31678 
31679  } // for (i < n_outer_boundaries)
31680 
31681  // ------------------------------------------------------------------
31682  // Internal boundaries
31683  // ------------------------------------------------------------------
31684 
31685  // Get the number of internal boundaries (closed boundaries)
31686  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31687 
31688  // Loop over the internal boundaries
31689  for (unsigned i = 0; i < n_internal_boundaries; i++)
31690  {
31691  // Get a temporary polygon representation
31692  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31693  // Get the number of polylines associated to the current internal
31694  // boundary
31695  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31696  // Loop over the polylines
31697  for (unsigned p = 0; p < n_polyline; p++)
31698  {
31699  // Get a temporary representation of the polyline
31700  TriangleMeshPolyLine* tmp_polyline_pt =
31701  tmp_polygon_pt->polyline_pt(p);
31702 
31703  // Is the initial vertex connected?
31704  if (tmp_polyline_pt->is_initial_vertex_connected())
31705  {
31706  // Get the boundary id of the current polyline
31707  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31708 
31709  // Include the boundary id to the set of boundaries with
31710  // connections
31711  boundary_id_with_connections.insert(bnd_id);
31712 
31713  // Boundary id to which the curve is connecte
31714  const unsigned dst_bnd_id =
31715  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31716 
31717  // Include the destination boundary id to the set of
31718  // boundaries with connections
31719  boundary_id_with_connections.insert(dst_bnd_id);
31720 
31721  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31722 
31723  // Is the final vertex connected?
31724  if (tmp_polyline_pt->is_final_vertex_connected())
31725  {
31726  // Get the boundary id of the current polyline
31727  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31728 
31729  // Include the boundary id to the set of boundaries with
31730  // connections
31731  boundary_id_with_connections.insert(bnd_id);
31732 
31733  // Boundary id to which the curve is connected
31734  const unsigned dst_bnd_id =
31735  tmp_polyline_pt->final_vertex_connected_bnd_id();
31736 
31737  // Include the destination boundary id to the set of
31738  // boundaries with connections
31739  boundary_id_with_connections.insert(dst_bnd_id);
31740 
31741  } // if (tmp_polyline_pt->is_final_vertex_connected())
31742 
31743  } // for (p < n_polyline)
31744 
31745  } // for (i < n_internal_boundaries)
31746 
31747  // ------------------------------------------------------------------
31748  // Open boundaries (nonclosed internal boundaries)
31749  // ------------------------------------------------------------------
31750 
31751  // Get the number of internal boundaries (open boundaries)
31752  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
31753 
31754  // Loop over the internal open boundaries
31755  for (unsigned i = 0; i < n_open_boundaries; i++)
31756  {
31757  // Get a temporary representation for the open curve
31758  TriangleMeshOpenCurve* tmp_open_curve_pt =
31759  this->Internal_open_curve_pt[i];
31760 
31761  // Get the number of curve sections associated to the current
31762  // internal open boundary
31763  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
31764 
31765  // Loop over the curve section
31766  for (unsigned p = 0; p < n_curve_section; p++)
31767  {
31768  // Get a temporary representation of the curve section
31769  // (polyline)
31770  TriangleMeshPolyLine* tmp_polyline_pt =
31771  tmp_open_curve_pt->polyline_pt(p);
31772 
31773  // Is the initial vertex connected?
31774  if (tmp_polyline_pt->is_initial_vertex_connected())
31775  {
31776  // Get the boundary id of the current polyline
31777  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31778 
31779  // Include the boundary id to the set of boundaries with
31780  // connections
31781  boundary_id_with_connections.insert(bnd_id);
31782 
31783  // Boundary id to which the curve is connecte
31784  const unsigned dst_bnd_id =
31785  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31786 
31787  // Include the destination boundary id to the set of
31788  // boundaries with connections
31789  boundary_id_with_connections.insert(dst_bnd_id);
31790 
31791  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31792 
31793  // Is the final vertex connected?
31794  if (tmp_polyline_pt->is_final_vertex_connected())
31795  {
31796  // Get the boundary id of the current polyline
31797  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31798 
31799  // Include the boundary id to the set of boundaries with
31800  // connections
31801  boundary_id_with_connections.insert(bnd_id);
31802 
31803  // Boundary id to which the curve is connected
31804  const unsigned dst_bnd_id =
31805  tmp_polyline_pt->final_vertex_connected_bnd_id();
31806 
31807  // Include the destination boundary id to the set of
31808  // boundaries with connections
31809  boundary_id_with_connections.insert(dst_bnd_id);
31810 
31811  } // if (tmp_polyline_pt->is_final_vertex_connected())
31812 
31813  } // for (p < n_curve_section)
31814 
31815  } // for (i < n_open_boundaries)
31816 
31817 #ifdef OOMPH_HAS_MPI
31818  // ------------------------------------------------------------------
31819  // Shared boundaries (only for distributed meshes)
31820  // ------------------------------------------------------------------
31821 
31822  // Check if we need to include any information associated with
31823  // shared boundaries
31824  if (this->is_mesh_distributed())
31825  {
31826  // Get the rank of the current processor
31827  const unsigned my_rank = this->communicator_pt()->my_rank();
31828 
31829  // Get the number of shared curves in the current processor
31830  const unsigned n_shared_curves =
31831  this->nshared_boundary_curves(my_rank);
31832 
31833  // Loop over the shared curves
31834  for (unsigned i = 0; i < n_shared_curves; i ++)
31835  {
31836  // Get the number of polylines associated to the current shared
31837  // curve
31838  const unsigned n_polyline =
31839  this->nshared_boundary_polyline(my_rank, i);
31840 
31841  // Loop over the polylines associated to the current shared
31842  // curve
31843  for (unsigned p = 0; p < n_polyline; p++)
31844  {
31845  // Get a temporary representation of the shared polyline
31846  TriangleMeshPolyLine* tmp_polyline_pt =
31847  this->shared_boundary_polyline_pt(my_rank, i, p);
31848 
31849  // Is the initial vertex connected?
31850  if (tmp_polyline_pt->is_initial_vertex_connected())
31851  {
31852  // Get the boundary id of the current polyline
31853  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31854 
31855  // Include the boundary id to the set of boundaries with
31856  // connections
31857  boundary_id_with_connections.insert(bnd_id);
31858 
31859  // Boundary id to which the curve is connecte
31860  const unsigned dst_bnd_id =
31861  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31862 
31863  // Include the destination boundary id to the set of
31864  // boundaries with connections
31865  boundary_id_with_connections.insert(dst_bnd_id);
31866 
31867  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31868 
31869  // Is the final vertex connected?
31870  if (tmp_polyline_pt->is_final_vertex_connected())
31871  {
31872  // Get the boundary id of the current polyline
31873  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31874 
31875  // Include the boundary id to the set of boundaries with
31876  // connections
31877  boundary_id_with_connections.insert(bnd_id);
31878 
31879  // Boundary id to which the curve is connected
31880  const unsigned dst_bnd_id =
31881  tmp_polyline_pt->final_vertex_connected_bnd_id();
31882 
31883  // Include the destination boundary id to the set of
31884  // boundaries with connections
31885  boundary_id_with_connections.insert(dst_bnd_id);
31886 
31887  } // if (tmp_polyline_pt->is_final_vertex_connected())
31888 
31889  } // for (p < n_polyline)
31890 
31891  } // for (i < n_shared_curves)
31892 
31893  } // if (this->is_mesh_distributed())
31894 
31895 #endif // #ifdef OOMPH_HAS_MPI
31896 
31897  // ---------------------------------------------------------------
31898  // Get the nodes sorted by segments of the boundaries with
31899  // connections
31900 
31901  // Store the sorted nodes by segments of the boundaries with
31902  // connections
31903  std::map<unsigned, Vector<Vector<Node*> > > bnd_sorted_segment_node_pt;
31904 
31905  // Loop over the boundaries with connections
31906  for (std::set<unsigned>::iterator it =
31907  boundary_id_with_connections.begin();
31908  it != boundary_id_with_connections.end(); it++)
31909  {
31910  // Get the boundary id
31911  const unsigned bnd_id = (*it);
31912 #ifdef OOMPH_HAS_MPI
31913  // Working with a distributed mesh
31914  if (this->is_mesh_distributed())
31915  {
31916  // Get the initial shared boundary id
31917  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
31918  // Is an original or shared boundary
31919  if (bnd_id >= init_shd_bnd_id)
31920  {
31921  // Is a shared boundary
31922 
31923  // Temporary storage for the nodes on the shared boundary
31924  Vector<Vector<Node*> > tmp_shared_nodes_pt;
31925 
31926  // Get the nodes associated to the shared boundary
31927  get_shared_boundary_segment_nodes_helper(bnd_id,
31928  tmp_shared_nodes_pt);
31929 
31930  // Store the nodes associated to the shared boundary
31931  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
31932 
31933  } // if (bnd_id >= init_shd_bnd_id)
31934  else
31935  {
31936  // Is an original boundary
31937 
31938  // Temporary storage for the nodes on the original boundary
31939  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31940 
31941  // Get the nodes associated to the shared boundary
31942  get_boundary_segment_nodes_helper(bnd_id,
31943  tmp_boundary_nodes_pt);
31944 
31945  // Store the nodes associated to the shared boundary
31946  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31947 
31948  } // if (bnd_id >= init_shd_bnd_id)
31949 
31950  } // if (this->is_mesh_distributed())
31951  else
31952 #endif // #ifdef OOMPH_HAS_MPI
31953  {
31954  // Is an original boundary
31955 
31956  // Temporary storage for the nodes on the original boundary
31957  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31958 
31959  // Get the nodes associated to the shared boundary
31960  get_boundary_segment_nodes_helper(bnd_id,
31961  tmp_boundary_nodes_pt);
31962 
31963  // Store the nodes associated to the shared boundary
31964  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31965 
31966  } // if (this->is_mesh_distributed())
31967 
31968  } // Loop over boundaries with connections
31969 
31970  // -----------------------------------------------------------------
31971  // Loop again over the boundaries (original and shared) and search
31972  // for the repeated nodes in those boundaries with connections
31973 
31974  // ------------------------------------------------------------------
31975  // Outer boundaries
31976  // ------------------------------------------------------------------
31977  // Loop over the outer boundaries
31978  for (unsigned i = 0; i < n_outer_boundaries; i++)
31979  {
31980  // Get a temporary polygon representation
31981  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31982  // Get the number of polylines associated to the current outer
31983  // boundary
31984  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31985  // Loop over the polylines
31986  for (unsigned p = 0; p < n_polyline; p++)
31987  {
31988  // Get a temporary representation of the polyline
31989  TriangleMeshPolyLine* tmp_polyline_pt =
31990  tmp_polygon_pt->polyline_pt(p);
31991 
31992  // Is the initial vertex connected?
31993  if (tmp_polyline_pt->is_initial_vertex_connected())
31994  {
31995  // Get the boundary id of the current polyline
31996  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31997 
31998  // Boundary id to which the curve is connected
31999  const unsigned dst_bnd_id =
32000  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32001 
32002  // Boundary chunk to which the curve is connected
32003  const unsigned dst_chunk =
32004  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32005 
32006  // Get the nodes representation of the current boundary
32007  Vector<Vector<Node*> > src_bnd_node_pt =
32008  bnd_sorted_segment_node_pt[bnd_id];
32009 
32010  // Get the nodes representation of the boundary to connect
32011  Vector<Vector<Node*> > dst_bnd_node_pt =
32012  bnd_sorted_segment_node_pt[dst_bnd_id];
32013 
32014  // Add the repeated node to the list of non delete-able
32015  // vertices
32016  add_non_delete_vertices_from_boundary_helper(
32017  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32018 
32019  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32020 
32021  // Is the final vertex connected?
32022  if (tmp_polyline_pt->is_final_vertex_connected())
32023  {
32024  // Get the boundary id of the current polyline
32025  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32026 
32027  // Boundary id to which the curve is connected
32028  const unsigned dst_bnd_id =
32029  tmp_polyline_pt->final_vertex_connected_bnd_id();
32030 
32031  // Boundary chunk to which the curve is connected
32032  const unsigned dst_chunk =
32033  tmp_polyline_pt->final_vertex_connected_n_chunk();
32034 
32035  // Get the nodes representation of the current boundary
32036  Vector<Vector<Node*> > src_bnd_node_pt =
32037  bnd_sorted_segment_node_pt[bnd_id];
32038 
32039  // Get the nodes representation of the boundary to connect
32040  Vector<Vector<Node*> > dst_bnd_node_pt =
32041  bnd_sorted_segment_node_pt[dst_bnd_id];
32042 
32043  // Add the repeated node to the list of non delete-able
32044  // vertices
32045  add_non_delete_vertices_from_boundary_helper(
32046  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32047 
32048  } // if (tmp_polyline_pt->is_final_vertex_connected())
32049 
32050  } // for (p < n_polyline)
32051 
32052  } // for (i < n_outer_boundaries)
32053 
32054  // ------------------------------------------------------------------
32055  // Internal boundaries
32056  // ------------------------------------------------------------------
32057  // Loop over the internal boundaries
32058  for (unsigned i = 0; i < n_internal_boundaries; i++)
32059  {
32060  // Get a temporary polygon representation
32061  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32062  // Get the number of polylines associated to the current internal
32063  // boundary
32064  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32065  // Loop over the polylines
32066  for (unsigned p = 0; p < n_polyline; p++)
32067  {
32068  // Get a temporary representation of the polyline
32069  TriangleMeshPolyLine* tmp_polyline_pt =
32070  tmp_polygon_pt->polyline_pt(p);
32071 
32072  // Is the initial vertex connected?
32073  if (tmp_polyline_pt->is_initial_vertex_connected())
32074  {
32075  // Get the boundary id of the current polyline
32076  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32077 
32078  // Boundary id to which the curve is connected
32079  const unsigned dst_bnd_id =
32080  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32081 
32082  // Boundary chunk to which the curve is connected
32083  const unsigned dst_chunk =
32084  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32085 
32086  // Get the nodes representation of the current boundary
32087  Vector<Vector<Node*> > src_bnd_node_pt =
32088  bnd_sorted_segment_node_pt[bnd_id];
32089 
32090  // Get the nodes representation of the boundary to connect
32091  Vector<Vector<Node*> > dst_bnd_node_pt =
32092  bnd_sorted_segment_node_pt[dst_bnd_id];
32093 
32094  // Add the repeated node to the list of non delete-able
32095  // vertices
32096  add_non_delete_vertices_from_boundary_helper(
32097  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32098 
32099  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32100 
32101  // Is the final vertex connected?
32102  if (tmp_polyline_pt->is_final_vertex_connected())
32103  {
32104  // Get the boundary id of the current polyline
32105  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32106 
32107  // Boundary id to which the curve is connected
32108  const unsigned dst_bnd_id =
32109  tmp_polyline_pt->final_vertex_connected_bnd_id();
32110 
32111  // Boundary chunk to which the curve is connected
32112  const unsigned dst_chunk =
32113  tmp_polyline_pt->final_vertex_connected_n_chunk();
32114 
32115  // Get the nodes representation of the current boundary
32116  Vector<Vector<Node*> > src_bnd_node_pt =
32117  bnd_sorted_segment_node_pt[bnd_id];
32118 
32119  // Get the nodes representation of the boundary to connect
32120  Vector<Vector<Node*> > dst_bnd_node_pt =
32121  bnd_sorted_segment_node_pt[dst_bnd_id];
32122 
32123  // Add the repeated node to the list of non delete-able
32124  // vertices
32125  add_non_delete_vertices_from_boundary_helper(
32126  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32127 
32128  } // if (tmp_polyline_pt->is_final_vertex_connected())
32129 
32130  } // for (p < n_polyline)
32131 
32132  } // for (i < n_internal_boundaries)
32133 
32134  // ------------------------------------------------------------------
32135  // Open boundaries (nonclosed internal boundaries)
32136  // ------------------------------------------------------------------
32137  // Loop over the internal open boundaries
32138  for (unsigned i = 0; i < n_open_boundaries; i++)
32139  {
32140  // Get a temporary representation for the open curve
32141  TriangleMeshOpenCurve* tmp_open_curve_pt =
32142  this->Internal_open_curve_pt[i];
32143 
32144  // Get the number of curve sections associated to the current
32145  // internal open boundary
32146  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32147 
32148  // Loop over the curve section
32149  for (unsigned p = 0; p < n_curve_section; p++)
32150  {
32151  // Get a temporary representation of the curve section
32152  // (polyline)
32153  TriangleMeshPolyLine* tmp_polyline_pt =
32154  tmp_open_curve_pt->polyline_pt(p);
32155 
32156  // Is the initial vertex connected?
32157  if (tmp_polyline_pt->is_initial_vertex_connected())
32158  {
32159  // Get the boundary id of the current polyline
32160  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32161 
32162  // Boundary id to which the curve is connected
32163  const unsigned dst_bnd_id =
32164  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32165 
32166  // Boundary chunk to which the curve is connected
32167  const unsigned dst_chunk =
32168  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32169 
32170  // Get the nodes representation of the current boundary
32171  Vector<Vector<Node*> > src_bnd_node_pt =
32172  bnd_sorted_segment_node_pt[bnd_id];
32173 
32174  // Get the nodes representation of the boundary to connect
32175  Vector<Vector<Node*> > dst_bnd_node_pt =
32176  bnd_sorted_segment_node_pt[dst_bnd_id];
32177 
32178  // Add the repeated node to the list of non delete-able
32179  // vertices
32180  add_non_delete_vertices_from_boundary_helper(
32181  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32182 
32183  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32184 
32185  // Is the final vertex connected?
32186  if (tmp_polyline_pt->is_final_vertex_connected())
32187  {
32188  // Get the boundary id of the current polyline
32189  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32190 
32191  // Boundary id to which the curve is connected
32192  const unsigned dst_bnd_id =
32193  tmp_polyline_pt->final_vertex_connected_bnd_id();
32194 
32195  // Boundary chunk to which the curve is connected
32196  const unsigned dst_chunk =
32197  tmp_polyline_pt->final_vertex_connected_n_chunk();
32198 
32199  // Get the nodes representation of the current boundary
32200  Vector<Vector<Node*> > src_bnd_node_pt =
32201  bnd_sorted_segment_node_pt[bnd_id];
32202 
32203  // Get the nodes representation of the boundary to connect
32204  Vector<Vector<Node*> > dst_bnd_node_pt =
32205  bnd_sorted_segment_node_pt[dst_bnd_id];
32206 
32207  // Add the repeated node to the list of non delete-able
32208  // vertices
32209  add_non_delete_vertices_from_boundary_helper(
32210  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32211 
32212  } // if (tmp_polyline_pt->is_final_vertex_connected())
32213 
32214  } // for (p < n_curve_section)
32215 
32216  } // for (i < n_open_boundaries)
32217 
32218 #ifdef OOMPH_HAS_MPI
32219  // ------------------------------------------------------------------
32220  // Shared boundaries (only for distributed meshes)
32221  // ------------------------------------------------------------------
32222 
32223  // Check if we need to include any information associated with
32224  // shared boundaries
32225  if (this->is_mesh_distributed())
32226  {
32227  // Get the rank of the current processor
32228  const unsigned my_rank = this->communicator_pt()->my_rank();
32229 
32230  // Get the number of shared curves in the current processor
32231  const unsigned n_shared_curves =
32232  this->nshared_boundary_curves(my_rank);
32233 
32234  // Loop over the shared curves
32235  for (unsigned i = 0; i < n_shared_curves; i ++)
32236  {
32237  // Get the number of polylines associated to the current shared
32238  // curve
32239  const unsigned n_polyline =
32240  this->nshared_boundary_polyline(my_rank, i);
32241 
32242  // Loop over the polylines associated to the current shared
32243  // curve
32244  for (unsigned p = 0; p < n_polyline; p++)
32245  {
32246  // Get a temporary representation of the shared polyline
32247  TriangleMeshPolyLine* tmp_polyline_pt =
32248  this->shared_boundary_polyline_pt(my_rank, i, p);
32249 
32250  // Is the initial vertex connected?
32251  if (tmp_polyline_pt->is_initial_vertex_connected())
32252  {
32253  // Get the boundary id of the current polyline
32254  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32255 
32256  // Boundary id to which the curve is connected
32257  const unsigned dst_bnd_id =
32258  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32259 
32260  // Boundary chunk to which the curve is connected
32261  const unsigned dst_chunk =
32262  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32263 
32264  // Get the nodes representation of the current boundary
32265  Vector<Vector<Node*> > src_bnd_node_pt =
32266  bnd_sorted_segment_node_pt[bnd_id];
32267 
32268  // Get the nodes representation of the boundary to connect
32269  Vector<Vector<Node*> > dst_bnd_node_pt =
32270  bnd_sorted_segment_node_pt[dst_bnd_id];
32271 
32272  // Add the repeated node to the list of non delete-able
32273  // vertices
32274  add_non_delete_vertices_from_boundary_helper(
32275  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32276 
32277  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32278 
32279  // Is the final vertex connected?
32280  if (tmp_polyline_pt->is_final_vertex_connected())
32281  {
32282  // Get the boundary id of the current polyline
32283  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32284 
32285  // Boundary id to which the curve is connected
32286  const unsigned dst_bnd_id =
32287  tmp_polyline_pt->final_vertex_connected_bnd_id();
32288 
32289  // Boundary chunk to which the curve is connected
32290  const unsigned dst_chunk =
32291  tmp_polyline_pt->final_vertex_connected_n_chunk();
32292 
32293  // Get the nodes representation of the current boundary
32294  Vector<Vector<Node*> > src_bnd_node_pt =
32295  bnd_sorted_segment_node_pt[bnd_id];
32296 
32297  // Get the nodes representation of the boundary to connect
32298  Vector<Vector<Node*> > dst_bnd_node_pt =
32299  bnd_sorted_segment_node_pt[dst_bnd_id];
32300 
32301  // Add the repeated node to the list of non delete-able
32302  // vertices
32303  add_non_delete_vertices_from_boundary_helper(
32304  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32305 
32306  } // if (tmp_polyline_pt->is_final_vertex_connected())
32307 
32308  } // for (p < n_polyline)
32309 
32310  } // for (i < n_shared_curves)
32311 
32312  } // if (this->is_mesh_distributed())
32313 
32314 #endif // #ifdef OOMPH_HAS_MPI
32315 
32316  }
32317 
32318  //=========================================================================
32319  /// \short Adds the vertices from the sources boundary that are
32320  /// repeated in the destination boundary to the list of non
32321  /// delete-able vertices in the destination boundary
32322  //=========================================================================
32323  template<class ELEMENT>
32326  Vector<Vector<Node*> > src_bound_segment_node_pt,
32327  Vector<Vector<Node*> > dst_bound_segment_node_pt,
32328  const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
32329  {
32330  // Get the number of segments in the source boundary
32331  const unsigned n_seg = src_bound_segment_node_pt.size();
32332  // Loop over the segments in the source boundary
32333  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32334  {
32335  // Get the number of nodes in the current segment
32336  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32337  // Get the left and right node of the current segment
32338  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32339  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode-1];
32340 
32341  // Get the number of segments in the destination boundary
32342  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32343  // Loop over the segments in the destination boundary
32344  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32345  {
32346  // Get the number of nodes on the current destination segment
32347  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32348  // Loop over the nodes until the node has been found or we have
32349  // visited all the nodes
32350  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32351  {
32352  // Get a pointer to the jnode in the destination segment
32353  // boundary
32354  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32355  // Is the node the same as the left or right node if
32356  // the source segment boundary
32357  if (tmp_node_pt == left_node_pt)
32358  {
32359  // We have foud the node to connect, get the vertex of the node
32360  Vector<double> vertex(2);
32361  vertex[0] = tmp_node_pt->x(0);
32362  vertex[1] = tmp_node_pt->x(1);
32363 
32364  // Establish the vertex coordinate as untouchable in the
32365  // destination boundary during the adaptation process. It
32366  // means that unrefinement can not take off the vertices
32367  // that receive connections in the destination boundary
32368  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32369  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32370  // insert(vertex);
32371 
32372  // return
32373  return;
32374 
32375  } // if (tmp_node_pt == left_node_pt)
32376  else if (tmp_node_pt == right_node_pt)
32377  {
32378  // We have foud the node to connect, get the vertex of the node
32379  Vector<double> vertex(2);
32380  vertex[0] = tmp_node_pt->x(0);
32381  vertex[1] = tmp_node_pt->x(1);
32382 
32383  // Establish the vertex coordinate as untouchable in the
32384  // destination boundary during the adaptation process. It
32385  // means that unrefinement can not take off the vertices
32386  // that receive connections in the destination boundary
32387  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32388  // insert(vertex);
32389  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32390 
32391  // return
32392  return;
32393 
32394  } // else if (tmp_node_pt == right_node_pt)
32395 
32396  } // for (jnode < n_dst_node)
32397 
32398  } // for (jseg < n_dst_seg)
32399 
32400  } // for (iseg < n_seg)
32401 
32402  }
32403 
32404 #ifdef OOMPH_HAS_MPI
32405  //=========================================================================
32406  /// \short Synchronise the vertices that are marked for non deletion
32407  // on the shared boundaries. Unrefinement of shared boundaries is
32408  // performed only if the candidate node is not marked for non deletion
32409  //=========================================================================
32410  template<class ELEMENT>
32413  {
32414  // Get the number of processors
32415  const unsigned nproc = this->communicator_pt()->nproc();
32416  // Get my rank
32417  const unsigned my_rank = this->communicator_pt()->my_rank();
32418 
32419  // loop over the processors
32420  for (unsigned jproc = 0; jproc < nproc; jproc++)
32421  {
32422  // The number of boundaries shared with the current processor
32423  // (if jproc==my_rank then there are no shared boundaries
32424  // between them)
32425  const unsigned n_shd_bnd_jproc =
32426  this->nshared_boundaries(my_rank, jproc);
32427 
32428  // Are there shared boundaries with the jproc processor?
32429  // There are no info. with myself
32430  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32431  {
32432  // Storage for the boundaries ids with vertices for non
32433  // deletion
32434  Vector<unsigned> shd_bnd_id_for_non_deletion;
32435 
32436  // Storage for chunk numbers of boundaries with vertices
32437  // for non deletion
32438  Vector<unsigned> chunk_for_non_deletion;
32439 
32440  // The number of vertices for nondeletion in the shared
32441  // boundaries
32442  Vector<unsigned> number_vertices_non_deletion;
32443 
32444  // Vertices marked for nondeletion in shared boundaries
32445  Vector<Vector<Vector<double> > > vertices_for_non_deletion;
32446 
32447  // Get the boundary ids of the shared boundaries with jproc
32448  // processor
32449  Vector<unsigned> shd_bnd_ids =
32450  this->shared_boundaries_ids(my_rank, jproc);
32451 
32452  // Get the number of shared boundaries with jproc
32453  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32454  // loop over the shared boundaries with jproc
32455  for (unsigned ishd_bnd=0;ishd_bnd<n_shd_bnd_jproc;ishd_bnd++)
32456  {
32457  // Get the shared boudary id
32458  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32459  // Get the associated polyline
32460  TriangleMeshPolyLine *shd_polyline_pt =
32461  this->boundary_polyline_pt(shd_bnd_id);
32462  // Get the chunk number
32463  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32464 
32465  // Store the vertices not allowed for deletion
32466  std::set<Vector<double> > no_delete_vertex;
32467 
32468  // Does the boundary has vertives for nondeleteion?
32469  const bool boundary_receive_connections =
32470  this->boundary_connections(shd_bnd_id, chunk,
32471  no_delete_vertex);
32472 
32473  // Get the number of vertices for nondeletion
32474  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32475 
32476  // Are there vertices for nondeletion?
32477  if (boundary_receive_connections && n_non_delete_vertex > 0)
32478  {
32479  // Add the shared boundary id
32480  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32481  // Add the chunk number
32482  chunk_for_non_deletion.push_back(chunk);
32483  // Add the number of vertices for non deletion
32484  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32485 
32486  // The list of vertices to add
32487  Vector<Vector<double> > tmp_vertices;
32488 
32489  // Add the vertices for non deletion
32490  for (std::set<Vector<double> >::iterator it =
32491  no_delete_vertex.begin();
32492  it != no_delete_vertex.end(); it++)
32493  {
32494  // Get the vertex coordinate
32495  Vector<double> vertex = (*it);
32496  tmp_vertices.push_back(vertex);
32497  }
32498 
32499  // Add the vertices coordinates to a vector storage
32500  vertices_for_non_deletion.push_back(tmp_vertices);
32501 
32502  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32503 
32504  } // for (ishd_bnd<n_shd_bnd_jproc)
32505 
32506  // ----------------------------------------------------------
32507  // ----------------------------------------------------------
32508  // ----------------------------------------------------------
32509  // Now send the info. to the other processor (jproc)
32510  // ----------------------------------------------------------
32511  // ----------------------------------------------------------
32512  // ----------------------------------------------------------
32513  // Get the communicator of the mesh
32514  OomphCommunicator* comm_pt = this->communicator_pt();
32515 
32516  // Set MPI info
32517  MPI_Status status;
32518  MPI_Request request;
32519 
32520  // -----------------------------------------------------------
32521  // Prepare the data
32522  // Get the number of shared boundaires with vertices marked
32523  // for non deletion
32524  const unsigned n_shd_bnd_with_non_delete_vertices =
32525  shd_bnd_id_for_non_deletion.size();
32526 
32527  // Size of the package
32528  const unsigned size_package = 3;
32529  // Ndata to send
32530  const unsigned n_unsigned_data_to_send =
32531  n_shd_bnd_with_non_delete_vertices*size_package;
32532  // The flat package to send the info.
32533  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32534  Vector<double> flat_package_double_send;
32535 
32536  Vector<unsigned> flat_package_unsigned_recv;
32537  Vector<double> flat_package_double_recv;
32538 
32539  // Prepare the data to be sent
32540  unsigned j=0;
32541  for (unsigned i=0;i<n_shd_bnd_with_non_delete_vertices;i++)
32542  {
32543  // The shared boundary id
32544  flat_package_unsigned_send[j++] =
32545  shd_bnd_id_for_non_deletion[i];
32546  // The chunk number
32547  flat_package_unsigned_send[j++] =
32548  chunk_for_non_deletion[i];
32549  // The number of vertices for nondeletion
32550  flat_package_unsigned_send[j++] =
32551  number_vertices_non_deletion[i];
32552  // Also package the vertices
32553  const unsigned n_vertices_non_deletion =
32554  number_vertices_non_deletion[i];
32555  // Loop over the vertices and store them in the flat
32556  // package to be sent
32557  for (unsigned h=0;h<n_vertices_non_deletion;h++)
32558  {
32559  flat_package_double_send.push_back(
32560  vertices_for_non_deletion[i][h][0]);
32561  flat_package_double_send.push_back(
32562  vertices_for_non_deletion[i][h][1]);
32563  } // for (h<n_vertices_non_deletion)
32564 
32565  } // for (i<n_shd_bnd_with_non_delete_vertices)
32566 
32567  // ----------------------------------------------------------
32568  int send_proc = jproc;
32569  int recv_proc = jproc;
32570  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32571  unsigned send_count_double_values = flat_package_double_send.size();
32572  //-----------------------------------------------------------
32573  // Do the transfering of info.
32574  //-----------------------------------------------------------
32575  // Start with UNSIGNED info.
32576  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
32577  send_proc,1,comm_pt->mpi_comm(),&request);
32578 
32579  unsigned receive_count_unsigned_values=0;
32580  MPI_Recv(&receive_count_unsigned_values,1,MPI_UNSIGNED,
32581  recv_proc,1,comm_pt->mpi_comm(),&status);
32582 
32583  MPI_Wait(&request,MPI_STATUS_IGNORE);
32584 
32585  // Send the actual data
32586  if (send_count_unsigned_values!=0)
32587  {
32588  MPI_Isend(&flat_package_unsigned_send[0],
32589  send_count_unsigned_values,MPI_UNSIGNED,
32590  send_proc,2,comm_pt->mpi_comm(),&request);
32591  }
32592 
32593  // Receive the actual data
32594  if (receive_count_unsigned_values!=0)
32595  {
32596  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32597  MPI_Recv(&flat_package_unsigned_recv[0],
32598  receive_count_unsigned_values,
32599  MPI_UNSIGNED,recv_proc,2,comm_pt->mpi_comm(),&status);
32600  }
32601 
32602  // Wait for sending the data and the other processor
32603  // receives
32604  if (send_count_unsigned_values!=0)
32605  {
32606  MPI_Wait(&request,MPI_STATUS_IGNORE);
32607  }
32608 
32609  //-----------------------------------------------------------
32610  // Then continue with DOUBLE info.
32611  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
32612  send_proc,1,comm_pt->mpi_comm(),&request);
32613 
32614  unsigned receive_count_double_values=0;
32615  MPI_Recv(&receive_count_double_values,1,MPI_UNSIGNED,
32616  recv_proc,1,comm_pt->mpi_comm(),&status);
32617 
32618  MPI_Wait(&request,MPI_STATUS_IGNORE);
32619 
32620  // Send the actual data
32621  if (send_count_double_values!=0)
32622  {
32623  MPI_Isend(&flat_package_double_send[0],
32624  send_count_double_values,MPI_DOUBLE,
32625  send_proc,2,comm_pt->mpi_comm(),&request);
32626  }
32627 
32628  // Receive the actual data
32629  if (receive_count_double_values!=0)
32630  {
32631  flat_package_double_recv.resize(receive_count_double_values);
32632  MPI_Recv(&flat_package_double_recv[0],
32633  receive_count_double_values,
32634  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
32635  }
32636 
32637  // Wait for sending the data and the other processor
32638  // receives
32639  if (send_count_double_values!=0)
32640  {
32641  MPI_Wait(&request,MPI_STATUS_IGNORE);
32642  }
32643 
32644  // ------------------------------------------------------------
32645  // ------------------------------------------------------------
32646  // ------------------------------------------------------------
32647  // Now unpackage the data
32648  // ------------------------------------------------------------
32649  // ------------------------------------------------------------
32650  // ------------------------------------------------------------
32651 
32652  // Storage for the boundaries ids with vertices for non
32653  // deletion
32654  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32655 
32656  // Storage for chunk numbers of boundaries with vertices
32657  // for non deletion
32658  Vector<unsigned> recv_chunk_for_non_deletion;
32659 
32660  // The number of vertices for nondeletion in the shared
32661  // boundaries
32662  Vector<unsigned> recv_number_vertices_non_deletion;
32663 
32664  // Vertices marked for nondeletion in shared boundaries
32665  Vector<Vector<Vector<double> > > recv_vertices_for_non_deletion;
32666 
32667  // Counter
32668  j = 0;
32669  for (unsigned i=0;i<receive_count_unsigned_values;i+=3)
32670  {
32671  // Get the shared boundary id
32672  const unsigned recv_shd_bnd_id =
32673  flat_package_unsigned_recv[i];
32674  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32675  // Get the chunk number
32676  const unsigned recv_chunk =
32677  flat_package_unsigned_recv[i+1];
32678  recv_chunk_for_non_deletion.push_back(recv_chunk);
32679  // Get the number of vertices for non deletion
32680  const unsigned recv_num_vertices =
32681  flat_package_unsigned_recv[i+2];
32682  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32683 
32684  // Create a temporal storage
32685  Vector<Vector<double> > temp_recv_vertices;
32686  // Now get the vertices
32687  for (unsigned h=0;h<recv_num_vertices;h++)
32688  {
32689  Vector<double> tmp_vertex(2);
32690  tmp_vertex[0] = flat_package_double_recv[j++];
32691  tmp_vertex[1] = flat_package_double_recv[j++];
32692  // Add the vertex to the vector of vertices
32693  temp_recv_vertices.push_back(tmp_vertex);
32694  } // for (h<recv_num_vertices)
32695 
32696  // Add the vertices to the vector of vertices
32697  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32698 
32699  } // for(i<receive_count_unsigned_values)
32700 
32701  // ---------------------------------------------------------
32702  // ---------------------------------------------------------
32703  // ---------------------------------------------------------
32704  // Now add the vertices to the data structures to mark them
32705  // as non delete-able
32706  // ---------------------------------------------------------
32707  // ---------------------------------------------------------
32708  // ---------------------------------------------------------
32709 
32710  // Get the number of shd boundaries that have vertices
32711  // marked for non deletion
32712  const unsigned n_recv_shd_bnd_id_for_non_deletion =
32713  recv_shd_bnd_id_for_non_deletion.size();
32714  // loop over the shared boundaries and add the data for non
32715  // deletion
32716  for (unsigned i=0;i<n_recv_shd_bnd_id_for_non_deletion;i++)
32717  {
32718  // Get the shared boundary id.
32719  const unsigned shd_bnd_id =
32720  recv_shd_bnd_id_for_non_deletion[i];
32721  // Get the chunk number
32722  unsigned chunk = recv_chunk_for_non_deletion[i];
32723  // Increase and decrease the chunk number to avoid the
32724  // warning when compiling without PARANOID
32725  chunk++;
32726  chunk--;
32727 
32728  // Get the number of vertices marked for non deletion
32729  const unsigned n_vertices =
32730  recv_number_vertices_non_deletion[i];
32731  // Add all the vertices
32732  for (unsigned h=0;h<n_vertices;h++)
32733  {
32734  // Get the vertex
32735  Vector<double> vertex(2);
32736  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
32737  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
32738  // Add the vertex to the data structure for non
32739  // deletion
32740  //Boundary_chunk_connections_pt[shd_bnd_id][chunk].
32741  // insert(vertex);
32742  Boundary_connections_pt[shd_bnd_id].insert(vertex);
32743 
32744  } // for (h<n_vertices)
32745 
32746  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
32747 
32748  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
32749 
32750  } // for (jproc < nproc)
32751 
32752  }
32753 #endif // #ifdef OOMPH_HAS_MPI
32754 
32755  //=========================================================================
32756  /// \short After unrefinement and refinement has taken place compute
32757  /// the new vertices numbers of the temporary representation of the
32758  // boundaries to connect.
32759  //=========================================================================
32760  template<class ELEMENT>
32762  Vector<TriangleMeshPolygon *> &tmp_outer_polygons_pt,
32763  Vector<TriangleMeshOpenCurve *> &tmp_open_curves_pt)
32764  {
32765  // Dummy storages
32766  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
32767  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
32768 
32769  // Clear the storage
32770  dummy_resume_initial_connection_polyline_pt.clear();
32771  dummy_resume_final_connection_polyline_pt.clear();
32772 
32773  // Get the initial shared boundary id (to check whether the
32774  // polylines represent original or shared boundaries)
32775  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32776 
32777  // ------------------------------------------------------------------
32778  // This seems unnecesary since the outer polygons does not create
32779  // connections with other boundaries (the original ones)
32780  // ------------------------------------------------------------------
32781  // Unnecessary?
32782  // ------------------------------------------------------------------
32783 
32784  // Loop over the temporary outer polygons create the connection
32785  // information of those boundaries marked to be connected at their
32786  // ends
32787 
32788  // ------------------------------------------------------------------
32789  // Temporary outer polygons
32790  // ------------------------------------------------------------------
32791 
32792  // Get the number of outer boundaries (closed boundaries)
32793  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
32794 
32795  // Loop over the outer boundaries
32796  for (unsigned i = 0; i < n_outer_boundaries; i++)
32797  {
32798  // Get a temporary polygon representation
32799  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
32800  // Get the number of polylines associated to the current outer
32801  // boundary
32802  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32803  // Loop over the polylines
32804  for (unsigned p = 0; p < n_polyline; p++)
32805  {
32806  // Get a temporary representation of the polyline
32807  TriangleMeshPolyLine* tmp_polyline_pt =
32808  tmp_polygon_pt->polyline_pt(p);
32809 
32810  // Get the boundary id
32811  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32812 
32813  // Is the boundary to connect a shared boundary
32814  if (bnd_id < init_shd_bnd_id)
32815  {
32816  // Restore the connections of the current polyline
32817  restore_polyline_connections_helper(
32818  tmp_polyline_pt,
32819  dummy_resume_initial_connection_polyline_pt,
32820  dummy_resume_final_connection_polyline_pt);
32821 
32822  } // if (bnd_id < init_shd_bnd_id)
32823 
32824  } // for (p < n_polyline)
32825 
32826  } // for (i < n_outer_boundaries)
32827 
32828  // ------------------------------------------------------------------
32829  // Unnecessary?
32830  // ------------------------------------------------------------------
32831 
32832  // ------------------------------------------------------------------
32833  // Temporary open boundaries (nonclosed internal boundaries)
32834  // ------------------------------------------------------------------
32835 
32836  // Get the number of internal boundaries (open boundaries)
32837  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
32838 
32839  // Loop over the internal open boundaries
32840  for (unsigned i = 0; i < n_open_boundaries; i++)
32841  {
32842  // Get a temporary representation for the open curve
32843  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
32844 
32845  // Get the number of curve sections associated to the current
32846  // internal open boundary
32847  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32848 
32849  // Loop over the curve section
32850  for (unsigned p = 0; p < n_curve_section; p++)
32851  {
32852  // Get a temporary representation of the curve section
32853  // (polyline)
32854  TriangleMeshPolyLine* tmp_polyline_pt =
32855  tmp_open_curve_pt->polyline_pt(p);
32856 
32857  // Get the boundary id
32858  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32859 
32860  // Is the boundary to connect a shared boundary
32861  if (bnd_id < init_shd_bnd_id)
32862  {
32863  // Restore the connections of the current polyline
32864  restore_polyline_connections_helper(
32865  tmp_polyline_pt,
32866  dummy_resume_initial_connection_polyline_pt,
32867  dummy_resume_final_connection_polyline_pt);
32868 
32869  } // if (bnd_id < init_shd_bnd_id)
32870 
32871  } // for (p < n_curve_section)
32872 
32873  } // for (i < n_open_boundaries)
32874 
32875  }
32876 
32877  //=========================================================================
32878  /// \short After unrefinement and refinement has taken place compute
32879  /// the new vertices numbers of the boundaries to connect (in a
32880  /// distributed scheme it may be possible that the destination
32881  /// boundary does no longer exist, therefore the connection is
32882  /// suspended. It is not permanently deleted because if load balance
32883  /// takes place it may be possible that the boundary to connect be
32884  /// part of the new domain representation, so the connection would
32885  /// exist)
32886  //=========================================================================
32887  template<class ELEMENT>
32889  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
32890  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
32891  {
32892  // Clear the storage
32893  resume_initial_connection_polyline_pt.clear();
32894  resume_final_connection_polyline_pt.clear();
32895 
32896  // Loop over the boundaries in the domain (outer, internal -- closed
32897  // and open) and restore the connection information of those
32898  // boundaries marked to be connected at their ends
32899 
32900  // ------------------------------------------------------------------
32901  // Outer boundaries
32902  // ------------------------------------------------------------------
32903 
32904  // Get the number of outer boundaries (closed boundaries)
32905  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
32906 
32907  // Loop over the outer boundaries
32908  for (unsigned i = 0; i < n_outer_boundaries; i++)
32909  {
32910  // Get a temporary polygon representation
32911  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32912  // Get the number of polylines associated to the current outer
32913  // boundary
32914  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32915  // Loop over the polylines
32916  for (unsigned p = 0; p < n_polyline; p++)
32917  {
32918  // Get a temporary representation of the polyline
32919  TriangleMeshPolyLine* tmp_polyline_pt =
32920  tmp_polygon_pt->polyline_pt(p);
32921 
32922  // Restore the connections of the current polyline
32923  restore_polyline_connections_helper(
32924  tmp_polyline_pt,
32925  resume_initial_connection_polyline_pt,
32926  resume_final_connection_polyline_pt);
32927 
32928  } // for (p < n_polyline)
32929 
32930  } // for (i < n_outer_boundaries)
32931 
32932  // ------------------------------------------------------------------
32933  // Internal boundaries
32934  // ------------------------------------------------------------------
32935 
32936  // Get the number of internal boundaries (closed boundaries)
32937  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
32938 
32939  // Loop over the internal boundaries
32940  for (unsigned i = 0; i < n_internal_boundaries; i++)
32941  {
32942  // Get a temporary polygon representation
32943  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32944  // Get the number of polylines associated to the current internal
32945  // boundary
32946  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32947  // Loop over the polylines
32948  for (unsigned p = 0; p < n_polyline; p++)
32949  {
32950  // Get a temporary representation of the polyline
32951  TriangleMeshPolyLine* tmp_polyline_pt =
32952  tmp_polygon_pt->polyline_pt(p);
32953 
32954  // Restore the connections of the current polyline
32955  restore_polyline_connections_helper(
32956  tmp_polyline_pt,
32957  resume_initial_connection_polyline_pt,
32958  resume_final_connection_polyline_pt);
32959 
32960  } // for (p < n_polyline)
32961 
32962  } // for (i < n_internal_boundaries)
32963 
32964  // ------------------------------------------------------------------
32965  // Open boundaries (nonclosed internal boundaries)
32966  // ------------------------------------------------------------------
32967 
32968  // Get the number of internal boundaries (open boundaries)
32969  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32970 
32971  // Loop over the internal open boundaries
32972  for (unsigned i = 0; i < n_open_boundaries; i++)
32973  {
32974  // Get a temporary representation for the open curve
32975  TriangleMeshOpenCurve* tmp_open_curve_pt =
32976  this->Internal_open_curve_pt[i];
32977 
32978  // Get the number of curve sections associated to the current
32979  // internal open boundary
32980  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32981 
32982  // Loop over the curve section
32983  for (unsigned p = 0; p < n_curve_section; p++)
32984  {
32985  // Get a temporary representation of the curve section
32986  // (polyline)
32987  TriangleMeshPolyLine* tmp_polyline_pt =
32988  tmp_open_curve_pt->polyline_pt(p);
32989 
32990  // Restore the connections of the current polyline
32991  restore_polyline_connections_helper(
32992  tmp_polyline_pt,
32993  resume_initial_connection_polyline_pt,
32994  resume_final_connection_polyline_pt);
32995 
32996  } // for (p < n_curve_section)
32997 
32998  } // for (i < n_open_boundaries)
32999 
33000  }
33001 
33002  //=========================================================================
33003  /// \short Restore the connections of the specific polyline
33004  /// The vertices numbering on the destination boundaries may have
33005  /// change because of (un)refinement in the destination boundaries.
33006  /// Also deals with connection that do not longer exist because the
33007  /// destination boundary does no longer exist because of the distribution
33008  /// process
33009  //=========================================================================
33010  template<class ELEMENT>
33013  TriangleMeshPolyLine* polyline_pt,
33014  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33015  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33016  {
33017  // If the polyline is connected at any of its ends compute the new
33018  // vertex number on the destination boundary
33019 
33020  // ------------------------------------------------------------------
33021  // Is the initial vertex connected?
33022  if (polyline_pt->is_initial_vertex_connected())
33023  {
33024  // The pointer to the boundary to connect
33025  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33026 
33027  // Get the boundary id of the destination/connected boundary
33028  const unsigned dst_bnd_id_initial =
33029  polyline_pt->initial_vertex_connected_bnd_id();
33030 
33031  // Get the initial vertex on the current boundary
33032  Vector<double> src_vertex_coordinates_initial =
33033  polyline_pt->vertex_coordinate(0);
33034 
33035 #ifdef PARANOID
33036  // Is the mesh distributed?
33037 #ifdef OOMPH_HAS_MPI
33038  if (this->is_mesh_distributed())
33039  {
33040  // Get the initial shared boundary id
33041  const unsigned init_shd_bnd_id =
33042  this->initial_shared_boundary_id();
33043  // Is the boundary to connect a shared boundary
33044  if (dst_bnd_id_initial >= init_shd_bnd_id)
33045  {
33046  // Get the current polyline original boundary id
33047  const unsigned bnd_id = polyline_pt->boundary_id();
33048  std::ostringstream error_message;
33049  error_message
33050  << "INITIAL VERTEX CONNECTION\n"
33051  << "The current original boundary is trying to connect to a\n"
33052  << "shared boundary, this is not allowed. In this case the\n"
33053  << "shared boundary should be the one that connects with the\n"
33054  << "original boundary\n"
33055  << "The current original boundary (" << bnd_id << ") is marked\n"
33056  << "to have a connection at the\nINITIAL vertex ("
33057  << src_vertex_coordinates_initial[0] << ","
33058  << src_vertex_coordinates_initial[1] << ")\n"
33059  << "with the shared boundary ("<< dst_bnd_id_initial << ")\n"
33060  << "This is the list of vertices on the shared destination boundary\n";
33061  // Get the pointer to the associated polyline by using the
33062  // boundary id
33063  TriangleMeshPolyLine *dst_polyline =
33064  this->boundary_polyline_pt(dst_bnd_id_initial);
33065  // The number of vertices on the destination boundary
33066  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33067  // Loop over the vertices print them
33068  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33069  {
33070  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33071  error_message
33072  << "Vertex#(i): ("
33073  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33074  }
33075  throw OomphLibError(
33076  error_message.str(),
33077  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33078  OOMPH_EXCEPTION_LOCATION);
33079  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33080 
33081  } // if (this->is_mesh_distributed())
33082 #endif // #ifdef OOMPH_HAS_MPI
33083 
33084 #endif // #ifdef PARANOID
33085 
33086  // Flag to indicate if the vertex was found on the destination
33087  // boundary
33088  bool found_vertex_on_dst_boundary_initial = false;
33089 
33090  // Flag that stores the chunk number to connect (only used in
33091  // distributed meshes)
33092  unsigned sub_poly_to_connect = 0;
33093 
33094  // Store the vertex number on the destination boundary
33095  unsigned n_vertex_connection_initial = 0;
33096 
33097  // Flags only used in a distributed mesh
33098  // ----------------------------------------
33099  // Flag to indicate we are trying to connect to an split boundary
33100  bool connecting_to_an_split_boundary = false;
33101 
33102  // Flag to indicate we are trying to connecto to an internal
33103  // boundary that is overlaped by a shared boundary)
33104  bool connecting_to_an_overlaped_boundary = false;
33105 
33106 #ifdef OOMPH_HAS_MPI
33107  if (this->is_mesh_distributed())
33108  {
33109  // We can only connect to an original boundary, check if the
33110  // boundary was splitted during the distribution process to
33111  // consider all the chunks (sub-polylines) of the boundary
33112  if (this->boundary_was_splitted(dst_bnd_id_initial))
33113  {
33114  connecting_to_an_split_boundary = true;
33115  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33116 
33117  // Check if the destination boundary, or any of its chunks is
33118  // marked to be overlapped by a shared boundary, if that is the
33119  // case we can only connect to the chunks that are not
33120  // overlapped by shared boundaries (the shared boundaries are in
33121  // charge of generating the connections with original boundaries
33122  // and with themselves)
33123  if (connecting_to_an_split_boundary)
33124  {
33125  // Get the number of chucks that represent the destination
33126  // boundary
33127  const unsigned n_sub_poly =
33128  this->nboundary_subpolylines(dst_bnd_id_initial);
33129  // Now loop over the chunks of the destination boundary and if
33130  // any of them is marked to be overlaped by a shared boundary
33131  // then set the flag and break the loop
33132  for (unsigned ii =0; ii < n_sub_poly; ii++)
33133  {
33134  if (this->
33135  boundary_marked_as_shared_boundary(dst_bnd_id_initial, ii))
33136  {
33137  // Mark the boundary as being overlaped by a shared
33138  // boundary
33139  connecting_to_an_overlaped_boundary = true;
33140  // Break, no need to look for more overlapings
33141  break;
33142  } // if (boundary_marked_as_shared_boundary(...))
33143  } // for (ii < n_sub_poly)
33144  } // if (connecting_to_an_split_boundary)
33145  else
33146  {
33147  // If not connecting to an split boundary then check if the
33148  // whole destination boundary is overlaped by an internal
33149  // boundary
33150  if (this->
33151  boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33152  {
33153  // Mark the boundary as being overlaped by a shared boundary
33154  connecting_to_an_overlaped_boundary = true;
33155  } // if (boundary_marked_as_shared_boundary(...))
33156  } // else if (connecting_to_an_split_boundary)
33157 
33158  } // if (this->is_mesh_distributed())
33159 
33160 #endif // #ifdef OOMPH_HAS_MPI
33161 
33162  // If we are connecting neither to an split boundary nor an
33163  // overlaped boundary then get the pointer to the original
33164  // boundary
33165  if (!(connecting_to_an_split_boundary ||
33166  connecting_to_an_overlaped_boundary))
33167  {
33168  // Get the polyline pointer representing the destination
33169  // boundary
33170  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33171  } // else if (NOT split, NOT overlaped)
33172 
33173  // Now look for the vertex number on the destination boundary(ies)
33174  // -- in case that the boundary was split ---
33175 
33176  // Do not check for same orientation, that was previously worked
33177  // by interchanging the connections boundaries (if necessary)
33178 
33179  // If the boundary was not split then ...
33180  if (!connecting_to_an_split_boundary)
33181  {
33182  // ... check if the boundary is marked to be overlaped by
33183  // a shared boundary
33184  if (!connecting_to_an_overlaped_boundary)
33185  {
33186  // If that is not the case then we can safely look for the
33187  // vertex number on the destination boundary
33188  found_vertex_on_dst_boundary_initial =
33189  this->get_connected_vertex_number_on_destination_polyline(
33190  poly_to_connect_pt,
33191  src_vertex_coordinates_initial,
33192  n_vertex_connection_initial);
33193 
33194  } // if (!connecting_to_an_overlaped_boundary)
33195  else
33196  {
33197  // If the whole boundary is marked to be overlaped by a shared
33198  // boundary then do nothing, the shared boundaries are already
33199  // in charge of performing the connection (it will be required
33200  // to disabled the connection) with the original boundary
33201 
33202  } // else if (!connecting_to_an_overlaped_boundary)
33203 
33204  } // if (!connecting_to_an_split_boundary)
33205 #ifdef OOMPH_HAS_MPI
33206  else
33207  {
33208  // If the boundary was split then we need to look for the vertex
33209  // in the sub-polylines
33210 
33211  // Get the sub-polylines vector
33212  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33213  this->boundary_subpolylines(dst_bnd_id_initial);
33214 
33215  // Get the number of sub-polylines
33216  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33217 #ifdef PARANOID
33218  if (nsub_poly <= 1)
33219  {
33220  std::ostringstream error_message;
33221  error_message
33222  <<"The boundary (" << dst_bnd_id_initial << ") was "
33223  << "marked to be splitted but\n"
33224  << "there are only ("<<nsub_poly<<") polylines to "
33225  << "represent it.\n";
33226  throw OomphLibError(
33227  error_message.str(),
33228  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33229  OOMPH_EXCEPTION_LOCATION);
33230  } // if (nsub_poly <= 1)
33231 #endif
33232  // We need to check if the boundary is marked to be overlaped by
33233  // a shared boundary, if that is the case we need to check for
33234  // each indivual subpolyline, and for those overlaped by a
33235  // shared polyline do nothing, the shared polylines have already
33236  // deal with these connections
33237 
33238  // ... check if the boundary is marked to be overlaped by
33239  // a shared boundary
33240  if (!connecting_to_an_overlaped_boundary)
33241  {
33242  // The boundary is not overlapped by shared boundaries, we can
33243  // work without checking the subpolylines individually (non of
33244  // them are overlapped by a shared boundary)
33245 
33246  // Look for the vertex number to connect on each of the
33247  // subpolyines
33248  for (unsigned isub = 0; isub < nsub_poly; isub++)
33249  {
33250  // Assign the pointer to the sub-polyline
33251  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33252  // Search for the vertex in the current sub-polyline
33253  found_vertex_on_dst_boundary_initial =
33254  this->get_connected_vertex_number_on_destination_polyline(
33255  poly_to_connect_pt,
33256  src_vertex_coordinates_initial,
33257  n_vertex_connection_initial);
33258 
33259  // If we have found the vertex to connect then break the
33260  // loop
33261  if (found_vertex_on_dst_boundary_initial)
33262  {
33263  // But first save the subpoly number (chunk), that will be
33264  // used to perform the connection
33265  sub_poly_to_connect = isub;
33266  break;
33267  } // if (found_vertex_on_dst_boundary_initial)
33268 
33269  } // for (isub < nsub_poly)
33270 
33271  } // if (!connecting_to_an_overlaped_boundary)
33272  else
33273  {
33274  // If connecting to an overlapped boundary then we ignore the
33275  // subpolylines overlapped by shared boundaries and only look
33276  // on the sub-polylines that are not marked as being overlaped
33277  // by shared boundaries
33278 
33279  // Look for the vertex number to connect on each of the
33280  // subpolyines
33281  for (unsigned isub = 0; isub < nsub_poly; isub++)
33282  {
33283  // Only work with those sub-polylines that are not overlaped
33284  // by shared boundaries
33285  if (!this->
33286  boundary_marked_as_shared_boundary(dst_bnd_id_initial, isub))
33287  {
33288  // Assign the pointer to the sub-polyline
33289  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33290 
33291  // Search for the vertex in the current sub-polyline
33292  found_vertex_on_dst_boundary_initial =
33293  this->get_connected_vertex_number_on_destination_polyline(
33294  poly_to_connect_pt,
33295  src_vertex_coordinates_initial,
33296  n_vertex_connection_initial);
33297 
33298  // Was the vertex found?
33299  if (found_vertex_on_dst_boundary_initial)
33300  {
33301  // But first save the subpoly number (chunk), that will
33302  // be used to perform the connection
33303  sub_poly_to_connect = isub;
33304  break;
33305  } // if (found_vertex_on_dst_boundary_initial)
33306 
33307  } // if (not overlaped by shared boundary)
33308 
33309  } // for (isub < nsub_poly)
33310 
33311  } // else if (!connecting_to_an_overlaped_boundary)
33312 
33313  } // else if (!connecting_to_an_split_boundary)
33314 #endif // #ifdef OOMPH_HAS_MPI
33315 
33316  // If not found it may be that the connection information is
33317  // inverted
33318  if (!found_vertex_on_dst_boundary_initial)
33319  {
33320  // Is the mesh distributed?
33321 #ifdef OOMPH_HAS_MPI
33322  if (this->is_mesh_distributed())
33323  {
33324  // If the mesh is distributed and the vertex number was not
33325  // found, that means that the boundary (or vertex) to connect
33326  // in the destination boundary is not in the current
33327  // processor. In that case suspend the connection
33328  polyline_pt->suspend_initial_vertex_connected();
33329  // Add the polyline to the vector of polylines whose
33330  // connection will be resumed at the end of the adaptation
33331  // process
33332  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33333  // The shared boundaries are marked to connect to the initial
33334  // vertex of the polyline (remember that a shared boundary
33335  // stops adding nodes when it finds a node on an original
33336  // boundary) -- The initial vertex is now a base node
33337  }
33338  else
33339 #endif // #ifdef OOMPH_HAS_MPI
33340  {
33341 #ifdef PARANOID
33342  // If not found then there is a problem with the vertices
33343  // Get the associated boundary id of the current polyline
33344  const unsigned bnd_id = polyline_pt->boundary_id();
33345  std::ostringstream error_message;
33346  error_message
33347  << "INITIAL VERTEX CONNECTION\n"
33348  << "It was not possible to find the associated "
33349  << "vertex number on the destination boundary\n"
33350  << "The current boundary (" << bnd_id << ") is marked to have"
33351  << "a connection at the\nINITIAL vertex ("
33352  << src_vertex_coordinates_initial[0] << ","
33353  << src_vertex_coordinates_initial[1] << ")\n"
33354  << "with boundary ("<< dst_bnd_id_initial << ")\n"
33355  << "This is the list of vertices on the destination boundary\n";
33356  // Get the pointer to the associated polyline by using the
33357  // boundary id
33358  TriangleMeshPolyLine *dst_polyline =
33359  this->boundary_polyline_pt(dst_bnd_id_initial);
33360  // The number of vertices on the destination boundary
33361  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33362  // Loop over the vertices print them
33363  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33364  {
33365  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33366  error_message
33367  << "Vertex#(i): ("
33368  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33369  }
33370  throw OomphLibError(
33371  error_message.str(),
33372  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33373  OOMPH_EXCEPTION_LOCATION);
33374 #endif
33375 
33376  } // else if (this->is_mesh_distributed())
33377 
33378  } // if (!found_vertex_on_dst_boundary_initial)
33379  else
33380  {
33381  // Set the vertex number on the destination boundary
33382  polyline_pt->initial_vertex_connected_n_vertex() =
33383  n_vertex_connection_initial;
33384 
33385  // Set the chunk number on the destination boundary
33386  polyline_pt->initial_vertex_connected_n_chunk() =
33387  sub_poly_to_connect;
33388 
33389  } // else if (!found_vertex_on_dst_boundary_initial)
33390 
33391  } // if (polyline_pt->is_initial_vertex_connected())
33392 
33393  // ------------------------------------------------------------------
33394  // Is the final vertex connected?
33395  if (polyline_pt->is_final_vertex_connected())
33396  {
33397  // The pointer to the boundary to connect
33398  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33399 
33400  // Get the boundary id of the destination/connected boundary
33401  const unsigned dst_bnd_id_final =
33402  polyline_pt->final_vertex_connected_bnd_id();
33403 
33404  // Get the final vertex on the current boundary
33405  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33406  Vector<double> src_vertex_coordinates_final =
33407  polyline_pt->vertex_coordinate(tmp_n_vertices-1);
33408 
33409 
33410 #ifdef PARANOID
33411  // Is the mesh distributed?
33412 #ifdef OOMPH_HAS_MPI
33413  if (this->is_mesh_distributed())
33414  {
33415  // Get the initial shared boundary id
33416  const unsigned init_shd_bnd_id =
33417  this->initial_shared_boundary_id();
33418  // Is the boundary to connect a shared boundary
33419  if (dst_bnd_id_final >= init_shd_bnd_id)
33420  {
33421  // Get the current polyline original boundary id
33422  const unsigned bnd_id = polyline_pt->boundary_id();
33423  std::ostringstream error_message;
33424  error_message
33425  << "FINAL VERTEX CONNECTION\n"
33426  << "The current original boundary is trying to connect to a\n"
33427  << "shared boundary, this is not allowed. In this case the\n"
33428  << "shared boundary should be the one that connects with the\n"
33429  << "original boundary\n"
33430  << "The current boundary (" << bnd_id << ") is marked to have "
33431  << "a connection at the\nFINAL vertex ("
33432  << src_vertex_coordinates_final[0] << ","
33433  << src_vertex_coordinates_final[1] << ")\n"
33434  << "with boundary ("<< dst_bnd_id_final << ")\n"
33435  << "This is the list of vertices on the destination boundary\n";
33436  // Get the pointer to the associated polyline by using the
33437  // boundary id
33438  TriangleMeshPolyLine *dst_polyline =
33439  this->boundary_polyline_pt(dst_bnd_id_final);
33440  // The number of vertices on the destination boundary
33441  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33442  // Loop over the vertices print them
33443  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33444  {
33445  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33446  error_message
33447  << "Vertex#("<<i<<"): ("
33448  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33449  }
33450  throw OomphLibError(
33451  error_message.str(),
33452  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33453  OOMPH_EXCEPTION_LOCATION);
33454  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33455 
33456  } // if (this->is_mesh_distributed())
33457 #endif // #ifdef OOMPH_HAS_MPI
33458 
33459 #endif // #ifdef PARANOID
33460 
33461  // Flag to indicate if the vertex was found on the destination
33462  // boundary
33463  bool found_vertex_on_dst_boundary_final = false;
33464 
33465  // Flag that stores the chunk number to connect (only used in
33466  // distributed meshes)
33467  unsigned sub_poly_to_connect = 0;
33468 
33469  // Store the vertex number on the destination boundary
33470  unsigned n_vertex_connection_final = 0;
33471 
33472  // Flags only used in a distributed mesh
33473  // ----------------------------------------
33474  // Flag to indicate we are trying to connect to an split boundary
33475  bool connecting_to_an_split_boundary = false;
33476 
33477  // Flag to indicate we are trying to connecto to an internal
33478  // boundary that is overlaped by a shared boundary)
33479  bool connecting_to_an_overlaped_boundary = false;
33480 
33481 #ifdef OOMPH_HAS_MPI
33482  if (this->is_mesh_distributed())
33483  {
33484  // We can only connect to an original boundary, check if the
33485  // boundary was splitted during the distribution process to
33486  // consider all the chunks (sub-polylines) of the boundary
33487  if (this->boundary_was_splitted(dst_bnd_id_final))
33488  {
33489  connecting_to_an_split_boundary = true;
33490  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33491 
33492  // Check if the destination boundary, or any of its chunks is
33493  // marked to be overlapped by a shared boundary, if that is the
33494  // case we can only connect to the chunks that are not
33495  // overlapped by shared boundaries (the shared boundaries are in
33496  // charge of generating the connections with original boundaries
33497  // and with themselves)
33498  if (connecting_to_an_split_boundary)
33499  {
33500  // Get the number of chucks that represent the destination
33501  // boundary
33502  const unsigned n_sub_poly =
33503  this->nboundary_subpolylines(dst_bnd_id_final);
33504  // Now loop over the chunks of the destination boundary and if
33505  // any of them is marked to be overlaped by a shared boundary
33506  // then set the flag and break the loop
33507  for (unsigned ii =0; ii < n_sub_poly; ii++)
33508  {
33509  if (this->
33510  boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33511  {
33512  // Mark the boundary as being overlaped by a shared
33513  // boundary
33514  connecting_to_an_overlaped_boundary = true;
33515  // Break, no need to look for more overlapings
33516  break;
33517  } // if (boundary_marked_as_shared_boundary(...))
33518  } // for (ii < n_sub_poly)
33519  } // if (connecting_to_an_split_boundary)
33520  else
33521  {
33522  // If not connecting to an split boundary then check if the
33523  // whole destination boundary is overlaped by an internal
33524  // boundary
33525  if (this->
33526  boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33527  {
33528  // Mark the boundary as being overlaped by a shared boundary
33529  connecting_to_an_overlaped_boundary = true;
33530  } // if (boundary_marked_as_shared_boundary(...))
33531  } // else if (connecting_to_an_split_boundary)
33532 
33533  } // if (this->is_mesh_distributed())
33534 
33535 #endif // #ifdef OOMPH_HAS_MPI
33536 
33537  // If we are connecting neither to an split boundary nor an
33538  // overlaped boundary then get the pointer to the original
33539  // boundary
33540  if (!(connecting_to_an_split_boundary ||
33541  connecting_to_an_overlaped_boundary))
33542  {
33543  // Get the polyline pointer representing the destination
33544  // boundary
33545  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33546  } // else if (NOT split, NOT overlaped)
33547 
33548  // Now look for the vertex number on the destination boundary(ies)
33549  // -- in case that the boundary was split ---
33550 
33551  // Do not check for same orientation, that was previously worked
33552  // by interchanging the connections boundaries (if necessary)
33553 
33554  // If the boundary was not split then ...
33555  if (!connecting_to_an_split_boundary)
33556  {
33557  // ... check if the boundary is marked to be overlaped by
33558  // a shared boundary
33559  if (!connecting_to_an_overlaped_boundary)
33560  {
33561  // If that is not the case then we can safely look for the
33562  // vertex number on the destination boundary
33563  found_vertex_on_dst_boundary_final =
33564  this->get_connected_vertex_number_on_destination_polyline(
33565  poly_to_connect_pt,
33566  src_vertex_coordinates_final,
33567  n_vertex_connection_final);
33568 
33569  } // if (!connecting_to_an_overlaped_boundary)
33570  else
33571  {
33572  // If the whole boundary is marked to be overlaped by a shared
33573  // boundary then do nothing, the shared boundaries are already
33574  // in charge of performing the connection (it will be required
33575  // to disabled the connection) with the original boundary
33576 
33577  } // else if (!connecting_to_an_overlaped_boundary)
33578 
33579  } // if (!connecting_to_an_split_boundary)
33580 #ifdef OOMPH_HAS_MPI
33581  else
33582  {
33583  // If the boundary was split then we need to look for the vertex
33584  // in the sub-polylines
33585 
33586  // Get the sub-polylines vector
33587  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33588  this->boundary_subpolylines(dst_bnd_id_final);
33589 
33590  // Get the number of sub-polylines
33591  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33592 #ifdef PARANOID
33593  if (nsub_poly <= 1)
33594  {
33595  std::ostringstream error_message;
33596  error_message
33597  <<"The boundary (" << dst_bnd_id_final << ") was "
33598  << "marked to be splitted but\n"
33599  << "there are only ("<<nsub_poly<<") polylines to "
33600  << "represent it.\n";
33601  throw OomphLibError(
33602  error_message.str(),
33603  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33604  OOMPH_EXCEPTION_LOCATION);
33605  } // if (nsub_poly <= 1)
33606 #endif
33607  // We need to check if the boundary is marked to be overlaped by
33608  // a shared boundary, if that is the case we need to check for
33609  // each indivual subpolyline, and for those overlaped by a
33610  // shared polyline do nothing, the shared polylines have already
33611  // deal with these connections
33612 
33613  // ... check if the boundary is marked to be overlaped by
33614  // a shared boundary
33615  if (!connecting_to_an_overlaped_boundary)
33616  {
33617  // The boundary is not overlapped by shared boundaries, we can
33618  // work without checking the subpolylines individually (non of
33619  // them are overlapped by a shared boundary)
33620 
33621  // Look for the vertex number to connect on each of the
33622  // subpolyines
33623  for (unsigned isub = 0; isub < nsub_poly; isub++)
33624  {
33625  // Assign the pointer to the sub-polyline
33626  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33627  // Search for the vertex in the current sub-polyline
33628  found_vertex_on_dst_boundary_final =
33629  this->get_connected_vertex_number_on_destination_polyline(
33630  poly_to_connect_pt,
33631  src_vertex_coordinates_final,
33632  n_vertex_connection_final);
33633 
33634  // If we have found the vertex to connect then break the
33635  // loop
33636  if (found_vertex_on_dst_boundary_final)
33637  {
33638  // But first save the subpoly number (chunk), that will be
33639  // used to perform the connection
33640  sub_poly_to_connect = isub;
33641  break;
33642  } // if (found_vertex_on_dst_boundary_initial)
33643 
33644  } // for (isub < nsub_poly)
33645 
33646  } // if (!connecting_to_an_overlaped_boundary)
33647  else
33648  {
33649  // If connecting to an overlapped boundary then we ignore the
33650  // subpolylines overlapped by shared boundaries and only look
33651  // on the sub-polylines that are not marked as being overlaped
33652  // by shared boundaries
33653 
33654  // Look for the vertex number to connect on each of the
33655  // subpolyines
33656  for (unsigned isub = 0; isub < nsub_poly; isub++)
33657  {
33658  // Only work with those sub-polylines that are not overlaped
33659  // by shared boundaries
33660  if (!this->
33661  boundary_marked_as_shared_boundary(dst_bnd_id_final, isub))
33662  {
33663  // Assign the pointer to the sub-polyline
33664  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33665 
33666  // Search for the vertex in the current sub-polyline
33667  found_vertex_on_dst_boundary_final =
33668  this->get_connected_vertex_number_on_destination_polyline(
33669  poly_to_connect_pt,
33670  src_vertex_coordinates_final,
33671  n_vertex_connection_final);
33672 
33673  // Was the vertex found?
33674  if (found_vertex_on_dst_boundary_final)
33675  {
33676  // But first save the subpoly number (chunk), that will
33677  // be used to perform the connection
33678  sub_poly_to_connect = isub;
33679  break;
33680  } // if (found_vertex_on_dst_boundary_final)
33681 
33682  } // if (not overlaped by shared boundary)
33683 
33684  } // for (isub < nsub_poly)
33685 
33686  } // else if (!connecting_to_an_overlaped_boundary)
33687 
33688  } // else if (!connecting_to_an_split_boundary)
33689 #endif // #ifdef OOMPH_HAS_MPI
33690 
33691  // If not found it may be that the connection information is
33692  // inverted
33693  if (!found_vertex_on_dst_boundary_final)
33694  {
33695  // Is the mesh distributed?
33696 #ifdef OOMPH_HAS_MPI
33697  if (this->is_mesh_distributed())
33698  {
33699  // If the mesh is distributed and the vertex number was not
33700  // found, that means that the boundary (or vertex) to connect
33701  // in the destination boundary is not in the current
33702  // processor. In that suspend the connection
33703  polyline_pt->suspend_final_vertex_connected();
33704  // Add the polyline to the vector of polylines whose
33705  // connection will be resumed at the end of the adaptation
33706  // process
33707  resume_final_connection_polyline_pt.push_back(polyline_pt);
33708  // The shared boundaries are marked to connect to the final
33709  // vertex of the polyline (remember that a shared boundary
33710  // stops adding nodes when it finds a node on an original
33711  // boundary) -- The final vertex is now a base node
33712  } // if (this->is_mesh_distributed())
33713  else
33714 #endif // #ifdef OOMPH_HAS_MPI
33715  {
33716 #ifdef PARANOID
33717  // If not found then there is a problem with the vertices
33718  // Get the associated boundary id of the current polyline
33719  const unsigned bnd_id = polyline_pt->boundary_id();
33720  std::ostringstream error_message;
33721  error_message
33722  << "FINAL VERTEX CONNECTION\n"
33723  << "It was not possible to find the associated "
33724  << "vertex number on the destination boundary\n"
33725  << "The current boundary (" << bnd_id << ") is marked to have "
33726  << "a connection at the\nFINAL vertex ("
33727  << src_vertex_coordinates_final[0] << ","
33728  << src_vertex_coordinates_final[1] << ")\n"
33729  << "with boundary ("<< dst_bnd_id_final << ")\n"
33730  << "This is the list of vertices on the destination boundary\n";
33731  // Get the pointer to the associated polyline by using the
33732  // boundary id
33733  TriangleMeshPolyLine *dst_polyline =
33734  this->boundary_polyline_pt(dst_bnd_id_final);
33735  // The number of vertices on the destination boundary
33736  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33737  // Loop over the vertices print them
33738  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33739  {
33740  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33741  error_message
33742  << "Vertex#("<<i<<"): ("
33743  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33744  }
33745  throw OomphLibError(
33746  error_message.str(),
33747  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33748  OOMPH_EXCEPTION_LOCATION);
33749 #endif
33750  } // else if (this->is_mesh_distributed())
33751 
33752  } // if (!found_vertex_on_dst_boundary_final)
33753  else
33754  {
33755  // Set the vertex number on the destination boundary
33756  polyline_pt->final_vertex_connected_n_vertex() =
33757  n_vertex_connection_final;
33758 
33759  // Set the chunk number on the destination boundary
33760  polyline_pt->final_vertex_connected_n_chunk() =
33761  sub_poly_to_connect;
33762 
33763  } // else if (!found_vertex_on_dst_boundary_final)
33764 
33765  } // if (polyline_pt->is_final_vertex_connected())
33766 
33767  }
33768 
33769  //=========================================================================
33770  /// \short Resume the boundary connections that may have been
33771  /// suspended because the destination boundary is no part of the
33772  /// domain. The connections are no permanently suspended because if
33773  /// load balance takes place the destination boundary may be part of
33774  /// the new domain representation therefore the connection would
33775  /// exist
33776  //=========================================================================
33777  template<class ELEMENT>
33779  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33780  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33781  {
33782  // Get the number of polylines that require to resume the connection
33783  // at the initial vertex
33784  const unsigned n_initial_poly =
33785  resume_initial_connection_polyline_pt.size();
33786  // Loop over the polylines that require to resume the connection
33787  // at the initial vertex
33788  for (unsigned p = 0; p < n_initial_poly; p++)
33789  {
33790  // Get the polyline
33791  TriangleMeshPolyLine* tmp_poly_pt =
33792  resume_initial_connection_polyline_pt[p];
33793  // Resume the connection with the initial vertex
33794  tmp_poly_pt->resume_initial_vertex_connected();
33795  } // for (p < n_initial_poly)
33796 
33797  // Get the number of polylines that require to resume the connection
33798  // at the final vertex
33799  const unsigned n_final_poly =
33800  resume_final_connection_polyline_pt.size();
33801  // Loop over the polylines that require to resume the connection at
33802  // the final vertex
33803  for (unsigned p = 0; p < n_final_poly; p++)
33804  {
33805  // Get the polyline
33806  TriangleMeshPolyLine* tmp_poly_pt =
33807  resume_final_connection_polyline_pt[p];
33808  // Resume the connection with the final vertex
33809  tmp_poly_pt->resume_final_vertex_connected();
33810  } // for (p < n_final_poly)
33811 
33812  // Clear the storage
33813  resume_initial_connection_polyline_pt.clear();
33814  resume_final_connection_polyline_pt.clear();
33815 
33816  }
33817 
33818 //=========================================================================
33819 /// \short Gets the associated vertex number according to the vertex
33820 /// coordinates on the destination boundary
33821 //=========================================================================
33822 template<class ELEMENT>
33825  Vector<double> &vertex_coordinates,
33826  const unsigned &dst_bnd_id,
33827  unsigned &vertex_number)
33828  {
33829 
33830  bool found_associated_vertex_number = false;
33831 
33832  // Get the pointer to the associated polyline by using the boundary id
33833  TriangleMeshPolyLine *dst_polyline =
33834  this->boundary_polyline_pt(dst_bnd_id);
33835 
33836  const unsigned n_vertices = dst_polyline->nvertex();
33837 
33838  // Loop over the vertices and return the closest vertex
33839  // to the given vertex coordinates
33840  for (unsigned i = 0; i < n_vertices; i++)
33841  {
33842 
33843  Vector<double> current_vertex =
33844  dst_polyline->vertex_coordinate(i);
33845 
33846  double error =
33847  (vertex_coordinates[0] - current_vertex[0])*
33848  (vertex_coordinates[0] - current_vertex[0])
33849  +
33850  (vertex_coordinates[1] - current_vertex[1])*
33851  (vertex_coordinates[1] - current_vertex[1]);
33852 
33853  error = sqrt(error);
33854 
33855  if(error <
33857  {
33858  vertex_number = i;
33859  found_associated_vertex_number = true;
33860  break;
33861  }
33862 
33863  }
33864 
33865  return found_associated_vertex_number;
33866 
33867  }
33868 
33869 //=========================================================================
33870 /// \short Helper function that updates the input polygon's PSLG
33871 /// by using the end-points of elements from FaceMesh(es) that are
33872 /// constructed for the boundaries associated with the segments of the
33873 /// polygon. Optional boolean is used to run it as test only (if
33874 /// true is specified as input) in which case polygon isn't actually
33875 /// modified. Returned boolean indicates if polygon was (or would have
33876 /// been -- if called with check_only=false) changed.
33877 //=========================================================================
33878 template<class ELEMENT>
33881  const bool& check_only)
33882  {
33883 #ifdef PARANOID
33884  // If the mesh is marked as distributed this method can not be
33885  // called since there is no guarantee of creating (distributed)
33886  // meshes that match in the number and position of nodes at their
33887  // shared boundaries. The only exececption is when called with
33888  // check_only=true, since no boundary updating is performed
33889  if (this->is_mesh_distributed() && !check_only)
33890  {
33891  std::stringstream error_message;
33892  error_message
33893  << "The updating of polygons of a distributed mesh can ONLY be\n"
33894  << "performed using the element's area associated to the halo(ed)\n"
33895  << "elements.\n"
33896  << "1) Make sure you have enabled the parallel mesh adaptation\n"
33897  << "option if you are working with a distributed mesh, OR\n"
33898  << "2) Make sure to call the update_..._using_elements_area() methods\n"
33899  << "if the mesh is marked as distributed\n\n";
33900  throw OomphLibError(error_message.str(),
33901  OOMPH_CURRENT_FUNCTION,
33902  OOMPH_EXCEPTION_LOCATION);
33903  } // if (this->is_mesh_distributed())
33904 #endif
33905 
33906  // Boolean that indicates whether an actual update of the polygon
33907  // was performed or not
33908  bool unrefinement_was_performed=false;
33909  bool refinement_was_performed=false;
33910  bool max_length_applied = false;
33911 
33912  //Loop over the number of polylines
33913  const unsigned n_polyline = polygon_pt->npolyline();
33914 
33915  // Get face mesh representation of all polylines, possibly
33916  // with segments re-distributed to maintain an approximately
33917  // even sub-division of the polygon
33918  Vector<Mesh*> face_mesh_pt;
33919  get_face_mesh_representation(polygon_pt,face_mesh_pt);
33920 
33921  // Create vertices for the polylines by using the vertices
33922  // of the FaceElements
33923  Vector<double> vertex_coord(3); // zeta,x,y
33924  Vector<double> bound_left(1);
33925  Vector<double> bound_right(1);
33926 
33927  for(unsigned p=0;p<n_polyline;p++)
33928  {
33929  // Set of coordinates that will be placed on the boundary
33930  // Set entries are ordered on first entry in vector which stores
33931  // the boundary coordinate so the vertices come out in order!
33932  std::set<Vector<double> > vertex_nodes;
33933 
33934  //Get the boundary id
33935  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
33936 
33937  // Get the chunk number
33938  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
33939 
33940  // Loop over the face elements (ordered) and add their vertices
33941  unsigned n_face_element = face_mesh_pt[p]->nelement();
33942  for(unsigned e=0;e<n_face_element;++e)
33943  {
33944  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
33945 
33946 #ifdef OOMPH_HAS_MPI
33947  // Only work with non-halo elements if the mesh is distributed
33948  if (this->is_mesh_distributed() && el_pt->is_halo()) {continue;}
33949 #endif
33950 
33951  unsigned n_node = el_pt->nnode();
33952 
33953  //Add the left-hand node to the set:
33954 
33955  // Boundary coordinate
33956  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
33957  vertex_coord[0] = bound_left[0];
33958 
33959  // Actual coordinates
33960  for(unsigned i=0;i<2;i++)
33961  {
33962  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
33963  }
33964  vertex_nodes.insert(vertex_coord);
33965 
33966  //Add the right-hand nodes to the set:
33967 
33968  //Boundary coordinate
33969  el_pt->node_pt(n_node-1)->
33970  get_coordinates_on_boundary(bound,bound_right);
33971  vertex_coord[0] = bound_right[0];
33972 
33973  // Actual coordinates
33974  for(unsigned i=0;i<2;i++)
33975  {
33976  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
33977  }
33978  vertex_nodes.insert(vertex_coord);
33979 
33980  }
33981 
33982  // Now turn into vector for ease of handling...
33983  unsigned n_poly_vertex = vertex_nodes.size();
33984  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
33985  unsigned count=0;
33986  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
33987  it!=vertex_nodes.end();++it)
33988  {
33989  tmp_vector_vertex_node[count].resize(3);
33990  tmp_vector_vertex_node[count][0] = (*it)[0];
33991  tmp_vector_vertex_node[count][1] = (*it)[1];
33992  tmp_vector_vertex_node[count][2] = (*it)[2];
33993  ++count;
33994  }
33995 
33996  // Size of the vector
33997  unsigned n_vertex=tmp_vector_vertex_node.size();
33998 
33999  // Tolerance below which the middle point can be deleted
34000  // (ratio of deflection to element length)
34001  double unrefinement_tolerance=
34002  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
34003 
34004  //------------------------------------------------------
34005  // Unrefinement
34006  //------------------------------------------------------
34007  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34008  {
34009  unrefinement_was_performed =
34010  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34011  unrefinement_tolerance, check_only);
34012 
34013  // In this case the "unrefinement_was_performed" variable
34014  // tell us if the update had been performed when calling
34015  // with check_oly=false
34016  if (check_only && unrefinement_was_performed)
34017  {
34018  // Cleanup (but only the elements -- the nodes still exist in
34019  // the bulk mesh!
34020  for(unsigned p=0;p<n_polyline;p++)
34021  {
34022  face_mesh_pt[p]->flush_node_storage();
34023  delete face_mesh_pt[p];
34024  }
34025  return true;
34026  }
34027 
34028  } // end of unrefinement
34029 
34030  // Do not perform refinement if there are no more than two vertices
34031  // New size of the vector
34032  n_vertex=tmp_vector_vertex_node.size();
34033 
34034  //------------------------------------------------
34035  // Refinement
34036  //------------------------------------------------
34037  double refinement_tolerance=
34038  polygon_pt->polyline_pt(p)->refinement_tolerance();
34039  if (refinement_tolerance>0.0 && n_vertex >= 2)
34040  {
34041  refinement_was_performed =
34042  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34043  refinement_tolerance, check_only);
34044 
34045  // In this case the "refinement_was_performed" variable
34046  // tell us if the update had been performed when calling
34047  // with check_only=false
34048  if (check_only && refinement_was_performed)
34049  {
34050  // Cleanup (but only the elements -- the nodes still exist in
34051  // the bulk mesh!
34052  for(unsigned p=0;p<n_polyline;p++)
34053  {
34054  face_mesh_pt[p]->flush_node_storage();
34055  delete face_mesh_pt[p];
34056  }
34057  return true;
34058  }
34059 
34060  } // end refinement
34061 
34062  // Do not perform maximum length constraint if there are no more than
34063  // two vertices
34064  // New size of the vector
34065  n_vertex=tmp_vector_vertex_node.size();
34066 
34067  //------------------------------------------------
34068  // Maximum length constrait
34069  //-----------------------------------------------
34070  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34071  if (maximum_length > 0.0 && n_vertex >= 2)
34072  {
34073  max_length_applied =
34074  apply_max_length_constraint(face_mesh_pt[p],
34075  tmp_vector_vertex_node,
34076  maximum_length);
34077 
34078  // In this case the max length criteria was applied, check if
34079  // check_only=false
34080  if (check_only && max_length_applied)
34081  {
34082  // Cleanup (but only the elements -- the nodes still exist in
34083  // the bulk mesh!
34084  for(unsigned p=0;p<n_polyline;p++)
34085  {
34086  face_mesh_pt[p]->flush_node_storage();
34087  delete face_mesh_pt[p];
34088  }
34089  return true;
34090  }
34091 
34092  }
34093 
34094  // For further processing the three-dimensional vector
34095  // has to be reduced to a two-dimensional vector
34096  n_vertex=tmp_vector_vertex_node.size();
34097  Vector<Vector<double> > vector_vertex_node(n_vertex);
34098 
34099  for(unsigned i=0;i<n_vertex;i++)
34100  {
34101  vector_vertex_node[i].resize(2);
34102  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34103  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34104  }
34105 
34106 #ifdef OOMPH_HAS_MPI
34107  // Only perform this checking if the mesh is not distributed. When
34108  // the mesh is distributed the polylines continuity is addressed in
34109  // the sort_polylines_helper() method
34110  if (!this->is_mesh_distributed())
34111 #endif
34112  {
34113  if ( (p > 0) && !check_only )
34114  {
34115  //Final end point of previous line
34116  Vector<double> final_vertex_of_previous_segment;
34117  unsigned n_prev_vertex =
34118  polygon_pt->curve_section_pt(p-1)->nvertex();
34119  final_vertex_of_previous_segment =
34120  polygon_pt->polyline_pt(p-1)->
34121  vertex_coordinate(n_prev_vertex-1);
34122 
34123  unsigned prev_seg_boundary_id =
34124  polygon_pt->curve_section_pt(p-1)->boundary_id();
34125 
34126  //Find the error between the final vertex of the previous
34127  //line and the first vertex of the current line
34128  double error = 0.0;
34129  for(unsigned i=0;i<2;i++)
34130  {
34131  const double dist =
34132  final_vertex_of_previous_segment[i] -
34133  (*vector_vertex_node.begin())[i];
34134  error += dist*dist;
34135  }
34136  error = sqrt(error);
34137 
34138  //If the error is bigger than the tolerance then
34139  //we probably need to reverse, but better check
34141  {
34142  //Find the error between the final vertex of the previous
34143  //line and the last vertex of the current line
34144  double rev_error = 0.0;
34145  for(unsigned i=0;i<2;i++)
34146  {
34147  const double dist =
34148  final_vertex_of_previous_segment[i] -
34149  (*--vector_vertex_node.end())[i];
34150  rev_error += dist*dist;
34151  }
34152  rev_error = sqrt(rev_error);
34153 
34154  if(rev_error >
34156  {
34157  // It could be possible that the first segment be reversed and we
34158  // did not notice it because this check does not apply for the
34159  // first segment. We can verify if the first segment is reversed
34160  // by using the vertex number 1
34161  if (p == 1)
34162  {
34163 
34164  //Initial end point of previous line
34165  Vector<double> initial_vertex_of_previous_segment;
34166 
34167  initial_vertex_of_previous_segment =
34168  polygon_pt->polyline_pt(p-1)->
34169  vertex_coordinate(0);
34170 
34171  unsigned prev_seg_boundary_id =
34172  polygon_pt->curve_section_pt(p-1)->boundary_id();
34173 
34174  //Find the error between the initial vertex of the previous
34175  //line and the first vertex of the current line
34176  double error = 0.0;
34177  for(unsigned i=0;i<2;i++)
34178  {
34179  const double dist =
34180  initial_vertex_of_previous_segment[i] -
34181  (*vector_vertex_node.begin())[i];
34182  error += dist*dist;
34183  }
34184  error = sqrt(error); // Reversed only the previous one
34185 
34186  //If the error is bigger than the tolerance then
34187  //we probably need to reverse, but better check
34189  {
34190  //Find the error between the final vertex of the previous
34191  //line and the last vertex of the current line
34192  double rev_error = 0.0;
34193  for(unsigned i=0;i<2;i++)
34194  {
34195  const double dist =
34196  initial_vertex_of_previous_segment[i] -
34197  (*--vector_vertex_node.end())[i];
34198  rev_error += dist*dist;
34199  }
34200  rev_error = sqrt(rev_error); // Reversed both the current one and
34201  // the previous one
34202 
34203  if (rev_error >
34205  {
34206  std::ostringstream error_stream;
34207  error_stream
34208  <<"The distance between the first node of the current\n"
34209  <<"line segment (boundary " << bound << ") and either end of "
34210  << "the previous line segment\n"
34211  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
34212  << "the desired tolerance " <<
34214  << "This suggests that the polylines defining the polygonal\n"
34215  << "representation are not properly ordered.\n"
34216  << "Fail on last vertex of polyline: ("
34217  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
34218  << bound << ").\nThis should have failed when first trying to "
34219  << "construct the\npolygon.\n";
34220  throw OomphLibError(error_stream.str(),
34221  OOMPH_CURRENT_FUNCTION,
34222  OOMPH_EXCEPTION_LOCATION);
34223 
34224  }
34225  else
34226  {
34227  // Reverse both
34228  // Reverse the current vector to line up with the previous one
34229  std::reverse(vector_vertex_node.begin(),
34230  vector_vertex_node.end());
34231 
34232  polygon_pt->polyline_pt(p-1)->reverse();
34233  }
34234  }
34235  else
34236  {
34237  // Reverse the previous one
34238  polygon_pt->polyline_pt(p-1)->reverse();
34239  }
34240 
34241  } // if p == 1
34242  else
34243  {
34244  std::ostringstream error_stream;
34245  error_stream
34246  <<"The distance between the first node of the current\n"
34247  <<"line segment (boundary " << bound << ") and either end of "
34248  << "the previous line segment\n"
34249  << "(boundary " << prev_seg_boundary_id << ") is bigger than the "
34250  << "desired tolerance " <<
34252  <<"This suggests that the polylines defining the polygonal\n"
34253  <<"representation are not properly ordered.\n"
34254  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
34255  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34256  << "This should have failed when first trying to construct the\n"
34257  << "polygon.\n";
34258  throw OomphLibError(error_stream.str(),
34259  OOMPH_CURRENT_FUNCTION,
34260  OOMPH_EXCEPTION_LOCATION);
34261  }
34262  }
34263  else
34264  {
34265  //Reverse the current vector to line up with the previous one
34266  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34267  }
34268 
34269  } // first error
34270  } // p > 0
34271  } // is mesh not distributed?
34272 
34273  if(!check_only)
34274  {
34275  // Now update the polyline according to the new vertices
34276  // The new one representation
34277  TriangleMeshPolyLine *tmp_polyline_pt =
34278  new TriangleMeshPolyLine(vector_vertex_node,bound);
34279 
34280  // Create a temporal "curve section" version of the recently created
34281  // polyline
34282  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
34283 
34284  // Establish refinement and unrefinement tolerance
34285  tmp_polyline_pt->set_unrefinement_tolerance(
34286  unrefinement_tolerance);
34287  tmp_polyline_pt->set_refinement_tolerance(
34288  refinement_tolerance);
34289 
34290  // Establish the maximum length constraint
34291  tmp_polyline_pt->set_maximum_length(maximum_length);
34292 
34293  // We pass the connection information from the old polyline to
34294  // the new one
34295  this->copy_connection_information(polygon_pt->polyline_pt(p),
34296  tmp_curve_section_pt);
34297 
34298  //Now update the polyline according to the new vertices but
34299  //first check if the object is allowed to delete the representation
34300  //or if it should be done by other object
34301  bool delete_it_on_destructor = false;
34302 
34303  std::set<TriangleMeshCurveSection*>::iterator it =
34304  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34305 
34306  if (it!=this->Free_curve_section_pt.end())
34307  {
34308  this->Free_curve_section_pt.erase(it);
34309  delete polygon_pt->curve_section_pt(p);
34310  delete_it_on_destructor = true;
34311  }
34312 
34313  // ------------------------------------------------------------
34314  // Copying the new representation
34315  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34316 
34317  // Update the Boundary - Polyline map
34318  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
34319 
34320  if (delete_it_on_destructor)
34321  {
34322  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34323  }
34324 
34325  } // if(!check_only)
34326 
34327  } // for (p < n_polyline)
34328 
34329  // Cleanup (but only the elements -- the nodes still exist in
34330  // the bulk mesh!
34331  for(unsigned p=0;p<n_polyline;p++)
34332  {
34333  face_mesh_pt[p]->flush_node_storage();
34334  delete face_mesh_pt[p];
34335  }
34336 
34337  if(check_only)
34338  {
34339  // if we end up all the way down here, no update of the internal boundaries
34340  // is necessary (in case we only check)
34341  return false;
34342  }
34343  else
34344  {
34345  // if we not only check, but actually perform the update and end up
34346  // all the way down here then we indicate whether an update was performed
34347  // or not
34348  return (unrefinement_was_performed ||
34349  refinement_was_performed ||
34350  max_length_applied);
34351  }
34352 
34353  }
34354 
34355 //=========================================================================
34356 /// \short Helper function that updates the input open curve by using
34357 /// end-points of elements from FaceMesh(es) that are constructed for the
34358 /// boundaries associated with the polylines. Optional boolean is used to
34359 /// run it as test only (if true is specified as input) in which case the
34360 /// polylines are not actually modified. Returned boolean indicates if
34361 /// polylines were (or would have been -- if called with check_only=false)
34362 /// changed.
34363 //=========================================================================
34364 template<class ELEMENT>
34367  const bool& check_only)
34368  {
34369 #ifdef PARANOID
34370  // If the mesh is marked as distributed this method can not be
34371  // called since there is no guarantee of creating (distributed)
34372  // meshes that match in the number and position of nodes at their
34373  // shared boundaries. The only exececption is when called with
34374  // check_only=true, since no boundary updating is performed
34375  if (this->is_mesh_distributed() && !check_only)
34376  {
34377  std::stringstream error_message;
34378  error_message
34379  << "The updating of open curves of a distributed mesh can ONLY be\n"
34380  << "performed using the element's area associated to the halo(ed)\n"
34381  << "elements.\n"
34382  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34383  << "option if you are working with a distributed mesh, OR\n"
34384  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34385  << "if the mesh is marked as distributed\n\n";
34386  throw OomphLibError(error_message.str(),
34387  OOMPH_CURRENT_FUNCTION,
34388  OOMPH_EXCEPTION_LOCATION);
34389  } // if (this->is_mesh_distributed())
34390 #endif
34391 
34392  // Boolean that indicates whether an actual update of the polylines
34393  // were performed or not
34394  bool unrefinement_was_performed=false;
34395  bool refinement_was_performed=false;
34396  bool max_length_applied = false;
34397 
34398  //Loop over the number of polylines
34399  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34400 
34401  // Get face mesh representation of all polylines, possibly
34402  // with segments re-distributed to maintain an approximately
34403  // even sub-division of the polygon
34404  Vector<Mesh*> face_mesh_pt;
34405  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34406 
34407  // Create vertices for the polylines by using the vertices
34408  // of the FaceElements
34409  Vector<double> vertex_coord(3); // zeta,x,y
34410  Vector<double> bound_left(1);
34411  Vector<double> bound_right(1);
34412 
34413  for(unsigned p=0;p<n_polyline;p++)
34414  {
34415  // Set of coordinates that will be placed on the boundary
34416  // Set entries are ordered on first entry in vector which stores
34417  // the boundary coordinate so the vertices come out in order!
34418  std::set<Vector<double> > vertex_nodes;
34419 
34420  //Get the boundary id
34421  const unsigned bound =
34422  open_polyline_pt->curve_section_pt(p)->boundary_id();
34423 
34424  // Get the chunk number
34425  const unsigned chunk =
34426  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34427 
34428  // Loop over the face elements (ordered) and add their vertices
34429  unsigned n_face_element = face_mesh_pt[p]->nelement();
34430 
34431  //n_count = 0;
34432  for(unsigned e=0;e<n_face_element;++e)
34433  {
34434  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34435  unsigned n_node = el_pt->nnode();
34436 
34437  //Add the left-hand node to the set:
34438 
34439  // Boundary coordinate
34440  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
34441  vertex_coord[0] = bound_left[0];
34442 
34443  // Actual coordinates
34444  for(unsigned i=0;i<2;i++)
34445  {
34446  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
34447  }
34448  vertex_nodes.insert(vertex_coord);
34449 
34450  //Add the right-hand nodes to the set:
34451 
34452  //Boundary coordinate
34453  el_pt->node_pt(n_node-1)->get_coordinates_on_boundary(bound,bound_right);
34454  vertex_coord[0] = bound_right[0];
34455 
34456  // Actual coordinates
34457  for(unsigned i=0;i<2;i++)
34458  {
34459  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
34460  }
34461  vertex_nodes.insert(vertex_coord);
34462 
34463  }
34464 
34465  // Now turn into vector for ease of handling...
34466  unsigned n_poly_vertex = vertex_nodes.size();
34467  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
34468  unsigned count=0;
34469  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
34470  it!=vertex_nodes.end();++it)
34471  {
34472  tmp_vector_vertex_node[count].resize(3);
34473  tmp_vector_vertex_node[count][0] = (*it)[0];
34474  tmp_vector_vertex_node[count][1] = (*it)[1];
34475  tmp_vector_vertex_node[count][2] = (*it)[2];
34476  ++count;
34477  }
34478 
34479  // Size of the vector
34480  unsigned n_vertex=tmp_vector_vertex_node.size();
34481 
34482  // Tolerance below which the middle point can be deleted
34483  // (ratio of deflection to element length)
34484  double unrefinement_tolerance=
34485  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34486 
34487  //------------------------------------------------------
34488  // Unrefinement
34489  //------------------------------------------------------
34490  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34491  {
34492  unrefinement_was_performed =
34493  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34494  unrefinement_tolerance, check_only);
34495 
34496  // In this case the unrefinement_was_performed variable actually
34497  // tell us if the update had been performed when calling
34498  // with check_only=false
34499  if (check_only && unrefinement_was_performed)
34500  {
34501  // Cleanup (but only the elements -- the nodes still exist in
34502  // the bulk mesh!
34503  for(unsigned p=0;p<n_polyline;p++)
34504  {
34505  face_mesh_pt[p]->flush_node_storage();
34506  delete face_mesh_pt[p];
34507  }
34508  return true;
34509  }
34510 
34511  } // end of unrefinement
34512 
34513  // Do not perform refinement if there are no more than two vertices
34514  // (open curve version)
34515  // New size of the vector
34516  n_vertex=tmp_vector_vertex_node.size();
34517 
34518  //------------------------------------------------
34519  /// Refinement
34520  //------------------------------------------------
34521  double refinement_tolerance=
34522  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34523  if (refinement_tolerance>0.0 && n_vertex >= 2)
34524  {
34525  refinement_was_performed =
34526  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34527  refinement_tolerance, check_only);
34528 
34529  // In this case the unrefinement_was_performed variable actually
34530  // tell us if the update had been performed when calling
34531  // with check_only=false
34532  if (check_only && refinement_was_performed)
34533  {
34534  // Cleanup (but only the elements -- the nodes still exist in
34535  // the bulk mesh!
34536  for(unsigned p=0;p<n_polyline;p++)
34537  {
34538  face_mesh_pt[p]->flush_node_storage();
34539  delete face_mesh_pt[p];
34540  }
34541  return true;
34542  }
34543 
34544  } // end refinement
34545 
34546  // Do not perform maximum length constraint if there are no more than
34547  // two vertices
34548  // New size of the vector
34549  n_vertex=tmp_vector_vertex_node.size();
34550 
34551  //------------------------------------------------
34552  // Maximum length constraint
34553  //-----------------------------------------------
34554  double maximum_length = open_polyline_pt->polyline_pt(p)->maximum_length();
34555  if (maximum_length > 0.0 && n_vertex >= 2)
34556  {
34557  bool max_length_applied = false;
34558  max_length_applied =
34559  apply_max_length_constraint(face_mesh_pt[p],
34560  tmp_vector_vertex_node,
34561  maximum_length);
34562 
34563  // In this case the max length criteria was applied, check if
34564  // check_only=false
34565  if (check_only && max_length_applied)
34566  {
34567  // Cleanup (but only the elements -- the nodes still exist in
34568  // the bulk mesh!
34569  for(unsigned p=0;p<n_polyline;p++)
34570  {
34571  face_mesh_pt[p]->flush_node_storage();
34572  delete face_mesh_pt[p];
34573  }
34574  return true;
34575  }
34576 
34577  }
34578 
34579  // For further processing the three-dimensional vector
34580  // has to be reduced to a two-dimensional vector
34581  n_vertex=tmp_vector_vertex_node.size();
34582  Vector<Vector<double> > vector_vertex_node(n_vertex);
34583 
34584  for(unsigned i=0;i<n_vertex;i++)
34585  {
34586  vector_vertex_node[i].resize(2);
34587  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34588  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34589  }
34590 
34591 #ifdef OOMPH_HAS_MPI
34592  // Only perform this checking if the mesh is not distributed. When
34593  // the mesh is distributed the polylines continuity is addressed
34594  // in the sort_polylines_helper() method
34595  if (!this->is_mesh_distributed())
34596 #endif
34597  {
34598  //Check whether the segments are continguous (first vertex of this
34599  //segment is equal to last vertex of previous segment).
34600  //If not, we should reverse the order of the current segment.
34601  //This check only applies for segments other than the first.
34602  //We only bother with this check, if we actually perform an update
34603  //of the polyline, i.e. if it's not only a check
34604  if( (p > 0) && !check_only )
34605  {
34606  //Final end point of previous line
34607  Vector<double> final_vertex_of_previous_segment;
34608  open_polyline_pt->polyline_pt(p-1)->
34609  final_vertex_coordinate(final_vertex_of_previous_segment);
34610 
34611  unsigned prev_seg_boundary_id =
34612  open_polyline_pt->curve_section_pt(p-1)->boundary_id();
34613 
34614  //Find the error between the final vertex of the previous
34615  //line and the first vertex of the current line
34616  double error = 0.0;
34617  for(unsigned i=0;i<2;i++)
34618  {
34619  const double dist =
34620  final_vertex_of_previous_segment[i] -
34621  (*vector_vertex_node.begin())[i];
34622  error += dist*dist;
34623  }
34624  error = sqrt(error);
34625 
34626  //If the error is bigger than the tolerance then
34627  //we probably need to reverse, but better check
34629  {
34630  //Find the error between the final vertex of the previous
34631  //line and the first vertex of the current line
34632  error = 0.0;
34633  for(unsigned i=0;i<2;i++)
34634  {
34635  const double dist =
34636  final_vertex_of_previous_segment[i] -
34637  (*--vector_vertex_node.end())[i];
34638  error += dist*dist;
34639  }
34640  error = sqrt(error);
34641 
34643  {
34644  // It could be possible that the first segment be reversed
34645  // and we did not notice it because this check does not
34646  // apply for the first segment. We can verify if the first
34647  // segment is reversed by using the vertex number 1
34648  if (p == 1)
34649  {
34650  // If no found it is possible that the previous polyline
34651  // be reversed Check for that case Initial point of
34652  // previous line
34653  Vector<double> initial_vertex_of_previous_segment;
34654  open_polyline_pt->polyline_pt(p-1)->
34655  initial_vertex_coordinate(initial_vertex_of_previous_segment);
34656 
34657  //Find the error between the initial vertex of the previous
34658  //line and the first vertex of the current line
34659  error = 0.0;
34660  for(unsigned i=0;i<2;i++)
34661  {
34662  const double dist =
34663  initial_vertex_of_previous_segment[i] -
34664  (*vector_vertex_node.begin())[i];
34665  error += dist*dist;
34666  }
34667  error = sqrt(error);
34668 
34669  //If the error is bigger than the tolerance then
34670  //we probably need to reverse, but better check
34672  {
34673  //Find the error between the final vertex of the previous
34674  //line and the first vertex of the current line
34675  error = 0.0;
34676  for(unsigned i=0;i<2;i++)
34677  {
34678  const double dist =
34679  initial_vertex_of_previous_segment[i] -
34680  (*--vector_vertex_node.end())[i];
34681  error += dist*dist;
34682  }
34683  error = sqrt(error);
34684 
34685  if(error >
34687  {
34688  std::ostringstream error_stream;
34689  error_stream
34690  <<"The distance between the first node of the current\n"
34691  <<"line segment (boundary " << bound
34692  <<") and either end of the previous line segment\n"
34693  <<"(boundary " << prev_seg_boundary_id << ") is bigger than "
34694  <<"the desired tolerance " <<
34696  <<"This suggests that the polylines defining the open "
34697  << "curve\n"
34698  <<"representation are not properly ordered.\n"
34699  <<"Fail on last vertex of polyline: ("
34700  << prev_seg_boundary_id
34701  <<") and\nfirst vertex of polyline (" << bound << ").\n"
34702  <<"This should have failed when first trying to construct\n"
34703  <<"the open curve.\n";
34704  throw OomphLibError(error_stream.str(),
34705  OOMPH_CURRENT_FUNCTION,
34706  OOMPH_EXCEPTION_LOCATION);
34707  }
34708  else // We have to reverse both
34709  {
34710  // First reverse the previous polyline
34711  open_polyline_pt->polyline_pt(p-1)->reverse();
34712  // Then reverse the current polyline
34713  std::reverse(vector_vertex_node.begin(),
34714  vector_vertex_node.end());
34715  }
34716  }
34717  else
34718  {
34719  // Reverse the previous polyline only
34720  open_polyline_pt->polyline_pt(p-1)->reverse();
34721  }
34722  } // if (p == 1)
34723  else
34724  {
34725  std::ostringstream error_stream;
34726  error_stream
34727  << "The distance between the first node of the current\n"
34728  << "line segment (boundary " << bound << ") and either end of "
34729  << "the previous line segment\n"
34730  << "(boundary "<<prev_seg_boundary_id<<") is bigger than the "
34731  << "desired tolerance " <<
34733  <<"This suggests that the polylines defining the polygonal\n"
34734  <<"representation are not properly ordered.\n"
34735  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
34736  << ") and\nfirst vertex of polyline ("<<bound<<").\n"
34737  << "This should have failed when first trying to construct the\n"
34738  << "polygon.\n";
34739  throw OomphLibError(error_stream.str(),
34740  OOMPH_CURRENT_FUNCTION,
34741  OOMPH_EXCEPTION_LOCATION);
34742  }
34743  }
34744  else
34745  {
34746  //Reverse the current vector to line up with the previous one
34747  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34748  }
34749 
34750  }
34751 
34752  } // if p > 0
34753 
34754  } // is mesh not distributed?
34755 
34756  if(!check_only)
34757  {
34758  // Now update the polyline according to the new vertices The new
34759  // one representation
34760  TriangleMeshPolyLine *tmp_polyline =
34761  new TriangleMeshPolyLine(vector_vertex_node, bound);
34762 
34763  // Create a temporal "curve section" version of the recently
34764  // created polyline
34765  TriangleMeshCurveSection *tmp_curve_section = tmp_polyline;
34766 
34767  // Copy the unrefinement and refinement information
34768  tmp_polyline->set_unrefinement_tolerance(
34769  unrefinement_tolerance);
34770  tmp_polyline->set_refinement_tolerance(
34771  refinement_tolerance);
34772 
34773  // Establish the maximum length constraint
34774  tmp_polyline->set_maximum_length(maximum_length);
34775 
34776  // Pass the connection information from the old polyline to the
34777  // new one
34778  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
34779  tmp_curve_section);
34780 
34781  std::set<TriangleMeshCurveSection*>::iterator it =
34782  this->Free_curve_section_pt.find(open_polyline_pt->curve_section_pt(p));
34783 
34784  bool delete_it_on_destructor = false;
34785 
34786  if (it!=this->Free_curve_section_pt.end())
34787  {
34788  // Free previous representation only if you created
34789  this->Free_curve_section_pt.erase(it);
34790  delete open_polyline_pt->curve_section_pt(p);
34791  delete_it_on_destructor = true;
34792  }
34793 
34794  // *****************************************************************
34795  // Copying the new representation
34796  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
34797 
34798  // Update the Boundary <--> PolyLine map
34799  this->Boundary_curve_section_pt[bound] =
34800  open_polyline_pt->curve_section_pt(p);
34801 
34802  if (delete_it_on_destructor)
34803  {
34804  this->Free_curve_section_pt.insert(
34805  open_polyline_pt->curve_section_pt(p));
34806  }
34807 
34808  } // if(!check_only)
34809 
34810  } // n_polylines
34811 
34812  // Cleanup (but only the elements -- the nodes still exist in
34813  // the bulk mesh!
34814  for(unsigned p=0;p<n_polyline;p++)
34815  {
34816  face_mesh_pt[p]->flush_node_storage();
34817  delete face_mesh_pt[p];
34818  }
34819 
34820  if(check_only)
34821  {
34822  // if we end up all the way down here, no update of the internal
34823  // boundaries is necessary (in case we only check)
34824  return false;
34825  }
34826  else
34827  {
34828  // if we not only check, but actually perform the update and end
34829  // up all the way down here then we indicate whether an update was
34830  // performed or not
34831  return (unrefinement_was_performed ||
34832  refinement_was_performed ||
34833  max_length_applied);
34834  }
34835 
34836  }
34837 
34838 //=========================================================================
34839 /// \short Helper function that performs the unrefinement process
34840 /// on the specified boundary by using the provided vertices
34841 /// representation. Optional boolean is used to run it as test only (if
34842 /// true is specified as input) in which case vertex coordinates aren't
34843 /// actually modified. Returned boolean indicates if polyline was (or
34844 /// would have been -- if called with check_only=false) changed.
34845 //=========================================================================
34846 template<class ELEMENT>
34848 unrefine_boundary(const unsigned &b,
34849  const unsigned &c,
34850  Vector<Vector<double> > &vector_bnd_vertices,
34851  double &unrefinement_tolerance,
34852  const bool &check_only)
34853  {
34854  // Store the vertices not allowed for deletion
34855  std::set<Vector<double> > no_delete_vertex;
34856 
34857  // Does the boundary receives connections?
34858  const bool boundary_receive_connections =
34859  this->boundary_connections(b, c, no_delete_vertex);
34860 
34861  // Boolean that indicates whether an actual update of the vertex
34862  // coordinates was performed or not
34863  bool unrefinement_was_performed=false;
34864 
34865  unsigned n_vertex = vector_bnd_vertices.size();
34866 
34867  // Initialise counter that indicates at which vertex we're currently
34868  // considering for deletion
34869  unsigned counter=1;
34870 
34871  // Loop over the nodes; start with the second one and increment by two
34872  // this way a "pack" of three nodes will be considered for calculation:
34873  // the middle-node (which is to be deleted or not) and the adjacent
34874  // nodes
34875  for(unsigned i=1;i<=n_vertex-2;i+=2)
34876  {
34877  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
34878  double a_x=vector_bnd_vertices[i-1][1];
34879  double a_y=vector_bnd_vertices[i-1][2];
34880  double b_x=vector_bnd_vertices[i][1];
34881  double b_y=vector_bnd_vertices[i][2];
34882  double c_x=vector_bnd_vertices[i+1][1];
34883  double c_y=vector_bnd_vertices[i+1][2];
34884 
34885  double a=b_x-a_x;
34886  double b=b_y-a_y;
34887  double c=c_x-a_x;
34888  double d=c_y-a_y;
34889 
34890  double e=a*(a_x+b_x)+b*(a_y+b_y);
34891  double f=c*(a_x+c_x)+d*(a_y+c_y);
34892 
34893  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
34894 
34895  bool do_it=false;
34896  if (std::fabs(g)<1.0e-14)
34897  {
34898  do_it=true;
34899  if(check_only) {return true;}
34900  }
34901  else
34902  {
34903  double p_x=(d*e-b*f)/g;
34904  double p_y=(a*f-c*e)/g;
34905 
34906  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
34907 
34908  double rhalfca_x=0.5*(a_x-c_x);
34909  double rhalfca_y=0.5*(a_y-c_y);
34910 
34911  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
34912 
34913  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
34914 
34915  // If sticky out bit divided by distance between end nodes
34916  // is less than tolerance the boundary is so flat that we
34917  // can safely kill the node
34918  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
34919  unrefinement_tolerance)
34920  {
34921  do_it=true;
34922  if(check_only) {return true;}
34923  }
34924  }
34925 
34926  // If the vertex was proposed for deletion check that it is
34927  // allowed for being deleted
34928  if (do_it && boundary_receive_connections)
34929  {
34930  // Is the vertex one of the non deletable vertices
34931  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
34932  it != no_delete_vertex.end(); it++)
34933  {
34934  // Compute the distance between the proposed node to delete
34935  // and the ones that should not be deleted
34936  const double x = (*it)[0];
34937  const double y = (*it)[1];
34938  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
34939  error = sqrt(error);
34940 
34942  {
34943  // Do not delete the vertex
34944  do_it = false;
34945  break;
34946  }
34947 
34948  }
34949 
34950  } // if (do_it && boundary_receive_connections)
34951 
34952  // Remove node?
34953  if (do_it)
34954  {
34955  vector_bnd_vertices[i].resize(0);
34956  }
34957 
34958  // Increase the counter, that indicates the number of the
34959  // next middle node
34960  counter+=2;
34961  }
34962 
34963  // coming out of here the value of counter is the index of the
34964  // last node on the polyline counter=n_vertex-1 (in case of an
34965  // even number of nodes) or counter has the value of the number
34966  // of nodes on the polyline counter=n_vertex (in case of an odd
34967  // number of nodes
34968 
34969  // Special treatment for the end of the polyline:
34970  // If the number of nodes is even, then the previous loop stopped
34971  // at the last but second node, i.e. the current value of counter
34972  // is the index of the last node. If that's the case, the last but
34973  // one node needs to be treated separately
34974  if( (counter)==(n_vertex-1) )
34975  {
34976  // Set the last but one node as middle node
34977  unsigned i=vector_bnd_vertices.size()-2;
34978 
34979  // Index of the current! last but second node (considering any
34980  // previous deletion)
34981  unsigned n=0;
34982 
34983  if(vector_bnd_vertices[counter-2].size()!=0)
34984  {
34985  // if the initial last but second node does still exist then
34986  // this one is obviously also the current last but second one
34987  n=counter-2;
34988  }
34989  else
34990  {
34991  // if the initial last but second node was deleted then the
34992  // initial last but third node is the current last but second
34993  // node
34994  n=counter-3;
34995  }
34996 
34997  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
34998  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
34999  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
35000 
35001  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35002  double a_x=vector_bnd_vertices[n][1];
35003  double a_y=vector_bnd_vertices[n][2];
35004  double b_x=vector_bnd_vertices[i][1];
35005  double b_y=vector_bnd_vertices[i][2];
35006  double c_x=vector_bnd_vertices[i+1][1];
35007  double c_y=vector_bnd_vertices[i+1][2];
35008 
35009  double a=b_x-a_x;
35010  double b=b_y-a_y;
35011  double c=c_x-a_x;
35012  double d=c_y-a_y;
35013 
35014  double e=a*(a_x+b_x)+b*(a_y+b_y);
35015  double f=c*(a_x+c_x)+d*(a_y+c_y);
35016 
35017  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
35018 
35019  bool do_it=false;
35020  if (std::fabs(g)<1.0e-14)
35021  {
35022  do_it=true;
35023  if(check_only) {return true;}
35024  }
35025  else
35026  {
35027  double p_x=(d*e-b*f)/g;
35028  double p_y=(a*f-c*e)/g;
35029 
35030  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
35031 
35032  double rhalfca_x=0.5*(a_x-c_x);
35033  double rhalfca_y=0.5*(a_y-c_y);
35034 
35035  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
35036 
35037  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
35038 
35039  // If sticky out bit divided by distance between end nodes
35040  // is less than tolerance the boundary is so flat that we
35041  // can safely kill the node
35042  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
35043  unrefinement_tolerance)
35044  {
35045  do_it=true;
35046  if(check_only) {return true;}
35047  }
35048  }
35049 
35050  // If the vertex was proposed for deletion check that it is
35051  // allowed for being deleted
35052  if (do_it && boundary_receive_connections)
35053  {
35054  // Is the vertex one of the non deletable vertices
35055  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
35056  it != no_delete_vertex.end(); it++)
35057  {
35058  // Compute the distance between the proposed node to delete
35059  // and the ones that should not be deleted
35060  const double x = (*it)[0];
35061  const double y = (*it)[1];
35062  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
35063  error = sqrt(error);
35064 
35065  if(error <
35067  {
35068  // Do not delete the vertex
35069  do_it = false;
35070  break;
35071  }
35072 
35073  }
35074 
35075  } // if (do_it && boundary_receive_connections)
35076 
35077  // Remove node?
35078  if (do_it)
35079  {
35080  vector_bnd_vertices[i].resize(0);
35081  }
35082  }
35083 
35084  // Create another vector, which will only contain entries of
35085  // nodes that still exist
35086  Vector<Vector<double> > compact_vector;
35087  compact_vector.reserve(n_vertex);
35088  for (unsigned i=0;i<n_vertex;i++)
35089  {
35090  // If the entry was not deleted include it in the new vector
35091  if (vector_bnd_vertices[i].size()!=0)
35092  {
35093  compact_vector.push_back(vector_bnd_vertices[i]);
35094  }
35095  }
35096 
35097  /// Get the size of the vector that now includes all remaining nodes
35098  n_vertex =compact_vector.size();
35099 
35100  // If the size of the vector containing the remaining nodes is
35101  // different from the size of the vector before the unrefinement
35102  // routine (with the original nodes)
35103  // then the polyline was obviously updated
35104  if( n_vertex != vector_bnd_vertices.size() )
35105  {
35106  unrefinement_was_performed=true;
35107  }
35108 
35109  /// Copy back
35110  vector_bnd_vertices.resize(n_vertex);
35111  for(unsigned i=0;i<n_vertex;i++)
35112  {
35113  vector_bnd_vertices[i].resize(3);
35114  vector_bnd_vertices[i][0]=compact_vector[i][0];
35115  vector_bnd_vertices[i][1]=compact_vector[i][1];
35116  vector_bnd_vertices[i][2]=compact_vector[i][2];
35117  }
35118 
35119  return unrefinement_was_performed;
35120 
35121  }
35122 
35123 //=========================================================================
35124 /// \short Helper function that performs the refinement process
35125 /// on the specified boundary by using the provided vertices
35126 /// representation. Optional boolean is used to run it as test only (if
35127 /// true is specified as input) in which case vertex coordinates aren't
35128 /// actually modified. Returned boolean indicates if polyline was (or
35129 /// would have been -- if called with check_only=false) changed.
35130 //=========================================================================
35131 template<class ELEMENT>
35133 refine_boundary(Mesh* face_mesh_pt,
35134  Vector<Vector<double> > &vector_bnd_vertices,
35135  double &refinement_tolerance,
35136  const bool &check_only)
35137  {
35138  // Boolean that indicates whether an actual update of the vertex
35139  // coordinates was performed or not
35140  bool refinement_was_performed=false;
35141 
35142  // Create a geometric object from the mesh to represent
35143  //the curvilinear boundary
35144  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35145 
35146  // Get the total number of current vertices
35147  unsigned n_vertex=vector_bnd_vertices.size();
35148 
35149  // Create a new (temporary) vector for the nodes, so
35150  // that new nodes can be stored
35151  Vector<Vector<double> > extended_vector;
35152 
35153  // Reserve memory space for twice the number of already
35154  // existing nodes (worst case)
35155  extended_vector.reserve(2*n_vertex);
35156 
35157  // Loop over the nodes until the last but one node
35158  for(unsigned inod=0;inod<n_vertex-1;inod++)
35159  {
35160  // Get local coordinate of "left" node
35161  double zeta_left=vector_bnd_vertices[inod][0];
35162 
35163  // Get position vector of "left" node
35164  Vector<double> R_left(2);
35165  for(unsigned i=0;i<2;i++)
35166  {
35167  R_left[i]=vector_bnd_vertices[inod][i+1];
35168  }
35169 
35170  // Get local coordinate of "right" node
35171  double zeta_right=vector_bnd_vertices[inod+1][0];
35172 
35173  // Get position vector of "right" node
35174  Vector<double> R_right(2);
35175  for(unsigned i=0;i<2;i++)
35176  {
35177  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35178  }
35179 
35180  // Get the boundary coordinate of the midpoint
35181  Vector<double> zeta_mid(1);
35182  zeta_mid[0]=0.5*(zeta_left+zeta_right);
35183 
35184  // Get the position vector of the midpoint on the
35185  // curvilinear boundary
35186  Vector<double> R_mid(2);
35187  mesh_geom_obj_pt->position(zeta_mid,R_mid);
35188 
35189  // Get the position vector of the midpoint on the straight
35190  // line connecting "left" and "right" node
35191  Vector<double> R_mid_polygon(2);
35192  for(unsigned i=0;i<2;i++)
35193  {
35194  R_mid_polygon[i]=0.5*(R_right[i]+R_left[i]);
35195  }
35196 
35197  // Calculate the distance between the midpoint on the curvilinear
35198  // boundary and the midpoint on the straight line
35199  double distance=sqrt((R_mid[0]-R_mid_polygon[0])*
35200  (R_mid[0]-R_mid_polygon[0])+
35201  (R_mid[1]-R_mid_polygon[1])*
35202  (R_mid[1]-R_mid_polygon[1]));
35203 
35204  // Calculating the length of the straight line
35205  double length=sqrt((R_right[0]-R_left[0])*(R_right[0]-R_left[0])+
35206  (R_right[1]-R_left[1])*(R_right[1]-R_left[1]));
35207 
35208  // If the ratio of distance between the midpoints to the length
35209  // of the straight line is larger than the tolerance
35210  // specified for the criterion when points can be deleted,
35211  // create a new node and add it to the (temporary) vector
35212  if((distance/length) > refinement_tolerance)
35213  {
35214 
35215  if(check_only)
35216  {
35217  // Delete the allocated memory for the geometric object
35218  // that represents the curvilinear boundary
35219  delete mesh_geom_obj_pt;
35220  return true;
35221  }
35222 
35223  Vector<double> new_node(3);
35224  new_node[0]=zeta_mid[0];
35225  new_node[1]=R_mid[0];
35226  new_node[2]=R_mid[1];
35227 
35228  // Include the "left" node in the new "temporary" vector
35229  extended_vector.push_back(vector_bnd_vertices[inod]);
35230 
35231  // Include the new node as well
35232  extended_vector.push_back(new_node);
35233 
35234  }
35235  else
35236  {
35237  // Include the "left" node in the new "temporary" vector
35238  // and move on to the next node
35239  extended_vector.push_back(vector_bnd_vertices[inod]);
35240  }
35241  } // end of loop over nodes
35242 
35243  // Add the last node to the vector
35244  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35245 
35246  /// Get the size of the vector that now includes all added nodes
35247  n_vertex=extended_vector.size();
35248 
35249  // If the size of the vector including the added nodes is
35250  // different from the size of the vector before the refinement
35251  // routine then the polyline was obviously updated
35252  if( n_vertex != vector_bnd_vertices.size() )
35253  {
35254  refinement_was_performed=true;
35255  }
35256 
35257  // Copy across
35258  vector_bnd_vertices.resize(n_vertex);
35259  for(unsigned i=0;i<n_vertex;i++)
35260  {
35261  vector_bnd_vertices[i].resize(3);
35262  vector_bnd_vertices[i][0]=extended_vector[i][0];
35263  vector_bnd_vertices[i][1]=extended_vector[i][1];
35264  vector_bnd_vertices[i][2]=extended_vector[i][2];
35265  }
35266 
35267  // Delete the allocated memory for the geometric object
35268  // that represents the curvilinear boundary
35269  delete mesh_geom_obj_pt;
35270 
35271  return refinement_was_performed;
35272 
35273  }
35274 
35275  //=========================================================================
35276  // \short Helper function that applies the maximum length constraint
35277  // when it was specified. This will increase the number of points in
35278  // the current curve section in case that any segment on it does not
35279  // fulfils the requirement
35280  //=========================================================================
35281  template<class ELEMENT>
35284  Vector<Vector<double> > &vector_bnd_vertices,
35285  double &max_length_constraint)
35286  {
35287  // Boolean that indicates whether an actual update of the vertex
35288  // coordinates was performed or not
35289  bool max_length_applied=false;
35290 
35291  // Create a geometric object from the mesh to represent
35292  //the curvilinear boundary
35293  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35294 
35295  // Get the total number of current vertices
35296  unsigned n_vertex=vector_bnd_vertices.size();
35297 
35298  // Create a new (temporary) vector for the nodes, so
35299  // that new nodes can be stored
35300  Vector<Vector<double> > extended_vector;
35301 
35302  // Loop over the nodes until the last but one node
35303  for(unsigned inod=0;inod<n_vertex-1;inod++)
35304  {
35305  // Get local coordinate of "left" node
35306  double zeta_left=vector_bnd_vertices[inod][0];
35307 
35308  // Get position vector of "left" node
35309  Vector<double> R_left(2);
35310  for(unsigned i=0;i<2;i++)
35311  {
35312  R_left[i]=vector_bnd_vertices[inod][i+1];
35313  }
35314 
35315  // Get local coordinate of "right" node
35316  double zeta_right=vector_bnd_vertices[inod+1][0];
35317 
35318  // Get position vector of "right" node
35319  Vector<double> R_right(2);
35320  for(unsigned i=0;i<2;i++)
35321  {
35322  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35323  }
35324 
35325  // Include the "left" node in the new "temporary" vector
35326  extended_vector.push_back(vector_bnd_vertices[inod]);
35327 
35328  // Check whether the current distance between the left and right node
35329  // is longer than the specified constraint or not
35330  double length=std::fabs(zeta_right-zeta_left);
35331 
35332  // Do we need to introduce new nodes?
35333  if (length > max_length_constraint)
35334  {
35335  double n_pts = length/max_length_constraint;
35336  // We only want the integer part
35337  unsigned n_points = static_cast<unsigned>(n_pts);
35338  double zeta_increment = (zeta_right-zeta_left)/((double)n_points+1);
35339 
35340  Vector<double> zeta(1);
35341  // Create the n_points+1 points inside the segment
35342  for(unsigned s=1;s<n_points+1;s++)
35343  {
35344  // Get the coordinates
35345  zeta[0]= zeta_left + zeta_increment*double(s);
35346  Vector<double> vertex(2);
35347  mesh_geom_obj_pt->position(zeta, vertex);
35348 
35349  // Create the new node
35350  Vector<double> new_node(3);
35351  new_node[0]=zeta[0];
35352  new_node[1]=vertex[0];
35353  new_node[2]=vertex[1];
35354 
35355  // Include the new node
35356  extended_vector.push_back(new_node);
35357  }
35358  }
35359  }
35360 
35361  // Add the last node to the vector
35362  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35363 
35364  /// Get the size of the vector that now includes all added nodes
35365  n_vertex=extended_vector.size();
35366 
35367  // If the size of the vector including the added nodes is
35368  // different from the size of the vector before applying the maximum length
35369  // constraint then the polyline was obviously updated
35370  if( n_vertex != vector_bnd_vertices.size() )
35371  {
35372  max_length_applied = true;
35373  }
35374 
35375  // Copy across
35376  vector_bnd_vertices.resize(n_vertex);
35377  for(unsigned i=0;i<n_vertex;i++)
35378  {
35379  vector_bnd_vertices[i].resize(3);
35380  vector_bnd_vertices[i][0]=extended_vector[i][0];
35381  vector_bnd_vertices[i][1]=extended_vector[i][1];
35382  vector_bnd_vertices[i][2]=extended_vector[i][2];
35383  }
35384 
35385  // Delete the allocated memory for the geometric object
35386  // that represents the curvilinear boundary
35387  delete mesh_geom_obj_pt;
35388 
35389  return max_length_applied;
35390 
35391  }
35392 
35393 //=========================================================================
35394 /// \short Helper function
35395 /// Creates an unsorted face mesh representation from the specified
35396 /// boundary id. It means that the elements are not sorted along the
35397 /// boundary
35398 //=========================================================================
35399 template<class ELEMENT>
35402  const unsigned &boundary_id,
35403  Mesh* face_mesh_pt)
35404  {
35405  // Create a face mesh adjacent to specified boundary.
35406  // The face mesh consists of FaceElements that may also be
35407  // interpreted as GeomObjects
35408 
35409  // Build the face mesh
35410  this->template build_face_mesh<ELEMENT,FaceElementAsGeomObject>
35411  (boundary_id,face_mesh_pt);
35412 
35413  // Find the total number of added elements
35414  unsigned n_element = face_mesh_pt->nelement();
35415  // Loop over the elements
35416  for(unsigned e=0;e<n_element;e++)
35417  {
35418 
35419  //Cast the element pointer to the correct thing!
35421  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
35422  (face_mesh_pt->element_pt(e));
35423 
35424  // Set bulk boundary number
35425  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35426 
35427  }
35428 
35429  }
35430 
35431 //=========================================================================
35432 /// \short Helper function
35433 /// Creates a sorted face mesh representation of the specified PolyLine
35434 /// It means that the elements are sorted along the boundary
35435 //=========================================================================
35436 template<class ELEMENT>
35439  const unsigned &boundary_id,
35440  Mesh* face_mesh_pt,
35441  std::map<FiniteElement*, bool> &is_inverted,
35442  bool &inverted_face_mesh)
35443  {
35444  Mesh *tmp_unsorted_face_mesh_pt = new Mesh();
35445 
35446  // First step we get the unsorted version of the face mesh
35447  create_unsorted_face_mesh_representation(
35448  boundary_id, tmp_unsorted_face_mesh_pt);
35449 
35450  // Once with the unsorted version of the face mesh
35451  // only left to sort it out!!!
35452 
35453  // Put all face elements in order
35454  //-------------------------------
35455 
35456  // Put first element into ordered list
35457  // Temporal list for sorting the elements
35458  std::list<FiniteElement*> sorted_el_pt;
35459  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35460  sorted_el_pt.push_back(el_pt);
35461 
35462  // Number of nodes
35463  unsigned nnod=el_pt->nnode();
35464 
35465  // Count elements that have been done
35466  unsigned count_done=0;
35467 
35468  // How many face elements are there?
35469  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35470 
35471  // Keep track of who's done
35472  std::map<FiniteElement*,bool> done_el;
35473 
35474  is_inverted.clear();
35475 
35476  // Fit in the other elements in at most nel^2 loops
35477  for (unsigned ee=1;ee<n_face_element;ee++)
35478  {
35479  // Loop over all elements to check if they fit to the right
35480  // or the left of the current one
35481  for (unsigned e=1;e<n_face_element;e++)
35482  {
35483  // Candidate element
35484  el_pt=tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35485 
35486  // Is it done yet?
35487  if (!done_el[el_pt])
35488  {
35489  // Left and rightmost elements
35490  FiniteElement* first_el_pt=(*sorted_el_pt.begin());
35491  std::list<FiniteElement*>::iterator it=sorted_el_pt.end();
35492  it--;
35493  FiniteElement* last_el_pt=*it;
35494 
35495  // Left and rightmost nodes
35496  Node* left_node_pt=first_el_pt->node_pt(0);
35497  if (is_inverted[first_el_pt])
35498  {
35499  left_node_pt=first_el_pt->node_pt(nnod-1);
35500  }
35501  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35502  if (is_inverted[last_el_pt])
35503  {
35504  right_node_pt=last_el_pt->node_pt(0);
35505  }
35506 
35507  // New element fits at the left of first element and is not inverted
35508  if (left_node_pt==el_pt->node_pt(nnod-1))
35509  {
35510  sorted_el_pt.push_front(el_pt);
35511  done_el[el_pt]=true;
35512  count_done++;
35513  is_inverted[el_pt]=false;
35514  }
35515  // New element fits at the left of first element and is inverted
35516 
35517  else if (left_node_pt==el_pt->node_pt(0))
35518  {
35519  sorted_el_pt.push_front(el_pt);
35520  done_el[el_pt]=true;
35521  count_done++;
35522  is_inverted[el_pt]=true;
35523  }
35524  // New element fits on the right of last element and is not inverted
35525 
35526  else if(right_node_pt==el_pt->node_pt(0))
35527  {
35528  sorted_el_pt.push_back(el_pt);
35529  done_el[el_pt]=true;
35530  count_done++;
35531  is_inverted[el_pt]=false;
35532  }
35533  // New element fits on the right of last element and is inverted
35534 
35535  else if (right_node_pt==el_pt->node_pt(nnod-1))
35536  {
35537  sorted_el_pt.push_back(el_pt);
35538  done_el[el_pt]=true;
35539  count_done++;
35540  is_inverted[el_pt]=true;
35541  }
35542 
35543  if (done_el[el_pt])
35544  {
35545  break;
35546  }
35547  }
35548  }
35549  }
35550 
35551  // Are we done?
35552  if (count_done!=(n_face_element-1))
35553  {
35554  std::ostringstream error_message;
35555  error_message
35556  << "When ordering FaceElements on "
35557  << "boundary " << boundary_id << " only managed to order \n" << count_done
35558  << " of " << n_face_element << " face elements.\n"
35559  << std::endl;
35560  throw OomphLibError(
35561  error_message.str(),
35562  OOMPH_CURRENT_FUNCTION,
35563  OOMPH_EXCEPTION_LOCATION);
35564  }
35565 
35566  // Now make a mesh that contains the FaceElements in order
35567  // Remember that we currently have a list, not a mesh of sorted elements
35568 
35569  // Fill it
35570  for (std::list<FiniteElement*>::iterator it=sorted_el_pt.begin();
35571  it!=sorted_el_pt.end();it++)
35572  {
35573  // Get element
35574  FiniteElement* el_pt=*it;
35575 
35576  // add this face element to the order original mesh
35577  face_mesh_pt->add_element_pt(el_pt);
35578  }
35579 
35580  // Verify if face mesh representation is not inverted according to the
35581  // polyline specified by the user, it means that the initial and the
35582  // final vertex does really correspond to the first and last vertex
35583  // respectively, if not, state that the face mesh representation is
35584  // inverted
35585 
35586  // Get the associated polyline representation to the boundary
35587  TriangleMeshPolyLine *bnd_polyline =
35588  this->Boundary_curve_section_pt[boundary_id];
35589 
35590  // Get the really first vertex
35591  Vector<double> first_vertex =
35592  bnd_polyline->vertex_coordinate(0);
35593 
35594  // Now get the first node based on the face mesh representation
35595  // First get access to the first element
35596  FiniteElement* first_el_pt =
35597  face_mesh_pt->finite_element_pt(0);
35598 
35599  // Now get access to the first node
35600  unsigned n_node = first_el_pt->nnode();
35601  // Get the very first node (taking into account if it is
35602  // inverted or not!!)
35603  Node* first_node_pt = first_el_pt->node_pt(0);
35604  if (is_inverted[first_el_pt])
35605  {
35606  first_node_pt = first_el_pt->node_pt(n_node-1);
35607  }
35608 
35609  double error = (first_node_pt->x(0) - first_vertex[0])*
35610  (first_node_pt->x(0) - first_vertex[0]) +
35611  (first_node_pt->x(1) - first_vertex[1])*
35612  (first_node_pt->x(1) - first_vertex[1]);
35613 
35614  error = sqrt(error);
35615 
35616  if(error <
35618  {
35619  inverted_face_mesh = false;
35620  }
35621  else
35622  {
35623  inverted_face_mesh = true;
35624  }
35625 
35626  }
35627 
35628 //=========================================================================
35629 /// Helper function to construct face mesh representation of all polylines,
35630 /// possibly with segments re-distributed between polylines
35631 /// to maintain an approximately even sub-division of the polygon
35632 //=========================================================================
35633 template<class ELEMENT>
35636  Vector<Mesh*>& face_mesh_pt)
35637  {
35638  // Number of polylines
35639  unsigned n_polyline = polygon_pt->npolyline();
35640  face_mesh_pt.resize(n_polyline);
35641 
35642  // Are we eligible for re-distributing polyline segments between
35643  // polylines? We're not if any of the boundaries are associated
35644  // with a GeomObject because we're then tied to the start and
35645  // end coordinates along it.
35646  bool eligible_for_segment_redistribution=true;
35647 
35648  // Loop over constituent polylines
35649  for(unsigned p=0;p<n_polyline;p++)
35650  {
35651 
35652  //Get the boundary id of the polyline
35653  unsigned bound =
35654  polygon_pt->polyline_pt(p)->boundary_id();
35655 
35656  //If the boundary has a geometric object representation then
35657  //we can't redistribute
35658  GeomObject* const geom_object_pt =
35659  this->boundary_geom_object_pt(bound);
35660  if(geom_object_pt!=0)
35661  {
35662  eligible_for_segment_redistribution=false;
35663  }
35664 
35665  face_mesh_pt[p] = new Mesh();
35666  create_unsorted_face_mesh_representation(
35667  bound, face_mesh_pt[p]);
35668 
35669  }
35670 
35672  {
35673  return;
35674  }
35675 
35676  //If there is more than one region we have to think... Die for now.
35677  if(this->nregion() > 1)
35678  {
35679  std::ostringstream warn_message;
35680  warn_message
35681  << "Can't currently re-distribute segments between polylines if there\n"
35682  << "are multiple regions; returning..." << std::endl;
35683  OomphLibWarning(warn_message.str(),
35684  "RefineableTriangleMesh::get_face_mesh_representation()",
35685  OOMPH_EXCEPTION_LOCATION);
35686  return;
35687  }
35688 
35689  // Redistribution overruled
35690  if (!eligible_for_segment_redistribution)
35691  {
35692  std::ostringstream warn_message;
35693  warn_message
35694  << "Over-ruling re-distribution of segments between polylines\n"
35695  << "because at least one boundary is associated with a GeomObject."
35696  << "Returning..." << std::endl;
35697  OomphLibWarning(warn_message.str(),
35698  "RefineableTriangleMesh::get_face_mesh_representation()",
35699  OOMPH_EXCEPTION_LOCATION);
35700  return;
35701  }
35702 
35703  // Create a vector for ordered face mesh
35704  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35705 
35706  // Storage for the total arclength of polygon
35707  double s_total=0.0;
35708 
35709  // Storage for first and last nodes on polylines so we can figure
35710  // out if they are inverted relative to each other
35711  Vector<Node*> first_polyline_node_pt(n_polyline);
35712  Vector<Node*> last_polyline_node_pt(n_polyline);
35713  std::vector<bool> is_reversed(n_polyline,false);
35714 
35715  // Loop over constituent polylines
35716  for(unsigned p=0;p<n_polyline;p++)
35717  {
35718 
35719  // Put all face elements in order
35720  //-------------------------------
35721 
35722  // Put first element into ordered list
35723  std::list<FiniteElement*> ordered_el_pt;
35724  FiniteElement* el_pt=face_mesh_pt[p]->finite_element_pt(0);
35725  ordered_el_pt.push_back(el_pt);
35726 
35727  // Number of nodes
35728  unsigned nnod=el_pt->nnode();
35729 
35730  // Default for first and last node on polyline
35731  first_polyline_node_pt[p]=el_pt->node_pt(0);
35732  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35733 
35734  // Count elements that have been done
35735  unsigned count_done=0;
35736 
35737  // How many face elements are there?
35738  unsigned n_face_element = face_mesh_pt[p]->nelement();
35739 
35740  //Get the boundary id of the polyline
35741  unsigned bound =
35742  polygon_pt->polyline_pt(p)->boundary_id();
35743 
35744  // Keep track of who's done
35745  std::map<FiniteElement*,bool> done_el;
35746 
35747  // Keep track of which element is inverted
35748  std::map<FiniteElement*,bool> is_inverted;
35749 
35750  // Fit in the other elements in at most nel^2 loops
35751  for (unsigned ee=1;ee<n_face_element;ee++)
35752  {
35753  // Loop over all elements to check if they fit to the right
35754  // or the left of the current one
35755  for (unsigned e=1;e<n_face_element;e++)
35756  {
35757  // Candidate element
35758  el_pt=face_mesh_pt[p]->finite_element_pt(e);
35759 
35760  // Is it done yet?
35761  if (!done_el[el_pt])
35762  {
35763  // Left and rightmost elements
35764  FiniteElement* first_el_pt=(*ordered_el_pt.begin());
35765  std::list<FiniteElement*>::iterator it=ordered_el_pt.end();
35766  it--;
35767  FiniteElement* last_el_pt=*it;
35768 
35769  // Left and rightmost nodes
35770  Node* left_node_pt=first_el_pt->node_pt(0);
35771  if (is_inverted[first_el_pt])
35772  {
35773  left_node_pt=first_el_pt->node_pt(nnod-1);
35774  }
35775  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35776  if (is_inverted[last_el_pt])
35777  {
35778  right_node_pt=last_el_pt->node_pt(0);
35779  }
35780 
35781  // New element fits at the left of first element and is not inverted
35782  if (left_node_pt==el_pt->node_pt(nnod-1))
35783  {
35784  ordered_el_pt.push_front(el_pt);
35785  done_el[el_pt]=true;
35786  count_done++;
35787  is_inverted[el_pt]=false;
35788  first_polyline_node_pt[p]=el_pt->node_pt(0);
35789  }
35790  // New element fits at the left of first element and is inverted
35791 
35792  else if (left_node_pt==el_pt->node_pt(0))
35793  {
35794  ordered_el_pt.push_front(el_pt);
35795  done_el[el_pt]=true;
35796  count_done++;
35797  is_inverted[el_pt]=true;
35798  first_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35799  }
35800  // New element fits on the right of last element and is not inverted
35801 
35802  else if(right_node_pt==el_pt->node_pt(0))
35803  {
35804  ordered_el_pt.push_back(el_pt);
35805  done_el[el_pt]=true;
35806  count_done++;
35807  is_inverted[el_pt]=false;
35808  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35809  }
35810  // New element fits on the right of last element and is inverted
35811 
35812  else if (right_node_pt==el_pt->node_pt(nnod-1))
35813  {
35814  ordered_el_pt.push_back(el_pt);
35815  done_el[el_pt]=true;
35816  count_done++;
35817  is_inverted[el_pt]=true;
35818  last_polyline_node_pt[p]=el_pt->node_pt(0);
35819  }
35820 
35821  if (done_el[el_pt])
35822  {
35823  break;
35824  }
35825  }
35826  }
35827  }
35828 
35829  // Are we done?
35830  if (count_done!=(n_face_element-1))
35831  {
35832  std::ostringstream error_message;
35833  error_message
35834  << "When ordering FaceElements on "
35835  << "boundary " << bound << " only managed to order \n" << count_done
35836  << " of " << n_face_element << " face elements.\n"
35837  << std::endl;
35838  throw OomphLibError(
35839  error_message.str(),
35840  OOMPH_CURRENT_FUNCTION,
35841  OOMPH_EXCEPTION_LOCATION);
35842  }
35843 
35844  // Now make a mesh that contains the FaceElements in order
35845  ordered_face_mesh_pt[p] = new Mesh;
35846 
35847  // Fill it
35848  for (std::list<FiniteElement*>::iterator it=ordered_el_pt.begin();
35849  it!=ordered_el_pt.end();it++)
35850  {
35851  // Get element
35852  FiniteElement* el_pt=*it;
35853 
35854  // add this face element to the order original mesh
35855  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
35856  }
35857 
35858  //Get the arclength along the polygon
35859  for(unsigned e=0;e<n_face_element;++e)
35860  {
35861  FiniteElement* el_pt=ordered_face_mesh_pt[p]->finite_element_pt(e);
35862  unsigned n_node=el_pt->nnode();
35863  double element_length_squared=0.0;
35864  for(unsigned i=0;i<2;i++)
35865  {
35866  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
35867  el_pt->node_pt(0)->x(i),2);
35868  }
35869 
35870  // Determine element length
35871  double element_length=sqrt(element_length_squared);
35872 
35873  // Add this length to the total arclength
35874  s_total += element_length;
35875  }
35876 
35877  // Empty the original meshes
35878  face_mesh_pt[p]->flush_element_and_node_storage();
35879  }
35880 
35881  // Is first one reversed?
35882  if ((last_polyline_node_pt[0]==first_polyline_node_pt[1])||
35883  (last_polyline_node_pt[0]==last_polyline_node_pt[1]))
35884  {
35885  is_reversed[0]=false;
35886  }
35887  else if ((first_polyline_node_pt[0]==first_polyline_node_pt[1])||
35888  (first_polyline_node_pt[0]==last_polyline_node_pt[1]))
35889  {
35890  is_reversed[0]=true;
35891  }
35892 
35893  // Reorder the face meshes so that they are contiguous
35894  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
35895  std::vector<bool> mesh_done(n_polyline,false);
35896  Vector<unsigned> old_polyline_number(n_polyline);
35897 
35898  // Initial entry
35899  tmp_face_mesh_pt[0]=ordered_face_mesh_pt[0];
35900  unsigned current=0;
35901  old_polyline_number[0]=0;
35902  unsigned count_found=0;
35903 
35904  // Fill in the next entries
35905  for(unsigned p=1;p<n_polyline;p++)
35906  {
35907  Node* end_node_pt=last_polyline_node_pt[current];
35908  if (is_reversed[current])
35909  {
35910  end_node_pt=first_polyline_node_pt[current];
35911  }
35912 
35913  // Loop over all remaining face meshes to see which one fits
35914  for(unsigned pp=1;pp<n_polyline;pp++)
35915  {
35916  if (!mesh_done[pp])
35917  {
35918  // Current one is not reversed, candidate is not reversed
35919  if ((!is_reversed[current])&&
35920  (end_node_pt==first_polyline_node_pt[pp]))
35921  {
35922  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35923  mesh_done[pp]=true;
35924  is_reversed[pp]=false;
35925  old_polyline_number[p]=pp;
35926  current=pp;
35927  count_found++;
35928  break;
35929  }
35930  // Current one is not reversed, candidate is reversed
35931 
35932  else if ((!is_reversed[current])&&
35933  (end_node_pt==last_polyline_node_pt[pp]))
35934  {
35935  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35936  mesh_done[pp]=true;
35937  is_reversed[pp]=true;
35938  old_polyline_number[p]=pp;
35939  current=pp;
35940  count_found++;
35941  break;
35942  }
35943  // Current one is reversed, candidate is not reversed
35944 
35945  else if ((is_reversed[current])&&
35946  (end_node_pt==first_polyline_node_pt[pp]))
35947  {
35948  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35949  mesh_done[pp]=true;
35950  is_reversed[pp]=false;
35951  old_polyline_number[p]=pp;
35952  current=pp;
35953  count_found++;
35954  break;
35955  }
35956  // Current one is reversed, candidate is reversed
35957 
35958  else if ((is_reversed[current])&&
35959  (end_node_pt==last_polyline_node_pt[pp]))
35960  {
35961  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35962  mesh_done[pp]=true;
35963  is_reversed[pp]=true;
35964  old_polyline_number[p]=pp;
35965  current=pp;
35966  count_found++;
35967  break;
35968  }
35969  }
35970  }
35971  }
35972 
35973 #ifdef PARANOID
35974  if (count_found!=n_polyline-1)
35975  {
35976  std::ostringstream error_message;
35977  error_message << "Only found " << count_found
35978  << " out of " << n_polyline-1
35979  << " polylines to be fitted in.\n";
35980  throw OomphLibError(
35981  error_message.str(),
35982  OOMPH_CURRENT_FUNCTION,
35983  OOMPH_EXCEPTION_LOCATION);
35984  }
35985 #endif
35986 
35987  // Now overwrite the re-ordered data
35988  for (unsigned i=0;i<n_polyline;i++)
35989  {
35990  ordered_face_mesh_pt[i]=tmp_face_mesh_pt[i];
35991  }
35992 
35993  // Now do an approximate equidistribution of polylines
35994  //----------------------------------------------------
35995  double s=0.0;
35996  unsigned new_face_id=0;
35997 
35998  // Matrix map to indicate if node must not be removed from specified
35999  // boundary (!=0) or not (=0). Initialises itself to zero
36000  std::map<Node*,std::map<unsigned,unsigned> >
36001  node_must_not_be_removed_from_boundary_flag;
36002 
36003  // Loop over the old face mesh
36004  for(unsigned p=0;p<n_polyline;p++)
36005  {
36006  // Loop over the face elements
36007  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36008  for (unsigned e=0;e<n_face_element;e++)
36009  {
36010  unsigned el_number=e;
36011  if (is_reversed[p])
36012  {
36013  el_number=n_face_element-e-1;
36014  }
36015 
36016  FiniteElement* el_pt=
36017  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36018  unsigned n_node = el_pt->nnode();
36019 
36020  // Determine element length
36021  double element_length_squared=0.0;
36022  for(unsigned i=0;i<2;i++)
36023  {
36024  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
36025  el_pt->node_pt(0)->x(i),2);
36026  }
36027  double element_length=sqrt(element_length_squared);
36028 
36029  // Add this length to the total arclength
36030  s += element_length;
36031 
36032  // Check if the current 'arclength' is less than the
36033  // whole 'arclength' divided by the number of polylines
36034  if(s < s_total/double(n_polyline)+1e-6)
36035  {
36036  // If so add this face element to the new face mesh
36037  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36038 
36039  unsigned bound_old =
36040  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36041 
36042  unsigned bound_new =
36043  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36044 
36045  // Loop over the nodes in the element
36046  for(unsigned i=0;i<n_node;i++)
36047  {
36048  // Get the pointer to the node
36049  Node* nod_pt=el_pt->node_pt(i);
36050 
36051  // If the two boundary id's are different, the face element's nodes
36052  // have to be added to the new boundary
36053  if(bound_new != bound_old)
36054  {
36055  // Add it to the new boundary
36056  add_boundary_node(bound_new,nod_pt);
36057 
36058  // We are happy for this node to be removed from the
36059  // old boundary?
36060  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=0;
36061  }
36062 
36063  // If the face element hasn't moved, its nodes MUST remain
36064  // on that boundary (incl. any nodes that ar shared by
36065  // FaceElements that have moved (see above)
36066 
36067  else
36068  {
36069  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=1;
36070  }
36071  }
36072  }
36073 
36074  // If not, reset the current 'arclength' to zero,
36075  // increase the new face id by one and go one element
36076  // back by decreasing e by one to make sure the current
36077  // element gets added to the next face mesh
36078 
36079  else
36080  {
36081  if(new_face_id!=n_polyline-1)
36082  {
36083  s=0.0;
36084  new_face_id++;
36085  --e;
36086  }
36087  else
36088  {
36089  s=0.0;
36090  --e;
36091  }
36092  }
36093  }
36094  } // end of loop over all polylines -- they are now re-distributed
36095 
36096 
36097  // Loop over all nodes on the boundaries of the polygon to remove
36098  // nodes from boundaries they are no longer on
36099  unsigned move_count=0;
36100  for (std::map<Node*,std::map<unsigned,unsigned> >::iterator
36101  it=node_must_not_be_removed_from_boundary_flag.begin();
36102  it!=node_must_not_be_removed_from_boundary_flag.end();it++)
36103  {
36104  // Get the node
36105  Node* nod_pt=(*it).first;
36106 
36107  // Now we loop over the boundaries that this node is on
36108  for (std::map<unsigned,unsigned>::iterator
36109  it_2=(*it).second.begin();it_2!=(*it).second.end();it_2++)
36110  {
36111  // Get the boundary id
36112  unsigned bound=(*it_2).first;
36113 
36114  // Remove it from that boundary?
36115  if((*it_2).second==0)
36116  {
36117  remove_boundary_node(bound,nod_pt);
36118  move_count++;
36119  }
36120  }
36121  }
36122 
36123  // Loop over the new face mesh to assign new boundary IDs
36124  for(unsigned p=0;p<n_polyline;p++)
36125  {
36126  //Get the boundary id of the polyline
36127  unsigned bound =
36128  polygon_pt->polyline_pt(p)->boundary_id();
36129 
36130  // Loop over the face elements
36131  unsigned n_face_element = face_mesh_pt[p]->nelement();
36132  for(unsigned e=0;e<n_face_element;e++)
36133  {
36134  //Cast the element pointer to the correct thing!
36136  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
36137  (face_mesh_pt[p]->element_pt(e));
36138 
36139  // Set bulk boundary number
36140  el_pt->set_boundary_number_in_bulk_mesh(bound);
36141  }
36142  }
36143 
36144  // Update look-up for elements next to boundary
36145  setup_boundary_element_info();
36146 
36147  // Now re-create the boundary coordinates
36148  for(unsigned p=0;p<n_polyline;p++)
36149  {
36150  //Get the boundary id of the polyline
36151  unsigned bound =
36152  polygon_pt->polyline_pt(p)->boundary_id();
36153 
36154  // Do it
36155  this->template setup_boundary_coordinates<ELEMENT>(bound);
36156  }
36157 
36158  // Clean up
36159  for(unsigned p=0;p<n_polyline;p++)
36160  {
36161  // Flush the nodes from the face mesh to make sure we
36162  // don't delete them (the face mesh that we're returning from here
36163  // still needs them!)
36164  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36165  delete ordered_face_mesh_pt[p];
36166  }
36167 
36168  }
36169 
36170 //=========================================================================
36171 /// Helper function to construct face mesh representation of all polylines
36172 //=========================================================================
36173 template<class ELEMENT>
36176  TriangleMeshOpenCurve* open_polyline_pt,
36177  Vector<Mesh*>& face_mesh_pt)
36178 {
36179  // Number of polylines
36180  unsigned n_polyline = open_polyline_pt->ncurve_section();
36181  face_mesh_pt.resize(n_polyline);
36182 
36183  // Loop over constituent polylines
36184  for(unsigned p=0;p<n_polyline;p++)
36185  {
36186 
36187  //Get the boundary id of the polyline
36188  unsigned bound =
36189  open_polyline_pt->curve_section_pt(p)->boundary_id();
36190 
36191  face_mesh_pt[p] = new Mesh();
36192  create_unsorted_face_mesh_representation(
36193  bound, face_mesh_pt[p]);
36194 
36195  }
36196 
36197 }
36198 
36199 //======================================================================
36200 /// Update the PSLG that define the inner boundaries of the mesh.
36201 ///Optional boolean is used to run it as test only (if
36202 /// true is specified as input) in which case PSLG isn't actually
36203 /// modified. Returned boolean indicates if PSLG was (or would have
36204 /// been -- if called with check_only=false) changed.
36205 //======================================================================
36206 template <class ELEMENT>
36209  &internal_point_coord,
36210  const bool& check_only)
36211  {
36212  //Boolean to indicate whether an actual update of the internal
36213  // holes was performed
36214  bool update_was_performed=false;
36215  //Loop over the number of internal boundaries
36216  unsigned n_hole = internal_point_coord.size();
36217  for(unsigned ihole=0;ihole<n_hole;ihole++)
36218  {
36219  //Cache the pointer to the polygon representation
36220  TriangleMeshPolygon* const poly_pt
36221  = this->Internal_polygon_pt[ihole];
36222 
36223 
36224  //Can the polygon update its own configuration, in which case this
36225  //is easy
36226  if(poly_pt->can_update_reference_configuration())
36227  {
36228  poly_pt->reset_reference_configuration();
36229 
36230  // Initialize Vector hole_coordinates
36231  internal_point_coord[ihole].resize(2);
36232 
36233  // Get the vector of hole coordinates
36234  internal_point_coord[ihole]=poly_pt->internal_point();
36235  }
36236  //Otherwise we have to work much harder
36237 
36238  else
36239  {
36240  //if we only want to check whether an update of the inner
36241  //hole is necessary
36242  if(check_only)
36243  {
36244  //is it necessary?
36245  bool update_necessary=
36246  this->update_polygon_using_face_mesh(poly_pt,check_only);
36247 
36248  //Yes?
36249  if(update_necessary)
36250  {
36251  //then we have to adaptand return 'true'
36252  return true;
36253  }
36254  }
36255  //if we not only want to check, then we actually perform
36256  //the update
36257  else
36258  {
36259  update_was_performed=
36260  this->update_polygon_using_face_mesh(poly_pt);
36261  }
36262 
36263  //Now we need to sort out the hole coordinates
36264  if (!poly_pt->internal_point().empty())
36265  {
36266  //If fixed don't update and simply
36267  //Read out the existing value
36268  if(poly_pt->is_internal_point_fixed())
36269  {
36270  // Get the vector of hole coordinates
36271  internal_point_coord[ihole]=poly_pt->internal_point();
36272  }
36273  //This is where the work starts and this could be made much
36274  //better than the current hack
36275  else
36276  {
36277  //If the user has set their own function then use that
36278  if(this->Internal_hole_point_update_fct_pt!=0)
36279  {
36280  this->Internal_hole_point_update_fct_pt(ihole,poly_pt);
36281  }
36282  //Otherwise use our clunky default
36283  else
36284  {
36285  //Now sort out the hole coordinates
36286  Vector<double> vertex_coord;
36287  unsigned n_polyline = poly_pt->npolyline();
36288 
36289  // Initialize Vector hole_coordinates
36290  vertex_coord.resize(2);
36291  internal_point_coord[ihole].resize(2);
36292 
36293  //Hole centre will be found by averaging the position of
36294  //all vertex nodes
36295  internal_point_coord[ihole][0] = 0.0;
36296  internal_point_coord[ihole][1] = 0.0;
36297 
36298  for(unsigned p=0;p<n_polyline;p++)
36299  {
36300  Vector<double> poly_ave(2,0.0);
36301  //How many vertices are there in the segment
36302  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36303  for(unsigned v=0;v<n_vertex;v++)
36304  {
36305  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36306  for(unsigned i=0;i<2;i++)
36307  {
36308  poly_ave[i] += vertex_coord[i];
36309  }
36310  }
36311 
36312  //Add the average polyline coordinate to the hole centre
36313  for(unsigned i=0;i<2;i++)
36314  {
36315  internal_point_coord[ihole][i] += poly_ave[i]/n_vertex;
36316  }
36317  }
36318 
36319  //Now average out the hole centre
36320  for(unsigned i=0;i<2;i++)
36321  {
36322  internal_point_coord[ihole][i] /= n_polyline;
36323  }
36324 
36325  //We have now found the hole centre stored in internal_point_coordinate[ihole][i]
36326 
36327  //Find polylines that intersect at y average value
36328  //Alice's version but this does not work if the end point of a
36329  //segment is the intersection point (i.e. at the y average value)
36330  /*Vector<double> vertex_coord2;
36331  unsigned n_intersect=0;
36332  double x_average=0.0;
36333 
36334  for(unsigned p=0;p<n_polyline;p++)
36335  {
36336  //How many vertices are there in the segment
36337  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36338  for(unsigned v=0;v<n_vertex-1;v++)
36339  {
36340  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36341  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36342  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36343  << " " <<
36344  vertex_coord2[0] << " " <<
36345 
36346  vertex_coord2[1] << "\n";
36347  //Does the line between vertices intersect the vertical position
36348  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36349  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36350  {
36351  ++n_intersect; x_average += 0.5*(vertex_coord[0] + vertex_coord2[0]);
36352  }
36353  }
36354  }
36355 
36356  //Now just report the value if we have had intersections
36357  if(n_intersect != 0)
36358  {
36359  //Report
36360  std::cout << "I have computed a hole " << x_average << " " << n_intersect << " "
36361  << x_average/((double)n_intersect) << std::endl;
36362  internal_point_coord[ihole][0] = x_average/((double)n_intersect);
36363  }
36364  */
36365 
36366  //Set the new hole centre
36367  poly_pt->internal_point() = internal_point_coord[ihole];
36368  //std::cout << "I've had my centre updated to "
36369  // << internal_point_coord[ihole][0]
36370  // << " " << internal_point_coord[ihole][1] << "\n";
36371  }
36372  }
36373 
36374  }
36375  }
36376  } //End of the action (n_hole for)
36377 
36378  if(check_only)
36379  {
36380  // If we make it up to here and we only check then no update is required
36381  return false;
36382  }
36383  else
36384  {
36385  // otherwise indicate whether an actual update was performed
36386  return update_was_performed;
36387  }
36388 
36389  } //End of the loop of internal boundaries
36390 
36391  //======================================================================
36392  /// Create the polylines and fill associate data structures, used when
36393  /// creating from a mesh from polyfiles
36394  //======================================================================
36395  template<class ELEMENT>
36398  const std::string& poly_file_name)
36399  {
36400  // Get the nodes coordinates (the index of the nodes to build the
36401  // polylines is the one used in the node_file_name file)
36402  // Process node file
36403  // -----------------
36404  std::ifstream node_file(node_file_name.c_str(),std::ios_base::in);
36405 
36406  // Check that the file actually opened correctly
36407  if(!node_file.is_open())
36408  {
36409  std::string error_msg("Failed to open node file: ");
36410  error_msg += "\"" + node_file_name + "\".";
36411  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36412  OOMPH_EXCEPTION_LOCATION);
36413  }
36414 
36415  // Read number of nodes
36416  unsigned nnodes;
36417  node_file >> nnodes;
36418 
36419  // Spatial dimension of nodes
36420  unsigned dimension;
36421  node_file >> dimension;
36422 
36423 #ifdef PARANOID
36424  if(dimension!=2)
36425  {
36426  throw OomphLibError("The dimension must be 2\n",
36427  OOMPH_CURRENT_FUNCTION,
36428  OOMPH_EXCEPTION_LOCATION);
36429  }
36430 #endif
36431 
36432  // Storage the nodes vertices
36433  Vector<double> x_node(nnodes);
36434  Vector<double> y_node(nnodes);
36435 
36436  // Number of attributes
36437  unsigned npoint_attributes;
36438  node_file >> npoint_attributes;;
36439 
36440  // Flag for boundary markers
36441  unsigned boundary_markers_flag=0;
36442  node_file >> boundary_markers_flag;
36443 
36444  // Dummy for node number
36445  unsigned dummy_node_number;
36446  // Dummy for node attribute
36447  unsigned dummy_node_attribute;
36448  // Dummy for node boundary
36449  unsigned dummy_node_boundary;
36450 
36451  // Load in nodal posititions, point attributes
36452  // and boundary markers
36453  for(unsigned i=0;i<nnodes;i++)
36454  {
36455  node_file>>dummy_node_number;
36456  node_file>>x_node[i];
36457  node_file>>y_node[i];
36458  for(unsigned j=0;j<npoint_attributes;++j)
36459  {
36460  node_file>>dummy_node_attribute;
36461  }
36462  if(boundary_markers_flag)
36463  {
36464  node_file>>dummy_node_boundary;
36465  }
36466  }
36467  node_file.close();
36468 
36469  // Get the segments information and use that info. to create the
36470  // polylines
36471 
36472  // A map to store the segments associated to a boundary, non sorted
36473  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >
36474  unsorted_boundary_segments;
36475 
36476  // Independent storage for the boundaries ids found in the segments so that
36477  // the polylines, and therefore polygons be created in the order they appear
36478  // in the polyfile
36479  Vector<unsigned> sorted_boundaries_ids;
36480 
36481  // Process poly file to extract edges
36482  //-----------------------------------
36483 
36484  // Open poly file
36485  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
36486 
36487  // Check that the file actually opened correctly
36488  if(!poly_file.is_open())
36489  {
36490  std::string error_msg("Failed to open poly file: ");
36491  error_msg += "\"" + poly_file_name + "\".";
36492  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36493  OOMPH_EXCEPTION_LOCATION);
36494  }
36495 
36496  // Number of nodes in poly file --- these will be ignore
36497  unsigned n_node_poly;
36498  poly_file >> n_node_poly;
36499 
36500  // Dimension
36501  poly_file >> dimension;
36502 
36503  // Attribute flag
36504  unsigned attribute_flag;
36505  poly_file >> attribute_flag;
36506 
36507  // Flag for boundary markers
36508  poly_file >> boundary_markers_flag;
36509 
36510  // Ignore node information: Note: No, we can't extract the
36511  // actual nodes themselves from here!
36512  unsigned dummy;
36513  for(unsigned i=0;i<n_node_poly;i++)
36514  {
36515  //Read in (and discard) node number and x and y coordinates
36516  poly_file>>dummy;
36517  poly_file>>dummy;
36518  poly_file>>dummy;
36519  //read in the attributes
36520  for(unsigned j=0;j<attribute_flag;++j)
36521  {
36522  poly_file >> dummy;
36523  }
36524  //read in the boundary marker
36525  if(boundary_markers_flag==1)
36526  {
36527  poly_file>>dummy;
36528  }
36529  }
36530 
36531  // Variable used to read the values from the input file
36532  unsigned read_value;
36533 
36534  // Number of segments
36535  poly_file >> read_value;
36536  const unsigned nglobal_segments = read_value;
36537 
36538  // Boundary marker flag
36539  poly_file >> boundary_markers_flag;
36540 
36541  // Global segment number
36542  unsigned global_segment_number;
36543 
36544  // Node identifier set (used to identify possible internal boundaries)
36545  std::set<unsigned> nodes_ids;
36546 
36547  // Extract information for each segment
36548  for(unsigned i=0;i<nglobal_segments;i++)
36549  {
36550  // Node id on the edge of the segment
36551  unsigned lnode_id=0; // left node
36552  unsigned rnode_id=0; // right node
36553  unsigned bnd_id=0; // boundary id associated to the current segment
36554  poly_file >> global_segment_number;
36555  poly_file >> lnode_id;
36556  poly_file >> rnode_id;
36557  nodes_ids.insert(lnode_id);
36558  nodes_ids.insert(rnode_id);
36559  if(boundary_markers_flag)
36560  {
36561  poly_file >> bnd_id;
36562  }
36563 
36564  // Store the segments info. (use bnd_id - 1 because the nodes and
36565  // elements associated the bnd_id have been associated by external
36566  // methods to bnd_id - 1)
36567  unsorted_boundary_segments[bnd_id-1].push_back(
36568  std::make_pair(lnode_id, rnode_id));
36569 
36570  // Add the boundary id to the vector of boundaries ids only if it
36571  // has not been added, the polylines will be created using this
36572  // order
36573 
36574  // Get the number of boundaries ids currently sorted
36575  const unsigned nsorted_boundaries_ids =
36576  sorted_boundaries_ids.size();
36577  // Flag to know if the boundary id was found
36578  bool boundary_id_found = false;
36579  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36580  {
36581  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36582  {
36583  boundary_id_found = true;
36584  break;
36585  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36586  } // for (ib < nsorted_boundaries_ids)
36587 
36588  // If th boundary id has not been added, then add it!!!
36589  if (!boundary_id_found)
36590  {
36591  sorted_boundaries_ids.push_back(bnd_id - 1);
36592  } // if (!boundary_id_found)
36593 
36594  }
36595 
36596  // Verify if there are internal boundaries defined, if that is the
36597  // case we can not continue since we are not yet supporting internal
36598  // boundaries defined in polyfiles to created a mesh that may be
36599  // adapted
36600 #ifdef PARANOID
36601  if (nglobal_segments != nodes_ids.size())
36602  {
36603  std::ostringstream error_message;
36604  error_message
36605  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36606  << nglobal_segments << ") is different.\nThis may mean that there "
36607  << "are internal non-closed boundaries defined in\nthe polyfile. "
36608  << "If you need this feature please use the TriangleMeshPoyLine\n"
36609  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36610  throw OomphLibError(error_message.str(),
36611  OOMPH_CURRENT_FUNCTION,
36612  OOMPH_EXCEPTION_LOCATION);
36613  }
36614 #endif
36615 
36616  // Now sort the segments associated to a boundary to create a contiguous
36617  // polyline, but first check that the number of found boundaries be the
36618  // same as the current number of boundaries in the mesh
36619  const unsigned nboundary = unsorted_boundary_segments.size();
36620 
36621 #ifdef PARANOID
36622  if (nboundary != this->nboundary())
36623  {
36624  std::ostringstream error_message;
36625  error_message
36626  << "The number of boundaries on the mesh (" << this->nboundary()
36627  << ") is different from the number of\nboundaries read from the "
36628  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36629  throw OomphLibError(error_message.str(),
36630  OOMPH_CURRENT_FUNCTION,
36631  OOMPH_EXCEPTION_LOCATION);
36632  }
36633 #endif
36634 
36635  // Get the number of sorted boundaries ids and check that it matches
36636  // with the total number of boundaries
36637  const unsigned nsorted_boundaries_ids =
36638  sorted_boundaries_ids.size();
36639 #ifdef PARANOID
36640  if (nsorted_boundaries_ids != this->nboundary())
36641  {
36642  std::ostringstream error_message;
36643  error_message
36644  << "The number of boundaries on the mesh (" << this->nboundary()
36645  << ") is different from the number of\nsorted boundaries ids read "
36646  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36647  throw OomphLibError(error_message.str(),
36648  OOMPH_CURRENT_FUNCTION,
36649  OOMPH_EXCEPTION_LOCATION);
36650  }
36651 #endif
36652 
36653  // Sorted segments (to create a polyline -- boundary)
36654  std::map<unsigned, std::list<unsigned> > sorted_boundary_segments;
36655 
36656  // Go through all the found boundaries
36657  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >::iterator it;
36658 
36659  for (it = unsorted_boundary_segments.begin();
36660  it != unsorted_boundary_segments.end();
36661  it++)
36662  {
36663  // Get the current boundary id, only look for the segments
36664  // associated with this boundary
36665  const unsigned bnd_id = (*it).first;
36666  Vector<std::pair<unsigned, unsigned> > segments_edges = (*it).second;
36667 
36668  // Now sort the segments associated to this boundary
36669  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36670  const unsigned nsegments = segments_edges.size();
36671 
36672  // Sorted nodes for the current segment
36673  std::list<unsigned> sorted_segments;
36674 
36675  // Get the left and right node of the zero segment
36676  unsigned left_node_id = segments_edges[0].first;
36677  unsigned right_node_id = segments_edges[0].second;
36678 
36679  // ... and add it to the sorted segments structure
36680  sorted_segments.push_back(left_node_id);
36681  sorted_segments.push_back(right_node_id);
36682 
36683  // Mark the current segment as done
36684  segment_done[segments_edges[0]] = true;
36685 
36686  // Set the number of sorted segments
36687  unsigned nsorted_segments = 1;
36688 
36689  while(nsorted_segments < nsegments)
36690  {
36691  for (unsigned i = 1; i < nsegments; i++)
36692  {
36693  // Check if the i-th segments has been done
36694  if (!segment_done[segments_edges[i]])
36695  {
36696  // Get the left and right node id
36697  unsigned current_left_node_id = segments_edges[i].first;
36698  unsigned current_right_node_id = segments_edges[i].second;
36699 
36700  // Now check if the current segment can be added to the left
36701  // or right side of the sorted segments
36702  if (current_left_node_id == right_node_id)
36703  {
36704  // Add the current_right_node_id to the right of the sorted
36705  // segments
36706  sorted_segments.push_back(current_right_node_id);
36707  // Increase the number of sorted segments
36708  nsorted_segments++;
36709  // Mark the segment as done
36710  segment_done[segments_edges[i]] = true;
36711  // Update the right most node
36712  right_node_id = current_right_node_id;
36713  // Break the for loop
36714  break;
36715  }
36716  else if (current_right_node_id == left_node_id)
36717  {
36718  // Add the current_left_node_id to the left of the sorted
36719  // segments
36720  sorted_segments.push_front(current_left_node_id);
36721  // Increase the number of sorted segments
36722  nsorted_segments++;
36723  // Mark the segment as done
36724  segment_done[segments_edges[i]] = true;
36725  // Update the left most node
36726  left_node_id = current_left_node_id;
36727  // Break the for loop
36728  break;
36729  }
36730  else if (current_left_node_id == left_node_id)
36731  {
36732  // Add the current_right_node_id to the left of the sorted
36733  // segments
36734  sorted_segments.push_front(current_right_node_id);
36735  // Increase the number of sorted segments
36736  nsorted_segments++;
36737  // Mark the segment as done
36738  segment_done[segments_edges[i]] = true;
36739  // Update the left most node
36740  left_node_id = current_right_node_id;
36741  // Break the for loop
36742  break;
36743  }
36744  else if (current_right_node_id == right_node_id)
36745  {
36746  // Add the current_left_node_id to the right of the sorted
36747  // segments
36748  sorted_segments.push_back(current_left_node_id);
36749  // Increase the number of sorted segments
36750  nsorted_segments++;
36751  // Mark the segment as done
36752  segment_done[segments_edges[i]] = true;
36753  // Update the left most node
36754  right_node_id = current_left_node_id;
36755  // Break the for loop
36756  break;
36757  }
36758  } // if (!segment_done[segments_edges[i]])
36759  } // for (i < nsegments)
36760  } // while(nsorted_segments < nsegments)
36761 
36762  sorted_boundary_segments[bnd_id] = sorted_segments;
36763 
36764  } // for (unsorted_boundary_segments.begin();
36765  // unsorted_boundary_segments.end())
36766 
36767 #ifdef PARANOID
36768  if (sorted_boundary_segments.size() != this->nboundary())
36769  {
36770  std::ostringstream error_message;
36771  error_message
36772  << "The number of boundaries on the mesh (" << this->nboundary()
36773  << ") is different from the number\nof sorted boundaries to create the "
36774  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
36775  throw OomphLibError(error_message.str(),
36776  OOMPH_CURRENT_FUNCTION,
36777  OOMPH_EXCEPTION_LOCATION);
36778  }
36779 #endif
36780 
36781  // Now we have the sorted nodes, we can create the polylines by
36782  // getting the vertices of the nodes
36783  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
36784  unsigned current_polyline = 0;
36785 
36786  // Go through the sorted boundaries using the sorted boundaries ids
36787  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36788  {
36789  // Get the boundary id from the vector of sorted boundaries ids
36790  const unsigned bnd_id = sorted_boundaries_ids[ib];
36791 
36792  // Create a vector representation for ease to use
36793  // Get the vertices of the nodes that create the boundary / polyline
36794  Vector<unsigned> nodes_ids;
36795  for (std::list<unsigned>::iterator it_list =
36796  sorted_boundary_segments[bnd_id].begin();
36797  it_list != sorted_boundary_segments[bnd_id].end();
36798  it_list++)
36799  {nodes_ids.push_back((*it_list));}
36800 
36801  // Get the number of vertices for the polyline
36802  const unsigned nvertices = nodes_ids.size();
36803 
36804  // The storage for the vertices
36805  Vector<Vector<double> > vertices(nvertices);
36806 
36807  // Now get the vertices of the nodes of the current boundary
36808  for (unsigned i = 0; i < nvertices; i++)
36809  {
36810  // Get the vertices
36811  vertices[i].resize(2);
36812  vertices[i][0] = x_node[nodes_ids[i]-1];
36813  vertices[i][1] = y_node[nodes_ids[i]-1];
36814  }
36815 
36816  // Now create the polyline
36817 
36818  // Note: The bnd_id is the real bnd_id (from the input file) - 1
36819  // since nodes and elements of the current boundary have been
36820  // associated to bnd_id - 1)
36821  polylines_pt[current_polyline] =
36822  new TriangleMeshPolyLine(vertices, bnd_id);
36823 
36824  // Updates bnd_id<--->curve section map
36825  this->Boundary_curve_section_pt[bnd_id] =
36826  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
36827 
36828  // Increase the index for the polyline storage
36829  current_polyline++;
36830 
36831  } // for (it_sorted = sorted_boundary_segments.begin();
36832  // it_sorted != sorted_boundary_segments.end())
36833 
36834  // Now create the polygons or closed curves
36835  // Sort the polylines to create polygons
36836  unsigned nsorted_polylines = 0;
36837 
36838  // Number of created polygons
36839  unsigned npolygons = 0;
36840 
36841  // Storage for the polygons
36842  Vector<TriangleMeshPolygon*> polygons_pt;
36843 
36844  // Mark the already done polylines
36845  std::map<unsigned, bool> polyline_done;
36846  while(nsorted_polylines < nboundary)
36847  {
36848  // Storage for the curve sections that create a polygon
36849  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
36850 
36851  unsigned init_poly = 0;
36852 #ifdef PARANOID
36853  bool found_root_polyline = false;
36854 #endif
36855  // Get the left and right node of the current polyline
36856  for (unsigned i = 0; i < nboundary; i++)
36857  {
36858  if (!polyline_done[i])
36859  {
36860  init_poly = i;
36861  // Increase the number of sorted polylines
36862  nsorted_polylines++;
36863 #ifdef PARANOID
36864  // Mark as found the root polyline
36865  found_root_polyline = true;
36866 #endif
36867  // Mark the polyline as done
36868  polyline_done[i] = true;
36869  // Add the polyline to the curve sections storage
36870  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36871  // Break the loop to set we have found a root polyline
36872  break;
36873  }
36874  }
36875 
36876 #ifdef PARANOID
36877  if (!found_root_polyline)
36878  {
36879  std::ostringstream error_message;
36880  error_message
36881  << "Was not possible to found the root polyline to create polygons\n\n";
36882  throw OomphLibError(error_message.str(),
36883  OOMPH_CURRENT_FUNCTION,
36884  OOMPH_EXCEPTION_LOCATION);
36885  }
36886 #endif
36887 
36888  // Get the associated boundary to the current polyline
36889  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
36890  // Get the initial and final node id of the current polyline
36891  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
36892  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
36893 
36894  // Flag to know that we already have a closed polygon
36895  bool closed_polygon = false;
36896 
36897  do
36898  {
36899  // Go through all the polylines
36900  for (unsigned i = init_poly; i < nboundary; i++)
36901  {
36902  // Check that the polyline has not been currently done
36903  if (!polyline_done[i])
36904  {
36905  // Get the initial and final nodes id of the current polyline
36906 
36907  // Get the associated boundary to the current polyline
36908  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
36909  // Get the initial and final node id of the current polyline
36910  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
36911  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
36912 
36913  // Check if the polyline goes to the left or right of the
36914  // current sorted polylines
36915  if (cleft_node_id == right_node_id)
36916  {
36917  // Add the polyline to the curve section storage
36918  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36919  // Mark the polyline as done
36920  polyline_done[i] = true;
36921  // Update the right node
36922  right_node_id = cright_node_id;
36923  // Increase the number of done polyines
36924  nsorted_polylines++;
36925  // Break the for loop
36926  break;
36927  }
36928  else if (cright_node_id == left_node_id)
36929  {
36930  // Add the polyline to the curve section storage
36931  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36932  // Mark the polyline as done
36933  polyline_done[i] = true;
36934  // Update the right node
36935  left_node_id = cleft_node_id;
36936  // Increase the number of done polyines
36937  nsorted_polylines++;
36938  // Break the for loop
36939  break;
36940  }
36941  else if (cleft_node_id == left_node_id)
36942  {
36943  // First reverse the polyline
36944  polylines_pt[i]->reverse();
36945  // Add the polyline to the curve section storage
36946  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36947  // Mark the polyline as done
36948  polyline_done[i] = true;
36949  // Update the right node
36950  left_node_id = cright_node_id;
36951  // Increase the number of done polyines
36952  nsorted_polylines++;
36953  // Break the for loop
36954  break;
36955  }
36956  else if (cright_node_id == right_node_id)
36957  {
36958  // First reverse the polyline
36959  polylines_pt[i]->reverse();
36960  // Add the polyline to the curve section storage
36961  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36962  // Mark the polyline as done
36963  polyline_done[i] = true;
36964  // Update the right node
36965  right_node_id = cleft_node_id;
36966  // Increase the number of done polyines
36967  nsorted_polylines++;
36968  // Break the for loop
36969  break;
36970  }
36971  } // if (!polyline_done[i])
36972 
36973  } // for (i < nboundary)
36974 
36975  // We have created a polygon
36976  if (left_node_id == right_node_id)
36977  {
36978  // Set the flag as true
36979  closed_polygon = true;
36980  }
36981 
36982  }while(nsorted_polylines < nboundary && !closed_polygon);
36983 
36984 #ifdef PARANOID
36985  if (!closed_polygon)
36986  {
36987  std::ostringstream error_message;
36988  error_message
36989  << "It was not possible to create a closed curve, these are the "
36990  << "vertices of the already sorted polylines\n\n";
36991  unsigned cpolyline = 0;
36992  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
36993  sorted_curve_sections_pt.begin();
36994  it_list != sorted_curve_sections_pt.end();
36995  it_list++)
36996  {
36997  error_message << "Polyline (" << cpolyline << ")\n";
36998  TriangleMeshPolyLine *tmp_poly_pt =
36999  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
37000  const unsigned nvertex = tmp_poly_pt->nvertex();
37001  for (unsigned v = 0; v < nvertex; v++)
37002  {
37003  error_message <<"("<<tmp_poly_pt->vertex_coordinate(v)[0]
37004  <<", "<<tmp_poly_pt->vertex_coordinate(v)[1]<<")\n";
37005  }
37006  error_message << "\n";
37007  cpolyline++;
37008  }
37009  throw OomphLibError(error_message.str(),
37010  OOMPH_CURRENT_FUNCTION,
37011  OOMPH_EXCEPTION_LOCATION);
37012  }
37013 #endif
37014 
37015  // Create a vector version to create the polygon from the sorted
37016  // polyines
37017  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37018  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37019  sorted_curve_sections_pt.begin();
37020  it_list != sorted_curve_sections_pt.end();
37021  it_list++)
37022  {tmp_sorted_curve_sections_pt.push_back((*it_list));}
37023 
37024  // Create a new polygon by using the new created polylines
37025  TriangleMeshPolygon *polygon_pt =
37026  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37027 
37028  // Keep track of new created polygons that need to be deleted!!!
37029  this->Free_polygon_pt.insert(polygon_pt);
37030 
37031  // Store the polygon in the polygons storages
37032  polygons_pt.push_back(polygon_pt);
37033 
37034  npolygons++;
37035 
37036  } // while(nsorted_polylines < nboundary)
37037 
37038  // ------------------------------------------------------------------
37039  // Before filling the data structures we need to identify the outer
37040  // closed boundary and the inner closed boundaries.
37041  // If the nodes are not in order we throw a warning message
37042 
37043  // Index for the polygon that is currently considered as the outer
37044  // boundary
37045  unsigned index_outer = 0;
37046 
37047  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37048  {
37049  // Get the vertices of the outer boundary
37050  Vector<Vector<double> > outer_vertex_coordinates;
37051 
37052  // Flag to know if ALL the inner closed boundaries are inside the
37053  // outer closed boundary
37054  bool all_inner_inside = true;
37055 
37056  // Number of polylines of the outer boundary
37057  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37058  for (unsigned p = 0; p < nouter_polylines; p++)
37059  {
37060  TriangleMeshPolyLine* tmp_poly_pt =
37061  polygons_pt[idx_outer]->polyline_pt(p);
37062  const unsigned nvertex = tmp_poly_pt->nvertex();
37063  for (unsigned v = 0; v < nvertex; v++)
37064  {
37065  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37066  outer_vertex_coordinates.push_back(current_vertex);
37067  } // for (v < nvertex)
37068  } // for (p < nouter_polylines)
37069 
37070  // Now get the vertices for the inner boundaries
37071 
37072  // First get the number of inner closed boundaries (polygons size
37073  // minus one because one of the polygons is considered to be the
37074  // outer closed boundary
37075  const unsigned ninner_polygons = polygons_pt.size() - 1;
37076 
37077  // Store the vertices of the inner closed boundaries
37078  Vector<Vector<Vector<double> > > inner_vertex_coordinates(ninner_polygons);
37079  // Get all the vertices of the inner closed boundaries
37080  for (unsigned i = 0; i <= ninner_polygons; i++)
37081  {
37082  if (i != idx_outer)
37083  {
37084  // Number of polylines of the current internal closed boundary
37085  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37086  for (unsigned p = 0; p < ninner_polylines; p++)
37087  {
37088  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37089  const unsigned nvertex = tmp_poly_pt->nvertex();
37090  for (unsigned v = 0; v < nvertex; v++)
37091  {
37092  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37093  if (i < idx_outer)
37094  {
37095  inner_vertex_coordinates[i].push_back(current_vertex);
37096  }
37097  else if (i > idx_outer)
37098  {
37099  inner_vertex_coordinates[i-1].push_back(current_vertex);
37100  }
37101  } // for (v < nvertex)
37102 
37103  } // for (p < ninner_polylines)
37104 
37105  } // if (i != index_outer)
37106 
37107  } // for (i <= ninner_polygons)
37108 
37109  // Now check that ALL the vertices of ALL the internal closed
37110  // boundaries are inside the outer closed boundary
37111  for (unsigned i = 0; i < ninner_polygons; i++)
37112  {
37113  // Get the number of vertices in the current internal closed
37114  // boundary
37115  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37116  for (unsigned v = 0; v < nvertex_internal; v++)
37117  {
37118  // Get a vertex in the current internal closed boundary
37119  Vector<double> current_point = inner_vertex_coordinates[i][v];
37120  all_inner_inside &=
37121  this->is_point_inside_polygon_helper(outer_vertex_coordinates,
37122  current_point);
37123 
37124  // Check if we should continue checking for more points inside
37125  // the current proposed outer boundary
37126  if (!all_inner_inside)
37127  {
37128  // Break the "for" for the vertices
37129  break;
37130  }
37131 
37132  } // for (v < nvertex_internal)
37133 
37134  // Check if we should continue checking for more inner closed
37135  // boundaries inside the current proposed outer boundary
37136  if (!all_inner_inside)
37137  {
37138  // Break the "for" for the inner boundaries
37139  break;
37140  }
37141 
37142  } // for (i < ninner_polygons)
37143 
37144  // Check if all the vertices of all the polygones are inside the
37145  // current proposed outer boundary
37146  if (all_inner_inside)
37147  {
37148  index_outer = idx_outer;
37149  break;
37150  }
37151 
37152  } // for (idx_outer < npolygons)
37153 
37154 #ifdef PARANOID
37155  // Check if the first nodes listed in the polyfiles correspond to
37156  // the outer boundary, if that is not the case then throw a warning
37157  // message
37158  if (index_outer != 0)
37159  {
37160  std::ostringstream warning_message;
37161  warning_message
37162  << "The first set of nodes listed in the input polyfiles does not\n"
37163  << "correspond to the outer closed boundary. This may lead to\n"
37164  << "problems at the adaptation stage if the holes coordinates\n"
37165  << "are no correctly associated to the inner closed boundaries.\n"
37166  << "You can check the generated mesh by calling the output() method\n"
37167  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37168  OomphLibWarning(warning_message.str(),
37169  OOMPH_CURRENT_FUNCTION,
37170  OOMPH_EXCEPTION_LOCATION);
37171  } // if (index_outer != 0)
37172 #endif
37173 
37174  // ------------------------------------------------------------------
37175  // Now fill the data structures
37176 
37177  // Store outer polygon
37178  // We are assuming there is only one outer polygon
37179  this->Outer_boundary_pt.resize(1);
37180  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37181 
37182  this->Internal_polygon_pt.resize(npolygons-1);
37183  for (unsigned i = 0; i < npolygons; i++)
37184  {
37185  if (i != index_outer)
37186  {
37187  if (i < index_outer)
37188  {
37189  // Store internal polygons by copy constructor
37190  this->Internal_polygon_pt[i] = polygons_pt[i];
37191  }
37192  else if (i > index_outer)
37193  {
37194  // Store internal polygons by copy constructor
37195  this->Internal_polygon_pt[i-1] = polygons_pt[i];
37196  }
37197  } // if (i != index_outer)
37198  } // for (i < npolygons)
37199 
37200  // Before assigning the hole vertex coordinate to the inner closed
37201  // boundaries check that the holes are listed in orderm if that is
37202  // not the case the associate each hole vertex coordinate to the
37203  // inner closed boundaries
37204 
37205  // Store the vertices of the inner closed boundaries
37206  Vector<Vector<Vector<double> > > inner_vertex_coordinates(npolygons-1);
37207  // Get all the vertices of the inner closed boundaries
37208  for (unsigned i = 0; i < npolygons-1; i++)
37209  {
37210  // Number of polylines of the current internal closed boundary
37211  const unsigned ninner_polylines =
37212  this->Internal_polygon_pt[i]->npolyline();
37213  for (unsigned p = 0; p < ninner_polylines; p++)
37214  {
37215  TriangleMeshPolyLine* tmp_poly_pt =
37216  this->Internal_polygon_pt[i]->polyline_pt(p);
37217  // Number of vertices of the current polyline in the current
37218  // internal closed polygon
37219  const unsigned nvertex = tmp_poly_pt->nvertex();
37220  for (unsigned v = 0; v < nvertex; v++)
37221  {
37222  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37223  inner_vertex_coordinates[i].push_back(current_vertex);
37224  } // for (v < nvertex)
37225 
37226  } // for (p < ninner_polylines)
37227 
37228  } // for (i <= ninner_polygons)
37229 
37230  // Holes information
37231  unsigned nholes;
37232  poly_file >> nholes;
37233 
37234 #ifdef PARANOID
37235  if (npolygons > 1 && (npolygons - 1) != nholes)
37236  {
37237  std::ostringstream error_message;
37238  error_message
37239  << "The number of holes (" << nholes << ") does not correspond "
37240  << "with the number\nof internal polygons ("
37241  << npolygons - 1 <<")\n\n"
37242  << "Using polyfiles as input does not currently allows the\n"
37243  << "definition of more than one outer polygon\n\n";
37244  throw OomphLibError(error_message.str(),
37245  OOMPH_CURRENT_FUNCTION,
37246  OOMPH_EXCEPTION_LOCATION);
37247  }
37248 #endif
37249 
37250  // Storage for the holes
37251  Vector<Vector<double> > hole_coordinates(nholes);
37252 
37253  // Dummy for hole number
37254  unsigned dummy_hole;
37255  // Loop over the holes to get centre coords
37256  for(unsigned ihole=0;ihole<nholes;ihole++)
37257  {
37258  hole_coordinates[ihole].resize(2);
37259  // Read the centre value
37260  poly_file >> dummy_hole;
37261  poly_file >> hole_coordinates[ihole][0];
37262  poly_file >> hole_coordinates[ihole][1];
37263  }
37264 
37265  // Vector that store the index of the hole coordinate that
37266  // correspond to each internal closed polygon
37267  Vector<unsigned> index_hole_of_internal_polygon(npolygons-1);
37268  std::map<unsigned, bool> hole_done;
37269 
37270  // Now associate each hole vertex to a corresponding internal closed
37271  // polygon
37272  for (unsigned i = 0; i < npolygons-1; i++)
37273  {
37274  // Find which hole is associated to each internal closed boundary
37275  for (unsigned h = 0; h < nholes; h++)
37276  {
37277  // If the hole has not been previously associated
37278  if (!hole_done[h])
37279  {
37280  // Get the hole coordinate
37281  Vector<double> current_point = hole_coordinates[h];
37282 
37283  const bool hole_in_polygon =
37284  this->is_point_inside_polygon_helper(inner_vertex_coordinates[i],
37285  current_point);
37286 
37287  // If the hole is inside the polygon
37288  if (hole_in_polygon)
37289  {
37290  // Mark the hole as done
37291  hole_done[h] = true;
37292  // Associate the current hole with the current inner closed
37293  // boundary
37294  index_hole_of_internal_polygon[i] = h;
37295  // Break the search
37296  break;
37297  }
37298 
37299  } // if (!hole_done[h])
37300 
37301  } // for (h < nholes)
37302 
37303  } // for (i < npolygons-1)
37304 
37305 #ifdef PARANOID
37306  if (hole_done.size() != npolygons-1)
37307  {
37308  std::ostringstream error_message;
37309  error_message
37310  << "Not all the holes were associated to an internal closed boundary\n"
37311  << "Only ("<<hole_done.size()<<") holes were assigned for a total of\n"
37312  << "(" << npolygons-1 << ") internal closed boundaries.\n"
37313  << "You can check the generated mesh by calling the output() method\n"
37314  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37315  throw OomphLibError(error_message.str(),
37316  OOMPH_CURRENT_FUNCTION,
37317  OOMPH_EXCEPTION_LOCATION);
37318  } // if (index_hole != ihole)
37319 #endif
37320 
37321  // Assign the holes coordinates to the internal polygons
37322  for (unsigned ihole = 0; ihole < nholes; ihole++)
37323  {
37324  // Get the index hole of the current internal closed polygon
37325  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37326 #ifdef PARANOID
37327  // Check if the hole index is the same as the internal closed
37328  // boundary, it means that the holes were listed in the same order
37329  // as the nodes of the internal closed boundaries
37330  if (index_hole != ihole)
37331  {
37332  std::ostringstream error_message;
37333  error_message
37334  << "The hole vertices coordinates are not listed in the same order\n"
37335  << "as the nodes that define the internal closed boundaries.\n"
37336  << "This may lead to problems in case that the holes coordinates\n"
37337  << "were no properly assigned to the internal closed boundaries.\n"
37338  << "You can check the generated mesh by calling the output() method\n"
37339  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37340  throw OomphLibError(error_message.str(),
37341  OOMPH_CURRENT_FUNCTION,
37342  OOMPH_EXCEPTION_LOCATION);
37343  } // if (index_hole != ihole)
37344 #endif
37345 
37346  // Set the hole coordinate for the internal polygon
37347  this->Internal_polygon_pt[ihole]->internal_point() =
37348  hole_coordinates[index_hole];
37349  }
37350 
37351  // Ignore the first line with structure description
37352  poly_file.ignore(80,'\n');
37353 
37354  // Regions information
37355  unsigned nregions;
37356 
37357  // Extract regions information
37358  // But first check if there are regions or not
37359  std::string regions_info_string;
37360 
37361  // Read line up to termination sign
37362  getline(poly_file, regions_info_string);
37363 
37364  // Check if the read string is a number or a comment wrote by triangle,
37365  // if it is a number then that is the number of regions
37366  if (isdigit(regions_info_string.c_str()[0]))
37367  {
37368  nregions = std::atoi(regions_info_string.c_str());
37369  }
37370  else
37371  {
37372  nregions = 0;
37373  }
37374 
37375  // The regions coordinates
37376  std::map<unsigned, Vector<double> > regions_coordinates;
37377 
37378  // Dummy for regions number
37379  unsigned dummy_region;
37380 
37381  unsigned region_id;
37382 
37383  // Loop over the regions to get their coords
37384  for(unsigned iregion=0;iregion<nregions;iregion++)
37385  {
37386  Vector<double> tmp_region_coordinates(2);
37387  // Read the regions coordinates
37388  poly_file >> dummy_region;
37389  poly_file >> tmp_region_coordinates[0];
37390  poly_file >> tmp_region_coordinates[1];
37391  poly_file >> region_id;
37392  regions_coordinates[region_id].resize(2);
37393  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37394  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37395 
37396  // Ignore the first line with structure description
37397  poly_file.ignore(80,'\n');
37398 
37399  // Verify if not using the default region number (zero)
37400  if (region_id == 0)
37401  {
37402  std::ostringstream error_message;
37403  error_message << "Please use another region id different from zero.\n"
37404  << "It is internally used as the default region number.\n";
37405  throw OomphLibError(error_message.str(),
37406  OOMPH_CURRENT_FUNCTION,
37407  OOMPH_EXCEPTION_LOCATION);
37408  }
37409 
37410  }
37411 
37412  // Store the extra regions coordinates
37413  this->Regions_coordinates = regions_coordinates;
37414 
37415  poly_file.close();
37416 
37417  }
37418 
37419 //======================================================================
37420 /// \short Updates the polygon but using the elements area instead of
37421 /// the default refinement and unrefinement methods
37422 //======================================================================
37423 template <class ELEMENT>
37426  const Vector<double> &target_area)
37427 {
37428  // Verify that there was a change on the polygon representation
37429  unsigned update_was_performed = false;
37430 
37431  const unsigned nele = this->nelement();
37432 
37433  // - Get the vertices along the boundaries and for each element identify
37434  // its associated target error.
37435  // - Get face mesh representation of each polyline.
37436  // - Get the vertices with the help of face elements.
37437  // - Find the global index in the mesh of the face element and use
37438  // it to get its associated target area
37439 
37440  // Get the face mesh representation
37441  Vector<Mesh*> face_mesh_pt;
37442  get_face_mesh_representation(polygon_pt,face_mesh_pt);
37443 
37444  // Create vertices of the polylines by using the vertices of the
37445  // FaceElements
37446  Vector<double> vertex_coord(3); // zeta,x,y
37447  Vector<double> bound_left(1);
37448  Vector<double> bound_right(1);
37449 
37450  unsigned n_polyline = polygon_pt->npolyline();
37451 
37452  // Go for each polyline
37453  for(unsigned p = 0; p < n_polyline; p++)
37454  {
37455  // Get the MeshAsGeomObject representation just once per polyline,
37456  // this object is only used by the
37457  // refine_boundary_constrained_by_target_area() method. We get it
37458  // here to ensure that all processors (in a distributed context)
37459  // get this representation just once, and because an AllToAll MPI
37460  // communication is used in this calling
37461  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
37462 
37463  // Set of coordinates on the boundary
37464  // Set entries are ordered on first entry in vector which stores
37465  // the boundary coordinate so the vertices come out in order!
37466  std::set<Vector<double> > vertex_nodes;
37467 
37468  // Vector to store the vertices, transfer the sorted vertices from the
37469  // set to this vector, --- including the z-value ---
37470  Vector<Vector<double> > tmp_vector_vertex_node;
37471 
37472  // Vector to store the coordinates of the polylines, same as the
37473  // tmp_vector_vertex_node vector (after adding more nodes) but
37474  // --- without the z-value ---, used to re-generate the polylines
37475  Vector<Vector<double> > vector_vertex_node;
37476 
37477 #ifdef OOMPH_HAS_MPI
37478  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37479  // Set of coordinates that are on the boundary (splitted boundary version)
37480  // The first vector is used to allocate the points for each sub-boundary
37481  // Set entries are ordered on first entry in vector which stores
37482  // the boundary coordinate so the vertices come out in order!
37483  Vector<std::set<Vector<double> > >sub_vertex_nodes;
37484 
37485  // Vector to store the vertices, transfer the sorted vertices from the
37486  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37487  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
37488 
37489  // Vector to store the coordinates of the polylines that will represent
37490  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37491  // but --- without the z-value ---, used to generate the sub-polylines
37492  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
37493  // --------- Stuff to deal with splitted boundaries ----------- End ------
37494 #endif
37495 
37496  //Get the boundary id
37497  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37498 
37499  // Get the chunk number
37500  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37501 
37502  /// Use a vector of vector for vertices and target areas to deal
37503  /// with the cases when the boundaries are split by the
37504  /// distribution process
37505 
37506  // Loop over the face elements (ordered) and add their vertices
37507  const unsigned nface_element = face_mesh_pt[p]->nelement();
37508 
37509  // Store the non halo face elements, the ones from which we will
37510  // get the vertices
37511  Vector<FiniteElement*> non_halo_face_element_pt;
37512 
37513  // Map to store the index of the face element on a boundary
37514  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
37515 
37516  for(unsigned ef=0;ef<nface_element;++ef)
37517  {
37518  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37519 #ifdef OOMPH_HAS_MPI
37520  // Skip the halo elements if working with a distributed mesh
37521  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37522  {continue;}
37523 #endif
37524  // Add the face element to the vector
37525  non_halo_face_element_pt.push_back(ele_face_pt);
37526  face_element_index_on_boundary[ele_face_pt] = ef;
37527  }
37528 
37529  // Get the number of non halo face element
37530  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37531 
37532  // Map to know the already sorted face elements
37533  std::map<FiniteElement*,bool> face_element_done;
37534 
37535  // Number of done face elements
37536  unsigned nsorted_face_elements = 0;
37537 
37538 #ifdef OOMPH_HAS_MPI
37539  // Counter for sub_boundaries
37540  unsigned nsub_boundaries = 0;
37541 #endif // #ifdef OOMPH_HAS_MPI
37542 
37543  // Continue until all the face elements have been sorted
37544  // While to deal with split boundaries cases
37545  while(nsorted_face_elements < nnon_halo_face_element)
37546  {
37547  // Get and initial face element
37548  FiniteElement* ele_face_pt = 0;
37549 #ifdef PARANOID
37550  bool found_initial_face_element = false;
37551 #endif
37552 
37553  unsigned iface = 0;
37554  for (iface = 0; iface < nnon_halo_face_element; iface++)
37555  {
37556  ele_face_pt = non_halo_face_element_pt[iface];
37557  // If not done then take it as initial face element
37558  if (!face_element_done[ele_face_pt])
37559  {
37560 #ifdef PARANOID
37561  found_initial_face_element = true;
37562 #endif
37563  nsorted_face_elements++;
37564  iface++;
37565  break;
37566  }
37567  }
37568 
37569 #ifdef PARANOID
37570  if (!found_initial_face_element)
37571  {
37572  std::ostringstream error_message;
37573  error_message
37574  <<"Could not find an initial face element for the current segment\n";
37575  // << "----- Possible memory leak -----\n";
37576  throw OomphLibError(error_message.str(),
37577  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37578  OOMPH_EXCEPTION_LOCATION);
37579  }
37580 #endif
37581 
37582  // Local set of coordinates that are on the boundary
37583  // Set entries are ordered on first entry in vector which stores
37584  // the boundary coordinate so the vertices come out in order!
37585  std::set<Vector<double> > local_vertex_nodes;
37586 
37587  // Vector to store the vertices, transfer the sorted vertices from the
37588  // set (local) to this vector (local), --- including the z-value ---
37589  Vector<Vector<double> > local_tmp_vector_vertex_node;
37590 
37591  // Vector to store the target areas, uses the same approach as the
37592  // set for the local_vertex_nodes, ordered on first entry
37593  std::set<Vector<double> > sorted_target_areas;
37594 
37595  // Vector to store the target areas, used to transfer the sorted target
37596  // areas from "local_sorted_target_areas" set
37597  Vector<double> tmp_sorted_target_areas;
37598 
37599  // -----------------------------------------------------------------
37600  // Add the vertices of the initial face element to the set of
37601  // local sorted vertices
37602  // -----------------------------------------------------------------
37603  unsigned nnode = ele_face_pt->nnode();
37604  // Add the left-hand node to the set:
37605  // Boundary coordinate
37606  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
37607  vertex_coord[0] = bound_left[0];
37608 
37609  // Actual coordinates
37610  for(unsigned i=0;i<2;i++)
37611  {
37612  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
37613  }
37614  local_vertex_nodes.insert(vertex_coord);
37615 
37616  // Add the right-hand nodes to the set:
37617  // Boundary coordinate
37618  ele_face_pt->node_pt(nnode-1)->
37619  get_coordinates_on_boundary(bound,bound_right);
37620  vertex_coord[0] = bound_right[0];
37621 
37622  // Actual coordinates
37623  for(unsigned i=0;i<2;i++)
37624  {
37625  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
37626  }
37627  local_vertex_nodes.insert(vertex_coord);
37628 
37629  // The initial and final node on the set
37630  Node *first_node_pt = ele_face_pt->node_pt(0);
37631  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
37632 
37633  // Mark the current face element as done
37634  face_element_done[ele_face_pt] = true;
37635 
37636  // -------------------------------------------------------
37637  // Find the global index in the mesh of the face element
37638  // and use it to get its associated target area
37639  // -------------------------------------------------------
37640  // Container to store the zeta value (used as index) and
37641  // the associated target area of the element
37642  Vector<double> zeta_target_area_values(2);
37643 
37644  // Use the minimum zeta value to sort the target areas
37645  // along the boundary
37646  zeta_target_area_values[0] =
37647  std::min(bound_left[0], bound_right[0]);
37648 
37649  // Get the index of the face element on the current boundary
37650  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37651  // Get the "ef"-th element on the boundary
37652  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
37653 
37654 #ifdef PARANOID
37655  bool found_global_element_index = false;
37656 #endif
37657  for (unsigned eg = 0 ; eg < nele; eg++)
37658  {
37659  // Get the "eg-th" element
37660  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
37661 
37662  // Compare with the element on the boundary, if equal then
37663  // store the target area
37664  if (el_pt == el_compare_pt)
37665  {
37666  zeta_target_area_values[1] = target_area[eg];
37667 #ifdef PARANOID
37668  found_global_element_index = true;
37669 #endif
37670  break; // break the for (e < nele) global element
37671  } // if element_pt == element_compare_pt
37672  } // for nele (on complete mesh)
37673 
37674 #ifdef PARANOID
37675  if (!found_global_element_index)
37676  {
37677  std::ostringstream error_message;
37678  error_message
37679  << "The global index for the ("<< ef <<")-th face element "
37680  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37681  throw OomphLibError(error_message.str(),
37682  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37683  OOMPH_EXCEPTION_LOCATION);
37684  }
37685 #endif
37686 
37687  // Add the target areas to the sorted set
37688  sorted_target_areas.insert(zeta_target_area_values);
37689  // ------------------------------------------------------------------
37690 
37691  // Continue iterating if a new face element has been added to the
37692  // list
37693  bool face_element_added = false;
37694 
37695  // While a new face element has been added to the set of sorted
37696  // face elements then re-iterate
37697  do
37698  {
37699  // Start from the next face elements since we have already
37700  // added the previous one as the initial face element (any
37701  // previous face element had to be added on previous
37702  // iterations)
37703  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
37704  {
37705  face_element_added = false;
37706  ele_face_pt = non_halo_face_element_pt[iiface];
37707  if (!face_element_done[ele_face_pt])
37708  {
37709  // Get each individual node to check if they are contiguous
37710  nnode = ele_face_pt->nnode();
37711  Node* left_node_pt = ele_face_pt->node_pt(0);
37712  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
37713 
37714  if (left_node_pt == first_node_pt)
37715  {
37716  first_node_pt = right_node_pt;
37717  face_element_added = true;
37718  }
37719  else if (left_node_pt == last_node_pt)
37720  {
37721  last_node_pt = right_node_pt;
37722  face_element_added = true;
37723  }
37724  else if (right_node_pt == first_node_pt)
37725  {
37726  first_node_pt = left_node_pt;
37727  face_element_added = true;
37728  }
37729  else if (right_node_pt == last_node_pt)
37730  {
37731  last_node_pt = left_node_pt;
37732  face_element_added = true;
37733  }
37734 
37735  if (face_element_added)
37736  {
37737  // Add the left-hand node to the set:
37738  // Boundary coordinate
37739  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
37740  vertex_coord[0] = bound_left[0];
37741 
37742  // Actual coordinates
37743  for(unsigned i=0;i<2;i++)
37744  {
37745  vertex_coord[i+1] = left_node_pt->x(i);
37746  }
37747  local_vertex_nodes.insert(vertex_coord);
37748 
37749  // Add the right-hand nodes to the set:
37750  // Boundary coordinate
37751  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
37752  vertex_coord[0] = bound_right[0];
37753 
37754  // Actual coordinates
37755  for(unsigned i=0;i<2;i++)
37756  {
37757  vertex_coord[i+1] = right_node_pt->x(i);
37758  }
37759  local_vertex_nodes.insert(vertex_coord);
37760 
37761  // Mark as done only if one of its nodes has been
37762  // added to the list
37763  face_element_done[ele_face_pt] = true;
37764  nsorted_face_elements++;
37765 
37766  // -----------------------------------------------------
37767  // Find the global index in the mesh of the face element
37768  // and use it to get its associated target area
37769  // -----------------------------------------------------
37770  // Use the minimum zeta value to sort the target areas
37771  // along the boundary
37772  zeta_target_area_values[0] =
37773  std::min(bound_left[0], bound_right[0]);
37774 
37775  // Get the "ef"-th element on the boundary
37776  ef = face_element_index_on_boundary[ele_face_pt];
37777  FiniteElement *lel_pt = this->boundary_element_pt(bound, ef);
37778 
37779 #ifdef PARANOID
37780  found_global_element_index = false;
37781 #endif
37782  for (unsigned eg = 0 ; eg < nele; eg++)
37783  {
37784  // Get the "eg-th" element
37785  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
37786 
37787  // Compare with the element on the boundary, if equal then
37788  // store the target area
37789  if (lel_pt == lel_compare_pt)
37790  {
37791  zeta_target_area_values[1] = target_area[eg];
37792 #ifdef PARANOID
37793  found_global_element_index = true;
37794 #endif
37795  break; // break the for (e < nele) global element
37796  } // if element_pt == element_compare_pt
37797  } // for nele (on complete mesh)
37798 
37799 #ifdef PARANOID
37800  if (!found_global_element_index)
37801  {
37802  std::ostringstream error_message;
37803  error_message
37804  << "The global index for the ("<< ef <<")-th face element "
37805  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37806  throw OomphLibError(error_message.str(),
37807  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37808  OOMPH_EXCEPTION_LOCATION);
37809  }
37810 #endif
37811 
37812  // Add the target areas to the sorted set
37813  sorted_target_areas.insert(zeta_target_area_values);
37814 
37815  break;
37816  }
37817 
37818  } // if (!edge_done[edge])
37819  } // for (iiedge < nedges)
37820  }while(face_element_added &&
37821  (nsorted_face_elements < nnon_halo_face_element));
37822 
37823  // -----------------------------------------------------------------
37824  // At this point we already have a sorted set of nodes and
37825  // can be used to peform the unrefinement and refinement procedures
37826  // -----------------------------------------------------------------
37827 
37828  // Get the number of nodes on the list
37829  const unsigned nlocal_nodes = local_vertex_nodes.size();
37830  // Change representation to vector for easy of handling ...
37831  local_tmp_vector_vertex_node.resize(nlocal_nodes);
37832 
37833  // Copy the vertices of the nodes
37834  unsigned counter = 0;
37835  std::set<Vector<double> >::iterator it_vertex;
37836  for (it_vertex = local_vertex_nodes.begin();
37837  it_vertex != local_vertex_nodes.end();
37838  it_vertex++)
37839  {
37840  local_tmp_vector_vertex_node[counter].resize(3);
37841  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
37842  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
37843  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
37844  counter++;
37845  }
37846 
37847  // ... same for the info. related with the target areas (turn
37848  // into vector)
37849  const unsigned ntarget_areas = sorted_target_areas.size();
37850  tmp_sorted_target_areas.resize(ntarget_areas);
37851  counter = 0;
37852  std::set<Vector<double> >::iterator it_area;
37853  for(it_area = sorted_target_areas.begin();
37854  it_area != sorted_target_areas.end();
37855  ++it_area)
37856  {
37857  tmp_sorted_target_areas[counter] = (*it_area)[1];
37858  ++counter;
37859  }
37860 
37861 #ifdef PARANOID
37862  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
37863  {
37864  std::ostringstream error_message;
37865  error_message
37866  << "The boundary (" << bound << ") was split during the "
37867  << "distribution process.\n"
37868  << "The problem is in the association of the target areas with the\n"
37869  << "elements that gave rise to the vertex coordinates.\n"
37870  << "The number of local nodes (" << nlocal_nodes
37871  << "), on the 'sub-polyline', is not\n"
37872  << "according with the number of target "
37873  << "areas ("<< ntarget_areas << ")\nfor that number of nodes.\n"
37874  << "The target areas number MUST be equal to the number of\n"
37875  << "local nodes minus one\n\n";
37876  throw OomphLibError(error_message.str(),
37877  OOMPH_CURRENT_FUNCTION,
37878  OOMPH_EXCEPTION_LOCATION);
37879  }
37880 #endif
37881 
37882  // -------------------------------------------------------------------
37883  // Update the vertices along the boundary using the target area
37884  // to define the distance among them
37885  // -------------------------------------------------------------------
37886 
37887  // Tolerance below which the middle point can be deleted
37888  // (ratio of deflection to element length)
37889  double unrefinement_tolerance=
37890  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
37891 
37892  // Apply unrefinement
37893  bool unrefinement_applied =
37894  unrefine_boundary_constrained_by_target_area(
37895  bound, chunk, local_tmp_vector_vertex_node,
37896  unrefinement_tolerance, tmp_sorted_target_areas);
37897 
37898  // Tolerance for refinement
37899  double refinement_tolerance=
37900  polygon_pt->polyline_pt(p)->refinement_tolerance();
37901 
37902  // Apply refinement
37903  bool refinement_applied =
37904  refine_boundary_constrained_by_target_area(
37905  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
37906  refinement_tolerance, tmp_sorted_target_areas);
37907 
37908  // Clear the local containter to recover the nodes ordered using the
37909  // zeta value
37910  local_vertex_nodes.clear();
37911 
37912  // At the end of each unrefinement/refinement step store the new nodes
37913  // on the set that will give rise to the vertices of the new polyline
37914  // representation
37915  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
37916  for (unsigned i = 0; i < nnew_nodes; i++)
37917  {
37918  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
37919  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
37920  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
37921  vertex_nodes.insert(vertex_coord); // Global container
37922  local_vertex_nodes.insert(vertex_coord);
37923  }
37924 
37925  // Update the flag to indicate whether an unrefinement or
37926  // refinement was applied
37927  update_was_performed = (unrefinement_applied || refinement_applied);
37928 
37929 #ifdef OOMPH_HAS_MPI
37930  if (this->is_mesh_distributed())
37931  {
37932  // Add the set of vertices for the boundary, this will help to
37933  // detect if we need to deal with sub-boundaries
37934  sub_vertex_nodes.push_back(local_vertex_nodes);
37935  // Increase the counter for sub-boundaries
37936  nsub_boundaries++;
37937  }
37938 #endif
37939 
37940  } // while(nsorted_face_elements < nnon_halo_face_element)
37941 
37942  // Now turn into vector for ease of handling...
37943  unsigned npoly_vertex = vertex_nodes.size();
37944  // This will store all the vertices whether the boundary was split
37945  // or not
37946  tmp_vector_vertex_node.resize(npoly_vertex);
37947  unsigned count = 0;
37948  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
37949  it!=vertex_nodes.end(); ++it)
37950  {
37951  tmp_vector_vertex_node[count].resize(3);
37952  tmp_vector_vertex_node[count][0] = (*it)[0];
37953  tmp_vector_vertex_node[count][1] = (*it)[1];
37954  tmp_vector_vertex_node[count][2] = (*it)[2];
37955  ++count;
37956  }
37957 
37958 #ifdef OOMPH_HAS_MPI
37959  // --------- Stuff for the sub_boundaries ----- Begin section ---------
37960 #ifdef PARANOID
37961  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
37962  if (nsub_boundaries_set != nsub_boundaries)
37963  {
37964  std::ostringstream error_message;
37965  error_message
37966  << "The number of found sub-boundaries and the number of counted\n"
37967  << "sub-boundaries are different:\n"
37968  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
37969  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
37970  throw OomphLibError(error_message.str(),
37971  OOMPH_CURRENT_FUNCTION,
37972  OOMPH_EXCEPTION_LOCATION);
37973  }
37974 #endif
37975 
37976  // Are there sub-boundaries (only appear in distributed meshes)
37977  if (this->is_mesh_distributed() && nsub_boundaries > 1)
37978  {
37979  // Mark the boundary as been splitted in the partition process
37980  this->Boundary_was_splitted[bound] = true;
37981  // Resize the vector to store the info. of sub-boundaries
37982  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
37983  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
37984  {
37985  // Turn info. into vector for ease of handling...
37986  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
37987  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
37988  unsigned subcount = 0;
37989  std::set<Vector<double> >::iterator subit;
37990  for(subit = sub_vertex_nodes[isub].begin();
37991  subit != sub_vertex_nodes[isub].end(); ++subit)
37992  {
37993  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
37994  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
37995  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
37996  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
37997  ++subcount;
37998  }
37999  }
38000  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38001  // --------- Stuff for the sub_boundaries ----- End section ------------
38002 #endif // OOMPH_HAS_MPI
38003 
38004  // For further processing the three-dimensional vector has to be
38005  // reduced to a two-dimensional vector
38006  unsigned n_vertex=tmp_vector_vertex_node.size();
38007 
38008  // Resize the vector for vectices
38009  vector_vertex_node.resize(n_vertex);
38010  for(unsigned i=0;i<n_vertex;i++)
38011  {
38012  vector_vertex_node[i].resize(2);
38013  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
38014  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
38015  }
38016 
38017 #ifdef OOMPH_HAS_MPI
38018  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38019  // Verify if need to deal with sub_boundaries
38020  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38021  {
38022  // For further processing the three-dimensional vector
38023  // has to be reduced to a two-dimensional vector
38024  // Resize the vector to store the info. of sub-boundaries
38025  sub_vector_vertex_node.resize(nsub_boundaries);
38026  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38027  {
38028  const unsigned subn_vertex =
38029  sub_tmp_vector_vertex_node[isub].size();
38030  // Resize the vector for vectices
38031  sub_vector_vertex_node[isub].resize(subn_vertex);
38032  for(unsigned i=0;i<subn_vertex;i++)
38033  {
38034  sub_vector_vertex_node[isub][i].resize(2);
38035  sub_vector_vertex_node[isub][i][0]=
38036  sub_tmp_vector_vertex_node[isub][i][1];
38037  sub_vector_vertex_node[isub][i][1]=
38038  sub_tmp_vector_vertex_node[isub][i][2];
38039  }
38040  }
38041  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38042 
38043  // We already have the info. for the sub-boundaries (if necessary)
38044  // and then we can create the sub-boundaries representations to
38045  // ease the generation of the mesh by Triangle
38046 
38047  // --------- Stuff for the sub_boundaries ----- End section ------------
38048  #endif // OOMPH_HAS_MPI
38049 
38050  // --------------------------------------------------------------------
38051  // Check for contiguousness
38052  // --------------------------------------------------------------------
38053 #ifdef OOMPH_HAS_MPI
38054  // Only perform this checking if the mesh is not distributed. When
38055  // the mesh is distributed the polylines continuity is addressed
38056  // by the sort_polylines_helper() method
38057  if (!this->is_mesh_distributed())
38058 #endif
38059  {
38060  if ( p > 0 )
38061  {
38062  //Final end point of previous line
38063  Vector<double> final_vertex_of_previous_segment;
38064  unsigned n_prev_vertex =
38065  polygon_pt->curve_section_pt(p-1)->nvertex();
38066  final_vertex_of_previous_segment =
38067  polygon_pt->polyline_pt(p-1)->
38068  vertex_coordinate(n_prev_vertex-1);
38069 
38070  unsigned prev_seg_boundary_id =
38071  polygon_pt->curve_section_pt(p-1)->boundary_id();
38072 
38073  //Find the error between the final vertex of the previous
38074  //line and the first vertex of the current line
38075  double error = 0.0;
38076  for(unsigned i=0;i<2;i++)
38077  {
38078  const double dist =
38079  final_vertex_of_previous_segment[i] -
38080  (*vector_vertex_node.begin())[i];
38081  error += dist*dist;
38082  }
38083  error = sqrt(error);
38084 
38085  //If the error is bigger than the tolerance then
38086  //we probably need to reverse, but better check
38088  {
38089  //Find the error between the final vertex of the previous
38090  //line and the last vertex of the current line
38091  double rev_error = 0.0;
38092  for(unsigned i=0;i<2;i++)
38093  {
38094  const double dist =
38095  final_vertex_of_previous_segment[i] -
38096  (*--vector_vertex_node.end())[i];
38097  rev_error += dist*dist;
38098  }
38099  rev_error = sqrt(rev_error);
38100 
38101  if(rev_error >
38103  {
38104  // It could be possible that the first segment be reversed
38105  // and we did not notice it because this check does not
38106  // apply for the first segment. We can verify if the first
38107  // segment is reversed by using the vertex number 1
38108  if (p == 1)
38109  {
38110  //Initial end point of previous line
38111  Vector<double> initial_vertex_of_previous_segment;
38112 
38113  initial_vertex_of_previous_segment =
38114  polygon_pt->polyline_pt(p-1)->
38115  vertex_coordinate(0);
38116 
38117  unsigned prev_seg_boundary_id =
38118  polygon_pt->curve_section_pt(p-1)->boundary_id();
38119 
38120  //Find the error between the initial vertex of the previous
38121  //line and the first vertex of the current line
38122  double error = 0.0;
38123  for(unsigned i=0;i<2;i++)
38124  {
38125  const double dist =
38126  initial_vertex_of_previous_segment[i] -
38127  (*vector_vertex_node.begin())[i];
38128  error += dist*dist;
38129  }
38130  error = sqrt(error); // Reversed only the previous one
38131 
38132  //If the error is bigger than the tolerance then
38133  //we probably need to reverse, but better check
38135  {
38136  //Find the error between the final vertex of the previous
38137  //line and the last vertex of the current line
38138  double rev_error = 0.0;
38139  for(unsigned i=0;i<2;i++)
38140  {
38141  const double dist =
38142  initial_vertex_of_previous_segment[i] -
38143  (*--vector_vertex_node.end())[i];
38144  rev_error += dist*dist;
38145  }
38146  rev_error = sqrt(rev_error); // Reversed both the current one and
38147  // the previous one
38148 
38149  if (rev_error >
38151  {
38152  std::ostringstream error_stream;
38153  error_stream
38154  <<"The distance between the first node of the current\n"
38155  <<"line segment (boundary "<<bound<<") and either end of "
38156  << "the previous line segment\n"
38157  << "(boundary "<<prev_seg_boundary_id<<") is bigger than "
38158  << "the desired tolerance "
38160  << ".\n"
38161  << "This suggests that the polylines defining the "
38162  << "polygonal\n"
38163  << "representation are not properly ordered.\n"
38164  << "Fail on last vertex of polyline: ("
38165  << prev_seg_boundary_id << ") and\n"
38166  << "first vertex of polyline (" << bound << ").\n"
38167  << "This should have failed when first trying to "
38168  << "construct the\npolygon.\n";
38169  throw OomphLibError(error_stream.str(),
38170  OOMPH_CURRENT_FUNCTION,
38171  OOMPH_EXCEPTION_LOCATION);
38172  }
38173  else
38174  {
38175  // Reverse both
38176  // Reverse the current vector to line up with the
38177  // previous one
38178  std::reverse(vector_vertex_node.begin(),
38179  vector_vertex_node.end());
38180 
38181  polygon_pt->polyline_pt(p-1)->reverse();
38182  }
38183  }
38184  else
38185  {
38186  // Reverse the previous one
38187  polygon_pt->polyline_pt(p-1)->reverse();
38188  }
38189 
38190  } // if p == 1
38191  else
38192  {
38193  std::ostringstream error_stream;
38194  error_stream
38195  <<"The distance between the first node of the current\n"
38196  <<"line segment (boundary " << bound << ") and either end of "
38197  <<"the previous line segment\n"
38198  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
38199  <<"desired tolerance " <<
38201  <<"This suggests that the polylines defining the polygonal\n"
38202  <<"representation are not properly ordered.\n"
38203  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
38204  << ") and\nfirst vertex of polyline ("<<bound << ").\n"
38205  << "This should have failed when first trying to construct"
38206  << " the polygon.\n";
38207  throw OomphLibError(error_stream.str(),
38208  OOMPH_CURRENT_FUNCTION,
38209  OOMPH_EXCEPTION_LOCATION);
38210  }
38211  }
38212  else
38213  {
38214  //Reverse the current vector to line up with the previous one
38215  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
38216  }
38217  } // error
38218 
38219  } // if ( p > 0 )
38220 
38221  } // if (!this->is_mesh_distributed())
38222 
38223  // --------------------------------------------------------------------
38224  // Update the polylines representation
38225  // --------------------------------------------------------------------
38226 
38227  // Always update the polylines representation, in a distributed
38228  // mesh it is necessary to update the polyline representation since
38229  // it may no longer have vertices (the boundary may not be part of
38230  // the domain in the current processor)
38231 
38232  // The new nunber of vertices
38233  n_vertex = vector_vertex_node.size();
38234 
38235  // Now update the polyline according to the new vertices
38236  TriangleMeshPolyLine *tmp_polyline_pt =
38237  new TriangleMeshPolyLine(vector_vertex_node,bound);
38238 
38239  // Create a temporal "curve section" version of the recently
38240  // created polyline
38241  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
38242 
38243  // Tolerance below which the middle point can be deleted (ratio of
38244  // deflection to element length)
38245  double unrefinement_tolerance=
38246  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38247 
38248  // Tolerance to add points
38249  double refinement_tolerance=
38250  polygon_pt->polyline_pt(p)->refinement_tolerance();
38251 
38252  // Establish refinement and unrefinement tolerance
38253  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38254  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38255 
38256  // Establish the maximum length constraint
38257  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38258  tmp_polyline_pt->set_maximum_length(maximum_length);
38259 
38260 #ifdef OOMPH_HAS_MPI
38261  // If the mesh is distributed check that the polyline still has
38262  // vertices
38263  if (this->is_mesh_distributed())
38264  {
38265  if (n_vertex >= 2)
38266  {
38267  // Pass the connection information from the old polyline to the
38268  // new one
38269  this->copy_connection_information(polygon_pt->polyline_pt(p),
38270  tmp_curve_section_pt);
38271  } // if (n_vertex >= 2)
38272  } // if (this->is_mesh_distributed())
38273  else
38274 #endif
38275  {
38276  // Pass the connection information from the old polyline to the
38277  // new one
38278  this->copy_connection_information(polygon_pt->polyline_pt(p),
38279  tmp_curve_section_pt);
38280  }
38281 
38282  // Now update the polyline according to the new vertices but first
38283  // check if the object is allowed to delete the representation or
38284  // if it should be done by other object
38285  bool delete_it_on_destructor = false;
38286 
38287  std::set<TriangleMeshCurveSection*>::iterator it =
38288  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38289 
38290  if (it!=this->Free_curve_section_pt.end())
38291  {
38292  this->Free_curve_section_pt.erase(it);
38293  delete polygon_pt->curve_section_pt(p);
38294  delete_it_on_destructor = true;
38295  }
38296 
38297  // -------------------------------------------------------
38298  // Copying the new representation
38299  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38300 
38301  // Update the Boundary - Polyline map
38302  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38303 
38304  if (delete_it_on_destructor)
38305  {
38306  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38307  }
38308 
38309 #ifdef OOMPH_HAS_MPI
38310  // --------- Stuff for the sub_boundaries ----- Begin section --------
38311  // Verify if need to deal with sub_boundaries
38312  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38313  {
38314  // Create temporary representations for the boundaries, only to
38315  // create the mesh when calling Triangle
38316 
38317  // Clear all previous stored data
38318  this->Boundary_subpolylines[bound].clear();
38319 
38320  // Create storage for the sub-boundaries
38321  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38322  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38323  {
38324  // Update the polyline according to the sub set of vertices,
38325  TriangleMeshPolyLine *sub_tmp_polyline_pt =
38326  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38327 
38328  // Add the sub-polyline to the container to represent the
38329  // boundary in parts
38330  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38331 
38332  // No need to send the unrefinement/refinement and maximum
38333  // length constraints since these are only temporary
38334  // representations. These polylines can be deleted once the new
38335  // polygons that represent the distributed domain have been
38336  // created
38337 
38338  } // for (isub < nsub_boundaries)
38339 
38340  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38341  // --------- Stuff for the sub_boundaries ----- End section ---------
38342  #endif // OOMPH_HAS_MPI
38343 
38344  // Delete the allocated memory for the geometric object that
38345  // represents the boundary
38346  delete mesh_geom_obj_pt;
38347 
38348  } // for (p < n_polyline)
38349 
38350  // Cleanup the face mesh
38351  for(unsigned p=0;p<n_polyline;p++)
38352  {
38353  face_mesh_pt[p]->flush_node_storage();
38354  delete face_mesh_pt[p];
38355  }
38356 
38357  return update_was_performed;
38358 
38359 }
38360 
38361 //======================================================================
38362 /// \short Updates the open curve but using the elements area instead
38363 /// of the default refinement and unrefinement methods
38364 //======================================================================
38365 template <class ELEMENT>
38368  const Vector<double> &target_area)
38369 {
38370  // Verify if there was a change on the open curve representation
38371  unsigned update_was_performed = false;
38372 
38373  const unsigned nele = this->nelement();
38374 
38375  // - Get the vertices along the boundaries and for each element identify
38376  // its associated target error.
38377  // - Get face mesh representation of each polyline.
38378  // - Get the vertices with the help of face elements.
38379  // - Find the global index in the mesh of the face element
38380  // and use it to get its associated target area.
38381 
38382  // Get the face mesh representation
38383  Vector<Mesh*> face_mesh_pt;
38384  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
38385 
38386  // Create vertices of the polylines by using the vertices of the
38387  // FaceElements
38388  Vector<double> vertex_coord(3); // zeta,x,y
38389  Vector<double> bound_left(1);
38390  Vector<double> bound_right(1);
38391 
38392  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38393 
38394  // Go for each curve section
38395  for(unsigned cs = 0; cs < ncurve_section; cs++)
38396  {
38397  // Get the MeshAsGeomObject representation just once per polyline,
38398  // this object is only used by the
38399  // refine_boundary_constrained_by_target_area() method. We get it
38400  // here to ensure that all processors (in a distributed context)
38401  // get this representation just once, and because an AllToAll MPI
38402  // communication is used in this calling
38403  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
38404 
38405  //Get the boundary id
38406  const unsigned bound =
38407  open_curve_pt->curve_section_pt(cs)->boundary_id();
38408 
38409  // Get the chunk number
38410  const unsigned chunk =
38411  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38412 
38413  /// Use a vector of vector for vertices and target areas to deal
38414  /// with the cases when the boundaries are split by the
38415  /// distribution process. Internal boundaries may be completely or
38416  /// partially overlapped by shared boundaries
38417 
38418  // Loop over the face elements and add their vertices (they are
38419  // automatically sorted because of the set)
38420  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38421 
38422  // Store the non halo elements and the element at the other side of
38423  // the boundary (whatever it be halo or not), the first will be the
38424  // ones from which we will get the vertices (in even position)
38425  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38426 
38427  // Map to store the index of the face element on a boundary
38428  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
38429 
38430  // Map to know the already sorted face elements
38431  std::map<FiniteElement*,bool> face_element_done;
38432 
38433  for(unsigned ef = 0; ef < nface_element; ++ef)
38434  {
38435  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38436 
38437  // Skip the halo elements (not used as base elements, only
38438  // include those elements whose element at the other side of the
38439  // boundary is non halo)
38440 #ifdef OOMPH_HAS_MPI
38441  if (this->is_mesh_distributed())
38442  {
38443  // Only work with non-halo elements
38444  if (ele_face_pt->is_halo()) {continue;}
38445  }
38446 #endif
38447 
38448  // Check if not already done
38449  if (!face_element_done[ele_face_pt])
38450  {
38451  // Add the element and look for the element at the other side
38452  // of the boundary to add it immediately after the new added
38453  // element
38454  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38455  // Create the map of the face element with the index
38456  face_element_index_on_boundary[ele_face_pt] = ef;
38457  // Mark the current element as done
38458  face_element_done[ele_face_pt] = true;
38459  // Get the number of nodes
38460  const unsigned nnodes = ele_face_pt->nnode();
38461  // Get the left and right node to look for the elements at the
38462  // other side of the boundary
38463  Node* left_node_pt = ele_face_pt->node_pt(0);
38464  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
38465 #ifdef PARANOID
38466  // Flag to know if the element at the other side of the
38467  // boundary was found
38468  bool found_other_side_face_ele = false;
38469 #endif
38470  for (unsigned iface = 0; iface < nface_element; iface++)
38471  {
38472  // Get the candidate face element
38473  FiniteElement *cele_face_pt =
38474  face_mesh_pt[cs]->finite_element_pt(iface);
38475  // Check if not already done
38476  if (!face_element_done[cele_face_pt])
38477  {
38478  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38479  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
38480  // Check if the nodes are the same
38481  if ((left_node_pt == cleft_node_pt &&
38482  right_node_pt == cright_node_pt) ||
38483  (left_node_pt == cright_node_pt &&
38484  right_node_pt == cleft_node_pt))
38485  {
38486  // Add the element to the storage
38487  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38488  // ... and mark the element as done
38489  face_element_done[cele_face_pt] = true;
38490  // Create the map of the face element with the index
38491  face_element_index_on_boundary[cele_face_pt] = iface;
38492 #ifdef PARANOID
38493  // Set the flag of found other side face element
38494  found_other_side_face_ele = true;
38495 #endif
38496  break;
38497  }
38498  }
38499  } // (iface < nface_element)
38500 
38501 #ifdef PARANOID
38502  if (!found_other_side_face_ele)
38503  {
38504  std::ostringstream error_message;
38505  error_message
38506  << "The face element at the other side of the boundary ("
38507  << bound << ") was not found!!\n"
38508  << "These are the nodes of the face element:\n"
38509  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
38510  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
38511  throw OomphLibError(error_message.str(),
38512  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38513  OOMPH_EXCEPTION_LOCATION);
38514  }
38515 #endif
38516  } // if (!face_ele_done[ele_face_pt])
38517 
38518  } // (ef < nface_element)
38519 
38520  // Clear the map of the already done face elements
38521  // This will be used to help sorting the face elements
38522  face_element_done.clear();
38523 
38524  // Set of coordinates that are on the boundary
38525  // The entries are sorted on first entry in vector which stores
38526  // the boundary coordinate so the vertices come out in order!
38527  std::set<Vector<double> > vertex_nodes;
38528 
38529  // Vector to store the vertices, transfer the sorted vertices from the
38530  // set to this vector, --- including the z-value ---
38531  Vector<Vector<double> > tmp_vector_vertex_node;
38532 
38533  // Vector to store the coordinates of the polylines, same as the
38534  // tmp_vector_vertex_node vector (after adding more nodes) but
38535  // --- without the z-value ---, used to re-generate the polylines
38536  Vector<Vector<double> > vector_vertex_node;
38537 
38538 #ifdef OOMPH_HAS_MPI
38539  // Indicates if the set of vertices give rise to a internal
38540  // boundary that will be used as shared boundary or as normal
38541  // internal boundary -- Only used to deal with internal boundaries
38542  // in a distributed scheme
38543  std::vector<bool> internal_to_shared_boundary;
38544 
38545  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38546  // Set of coordinates that are on the boundary (splitted boundary version)
38547  // The first vector is used to allocate the points for each sub-boundary
38548  // Set entries are ordered on first entry in vector which stores
38549  // the boundary coordinate so the vertices come out in order!
38550  Vector<std::set<Vector<double> > > sub_vertex_nodes;
38551 
38552  // Vector to store the vertices, transfer the sorted vertices from the
38553  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38554  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
38555 
38556  // Vector to store the coordinates of the polylines that will represent
38557  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38558  // but --- without the z-value ---, used to generate the sub-polylines
38559  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
38560 
38561  // --------- Stuff to deal with splitted boundaries ----------- End ------
38562 
38563 #endif // #ifdef OOMPH_HAS_MPI
38564 
38565  // Sort the face element, those that have both elements (one at
38566  // each side of the boundary) marked as nonhalo, and those with one
38567  // nonhalo an the other as halo
38568 
38569  // Number of done face elements
38570  unsigned nsorted_face_elements = 0;
38571 
38572 #ifdef OOMPH_HAS_MPI
38573  // Counter for sub_boundaries
38574  unsigned nsub_boundaries = 0;
38575 #endif // #ifdef OOMPH_HAS_MPI
38576 
38577  // Total number of non halo double face element
38578  const unsigned nnon_halo_doubled_face_ele =
38579  non_halo_doubled_face_element_pt.size();
38580 
38581  // Continue until all the face elements have been sorted
38582  // This while is to deal with the cases of splitted boundaries
38583  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
38584  {
38585  // Get and initial face element
38586  FiniteElement* ele_face_pt = 0;
38587  FiniteElement* repeated_ele_face_pt = 0;
38588 #ifdef PARANOID
38589  bool found_initial_face_element = false;
38590 #endif
38591 
38592  // Flag to know if we are working with a face element which the
38593  // face element at the other side of the boundary is also non
38594  // halo
38595  bool both_root_face_elements_are_nonhalo = false;
38596 
38597  unsigned iface = 0;
38598  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
38599  {
38600  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38601  // If not done then take it as initial face element
38602  if (!face_element_done[ele_face_pt])
38603  {
38604  // Mark it as done
38605  face_element_done[ele_face_pt] = true;
38606  // Get the other side boundary face element
38607  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
38608  // ... also mark as done the repeated face element
38609  face_element_done[repeated_ele_face_pt] = true;
38610 
38611 #ifdef OOMPH_HAS_MPI
38612  if (!repeated_ele_face_pt->is_halo())
38613  {both_root_face_elements_are_nonhalo = true;}
38614 #endif // #ifdef OOMPH_HAS_MPI
38615 
38616  // Plus two because internal boundaries have
38617  // two face elements per each edge
38618  nsorted_face_elements+=2;
38619  iface+=2;
38620 #ifdef PARANOID
38621  // And set the flag to true
38622  found_initial_face_element = true;
38623 #endif
38624  break;
38625  }
38626  }
38627 
38628 #ifdef PARANOID
38629  if (!found_initial_face_element)
38630  {
38631  std::ostringstream error_message;
38632  error_message
38633  <<"Could not find an initial face element for the current segment\n";
38634  throw OomphLibError(error_message.str(),
38635  OOMPH_CURRENT_FUNCTION,
38636  OOMPH_EXCEPTION_LOCATION);
38637  }
38638 #endif
38639 
38640  // Local set of coordinates that are on the boundary Set entries
38641  // are ordered on first entry in vector which stores the boundary
38642  // coordinate so the vertices come out in order
38643  std::set<Vector<double> > local_vertex_nodes;
38644 
38645  // Vector to store the vertices, transfer the sorted vertices from the
38646  // set (local) to this vector (local), --- including the z-value ---
38647  Vector<Vector<double> > local_tmp_vector_vertex_node;
38648 
38649  // Vector to store the target areas, uses the same approach as the
38650  // set for the local_vertex_nodes, ordered on first entry
38651  std::set<Vector<double> > sorted_target_areas;
38652 
38653  // Vector to store the target areas, used to transfer the sorted target
38654  // areas from "sorted_target_areas" set
38655  Vector<double> tmp_sorted_target_areas;
38656 
38657  // ------------------------------------------------------------------
38658  // Add the vertices of the initial face element to the set of local
38659  // sorted vertices
38660  // ------------------------------------------------------------------
38661  const unsigned nnode = ele_face_pt->nnode();
38662  // Add the left-hand node to the set:
38663  // Boundary coordinate
38664  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
38665  vertex_coord[0] = bound_left[0];
38666 
38667  // Actual coordinates
38668  for(unsigned i=0;i<2;i++)
38669  {
38670  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
38671  }
38672  local_vertex_nodes.insert(vertex_coord);
38673 
38674  // Add the right-hand node to the set:
38675  // Boundary coordinate
38676  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
38677  bound_right);
38678  vertex_coord[0] = bound_right[0];
38679 
38680  // Actual coordinates
38681  for(unsigned i=0;i<2;i++)
38682  {
38683  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
38684  }
38685  local_vertex_nodes.insert(vertex_coord);
38686 
38687  // The initial and final node on the set
38688  Node *first_node_pt = ele_face_pt->node_pt(0);
38689  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
38690 
38691  // -----------------------------------------------------
38692  // Find the global index in the mesh of the face element
38693  // and use it to get its associated target area
38694  // -----------------------------------------------------
38695  // Container to store the zeta value (used as index) and
38696  // the associated target area of the element
38697  Vector<double> zeta_target_area_values(2);
38698 
38699  // Use the minimum zeta value to sort the target areas
38700  // along the boundary
38701  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38702 
38703  // Get the index of the face element on the current boundary
38704  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38705  // Get the "ef"-th element on the boundary
38706  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
38707  double target_area_face_element = 0.0;
38708 
38709 #ifdef PARANOID
38710  bool found_global_element_index = false;
38711 #endif
38712  for (unsigned eg = 0 ; eg < nele; eg++)
38713  {
38714  // Get the "eg-th" element
38715  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38716 
38717  // Compare with the element on the boundary, if equal then
38718  // store the target area
38719  if (el_pt == el_compare_pt)
38720  {
38721  target_area_face_element = target_area[eg];
38722 #ifdef PARANOID
38723  found_global_element_index = true;
38724 #endif
38725  break; // break the for (eg < nele) global element
38726  } // if el_pt == el_compare_pt
38727  } // for nele (on complete mesh)
38728 
38729 #ifdef PARANOID
38730  if (!found_global_element_index)
38731  {
38732  std::ostringstream error_message;
38733  error_message
38734  << "The global index for the ("<< ef <<")-th face element "
38735  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38736  throw OomphLibError(error_message.str(),
38737  OOMPH_CURRENT_FUNCTION,
38738  OOMPH_EXCEPTION_LOCATION);
38739  }
38740 #endif
38741 
38742  // Get the index of the repeated face element on the current boundary
38743  const unsigned ref = face_element_index_on_boundary[repeated_ele_face_pt];
38744  FiniteElement *rel_pt = this->boundary_element_pt(bound, ref);
38745  double target_area_repeated_face_element = 0.0;
38746 
38747 #ifdef PARANOID
38748  bool found_global_repeated_element_index = false;
38749 #endif
38750  for (unsigned eg = 0 ; eg < nele; eg++)
38751  {
38752  // Get the "eg-th" element
38753  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38754 
38755  // Compare with the element on the boundary, if equal then
38756  // store the target area
38757  if (rel_pt == el_compare_pt)
38758  {
38759  target_area_repeated_face_element = target_area[eg];
38760 #ifdef PARANOID
38761  found_global_repeated_element_index = true;
38762 #endif
38763  break; // break the for (eg < nele) global element
38764  } // if rel_pt == el_compare_pt
38765  } // for nele (on complete mesh)
38766 
38767 #ifdef PARANOID
38768  if (!found_global_repeated_element_index)
38769  {
38770  std::ostringstream error_message;
38771  error_message
38772  << "The global index for the ("<< ref <<")-th face element "
38773  << "on\nthe ("<< bound <<")-th boundary was not found (repeated "
38774  << "face element)!!!";
38775  throw OomphLibError(error_message.str(),
38776  OOMPH_CURRENT_FUNCTION,
38777  OOMPH_EXCEPTION_LOCATION);
38778  }
38779 #endif
38780 
38781  // Choose the minimum target area from both elements, one at each side
38782  // of the edge on the boundary
38783  zeta_target_area_values[1]=std::min(target_area_face_element,
38784  target_area_repeated_face_element);
38785 
38786  // Add the target areas to the sorted set
38787  sorted_target_areas.insert(zeta_target_area_values);
38788  // ------------------------------------------------------------------
38789 
38790  // Continue iterating if a new face element has been added to the
38791  // list
38792  bool face_element_added = false;
38793 
38794  // While a new face element has been added to the set of sorted
38795  // face elements then re-iterate
38796  do
38797  {
38798  // Start from the next face elements since we have already
38799  // added the previous one as the initial face element (any
38800  // previous face element had to be added on previous
38801  // iterations)
38802  for (unsigned iiface=iface;
38803  iiface<nnon_halo_doubled_face_ele;iiface+=2)
38804  {
38805  face_element_added = false;
38806  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
38807 
38808  // Check that the face element with which we are working has
38809  // the same conditions as the root face element (both faces
38810  // are nonhalo or one face is halo and the other nonhalo)
38811 
38812  // Get the face element at the other side of the boundary
38813  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38814  bool both_face_elements_are_nonhalo = false;
38815 
38816 #ifdef OOMPH_HAS_MPI
38817  if (!repeated_ele_face_pt->is_halo())
38818  {both_face_elements_are_nonhalo = true;}
38819 #endif // #ifdef OOMPH_HAS_MPI
38820 
38821  if (!face_element_done[ele_face_pt] &&
38822  (both_face_elements_are_nonhalo ==
38823  both_root_face_elements_are_nonhalo))
38824  {
38825  // Get each individual node to check if they are contiguous
38826  const unsigned nlnode = ele_face_pt->nnode();
38827  Node* left_node_pt = ele_face_pt->node_pt(0);
38828  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
38829 
38830  if (left_node_pt == first_node_pt)
38831  {
38832  first_node_pt = right_node_pt;
38833  face_element_added = true;
38834  }
38835  else if (left_node_pt == last_node_pt)
38836  {
38837  last_node_pt = right_node_pt;
38838  face_element_added = true;
38839  }
38840  else if (right_node_pt == first_node_pt)
38841  {
38842  first_node_pt = left_node_pt;
38843  face_element_added = true;
38844  }
38845  else if (right_node_pt == last_node_pt)
38846  {
38847  last_node_pt = left_node_pt;
38848  face_element_added = true;
38849  }
38850 
38851  if (face_element_added)
38852  {
38853  // Add the left-hand node to the set:
38854  // Boundary coordinate
38855  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
38856  vertex_coord[0] = bound_left[0];
38857 
38858  // Actual coordinates
38859  for(unsigned i=0;i<2;i++)
38860  {
38861  vertex_coord[i+1] = left_node_pt->x(i);
38862  }
38863  local_vertex_nodes.insert(vertex_coord);
38864 
38865  // Add the right-hand nodes to the set:
38866  // Boundary coordinate
38867  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
38868  vertex_coord[0] = bound_right[0];
38869 
38870  // Actual coordinates
38871  for(unsigned i=0;i<2;i++)
38872  {
38873  vertex_coord[i+1] = right_node_pt->x(i);
38874  }
38875  local_vertex_nodes.insert(vertex_coord);
38876 
38877  // Mark as done only if one of its nodes has been
38878  // added to the list
38879  face_element_done[ele_face_pt] = true;
38880  // .. also mark as done the face element at the othe side of
38881  // the boundary
38882  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38883  face_element_done[repeated_ele_face_pt] = true;
38884  // ... and increase the number of sorted face elements
38885  nsorted_face_elements+=2;
38886 
38887  // -----------------------------------------------------
38888  // Find the global index in the mesh of the face element
38889  // and use it to get its associated target area
38890  // -----------------------------------------------------
38891  // Use the minimum zeta value to sort the target areas
38892  // along the boundary
38893  zeta_target_area_values[0] =
38894  std::min(bound_left[0], bound_right[0]);
38895 
38896  // Get the "ef"-th element on the boundary
38897  const unsigned lef = face_element_index_on_boundary[ele_face_pt];
38898  FiniteElement *lel_pt = this->boundary_element_pt(bound, lef);
38899 
38900 #ifdef PARANOID
38901  found_global_element_index = false;
38902 #endif
38903  for (unsigned eg = 0 ; eg < nele; eg++)
38904  {
38905  // Get the "eg-th" element
38906  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38907 
38908  // Compare with the element on the boundary, if equal then
38909  // store the target area
38910  if (lel_pt == lel_compare_pt)
38911  {
38912  target_area_face_element = target_area[eg];
38913 #ifdef PARANOID
38914  found_global_element_index = true;
38915 #endif
38916  break; // break the for (eg < nele) global element
38917  } // if lel_pt == lel_compare_pt
38918  } // for nele (on complete mesh)
38919 
38920 #ifdef PARANOID
38921  if (!found_global_element_index)
38922  {
38923  std::ostringstream error_message;
38924  error_message
38925  << "The global index for the ("<< lef <<")-th face element "
38926  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38927  throw OomphLibError(error_message.str(),
38928  OOMPH_CURRENT_FUNCTION,
38929  OOMPH_EXCEPTION_LOCATION);
38930  }
38931 #endif
38932 
38933  // Get the index of the repeated face element on the boundary
38934  const unsigned rlef =
38935  face_element_index_on_boundary[repeated_ele_face_pt];
38936  FiniteElement *rlel_pt = this->boundary_element_pt(bound, rlef);
38937 
38938 #ifdef PARANOID
38939  found_global_repeated_element_index = false;
38940 #endif
38941  for (unsigned eg = 0 ; eg < nele; eg++)
38942  {
38943  // Get the "eg-th" element
38944  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38945 
38946  // Compare with the element on the boundary, if equal then
38947  // store the target area
38948  if (rlel_pt == lel_compare_pt)
38949  {
38950  target_area_repeated_face_element = target_area[eg];
38951 #ifdef PARANOID
38952  found_global_repeated_element_index = true;
38953 #endif
38954  break; // break the for (eg < nele) global element
38955  } // if rlel_pt == el_compare_pt
38956  } // for nele (on complete mesh)
38957 
38958 #ifdef PARANOID
38959  if (!found_global_repeated_element_index)
38960  {
38961  std::ostringstream error_message;
38962  error_message
38963  << "The global index for the ("<< rlef <<")-th face element "
38964  << "on\nthe ("<< bound <<")-th boundary was not found "
38965  << "(repeated face element)!!!";
38966  throw OomphLibError(error_message.str(),
38967  OOMPH_CURRENT_FUNCTION,
38968  OOMPH_EXCEPTION_LOCATION);
38969  }
38970 #endif
38971 
38972  // Choose the minimum target area from both elements, one
38973  // at each side of the edge on the boundary
38974  zeta_target_area_values[1] =
38975  std::min(target_area_face_element,
38976  target_area_repeated_face_element);
38977 
38978  // Add the target areas to the sorted set
38979  sorted_target_areas.insert(zeta_target_area_values);
38980 
38981  break;
38982  }
38983 
38984  } // if (!face_element_done[[ele_face_pt])
38985  } // for (iiface<nnon_halo_doubled_face_ele)
38986  }while(face_element_added &&
38987  (nsorted_face_elements < nnon_halo_doubled_face_ele));
38988 
38989  // -------------------------------------------------------------
38990  // At this point we already have a sorted set of nodes and can
38991  // be used to peform the unrefinement and refinement procedures
38992  // -------------------------------------------------------------
38993 
38994  // Get the number of nodes on the list
38995  const unsigned nlocal_nodes = local_vertex_nodes.size();
38996  // Change representation to vector for easy of handling ...
38997  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38998 
38999  // Copy the vertices of the nodes
39000  unsigned counter = 0;
39001  std::set<Vector<double> >::iterator it_vertex;
39002  for (it_vertex = local_vertex_nodes.begin();
39003  it_vertex != local_vertex_nodes.end();
39004  it_vertex++)
39005  {
39006  local_tmp_vector_vertex_node[counter].resize(3);
39007  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39008  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39009  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39010  counter++;
39011  }
39012 
39013  // ... same for the info. related with the target areas (turn
39014  // into vector)
39015  const unsigned ntarget_areas = sorted_target_areas.size();
39016  tmp_sorted_target_areas.resize(ntarget_areas);
39017  counter = 0;
39018  std::set<Vector<double> >::iterator it_area;
39019  for(it_area = sorted_target_areas.begin();
39020  it_area != sorted_target_areas.end();
39021  ++it_area)
39022  {
39023  tmp_sorted_target_areas[counter] = (*it_area)[1];
39024  ++counter;
39025  }
39026 
39027 #ifdef PARANOID
39028  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
39029  {
39030  std::ostringstream error_message;
39031  error_message
39032  << "The boundary (" << bound << ") was split during the "
39033  << "distribution process.\n"
39034  << "The problem comes when associating the target areas with the "
39035  << "elements that gave\nrise to the vertex coordinates.\n"
39036  << "The number of local nodes on the 'sub-polyline' ("
39037  << nlocal_nodes << ") is not according with the number of target\n"
39038  << "areas ("<< ntarget_areas << ") for that number of nodes.\n"
39039  << "The target areas number must be equal to the number of nodes-1\n";
39040  throw OomphLibError(error_message.str(),
39041  OOMPH_CURRENT_FUNCTION,
39042  OOMPH_EXCEPTION_LOCATION);
39043  }
39044 #endif
39045 
39046  // The unrefinement and refinement process needs to be applied
39047  // from the bottom-left node since the internal open curve could
39048  // lie on the shared boundaries
39049  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
39050  local_tmp_vector_vertex_node[0][2])
39051  {
39052  std::reverse(local_tmp_vector_vertex_node.begin(),
39053  local_tmp_vector_vertex_node.end());
39054  std::reverse(tmp_sorted_target_areas.begin(),
39055  tmp_sorted_target_areas.end());
39056  }
39057  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
39058  local_tmp_vector_vertex_node[0][2])
39059  {
39060  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
39061  local_tmp_vector_vertex_node[0][1])
39062  {
39063  std::reverse(local_tmp_vector_vertex_node.begin(),
39064  local_tmp_vector_vertex_node.end());
39065  std::reverse(tmp_sorted_target_areas.begin(),
39066  tmp_sorted_target_areas.end());
39067  }
39068  }
39069 
39070  // ------------------------------------------------------------
39071  // Create the vertices along the boundary using the target
39072  // area to define the distance among them
39073  // ------------------------------------------------------------
39074 
39075  // Tolerance below which the middle point can be deleted
39076  // (ratio of deflection to element length)
39077  double unrefinement_tolerance=
39078  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39079 
39080  // Apply unrefinement
39081  bool unrefinement_applied =
39082  unrefine_boundary_constrained_by_target_area(
39083  bound, chunk, local_tmp_vector_vertex_node,
39084  unrefinement_tolerance, tmp_sorted_target_areas);
39085 
39086  // Tolerance for refinement
39087  double refinement_tolerance=
39088  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39089 
39090  // Apply refinement
39091  bool refinement_applied =
39092  refine_boundary_constrained_by_target_area(
39093  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
39094  refinement_tolerance, tmp_sorted_target_areas);
39095 
39096  // Clear the local containter to recover the nodes ordered using
39097  // the zeta value
39098  local_vertex_nodes.clear();
39099 
39100  // At the end of each unrefinement/refinement step store the new
39101  // nodes on the set that will give rise to the vertices of the
39102  // new polyline representation
39103  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39104  for (unsigned i = 0; i < nnew_nodes; i++)
39105  {
39106  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39107  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39108  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39109  vertex_nodes.insert(vertex_coord); // Global container
39110  local_vertex_nodes.insert(vertex_coord);
39111  }
39112 
39113  // Update the flag to indicate whether an unrefinement or
39114  // refinement was applied
39115  update_was_performed = (unrefinement_applied || refinement_applied);
39116 
39117 #ifdef OOMPH_HAS_MPI
39118  if (this->is_mesh_distributed())
39119  {
39120  // Add the set of vertices for the boundary, this will help to
39121  // detect if we need to deal with sub_boundaries and
39122  // sub_polylines representations
39123  sub_vertex_nodes.push_back(local_vertex_nodes);
39124  // Increase the counter for sub_boundaries
39125  nsub_boundaries++;
39126 
39127  // Mark if the polyline created by these vertices will be used
39128  // as a shared boundary or as an internal boundary
39129  if (both_root_face_elements_are_nonhalo)
39130  {internal_to_shared_boundary.push_back(false);}
39131  else
39132  {internal_to_shared_boundary.push_back(true);}
39133  }
39134 #endif
39135 
39136  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39137  // This while is in charge of sorting all the face elements to
39138  // create the new representation of the polyline (also deals
39139  // with the sub-boundary cases)
39140 
39141  // Now turn into vector for ease of handling...
39142  const unsigned npoly_vertex = vertex_nodes.size();
39143  tmp_vector_vertex_node.resize(npoly_vertex);
39144  unsigned count = 0;
39145  for (std::set<Vector<double> >::iterator it = vertex_nodes.begin();
39146  it!=vertex_nodes.end(); ++it)
39147  {
39148  tmp_vector_vertex_node[count].resize(3);
39149  tmp_vector_vertex_node[count][0] = (*it)[0];
39150  tmp_vector_vertex_node[count][1] = (*it)[1];
39151  tmp_vector_vertex_node[count][2] = (*it)[2];
39152  ++count;
39153  }
39154 
39155 #ifdef OOMPH_HAS_MPI
39156  // Check that the number of set of vertices marked to be part of a
39157  // shared boundary or of an internal boundaries be the same as the
39158  // total number of sub-boundaries
39159 #ifdef PARANOID
39160  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39161  const unsigned ninternal_to_shared_boundaries =
39162  internal_to_shared_boundary.size();
39163  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39164  {
39165  std::ostringstream error_message;
39166  error_message
39167  << "The number of found sub-boundaries and the number of marked "
39168  << "internal\nboundaries are different\n"
39169  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39170  << "Number of marked internal boundaries: ("
39171  << ninternal_to_shared_boundaries << ")\n\n";
39172  throw OomphLibError(error_message.str(),
39173  OOMPH_CURRENT_FUNCTION,
39174  OOMPH_EXCEPTION_LOCATION);
39175  }
39176 #endif
39177 
39178  // --------- Stuff for the sub_boundaries ----- Begin section -------
39179 #ifdef PARANOID
39180  if (nsub_boundaries_set != nsub_boundaries)
39181  {
39182  std::ostringstream error_message;
39183  error_message
39184  << "The number of found sub-boundaries and the number of counted\n"
39185  << "sub-boundaries are different:\n"
39186  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39187  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
39188  throw OomphLibError(error_message.str(),
39189  OOMPH_CURRENT_FUNCTION,
39190  OOMPH_EXCEPTION_LOCATION);
39191  }
39192 #endif
39193 
39194  // Verify if need to deal with sub_boundaries
39195  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39196  {
39197  // Mark the boundary as been splitted in the partition process
39198  this->Boundary_was_splitted[bound] = true;
39199 
39200  // Resize the vector to store the info. of sub-boundaries
39201  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39202  // Loop over the sub-boundaries
39203  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39204  {
39205  // Turn info. into vector for ease of handling...
39206  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39207  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39208  unsigned subcount = 0;
39209  std::set<Vector<double> >::iterator subit;
39210  for(subit = sub_vertex_nodes[isub].begin();
39211  subit != sub_vertex_nodes[isub].end(); ++subit)
39212  {
39213  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39214  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39215  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39216  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39217  ++subcount;
39218  }
39219  }
39220  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39221  // --------- Stuff for the sub_boundaries ----- End section ----------
39222 #endif // OOMPH_HAS_MPI
39223 
39224  // For further processing the three-dimensional vector has to be
39225  // reduced to a two-dimensional vector
39226  unsigned n_vertex=tmp_vector_vertex_node.size();
39227 
39228  // Resize the vector for vectices
39229  vector_vertex_node.resize(n_vertex);
39230  for(unsigned i=0;i<n_vertex;i++)
39231  {
39232  vector_vertex_node[i].resize(2);
39233  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
39234  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
39235  }
39236 
39237 #ifdef OOMPH_HAS_MPI
39238  // --------- Stuff for the sub_boundaries ----- Begin section -------
39239  // Verify if need to deal with sub_boundaries
39240  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39241  {
39242  // For further processing the three-dimensional vector has to be
39243  // reduced to a two-dimensional vector
39244  // Resize the vector to store the info. of sub-boundaries
39245  sub_vector_vertex_node.resize(nsub_boundaries);
39246  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39247  {
39248  const unsigned subn_vertex =
39249  sub_tmp_vector_vertex_node[isub].size();
39250  // Resize the vector for vectices
39251  sub_vector_vertex_node[isub].resize(subn_vertex);
39252  for(unsigned i=0;i<subn_vertex;i++)
39253  {
39254  sub_vector_vertex_node[isub][i].resize(2);
39255  sub_vector_vertex_node[isub][i][0]=
39256  sub_tmp_vector_vertex_node[isub][i][1];
39257  sub_vector_vertex_node[isub][i][1]=
39258  sub_tmp_vector_vertex_node[isub][i][2];
39259  }
39260  }
39261  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39262 
39263  // We already have the info. for the sub-boundaries (if necessary)
39264  // and then we can create the sub-boundaries representations to
39265  // ease the generation of the mesh by Triangle
39266 
39267  // --------- Stuff for the sub_boundaries ----- End section ---------
39268 #endif // OOMPH_HAS_MPI
39269 
39270  // ------------------------------------------------------------------
39271  // Check for contiguousness
39272  // ------------------------------------------------------------------
39273 #ifdef OOMPH_HAS_MPI
39274  // Only perform this checking if the mesh is not distributed When
39275  // the mesh is distributed the polylines continuity is addressed by
39276  // the sort_polylines_helper() method
39277  if (!this->is_mesh_distributed())
39278 #endif
39279  {
39280  if ( cs > 0 )
39281  {
39282  //Final end point of previous line
39283  Vector<double> final_vertex_of_previous_segment;
39284  unsigned n_prev_vertex =
39285  open_curve_pt->curve_section_pt(cs-1)->nvertex();
39286  final_vertex_of_previous_segment =
39287  open_curve_pt->polyline_pt(cs-1)->
39288  vertex_coordinate(n_prev_vertex-1);
39289 
39290  unsigned prev_seg_boundary_id =
39291  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39292 
39293  //Find the error between the final vertex of the previous
39294  //line and the first vertex of the current line
39295  double error = 0.0;
39296  for(unsigned i=0;i<2;i++)
39297  {
39298  const double dist =
39299  final_vertex_of_previous_segment[i] -
39300  (*vector_vertex_node.begin())[i];
39301  error += dist*dist;
39302  }
39303  error = sqrt(error);
39304 
39305  //If the error is bigger than the tolerance then
39306  //we probably need to reverse, but better check
39308  {
39309  //Find the error between the final vertex of the previous
39310  //line and the last vertex of the current line
39311  double rev_error = 0.0;
39312  for(unsigned i=0;i<2;i++)
39313  {
39314  const double dist =
39315  final_vertex_of_previous_segment[i] -
39316  (*--vector_vertex_node.end())[i];
39317  rev_error += dist*dist;
39318  }
39319  rev_error = sqrt(rev_error);
39320 
39321  if(rev_error >
39323  {
39324  // It could be possible that the first segment be reversed and we
39325  // did not notice it because this check does not apply for the
39326  // first segment. We can verify if the first segment is reversed
39327  // by using the vertex number 1
39328  if (cs == 1)
39329  {
39330  //Initial end point of previous line
39331  Vector<double> initial_vertex_of_previous_segment;
39332 
39333  initial_vertex_of_previous_segment =
39334  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
39335 
39336  unsigned prev_seg_boundary_id =
39337  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39338 
39339  //Find the error between the initial vertex of the previous
39340  //line and the first vertex of the current line
39341  double error = 0.0;
39342  for(unsigned i=0;i<2;i++)
39343  {
39344  const double dist =
39345  initial_vertex_of_previous_segment[i] -
39346  (*vector_vertex_node.begin())[i];
39347  error += dist*dist;
39348  }
39349  error = sqrt(error); // Reversed only the previous one
39350 
39351  //If the error is bigger than the tolerance then
39352  //we probably need to reverse, but better check
39354  {
39355  //Find the error between the final vertex of the previous
39356  //line and the last vertex of the current line
39357  double rev_error = 0.0;
39358  for(unsigned i=0;i<2;i++)
39359  {
39360  const double dist =
39361  initial_vertex_of_previous_segment[i] -
39362  (*--vector_vertex_node.end())[i];
39363  rev_error += dist*dist;
39364  }
39365  rev_error = sqrt(rev_error); // Reversed both the current
39366  // one and the previous one
39367 
39368  if (rev_error >
39370  {
39371  std::ostringstream error_stream;
39372  error_stream
39373  <<"The distance between the first node of the current\n"
39374  <<"line segment (boundary "<<bound<<") and either end of "
39375  <<"the previous line segment\n"
39376  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
39377  << " the desired tolerance " <<
39379  <<"This suggests that the polylines defining the polygonal\n"
39380  <<"representation are not properly ordered.\n"
39381  <<"Fail on last vertex of polyline: ("
39382  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
39383  <<bound<< ").\nThis should have failed when first trying to "
39384  <<"construct the\npolygon.\n";
39385  throw OomphLibError(error_stream.str(),
39386  OOMPH_CURRENT_FUNCTION,
39387  OOMPH_EXCEPTION_LOCATION);
39388  }
39389  else
39390  {
39391  // Reverse both
39392  // Reverse the current vector to line up with the previous one
39393  std::reverse(vector_vertex_node.begin(),
39394  vector_vertex_node.end());
39395  open_curve_pt->polyline_pt(cs-1)->reverse();
39396  }
39397  }
39398  else
39399  {
39400  // Reverse the previous one
39401  open_curve_pt->polyline_pt(cs-1)->reverse();
39402  }
39403 
39404  } // if (cs == 1)
39405  else
39406  {
39407  std::ostringstream error_stream;
39408  error_stream
39409  <<"The distance between the first node of the current\n"
39410  <<"line segment (boundary " << bound << ") and either end of "
39411  <<"the previous line segment\n"
39412  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
39413  <<"desired tolerance " <<
39415  <<"This suggests that the polylines defining the polygonal\n"
39416  <<"representation are not properly ordered.\n"
39417  <<"Fail on last vertex of polyline: ("<<prev_seg_boundary_id
39418  <<") and\nfirst vertex of polyline (" <<bound << ").\n"
39419  <<"This should have failed when first trying to construct\n"
39420  << "the polygon.\n";
39421  throw OomphLibError(error_stream.str(),
39422  OOMPH_CURRENT_FUNCTION,
39423  OOMPH_EXCEPTION_LOCATION);
39424  }
39425  }
39426  else
39427  {
39428  //Reverse the current vector to line up with the previous one
39429  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
39430  }
39431 
39432  }
39433 
39434  } // if (cs > 0)
39435 
39436  } // if (!this->is_mesh_distributed())
39437 
39438  // ---------------------------------------------------------------
39439  // Update the polylines representation
39440  // ---------------------------------------------------------------
39441  // Always update the polylines representation, in a distributed
39442  // mesh it is necessary to update the polyline representation since
39443  // it may no longer have vertices (the boundary may not be part of
39444  // the domain in the current processor)
39445 
39446  // The new number of vertices
39447  n_vertex = vector_vertex_node.size();
39448 
39449  // Update the polyline according to the new vertices
39450  TriangleMeshPolyLine *tmp_polyline_pt =
39451  new TriangleMeshPolyLine(vector_vertex_node,bound);
39452 
39453  // Create a temporal "curve section" version of the recently
39454  // created polyline
39455  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
39456 
39457  // Tolerance below which the middle point can be deleted (ratio of
39458  // deflection to element length)
39459  double unrefinement_tolerance=
39460  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39461 
39462  // Tolerance to add points
39463  double refinement_tolerance=
39464  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39465 
39466  // Establish refinement and unrefinement tolerance
39467  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39468  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39469 
39470  // Establish the maximum length constraint
39471  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39472  tmp_polyline_pt->set_maximum_length(maximum_length);
39473 
39474 #ifdef OOMPH_HAS_MPI
39475  // If the mesh is distributed check that the polyline still has
39476  // vertices
39477  if (this->is_mesh_distributed())
39478  {
39479  if (n_vertex >= 2)
39480  {
39481  // Pass the connection information from the old polyline to
39482  // the new one
39483  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39484  tmp_curve_section_pt);
39485  } // if (n_vertex >= 2)
39486  } // if (this->is_mesh_distributed())
39487  else
39488 #endif
39489  {
39490  // Pass the connection information from the old polyline to the
39491  // new one
39492  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39493  tmp_curve_section_pt);
39494  }
39495 
39496  // Now update the polyline according to the new vertices but first
39497  // check if the object is allowed to delete the representation or
39498  // if it should be done by other object
39499  bool delete_it_on_destructor = false;
39500 
39501  std::set<TriangleMeshCurveSection*>::iterator it =
39502  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39503 
39504  if (it!=this->Free_curve_section_pt.end())
39505  {
39506  this->Free_curve_section_pt.erase(it);
39507  delete open_curve_pt->curve_section_pt(cs);
39508  delete_it_on_destructor = true;
39509  }
39510 
39511  // -------------------------------------------------------------
39512  // Copying the new representation
39513  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39514 
39515  // Update the Boundary - Polyline map
39516  this->Boundary_curve_section_pt[bound] =
39517  open_curve_pt->curve_section_pt(cs);
39518 
39519  if (delete_it_on_destructor)
39520  {
39521  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39522  }
39523 
39524 #ifdef OOMPH_HAS_MPI
39525  // If there are not sub-boundaries mark the boundary if need to be
39526  // trated as shared or as internal boundary
39527  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39528  {
39529  // Clear all previous stored data
39530  this->Boundary_marked_as_shared_boundary[bound].clear();
39531 
39532  // .. and store the flag for the boundary
39533  this->Boundary_marked_as_shared_boundary[bound].push_back(
39534  internal_to_shared_boundary[0]);
39535  }
39536  // --------- Stuff for the sub_boundaries ----- Begin section --------
39537  // Verify if need to deal with sub_boundaries
39538  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39539  {
39540  // Create temporary representations for the boundaries, only to
39541  // create the mesh when calling Triangle
39542 
39543  // Clear all previous stored data
39544  this->Boundary_subpolylines[bound].clear();
39545  // Now create storage for the sub-boundaries
39546  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39547 
39548  // Clear all previous stored data
39549  this->Boundary_marked_as_shared_boundary[bound].clear();
39550  // Create storage to mark the internal boundaries as shared
39551  // boundaries
39552  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39553  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39554  {
39555  // Now update the polyline according to the sub set of
39556  // vertices, set the chunk number of the polyline
39557  TriangleMeshPolyLine *sub_tmp_polyline_pt =
39558  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39559 
39560  // Add the sub-polyline to the container to represent the
39561  // boundary in parts
39562  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39563 
39564  // Copy the flag that mark the boundary as internal or as
39565  // shared bound
39566  this->Boundary_marked_as_shared_boundary[bound][isub] =
39567  internal_to_shared_boundary[isub];
39568 
39569  // No need to send the unrefinement/refinement and maximum
39570  // length constraints since these are only temporary
39571  // representations
39572 
39573  // But we certanly we need to pass the connection information
39574  // to the sub-polylines
39575  // Get a curve section representation of the sub-polyline
39576  TriangleMeshCurveSection *tmp_sub_curve_section_pt =
39577  sub_tmp_polyline_pt;
39578  this->copy_connection_information_to_sub_polylines(
39579  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39580 
39581  } // for (isub < nsub_boundaries)
39582 
39583  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39584  // --------- Stuff for the sub_boundaries ----- End section ---------
39585 #endif // OOMPH_HAS_MPI
39586 
39587  // Delete the allocated memory for the geometric object
39588  // that represents the curvilinear boundary
39589  delete mesh_geom_obj_pt;
39590 
39591  } // for (cs < ncurve_section)
39592 
39593  // Cleanup the face mesh
39594  for(unsigned p = 0; p < ncurve_section; p++)
39595  {
39596  face_mesh_pt[p]->flush_node_storage();
39597  delete face_mesh_pt[p];
39598  }
39599 
39600  return update_was_performed;
39601 
39602 }
39603 
39604 #ifdef OOMPH_HAS_MPI
39605 //======================================================================
39606 /// \short Updates the polylines using the elements area as
39607 /// constraint for the number of points along the boundaries
39608 //======================================================================
39609 template <class ELEMENT>
39612  &vector_polyline_pt,
39613  const Vector<double> &target_areas)
39614 {
39615  // Flag to check if there were a change on the shared boundary
39616  // representation
39617  unsigned update_was_performed = false;
39618 
39619  // Go through all the shared boundaries/polylines
39620  const unsigned n_polylines = vector_polyline_pt.size();
39621  for (unsigned pp = 0; pp < n_polylines; pp++)
39622  {
39623  // Get the boundary id of the current polyline
39624  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39625 
39626  // Get the chunk number
39627  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39628 
39629  // Get the face elements that created the shared boundary from the
39630  // bulk shared boundary elements
39631 
39632  // Compute the face elements from the shared boundary elements,
39633  // create an association from the face element with the "bulk"
39634  // elements
39635  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39636 
39637  // The temporary storage for the halo face elements
39638  Vector<FiniteElement*> halo_shared_face_ele_pt;
39639  // The temporary storage for the nonhalo face elements
39640  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39641 
39642  // Get the number of shared boundary elements associated with the
39643  // current shared boundary
39644  const unsigned nshared_bound_ele =
39645  this->nshared_boundary_element(shd_bnd_id);
39646 
39647  // Loop over the elements in the shared boundary to create the face
39648  // elements
39649  for (unsigned e = 0; e < nshared_bound_ele; e++)
39650  {
39651  // Get the shared boundary element
39652  FiniteElement* bulk_ele_pt =
39653  this->shared_boundary_element_pt(shd_bnd_id, e);
39654 
39655  // Get the face index
39656  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39657 
39658  // Before adding the new element we need to ensure that the edge
39659  // that this element represents has not been already added
39660  FiniteElement* face_ele_pt =
39661  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39662 
39663  // Establish the association between the bulk element and the
39664  // face element
39665  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39666 
39667  // Nonhalo element
39668  if (!bulk_ele_pt->is_halo())
39669  {
39670  // Add nonhalo shared face element to the container
39671  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39672  }
39673  else // halo element
39674  {
39675  // Add halo shared face element to the container
39676  halo_shared_face_ele_pt.push_back(face_ele_pt);
39677  }
39678 
39679  } // for (e < nshared_bound_ele)
39680 
39681  // Now we have the face elements, we need to ensure that the halo
39682  // and nonhalo bulk element are sorted one after the other
39683  Vector<Vector<FiniteElement*> > unsorted_shared_bulk_ele_pt;
39684 
39685  // Mark the face elements already used
39686  std::map<FiniteElement*, bool> shared_face_done;
39687 
39688  // Get the number of nonhalo face elements
39689  const unsigned nnonhalo_face_shared_ele =
39690  nonhalo_shared_face_ele_pt.size();
39691 
39692  // Get the number of halo face elements
39693  const unsigned nhalo_face_shared_ele =
39694  halo_shared_face_ele_pt.size();
39695 
39696 #ifdef PARANOID
39697  // The number of nonhalo shared face boundary elements must be the
39698  // half of the total number of shared boundary elements
39699  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39700  {
39701  std::ostringstream error_message;
39702  error_message
39703  << "The number of shared boundary elements (" << nshared_bound_ele
39704  << ") is not the double\nof the number of unsorted NONHALO shared "
39705  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39706  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39707  throw OomphLibError(error_message.str(),
39708  OOMPH_CURRENT_FUNCTION,
39709  OOMPH_EXCEPTION_LOCATION);
39710  }
39711 
39712  // The number of halo shared face boundary elements must be the
39713  // half of the total number of shared boundary elements
39714  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39715  {
39716  std::ostringstream error_message;
39717  error_message
39718  << "The number of shared boundary elements (" << nshared_bound_ele
39719  << ") is not the double\nof the number of unsorted HALO shared "
39720  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
39721  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39722  throw OomphLibError(error_message.str(),
39723  OOMPH_CURRENT_FUNCTION,
39724  OOMPH_EXCEPTION_LOCATION);
39725  }
39726 #endif
39727 
39728  // ------------------------------------------------------------------
39729  // Loop over the nonhalo face elements and look for the halo face
39730  // element at the other side of the shared boundary
39731  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
39732  {
39733  // Get the inh-th face element
39734  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
39735 
39736  // Get the number of nodes on the face element
39737  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
39738  // Get the first and last node on the element
39739  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
39740  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
39741 
39742  // Now find the (halo) face element at the other side of the
39743  // shared boundary
39744  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
39745  {
39746  // Get the ih-th face element
39747  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
39748 
39749  // Check that the face element has not been done
39750  if (!shared_face_done[halo_face_ele_pt])
39751  {
39752  // Get the number of nodes on the face element
39753  const unsigned nnodes_h = halo_face_ele_pt->nnode();
39754  // Get the first and last node on the element
39755  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
39756  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
39757 
39758  // If the nodes are the same then we have found the (halo)
39759  // face element at the other side of the shared boundary
39760  if (nh_first_node_pt == h_first_node_pt &&
39761  nh_last_node_pt == h_last_node_pt)
39762  {
39763  // Get the BULK elements associated with the face elements
39764  Vector<FiniteElement*> tmp_bulk_element_pt;
39765  // Get the BULK elements associated to the face elements
39766  // (the nonhalo and the halo)
39767  FiniteElement* nonhalo_bulk_ele_pt =
39768  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39769  FiniteElement* halo_bulk_ele_pt =
39770  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39771 
39772  // Add the BULK elements to the temporal storage
39773  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39774  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39775 
39776  // Store the pair of elements associated to the "edge"
39777  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39778 
39779  // Mark the face elements as done
39780  shared_face_done[nonhalo_face_ele_pt] = true;
39781  shared_face_done[halo_face_ele_pt] = true;
39782 
39783  // Break the loop for (ih < nhalo_face_shared_ele)
39784  break;
39785  } // if (nh_first_node_pt == h_first_node_pt &&
39786  // nh_last_node_pt == h_last_node_pt)
39787  else if (nh_first_node_pt == h_last_node_pt &&
39788  nh_last_node_pt == h_first_node_pt)
39789  {
39790  // Get the BULK elements associated with the face elements
39791  Vector<FiniteElement*> tmp_bulk_element_pt;
39792  // Get the BULK elements associated to the face elements
39793  // (the nonhalo and the halo)
39794  FiniteElement* nonhalo_bulk_ele_pt =
39795  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39796  FiniteElement* halo_bulk_ele_pt =
39797  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39798 
39799  // Add the BULK elements to the temporal storage
39800  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39801  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39802 
39803  // Store the pair of elements associated to the "edge"
39804  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39805 
39806  // Mark the face elements as done
39807  shared_face_done[nonhalo_face_ele_pt] = true;
39808  shared_face_done[halo_face_ele_pt] = true;
39809 
39810  // Break the loop for (ih < nhalo_face_shared_ele)
39811  break;
39812  } // else if (nh_first_node_pt == h_last_node_pt &&
39813  // nh_last_node_pt == h_first_node_pt)
39814 
39815  } // if (face_done[halo_face_ele_pt])
39816 
39817  } // for (ih < nhalo_face_shared_ele)
39818 
39819  } // for (inh < nnonhalo_face_shared_ele)
39820 
39821  // -------------------------------------------------------------
39822  // Now sort the face elements
39823  // -------------------------------------------------------------
39824 
39825  // We already have the shared face elements that make the shared
39826  // boundary (and the bulk elements), now sort them to create a
39827  // contiguous boundary
39828 
39829 #ifdef PARANOID
39830  const unsigned nunsorted_shared_bulk_ele =
39831  unsorted_shared_bulk_ele_pt.size();
39832 
39833  // The number of unsorted shared BULK elements MUST be the same
39834  // as the number of shared_boundary elements divided by two
39835  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
39836  {
39837  std::ostringstream error_message;
39838  error_message
39839  << "The number of shared boundary elements (" << nshared_bound_ele
39840  << ") is not the double\nof the number of unsorted shared bulk "
39841  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
39842  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39843  throw OomphLibError(error_message.str(),
39844  OOMPH_CURRENT_FUNCTION,
39845  OOMPH_EXCEPTION_LOCATION);
39846  }
39847 
39848  // The number of done shared face elements MUST be the same as the
39849  // sum of the nonhalo and halo shared boundary face elements
39850  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
39851  shared_face_done.size())
39852  {
39853  std::ostringstream error_message;
39854  error_message
39855  << "The number of DONE shared boundary face elements ("
39856  << shared_face_done.size() << ") is not the same\n as the sum of"
39857  << "the nonhalo face shared boundary elements ("
39858  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
39859  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
39860  << "current boundary (" << shd_bnd_id << ")\n\n";
39861  throw OomphLibError(error_message.str(),
39862  OOMPH_CURRENT_FUNCTION,
39863  OOMPH_EXCEPTION_LOCATION);
39864  }
39865 #endif
39866 
39867  // Clear the already done face elements
39868  shared_face_done.clear();
39869 
39870  // The number of sorted face elements
39871  unsigned nsorted_face_ele = 0;
39872 
39873  // Storing for the sorting nodes extracted from the face
39874  // elements. This are also used to update the polyline
39875  std::list<Node*> sorted_nodes;
39876 
39877  // Storing for the sorted shared face elements
39878  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
39879 
39880  // Get the root face element
39881  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
39882  nsorted_face_ele++;
39883 
39884  // Mark face as done
39885  shared_face_done[root_face_ele_pt] = true;
39886 
39887  // The initial and final node on the list
39888  const unsigned nnodes_root = root_face_ele_pt->nnode();
39889  Node *first_node_pt = root_face_ele_pt->node_pt(0);
39890  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
39891 
39892  // Push back on the list the new nodes
39893  sorted_nodes.push_back(first_node_pt);
39894  sorted_nodes.push_back(last_node_pt);
39895 
39896  // Store the bulk elements of the current face
39897  sorted_shared_bound_elements_pt.push_back(
39898  unsorted_shared_bulk_ele_pt[0][0]);
39899  sorted_shared_bound_elements_pt.push_back(
39900  unsorted_shared_bulk_ele_pt[0][1]);
39901 
39902  // Sort the face elements
39903  while (nsorted_face_ele < nnonhalo_face_shared_ele)
39904  {
39905  // Flag to indicate when a node was added
39906  bool node_added = false;
39907 
39908  // Start from the next edge since we have already added the
39909  // previous one as the initial face element
39910  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
39911  {
39912  FiniteElement* tmp_shared_face_ele_pt =
39913  nonhalo_shared_face_ele_pt[iface];
39914 
39915  // If face has not been sorted
39916  if (!shared_face_done[tmp_shared_face_ele_pt])
39917  {
39918  // Get the number of nodes for the current face element
39919  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
39920 
39921  // Get each individual node
39922  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
39923  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
39924 
39925  if (left_node_pt == first_node_pt)
39926  {
39927  // Push front the new node
39928  sorted_nodes.push_front(right_node_pt);
39929  first_node_pt = right_node_pt;
39930  node_added = true;
39931 
39932  // Store the elements of the current face element
39933  sorted_shared_bound_elements_pt.push_front(
39934  unsorted_shared_bulk_ele_pt[iface][1]);
39935  sorted_shared_bound_elements_pt.push_front(
39936  unsorted_shared_bulk_ele_pt[iface][0]);
39937  }
39938  else if (left_node_pt == last_node_pt)
39939  {
39940  // Push back the new node
39941  sorted_nodes.push_back(right_node_pt);
39942  last_node_pt = right_node_pt;
39943  node_added = true;
39944 
39945  // Store the elements of the current face element
39946  sorted_shared_bound_elements_pt.push_back(
39947  unsorted_shared_bulk_ele_pt[iface][0]);
39948  sorted_shared_bound_elements_pt.push_back(
39949  unsorted_shared_bulk_ele_pt[iface][1]);
39950  }
39951  else if (right_node_pt == first_node_pt)
39952  {
39953  // Push front the new node
39954  sorted_nodes.push_front(left_node_pt);
39955  first_node_pt = left_node_pt;
39956  node_added = true;
39957 
39958  // Store the elements of the current face element
39959  sorted_shared_bound_elements_pt.push_front(
39960  unsorted_shared_bulk_ele_pt[iface][1]);
39961  sorted_shared_bound_elements_pt.push_front(
39962  unsorted_shared_bulk_ele_pt[iface][0]);
39963  }
39964  else if (right_node_pt == last_node_pt)
39965  {
39966  // Push back the new node
39967  sorted_nodes.push_back(left_node_pt);
39968  last_node_pt = left_node_pt;
39969  node_added = true;
39970 
39971  // Store the elements of the current face element
39972  sorted_shared_bound_elements_pt.push_back(
39973  unsorted_shared_bulk_ele_pt[iface][0]);
39974  sorted_shared_bound_elements_pt.push_back(
39975  unsorted_shared_bulk_ele_pt[iface][1]);
39976  }
39977 
39978  if (node_added)
39979  {
39980  // Mark as done if one of its nodes has been added to the
39981  // list
39982  shared_face_done[tmp_shared_face_ele_pt] = true;
39983  nsorted_face_ele++;
39984 
39985  // Break the for
39986  break;
39987  }
39988 
39989  } // if (!shared_face_done[tmp_shared_face_ele_pt])
39990 
39991  } // for (iface < nnonhalo_face_shared_ele)
39992 
39993  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
39994 
39995  // ----------------------------------------------------------------
39996  // Here we can safely delete the face elements, they are no longer
39997  // required
39998 
39999  // First the nonhalo face elements
40000  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40001  {
40002  delete nonhalo_shared_face_ele_pt[inh];
40003  nonhalo_shared_face_ele_pt[inh] = 0;
40004  } // for (inh < nnonhalo_face_shared_ele)
40005 
40006  // ... then the halo face elements
40007  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40008  {
40009  delete halo_shared_face_ele_pt[ih];
40010  halo_shared_face_ele_pt[ih] = 0;
40011  } // for (inh < nhalo_face_shared_ele)
40012 
40013  // ------------------------------------------------------------------
40014  // At this point we already have a sorted list of nodes, get the
40015  // vertices from them and store them in a vector container
40016 
40017  // Get the number of nodes on the list
40018  const unsigned n_nodes = sorted_nodes.size();
40019 
40020  // The vector to store the vertices
40021  Vector<Vector<double> > polyline_vertices(n_nodes);
40022 
40023  // Copy the vertices from the nodes
40024  unsigned counter = 0;
40025  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40026  it_nodes != sorted_nodes.end();
40027  it_nodes++)
40028  {
40029  polyline_vertices[counter].resize(2);
40030  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40031  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40032  counter++;
40033  }
40034 
40035  // ------------------------------------------------------------------
40036  // Now get the target areas associated to the shared boundary
40037  // elements
40038 
40039  // Copy the sorted elements in a vector
40040  Vector<FiniteElement*> sorted_shared_ele_pt;
40041  for (std::list<FiniteElement*>::iterator it_ele =
40042  sorted_shared_bound_elements_pt.begin();
40043  it_ele != sorted_shared_bound_elements_pt.end();
40044  it_ele++)
40045  {sorted_shared_ele_pt.push_back((*it_ele));}
40046 
40047  // Get the number of target areas
40048  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40049  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40050 
40051  // Mark those shared elements already found
40052  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40053 
40054  // Counter for the number of already done shared elements
40055  unsigned count_found_shared_element = 0;
40056 
40057  // Get the target area associated to the shared boundary elements
40058  const unsigned nele = this->nelement();
40059 
40060  // Loop over the elements to find the target areas associated to
40061  // the shared boundary elements
40062  for (unsigned e = 0; e < nele; e++)
40063  {
40064  GeneralisedElement* current_ele_pt = this->element_pt(e);
40065  // Now compare the current element with those in the sorted
40066  // shared element array
40067  for (unsigned s = 0; s < n_shared_target_areas; s++)
40068  {
40069  // Get the element
40070  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40071  // Create the pair element-index to check if done
40072  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40073  std::make_pair(current_shared_ele_pt, s);
40074  if (!shared_ele_done[pair_gen_ele_idx])
40075  {
40076  // Compare with the global element
40077  if (current_ele_pt == current_shared_ele_pt)
40078  {
40079  // Store the target area of the current shared element
40080  sorted_shared_target_areas[s] = target_areas[e];
40081  // Mark the shared element as done
40082  shared_ele_done[pair_gen_ele_idx] = true;
40083  // Increase the number of found elements
40084  count_found_shared_element++;
40085  } // if (current_ele_pt == current_shared_ele_pt)
40086  } // if (!shared_ele_done[current_shared_ele_pt])
40087  } // for (s < nshared_taget_areas)
40088 
40089  // Check if all shared elements have been found
40090  if (count_found_shared_element == n_shared_target_areas)
40091  {break;}
40092 
40093  } // for (e < nele)
40094 
40095 #ifdef PARANOID
40096  // Check if the number of found target areas is the same as the
40097  // number of shared target areas
40098  if (count_found_shared_element != n_shared_target_areas)
40099  {
40100  std::ostringstream error_message;
40101  error_message
40102  << "The number of found target areas ("
40103  << count_found_shared_element << ") is different from the "
40104  << "total number\nof target areas ("
40105  << n_shared_target_areas << ") in shared boundary ("
40106  << shd_bnd_id <<")\n\n";
40107  throw OomphLibError(error_message.str(),
40108  OOMPH_CURRENT_FUNCTION,
40109  OOMPH_EXCEPTION_LOCATION);
40110  }
40111 #endif
40112 
40113  // The number of vertices
40114  const unsigned n_vertices = n_nodes;
40115 
40116  // Get the number of segments from the input vector_polyline_pt
40117  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40118  // Get the number of segments from the input vector_polyline_pt to
40119  // ensure that the shared boundary corresponds to the one
40120  // represented by the shared face elements (this has sence when the
40121  // mesh was re-created from re-starting)
40122 
40123  // Check that the number of vertices correspond with the number of
40124  // segments
40125 #ifdef PARANOID
40126  if (n_segments != n_vertices-1)
40127  {
40128  std::ostringstream error_message;
40129  error_message
40130  << "The number of segments from the current shared polyline "
40131  << "(" << n_segments << ") does not\ncorrespond with the number of "
40132  << "sorted vertices (" << n_vertices-1 << ") of the current shared\n"
40133  << "boundary\n\n";
40134  throw OomphLibError(error_message.str(),
40135  OOMPH_CURRENT_FUNCTION,
40136  OOMPH_EXCEPTION_LOCATION);
40137  }
40138 
40139  // Check that the number of target areas correspond with the number
40140  // of vertices
40141  if (n_segments != n_shared_target_areas/2)
40142  {
40143  std::ostringstream error_message;
40144  error_message
40145  << "The number of segments for the current sorting of edges "
40146  << "(" << n_segments << ") is different\nfrom the number of "
40147  << "target areas (" << n_shared_target_areas/2 << ")\n\n";
40148  throw OomphLibError(error_message.str(),
40149  OOMPH_CURRENT_FUNCTION,
40150  OOMPH_EXCEPTION_LOCATION);
40151  }
40152 #endif
40153 
40154  // ------------------------------------------------------------------
40155  // Get the target areas that are used to perform the unrefinement
40156  // and refinement operation. For each face element on a shared
40157  // polyline there are two bulk elements, a halo and a haloed
40158  // element, each with an associated target area. Review the
40159  // function
40160  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40161  // check how the shared boundaries were created
40162  Vector<double> polyline_target_area(n_segments);
40163  // Loop over the segments in the shared polyline
40164  for (unsigned s = 0; s < n_segments; s++)
40165  {
40166  // Get the minimum of the associated target areas
40167  polyline_target_area[s] = std::min(sorted_shared_target_areas[s*2],
40168  sorted_shared_target_areas[(s*2)+1]);
40169  }
40170 
40171  // Before going to the unrefinement or refinement process check
40172  // that in all processors where the shared boundary lives start
40173  // from the same vertex.
40174  // Start from the bottom left vertex
40175  if (polyline_vertices[n_vertices-1][1] < polyline_vertices[0][1])
40176  {
40177  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40178  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40179  }
40180  else if (polyline_vertices[n_vertices-1][1] == polyline_vertices[0][1])
40181  {
40182  if (polyline_vertices[n_vertices-1][0] < polyline_vertices[0][0])
40183  {
40184  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40185  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40186  }
40187  }
40188 
40189  // ------------------------------------------------------------------
40190  // Apply unrefinement
40191  bool unrefinement_applied = false;
40192  // Apply unefinement if there are more than three nodes at the
40193  // shared boundary
40194  if (n_vertices > 3)
40195  {
40196  unrefinement_applied =
40197  unrefine_shared_boundary_constrained_by_target_area(
40198  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40199  }
40200 
40201  // Apply refinement
40202  bool refinement_applied =
40203  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40204  polyline_target_area);
40205 
40206  // Was unrefinement/refinement applied
40207  update_was_performed |= (unrefinement_applied || refinement_applied);
40208 
40209  // ------------------------------------------------------------------
40210  // Update the polyline representation of the shared boundary
40211 
40212  // The new shared polyline representation
40213  TriangleMeshPolyLine *new_polyline_pt =
40214  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40215 
40216  // Get the curve section representation
40217  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
40218 
40219  // Copy the connection information from the old shared polyline to
40220  // the new one
40221  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40222 
40223  // Now update the polyline according to the new vertices but first
40224  // check if the object is allowed to delete the representation or
40225  // if it should be done by other object
40226  bool delete_it_on_destructor = false;
40227 
40228  // Establish the element as being deleted by the destructor of the
40229  // class
40230  std::set<TriangleMeshCurveSection*>::iterator it =
40231  this->Free_curve_section_pt.find(curve_section_pt);
40232 
40233  if (it!=this->Free_curve_section_pt.end())
40234  {
40235  this->Free_curve_section_pt.erase(it);
40236  delete curve_section_pt;
40237  delete_it_on_destructor = true;
40238  }
40239 
40240  // Copy the new representation to the output vector_polyline_pt
40241  vector_polyline_pt[pp] = new_polyline_pt;
40242 
40243  // Get the new curve section representation
40244  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
40245 
40246  // Update the Boundary - Polyline map
40247  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40248 
40249  if (delete_it_on_destructor)
40250  {
40251  this->Free_curve_section_pt.insert(new_curve_section_pt);
40252  }
40253 
40254  } // for (pp < npoly)
40255 
40256  return update_was_performed;
40257 
40258 }
40259 #endif // #ifdef OOMPH_HAS_MPI
40260 
40261  //=========================================================================
40262  /// \short Helper function that performs the unrefinement process
40263  /// on the specified boundary by using the provided vertices
40264  /// representation and the associated target area.
40265  //=========================================================================
40266  template<class ELEMENT>
40269  const unsigned &c,
40271  &vector_bnd_vertices,
40272  double &unrefinement_tolerance,
40273  Vector<double> &area_constraint)
40274  {
40275  // Store the vertices not allowed for deletion
40276  std::set<Vector<double> > no_delete_vertex;
40277 
40278  // Does the boundary receives connections?
40279  const bool boundary_receive_connections =
40280  this->boundary_connections(b, c, no_delete_vertex);
40281 
40282  // Boolean that indicates whether an actual update of the vertex
40283  // coordinates was performed
40284  bool unrefinement_applied = false;
40285 
40286  // Return inmedately
40287  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40288  {
40289  return unrefinement_applied;
40290  }
40291 
40292  // Strategy to delete nodes: Consider the target area of the
40293  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40294  // if the number of segments to be added is equal to zero for both
40295  // elements then compute the average of both target areas and check
40296  // if the number of segments is still zero, if that holds mark the
40297  // node to be deleted. Before delete the node check whether it is in
40298  // the non_delete_vertex list. Skip the i+1-th node and go for the
40299  // (i+2)-th one, it means, increase the counter for current node by
40300  // two.
40301 
40302  // Number of vertices on the boundary
40303  unsigned n_vertex = vector_bnd_vertices.size();
40304 
40305  // Compute a constant value
40306  const double constant_value = 4.0/sqrt(3.0);
40307 
40308  if (n_vertex > 2)
40309  {
40310  // Go through all the vertices and delete points when the target area
40311  // indicates zero points along the boundary
40312  for (unsigned i = 1; i < n_vertex-1; i+=2)
40313  {
40314  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40315  {
40316  const double local_zeta_first = vector_bnd_vertices[i-1][0];
40317  const double local_zeta_last = vector_bnd_vertices[i+1][0];
40318  const double local_length_zeta =
40319  std::fabs(local_zeta_last-local_zeta_first);
40320 
40321  const double x1 = vector_bnd_vertices[i-1][1];
40322  const double y1 = vector_bnd_vertices[i-1][2];
40323  const double x2 = vector_bnd_vertices[i+1][1];
40324  const double y2 = vector_bnd_vertices[i+1][2];
40325  const double local_length =
40326  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40327 
40328  const double x_m = vector_bnd_vertices[i][1];
40329  const double y_m = vector_bnd_vertices[i][2];
40330 
40331  const double average_area_constraint =
40332  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40333 
40334  // Compute the length of the the side of an equilateral
40335  // triangle
40336  const double length_side =
40337  sqrt(constant_value*average_area_constraint);
40338 
40339  const double length_side_zeta =
40340  (local_length_zeta * length_side) / local_length;
40341 
40342  // Is the new length greater that the old one
40343  if ((length_side_zeta / local_length_zeta) > 1.0)
40344  {
40345  // If the number of segments is zero then verify the condition for
40346  // deletion of nodes but using the condition in the default
40347  // unrefine_boundary() method. If both conditions are true then
40348  // delete the node
40349  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40350  double a_x=vector_bnd_vertices[i-1][1];
40351  double a_y=vector_bnd_vertices[i-1][2];
40352  double b_x=vector_bnd_vertices[i][1];
40353  double b_y=vector_bnd_vertices[i][2];
40354  double c_x=vector_bnd_vertices[i+1][1];
40355  double c_y=vector_bnd_vertices[i+1][2];
40356 
40357  double a=b_x-a_x;
40358  double b=b_y-a_y;
40359  double c=c_x-a_x;
40360  double d=c_y-a_y;
40361 
40362  double e=a*(a_x+b_x)+b*(a_y+b_y);
40363  double f=c*(a_x+c_x)+d*(a_y+c_y);
40364 
40365  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
40366 
40367  bool do_it=false;
40368  if (std::fabs(g)<1.0e-14)
40369  {
40370  do_it=true;
40371  }
40372  else
40373  {
40374  double p_x=(d*e-b*f)/g;
40375  double p_y=(a*f-c*e)/g;
40376 
40377  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
40378 
40379  double rhalfca_x=0.5*(a_x-c_x);
40380  double rhalfca_y=0.5*(a_y-c_y);
40381 
40382  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
40383 
40384  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
40385 
40386  // If sticky out bit divided by distance between end nodes
40387  // is less than tolerance the boundary is so flat that we
40388  // can safely kill the node
40389  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
40390  unrefinement_tolerance)
40391  {
40392  do_it=true;
40393  }
40394  }
40395 
40396  // If the vertex was proposed for deletion check if it is
40397  // allowed for being deleted
40398  if (do_it && boundary_receive_connections)
40399  {
40400  // Is the vertex one of the non deletable vertices
40401  for (std::set<Vector<double> >::iterator it =
40402  no_delete_vertex.begin();
40403  it != no_delete_vertex.end(); it++)
40404  {
40405  // Compute the distance between the proposed node to
40406  // delete and the ones that should not be deleted
40407  const double x = (*it)[0];
40408  const double y = (*it)[1];
40409  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40410  error = sqrt(error);
40411 
40412  if(error <
40414  {
40415  // Do not delete the vertex
40416  do_it = false;
40417  break;
40418  }
40419 
40420  }
40421 
40422  } // if (do_it && boundary_receive_connections)
40423 
40424  // Remove node?
40425  if (do_it)
40426  {
40427  vector_bnd_vertices[i].resize(0);
40428  }
40429  } // if (n_seg == 0)
40430  } // if (area_constraint[i] >= 0)
40431  } // for (i < n_vertex-1)
40432 
40433  // Create a new (temporary) vector for the nodes, so that deleted nodes
40434  // are not stored
40435  Vector<Vector<double> > compact_vector;
40436 
40437  // Compact vector for target areas too
40438  Vector<double> compact_area_constraint;
40439 
40440  // Copy only the non deleted nodes
40441  for(unsigned i = 0; i < n_vertex; i++)
40442  {
40443  // If the entry was not deleted include it in the new vector
40444  if (vector_bnd_vertices[i].size()!=0)
40445  {
40446  compact_vector.push_back(vector_bnd_vertices[i]);
40447  }
40448  }
40449 
40450  // ------------------------------------------------------------------
40451  // Size of the target areas vector
40452  unsigned nsize_target = area_constraint.size();
40453  if (nsize_target == 1)
40454  {
40455  // No node was deleted, just copy the target area
40456  compact_area_constraint.push_back(area_constraint[0]);
40457  }
40458 
40459  // Copy the target areas
40460  for(unsigned i = 1; i < n_vertex; i+=2)
40461  {
40462  // If the entry was not deleted include the target areas of both
40463  // elements sharing the node
40464  if (vector_bnd_vertices[i].size()!=0)
40465  {
40466  compact_area_constraint.push_back(area_constraint[i-1]);
40467  // To catch the case when working with even number of vertex
40468  if (i < nsize_target)
40469  {
40470  compact_area_constraint.push_back(area_constraint[i]);
40471  }
40472  }
40473  else
40474  {
40475  // If the node was deleted then compute the new target area as the
40476  // average of the target area of the elements sharing the node
40477  double new_area_constraint =
40478  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40479  compact_area_constraint.push_back(new_area_constraint);
40480  }
40481  }
40482 
40483  // If the size of the compact vector is different from the size of the
40484  // vector before applying the area length constraint then the polyline
40485  // was updated
40486  if( n_vertex != compact_vector.size() )
40487  {
40488  unrefinement_applied = true;
40489  }
40490 
40491  // Copy back to the original vector
40492  n_vertex = compact_vector.size();
40493  vector_bnd_vertices.resize(n_vertex);
40494  for(unsigned i = 0; i < n_vertex; i++)
40495  {
40496  vector_bnd_vertices[i].resize(3);
40497  vector_bnd_vertices[i][0] = compact_vector[i][0];
40498  vector_bnd_vertices[i][1] = compact_vector[i][1];
40499  vector_bnd_vertices[i][2] = compact_vector[i][2];
40500  }
40501 
40502  // Copy back to the original vector of target areas
40503  unsigned ntarget_areas = compact_area_constraint.size();
40504  area_constraint.resize(ntarget_areas);
40505  for(unsigned i = 0; i < ntarget_areas; i++)
40506  {
40507  area_constraint[i] = compact_area_constraint[i];
40508  }
40509 
40510  } // if (n_vertex > 2)
40511 
40512  return unrefinement_applied;
40513 
40514  }
40515 
40516  //=========================================================================
40517  /// \short Helper function that performs the refinement process
40518  /// on the specified boundary by using the provided vertices
40519  /// representation and the associated elements target area.
40520  //=========================================================================
40521  template<class ELEMENT>
40524  mesh_geom_obj_pt,
40526  &vector_bnd_vertices,
40527  double &refinement_tolerance,
40528  Vector<double> &area_constraint)
40529  {
40530  // Boolean that indicates whether an actual update of the vertex
40531  // coordinates was performed
40532  bool refinement_applied = false;
40533 
40534  // Return inmedately
40535  if (!Do_boundary_refinement_constrained_by_target_areas)
40536  {
40537  return refinement_applied;
40538  }
40539 
40540  // Get the total number of current vertices
40541  unsigned n_vertex=vector_bnd_vertices.size();
40542 
40543  // Compute a constant value
40544  const double constant_value = 4.0/sqrt(3.0);
40545 
40546  if (n_vertex > 1)
40547  {
40548  // Create a new (temporary) vector for the nodes, so that new
40549  // nodes can be stored
40550  Vector<Vector<double> > new_vector;
40551 
40552  // Go through all the vertices and create points according to the
40553  // specified element area
40554  for (unsigned i = 0; i < n_vertex-1; i++)
40555  {
40556  // Include the first node
40557  new_vector.push_back(vector_bnd_vertices[i]);
40558 
40559  if (area_constraint[i] > 0)
40560  {
40561  double local_zeta_first = vector_bnd_vertices[i][0];
40562  double local_zeta_last = vector_bnd_vertices[i+1][0];
40563  const double local_length_zeta =
40564  std::fabs(local_zeta_last-local_zeta_first);
40565 
40566  // Check if need to interchange the zeta first and the zeta
40567  // last (to ensure the same order in zeta values in any two
40568  // processors)
40569  if (local_zeta_first > local_zeta_last)
40570  {
40571  const double tmp_zeta = local_zeta_first;
40572  local_zeta_first = local_zeta_last;
40573  local_zeta_last = tmp_zeta;
40574  }
40575 
40576  const double x1 = vector_bnd_vertices[i][1];
40577  const double y1 = vector_bnd_vertices[i][2];
40578  const double x2 = vector_bnd_vertices[i+1][1];
40579  const double y2 = vector_bnd_vertices[i+1][2];
40580  const double local_length =
40581  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40582 
40583  // Compute the length in zeta units
40584  const double length_side = sqrt(constant_value*area_constraint[i]);
40585  const double length_side_zeta =
40586  (local_length_zeta * length_side) / local_length;
40587 
40588  // How many segments should be introduced
40589  const double n_seg_double = length_side_zeta/local_length_zeta;
40590 
40591  // One segment initialy (the original one)
40592  unsigned n_seg = 1;
40593 
40594  // How many more segments to introduce?
40595  n_seg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40596 
40597  // Are there segments to introduce? There must be at least one
40598  // segment, the original one
40599  if (n_seg > 0)
40600  {
40601  // The zeta increment
40602  double zeta_increment = (local_length_zeta)/((double)n_seg);
40603 
40604  Vector<double> zeta(1);
40605  // Create the n_seg segmets between each pair of nodes
40606  for(unsigned s=1;s<n_seg;s++)
40607  {
40608  // Get the coordinates
40609  zeta[0]= local_zeta_first + zeta_increment*double(s);
40610  Vector<double> vertex(2);
40611  mesh_geom_obj_pt->position(zeta, vertex);
40612 
40613  // Create the new node
40614  Vector<double> new_node(3);
40615  new_node[0]=zeta[0];
40616  new_node[1]=vertex[0];
40617  new_node[2]=vertex[1];
40618 
40619  // Include the new node
40620  new_vector.push_back(new_node);
40621 
40622  } // for (s<=n_seg)
40623 
40624  } // if (n_seg > 0)
40625 
40626  } // if (area_constraint[i] >= 0)
40627 
40628  } // for (i < n_vertex-1)
40629 
40630  // Once finished all the vertices add the last node to the vector
40631  new_vector.push_back(vector_bnd_vertices[n_vertex-1]);
40632 
40633  // If the new size of the vector (including the added nodes) is
40634  // different from the size of the vector before applying the
40635  // area length constraint then the polyline was updated
40636  n_vertex=new_vector.size();
40637  if( n_vertex != vector_bnd_vertices.size() )
40638  {
40639  refinement_applied = true;
40640  }
40641 
40642  // Copy the new representation
40643  vector_bnd_vertices.resize(n_vertex);
40644  for(unsigned i=0;i<n_vertex;i++)
40645  {
40646  vector_bnd_vertices[i].resize(3);
40647  vector_bnd_vertices[i][0]=new_vector[i][0];
40648  vector_bnd_vertices[i][1]=new_vector[i][1];
40649  vector_bnd_vertices[i][2]=new_vector[i][2];
40650  }
40651 
40652  } // if (n_vertex > 1)
40653 
40654  return refinement_applied;
40655 
40656  }
40657 
40658  //======================================================================
40659  /// \short Helper function that performs the unrefinement process
40660  /// on the specified boundary by using the provided vertices
40661  /// representation and the associated target area.
40662  /// NOTE: This is the version that applies unrefinement to shared
40663  /// boundaries
40664  //======================================================================
40665  template <class ELEMENT>
40668  const unsigned &b,
40669  const unsigned &c,
40670  Vector<Vector<double> > &vector_bnd_vertices,
40671  Vector<double> &area_constraint)
40672  {
40673  // Store the vertices not allowed for deletion
40674  std::set<Vector<double> > no_delete_vertex;
40675 
40676  // Does the boundary receives connections?
40677  const bool boundary_receive_connections =
40678  this->boundary_connections(b, c, no_delete_vertex);
40679 
40680  // Boolean that indicates whether an actual update of the vertex
40681  // coordinates was performed
40682  bool unrefinement_applied = false;
40683 
40684  // Return inmedately
40685  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40686  {
40687  return unrefinement_applied;
40688  }
40689 
40690  // Strategy to delete nodes:
40691 
40692  // Strategy to delete nodes: Consider the target area of the
40693  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40694  // if the number of segments to be added is equal to zero for both
40695  // elements then compute the average of both target areas and check
40696  // if the number of segments is still zero, if that holds mark the
40697  // node to be deleted. Before delete the node check whether it is in
40698  // the non_delete_vertex list. Skip the i+1-th node and go for the
40699  // (i+2)-th one, it means, increase the counter for current node by
40700  // two.
40701 
40702  // Number of vertices on the boundary
40703  unsigned n_vertex = vector_bnd_vertices.size();
40704 
40705  // Compute a constant value
40706  const double constant_value = 4.0/sqrt(3.0);
40707 
40708  if (n_vertex > 2)
40709  {
40710  // Go through all the vertices and delete points when the target
40711  // area indicates zero points along the boundary
40712  for (unsigned i = 1; i < n_vertex-1; i+=2)
40713  {
40714  // Is a target area assigned to the left and right element of
40715  // the i-th node
40716  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40717  {
40718  // Get the vertices to the left
40719  const double x1 = vector_bnd_vertices[i-1][0];
40720  const double y1 = vector_bnd_vertices[i-1][1];
40721  // ... and to the right of the i-th vertex
40722  const double x2 = vector_bnd_vertices[i+1][0];
40723  const double y2 = vector_bnd_vertices[i+1][1];
40724 
40725  // The distance
40726  const double local_length =
40727  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40728 
40729  // Get the middle vertex
40730  const double x_m = vector_bnd_vertices[i][0];
40731  const double y_m = vector_bnd_vertices[i][1];
40732 
40733  // The average area
40734  const double average_area_constraint =
40735  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40736 
40737  // Compute the base length of the triangle with
40738  // area_constraint area
40739  const double length_side =
40740  sqrt(constant_value*average_area_constraint);
40741 
40742  // Is the new length greater than the old one
40743  if ((length_side / local_length) > 1.0)
40744  {
40745  bool do_it=true;
40746 
40747  // If the vertex was proposed for deletion check that it is
40748  // allowed for being deleted
40749  if (do_it && boundary_receive_connections)
40750  {
40751  // Is the vertex one of the non deletable vertices
40752  for (std::set<Vector<double> >::iterator it =
40753  no_delete_vertex.begin();
40754  it != no_delete_vertex.end(); it++)
40755  {
40756  // Compute the distance between the proposed node to delete
40757  // and the ones that should not be deleted
40758  const double x = (*it)[0];
40759  const double y = (*it)[1];
40760  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40761  error = sqrt(error);
40762 
40763  if(error <
40765  {
40766  // Do not delete the vertex
40767  do_it = false;
40768  break;
40769  }
40770 
40771  }
40772 
40773  } // if (do_it && boundary_receive_connections)
40774 
40775  // Remove node?
40776  if (do_it)
40777  {
40778  vector_bnd_vertices[i].resize(0);
40779  }
40780  } // if ((local_length / length_side) <= 1.3)
40781 
40782  } // if (area_constraint[i] >= 0)
40783 
40784  } // for (i < n_vertex-1)
40785 
40786  // Create a new (temporary) vector for the nodes, so that deleted nodes
40787  // are not stored
40788  Vector<Vector<double> > compact_vector;
40789 
40790  // Compact vector for target areas too
40791  Vector<double> compact_area_constraint;
40792 
40793  // Copy only the non deleted nodes
40794  for(unsigned i = 0; i < n_vertex; i++)
40795  {
40796  // If the entry was not deleted include it in the new vector
40797  if (vector_bnd_vertices[i].size()!=0)
40798  {
40799  compact_vector.push_back(vector_bnd_vertices[i]);
40800  }
40801  }
40802 
40803  // ------------------------------------------------------------------
40804  // The number of target areas
40805  unsigned n_area_constraint = area_constraint.size();
40806  if (n_area_constraint == 1)
40807  {
40808  // No node could be deleted then just copy the target area
40809  compact_area_constraint.push_back(area_constraint[0]);
40810  }
40811 
40812  // Copy the target areas
40813  for(unsigned i = 1; i < n_vertex; i+=2)
40814  {
40815  // If the entry was not deleted include the target areas of both
40816  // elements sharing the node
40817  if (vector_bnd_vertices[i].size()!=0)
40818  {
40819  compact_area_constraint.push_back(area_constraint[i-1]);
40820  // To catch the case when working with even number of vertices
40821  if (i < n_area_constraint)
40822  {
40823  compact_area_constraint.push_back(area_constraint[i]);
40824  }
40825  }
40826  else
40827  {
40828  // If the node was deleted then compute the new target area as the
40829  // average of the target area of the elements sharing the node
40830  const double new_area_constraint =
40831  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40832  compact_area_constraint.push_back(new_area_constraint);
40833  }
40834  } // for (i < n_vertex)
40835 
40836  // If the size of the compact vector is different from the size of
40837  // the vector before applying the area length constraint then the
40838  // polyline was updated
40839  if( n_vertex != compact_vector.size() )
40840  {
40841  unrefinement_applied = true;
40842  }
40843 
40844  // Copy back to the original vector
40845  n_vertex = compact_vector.size();
40846  vector_bnd_vertices.resize(n_vertex);
40847  for(unsigned i = 0; i < n_vertex; i++)
40848  {
40849  vector_bnd_vertices[i].resize(2);
40850  vector_bnd_vertices[i][0] = compact_vector[i][0];
40851  vector_bnd_vertices[i][1] = compact_vector[i][1];
40852  }
40853 
40854  // Copy back to the original vector of target areas
40855  unsigned ntarget_areas = compact_area_constraint.size();
40856  area_constraint.resize(ntarget_areas);
40857  for(unsigned i = 0; i < ntarget_areas; i++)
40858  {
40859  area_constraint[i] = compact_area_constraint[i];
40860  }
40861 
40862  } // if (n_vertex > 2)
40863 
40864  return unrefinement_applied;
40865 
40866  }
40867 
40868  //======================================================================
40869  /// \short Helper function that performs the refinement process
40870  /// on the specified boundary by using the provided vertices
40871  /// representation and the associated elements target area.
40872  /// NOTE: This is the version that applies refinement to shared
40873  /// boundaries
40874  //======================================================================
40875  template <class ELEMENT>
40878  Vector<Vector<double> > &vector_bnd_vertices,
40879  Vector<double> &area_constraint)
40880  {
40881  // Boolean that indicates whether an actual update of the vertex
40882  // coordinates was performed
40883  bool refinement_applied = false;
40884 
40885  // Return inmedately
40886  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
40887  {
40888  return refinement_applied;
40889  }
40890 
40891  // Get the number of segments
40892  unsigned nsegments = vector_bnd_vertices.size() - 1;
40893 
40894  // Create a new (temporary) vector for the nodes, so that new nodes
40895  // can be stored
40896  Vector<Vector<double> > tmp_bnd_vertices;
40897 
40898  // Compute a constant value
40899  const double constant_value = 4.0/sqrt(3.0);
40900 
40901  for (unsigned s = 0; s < nsegments; s++)
40902  {
40903  Vector<double> left_vertex = vector_bnd_vertices[s];
40904  Vector<double> right_vertex = vector_bnd_vertices[s+1];
40905 
40906  // Initial and final point of the segment
40907  const double x1 = left_vertex[0];
40908  const double y1 = left_vertex[1];
40909  const double x2 = right_vertex[0];
40910  const double y2 = right_vertex[1];
40911 
40912  // Lenght of the segment
40913  const double segment_length =
40914  sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
40915 
40916  // Compute the distance for the new segments
40917  const double new_segment_length =
40918  sqrt(constant_value*area_constraint[s]);
40919 
40920  // How many segments should be introduced
40921  const double n_seg_double = new_segment_length / segment_length;
40922 
40923  // One segment initialy (the original one)
40924  unsigned nseg = 1;
40925  // How many more segments to introduce?
40926  nseg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40927 
40928  // The left vertex must be always included, even though no new vertex
40929  // be added
40930  tmp_bnd_vertices.push_back(left_vertex);
40931 
40932  // Are there segments to introduce? There must be at least one
40933  // segment, the original one
40934  if (nseg > 0)
40935  {
40936  // Create intermediate vertices
40937  double incrementx = (right_vertex[0] - left_vertex[0])/(double)(nseg);
40938  double incrementy = (right_vertex[1] - left_vertex[1])/(double)(nseg);
40939  for (unsigned i = 1; i < nseg; i++)
40940  {
40941  Vector<double> tmp_vertex(2);
40942  tmp_vertex[0] = left_vertex[0] + incrementx*i;
40943  tmp_vertex[1] = left_vertex[1] + incrementy*i;
40944  tmp_bnd_vertices.push_back(tmp_vertex);
40945  } // for (i < nseg)
40946 
40947  } // if (nseg > 0)
40948 
40949  } // for (s < nsegments)
40950 
40951  // Add the last vertex
40952  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
40953 
40954  // If the new size of the vector (including the added nodes) is
40955  // different from the size of the vector before applying the
40956  // refinement then the polyline was updated
40957  nsegments = tmp_bnd_vertices.size() - 1;
40958  if( nsegments != vector_bnd_vertices.size() - 1 )
40959  {
40960  refinement_applied = true;
40961 
40962  // Copy across
40963  vector_bnd_vertices.resize(nsegments + 1);
40964  for(unsigned i = 0; i < nsegments + 1; i++)
40965  {
40966  vector_bnd_vertices[i].resize(2);
40967  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
40968  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
40969  }
40970  }
40971 
40972  return refinement_applied;
40973 
40974  }
40975 
40976 //======================================================================
40977 /// \short Updates the polylines representation after restart
40978 //======================================================================
40979 template <class ELEMENT>
40982 {
40983 
40984  // **********************************************************************
40985  // 1) Collect the elements adjacet to the polyline boundary id and
40986  // update the polyline
40987  // **********************************************************************
40988 
40989  // (1.1) Get the face mesh representation
40990  Vector<Mesh*> face_mesh_pt;
40991  get_face_mesh_representation(polygon_pt,face_mesh_pt);
40992 
40993  // (1.2) Create vertices of the polylines by using the vertices of the
40994  // FaceElements
40995  Vector<double> vertex_coord(3); // zeta,x,y
40996  Vector<double> bound_left(1);
40997  Vector<double> bound_right(1);
40998 
40999  const unsigned n_polyline = polygon_pt->npolyline();
41000 
41001  // Go for each polyline
41002  for(unsigned p=0;p<n_polyline;p++)
41003  {
41004  // Get the MeshAsGeomObject representation just once per polyline,
41005  // this object is only used by the
41006  // refine_boundary_constrained_by_target_area() method. We get it here
41007  // to ensure that all processors (in a distributed context) get this
41008  // representation just once, and because an AllToAll MPI communication
41009  // is used in this calling
41010  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
41011 
41012  // Set of coordinates that are on the boundary
41013  // Set entries are ordered on first entry in vector which stores
41014  // the boundary coordinate so the vertices come out in order!
41015  std::set<Vector<double> > vertex_nodes;
41016 
41017  // Vector to store the vertices, transfer the sorted vertices from the
41018  // set to this vector, --- including the z-value ---
41019  Vector<Vector<double> > tmp_vector_vertex_node;
41020 
41021  // Vector to store the coordinates of the polylines, same as the
41022  // tmp_vector_vertex_node vector (after adding more nodes) but
41023  // --- without the z-value ---, used to re-generate the polylines
41024  Vector<Vector<double> > vector_vertex_node;
41025 
41026 #ifdef OOMPH_HAS_MPI
41027  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41028  // Set of coordinates that are on the boundary (splitted boundary version)
41029  // The first vector is used to allocate the points for each sub-boundary
41030  // Set entries are ordered on first entry in vector which stores
41031  // the boundary coordinate so the vertices come out in order!
41032  Vector<std::set<Vector<double> > >sub_vertex_nodes;
41033 
41034  // Vector to store the vertices, transfer the sorted vertices from the
41035  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41036  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
41037 
41038  // Vector to store the coordinates of the polylines that will represent
41039  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41040  // but --- without the z-value ---, used to generate the sub-polylines
41041  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41042  // --------- Stuff to deal with splitted boundaries ----------- End ------
41043 #endif
41044 
41045  //Get the boundary id
41046  unsigned bound=polygon_pt->curve_section_pt(p)->boundary_id();
41047 
41048  /// Use a vector of vector for vertices and target areas to
41049  /// deal with the cases when the boundaries are split by the
41050  /// distribution process
41051 
41052  // Loop over the face elements (ordered) and add their vertices
41053  const unsigned nface_element = face_mesh_pt[p]->nelement();
41054 
41055  // Store the non halo face elements, the ones from which we will
41056  // get the vertices
41057  Vector<FiniteElement*> non_halo_face_element_pt;
41058  // Map to store the index of the face element on a boundary
41059  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41060 
41061  for(unsigned ef=0;ef<nface_element;++ef)
41062  {
41063  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41064  // Skip the halo elements
41065 #ifdef OOMPH_HAS_MPI
41066  if (this->is_mesh_distributed())
41067  {
41068  // Only work with non-halo elements
41069  if (ele_face_pt->is_halo()) {continue;}
41070  }
41071 #endif
41072  // Add the face element to the vector
41073  non_halo_face_element_pt.push_back(ele_face_pt);
41074  face_element_index_on_boundary[ele_face_pt] = ef;
41075  }
41076 
41077  // Get the number of non halo face element
41078  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41079 
41080  // Map to know the already sorted face elements
41081  std::map<FiniteElement*,bool> face_element_done;
41082 
41083  // Number of done face elements
41084  unsigned nsorted_face_elements = 0;
41085 
41086 #ifdef OOMPH_HAS_MPI
41087  // Counter for sub_boundaries
41088  unsigned nsub_boundaries = 0;
41089 #endif // #ifdef OOMPH_HAS_MPI
41090 
41091  // Continue until all the face elements have been sorted
41092  // This while is to deal with the cases of splitted boundaries
41093  while(nsorted_face_elements < nnon_halo_face_element)
41094  {
41095  // Get and initial face element
41096  FiniteElement* ele_face_pt = 0;
41097 #ifdef PARANOID
41098  bool found_initial_face_element = false;
41099 #endif
41100 
41101  unsigned iface = 0;
41102  for (iface = 0; iface < nnon_halo_face_element; iface++)
41103  {
41104  ele_face_pt = non_halo_face_element_pt[iface];
41105  // If not done then take it as initial face element
41106  if (!face_element_done[ele_face_pt])
41107  {
41108 #ifdef PARANOID
41109  found_initial_face_element = true;
41110 #endif
41111  nsorted_face_elements++;
41112  iface++;
41113  break;
41114  }
41115  }
41116 
41117 #ifdef PARANOID
41118  if (!found_initial_face_element)
41119  {
41120  std::ostringstream error_message;
41121  error_message
41122  <<"Could not find an initial face element for the current segment\n";
41123  // << "----- Possible memory leak -----\n";
41124  throw OomphLibError(error_message.str(),
41125  "RefineableTriangleMesh::update_polygon_after_restart()",
41126  OOMPH_EXCEPTION_LOCATION);
41127  }
41128 #endif
41129 
41130  // Local set of coordinates that are on the boundary
41131  // Set entries are ordered on first entry in vector which stores
41132  // the boundary coordinate so the vertices come out in order!
41133  std::set<Vector<double> > local_vertex_nodes;
41134 
41135  // Vector to store the vertices, transfer the sorted vertices from the
41136  // set (local) to this vector (local), --- including the z-value ---
41137  Vector<Vector<double> > local_tmp_vector_vertex_node;
41138 
41139  // ------------------------------------------------------------------
41140  // ------------------------------------------------------------------
41141  // -----------------------------------------------------------------
41142  // Add the vertices of the initial face element to the set of local
41143  // sorted vertices
41144  // -----------------------------------------------------------------
41145  unsigned nnode = ele_face_pt->nnode();
41146  // Add the left-hand node to the set:
41147  // Boundary coordinate
41148  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
41149  vertex_coord[0] = bound_left[0];
41150 
41151  // Actual coordinates
41152  for(unsigned i=0;i<2;i++)
41153  {
41154  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
41155  }
41156  local_vertex_nodes.insert(vertex_coord);
41157 
41158  // Add the right-hand nodes to the set:
41159  // Boundary coordinate
41160  ele_face_pt->node_pt(nnode-1)->
41161  get_coordinates_on_boundary(bound,bound_right);
41162  vertex_coord[0] = bound_right[0];
41163 
41164  // Actual coordinates
41165  for(unsigned i=0;i<2;i++)
41166  {
41167  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
41168  }
41169  local_vertex_nodes.insert(vertex_coord);
41170 
41171  // The initial and final node on the set
41172  Node *first_node_pt = ele_face_pt->node_pt(0);
41173  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
41174 
41175  // Mark the current face element as done
41176  face_element_done[ele_face_pt] = true;
41177 
41178  // ------------------------------------------------------------------
41179  // ------------------------------------------------------------------
41180  // ------------------------------------------------------------------
41181 
41182  // Continue iterating if a new face element has been added to the
41183  // list
41184  bool face_element_added = false;
41185 
41186  // While a new face element has been added to the set of sorted
41187  // face elements then re-iterate
41188  do
41189  {
41190  // Start from the next face elements since we have already added
41191  // the previous one as the initial face element (any previous face
41192  // element had to be added on previous iterations)
41193  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
41194  {
41195  face_element_added = false;
41196  ele_face_pt = non_halo_face_element_pt[iiface];
41197  if (!face_element_done[ele_face_pt])
41198  {
41199  // Get each individual node to check if they are contiguous
41200  nnode = ele_face_pt->nnode();
41201  Node* left_node_pt = ele_face_pt->node_pt(0);
41202  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
41203 
41204  if (left_node_pt == first_node_pt)
41205  {
41206  first_node_pt = right_node_pt;
41207  face_element_added = true;
41208  }
41209  else if (left_node_pt == last_node_pt)
41210  {
41211  last_node_pt = right_node_pt;
41212  face_element_added = true;
41213  }
41214  else if (right_node_pt == first_node_pt)
41215  {
41216  first_node_pt = left_node_pt;
41217  face_element_added = true;
41218  }
41219  else if (right_node_pt == last_node_pt)
41220  {
41221  last_node_pt = left_node_pt;
41222  face_element_added = true;
41223  }
41224 
41225  if (face_element_added)
41226  {
41227  // Add the left-hand node to the set:
41228  // Boundary coordinate
41229  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
41230  vertex_coord[0] = bound_left[0];
41231 
41232  // Actual coordinates
41233  for(unsigned i=0;i<2;i++)
41234  {
41235  vertex_coord[i+1] = left_node_pt->x(i);
41236  }
41237  local_vertex_nodes.insert(vertex_coord);
41238 
41239  // Add the right-hand nodes to the set:
41240  // Boundary coordinate
41241  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
41242  vertex_coord[0] = bound_right[0];
41243 
41244  // Actual coordinates
41245  for(unsigned i=0;i<2;i++)
41246  {
41247  vertex_coord[i+1] = right_node_pt->x(i);
41248  }
41249  local_vertex_nodes.insert(vertex_coord);
41250 
41251  // Mark as done only if one of its nodes has been
41252  // added to the list
41253  face_element_done[ele_face_pt] = true;
41254  nsorted_face_elements++;
41255 
41256  break;
41257  }
41258 
41259  } // if (!edge_done[edge])
41260  } // for (iiedge < nedges)
41261  }while(face_element_added &&
41262  (nsorted_face_elements < nnon_halo_face_element));
41263 
41264  // -----------------------------------------------------------------
41265  // At this point we already have a sorted set of nodes and
41266  // can be used to peform the unrefinement and refinement procedures
41267  // -----------------------------------------------------------------
41268 
41269  // Get the number of nodes on the list
41270  const unsigned nlocal_nodes = local_vertex_nodes.size();
41271  // Change representation to vector for easy of handling ...
41272  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41273 
41274  // Copy the vertices of the nodes
41275  unsigned counter = 0;
41276  std::set<Vector<double> >::iterator it_vertex;
41277  for (it_vertex = local_vertex_nodes.begin();
41278  it_vertex != local_vertex_nodes.end();
41279  it_vertex++)
41280  {
41281  local_tmp_vector_vertex_node[counter].resize(3);
41282  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41283  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41284  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41285  counter++;
41286  }
41287 
41288  // *********************************************************************
41289  // 3) Create the vertices along the boundary using the target area to
41290  // define the distance among them
41291  // *********************************************************************
41292 
41293  // Clear the local containter to recover the nodes ordered using the
41294  // zeta value
41295  local_vertex_nodes.clear();
41296 
41297  // At the end of each unrefinement/refinement step store the new nodes
41298  // on the set that will give rise to the vertices of the new polyline
41299  // representation
41300  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41301  for (unsigned i = 0; i < nnew_nodes; i++)
41302  {
41303  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41304  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41305  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41306  vertex_nodes.insert(vertex_coord); // Global container
41307  local_vertex_nodes.insert(vertex_coord);
41308  }
41309 
41310 #ifdef OOMPH_HAS_MPI
41311  if (this->is_mesh_distributed())
41312  {
41313  // Add the set of vertices for the boundary, this will help to detect
41314  // if we need to deal with sub_boundaries and sub_polylines represen.
41315  sub_vertex_nodes.push_back(local_vertex_nodes);
41316  // Increase the counter for sub_boundaries
41317  nsub_boundaries++;
41318  }
41319 #endif
41320 
41321  } // while(nsorted_face_elements < nnon_halo_face_element)
41322 
41323  // Now turn into vector for ease of handling...
41324  unsigned npoly_vertex = vertex_nodes.size();
41325  tmp_vector_vertex_node.resize(npoly_vertex);
41326  unsigned count = 0;
41327  std::set<Vector<double> >::iterator it;
41328  for(it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
41329  {
41330  tmp_vector_vertex_node[count].resize(3);
41331  tmp_vector_vertex_node[count][0] = (*it)[0];
41332  tmp_vector_vertex_node[count][1] = (*it)[1];
41333  tmp_vector_vertex_node[count][2] = (*it)[2];
41334  ++count;
41335  }
41336 
41337 #ifdef OOMPH_HAS_MPI
41338  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41339 #ifdef PARANOID
41340  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41341  if (nsub_boundaries_set != nsub_boundaries)
41342  {
41343  std::ostringstream error_message;
41344  error_message
41345  << "The number of found sub-boundaries and the number of counted\n"
41346  << "sub-boundaries are different:\n"
41347  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
41348  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
41349  throw OomphLibError(error_message.str(),
41350  "RefineableTriangleMesh::update_polygon_after_restart()",
41351  OOMPH_EXCEPTION_LOCATION);
41352  }
41353 #endif
41354 
41355  // Verify if need to deal with sub_boundaries
41356  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41357  {
41358  // Mark the boundary as been splitted in the partition process
41359  this->Boundary_was_splitted[bound] = true;
41360  // Resize the vector to store the info. of sub-boundaries
41361  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41362  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41363  {
41364  // Turn info. into vector for ease of handling...
41365  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41366  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41367  unsigned subcount = 0;
41368  std::set<Vector<double> >::iterator subit;
41369  for(subit = sub_vertex_nodes[isub].begin();
41370  subit != sub_vertex_nodes[isub].end(); ++subit)
41371  {
41372  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41373  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41374  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41375  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41376  ++subcount;
41377  }
41378  }
41379  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41380  // --------- Stuff for the sub_boundaries ----- End section ------------
41381 #endif // OOMPH_HAS_MPI
41382 
41383 
41384  // For further processing the three-dimensional vector
41385  // has to be reduced to a two-dimensional vector
41386  unsigned n_vertex=tmp_vector_vertex_node.size();
41387 
41388  // Resize the vector for vectices
41389  vector_vertex_node.resize(n_vertex);
41390  for(unsigned i=0;i<n_vertex;i++)
41391  {
41392  vector_vertex_node[i].resize(2);
41393  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
41394  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
41395  }
41396 
41397 #ifdef OOMPH_HAS_MPI
41398  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41399  // Verify if need to deal with sub_boundaries
41400  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41401  {
41402  // For further processing the three-dimensional vector
41403  // has to be reduced to a two-dimensional vector
41404  // Resize the vector to store the info. of sub-boundaries
41405  sub_vector_vertex_node.resize(nsub_boundaries);
41406  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41407  {
41408  const unsigned subn_vertex =
41409  sub_tmp_vector_vertex_node[isub].size();
41410  // Resize the vector for vectices
41411  sub_vector_vertex_node[isub].resize(subn_vertex);
41412  for(unsigned i=0;i<subn_vertex;i++)
41413  {
41414  sub_vector_vertex_node[isub][i].resize(2);
41415  sub_vector_vertex_node[isub][i][0]=
41416  sub_tmp_vector_vertex_node[isub][i][1];
41417  sub_vector_vertex_node[isub][i][1]=
41418  sub_tmp_vector_vertex_node[isub][i][2];
41419  }
41420  }
41421  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41422 
41423  // We already have the info. for the sub-boundaries (if necessary)
41424  // and then we can create the sub-boundaries representations to
41425  // ease the generation of the mesh by Triangle
41426 
41427  // --------- Stuff for the sub_boundaries ----- End section ------------
41428 #endif // OOMPH_HAS_MPI
41429 
41430  // *********************************************************************
41431  // 4) Check for contiguousness
41432  // *********************************************************************
41433 #ifdef OOMPH_HAS_MPI
41434  // Only perform this checking if the mesh is not distributed
41435  // When the mesh is distributed the polylines continuity is
41436  // addressed with the sort_polylines_helper() method
41437  if (!this->is_mesh_distributed())
41438 #endif
41439  {
41440  if ( p > 0 )
41441  {
41442  //Final end point of previous line
41443  Vector<double> final_vertex_of_previous_segment;
41444  unsigned n_prev_vertex =
41445  polygon_pt->curve_section_pt(p-1)->nvertex();
41446  final_vertex_of_previous_segment =
41447  polygon_pt->polyline_pt(p-1)->
41448  vertex_coordinate(n_prev_vertex-1);
41449 
41450  unsigned prev_seg_boundary_id =
41451  polygon_pt->curve_section_pt(p-1)->boundary_id();
41452 
41453  //Find the error between the final vertex of the previous
41454  //line and the first vertex of the current line
41455  double error = 0.0;
41456  for(unsigned i=0;i<2;i++)
41457  {
41458  const double dist =
41459  final_vertex_of_previous_segment[i] -
41460  (*vector_vertex_node.begin())[i];
41461  error += dist*dist;
41462  }
41463  error = sqrt(error);
41464 
41465  //If the error is bigger than the tolerance then
41466  //we probably need to reverse, but better check
41468  {
41469  //Find the error between the final vertex of the previous
41470  //line and the last vertex of the current line
41471  double rev_error = 0.0;
41472  for(unsigned i=0;i<2;i++)
41473  {
41474  const double dist =
41475  final_vertex_of_previous_segment[i] -
41476  (*--vector_vertex_node.end())[i];
41477  rev_error += dist*dist;
41478  }
41479  rev_error = sqrt(rev_error);
41480 
41481  if(rev_error >
41483  {
41484  // It could be possible that the first segment be reversed and we
41485  // did not notice it because this check does not apply for the
41486  // first segment. We can verify if the first segment is reversed
41487  // by using the vertex number 1
41488  if (p == 1)
41489  {
41490  //Initial end point of previous line
41491  Vector<double> initial_vertex_of_previous_segment;
41492 
41493  initial_vertex_of_previous_segment =
41494  polygon_pt->polyline_pt(p-1)->
41495  vertex_coordinate(0);
41496 
41497  unsigned prev_seg_boundary_id =
41498  polygon_pt->curve_section_pt(p-1)->boundary_id();
41499 
41500  //Find the error between the initial vertex of the previous
41501  //line and the first vertex of the current line
41502  double error = 0.0;
41503  for(unsigned i=0;i<2;i++)
41504  {
41505  const double dist =
41506  initial_vertex_of_previous_segment[i] -
41507  (*vector_vertex_node.begin())[i];
41508  error += dist*dist;
41509  }
41510  error = sqrt(error); // Reversed only the previous one
41511 
41512  //If the error is bigger than the tolerance then
41513  //we probably need to reverse, but better check
41515  {
41516  //Find the error between the final vertex of the previous
41517  //line and the last vertex of the current line
41518  double rev_error = 0.0;
41519  for(unsigned i=0;i<2;i++)
41520  {
41521  const double dist =
41522  initial_vertex_of_previous_segment[i] -
41523  (*--vector_vertex_node.end())[i];
41524  rev_error += dist*dist;
41525  }
41526  rev_error = sqrt(rev_error); // Reversed both the current one and
41527  // the previous one
41528 
41529  if (rev_error >
41531  {
41532  std::ostringstream error_stream;
41533  error_stream
41534  <<"The distance between the first node of the current\n"
41535  <<"line segment (boundary " << bound << ") and either end of "
41536  << "the previous line segment\n"
41537  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
41538  << "the desired tolerance " <<
41540  << "This suggests that the polylines defining the polygonal\n"
41541  << "representation are not properly ordered.\n"
41542  << "Fail on last vertex of polyline: ("
41543  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
41544  << bound << ").\nThis should have failed when first trying to"
41545  << " construct the\npolygon.\n";
41546  throw OomphLibError(error_stream.str(),
41547  "RefineableTriangleMesh::update_polygon_after_restart()",
41548  OOMPH_EXCEPTION_LOCATION);
41549  }
41550  else
41551  {
41552  // Reverse both
41553  // Reverse the current vector to line up with the previous one
41554  std::reverse(vector_vertex_node.begin(),
41555  vector_vertex_node.end());
41556  polygon_pt->polyline_pt(p-1)->reverse();
41557  }
41558  }
41559  else
41560  {
41561  // Reverse the previous one
41562  polygon_pt->polyline_pt(p-1)->reverse();
41563  }
41564 
41565  } // if p == 1
41566  else
41567  {
41568  std::ostringstream error_stream;
41569  error_stream
41570  <<"The distance between the first node of the current\n"
41571  <<"line segment (boundary " << bound << ") and either end of "
41572  <<"the previous line segment\n"
41573  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
41574  <<"desired tolerance " <<
41576  <<"This suggests that the polylines defining the polygonal\n"
41577  <<"representation are not properly ordered.\n"
41578  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
41579  << ") and\nfirst vertex of polyline (" << bound << ").\n"
41580  << "This should have failed when first trying to construct the\n"
41581  << "polygon.\n";
41582  throw OomphLibError(
41583  error_stream.str(),
41584  "RefineableTriangleMesh::update_polygon_after_restart()",
41585  OOMPH_EXCEPTION_LOCATION);
41586  }
41587  }
41588  else
41589  {
41590  //Reverse the current vector to line up with the previous one
41591  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
41592  }
41593  } // error
41594  } // p > 0
41595  } // is mesh not distributed
41596 
41597  // *********************************************************************
41598  // 5) Update the polylines representation
41599  // *********************************************************************
41600  // if (applied_area_length_constraint)
41601  // If only applied when there is a change then it keeps the
41602  // previous polyline representation, it means, it does not delete
41603  // the boundaries that are not part of the domain. We must update
41604  // the boundary representation
41605  {
41606  n_vertex = vector_vertex_node.size();
41607 
41608  // Now update the polyline according to the new vertices
41609  // The new one representation
41610  TriangleMeshPolyLine *tmp_polyline_pt =
41611  new TriangleMeshPolyLine(vector_vertex_node,bound);
41612 
41613  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41614  // {
41615  // DEBP(h);
41616  // DEBP(vector_vertex_node[h][0]);
41617  // DEBP(vector_vertex_node[h][1]);
41618  // }
41619 
41620  // Create a temporal "curve section" version of the recently created
41621  // polyline
41622  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
41623 
41624  // Tolerance below which the middle point can be deleted
41625  // (ratio of deflection to element length)
41626  double unrefinement_tolerance=
41627  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41628 
41629  // Tolerance to add points
41630  double refinement_tolerance=
41631  polygon_pt->polyline_pt(p)->refinement_tolerance();
41632 
41633  // Establish refinement and unrefinement tolerance
41634  tmp_polyline_pt->set_unrefinement_tolerance(
41635  unrefinement_tolerance);
41636  tmp_polyline_pt->set_refinement_tolerance(
41637  refinement_tolerance);
41638 
41639  // Establish the maximum length constraint
41640  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41641  tmp_polyline_pt->set_maximum_length(maximum_length);
41642 
41643  if (n_vertex >= 2)
41644  {
41645  // Pass the connection information from the old polyline to the
41646  // new one
41647  this->copy_connection_information(polygon_pt->polyline_pt(p),
41648  tmp_curve_section_pt);
41649  }
41650 
41651  //Now update the polyline according to the new vertices but
41652  //first check if the object is allowed to delete the representation
41653  //or if it should be done by other object
41654  bool delete_it_on_destructor = false;
41655 
41656  std::set<TriangleMeshCurveSection*>::iterator it =
41657  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41658 
41659  if (it!=this->Free_curve_section_pt.end())
41660  {
41661  this->Free_curve_section_pt.erase(it);
41662  delete polygon_pt->curve_section_pt(p);
41663  delete_it_on_destructor = true;
41664  }
41665 
41666  // *****************************************************************
41667  // Copying the new representation
41668  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41669 
41670  // Update the Boundary - Polyline map
41671  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
41672 
41673  if (delete_it_on_destructor)
41674  {
41675  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41676  }
41677 
41678 #ifdef OOMPH_HAS_MPI
41679  // --------- Stuff for the sub_boundaries ----- Begin section --------
41680  // Verify if need to deal with sub_boundaries
41681  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41682  {
41683  // Create temporary representations for the boundaries, only to
41684  // create the mesh when calling Triangle
41685  // Clear all previous stored data
41686  this->Boundary_subpolylines[bound].clear();
41687  // Now create storage for the sub-boundaries
41688  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41689  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41690  {
41691  // Now update the polyline according to the sub set of
41692  // vertices, set the chunk number of the polyline
41693  TriangleMeshPolyLine *sub_tmp_polyline_pt =
41694  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
41695 
41696  // Add the sub-polyline to the container to represent the boundary
41697  // in parts
41698  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
41699 
41700  // No need to send the unrefinement/refinement and maximum
41701  // length constraints since these are only temporary
41702  // representations. These polylines can be deleted once the
41703  // new polygons that represent the distributed domain have
41704  // been created
41705 
41706  } // for (isub < nsub_boundaries)
41707 
41708  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41709  // --------- Stuff for the sub_boundaries ----- End section ---------
41710 #endif // OOMPH_HAS_MPI
41711 
41712  } // update polyline representation
41713 
41714  // Delete the allocated memory for the geometric object that
41715  // represents the curvilinear boundary
41716  delete mesh_geom_obj_pt;
41717 
41718  } // npolyline
41719 
41720  // Cleanup the face mesh
41721  for(unsigned p=0;p<n_polyline;p++)
41722  {
41723  face_mesh_pt[p]->flush_node_storage();
41724  delete face_mesh_pt[p];
41725  }
41726 
41727 }
41728 
41729 
41730 //======================================================================
41731 /// \short Updates the open curve representation after restart
41732 //======================================================================
41733 template <class ELEMENT>
41736 {
41737  // **********************************************************************
41738  // 1) Get the vertices along the boundaries ids of the polylines and
41739  // update them
41740  // **********************************************************************
41741 
41742  // (1.1) Get the face mesh representation
41743  Vector<Mesh*> face_mesh_pt;
41744  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
41745 
41746  // (1.2) Create vertices of the polylines by using the vertices of the
41747  // FaceElements
41748  Vector<double> vertex_coord(3); // zeta,x,y
41749  Vector<double> bound_left(1);
41750  Vector<double> bound_right(1);
41751 
41752  const unsigned ncurve_section = open_curve_pt->ncurve_section();
41753  // Go for each curve section
41754  for(unsigned cs = 0; cs < ncurve_section; cs++)
41755  {
41756  // Get the MeshAsGeomObject representation just once per polyline,
41757  // this object is only used by the
41758  // refine_boundary_constrained_by_target_area() method. We get it here
41759  // to ensure that all processors (in a distributed context) get this
41760  // representation just once, and because an AllToAll MPI communication
41761  // is used in this calling
41762  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
41763 
41764  //Get the boundary id
41765  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
41766 
41767  /// Use a vector of vector for vertices and target areas to deal
41768  /// with the cases when the boundaries are split bn the
41769  /// distribution process. Internal boundaries may be completely or
41770  /// partially overlapped by shared boundaries
41771 
41772  // Loop over the face elements and add their vertices (they are
41773  // automatically sorted because of the set)
41774  const unsigned nface_element = face_mesh_pt[cs]->nelement();
41775  // Store the non halo elements and the element at the other side of
41776  // the boundary (whatever it be halo or not), the first will be the
41777  // ones from which we will get the vertices (in even position)
41778  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
41779 
41780  // Map to store the index of the face element on a boundary
41781  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41782 
41783  // Map to know the already sorted face elements
41784  std::map<FiniteElement*,bool> face_element_done;
41785 
41786  for(unsigned ef = 0; ef < nface_element; ++ef)
41787  {
41788  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
41789 
41790  // Skip the halo elements (not used as base elements, only
41791  // include those elements which one of its counterparts -- at the
41792  // other side of the boundary -- is non halo)
41793 #ifdef OOMPH_HAS_MPI
41794  if (this->is_mesh_distributed())
41795  {
41796  // Only work with non-halo elements
41797  if (ele_face_pt->is_halo()) {continue;}
41798  }
41799 #endif
41800 
41801  // Check if not already done
41802  if (!face_element_done[ele_face_pt])
41803  {
41804  // Add the element and look for the element at the other side
41805  // of the boundary to add it immediately after the new added
41806  // element
41807  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
41808  // Create the map of the face element with the index
41809  face_element_index_on_boundary[ele_face_pt] = ef;
41810  // Mark the current element as done
41811  face_element_done[ele_face_pt] = true;
41812  // Get the number of nodes
41813  const unsigned nnodes = ele_face_pt->nnode();
41814  // Get the left and right node to look for the elements at the
41815  // other side of the boundary
41816  Node* left_node_pt = ele_face_pt->node_pt(0);
41817  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
41818 
41819 #ifdef PARANOID
41820  // Flag to know if the element at the other side of the
41821  // boundary was found
41822  bool found_other_side_face_ele = false;
41823 #endif
41824  for (unsigned iface = 0; iface < nface_element; iface++)
41825  {
41826  // Get the candidate face element
41827  FiniteElement *cele_face_pt =
41828  face_mesh_pt[cs]->finite_element_pt(iface);
41829  // Check if not already done
41830  if (!face_element_done[cele_face_pt])
41831  {
41832  Node* cleft_node_pt = cele_face_pt->node_pt(0);
41833  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
41834 
41835  // Check if the nodes are the same
41836  if ((left_node_pt == cleft_node_pt &&
41837  right_node_pt == cright_node_pt) ||
41838  (left_node_pt == cright_node_pt &&
41839  right_node_pt == cleft_node_pt))
41840  {
41841  // Add the element to the storage
41842  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
41843  // ... and mark the element as done
41844  face_element_done[cele_face_pt] = true;
41845  // Create the map of the face element with the index
41846  face_element_index_on_boundary[cele_face_pt] = iface;
41847 #ifdef PARANOID
41848  // Set the flag of found other side face element
41849  found_other_side_face_ele = true;
41850 #endif
41851  break;
41852  }
41853  }
41854  } // (iface < nface_element)
41855 
41856 #ifdef PARANOID
41857  if (!found_other_side_face_ele)
41858  {
41859  std::ostringstream error_message;
41860  error_message
41861  << "The face element at the other side of the boundary ("
41862  << bound << ") was not found!!\n"
41863  << "These are the nodes of the face element:\n"
41864  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
41865  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
41866  throw OomphLibError(error_message.str(),
41867  "RefineableTriangleMesh::update_open_curve_after_restart()",
41868  OOMPH_EXCEPTION_LOCATION);
41869  }
41870 #endif
41871  } // if (!face_ele_done[ele_face_pt])
41872 
41873  } // (ef < nface_element)
41874 
41875  // Clear the map of the already done face elements
41876  // This will now be used to sort the face elements
41877  face_element_done.clear();
41878 
41879  // Set of coordinates that are on the boundary
41880  // The entries are sorted on first entry in vector which stores
41881  // the boundary coordinate so the vertices come out in order!
41882  std::set<Vector<double> > vertex_nodes;
41883 
41884  // Vector to store the vertices, transfer the sorted vertices from the
41885  // set to this vector, --- including the z-value ---
41886  Vector<Vector<double> > tmp_vector_vertex_node;
41887 
41888  // Vector to store the coordinates of the polylines, same as the
41889  // tmp_vector_vertex_node vector (after adding more nodes) but
41890  // --- without the z-value ---, used to re-generate the polylines
41891  Vector<Vector<double> > vector_vertex_node;
41892 
41893 #ifdef OOMPH_HAS_MPI
41894  // Indicates if the set of vertices give rise to a internal
41895  // boundary that will be used as shared boundary or as normal
41896  // internal boundary -- Only used to deal with internal boundaries
41897  // in a distributed scheme
41898  std::vector<bool> internal_to_shared_boundary;
41899 
41900  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41901  // Set of coordinates that are on the boundary (splitted boundary version)
41902  // The first vector is used to allocate the points for each sub-boundary
41903  // Set entries are ordered on first entry in vector which stores
41904  // the boundary coordinate so the vertices come out in order!
41905  Vector<std::set<Vector<double> > > sub_vertex_nodes;
41906 
41907  // Vector to store the vertices, transfer the sorted vertices from the
41908  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41909  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
41910 
41911  // Vector to store the coordinates of the polylines that will represent
41912  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41913  // but --- without the z-value ---, used to generate the sub-polylines
41914  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41915 
41916  // --------- Stuff to deal with splitted boundaries ----------- End ------
41917 #endif
41918 
41919  // Sort face elements, separate those with both nonhalo face
41920  // elements from those with one halo and one nonhalo face element
41921 
41922  // Number of done face elements
41923  unsigned nsorted_face_elements = 0;
41924 
41925 #ifdef OOMPH_HAS_MPI
41926  // Counter for sub_boundaries
41927  unsigned nsub_boundaries = 0;
41928 #endif // #ifdef OOMPH_HAS_MPI
41929 
41930  // Total number of non halo double face element
41931  const unsigned nnon_halo_doubled_face_ele =
41932  non_halo_doubled_face_element_pt.size();
41933 
41934  // Continue until all the face elements have been sorted
41935  // This while is to deal with the cases of splitted boundaries
41936  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
41937  {
41938  // Get and initial face element
41939  FiniteElement* ele_face_pt = 0;
41940  FiniteElement* repeated_ele_face_pt = 0;
41941 #ifdef PARANOID
41942  bool found_initial_face_element = false;
41943 #endif
41944 
41945  // Flag to know if we are working with a face element which the
41946  // face element at the other side of the boundary is also non
41947  // halo
41948  bool both_root_face_elements_are_nonhalo = false;
41949 
41950  unsigned iface = 0;
41951  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
41952  {
41953  ele_face_pt = non_halo_doubled_face_element_pt[iface];
41954  // If not done then take it as initial face element
41955  if (!face_element_done[ele_face_pt])
41956  {
41957  // Mark it as done
41958  face_element_done[ele_face_pt] = true;
41959  // Get the other side boundary face element
41960  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
41961  // ... also mark as done the repeated face element
41962  face_element_done[repeated_ele_face_pt] = true;
41963 
41964 #ifdef OOMPH_HAS_MPI
41965  if (!repeated_ele_face_pt->is_halo())
41966  {both_root_face_elements_are_nonhalo = true;}
41967 #endif // #ifdef OOMPH_HAS_MPI
41968 
41969  // Plus two because internal boundaries have
41970  // two face elements per each edge
41971  nsorted_face_elements+=2;
41972  iface+=2;
41973 #ifdef PARANOID
41974  // And set the flag to true
41975  found_initial_face_element = true;
41976 #endif
41977  break;
41978  }
41979  }
41980 
41981 #ifdef PARANOID
41982  if (!found_initial_face_element)
41983  {
41984  std::ostringstream error_message;
41985  error_message
41986  <<"Could not find an initial face element for the current segment\n";
41987  // << "----- Possible memory leak -----\n";
41988  throw OomphLibError(error_message.str(),
41989  OOMPH_CURRENT_FUNCTION,
41990  OOMPH_EXCEPTION_LOCATION);
41991  }
41992 #endif
41993 
41994  // Local set of coordinates that are on the boundary Set entries
41995  // are ordered on first entry in vector which stores the boundary
41996  // coordinate so the vertices come out in order
41997  std::set<Vector<double> > local_vertex_nodes;
41998 
41999  // Vector to store the vertices, transfer the sorted vertices from the
42000  // set (local) to this vector (local), --- including the z-value ---
42001  Vector<Vector<double> > local_tmp_vector_vertex_node;
42002 
42003  // ------------------------------------------------------------------
42004  // ------------------------------------------------------------------
42005  // Add the vertices of the initial face element to the set of local
42006  // sorted vertices
42007  // ------------------------------------------------------------------
42008  // ------------------------------------------------------------------
42009  const unsigned nnode = ele_face_pt->nnode();
42010  // Add the left-hand node to the set:
42011  // Boundary coordinate
42012  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
42013  vertex_coord[0] = bound_left[0];
42014 
42015  // Actual coordinates
42016  for(unsigned i=0;i<2;i++)
42017  {
42018  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
42019  }
42020  local_vertex_nodes.insert(vertex_coord);
42021 
42022  // Add the right-hand node to the set:
42023  // Boundary coordinate
42024  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
42025  bound_right);
42026  vertex_coord[0] = bound_right[0];
42027 
42028  // Actual coordinates
42029  for(unsigned i=0;i<2;i++)
42030  {
42031  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
42032  }
42033  local_vertex_nodes.insert(vertex_coord);
42034 
42035  // The initial and final node on the set
42036  Node *first_node_pt = ele_face_pt->node_pt(0);
42037  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
42038 
42039  // Continue iterating if a new face element has been added to the
42040  // list
42041  bool face_element_added = false;
42042 
42043  // While a new face element has been added to the set of sorted
42044  // face elements then re-iterate
42045  do
42046  {
42047  // Start from the next face elements since we have already
42048  // added the previous one as the initial face element (any
42049  // previous face element had to be added on previous
42050  // iterations)
42051  for (unsigned iiface=iface;
42052  iiface<nnon_halo_doubled_face_ele;iiface+=2)
42053  {
42054  face_element_added = false;
42055  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42056 
42057  // Check that the face element with which we are working has
42058  // the same conditions as the root face element (both faces
42059  // are nonhalo or one face is halo and the other nonhalo)
42060 
42061  // Get the face element at the other side of the boundary
42062  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42063  bool both_face_elements_are_nonhalo = false;
42064 
42065 #ifdef OOMPH_HAS_MPI
42066  if (!repeated_ele_face_pt->is_halo())
42067  {both_face_elements_are_nonhalo = true;}
42068 #endif // #ifdef OOMPH_HAS_MPI
42069 
42070  if (!face_element_done[ele_face_pt] &&
42071  (both_face_elements_are_nonhalo ==
42072  both_root_face_elements_are_nonhalo))
42073  {
42074  // Get each individual node to check if they are contiguous
42075  const unsigned nlnode = ele_face_pt->nnode();
42076  Node* left_node_pt = ele_face_pt->node_pt(0);
42077  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
42078 
42079  if (left_node_pt == first_node_pt)
42080  {
42081  first_node_pt = right_node_pt;
42082  face_element_added = true;
42083  }
42084  else if (left_node_pt == last_node_pt)
42085  {
42086  last_node_pt = right_node_pt;
42087  face_element_added = true;
42088  }
42089  else if (right_node_pt == first_node_pt)
42090  {
42091  first_node_pt = left_node_pt;
42092  face_element_added = true;
42093  }
42094  else if (right_node_pt == last_node_pt)
42095  {
42096  last_node_pt = left_node_pt;
42097  face_element_added = true;
42098  }
42099 
42100  if (face_element_added)
42101  {
42102  // Add the left-hand node to the set:
42103  // Boundary coordinate
42104  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
42105  vertex_coord[0] = bound_left[0];
42106 
42107  // Actual coordinates
42108  for(unsigned i=0;i<2;i++)
42109  {
42110  vertex_coord[i+1] = left_node_pt->x(i);
42111  }
42112  local_vertex_nodes.insert(vertex_coord);
42113 
42114  // Add the right-hand nodes to the set:
42115  // Boundary coordinate
42116  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
42117  vertex_coord[0] = bound_right[0];
42118 
42119  // Actual coordinates
42120  for(unsigned i=0;i<2;i++)
42121  {
42122  vertex_coord[i+1] = right_node_pt->x(i);
42123  }
42124  local_vertex_nodes.insert(vertex_coord);
42125 
42126  // Mark as done only if one of its nodes has been
42127  // added to the list
42128  face_element_done[ele_face_pt] = true;
42129  // .. also mark as done the face element at the othe side of
42130  // the boundary
42131  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42132  face_element_done[repeated_ele_face_pt] = true;
42133  // ... and increase the number of sorted face elements
42134  nsorted_face_elements+=2;
42135 
42136  break;
42137  }
42138 
42139  } // if (!face_element_done[[ele_face_pt])
42140  } // for (iiface<nnon_halo_doubled_face_ele)
42141  }while(face_element_added &&
42142  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42143 
42144  // -------------------------------------------------------------
42145  // At this point we already have a sorted set of nodes and can
42146  // be used to peform the unrefinement and refinement procedures
42147  // -------------------------------------------------------------
42148 
42149  // Get the number of nodes on the list
42150  const unsigned nlocal_nodes = local_vertex_nodes.size();
42151  // Change representation to vector for easy of handling ...
42152  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42153 
42154  // Copy the vertices of the nodes
42155  unsigned counter = 0;
42156  std::set<Vector<double> >::iterator it_vertex;
42157  for (it_vertex = local_vertex_nodes.begin();
42158  it_vertex != local_vertex_nodes.end();
42159  it_vertex++)
42160  {
42161  local_tmp_vector_vertex_node[counter].resize(3);
42162  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42163  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42164  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42165  counter++;
42166  }
42167 
42168  // The unrefinement and refinement process needs to be applied
42169  // from the bottom-left node since the internal open curve could
42170  // lie on the shared boundaries
42171  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
42172  local_tmp_vector_vertex_node[0][2])
42173  {
42174  std::reverse(local_tmp_vector_vertex_node.begin(),
42175  local_tmp_vector_vertex_node.end());
42176  }
42177  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
42178  local_tmp_vector_vertex_node[0][2])
42179  {
42180  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
42181  local_tmp_vector_vertex_node[0][1])
42182  {
42183  std::reverse(local_tmp_vector_vertex_node.begin(),
42184  local_tmp_vector_vertex_node.end());
42185  }
42186  }
42187 
42188  // ****************************************************************
42189  // 3) Create the vertices along the boundary using the target
42190  // area to define the distance among them
42191  // ****************************************************************
42192 
42193  // Clear the local containter to recover the nodes ordered using
42194  // the zeta value
42195  local_vertex_nodes.clear();
42196 
42197  // At the end of each unrefinement/refinement step store the new
42198  // nodes on the set that will give rise to the vertices of the
42199  // new polyline representation
42200  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42201  for (unsigned i = 0; i < nnew_nodes; i++)
42202  {
42203  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42204  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42205  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42206  vertex_nodes.insert(vertex_coord); // Global container
42207  local_vertex_nodes.insert(vertex_coord);
42208  }
42209 
42210 #ifdef OOMPH_HAS_MPI
42211  if (this->is_mesh_distributed())
42212  {
42213  // Add the set of vertices for the boundary, this will help to
42214  // detect if we need to deal with sub_boundaries and
42215  // sub_polylines representations
42216  sub_vertex_nodes.push_back(local_vertex_nodes);
42217  // Increase the counter for sub_boundaries
42218  nsub_boundaries++;
42219 
42220  // Mark if the polyline created by these vertices will be used
42221  // as a shared boundary or as an internal boundary
42222  if (both_root_face_elements_are_nonhalo)
42223  {internal_to_shared_boundary.push_back(false);}
42224  else
42225  {internal_to_shared_boundary.push_back(true);}
42226  }
42227 #endif
42228 
42229  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42230  // This while is in charge of sorting all the face elements to
42231  // create the new representation of the polyline (also deals
42232  // with the sub-boundary cases)
42233 
42234  // Now turn into vector for ease of handling...
42235  const unsigned npoly_vertex = vertex_nodes.size();
42236  tmp_vector_vertex_node.resize(npoly_vertex);
42237  unsigned count = 0;
42238  std::set<Vector<double> >::iterator it;
42239  for (it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
42240  {
42241  tmp_vector_vertex_node[count].resize(3);
42242  tmp_vector_vertex_node[count][0] = (*it)[0];
42243  tmp_vector_vertex_node[count][1] = (*it)[1];
42244  tmp_vector_vertex_node[count][2] = (*it)[2];
42245  ++count;
42246  }
42247 
42248 #ifdef OOMPH_HAS_MPI
42249  // Check that the number of set of vertices marked to be shared or
42250  // internal boundaries be the same as the total number of
42251  // sub-boundaries
42252 #ifdef PARANOID
42253  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42254  const unsigned ninternal_to_shared_boundaries =
42255  internal_to_shared_boundary.size();
42256  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42257  {
42258  std::ostringstream error_message;
42259  error_message
42260  << "The number of found sub-boundaries and the number of marked "
42261  << "internal\nboundaries are different\n"
42262  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42263  << "Number of marked internal boundaries: ("
42264  << ninternal_to_shared_boundaries << ")\n\n";
42265  throw OomphLibError(error_message.str(),
42266  "RefineableTriangleMesh::update_open_curve_after_restart()",
42267  OOMPH_EXCEPTION_LOCATION);
42268  }
42269 #endif
42270 
42271  // --------- Stuff for the sub_boundaries ----- Begin section -------
42272 #ifdef PARANOID
42273  if (nsub_boundaries_set != nsub_boundaries)
42274  {
42275  std::ostringstream error_message;
42276  error_message
42277  << "The number of found sub-boundaries and the number of counted\n"
42278  << "sub-boundaries are different:\n"
42279  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42280  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
42281  throw OomphLibError(error_message.str(),
42282  "RefineableTriangleMesh::update_open_curve_after_restart()",
42283  OOMPH_EXCEPTION_LOCATION);
42284  }
42285 #endif
42286 
42287  // Verify if need to deal with sub_boundaries
42288  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42289  {
42290  // Mark the boundary as been splitted in the partition process
42291  this->Boundary_was_splitted[bound] = true;
42292  // Resize the vector to store the info. of sub-boundaries
42293  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42294  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42295  {
42296  // Turn info. into vector for ease of handling...
42297  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42298  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42299  unsigned subcount = 0;
42300  std::set<Vector<double> >::iterator subit;
42301  for(subit = sub_vertex_nodes[isub].begin();
42302  subit != sub_vertex_nodes[isub].end(); ++subit)
42303  {
42304  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42305  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42306  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42307  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42308  ++subcount;
42309  }
42310  }
42311  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42312  // --------- Stuff for the sub_boundaries ----- End section ----------
42313 #endif // OOMPH_HAS_MPI
42314 
42315  // For further processing the three-dimensional vector has to be
42316  // reduced to a two-dimensional vector
42317  unsigned n_vertex=tmp_vector_vertex_node.size();
42318 
42319  // Resize the vector for vectices
42320  vector_vertex_node.resize(n_vertex);
42321  for(unsigned i=0;i<n_vertex;i++)
42322  {
42323  vector_vertex_node[i].resize(2);
42324  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
42325  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
42326  }
42327 
42328 #ifdef OOMPH_HAS_MPI
42329  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42330  // Verify if need to deal with sub_boundaries
42331  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42332  {
42333  // For further processing the three-dimensional vector
42334  // has to be reduced to a two-dimensional vector
42335  // Resize the vector to store the info. of sub-boundaries
42336  sub_vector_vertex_node.resize(nsub_boundaries);
42337  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42338  {
42339  const unsigned subn_vertex =
42340  sub_tmp_vector_vertex_node[isub].size();
42341  // Resize the vector for vectices
42342  sub_vector_vertex_node[isub].resize(subn_vertex);
42343  for(unsigned i=0;i<subn_vertex;i++)
42344  {
42345  sub_vector_vertex_node[isub][i].resize(2);
42346  sub_vector_vertex_node[isub][i][0]=
42347  sub_tmp_vector_vertex_node[isub][i][1];
42348  sub_vector_vertex_node[isub][i][1]=
42349  sub_tmp_vector_vertex_node[isub][i][2];
42350  }
42351  }
42352  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42353 
42354  // We already have the info. for the sub-boundaries (if necessary) and
42355  // then we can create the sub-boundaries representations to ease the
42356  // generation of the mesh by Triangle
42357 
42358  // --------- Stuff for the sub_boundaries ----- End section ------------
42359 #endif // OOMPH_HAS_MPI
42360 
42361  // *********************************************************************
42362  // 4) Check for contiguousness
42363  // *********************************************************************
42364 #ifdef OOMPH_HAS_MPI
42365  // Only perform this checking if the mesh is not distributed
42366  // When the mesh is distributed the polylines continuity is
42367  // addressed with the sort_polylines_helper() method
42368  if (!this->is_mesh_distributed())
42369 #endif
42370  {
42371  if ( cs > 0 )
42372  {
42373  //Final end point of previous line
42374  Vector<double> final_vertex_of_previous_segment;
42375  unsigned n_prev_vertex =
42376  open_curve_pt->curve_section_pt(cs-1)->nvertex();
42377  final_vertex_of_previous_segment =
42378  open_curve_pt->polyline_pt(cs-1)->
42379  vertex_coordinate(n_prev_vertex-1);
42380 
42381  unsigned prev_seg_boundary_id =
42382  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42383 
42384  //Find the error between the final vertex of the previous
42385  //line and the first vertex of the current line
42386  double error = 0.0;
42387  for(unsigned i=0;i<2;i++)
42388  {
42389  const double dist =
42390  final_vertex_of_previous_segment[i] -
42391  (*vector_vertex_node.begin())[i];
42392  error += dist*dist;
42393  }
42394  error = sqrt(error);
42395 
42396  //If the error is bigger than the tolerance then
42397  //we probably need to reverse, but better check
42399  {
42400  //Find the error between the final vertex of the previous
42401  //line and the last vertex of the current line
42402  double rev_error = 0.0;
42403  for(unsigned i=0;i<2;i++)
42404  {
42405  const double dist =
42406  final_vertex_of_previous_segment[i] -
42407  (*--vector_vertex_node.end())[i];
42408  rev_error += dist*dist;
42409  }
42410  rev_error = sqrt(rev_error);
42411 
42412  if(rev_error >
42414  {
42415  // It could be possible that the first segment be reversed and we
42416  // did not notice it because this check does not apply for the
42417  // first segment. We can verify if the first segment is reversed
42418  // by using the vertex number 1
42419  if (cs == 1)
42420  {
42421  //Initial end point of previous line
42422  Vector<double> initial_vertex_of_previous_segment;
42423 
42424  initial_vertex_of_previous_segment =
42425  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
42426 
42427  unsigned prev_seg_boundary_id =
42428  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42429 
42430  //Find the error between the initial vertex of the previous
42431  //line and the first vertex of the current line
42432  double error = 0.0;
42433  for(unsigned i=0;i<2;i++)
42434  {
42435  const double dist =
42436  initial_vertex_of_previous_segment[i] -
42437  (*vector_vertex_node.begin())[i];
42438  error += dist*dist;
42439  }
42440  error = sqrt(error); // Reversed only the previous one
42441 
42442  //If the error is bigger than the tolerance then
42443  //we probably need to reverse, but better check
42445  {
42446  //Find the error between the final vertex of the previous
42447  //line and the last vertex of the current line
42448  double rev_error = 0.0;
42449  for(unsigned i=0;i<2;i++)
42450  {
42451  const double dist =
42452  initial_vertex_of_previous_segment[i] -
42453  (*--vector_vertex_node.end())[i];
42454  rev_error += dist*dist;
42455  }
42456  rev_error = sqrt(rev_error); // Reversed both the current
42457  // one and the previous one
42458 
42459  if (rev_error >
42461  {
42462  std::ostringstream error_stream;
42463  error_stream
42464  <<"The distance between the first node of the current\n"
42465  <<"line segment (boundary "<<bound<<") and either end of "
42466  <<"the previous line segment\n"
42467  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
42468  << " the desired tolerance " <<
42470  <<"This suggests that the polylines defining the polygonal\n"
42471  <<"representation are not properly ordered.\n"
42472  <<"Fail on last vertex of polyline: ("
42473  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
42474  <<bound<< ").\nThis should have failed when first trying to "
42475  <<"construct the\npolygon.\n";
42476  throw OomphLibError(error_stream.str(),
42477  "RefineableTriangleMesh::update_open_curve_after_restart()",
42478  OOMPH_EXCEPTION_LOCATION);
42479  }
42480  else
42481  {
42482  // Reverse both
42483  // Reverse the current vector to line up with the previous one
42484  std::reverse(vector_vertex_node.begin(),
42485  vector_vertex_node.end());
42486  open_curve_pt->polyline_pt(cs-1)->reverse();
42487  }
42488  }
42489  else
42490  {
42491  // Reverse the previous one
42492  open_curve_pt->polyline_pt(cs-1)->reverse();
42493  }
42494 
42495  } // if (cs == 1)
42496  else
42497  {
42498  std::ostringstream error_stream;
42499  error_stream
42500  <<"The distance between the first node of the current\n"
42501  <<"line segment (boundary " << bound << ") and either end of "
42502  <<"the previous line segment\n"
42503  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
42504  <<"desired tolerance " <<
42506  <<"This suggests that the polylines defining the polygonal\n"
42507  <<"representation are not properly ordered.\n"
42508  <<"Fail on last vertex of polyline: (" << prev_seg_boundary_id
42509  <<") and\nfirst vertex of polyline (" << bound << ").\n"
42510  <<"This should have failed when first trying to construct the\n"
42511  <<"polygon.\n";
42512  throw OomphLibError(
42513  error_stream.str(),
42514  "RefineableTriangleMesh::update_open_curve_after_restart()",
42515  OOMPH_EXCEPTION_LOCATION);
42516  }
42517  }
42518  else
42519  {
42520  //Reverse the current vector to line up with the previous one
42521  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
42522  }
42523  } // error
42524  } // (cs > 0)
42525  } // is mesh not distributed
42526 
42527  // DEBP(applied_area_length_constraint);
42528  // DEBP(p);
42529  // getchar();
42530  // *********************************************************************
42531  // 5) Update the polylines representation
42532  // *********************************************************************
42533  // if (applied_area_length_constraint)
42534  // If only applied when there is a change then it keeps the
42535  // previous polyline representation, it means, it does not delete
42536  // the boundaries that are not part of the domain. We must update
42537  // the boundary representation
42538  {
42539  n_vertex = vector_vertex_node.size();
42540 
42541  // Now update the polyline according to the new vertices
42542  // The new one representation
42543  TriangleMeshPolyLine *tmp_polyline_pt =
42544  new TriangleMeshPolyLine(vector_vertex_node,bound);
42545 
42546  // Create a temporal "curve section" version of the recently created
42547  // polyline
42548  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
42549 
42550  // Tolerance below which the middle point can be deleted
42551  // (ratio of deflection to element length)
42552  double unrefinement_tolerance=
42553  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42554 
42555  // Tolerance to add points
42556  double refinement_tolerance=
42557  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42558 
42559  // Establish refinement and unrefinement tolerance
42560  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42561  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42562 
42563  // Establish the maximum length constraint
42564  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
42565  tmp_polyline_pt->set_maximum_length(maximum_length);
42566 
42567  if (n_vertex >= 2)
42568  {
42569  // Pass the connection information from the old polyline to the
42570  // new one
42571  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42572  tmp_curve_section_pt);
42573  }
42574 
42575  //Now update the polyline according to the new vertices but first
42576  //check if the object is allowed to delete the representation or
42577  //if it should be done by other object
42578  bool delete_it_on_destructor = false;
42579 
42580  std::set<TriangleMeshCurveSection*>::iterator it =
42581  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42582 
42583  if (it!=this->Free_curve_section_pt.end())
42584  {
42585  this->Free_curve_section_pt.erase(it);
42586  delete open_curve_pt->curve_section_pt(cs);
42587  delete_it_on_destructor = true;
42588  }
42589 
42590  // *****************************************************************
42591  // Copying the new representation
42592  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42593 
42594  // Update the Boundary - Polyline map
42595  this->Boundary_curve_section_pt[bound]=open_curve_pt->curve_section_pt(cs);
42596 
42597  if (delete_it_on_destructor)
42598  {
42599  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
42600  }
42601 
42602 #ifdef OOMPH_HAS_MPI
42603 
42604  // If there are not sub-boundaries mark the boundary if need to be
42605  // trated as shared or as internal boundary
42606  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42607  {
42608  // Clear all previous stored data
42609  this->Boundary_marked_as_shared_boundary[bound].clear();
42610 
42611  // .. and store the flag for the boundary
42612  this->Boundary_marked_as_shared_boundary[bound].push_back(
42613  internal_to_shared_boundary[0]);
42614  }
42615  // --------- Stuff for the sub_boundaries ----- Begin section --------
42616  // Verify if need to deal with sub_boundaries
42617  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42618  {
42619  // Create temporary representations for the boundaries, only to
42620  // create the mesh when calling Triangle
42621  // Clear all previous stored data
42622  this->Boundary_subpolylines[bound].clear();
42623  // Now create storage for the sub-boundaries
42624  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42625 
42626  // Clear all previous stored data
42627  this->Boundary_marked_as_shared_boundary[bound].clear();
42628  // Create storage to mark the internal boundaries as shared
42629  // boundaries
42630  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
42631  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42632  {
42633  // Now update the polyline according to the sub set of
42634  // vertices, set the chunk number of the polyline
42635  TriangleMeshPolyLine *sub_tmp_polyline_pt =
42636  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
42637 
42638  // Add the sub-polyline to the container to represent the
42639  // boundary in parts
42640  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42641 
42642  // Copy the flag that mark the boundary as internal or as
42643  // shared bound
42644  this->Boundary_marked_as_shared_boundary[bound][isub] =
42645  internal_to_shared_boundary[isub];
42646 
42647  // No need to send the unrefinement/refinement and maximum
42648  // length constraints since these are only temporary
42649  // representations
42650 
42651  }
42652 
42653  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42654  // --------- Stuff for the sub_boundaries ----- End section ---------
42655 #endif // OOMPH_HAS_MPI
42656 
42657  } // update polyline representation
42658 
42659  // Delete the allocated memory for the geometric object
42660  // that represents the curvilinear boundary
42661  delete mesh_geom_obj_pt;
42662 
42663  } // npolyline
42664 
42665  // Cleanup the face mesh
42666  for(unsigned p = 0; p < ncurve_section; p++)
42667  {
42668  face_mesh_pt[p]->flush_node_storage();
42669  delete face_mesh_pt[p];
42670  }
42671 
42672 }
42673 
42674 #ifdef OOMPH_HAS_MPI
42675 //======================================================================
42676 /// \short Updates the shared polylines representation after restart
42677 //======================================================================
42678 template <class ELEMENT>
42681  &vector_polyline_pt)
42682 {
42683  // Go through all the shared boundaries/polylines
42684  const unsigned npolylines = vector_polyline_pt.size();
42685  for (unsigned pp = 0; pp < npolylines; pp++)
42686  {
42687  // Get the boundary of the current polyline
42688  const unsigned b = vector_polyline_pt[pp]->boundary_id();
42689 
42690  // Get the edges of the shared boundary elements that create the
42691  // shared boundary and store the shared boundary elements from where
42692  // were created
42693  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
42694  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
42695 
42696  // Store the nodes that define the edges
42697  Vector<Node*> halo_edge_nodes_pt;
42698  Vector<Node*> nonhalo_edge_nodes_pt;
42699 
42700  // Go through the shared boundary elements and store their edges
42701  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
42702  for (unsigned e = 0; e < nshared_bound_ele; e++)
42703  {
42704  // Get the shared boundary element
42705  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
42706 
42707  // Get the corner nodes, the first three nodes
42708  Node *first_node_pt = current_ele_pt->node_pt(0);
42709  Node *second_node_pt = current_ele_pt->node_pt(1);
42710  Node *third_node_pt = current_ele_pt->node_pt(2);
42711 
42712  // Check if the elements is halo
42713  if (!current_ele_pt->is_halo())
42714  {
42715  // Store the edges
42716  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42717  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42718 
42719  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42720  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42721 
42722  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42723  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42724 
42725  // Store the info. of the element used to create these edges
42726  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42727  second_node_pt);
42728  nonhalo_edge_element_pt[edge1] = current_ele_pt;
42729 
42730  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42731  third_node_pt);
42732  nonhalo_edge_element_pt[edge2] = current_ele_pt;
42733 
42734  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42735  first_node_pt);
42736  nonhalo_edge_element_pt[edge3] = current_ele_pt;
42737  }
42738  else
42739  {
42740  // Store the edges
42741  halo_edge_nodes_pt.push_back(first_node_pt);
42742  halo_edge_nodes_pt.push_back(second_node_pt);
42743 
42744  halo_edge_nodes_pt.push_back(second_node_pt);
42745  halo_edge_nodes_pt.push_back(third_node_pt);
42746 
42747  halo_edge_nodes_pt.push_back(third_node_pt);
42748  halo_edge_nodes_pt.push_back(first_node_pt);
42749 
42750  // Store the info. of the element used to create these edges
42751  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42752  second_node_pt);
42753  halo_edge_element_pt[edge1] = current_ele_pt;
42754 
42755  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42756  third_node_pt);
42757  halo_edge_element_pt[edge2] = current_ele_pt;
42758 
42759  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42760  first_node_pt);
42761  halo_edge_element_pt[edge3] = current_ele_pt;
42762  }
42763 
42764  } // for (e < nshared_bound_ele)
42765 
42766  // Filter the edges that give rise to a shared boundary
42767 
42768  // Mark the done edges
42769  std::map<std::pair<Node*,Node*>, bool> edge_done;
42770 
42771  // Storage for the edges shared by the elements
42772  Vector<std::pair<Node*, Node*> > unsorted_edges;
42773 
42774  // Storage for the elements that created the unsorted edges (two
42775  // elements, one at each side of the shared boundary)
42776  Vector<Vector<FiniteElement*> > unsorted_edges_elements_pt;
42777 
42778  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
42779  for (unsigned i = 0; i < nnonhalo_edge_nodes; i+=2)
42780  {
42781  Vector<Node*> currenti_edge(2);
42782  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
42783  currenti_edge[1] = nonhalo_edge_nodes_pt[i+1];
42784 
42785  // Create the edge (both nodes that make the edge)
42786  std::pair<Node*, Node*> new_edge =
42787  std::make_pair(currenti_edge[0], currenti_edge[1]);
42788 
42789  if (!edge_done[new_edge])
42790  {
42791  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
42792  for (unsigned j = 0; j < nhalo_edge_nodes; j+=2)
42793  {
42794  Vector<Node*> currentj_edge(2);
42795  currentj_edge[0] = halo_edge_nodes_pt[j];
42796  currentj_edge[1] = halo_edge_nodes_pt[j+1];
42797 
42798  // Comparing pointer of nodes
42799  if (currenti_edge[0] == currentj_edge[0] &&
42800  currenti_edge[1] == currentj_edge[1])
42801  {
42802  // Store the edge in the proper container
42803  unsorted_edges.push_back(new_edge);
42804 
42805  // Get the elements associated with the edges
42806  Vector<FiniteElement*> tmp_edge_element_pt;
42807 
42808  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42809  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
42810 
42811  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42812  tmp_edge_element_pt.push_back(halo_ele_pt);
42813 
42814  // Store the elements associated with the edge
42815  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42816 
42817  // Mark the edge as done
42818  edge_done[new_edge] = true;
42819 
42820  // Break the loop for (j < nedge_node)
42821  break;
42822 
42823  } // equal edge
42824 
42825  // Comparing pointer of nodes (reversed)
42826  else if (currenti_edge[0] == currentj_edge[1] &&
42827  currenti_edge[1] == currentj_edge[0])
42828  {
42829  // Create the edge (both nodes that make the edge)
42830  std::pair<Node*, Node*> new_edge =
42831  std::make_pair(currenti_edge[0], currenti_edge[1]);
42832 
42833  // Store the edge in the proper container
42834  unsorted_edges.push_back(new_edge);
42835 
42836  // Create the (reversed) edge (both nodes that make the edge)
42837  std::pair<Node*, Node*> rev_new_edge =
42838  std::make_pair(currentj_edge[0], currentj_edge[1]);
42839 
42840  // Get the elements associated with the edge
42841  Vector<FiniteElement*> tmp_edge_element_pt;
42842 
42843  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42844  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
42845 
42846  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42847  tmp_edge_element_pt.push_back(halo_ele_pt);
42848 
42849  // Store the elements associated with the edge
42850  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42851 
42852  // Mark the edge as done
42853  edge_done[new_edge] = true;
42854 
42855  // Break the loop for (j < nedge_node)
42856  break;
42857 
42858  } // if (equal edge)
42859 
42860  } // for (j < nhalo_edge_nodes)
42861 
42862  } // if (!edge_done[new_edge])
42863 
42864  } // for (i < nnonhalo_edge_nodes)
42865 
42866  // We already have the edges that make the shared boundary (and the
42867  // elements)
42868  // Sort them to create a contiguous boundary
42869 
42870  // Mark the already sorted edges
42871  std::map<std::pair<Node*,Node*>, bool> edge_sorted;
42872 
42873  const unsigned nunsorted_edges = unsorted_edges.size();
42874 
42875 #ifdef PARANOID
42876  // The number of unsorted edges must be the same as the number of
42877  // shared_boundary element / 2
42878  if (nshared_bound_ele / 2 != nunsorted_edges)
42879  {
42880  std::ostringstream error_message;
42881  error_message
42882  << "The number of shared boundary elements (" << nshared_bound_ele
42883  << ") is not the double\nof the number of unsorted edges ("
42884  << nunsorted_edges << ") for the current boundary ("<< b << ")\n\n";
42885  throw OomphLibError(error_message.str(),
42886  "RefineableTriangleMesh::update_shared_curve_after_restart()",
42887  OOMPH_EXCEPTION_LOCATION);
42888  }
42889 #endif
42890 
42891  unsigned nsorted_edges = 0;
42892 
42893  // Storing for the sorting nodes extracted from the edges, and
42894  // then used to update the polyline
42895  std::list<Node*> sorted_nodes;
42896 
42897  // Storing for the edges elements
42898  std::list<FiniteElement*> sorted_edges_elements_pt;
42899 
42900  // Get the root edge
42901  std::pair<Node*,Node*> edge = unsorted_edges[0];
42902  nsorted_edges++;
42903 
42904  // Mark edge as done
42905  edge_sorted[edge] = true;
42906 
42907  // The initial and final node on the list
42908  Node *first_node_pt = edge.first;
42909  Node *last_node_pt = edge.second;
42910 
42911  // Push back on the list the new edge (nodes)
42912  sorted_nodes.push_back(first_node_pt);
42913  sorted_nodes.push_back(last_node_pt);
42914 
42915  // Store the elements for the current edge
42916  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
42917  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
42918 
42919  // Iterate while the number of sorted edges be less than the number of
42920  // unsorted edges
42921  while (nsorted_edges < nunsorted_edges)
42922  {
42923  // Flag to indicate when a node was added
42924  bool node_added = false;
42925 
42926  // Start from the next edge since we have already added the
42927  // previous one as the initial edge
42928  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
42929  {
42930  edge = unsorted_edges[iedge];
42931 
42932  // If edge not done
42933  if (!edge_sorted[edge])
42934  {
42935  // Get each individual node
42936  Node* left_node_pt = edge.first;
42937  Node* right_node_pt = edge.second;
42938 
42939  if (left_node_pt == first_node_pt)
42940  {
42941  // Push front the new node
42942  sorted_nodes.push_front(right_node_pt);
42943  first_node_pt = right_node_pt;
42944  node_added = true;
42945 
42946  // Store the elements for the current edge
42947  sorted_edges_elements_pt.push_front(
42948  unsorted_edges_elements_pt[iedge][1]);
42949  sorted_edges_elements_pt.push_front(
42950  unsorted_edges_elements_pt[iedge][0]);
42951  }
42952  else if (left_node_pt == last_node_pt)
42953  {
42954  // Push back the new node
42955  sorted_nodes.push_back(right_node_pt);
42956  last_node_pt = right_node_pt;
42957  node_added = true;
42958 
42959  // Store the elements for the current edge
42960  sorted_edges_elements_pt.push_back(
42961  unsorted_edges_elements_pt[iedge][0]);
42962  sorted_edges_elements_pt.push_back(
42963  unsorted_edges_elements_pt[iedge][1]);
42964  }
42965  else if (right_node_pt == first_node_pt)
42966  {
42967  // Push front the new node
42968  sorted_nodes.push_front(left_node_pt);
42969  first_node_pt = left_node_pt;
42970  node_added = true;
42971 
42972  // Store the elements for the current edge
42973  sorted_edges_elements_pt.push_front(
42974  unsorted_edges_elements_pt[iedge][1]);
42975  sorted_edges_elements_pt.push_front(
42976  unsorted_edges_elements_pt[iedge][0]);
42977  }
42978  else if (right_node_pt == last_node_pt)
42979  {
42980  // Push back the new node
42981  sorted_nodes.push_back(left_node_pt);
42982  last_node_pt = left_node_pt;
42983  node_added = true;
42984 
42985  // Store the elements for the current edge
42986  sorted_edges_elements_pt.push_back(
42987  unsorted_edges_elements_pt[iedge][0]);
42988  sorted_edges_elements_pt.push_back(
42989  unsorted_edges_elements_pt[iedge][1]);
42990  }
42991 
42992  if (node_added)
42993  {
42994  // Mark as done only if one of its nodes has been
42995  // added to the list
42996  edge_sorted[edge] = true;
42997  nsorted_edges++;
42998 
42999  // Break the for
43000  break;
43001  }
43002 
43003  } // if (!edge_done[edge])
43004  } // for (iedge < nunsorted_edges)
43005  } // while (nsorted_edges < nunsorted_edges)
43006 
43007  // At this point we already have a sorted list of nodes, get the
43008  // vertices from them and store them in a vector container
43009 
43010  // Get the number of nodes on the list
43011  unsigned nvertex = sorted_nodes.size();
43012  // The vector to store the vertices (assign space)
43013  Vector<Vector<double> > polyline_vertices(nvertex);
43014 
43015  // Copy the vertices of the nodes
43016  unsigned counter = 0;
43017  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43018  it_nodes != sorted_nodes.end();
43019  it_nodes++)
43020  {
43021  polyline_vertices[counter].resize(2);
43022  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43023  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43024  counter++;
43025  }
43026 
43027  // Before going to the unrefinement or refinement process check that
43028  // all processors start from the same vertex. Start from the bottom
43029  // left vertex
43030  if (polyline_vertices[nvertex-1][1] < polyline_vertices[0][1])
43031  {
43032  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43033  }
43034  else if (polyline_vertices[nvertex-1][1] == polyline_vertices[0][1])
43035  {
43036  if (polyline_vertices[nvertex-1][0] < polyline_vertices[0][0])
43037  {
43038  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43039  }
43040  }
43041 
43042  // Create the polyline associated with this edge
43043  TriangleMeshPolyLine *new_polyline_pt =
43044  new TriangleMeshPolyLine(polyline_vertices, b);
43045 
43046  // Get the curve section representation
43047  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
43048 
43049  // Copy the connection information from the old shared polyline
43050  // to the new one
43051  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43052 
43053  //Now update the polyline according to the new vertices but first
43054  //check if the object is allowed to delete the representation
43055  //or if it should be done by other object
43056  bool delete_it_on_destructor = false;
43057 
43058  // Establish the element as being deleted by the destructor of
43059  // the class
43060  std::set<TriangleMeshCurveSection*>::iterator it =
43061  this->Free_curve_section_pt.find(curve_section_pt);
43062 
43063  if (it!=this->Free_curve_section_pt.end())
43064  {
43065  this->Free_curve_section_pt.erase(it);
43066  delete curve_section_pt;
43067  delete_it_on_destructor = true;
43068  }
43069 
43070  // Copy the new representation
43071  vector_polyline_pt[pp] = new_polyline_pt;
43072 
43073  // Get the new curve section representation
43074  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
43075 
43076  // Update the Boundary - Polyline map
43077  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43078 
43079  if (delete_it_on_destructor)
43080  {
43081  this->Free_curve_section_pt.insert(new_curve_section_pt);
43082  }
43083 
43084  } // for (pp < npoly)
43085 
43086 }
43087 
43088 //===================================================================
43089 // \short Fill the boundary elements structures when dealing with
43090 // shared boundaries that overlap internal boundaries. Document the
43091 // number of elements on the shared boundaries that go to internal
43092 // boundaries
43093 //===================================================================
43094 template <class ELEMENT>
43097 {
43098  // Dummy file
43099  std::ofstream some_file;
43100  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43101 }
43102 
43103 //===================================================================
43104 // \short Fill the boundary elements structures when dealing with
43105 // shared boundaries that overlap internal boundaries
43106 //===================================================================
43107 template <class ELEMENT>
43110  std::ofstream& outfile)
43111 {
43112  // Get the number of processors
43113  const unsigned nproc = this->communicator_pt()->nproc();
43114  // Get the rank of the current processor
43115  unsigned my_rank = this->communicator_pt()->my_rank();
43116 
43117  // Temporal name for the shared boundary overlaps structure
43118  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43119  this->Shared_boundary_overlaps_internal_boundary;
43120 
43121  // Register the internal boundary elements that where found to be
43122  // overlapped by shared boundaries
43123  std::set<unsigned> internal_boundary_overlaped;
43124 
43125  // Document the number of elements and nodes associated to the
43126  // boundaries before filling elements and nodes
43127  if (outfile.is_open())
43128  {
43129  const unsigned nbound = this->nboundary();
43130  outfile << "Number of boundaries: " << nbound << "\n\n";
43131  outfile << "Number of elements and nodes associated to each "
43132  << "boundary before\nfilling elements and nodes\n\n";
43133  for (unsigned i = 0; i < nbound; i++)
43134  {
43135  outfile << "Boundary (" << i << ") Elements ("
43136  << this->nboundary_element(i) << ") " << "Nodes ("
43137  << this->nboundary_node(i) << ")\n";
43138  }
43139  }
43140 
43141  // Storage for the shared boundaries in this processor
43142  std::set<unsigned> shared_boundaries_in_this_processor;
43143 
43144  // Get the shared boundaries that this processor has with other
43145  // processors
43146  for (unsigned iproc = 0; iproc < nproc; iproc++)
43147  {
43148  // Work with other processors only
43149  if (iproc != my_rank)
43150  {
43151  // Get the number of boundaries shared with the "iproc"-th processor
43152  unsigned nshared_boundaries_with_iproc =
43153  this->nshared_boundaries(my_rank, iproc);
43154 
43155  if (nshared_boundaries_with_iproc > 0)
43156  {
43157  // Get the boundaries ids shared with "iproc"-th processor
43158  Vector<unsigned> bound_shared_with_iproc;
43159  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank,
43160  iproc);
43161 
43162  // Loop over shared boundaries with "iproc"-th processor
43163  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43164  {
43165  unsigned bnd_id = bound_shared_with_iproc[bs];
43166  shared_boundaries_in_this_processor.insert(bnd_id);
43167  }
43168  }
43169  }
43170  }
43171 
43172  // ------------------------------------------------------------------
43173  // Copy the boundary elements and nodes from the shared boundary to
43174  // the internal boundary it overlaps
43175  // ------------------------------------------------------------------
43176  // Go through the shared boundaries that overlap internal boundaries
43177  for (std::map<unsigned, unsigned>::iterator it =
43178  shd_bnd_over_int_bnd.begin(); it != shd_bnd_over_int_bnd.end(); it++)
43179  {
43180  // The shared boundary id that overlaps with an internal boundary
43181  const unsigned shd_bnd_id = (*it).first;
43182  // The internal boundary overlapped by the shared boundary
43183  const unsigned int_bnd_id = (*it).second;
43184 
43185  // Check if the shared boundary exist in this processor
43186  std::set<unsigned>::iterator it_set =
43187  shared_boundaries_in_this_processor.find(shd_bnd_id);
43188  if (it_set != shared_boundaries_in_this_processor.end())
43189  {
43190  internal_boundary_overlaped.insert(int_bnd_id);
43191 
43192  // -----------------------------------------------------------------
43193  // First work the nodes of the shared boundaries that should be
43194  // added to the internal boundaries
43195  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43196 
43197  // Document the number of nodes that will be passed to the internal
43198  // boundary from the current shared boundary
43199  if (outfile.is_open())
43200  {
43201  outfile << "\nPass info. from shared (" << shd_bnd_id
43202  << ") to internal (" << int_bnd_id << ")\n";
43203  outfile << "Number of shared boundary nodes: "
43204  << nbnd_node_shd_bnd << "\n";
43205  }
43206 
43207  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43208  {
43209  // Get the boundary node
43210  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43211  // Add the node to the internal boundary
43212  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43213  }
43214 
43215  // -----------------------------------------------------------------
43216  // Second work the boundary elements
43217  // Get the number of boundary elements that should be copied to the
43218  // internal boundary
43219  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43220 
43221  // Document the number of elements that will be passed to the
43222  // internal boundary from the current shared boundary
43223  if (outfile.is_open())
43224  {
43225  outfile << "Number of shared boundary elements: "
43226  << nbnd_ele_shd_bnd << "\n\n";
43227  }
43228 
43229  // Go through the boundary elements in the shrared boundary and add
43230  // them to the boundary elements of the internal boundary
43231  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43232  {
43233  // Get the boundary element
43234  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43235  // Add the element to the boundary elements storage of the
43236  // internal boundary
43237  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43238  // Get the face index of the boundary
43239  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43240  // Add the face index to the storage of the boundary
43241  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43242 
43243  } // for (ie < nbnd_ele_shd_bnd)
43244 
43245  // If there are regions we need to fill the storage for regions too
43246  const unsigned nregions = this->nregion();
43247  if (nregions > 1)
43248  {
43249  for (unsigned ir = 0 ; ir < nregions; ir++)
43250  {
43251  // Get the region attribute
43252  const unsigned region_id =
43253  static_cast<unsigned>(this->Region_attribute[ir]);
43254 
43255  // Loop over all elements on boundaries in region ir
43256  const unsigned nele_ir = this->nboundary_element_in_region(shd_bnd_id,
43257  region_id);
43258  for (unsigned ier = 0; ier < nele_ir; ier++)
43259  {
43260  // Get the boundary element in current region
43261  FiniteElement* bnd_ele_pt =
43262  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43263  // Add the boundary element to the internal boundary in the
43264  // region
43265  this->Boundary_region_element_pt[int_bnd_id][region_id].
43266  push_back(bnd_ele_pt);
43267 
43268  // Get the face index of the boundary
43269  int face_index =
43270  this->face_index_at_boundary_in_region(shd_bnd_id, region_id, ier);
43271  // Add the face index to the storage of the boundary region
43272  this->Face_index_region_at_boundary[int_bnd_id][region_id].
43273  push_back(face_index);
43274 
43275  } // for (ier < nele_ir)
43276 
43277  } // for (ir < nregions)
43278 
43279  } // if (nregions > 1)
43280 
43281  } // if (the shared boundary appears in the current processor)
43282 
43283  } // for (loop over the shared bound that overlap an internal bound)
43284 
43285  // Document the number of elements and nodes associated to the
43286  // boundaries after filling elements and nodes
43287  if (outfile.is_open())
43288  {
43289  const unsigned nbound = this->nboundary();
43290  outfile << "Number of boundaries: " << nbound << "\n\n";
43291  outfile << "Number of elements and nodes associated to each "
43292  << "boundary after\nfilling elements and nodes\n\n";
43293  for (unsigned i = 0; i < nbound; i++)
43294  {
43295  outfile << "Boundary (" << i << ") Elements ("
43296  << this->nboundary_element(i) << ")" << " Nodes ("
43297  << this->nboundary_node(i) << ")\n";
43298  }
43299  }
43300 
43301  // ------------------------------------------------------------------
43302  // Finally, re-setup the boundary coordinates for the new nodes on
43303  // the overlaped internal boundaries
43304  // ------------------------------------------------------------------
43305  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43306  it != internal_boundary_overlaped.end(); it++)
43307  {
43308  const unsigned overlaped_internal_bnd_id = (*it);
43309 
43310  // Re-setup boundary coordinates
43311  this->template setup_boundary_coordinates<ELEMENT>(overlaped_internal_bnd_id);
43312  }
43313 
43314 }
43315 
43316 #endif // #ifdef OOMPH_HAS_MPI
43317 
43318  //======================================================================
43319  /// Move the boundary nodes onto the boundary defined by the old mesh
43320  //======================================================================
43321  template <class ELEMENT>
43323  RefineableTriangleMesh<ELEMENT>* &new_mesh_pt, const unsigned &b)
43324  {
43325 
43326  // Quick return
43327  if (!Boundary_coordinate_exists[b])
43328  {
43329  return;
43330  }
43331 
43332  //Firstly we set the boundary coordinates of the new nodes
43333  //In case the mapping between the geometric object's intrinsic coordinate
43334  //and the arc-length coordinate is nonlinear. This is only an approximation,
43335  //but it will ensure that the nodes that were input to triangle will
43336  //retain exactly the same boundary coordinates and then linear interpolation
43337  //is used between those values for any newly created nodes.
43338 
43339  // We need to get the boundary nodes from the boundary face
43340  // elements since the "multi_domain" methods add nodes to the
43341  // "Boundary_node_pt" structure which have no boundary coordinates
43342  // assigned
43343  std::set<Node*> tmp_boundary_node_pt;
43344  const unsigned nboundary_ele = this->nboundary_element(b);
43345  for (unsigned e = 0; e < nboundary_ele; e++)
43346  {
43347  // Get the boundary bulk element
43348  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43349 #ifdef OOMPH_HAS_MPI
43350  // Only work with nonhalo elements if the mesh is distributed
43351  if (!bulk_ele_pt->is_halo())
43352  {
43353 #endif
43354  // Get the face index
43355  int face_index = this->face_index_at_boundary(b, e);
43356  // Create the face element
43357  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
43358  bulk_ele_pt, face_index);
43359 
43360  // Get the number of nodes on the face element
43361  const unsigned nnodes = face_ele_pt->nnode();
43362  for (unsigned i = 0; i < nnodes; i++)
43363  {
43364  // Get the nodes in the face elements
43365  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43366  // Add the nodes to the set of boundary nodes
43367  tmp_boundary_node_pt.insert(tmp_node_pt);
43368  } // for (i < nnodes)
43369 
43370  // Free the memory allocated for the face element
43371  delete face_ele_pt;
43372  face_ele_pt = 0;
43373 #ifdef OOMPH_HAS_MPI
43374  } // if (!bulk_ele_pt->is_halo())
43375 #endif
43376 
43377  } // for (e < nboundary_ele)
43378 
43379  // Get the number of boundary nodes
43380  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43381 
43382  // Quick return if there are no nodes
43383  if (n_boundary_node==0)
43384  {
43385 #ifdef OOMPH_HAS_MPI
43386  // Check if we are working with a distributed mesh
43387  if (!this->is_mesh_distributed())
43388  {
43389 #endif
43390  return;
43391 #ifdef OOMPH_HAS_MPI
43392  }
43393  else // The mesh is distributed !!!
43394  {
43395  // Do not forget to participate in the communication
43396  Mesh* face_mesh_pt = new Mesh();
43397  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43398  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43399 
43400  //Delete the allocated memory for the geometric object and face mesh
43401  delete mesh_geom_obj_pt;
43402 
43403  // Flush the nodes from the face mesh to make sure we
43404  // don't delete them (the bulk mesh still needs them!)
43405  face_mesh_pt->flush_node_storage();
43406  delete face_mesh_pt;
43407  return;
43408  }
43409 #endif
43410  } // if (n_boundary_node==0)
43411 
43412  //Create a vector of existing boundary nodes with their boundary
43413  //coordinate as the first entry so that we can use standard sort algorithms
43414  Vector<double> node_coord(3);
43415  Vector<double> b_coord(1);
43416 
43417  Vector<Vector<double> > old_boundary_node(n_boundary_node);
43418  unsigned tmp_counter = 0;
43419  for(std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43420  it_node != tmp_boundary_node_pt.end(); it_node++, tmp_counter++)
43421  {
43422  Node* nod_pt = (*it_node);
43423  nod_pt->get_coordinates_on_boundary(b,b_coord);
43424  node_coord[0] = b_coord[0];
43425  node_coord[1] = nod_pt->x(0);
43426  node_coord[2] = nod_pt->x(1);
43427  old_boundary_node[tmp_counter] = node_coord;
43428  } // for (it_node != tmp_boundary_node_pt.end())
43429 
43430  //Sort the vector
43431  std::sort(old_boundary_node.begin(),old_boundary_node.end());
43432 
43433  //Set up an equivalent ordered vector for the new nodes, based on the
43434  //current coordinate which is the scaled arc-length.
43435  //Also provide storage for the original node index,
43436  //the mapped coordinate and a flag to indicate whether the mapped
43437  //coordinate has been assigned.
43438  //Get the nodes on the boundary but consider to which segment (which
43439  //may appear in a distributed mesh) they belong
43440  Vector<Vector<Node*> > segment_nodes_pt;
43441 
43442 #ifdef OOMPH_HAS_MPI
43443  // Get the number of segments
43444  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43445 #else
43446  // The number of segments is one since the boundary is not split
43447  // over multiple processors
43448  const unsigned nsegments = 1;
43449 #endif // #ifdef OOMPH_HAS_MPI
43450 
43451 #ifdef OOMPH_HAS_MPI
43452  // Get the total number of nodes on the boundary
43453  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43454 
43455  // Check if we are working with a distributed mesh
43456  if (this->is_mesh_distributed())
43457  {
43458  // If that is the case we need to ensure that the new mesh has
43459  // nodes too, if that is not the case then return
43460  // Quick return if there are no nodes
43461  if (n_new_boundary_node==0)
43462  {
43463  // Do not forget to participate in the communication
43464  Mesh* face_mesh_pt = new Mesh();
43465  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43466  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43467 
43468  //Delete the allocated memory for the geometric object and face mesh
43469  delete mesh_geom_obj_pt;
43470  // Flush the nodes from the face mesh to make sure we
43471  // don't delete them (the bulk mesh still needs them!)
43472  face_mesh_pt->flush_node_storage();
43473  delete face_mesh_pt;
43474  return;
43475  }
43476  }
43477 #endif // #ifdef OOMPH_HAS_MPI
43478 
43479  //Create a vector of boundary nodes that must be moved
43480  Vector<Vector<unsigned> > nodes_to_be_snapped(nsegments);
43481 
43482  // Go through all the segments to assign the snapped zeta coordinates
43483  // for the new nodes
43484  for (unsigned is = 0; is < nsegments; is++)
43485  {
43486 #ifdef OOMPH_HAS_MPI
43487  const unsigned n_new_boundary_segment_node =
43488  new_mesh_pt->nboundary_segment_node(b,is);
43489 #else
43490  const unsigned n_new_boundary_segment_node = new_mesh_pt->nboundary_node(b);
43491 #endif // #ifdef OOMPH_HAS_MPI
43492 
43493  Vector<Vector<double> > new_boundary_node(n_new_boundary_segment_node);
43494  //There will be six data associated with each node
43495  node_coord.resize(6,0.0);
43496  for(unsigned n = 0; n < n_new_boundary_segment_node; n++)
43497  {
43498 #ifdef OOMPH_HAS_MPI
43499  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43500 #else
43501  Node* nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43502 #endif // #ifdef OOMPH_HAS_MPI
43503  nod_pt->get_coordinates_on_boundary(b,b_coord);
43504  node_coord[0] = b_coord[0];
43505  node_coord[1] = nod_pt->x(0);
43506  node_coord[2] = nod_pt->x(1);
43507  node_coord[3] = n;
43508  new_boundary_node[n] = node_coord;
43509  } // for (n < n_new_boundary_segment_node)
43510 
43511  //Sort the new boundary nodes based on their arc-length coordinate
43512  std::sort(new_boundary_node.begin(),new_boundary_node.end());
43513 
43514  //We now have two sets of nodes ordered by a coordinate that acts in the
43515  //same direction and has the same limits.
43516 
43517  //Loop over the vector of new nodes and allocate exactly the same
43518  //coordinate as the old nodes at points of coincidence
43519  unsigned old_index = 0;
43520  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43521  {
43522  //Loop over the set of old nodes and if the x and y coordinates
43523  //coincide with the new node copy accross the new boundary coordinate
43524  for(unsigned m=old_index;m<n_boundary_node;++m)
43525  {
43526  if(
43527  (std::fabs(old_boundary_node[m][1]-new_boundary_node[n][1])<1.0e-14)
43528  &&
43529  (std::fabs(old_boundary_node[m][2]-new_boundary_node[n][2])<1.0e-14))
43530  {
43531  //Store the boundary coordinate from the old mesh
43532  new_boundary_node[n][4] = old_boundary_node[m][0];
43533  //Say that it has been stored
43534  new_boundary_node[n][5] = 1.0;
43535  //For efficiency, we can start the iteration from here next
43536  //time round because both vectors are ordered
43537  old_index = m;
43538  break;
43539  }
43540  }
43541  }
43542 
43543  //Check that the end-points have new boundary coordinates allocated
43544 #ifdef PARANOID
43545  if((new_boundary_node[0][5]==0.0) ||
43546  (new_boundary_node[n_new_boundary_segment_node-1][5] == 0.0))
43547  {
43548  std::ostringstream error_stream;
43549  error_stream
43550  <<"New boundary coordinates not found for the first and/or last "
43551  <<"nodes\n"
43552  <<"on the boundary " << b << ". This should not happen because "
43553  <<"these\nlimits should have been setup in the constructor\n";
43554  error_stream
43555  <<"The distance between the new and old nodes is probably outside\n"
43556  <<"our tolerance.\n";
43557  error_stream.precision(20);
43558  error_stream << "Old boundaries: \n";
43559  error_stream <<
43560  old_boundary_node[0][1] << " " << old_boundary_node[0][2]
43561  << " : " <<
43562  old_boundary_node[n_boundary_node-1][1] << " " <<
43563  old_boundary_node[n_boundary_node-1][2] << "\n";
43564  error_stream << "New boundaries: \n" <<
43565  new_boundary_node[0][1] << " " << new_boundary_node[0][2] << " : " <<
43566  new_boundary_node[n_new_boundary_segment_node-1][1] << " " <<
43567  new_boundary_node[n_new_boundary_segment_node-1][2] << "\n";
43568  OomphLibWarning(error_stream.str(),
43569  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43570  OOMPH_EXCEPTION_LOCATION);
43571  }
43572 #endif
43573 
43574  // This is only true if the boundary is not splitted among the
43575  // processors
43576  if (!this->is_mesh_distributed())
43577  {
43578  //The end points should always be present, so we
43579  //can (and must) always add them in exactly
43580  new_boundary_node[0][4] = new_boundary_node[0][0];
43581 
43582  /// Correct!? Because assigned again below
43583  new_boundary_node[n_new_boundary_segment_node-1][4] =
43584  new_boundary_node[0][5] = 1.0;
43585 
43586  new_boundary_node[n_new_boundary_segment_node-1][4] =
43587  new_boundary_node[n_new_boundary_segment_node-1][0];
43588  new_boundary_node[n_new_boundary_segment_node-1][5] = 1.0;
43589  }
43590 
43591  //Now loop over the interior nodes again and
43592  //use linear interpolation to fill in any unassigned coordiantes
43593  for(unsigned n=1;n<n_new_boundary_segment_node-1;++n)
43594  {
43595  //If the new boundary coordinate has NOT been allocated
43596  if(new_boundary_node[n][5]==0.0)
43597  {
43598  //Add its (unsorted) node number to the list
43599  nodes_to_be_snapped[is].push_back(
43600  static_cast<unsigned>(new_boundary_node[n][3]));
43601 
43602  //We assume that the previous nodal value has been assigned
43603  //and read out the old and new boundary coordinates
43604  double zeta_old_low = new_boundary_node[n-1][0];
43605  double zeta_new_low = new_boundary_node[n-1][4];
43606 
43607  //Loop over the nodes above the current node until
43608  //we find the next one that has been allocated
43609  for(unsigned m=n+1;m<n_new_boundary_segment_node;++m)
43610  {
43611  if(new_boundary_node[m][5]==1.0)
43612  {
43613  //Read out the old boundary coordinate
43614  double zeta_old_high = new_boundary_node[m][0];
43615  double zeta_new_high = new_boundary_node[m][4];
43616  //Use linear interpolation to assign the new boundary coordinate
43617  double frac = (new_boundary_node[n][0] - zeta_old_low)/
43618  (zeta_old_high - zeta_old_low);
43619  new_boundary_node[n][4] = zeta_new_low
43620  + frac*(zeta_new_high - zeta_new_low);
43621  new_boundary_node[n][5] = 1.0;
43622  break;
43623  }
43624  }
43625  }
43626  }
43627 
43628  //Loop over all the nodes and set the new boundary coordinate
43629  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43630  {
43631  if(new_boundary_node[n][5]==0)
43632  {
43633  throw OomphLibError(
43634  "New boundary coordinate not assigned\n",
43635  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43636  OOMPH_EXCEPTION_LOCATION);
43637  }
43638 
43639 #ifdef OOMPH_HAS_MPI
43640  //get the old coordinate
43641  new_mesh_pt->boundary_segment_node_pt(
43642  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43643  ->get_coordinates_on_boundary(b,b_coord);
43644  //Set the new coordinate
43645  b_coord[0] = new_boundary_node[n][4];
43646  new_mesh_pt->boundary_segment_node_pt(
43647  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43648  ->set_coordinates_on_boundary(b,b_coord);
43649 #else
43650  //get the old coordinate
43651  new_mesh_pt->boundary_node_pt(
43652  b,static_cast<unsigned>(new_boundary_node[n][3]))
43653  ->get_coordinates_on_boundary(b,b_coord);
43654  //Set the new coordinate
43655  b_coord[0] = new_boundary_node[n][4];
43656  new_mesh_pt->boundary_node_pt(
43657  b,static_cast<unsigned>(new_boundary_node[n][3]))
43658  ->set_coordinates_on_boundary(b,b_coord);
43659 #endif // #ifdef OOMPH_HAS_MPI
43660 
43661  }
43662 
43663  } // for (is < nsegments)
43664 
43665  Mesh* face_mesh_pt = new Mesh();
43666  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43667 
43668  //Now that the coordinates have been set up we can do the snapping
43669  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
43670 
43671  //Now assign the new nodes positions based on the old meshes
43672  //potentially curvilinear boundary (its geom object incarnation)
43673  Vector<double> new_x(2);
43674 
43675  //Loop over the nodes that need to be snapped
43676  for(unsigned is = 0; is < nsegments; is++)
43677  {
43678  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
43679 
43680  for (unsigned in = 0; in < nnodes_to_snap; in++)
43681  {
43682  //Read out the boundary node number
43683  unsigned n = nodes_to_be_snapped[is][in];
43684 #ifdef OOMPH_HAS_MPI
43685  //Get the boundary coordinate of all new nodes
43686  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43687 #else
43688  //Get the boundary coordinate of all new nodes
43689  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43690 #endif // #ifdef OOMPH_HAS_MPI
43691 
43692  nod_pt->get_coordinates_on_boundary(b,b_coord);
43693  //Let's find boundary coordinates of the new node
43694  mesh_geom_obj_pt->position(b_coord,new_x);
43695 
43696  //Now snap to the boundary
43697  for(unsigned i=0;i<2;i++)
43698  {
43699  nod_pt->x(i) = new_x[i];
43700  }
43701  }
43702  }
43703 
43704  //Delete the allocated memory for the geometric object and face mesh
43705  delete mesh_geom_obj_pt;
43706  // Flush the nodes from the face mesh to make sure we
43707  // don't delete them (the bulk mesh still needs them!)
43708  face_mesh_pt->flush_node_storage();
43709  delete face_mesh_pt;
43710 
43711  //Fix up the elements adjacent to the boundary
43712 
43713  // Dummy six node element for sorting out bubble node for
43714  // seven node enriched quadratic triangles
43715  TElement<2,3> dummy_six_node_element;
43716  for (unsigned j=0;j<6;j++)
43717  {
43718  dummy_six_node_element.construct_node(j);
43719  }
43720 
43721  //This should definitely become a triangular element member function
43722  //Loop over elements
43723  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
43724  for(unsigned e=0;e<n_bound_el;e++)
43725  {
43726  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b,e);
43727 
43728  // Deal with different numbers of nodes separately
43729  unsigned nnod=el_pt->nnode();
43730 
43731 // #ifdef PARANOID
43732 // // Flag to indicate if we successully classified/dealt with the element
43733 // bool success=false;
43734 // #endif
43735 
43736  // Simplex element: Nothing to be done other than error checking
43737  if (nnod==3)
43738  {
43739 #ifdef PARANOID
43740  // Try to cast to a simplex element
43741  TElement<2,2>* t_el_pt=dynamic_cast<TElement<2,2>*>(el_pt);
43742  if (t_el_pt==0)
43743  {
43744  throw OomphLibError(
43745  "Have a three-noded element that's not a TElement<2,2>",
43746  OOMPH_CURRENT_FUNCTION,
43747  OOMPH_EXCEPTION_LOCATION);
43748  }
43749  // If I get there I must not have thrown :)
43750  //success=true;
43751 #endif
43752  }
43753  // Quadratic element (or enriched quadratic)
43754 
43755  else if ((nnod==6)||(nnod==7))
43756  {
43757 
43758 #ifdef PARANOID
43759  // Try to cast to a quadratic element
43760  TElement<2,3>* t_el_pt=dynamic_cast<TElement<2,3>*>(el_pt);
43761  if (t_el_pt==0)
43762  {
43763  if (nnod==6)
43764  {
43765  throw OomphLibError(
43766  "Have a six-noded element that's not a TElement<2,3>",
43767  OOMPH_CURRENT_FUNCTION,
43768  OOMPH_EXCEPTION_LOCATION);
43769  }
43770  else
43771  {
43772  throw OomphLibError(
43773  "Have a seven-noded element that's not a TElement<2,3>",
43774  OOMPH_CURRENT_FUNCTION,
43775  OOMPH_EXCEPTION_LOCATION);
43776  }
43777  }
43778  // If I get there I must not have thrown :)
43779  //success=true;
43780 #endif
43781  // Deal with six noded stuff for all (normal and enriched) elements
43782 
43783  ///----------------------------------------------------------------
43784  /// Repositioning of mid-side nodes
43785  ///----------------------------------------------------------------
43786 
43787  //Side between 0 and 1
43788  if(el_pt->node_pt(3)->is_on_boundary(b))
43789  {
43790  //Make sure that the node I'm about to move is NOT on
43791  //a boundary
43792  if(!el_pt->node_pt(5)->is_on_boundary())
43793  {
43794  //Reset the internal nodes
43795  for(unsigned i=0;i<2;i++)
43796  {
43797  el_pt->node_pt(5)->x(i) =
43798  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43799  }
43800  }
43801  //Make sure that the node I'm about to move is NOT on
43802  //a boundary
43803  if(!el_pt->node_pt(4)->is_on_boundary())
43804  {
43805  //Reset the internal nodes
43806  for(unsigned i=0;i<2;i++)
43807  {
43808  el_pt->node_pt(4)->x(i) =
43809  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43810  }
43811  }
43812  }
43813 
43814  //Side between 1 and 2
43815  if(el_pt->node_pt(4)->is_on_boundary(b))
43816  {
43817  //Make sure that the node I'm about to move is NOT on
43818  //a boundary
43819  if(!el_pt->node_pt(5)->is_on_boundary())
43820  {
43821  //Reset the internal nodes
43822  for(unsigned i=0;i<2;i++)
43823  {
43824  el_pt->node_pt(5)->x(i) =
43825  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43826  }
43827  }
43828  //Make sure that the node I'm about to move is NOT on
43829  //a boundary
43830  if(!el_pt->node_pt(3)->is_on_boundary())
43831  {
43832  //Reset the internal nodes
43833  for(unsigned i=0;i<2;i++)
43834  {
43835  el_pt->node_pt(3)->x(i) =
43836  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43837  }
43838  }
43839  }
43840 
43841  //Side between 0 and 2
43842  if(el_pt->node_pt(5)->is_on_boundary(b))
43843  {
43844  //Make sure that the node I'm about to move is NOT on
43845  //a boundary
43846  if(!el_pt->node_pt(4)->is_on_boundary())
43847  {
43848  //Reset the internal nodes
43849  for(unsigned i=0;i<2;i++)
43850  {
43851  el_pt->node_pt(4)->x(i) =
43852  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43853  }
43854  }
43855  //Make sure that the node I'm about to move is NOT on
43856  //a boundary
43857  if(!el_pt->node_pt(3)->is_on_boundary())
43858  {
43859  //Reset the internal nodes
43860  for(unsigned i=0;i<2;i++)
43861  {
43862  el_pt->node_pt(3)->x(i) =
43863  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43864  }
43865  }
43866  }
43867 
43868  // If it's seven noded it's likely to be an enriched one: Deal with
43869  // the central (bubble) node
43870  if (nnod==7)
43871  {
43872  // Try to cast to an enriched quadratic element
43873  TBubbleEnrichedElement<2,3>* t_el_pt=
43874  dynamic_cast<TBubbleEnrichedElement<2,3>*>(el_pt);
43875  if (t_el_pt==0)
43876  {
43877  throw OomphLibError(
43878  "Have seven-noded element that's not a TBubbleEnrichedElement<2,3>",
43879  OOMPH_CURRENT_FUNCTION,
43880  OOMPH_EXCEPTION_LOCATION);
43881  }
43882 
43883  // Assign the new non-bubble coordinates to the six noded dummy element
43884  for (unsigned j=0;j<6;j++)
43885  {
43886  for (unsigned i=0;i<2;i++)
43887  {
43888  dummy_six_node_element.node_pt(j)->x(i)=el_pt->node_pt(j)->x(i);
43889  }
43890  }
43891 
43892  // Local coordinate of enriched node
43893  unsigned j_enriched=6;
43894  Vector<double> s(2);
43895  el_pt->local_coordinate_of_node(j_enriched,s);
43896 
43897  // Get its position from non-enriched element
43898  Vector<double> x(2);
43899  dummy_six_node_element.interpolated_x(s,x);
43900  el_pt->node_pt(j_enriched)->x(0) = x[0];
43901  el_pt->node_pt(j_enriched)->x(1) = x[1];
43902  }
43903  }
43904  // Any other case cannot be dealt with at the moment
43905 
43906  else
43907  {
43908  std::ostringstream error_stream;
43909  error_stream
43910  << "Cannot deal with this particular " << nnod
43911  << "-noded element yet.\n"
43912  << "Please implement this yourself.\n";
43913  throw OomphLibError(error_stream.str(),
43914 OOMPH_CURRENT_FUNCTION,
43915  OOMPH_EXCEPTION_LOCATION);
43916  }
43917  }
43918 
43919  // Cleanup
43920  for (unsigned j=0;j<6;j++)
43921  {
43922  delete dummy_six_node_element.node_pt(j);
43923  }
43924 
43925  }
43926 
43927 
43928 
43929 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
43930 
43931 }
43932 
43933 #endif
unsigned nboundary_element(const unsigned &b) const
Return number of finite elements that are adjacent to boundary b.
Definition: mesh.h:852
A Generalised Element class.
Definition: elements.h:76
bool is_redistribution_of_segments_between_polylines_enabled()
Is re-distribution of polyline segments in the curve between different boundaries during adaptation e...
std::map< unsigned, Vector< double > > & boundary_segment_initial_zeta()
Return direct access to the initial zeta for the segments that are part of a boundary.
void add_node_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement *> > &f_halo_ele_pt, Vector< Node *> &new_nodes_on_domain, Node *nod_pt)
Helper function to add haloed node.
void add_haloed_node_helper(unsigned &iproc, Node *nod_pt)
Helper function to add haloed node.
void select_boundary_face_elements(Vector< FiniteElement *> &face_el_pt, const unsigned &b, bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement *> &face_to_bulk_element_pt)
Select face element from boundary using the criteria to decide which of the two face elements should ...
virtual TriangleMeshCurveSection * curve_section_pt(const unsigned &i) const
Pointer to i-th constituent curve section.
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size (broken virtual) ...
Definition: elements.h:1803
std::map< unsigned, Vector< Vector< double > > > & boundary_segment_initial_coordinate()
Return direct access to the initial coordinates for the segments that are part of a boundary...
unsigned nboundary_segment(const unsigned &b)
Return the number of segments associated with a boundary.
bool refine_boundary_constrained_by_target_area(MeshAsGeomObject *mesh_geom_obj_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
std::map< unsigned, Vector< double > > & boundary_final_coordinate()
Return direct access to the final coordinates of a boundary.
virtual void set_coordinates_on_boundary(const unsigned &b, const unsigned &k, const Vector< double > &boundary_zeta)
Set the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interf...
Definition: nodes.cc:2315
void create_tmp_open_curves_helper(Vector< Vector< TriangleMeshPolyLine *> > &sorted_open_curves_pt, Vector< TriangleMeshPolyLine *> &unsorted_shared_to_internal_poly_pt, Vector< TriangleMeshOpenCurve *> &open_curves_pt)
Take the polylines from the original open curves and created new temporaly representations of open cu...
void break_loops_on_shared_polyline_load_balance_helper(const unsigned &initial_shd_bnd_id, std::list< Node *> &input_nodes, Vector< FiniteElement *> &input_boundary_element_pt, Vector< FiniteElement *> &input_boundary_face_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node *> > &output_sorted_nodes_pt, Vector< Vector< FiniteElement *> > &output_boundary_element_pt, Vector< Vector< FiniteElement *> > &output_boundary_face_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
double * pointlist
Pointer to list of points x coordinate followed by y coordinate.
void get_required_nodal_information_helper(unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from a haloed node so that a fully-functional h...
void create_unsorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt)
Helper function Creates an unsorted face mesh representation from the specified boundary id...
double & min_element_size()
Min element size allowed during adaptation.
void create_shared_boundaries(OomphCommunicator *comm_pt, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement *> &backed_up_el_pt, const Vector< FiniteElement *> &backed_up_f_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status)
Creates the shared boundaries.
void set_initial_vertex_connected()
Sets the initial vertex as connected.
GeomObject * geom_object_pt(const unsigned &i)
Return pointer to i-th geometric object involved in default (usually first) update function...
unsigned nboundary_element_in_region(const unsigned &b, const unsigned &r) const
Return the number of elements adjacent to boundary b in region r.
double * pointattributelist
Pointer to list of point attributes.
void get_face_mesh_representation(TriangleMeshPolygon *polygon_pt, Vector< Mesh *> &face_mesh_pt)
Helper function to construct face mesh representation of all polylines, possibly with segments re-dis...
Unstructured refineable Triangle Mesh upgraded to solid mesh.
void final_vertex_coordinate(Vector< double > &vertex)
Get last vertex coordinates.
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition: mesh.h:497
void add_vertices_for_non_deletion()
Mark the vertices that are not allowed for deletion by the unrefienment/refinement polyline methods...
int * pointmarkerlist
Pointer to list of point markers.
void get_required_elemental_information_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to get the required elemental information from an haloed element. This info...
void create_element_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement *> > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement *> > > &received_old_haloed_element_pt, Vector< FiniteElement *> &new_elements_on_domain, Vector< Node *> &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
void get_element_edges_on_boundary(std::map< std::pair< Node *, Node *>, unsigned > &element_edges_on_boundary)
Get the element edges (pair of nodes, edges) that lie on a boundary (used to mark shared boundaries t...
bool update_polygon_using_face_mesh(TriangleMeshPolygon *polygon_pt, const bool &check_only=false)
Helper function that updates the input polygon&#39;s PSLG by using the end-points of elements from FaceMe...
const void synchronize_shared_boundary_connections()
Synchronise the vertices that are marked for non deletion.
TriangleMeshPolyLine * polyline_pt(const unsigned &i) const
Pointer to i-th constituent polyline.
virtual void update_node_update(AlgebraicNode *&node_pt)=0
Update the node update info for given node, following mesh adaptation. Must be implemented for every ...
void get_required_nodal_information_load_balance_helper(Vector< Vector< FiniteElement *> > &f_halo_ele_pt, unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from an haloed node so that a fully-functional ...
TriangulateIO & triangulateio_representation()
Access to the triangulateio representation of the mesh.
void re_scale_re_assigned_initial_zeta_values_for_internal_boundary(const unsigned &b)
Re-scale the re-assigned zeta values for the boundary nodes, apply only for internal boundaries...
void create_sorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt, std::map< FiniteElement *, bool > &is_inverted, bool &inverted_face_mesh)
Helper function Creates a sorted face mesh representation of the specified PolyLine It means that the...
FiniteElement * boundary_element_in_region_pt(const unsigned &b, const unsigned &r, const unsigned &e) const
Return pointer to the e-th element adjacent to boundary b in region r.
Information for documentation of results: Directory and file number to enable output in the form RESL...
void add_non_delete_vertices_from_boundary_helper(Vector< Vector< Node *> > src_bound_segment_node_pt, Vector< Vector< Node *> > dst_bound_segment_node_pt, const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
Adds the vertices from the sources boundary that are repeated in the destination boundary to the list...
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
bool unrefine_shared_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
cstr elem_len * i
Definition: cfortran.h:607
unsigned Counter_for_flat_packed_unsigneds
Counter used when processing vector of flat-packed unsigneds – this is really "private" data...
void add_element_load_balance_helper(const unsigned &iproc, Vector< Vector< std::map< unsigned, FiniteElement *> > > &received_old_haloed_element_pt, FiniteElement *ele_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
void update_polygon_after_restart(TriangleMeshPolygon *&polygon_pt)
Updates the polylines representation after restart.
void update_open_curve_after_restart(TriangleMeshOpenCurve *&open_curve_pt)
Updates the open curve representation after restart.
Class to keep track of discrete/continous time. It is essential to have a single Time object when usi...
Definition: timesteppers.h:67
Helper object for dealing with the parameters used for the NonRefineableBinArray objects.
void fill_bin_by_diffusion(const unsigned &bin_diffusion_radius=1)
Fill bin by diffusion, populating each empty bin with the same content as the first non-empty bin fou...
bool update_open_curve_using_elements_area(TriangleMeshOpenCurve *&open_curve_pt, const Vector< double > &target_area)
Updates the open curve but using the elements area instead of the default refinement and unrefinement...
void add_node_update_info(const int &id, AlgebraicMesh *mesh_pt, const Vector< GeomObject *> &geom_object_pt, const Vector< double > &ref_value, const bool &called_from_constructor=false)
Add algebraic update information for node: What&#39;s the ID of the mesh update function (typically used ...
unsigned nref_value(const int &id)
Number of reference values involved in id-th update function.
std::map< unsigned, Vector< double > > & boundary_coordinate_limits()
Return access to the vector of boundary coordinates associated with each geometric object...
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
void sort_nodes_on_shared_boundaries()
Sort the nodes on shared boundaries so that the processors that share a boundary agree with the order...
Helper object for dealing with the parameters used for the CGALSamplePointContainer objects...
void read_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all data and time history values from the vector starting from index. On return the index will b...
Definition: nodes.cc:3650
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned > > &ntmp_boundary_elements_in_region, Vector< FiniteElement *> &deleted_elements)
Reset the boundary elements info. after load balance have taken place.
A general Finite Element class.
Definition: elements.h:1274
bool Doc_timings
Boolean to indicate whether to doc timings or not.
unsigned final_vertex_connected_n_chunk() const
Gets the boundary chunk to which the final end is connected.
virtual void reset_reference_configuration()
Virtual function that should be overloaded to update the polygons reference configuration.
void restore_boundary_connections(Vector< TriangleMeshPolyLine *> &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine *> &resume_final_connection_polyline_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the boundaries ...
std::map< unsigned, Vector< double > > & boundary_initial_coordinate()
Return direct access to the initial coordinates of a boundary.
Vector< std::string > Flat_packed_unsigneds_string
char t
Definition: cfortran.h:572
int non_halo_proc_ID()
ID of processor ID that holds non-halo counterpart of halo node; negative if not a halo...
Definition: nodes.h:494
void enable_use_attributes()
Helper function for enabling the use of attributes.
FiniteElement * boundary_element_pt(const unsigned &b, const unsigned &e) const
Return pointer to e-th finite element on boundary b.
Definition: mesh.h:814
Helper object for dealing with the parameters used for the TriangleMesh objects.
CGAL-based SamplePointContainer.
void add_halo_element_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Vector< double > internal_point() const
Coordinates of the internal point.
void snap_nodes_onto_boundary(RefineableTriangleMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
double refinement_tolerance()
Get tolerance for refinement of curve sections to create a better representation of curvilinear bound...
bool is_halo() const
Is this element a halo?
Definition: elements.h:1141
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
Definition: elements.h:2420
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
void get_required_nodal_information_helper(int &iproc, Node *nod_pt, Mesh *const &mesh_pt, int &n_cont_inter_values, Vector< unsigned > &send_unsigneds, Vector< double > &send_doubles)
Helper function to get the required nodal information from an external haloed node so that a fully-fu...
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
Definition: mesh.h:809
void create_tmp_polygons_helper(Vector< Vector< TriangleMeshPolyLine *> > &polylines_pt, Vector< TriangleMeshPolygon *> &polygons_pt)
Take the polylines from the shared boundaries and create temporary polygon representations of the dom...
void project(Mesh *base_mesh_pt, const bool &dont_project_positions=false)
Project from base into the problem&#39;s own mesh.
Definition: projection.h:726
void reset_shared_boundary_elements_and_nodes(const bool flush_elements=true, const bool update_elements=true, const bool flush_nodes=true, const bool update_nodes=true)
Re-establish the shared boundary elements after the adaptation process (the updating of shared nodes ...
void construct_new_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement *> > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement *> > > &received_old_haloed_element_pt, Vector< Node *> &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function which constructs a new node (on an element) with the information sent from the load b...
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1264
OomphInfo oomph_info
TriangleMeshPolyLine * polyline_pt(const unsigned &i) const
Pointer to i-th constituent polyline.
void resume_boundary_connections(Vector< TriangleMeshPolyLine *> &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine *> &resume_final_connection_polyline_pt)
Resume the boundary connections that may have been suspended because the destination boundary is no p...
int face_index_at_boundary(const unsigned &b, const unsigned &e) const
For the e-th finite element on boundary b, return int to indicate the face_index of the face adjacent...
Definition: mesh.h:870
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:448
std::map< unsigned, Vector< double > > & boundary_final_zeta_coordinate()
Return direct access to the final zeta coordinates of a boundary.
bool refine_boundary(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, const bool &check_only=false)
Helper function that performs the refinement process on the specified boundary by using the provided ...
void load_balance(const Vector< unsigned > &input_target_domain_for_local_non_halo_element)
Performs the load balancing for unstructured meshes, the load balancing strategy is based on mesh mig...
e
Definition: cfortran.h:575
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
Definition: elements.h:4277
bool Doc_comprehensive_timings
Global boolean to switch on comprehensive timing – can probably be declared const false when develop...
Vector< unsigned > Flat_packed_unsigneds
Vector of flat-packed unsigneds to be communicated with other processors – this is really "private" ...
GeomObject * geom_object_list_pt(const unsigned &i)
Access function to the ith GeomObject.
void output_boundary_coordinates(const unsigned &b, std::ostream &outfile)
bool unrefine_boundary(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, const bool &check_only=false)
Helper function that performs the unrefinement process.
void update_holes_information_helper(Vector< TriangleMeshPolygon *> &polygons_pt, Vector< Vector< double > > &output_holes_coordinates)
Keeps those vertices that define a hole, those that are inside closed internal boundaries in the new ...
bool get_connected_vertex_number_on_dst_boundary(Vector< double > &vertex_coordinates, const unsigned &dst_b_id, unsigned &vertex_number)
Computes the associated vertex number on the destination boundary.
void get_shared_boundary_segment_nodes_helper(const unsigned &shd_bnd_id, Vector< Vector< Node *> > &tmp_segment_nodes)
Get the nodes on the shared boundary (b), these are stored in the segment they belong.
bool is_initial_vertex_connected() const
Test whether initial vertex is connected or not.
double size() const
Definition: elements.cc:4207
virtual void get_coordinates_on_boundary(const unsigned &b, const unsigned &k, Vector< double > &boundary_zeta)
Return the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interface provides run-time error checking.
Definition: nodes.cc:2301
double region_attribute(const unsigned &i)
Return the attribute associated with region i.
int node_update_fct_id()
Default (usually first if there are multiple ones) node update fct id.
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
void set_refinement_tolerance(const double &tolerance)
Set tolerance for refinement of curve sections to create a better representation of curvilinear bound...
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
void dump_distributed_info_for_restart(std::ostream &dump_file)
Used to dump info. related with distributed triangle meshes.
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:587
bool refine_shared_boundary_constrained_by_target_area(Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
double maximum_length()
Gets access to the maximum length variable.
double & max_element_size()
Max element size allowed during adaptation.
struct oomph::classcomp Bottom_left_sorter
bool operator()(const std::pair< double, double > &lhs, const std::pair< double, double > &rhs) const
bool Doc_full_stats
Boolean to indicate whether to output further info during setup_multi_domain_interaction() routines...
void add_time_stepper_pt(TimeStepper *const &time_stepper_pt)
Add a timestepper to the problem. The function will automatically create or resize the Time object so...
Definition: problem.cc:1529
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:992
virtual void remove_from_boundary(const unsigned &b)
Broken interface for removing the node from the mesh boundary b Here to provide error reporting...
Definition: nodes.cc:2272
bool must_be_kept_as_halo() const
Test whether the element must be kept as a halo element.
Definition: elements.h:1158
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Return a pointer to set of mesh boundaries that this node occupies; this will be overloaded by Bounda...
Definition: nodes.h:1284
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:995
A class that contains the information required by Nodes that are located on Mesh boundaries. A BoundaryNode of a particular type is obtained by combining a given Node with this class. By differentiating between Nodes and BoundaryNodes we avoid a lot of un-necessary storage in the bulk Nodes.
Definition: nodes.h:1855
int non_halo_proc_ID()
ID of processor ID that holds non-halo counterpart of halo element; negative if not a halo...
Definition: elements.h:1145
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition: elements.cc:3881
void synchronize_boundary_coordinates(const unsigned &b)
In charge of sinchronize the boundary coordinates for internal boundaries that were split as part of ...
const int check_connections_of_polyline_nodes(std::set< FiniteElement *> &element_in_processor_pt, const int &root_edge_bnd_id, std::map< std::pair< Node *, Node *>, bool > &overlapped_face, std::map< unsigned, std::map< Node *, bool > > &node_on_bnd_not_overlapped_by_shd_bnd, std::list< Node *> &current_polyline_nodes, std::map< unsigned, std::list< Node *> > &shared_bnd_id_to_sorted_list_node_pt, const unsigned &node_degree, Node *&new_node_pt, const bool called_from_load_balance=false)
Check for any possible connections that the array of sorted nodes have with any previous boundaries o...
unsigned nvertex() const
Number of vertices.
void add_values_to_vector(Vector< double > &vector_of_values)
Add all data, position and time history values to the vector Overload to add the Lagrangian coordinat...
Definition: nodes.cc:3603
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
void set_nodal_and_elemental_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set the timestepper associated with all nodal and elemental data stored in the mesh.
Definition: mesh.h:993
Class defining a polyline for use in Triangle Mesh generation.
void update_shared_curve_after_restart(Vector< TriangleMeshPolyLine *> &vector_polyline_pt)
Updates the shared polylines representation after restart.
void flush_node_storage()
Flush storage for nodes (only) by emptying the vectors that store the pointers to them...
Definition: mesh.h:450
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the position as a function of the intrinsic coordinate zeta. This provides an (expensive!) def...
std::map< unsigned, Vector< Vector< double > > > & boundary_segment_final_coordinate()
Return direct access to the final coordinates for the segments that are part of a boundary...
void connect_final_vertex_to_polyline(TriangleMeshPolyLine *polyline_pt, const unsigned &vertex_number, const double &tolerance_for_connection=1.0e-14)
Connects the final vertex of the curve section to a desired target polyline by specifying the vertex ...
void enable_problem_distributed()
Enable problem distributed.
Definition: problem.h:959
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:462
unsigned initial_vertex_connected_n_vertex() const
Gets the vertex number to which the initial end is connected.
FiniteElement * region_element_pt(const unsigned &i, const unsigned &e)
Return the e-th element in the i-th region.
void clear_triangulateio(TriangulateIO &triangulate_io, const bool &clear_hole_data)
Clear TriangulateIO structure.
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object. ...
Definition: elements.h:2392
void compute_boundary_segments_connectivity_and_initial_zeta_values(const unsigned &b)
Compute the boundary segments connectivity for those boundaries that were splited during the distribu...
virtual bool surface_remesh_for_inner_hole_boundaries(Vector< Vector< double > > &internal_point_coord, const bool &check_only=false)
Generate a new PSLG representation of the inner hole boundaries. Optional boolean is used to run it a...
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:806
void create_shared_polylines_connections()
Establish the connections of the polylines previously marked as having connections. This connections were marked in the function TriangleMesh::create_polylines_from_halo_elements_helper().
double Tolerable_error
Acceptable discrepancy for mismatch in vertex coordinates. In paranoid mode, the code will die if the...
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
static char t char * s
Definition: cfortran.h:572
std::map< unsigned, Vector< double > > & boundary_initial_zeta_coordinate()
Return direct access to the initial zeta coordinate of a boundary.
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition: nodes.h:267
Vector< unsigned > & dimensions_of_bin_array()
Number of bins in each coordinate direction.
void create_adjacency_matrix_new_shared_edges_helper(Vector< Vector< FiniteElement *> > &unsorted_face_ele_pt, Vector< Vector< Node *> > &tmp_sorted_shared_node_pt, std::map< Node *, Vector< Vector< unsigned > > > &node_alias, Vector< Vector< Vector< unsigned > > > &adjacency_matrix)
Sort the nodes on the new shared boundaries (after load balancing), computes the alias of the nodes a...
virtual unsigned nvertex() const =0
Number of vertices.
virtual unsigned boundary_chunk() const =0
bool unrefine_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
void send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
Helper function to send back halo and haloed information.
void connect_initial_vertex_to_polyline(TriangleMeshPolyLine *polyline_pt, const unsigned &vertex_number, const double &tolerance_for_connection=1.0e-14)
Connects the initial vertex of the curve section to a desired target polyline by specifying the verte...
void build_triangulateio(const std::string &poly_file_name, TriangulateIO &triangulate_io, bool &use_attributes)
Helper function to create TriangulateIO object (return in triangulate_io) from the ...
void initial_vertex_coordinate(Vector< double > &vertex)
Get first vertex coordinates.
void compute_holes_left_by_halo_elements_helper(Vector< Vector< double > > &output_holes_coordinates)
Compute the holes left by the halo elements, those adjacent to the shared boundaries.
void compute_global_node_names_and_shared_nodes(Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Compute the names of the nodes on shared boundaries in this (my_rank) processor with other processors...
bool is_final_vertex_connected() const
Test whether final vertex is connected or not.
virtual unsigned boundary_id() const =0
Boundary id.
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:89
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
unsigned nregion()
Return the number of regions specified by attributes.
std::map< unsigned, Vector< double > > & boundary_segment_final_zeta()
Return direct access to the final zeta for the segments that are part of a boundary.
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
Definition: nodes.h:1655
void set_final_vertex_connected()
Sets the final vertex as connected.
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
double unrefinement_tolerance()
Get tolerance for unrefinement of curve section to create a better representation of curvilinear boun...
void create_distributed_domain_representation(Vector< TriangleMeshPolygon *> &polygons_pt, Vector< TriangleMeshOpenCurve *> &open_curves_pt)
Creates the distributed domain representation. Joins the original boundaires, shared boundaries and c...
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
double timer()
returns the time in seconds after some point in past
void sort_polylines_helper(Vector< TriangleMeshPolyLine *> &unsorted_polylines_pt, Vector< Vector< TriangleMeshPolyLine *> > &sorted_polylines_pt)
Sorts the polylines so they be continuous and then we can create a closed or open curve from them...
void initialise_triangulateio(TriangulateIO &triangle_io)
Initialise TriangulateIO structure.
void get_bin(const Vector< double > &zeta, int &bin_number)
Get the number of the bin containing the specified coordinate. Bin number is negative if the coordina...
void set_maximum_length(const double &maximum_length)
Allows to specify the maximum distance between two vertices that define the associated polyline of th...
Vector< double > Flat_packed_doubles
Vector of flat-packed doubles to be communicated with other processors.
void update_other_proc_shd_bnd_node_helper(Node *&new_nod_pt, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, Vector< unsigned > &other_processor_1, Vector< unsigned > &other_processor_2, Vector< unsigned > &other_shared_boundaries, Vector< unsigned > &other_indexes, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function that assigns/updates the references to the node so that it can be found with any othe...
void set_unrefinement_tolerance(const double &tolerance)
Set tolerance for unrefinement of curve sections to avoid unnecessarily large numbers of elements on ...
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:562
void get_fill_stats(unsigned &n_bin, unsigned &max_n_entry, unsigned &min_n_entry, unsigned &tot_n_entry, unsigned &n_empty) const
Provide some stats on the fill level of the associated bin.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:456
void disable_use_iterative_solver_for_projection()
Disbales the use of an iterative solver for projection.
Definition: projection.h:722
bool apply_max_length_constraint(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &max_length_constraint)
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:590
void create_temporary_boundary_connections(Vector< TriangleMeshPolygon *> &tmp_outer_polygons_pt, Vector< TriangleMeshOpenCurve *> &tmp_open_curves_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the temporary r...
void reset_halo_haloed_scheme()
In charge of. re-establish the halo(ed) scheme on all processors. Sends info. to create halo elements...
void add_received_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement *> > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement *> > > &received_old_haloed_element_pt, Vector< Node *> &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function to add a new node from load balance.
void create_shared_polyline(const unsigned &my_rank, const unsigned &shd_bnd_id, const unsigned &iproc, const unsigned &jproc, std::list< Node *> &sorted_nodes, const int &root_edge_bnd_id, Vector< FiniteElement *> &bulk_bnd_ele_pt, Vector< int > &face_index_ele, Vector< Vector< TriangleMeshPolyLine *> > &unsorted_polylines_pt, const int &connect_to_the_left_flag, const int &connect_to_the_right_flag)
Create the shared polyline and fill the data structured that keep all the information associated with...
TriangulateIO deep_copy_of_triangulateio_representation(TriangulateIO &triangle_io, const bool &quiet)
Make (partial) deep copy of TriangulateIO object. We only copy those items we need within oomph-lib&#39;s...
General SolidMesh class.
Definition: mesh.h:2213
void send_boundary_node_info_of_shared_nodes(Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Get the original boundaries to which is associated each shared node, and send the info...
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition: mesh.h:477
void add_halo_node_helper(Node *&new_nod_pt, Vector< Node *> &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function to add halo node.
const std::map< unsigned, Vector< std::pair< FiniteElement *, Vector< double > > > > * get_all_bins_content() const
Get the contents of all bins in vector.
void set_node_update_info(FiniteElement *node_update_element_pt, const Vector< double > &s_in_node_update_element, const Vector< GeomObject *> &geom_object_pt)
Set node update information for node: Pass the pointer to the element that performs the update operat...
void disable_doc()
Disable documentation.
double ref_value(const unsigned &i)
Return i-th reference value involved in default (usually first) update function.
A Class for nodes that deform elastically (i.e. position is an unknown in the problem). The idea is that the Eulerian positions are stored in a Data object and the Lagrangian coordinates are stored in addition. The pointer that addresses the Eulerian positions is set to the pointer to Value in the Data object. Hence, SolidNode uses knowledge of the internal structure of Data and must be a friend of the Data class. In order to allow a mesh to deform via an elastic-style equation in deforming-domain problems, the positions are stored separately from the values, so that elastic problems may be combined with any other type of problem.
Definition: nodes.h:1569
unsigned ngeom_object_list_pt()
Return number of geometric objects associated with AlgebraicMesh.
bool update_shared_curve_using_elements_area(Vector< TriangleMeshPolyLine *> &vector_polyline_pt, const Vector< double > &target_areas)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
NonRefineableBinArray class.
void create_new_shared_boundaries(std::set< FiniteElement *> &element_in_processor_pt, Vector< Vector< FiniteElement *> > &new_shared_boundary_element_pt, Vector< Vector< unsigned > > &new_shared_boundary_element_face_index)
Creates the new shared boundaries, this method is also in charge of computing the shared boundaries i...
void resize(const unsigned &n_value)
Resize the number of equations.
Definition: nodes.cc:2089
bool update_polygon_using_elements_area(TriangleMeshPolygon *&polygon_pt, const Vector< double > &target_area)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
bool update_open_curve_using_face_mesh(TriangleMeshOpenCurve *open_polyline_pt, const bool &check_only=false)
Helper function that updates the input open curve by using end-points of elements from FaceMesh(es) t...
double element_area() const
Helper function for getting the element area.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn&#39;t been defined.
unsigned ngeom_object(const int &id)
Number of geometric objects involved in id-th update function.
bool is_internal_point_fixed() const
Test whether the internal point is fixed.
Vector< double > vertex_coordinate(const unsigned &i) const
Coordinate vector of i-th vertex (const version)
void add_element_pt(GeneralisedElement *const &element_pt)
Add a (pointer to) an element to the mesh.
Definition: mesh.h:605
void construct_new_halo_node_helper(Node *&new_nod_pt, Vector< Node *> &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function which constructs a new halo node (on an element) with the information sent from the h...
virtual bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary, so return false. This will be overloaded by BoundaryNodes.
Definition: nodes.h:1290
void reset_halo_haloed_scheme_helper(Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Node *> > &iproc_currently_created_nodes_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
In charge of creating additional halo(ed) elements on those processors that have no shared boundaries...
std::map< unsigned, Vector< double > > & boundary_segment_initial_arclength()
Return direct access to the initial arclength for the segments that are part of a boundary...
unsigned final_vertex_connected_bnd_id() const
Gets the id to which the final end is connected.
void create_halo_element(unsigned &iproc, Vector< Node *> &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node *> > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node *> &global_shared_node_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
void compute_shared_node_degree_helper(Vector< Vector< FiniteElement *> > &unsorted_face_ele_pt, std::map< Node *, unsigned > &global_node_degree)
Computes the degree of the nodes on the shared boundaries, the degree of the node is computed from th...
void get_boundary_segment_nodes_helper(const unsigned &b, Vector< Vector< Node *> > &tmp_segment_nodes)
Get the nodes on the boundary (b), these are stored in the segment they belong (also used by the load...
int face_index_at_boundary_in_region(const unsigned &b, const unsigned &r, const unsigned &e) const
Return face index of the e-th element adjacent to boundary b in region r.
void get_required_elemental_information_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement *> > &f_haloed_ele_pt, FiniteElement *ele_pt)
Helper function to get the required elemental information from the element to be sent. This info. involves the association of the element to a boundary or region, and if its part of the halo(ed) elements within a processor.
void create_polylines_from_halo_elements_helper(const Vector< unsigned > &element_domain, std::map< GeneralisedElement *, unsigned > &element_to_global_index, std::set< FiniteElement *> &element_in_processor_pt, Vector< Vector< Vector< GeneralisedElement *> > > &input_halo_elements, std::map< std::pair< Node *, Node *>, unsigned > &elements_edges_on_boundary, Vector< Vector< Vector< TriangleMeshPolyLine *> > > &output_polylines_pt)
Creates polylines from the intersection of halo elements on all processors. The new polylines define ...
unsigned initial_vertex_connected_n_chunk() const
Gets the boundary chunk to which the initial end is connected.
unsigned long nboundary_segment_node(const unsigned &b)
Return the number of segments associated with a boundary.
void break_loops_on_shared_polyline_helper(const unsigned &initial_shd_bnd_id, std::list< Node *> &input_nodes, Vector< FiniteElement *> &input_boundary_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node *> > &output_sorted_nodes_pt, Vector< Vector< FiniteElement *> > &output_boundary_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them...
Definition: mesh.h:427
void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Overload set_mesh_level_time_stepper so that the stored time stepper now corresponds to the new times...
std::map< unsigned, unsigned > *& index_of_first_value_assigned_by_face_element_pt()
Return pointer to the map giving the index of the first face element value.
Definition: nodes.h:1910
unsigned nregion_element(const unsigned &i)
Return the number of elements in the i-th region.
void read_distributed_info_for_restart(std::istream &restart_file)
Used to read info. related with distributed triangle meshes.
void set_non_obsolete()
Mark node as non-obsolete.
Definition: nodes.h:1351
void re_assign_initial_zeta_values_for_internal_boundary(const unsigned &b, Vector< std::list< FiniteElement *> > &old_segment_sorted_ele_pt, std::map< FiniteElement *, bool > &old_is_inverted)
Re-assign the boundary segments initial zeta (arclength) value for those internal boundaries that wer...
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
double & min_permitted_angle()
Min angle before remesh gets triggered.
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition: timesteppers.h:219
bool Doc_stats
Boolean to indicate whether to output basic info during setup_multi_domain_interaction() routines...
unsigned final_vertex_connected_n_vertex() const
Sets the vertex number to which the final end is connected.
GeomObject * boundary_geom_object_pt(const unsigned &b)
Return the geometric object associated with the b-th boundary or null if the boundary has associated ...
Unstructured refineable Triangle Mesh.
void refine_triangulateio(TriangulateIO &triangulate_io, const Vector< double > &target_area, TriangulateIO &triangle_refine)
Build a new TriangulateIO object from previous TriangulateIO based on target area for each element...
void identify_boundary_segments_and_assign_initial_zeta_values(const unsigned &b, Vector< FiniteElement *> &input_face_ele_pt, const bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement *> &face_to_bulk_element_pt)
Identify the segments from the old mesh (original mesh) in the new mesh (this) and assign initial and...
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
std::map< unsigned, Vector< double > > & boundary_segment_final_arclength()
Return direct access to the final arclength for the segments that are part of a boundary.
Vector< GeomObject * > geom_object_vector_pt()
Access function to the vector of GeomObject.
A general mesh class.
Definition: mesh.h:74
void restore_polyline_connections_helper(TriangleMeshPolyLine *polyline_pt, Vector< TriangleMeshPolyLine *> &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine *> &resume_final_connection_polyline_pt)
Restore the connections of the specific polyline The vertices numbering on the destination boundaries...
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation...
Definition: nodes.cc:2328
bool can_update_reference_configuration() const
Test whether curve can update reference.
void get_halo_elements_on_all_procs(const unsigned &nproc, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement *> &backed_up_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status, std::map< GeneralisedElement *, unsigned > &element_to_global_index, Vector< Vector< Vector< GeneralisedElement *> > > &output_halo_elements_pt)
Creates the halo elements on all processors Gets the halo elements on all processors, these elements are then used on the function that computes the shared boundaries among the processors.
virtual unsigned ncurve_section() const
Number of constituent curves.
void get_shared_boundary_elements_and_face_indexes(const Vector< FiniteElement *> &first_element_pt, const Vector< FiniteElement *> &second_element_pt, Vector< FiniteElement *> &first_shared_boundary_element_pt, Vector< unsigned > &first_shared_boundary_element_face_index, Vector< FiniteElement *> &second_shared_boundary_element_pt, Vector< unsigned > &second_shared_boundary_element_face_index)
Use the first and second group of elements to find the intersection between them to get the shared bo...
unsigned Counter_for_flat_packed_doubles
Counter used when processing vector of flat-packed doubles – this is really "private" data...
unsigned initial_vertex_connected_bnd_id() const
Gets the id to which the initial end is connected.
void create_polylines_from_polyfiles(const std::string &node_file_name, const std::string &poly_file_name)
Helper function to create polylines and fill associate data.
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
unsigned npolyline() const
Number of constituent polylines.
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
Definition: communicator.h:57
Class defining a closed polygon for the Triangle mesh generation.