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// Copyright (C) 2006-2024 Matthias Heil and Andrew Hazel
7 // LIC//
8 // LIC// This library is free software; you can redistribute it and/or
9 // LIC// modify it under the terms of the GNU Lesser General Public
10 // LIC// License as published by the Free Software Foundation; either
11 // LIC// version 2.1 of the License, or (at your option) any later version.
12 // LIC//
13 // LIC// This library is distributed in the hope that it will be useful,
14 // LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // LIC// Lesser General Public License for more details.
17 // LIC//
18 // LIC// You should have received a copy of the GNU Lesser General Public
19 // LIC// License along with this library; if not, write to the Free Software
20 // LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // LIC// 02110-1301 USA.
22 // LIC//
23 // LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 // LIC//
25 // LIC//====================================================================
26 #ifndef OOMPH_TRIANGLE_MESH_TEMPLATE_CC
27 #define OOMPH_TRIANGLE_MESH_TEMPLATE_CC
28 
29 #include <iostream>
30 
31 #include "triangle_mesh.template.h"
32 #include "../generic/map_matrix.h"
33 #include "../generic/multi_domain.h"
34 #include "../generic/projection.h"
35 #include "../generic/face_element_as_geometric_object.h"
36 
37 namespace oomph
38 {
39  //======================================================================
40  /// Build with the help of the scaffold mesh coming
41  /// from the triangle mesh generator Triangle.
42  //======================================================================
43  template<class ELEMENT>
44  void TriangleMesh<ELEMENT>::build_from_scaffold(TimeStepper* time_stepper_pt,
45  const bool& use_attributes)
46  {
47  // Mesh can only be built with 2D Telements.
48  MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(2);
49 
50  // Create space for elements
51  unsigned nelem = Tmp_mesh_pt->nelement();
52  Element_pt.resize(nelem);
53 
54  // Create space for nodes
55  unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
56 
57  // Create a map storing the node_id of the mesh used to update the
58  // node position in the update_triangulateio function
59  std::map<Node*, unsigned> old_global_number;
60 
61  // Store the TriangulateIO node id
62  for (unsigned inod = 0; inod < nnode_scaffold; inod++)
63  {
64  Node* old_node_pt = Tmp_mesh_pt->node_pt(inod);
65  old_global_number[old_node_pt] = inod;
66  }
67 
68  // Initialize the old node id vector
69  Oomph_vertex_nodes_id.resize(nnode_scaffold);
70 
71  // Create space for nodes
72  Node_pt.resize(nnode_scaffold, 0);
73 
74  // Set number of boundaries
75  unsigned nbound = Tmp_mesh_pt->nboundary();
76 
77  // Resize the boundary information
78  set_nboundary(nbound);
79  Boundary_element_pt.resize(nbound);
80  Face_index_at_boundary.resize(nbound);
81 
82  // If we have different regions, then resize the region
83  // information
84  if (use_attributes)
85  {
86  Boundary_region_element_pt.resize(nbound);
87  Face_index_region_at_boundary.resize(nbound);
88  }
89 
90  // Loop over elements in scaffold mesh, visit their nodes
91  for (unsigned e = 0; e < nelem; e++)
92  {
93  Element_pt[e] = new ELEMENT;
94  }
95 
96  // Number of nodes per element from the scaffold mesh
97  unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
98 
99  // Setup map to check the (pseudo-)global node number
100  // Nodes whose number is zero haven't been copied across
101  // into the mesh yet.
102  std::map<Node*, unsigned> global_number;
103  unsigned global_count = 0;
104 
105  // Map of Element attribute pairs
106  std::map<double, Vector<FiniteElement*>> element_attribute_map;
107 
108  // If we're using attributes
109  if (use_attributes)
110  {
111  // If we're using attributes then we need attribute 0 which will
112  // be associated with region 0
113  element_attribute_map[0].resize(0);
114  }
115 
116  // Loop over elements in scaffold mesh, visit their nodes
117  for (unsigned e = 0; e < nelem; e++)
118  {
119  // Loop over all nodes in element
120  for (unsigned j = 0; j < nnod_el; j++)
121  {
122  // Pointer to node in the scaffold mesh
123  Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
124 
125  // Get the (pseudo-)global node number in scaffold mesh
126  // (It's zero [=default] if not visited this one yet)
127  unsigned j_global = global_number[scaffold_node_pt];
128 
129  // Haven't done this one yet
130  if (j_global == 0)
131  {
132  // Find and store the node_id in the old nodes map
133  Oomph_vertex_nodes_id[global_count] =
134  old_global_number[scaffold_node_pt];
135 
136  // Get pointer to set of mesh boundaries that this
137  // scaffold node occupies; NULL if the node is not on any boundary
138  std::set<unsigned>* boundaries_pt;
139  scaffold_node_pt->get_boundaries_pt(boundaries_pt);
140 
141  // Storage for the new node
142  Node* new_node_pt = 0;
143 
144  // Is it on boundaries
145  if (boundaries_pt != 0)
146  {
147  // Create new boundary node
148  new_node_pt =
149  finite_element_pt(e)->construct_boundary_node(j, time_stepper_pt);
150 
151  // Add to boundaries
152  for (std::set<unsigned>::iterator it = boundaries_pt->begin();
153  it != boundaries_pt->end();
154  ++it)
155  {
156  add_boundary_node(*it, new_node_pt);
157  }
158  }
159  // Build normal node
160  else
161  {
162  // Create new normal node
163  new_node_pt =
164  finite_element_pt(e)->construct_node(j, time_stepper_pt);
165  }
166 
167  // Give it a number (not necessarily the global node
168  // number in the scaffold mesh -- we just need something
169  // to keep track...)
170  global_count++;
171  global_number[scaffold_node_pt] = global_count;
172 
173  // Copy new node, created using the NEW element's construct_node
174  // function into global storage, using the same global
175  // node number that we've just associated with the
176  // corresponding node in the scaffold mesh
177  Node_pt[global_count - 1] = new_node_pt;
178 
179  // Assign coordinates
180  for (unsigned i = 0; i < finite_element_pt(e)->dim(); i++)
181  {
182  new_node_pt->x(i) = scaffold_node_pt->x(i);
183  }
184  }
185  // This one has already been done: Copy accross
186  else
187  {
188  finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
189  }
190  }
191 
192  // If we're using attributes
193  if (use_attributes)
194  {
195  element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
196  finite_element_pt(e));
197  }
198  }
199 
200  // Now let's construct lists
201  // Find the number of attributes
202  if (use_attributes)
203  {
204  unsigned n_attribute = element_attribute_map.size();
205 
206  // There are n_attribute different regions
207  this->Region_attribute.resize(n_attribute);
208 
209  // Copy the vectors in the map over to our internal storage
210  unsigned count = 0;
211  for (std::map<double, Vector<FiniteElement*>>::iterator it =
212  element_attribute_map.begin();
213  it != element_attribute_map.end();
214  ++it)
215  {
216  this->Region_attribute[count] = it->first;
217  Region_element_pt[static_cast<unsigned>(Region_attribute[count])] =
218  it->second;
219  ++count;
220  }
221  }
222 
223  // At this point we've created all the elements and
224  // created their vertex nodes. Now we need to create
225  // the additional (midside and internal) nodes!
226 
227  unsigned boundary_id = 0;
228 
229  // Get number of nodes along element edge and dimension of element (2)
230  // from first element
231  unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
232  unsigned dim = finite_element_pt(0)->dim();
233 
234  // Storage for the local coordinate of the new node
235  Vector<double> s(dim);
236 
237  // Get number of nodes in the element from first element
238  unsigned n_node = finite_element_pt(0)->nnode();
239 
240  // Storage for each global edge of the mesh
241  unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
242  Vector<Vector<Node*>> nodes_on_global_edge(n_global_edge);
243 
244  // Loop over elements
245  for (unsigned e = 0; e < nelem; e++)
246  {
247  // Cache pointers to the elements
248  FiniteElement* const elem_pt = finite_element_pt(e);
249  FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
250 
251  // The number of edge nodes is 3*(nnode_1d-1)
252  unsigned n_edge_node = 3 * (n_node_1d - 1);
253 
254  // If there are any more nodes, these are internal and can be
255  // constructed and added directly to the mesh
256  for (unsigned n = n_edge_node; n < n_node; ++n)
257  {
258  // Create new node (it can never be a boundary node)
259  Node* new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
260 
261  // What are the node's local coordinates?
262  elem_pt->local_coordinate_of_node(n, s);
263 
264  // Find the coordinates of the new node from the existing
265  // and fully-functional element in the scaffold mesh
266  for (unsigned i = 0; i < dim; i++)
267  {
268  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
269  }
270 
271  // Add the node to the mesh's global look-up scheme
272  Node_pt.push_back(new_node_pt);
273  }
274 
275  // Now loop over the mid-side edge nodes
276  // Start from node number 3
277  unsigned n = 3;
278 
279  // Loop over edges
280  for (unsigned j = 0; j < 3; j++)
281  {
282  // Find the boundary id of the edge
283  boundary_id = Tmp_mesh_pt->edge_boundary(e, j);
284 
285  // Find the global edge index
286  unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
287 
288  // If the nodes on the edge have not been allocated, construct them
289  if (nodes_on_global_edge[edge_index].size() == 0)
290  {
291  // Loop over the nodes on the edge excluding the ends
292  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
293  {
294  // Storage for the new node
295  Node* new_node_pt = 0;
296 
297  // If the edge is on a boundary, construct a boundary node
298  if (boundary_id > 0)
299  {
300  new_node_pt =
301  elem_pt->construct_boundary_node(n, time_stepper_pt);
302  // Add it to the boundary
303  this->add_boundary_node(boundary_id - 1, new_node_pt);
304  }
305  // Otherwise construct a normal node
306  else
307  {
308  new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
309  }
310 
311  // What are the node's local coordinates?
312  elem_pt->local_coordinate_of_node(n, s);
313 
314  // Find the coordinates of the new node from the existing
315  // and fully-functional element in the scaffold mesh
316  for (unsigned i = 0; i < dim; i++)
317  {
318  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
319  }
320 
321  // Add to the global node list
322  Node_pt.push_back(new_node_pt);
323 
324  // Add to the edge index
325  nodes_on_global_edge[edge_index].push_back(new_node_pt);
326  // Increment the node number
327  ++n;
328  }
329  }
330  // Otherwise just set the pointers
331  // using the fact that the next time the edge is visited
332  // the nodes must be arranged in the other order because all
333  // triangles have the same orientation
334  else
335  {
336  // Loop over the nodes on the edge excluding the ends
337  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
338  {
339  // Set the local node from the edge but indexed the other
340  // way around
341  elem_pt->node_pt(n) =
342  nodes_on_global_edge[edge_index][n_node_1d - 3 - j2];
343  ++n;
344  }
345  }
346 
347  // Set the elements adjacent to the boundary from the
348  // boundary id information
349  if (boundary_id > 0)
350  {
351  Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
352  // Need to put a shift in here because of an inconsistent naming
353  // convention between triangle and face elements
354  Face_index_at_boundary[boundary_id - 1].push_back((j + 2) % 3);
355 
356  // If using regions set up the boundary information
357  if (use_attributes)
358  {
359  unsigned tmp_region =
360  static_cast<unsigned>(Tmp_mesh_pt->element_attribute(e));
361  // Element adjacent to boundary
362  Boundary_region_element_pt[boundary_id - 1][tmp_region].push_back(
363  elem_pt);
364  // Need to put a shift in here because of an inconsistent naming
365  // convention between triangle and face elements
366  Face_index_region_at_boundary[boundary_id - 1][tmp_region]
367  .push_back((j + 2) % 3);
368  }
369  }
370 
371  } // end of loop over edges
372  } // end of loop over elements
373 
374 
375  // Lookup scheme has now been setup
376  Lookup_for_elements_next_boundary_is_setup = true;
377  }
378 
379 #ifdef OOMPH_HAS_MPI
380 
381  //======================================================================
382  /// Identify the segments from the old mesh (original mesh)
383  /// in the new mesh (this) and assign initial and final boundary
384  /// coordinates for the segments that create the boundary
385  //======================================================================
386  template<class ELEMENT>
389  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt)
390  {
391  // ------------------------------------------------------------------
392  // First: Get the face elements associated with the current boundary
393  // (nonhalo elements only)
394  // ------------------------------------------------------------------
395  // Temporary storage for face elements
396  Vector<FiniteElement*> face_el_pt;
397 
398  // Temporary storage for number of elements adjacent to the boundary
399  unsigned nele = 0;
400 
401  // Temporary storage for elements adjacent to the boundary that have
402  // a common edge (related with internal boundaries)
403  unsigned n_repeated_ele = 0;
404 
405  const unsigned n_regions = this->nregion();
406 
407  // map to associate the face element to the bulk element, necessary
408  // to attach halo face elements at both sides of each found segment
409  std::map<FiniteElement*, FiniteElement*> face_to_bulk_element_pt;
410 
411  // Temporary storage for already done nodes
412  Vector<std::pair<Node*, Node*>> done_nodes_pt;
413 
414  // If there is more than one region then only use boundary
415  // coordinates from the bulk side (region 0)
416  if (n_regions > 1)
417  {
418  for (unsigned rr = 0; rr < n_regions; rr++)
419  {
420  const unsigned region_id =
421  static_cast<unsigned>(this->Region_attribute[rr]);
422 
423  // Loop over all elements on boundaries in region i_r
424  const unsigned nel_in_region =
425  this->nboundary_element_in_region(b, region_id);
426 
427  unsigned nel_repetead_in_region = 0;
428 
429  // Only bother to do anything else, if there are elements
430  // associated with the boundary and the current region
431  if (nel_in_region > 0)
432  {
433  // Flag that activates when a repeated face element is found,
434  // possibly because we are dealing with an internal boundary
435  bool repeated = false;
436 
437  // Loop over the bulk elements adjacent to boundary b
438  for (unsigned e = 0; e < nel_in_region; e++)
439  {
440  // Get pointer to the bulk element that is adjacent to boundary b
441  FiniteElement* bulk_elem_pt =
442  this->boundary_element_in_region_pt(b, region_id, e);
443 
444 #ifdef OOMPH_HAS_MPI
445  // In a distributed mesh only work with nonhalo elements
446  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
447  {
448  // Increase the number of repeated elements
449  n_repeated_ele++;
450  // Go for the next element
451  continue;
452  }
453 #endif
454 
455  // Find the index of the face of element e along boundary b
456  int face_index =
457  this->face_index_at_boundary_in_region(b, region_id, e);
458 
459  // Before adding the new element we need to be sure that
460  // the edge that this element represent has not been
461  // already added
462  FiniteElement* tmp_ele_pt =
463  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
464 
465  const unsigned n_nodes = tmp_ele_pt->nnode();
466 
467  std::pair<Node*, Node*> tmp_pair = std::make_pair(
468  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
469 
470  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
471  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
472 
473  // Search for repeated nodes
474  const unsigned n_done_nodes = done_nodes_pt.size();
475  for (unsigned l = 0; l < n_done_nodes; l++)
476  {
477  if (tmp_pair == done_nodes_pt[l] ||
478  tmp_pair_inverse == done_nodes_pt[l])
479  {
480  nel_repetead_in_region++;
481  repeated = true;
482  break;
483  }
484  }
485 
486  // Create new face element
487  if (!repeated)
488  {
489  // Add the pair of nodes (edge) to the node dones
490  done_nodes_pt.push_back(tmp_pair);
491  // Create the map to know if the element is halo
492  face_el_pt.push_back(tmp_ele_pt);
493  // Add the element to the face elements
494  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
495  }
496  else
497  {
498  // Clean up
499  delete tmp_ele_pt;
500  tmp_ele_pt = 0;
501  }
502 
503  // Re-start
504  repeated = false;
505 
506  } // for (e < nel_in_region)
507 
508  nele += nel_in_region;
509 
510  n_repeated_ele += nel_repetead_in_region;
511 
512  } // if (nel_in_region > 0)
513  } // for (rr < n_regions)
514  } // if (n_regions > 1)
515  // Otherwise it's just the normal boundary functions
516  else
517  {
518  // Loop over all elements on boundaries
519  nele = this->nboundary_element(b);
520 
521  // Only bother to do anything else, if there are elements
522  if (nele > 0)
523  {
524  // Flag that activates when a repeated face element is found,
525  // possibly because we are dealing with an internal boundary
526  bool repeated = false;
527 
528  // Loop over the bulk elements adjacent to boundary b
529  for (unsigned e = 0; e < nele; e++)
530  {
531  // Get pointer to the bulk element that is adjacent to boundary b
532  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
533 
534 #ifdef OOMPH_HAS_MPI
535  // In a distributed mesh only work with nonhalo elements
536  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
537  {
538  // Increase the number of repeated elements
539  n_repeated_ele++;
540  // Go for the next element
541  continue;
542  }
543 #endif
544 
545  // Find the index of the face of element e along boundary b
546  int face_index = this->face_index_at_boundary(b, e);
547 
548  // Before adding the new element we need to be sure that
549  // the edge that this element represents has not been
550  // already added (only applies for internal boundaries)
551  FiniteElement* tmp_ele_pt =
552  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
553 
554  const unsigned n_nodes = tmp_ele_pt->nnode();
555 
556  std::pair<Node*, Node*> tmp_pair = std::make_pair(
557  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
558 
559  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
560  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
561 
562  // Search for repeated nodes
563  const unsigned n_done_nodes = done_nodes_pt.size();
564  for (unsigned l = 0; l < n_done_nodes; l++)
565  {
566  if (tmp_pair == done_nodes_pt[l] ||
567  tmp_pair_inverse == done_nodes_pt[l])
568  {
569  // Increase the number of repeated elements
570  n_repeated_ele++;
571  // Mark the element as repeated
572  repeated = true;
573  break;
574  }
575  }
576 
577  // Create new face element
578  if (!repeated)
579  {
580  // Add the pair of nodes (edge) to the node dones
581  done_nodes_pt.push_back(tmp_pair);
582  // Add the element to the face elements
583  face_el_pt.push_back(tmp_ele_pt);
584  // Create the map to know if the element is halo
585  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
586  }
587  else
588  {
589  // Free the repeated bulk element!!
590  delete tmp_ele_pt;
591  tmp_ele_pt = 0;
592  }
593 
594  // Re-start
595  repeated = false;
596 
597  } // for (e < nel)
598  } // if (nel > 0)
599 
600  } // else (n_regions > 1)
601 
602  // Do not consider the repeated elements
603  nele -= n_repeated_ele;
604 
605 #ifdef PARANOID
606  if (nele != face_el_pt.size())
607  {
608  std::ostringstream error_message;
609  error_message
610  << "The independent counting of face elements (" << nele << ") for "
611  << "boundary (" << b << ") is different\n"
612  << "from the real number of face elements in the container ("
613  << face_el_pt.size() << ")\n";
614  throw OomphLibError(error_message.str(),
615  "TriangleMesh::identify_boundary_segments_and_assign_"
616  "initial_zeta_values()",
617  OOMPH_EXCEPTION_LOCATION);
618  }
619 #endif
620 
621  // Continue even thought there are no elements, the processor needs
622  // to participate in the communications
623 
624  // ----------------------------------------------------------------
625  // Second: Sort the face elements, only consider nonhalo elements
626  // ----------------------------------------------------------------
627 
628  // A flag vector to mark those face elements that are considered as
629  // halo in the current processor
630  std::vector<bool> is_halo_face_element(nele, false);
631 
632  // Count the total number of non halo face elements
633  unsigned nnon_halo_face_elements = 0;
634 
635  // We will have halo face elements if the mesh is distributed
636  for (unsigned ie = 0; ie < nele; ie++)
637  {
638  // Get the face element
639  FiniteElement* face_ele_pt = face_el_pt[ie];
640  // Get the bulk element
641  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
642  // Check if the bulk element is halo
643  if (!tmp_bulk_ele_pt->is_halo())
644  {
645  is_halo_face_element[ie] = false;
646  nnon_halo_face_elements++;
647  }
648  else
649  {
650  // Mark the face element as halo
651  is_halo_face_element[ie] = true;
652  }
653  } // for (ie < nele)
654 
655 #ifdef PARANOID
656  // Get the total number of halo face elements
657  const unsigned nhalo_face_element = nele - nnon_halo_face_elements;
658  if (nhalo_face_element > 0)
659  {
660  std::ostringstream error_message;
661  error_message
662  << "There should not be halo face elements since they were not "
663  << "considered when computing the face elements\n\n"
664  << "The number of found halo face elements is: " << nhalo_face_element
665  << "\n\n";
666  throw OomphLibError(error_message.str(),
667  "TriangleMesh::identify_boundary_segments_and_assign_"
668  "initial_zeta_values()",
669  OOMPH_EXCEPTION_LOCATION);
670  }
671 #endif
672 
673  // The vector of list to store the "segments" that compound the
674  // boundary (segments may appear only in a distributed mesh)
675  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
676 
677  // Number of already sorted face elements (only nonhalo elements for
678  // a distributed mesh)
679  unsigned nsorted_face_elements = 0;
680 
681  // Keep track of who's done (this apply to nonhalo only, remember we
682  // are only working with nonhalo elements)
683  std::map<FiniteElement*, bool> done_el;
684 
685  // Keep track of which element is inverted (in distributed mesh the
686  // elements may be inverted with respect to the segment they belong)
687  std::map<FiniteElement*, bool> is_inverted;
688 
689  // Iterate until all possible segments have been created
690  while (nsorted_face_elements < nnon_halo_face_elements)
691  {
692  // The ordered list of face elements (in a distributed mesh a
693  // collection of contiguous face elements define a segment)
694  std::list<FiniteElement*> sorted_el_pt;
695  sorted_el_pt.clear();
696 
697 #ifdef PARANOID
698  // Select an initial element for the segment
699  bool found_initial_face_element = false;
700 #endif
701 
702  FiniteElement* ele_face_pt = 0;
703 
704  unsigned iface = 0;
705  for (iface = 0; iface < nele; iface++)
706  {
707  if (!is_halo_face_element[iface])
708  {
709  ele_face_pt = face_el_pt[iface];
710  // If not done then take it as initial face element
711  if (!done_el[ele_face_pt])
712  {
713 #ifdef PARANOID
714  found_initial_face_element = true;
715 #endif
716  nsorted_face_elements++;
717  iface++; // The next element number
718  sorted_el_pt.push_back(ele_face_pt);
719  // Mark as done
720  done_el[ele_face_pt] = true;
721  break;
722  }
723  }
724  } // for (iface < nele)
725 
726 #ifdef PARANOID
727  if (!found_initial_face_element)
728  {
729  std::ostringstream error_message;
730  error_message
731  << "Could not find an initial face element for the current segment\n";
732  throw OomphLibError(error_message.str(),
733  "TriangleMesh::identify_boundary_segments_and_"
734  "assign_initial_zeta_values()",
735  OOMPH_EXCEPTION_LOCATION);
736  }
737 #endif
738 
739  // Number of nodes
740  const unsigned nnod = ele_face_pt->nnode();
741 
742  // Left and right most nodes (the left and right nodes of the
743  // current face element)
744  Node* left_node_pt = ele_face_pt->node_pt(0);
745  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
746 
747  // Continue iterating if a new face element has been added to the
748  // list
749  bool face_element_added = false;
750 
751  // While a new face element has been added to the set of sorted
752  // face elements then re-iterate
753  do
754  {
755  // Start from the next face element since we have already added
756  // the previous one as the initial face element (any previous
757  // face element had to be added on previous iterations)
758  for (unsigned iiface = iface; iiface < nele; iiface++)
759  {
760  // Re-start flag
761  face_element_added = false;
762 
763  // Get the candidate element
764  ele_face_pt = face_el_pt[iiface];
765 
766  // Check that the candidate element has not been done and is
767  // not a halo element
768  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
769  {
770  // Get the left and right nodes of the current element
771  Node* local_left_node_pt = ele_face_pt->node_pt(0);
772  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
773  // New element fits at the left of segment and is not inverted
774  if (left_node_pt == local_right_node_pt)
775  {
776  left_node_pt = local_left_node_pt;
777  sorted_el_pt.push_front(ele_face_pt);
778  is_inverted[ele_face_pt] = false;
779  face_element_added = true;
780  }
781  // New element fits at the left of segment and is inverted
782  else if (left_node_pt == local_left_node_pt)
783  {
784  left_node_pt = local_right_node_pt;
785  sorted_el_pt.push_front(ele_face_pt);
786  is_inverted[ele_face_pt] = true;
787  face_element_added = true;
788  }
789  // New element fits on the right of segment and is not inverted
790  else if (right_node_pt == local_left_node_pt)
791  {
792  right_node_pt = local_right_node_pt;
793  sorted_el_pt.push_back(ele_face_pt);
794  is_inverted[ele_face_pt] = false;
795  face_element_added = true;
796  }
797  // New element fits on the right of segment and is inverted
798  else if (right_node_pt == local_right_node_pt)
799  {
800  right_node_pt = local_left_node_pt;
801  sorted_el_pt.push_back(ele_face_pt);
802  is_inverted[ele_face_pt] = true;
803  face_element_added = true;
804  }
805 
806  if (face_element_added)
807  {
808  done_el[ele_face_pt] = true;
809  nsorted_face_elements++;
810  break;
811  }
812 
813  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
814  } // for (iiface<nnon_halo_face_element)
815  } while (face_element_added &&
816  (nsorted_face_elements < nnon_halo_face_elements));
817 
818  // Store the created segment in the vector of segments
819  segment_sorted_ele_pt.push_back(sorted_el_pt);
820 
821  } // while(nsorted_face_elements < nnon_halo_face_elements);
822 
823  // The number of segments in this processor
824  const unsigned nsegments = segment_sorted_ele_pt.size();
825 
826  // ------------------------------------------------------------------
827  // Third: We have the face elements sorted (nonhalo only), now
828  // assign boundary coordinates to the nodes in the segments. This is
829  // the LOCAL boundary coordinate which is required if the zeta
830  // values need to be inverted
831  // ------------------------------------------------------------------
832  // Necessary in case boundaries with no geom object associated need
833  // to be inverted the zeta values (It is necessary to compute the
834  // arclength but also to store the nodes in a container (set))
835  // ------------------------------------------------------------------
836 
837  // Vector of sets that stores the nodes of each segment based on a
838  // lexicographically order starting from the bottom left node of
839  // each segment
840  Vector<std::set<Node*>> segment_all_nodes_pt;
841 
842  // The arclength of each segment in the current processor
843  Vector<double> segment_arclength(nsegments);
844 
845  // The number of vertices of each segment
846  Vector<unsigned> nvertices_per_segment(nsegments);
847 
848  // The initial zeta for the segment
849  Vector<double> initial_zeta_segment(nsegments);
850 
851  // The final zeta for the segment
852  Vector<double> final_zeta_segment(nsegments);
853 
854 #ifdef PARANOID
855  if (nnon_halo_face_elements > 0 && nsegments == 0)
856  {
857  std::ostringstream error_message;
858  error_message
859  << "The number of segments is zero, but the number of nonhalo\n"
860  << "elements is: (" << nnon_halo_face_elements << ")\n";
861  throw OomphLibError(error_message.str(),
862  "TriangleMesh::identify_boundary_segments_and_assign_"
863  "initial_zeta_values()",
864  OOMPH_EXCEPTION_LOCATION);
865  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
866 #endif
867 
868  // Go through all the segments and compute the LOCAL boundary
869  // coordinates
870  for (unsigned is = 0; is < nsegments; is++)
871  {
872 #ifdef PARANOID
873  if (segment_sorted_ele_pt[is].size() == 0)
874  {
875  std::ostringstream error_message;
876  error_message << "The (" << is << ")-th segment has no elements\n";
877  throw OomphLibError(error_message.str(),
878  "TriangleMesh::identify_boundary_segments_and_"
879  "assign_initial_zeta_values()",
880  OOMPH_EXCEPTION_LOCATION);
881  } // if (segment_sorted_ele_pt[is].size() == 0)
882 #endif
883 
884  // Get access to the first element on the segment
885  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
886 
887  // Number of nodes
888  const unsigned nnod = first_ele_pt->nnode();
889 
890  // Get the first node of the current segment
891  Node* first_node_pt = first_ele_pt->node_pt(0);
892  if (is_inverted[first_ele_pt])
893  {
894  first_node_pt = first_ele_pt->node_pt(nnod - 1);
895  }
896 
897  // Get access to the last element on the segment
898  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
899 
900  // Get the last node of the current segment
901  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
902  if (is_inverted[last_ele_pt])
903  {
904  last_node_pt = last_ele_pt->node_pt(0);
905  }
906 
907  // Coordinates of left node
908  double x_left = first_node_pt->x(0);
909  double y_left = first_node_pt->x(1);
910 
911  // Initialise boundary coordinate (local boundary coordinate for
912  // boundaries with more than one segment)
913  Vector<double> zeta(1, 0.0);
914 
915  // If the boundary has an associated GeomObject then it is not
916  // necessary to compute the arclength, only read the values from
917  // the nodes at the edges
918  if (this->boundary_geom_object_pt(b) != 0)
919  {
920  first_node_pt->get_coordinates_on_boundary(b, zeta);
921  initial_zeta_segment[is] = zeta[0];
922  last_node_pt->get_coordinates_on_boundary(b, zeta);
923  final_zeta_segment[is] = zeta[0];
924  }
925 
926  // Lexicographically bottom left node
927  std::set<Node*> local_nodes_pt;
928  local_nodes_pt.insert(first_node_pt);
929 
930  // Now loop over nodes in order
931  for (std::list<FiniteElement*>::iterator it =
932  segment_sorted_ele_pt[is].begin();
933  it != segment_sorted_ele_pt[is].end();
934  it++)
935  {
936  // Get element
937  FiniteElement* el_pt = *it;
938 
939  // Start node and increment
940  unsigned k_nod = 1;
941  int nod_diff = 1;
942  if (is_inverted[el_pt])
943  {
944  k_nod = nnod - 2;
945  nod_diff = -1;
946  }
947 
948  // Loop over nodes
949  for (unsigned j = 1; j < nnod; j++)
950  {
951  Node* nod_pt = el_pt->node_pt(k_nod);
952  k_nod += nod_diff;
953 
954  // Coordinates of right node
955  double x_right = nod_pt->x(0);
956  double y_right = nod_pt->x(1);
957 
958  // Increment boundary coordinate (the arclength)
959  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
960  (y_right - y_left) * (y_right - y_left));
961 
962  // // When we have a GeomObject associated to the boundary we already
963  // // know the zeta values for the nodes, there is no need to compute
964  // // the arclength
965  // if (this->boundary_geom_object_pt(b)==0)
966  // {
967  // // Set boundary coordinate
968  // nod_pt->set_coordinates_on_boundary(b, zeta);
969  // }
970 
971  // Increment reference coordinate
972  x_left = x_right;
973  y_left = y_right;
974 
975  // Get lexicographically bottom left node but only
976  // use vertex nodes as candidates
977  local_nodes_pt.insert(nod_pt);
978  } // for (j < nnod)
979 
980  } // iterator over the elements in the segment
981 
982  // Store the arclength of the segment
983  segment_arclength[is] = zeta[0];
984 
985  // Store the number of vertices in the segment
986  nvertices_per_segment[is] = local_nodes_pt.size();
987 
988  // Add the nodes for the corresponding segment in the container
989  segment_all_nodes_pt.push_back(local_nodes_pt);
990 
991  } // for (is < nsegments)
992 
993  // Get the number of sets for nodes
994 #ifdef PARANOID
995  if (segment_all_nodes_pt.size() != nsegments)
996  {
997  std::ostringstream error_message;
998  error_message << "The number of segments (" << nsegments
999  << ") and the number of "
1000  << "sets of nodes (" << segment_all_nodes_pt.size()
1001  << ") representing\n"
1002  << "the\nsegments is different!!!\n\n";
1003  throw OomphLibError(
1004  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1005  }
1006 #endif
1007 
1008  // Store the initial arclength for each segment of boundary in the
1009  // current processor, initalise to zero in case we have a non
1010  // distributed boundary
1011  Vector<double> initial_segment_arclength(nsegments, 0.0);
1012 
1013  // Associated the index of the current segment to the segment index
1014  // in the original mesh (input mesh)
1015  Vector<unsigned> current_segment_to_original_segment_index(nsegments);
1016 
1017  // Each segment needs to know whether it has to be inverted or not
1018  // Store whether a segment needs to be inverted or not
1019  Vector<unsigned> segment_inverted(nsegments);
1020 
1021  // -----------------------------------------------------------------
1022  // Fourth: Identify the segments with the ones in the original mesh
1023  // (has sense only in the adaptation process)
1024  // -----------------------------------------------------------------
1025 
1026  // Now check if there are segments associated to this boundary
1027  if (nsegments > 0)
1028  {
1029 #ifdef PARANOID
1030  // Double check that the same number of coordinates (nsegments)
1031  // have been established for the boundary
1032  const unsigned nsegments_initial_coordinates =
1033  original_mesh_pt->boundary_segment_initial_coordinate(b).size();
1034 
1035  const unsigned nsegments_final_coordinates =
1036  original_mesh_pt->boundary_segment_final_coordinate(b).size();
1037 
1038  if (nsegments_initial_coordinates != nsegments_final_coordinates)
1039  {
1040  std::stringstream error_message;
1041  error_message
1042  << "The number of segments that present initial coordinates "
1043  << nsegments_initial_coordinates << " is different from "
1044  << "the\nnumber of segments that present final coordinates "
1045  << nsegments_final_coordinates << "\n\n";
1046  throw OomphLibError(error_message.str(),
1047  OOMPH_CURRENT_FUNCTION,
1048  OOMPH_EXCEPTION_LOCATION);
1049  } // if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1050 
1051  // Also check that the number of segments found in the previous
1052  // mesh is the same as the number of segments found in this mesh
1053  if (nsegments_initial_coordinates != nsegments)
1054  {
1055  std::stringstream error_message;
1056  error_message << "Working with boundary (" << b
1057  << ").\n The number of initial and "
1058  << "final coordinates (" << nsegments_initial_coordinates
1059  << ") is different from\n"
1060  << "the number of found segments (" << nsegments
1061  << ").\n\n";
1062  throw OomphLibError(error_message.str(),
1063  OOMPH_CURRENT_FUNCTION,
1064  OOMPH_EXCEPTION_LOCATION);
1065  } // if (nsegments_initial_coordinates != nsegments)
1066 #endif
1067 
1068  // Create a backup for the data from the original mesh
1069  // Backup for the coordinates
1070  Vector<Vector<double>> original_mesh_segment_initial_coordinate(
1071  nsegments);
1072  Vector<Vector<double>> original_mesh_segment_final_coordinate(nsegments);
1073  // Backup for the zeta values
1074  Vector<double> original_mesh_segment_initial_zeta(nsegments);
1075  Vector<double> original_mesh_segment_final_zeta(nsegments);
1076  // Backup for the arclengths
1077  Vector<double> original_mesh_segment_initial_arclength(nsegments);
1078  Vector<double> original_mesh_segment_final_arclength(nsegments);
1079  // Do the backup
1080  for (unsigned is = 0; is < nsegments; is++)
1081  {
1082  original_mesh_segment_initial_coordinate[is].resize(2);
1083  original_mesh_segment_final_coordinate[is].resize(2);
1084  for (unsigned k = 0; k < 2; k++)
1085  {
1086  original_mesh_segment_initial_coordinate[is][k] =
1087  original_mesh_pt->boundary_segment_initial_coordinate(b)[is][k];
1088  original_mesh_segment_final_coordinate[is][k] =
1089  original_mesh_pt->boundary_segment_final_coordinate(b)[is][k];
1090  }
1091  // Check if the boudary has an associated GeomObject
1092  if (this->boundary_geom_object_pt(b) != 0)
1093  {
1094  original_mesh_segment_initial_zeta[is] =
1095  original_mesh_pt->boundary_segment_initial_zeta(b)[is];
1096  original_mesh_segment_final_zeta[is] =
1097  original_mesh_pt->boundary_segment_final_zeta(b)[is];
1098  }
1099  else
1100  {
1101  original_mesh_segment_initial_arclength[is] =
1102  original_mesh_pt->boundary_segment_initial_arclength(b)[is];
1103  original_mesh_segment_final_arclength[is] =
1104  original_mesh_pt->boundary_segment_final_arclength(b)[is];
1105  }
1106  } // for (is < nsegments)
1107 
1108  // Clear all the storage
1109  Boundary_segment_inverted[b].clear();
1110  Boundary_segment_initial_coordinate[b].clear();
1111  Boundary_segment_final_coordinate[b].clear();
1112 
1113  Boundary_segment_initial_zeta[b].clear();
1114  Boundary_segment_final_zeta[b].clear();
1115 
1116  Boundary_segment_initial_arclength[b].clear();
1117  Boundary_segment_final_arclength[b].clear();
1118 
1119  // Identify each segment in the processor with the ones created
1120  // by the original mesh
1121  // -----------------------------------------------------------------
1122  // Keep track of the already identified segments
1123  std::map<unsigned, bool> segment_done;
1124  for (unsigned is = 0; is < nsegments; is++)
1125  {
1126 #ifdef PARANOID
1127  // Flag to know if the segment was identified
1128  bool found_original_segment = false;
1129 #endif
1130 
1131  // Get the initial and final coordinates of the current segment
1132  Vector<double> current_seg_initial_coord(2);
1133  Vector<double> current_seg_final_coord(2);
1134 
1135  // Get access to the initial element on the segment
1136  FiniteElement* current_seg_initial_ele_pt =
1137  segment_sorted_ele_pt[is].front();
1138 
1139  // Number of nodes
1140  const unsigned nnod = current_seg_initial_ele_pt->nnode();
1141 
1142  // Get the first node of the current segment
1143  Node* current_seg_first_node_pt =
1144  current_seg_initial_ele_pt->node_pt(0);
1145  if (is_inverted[current_seg_initial_ele_pt])
1146  {
1147  current_seg_first_node_pt =
1148  current_seg_initial_ele_pt->node_pt(nnod - 1);
1149  }
1150 
1151  // Get access to the last element on the segment
1152  FiniteElement* current_seg_last_ele_pt =
1153  segment_sorted_ele_pt[is].back();
1154 
1155  // Get the last node of the current segment
1156  Node* current_seg_last_node_pt =
1157  current_seg_last_ele_pt->node_pt(nnod - 1);
1158  if (is_inverted[current_seg_last_ele_pt])
1159  {
1160  current_seg_last_node_pt = current_seg_last_ele_pt->node_pt(0);
1161  }
1162 
1163  // Get the coordinates for the first and last seg node
1164  for (unsigned i = 0; i < 2; i++)
1165  {
1166  current_seg_initial_coord[i] = current_seg_first_node_pt->x(i);
1167  current_seg_final_coord[i] = current_seg_last_node_pt->x(i);
1168  }
1169 
1170  // We have got the initial and final coordinates of the current
1171  // segment, compare those with the initial and final coordinates
1172  // of the original mesh segments to identify which segments is
1173  // which
1174  for (unsigned orig_s = 0; orig_s < nsegments; orig_s++)
1175  {
1176  if (!segment_done[orig_s])
1177  {
1178  // Get the coordinates to compare
1179  Vector<double> initial_coordinate =
1180  original_mesh_segment_initial_coordinate[orig_s];
1181  Vector<double> final_coordinate =
1182  original_mesh_segment_final_coordinate[orig_s];
1183 
1184  // Compute the distance initial(current)-initial(original)
1185  // coordinates
1186  double dist =
1187  ((current_seg_initial_coord[0] - initial_coordinate[0]) *
1188  (current_seg_initial_coord[0] - initial_coordinate[0])) +
1189  ((current_seg_initial_coord[1] - initial_coordinate[1]) *
1190  (current_seg_initial_coord[1] - initial_coordinate[1]));
1191  dist = sqrt(dist);
1192 
1193  // If the initial node is the same, check for the last node
1194  if (dist < ToleranceForVertexMismatchInPolygons::Tolerable_error)
1195  {
1196  // Compute the distance final(current)-final(original)
1197  // coordinates
1198  dist = ((current_seg_final_coord[0] - final_coordinate[0]) *
1199  (current_seg_final_coord[0] - final_coordinate[0])) +
1200  ((current_seg_final_coord[1] - final_coordinate[1]) *
1201  (current_seg_final_coord[1] - final_coordinate[1]));
1202  dist = sqrt(dist);
1203 
1204  // The final node is the same, we have identified the
1205  // segments
1206  if (dist < ToleranceForVertexMismatchInPolygons::Tolerable_error)
1207  {
1208  // Store the index that relates the previous index with the
1209  // current one
1210  current_segment_to_original_segment_index[is] = orig_s;
1211 
1212  // In this case the segment is not inverted
1213  Boundary_segment_inverted[b].push_back(0);
1214 
1215  // Copy the initial and final coordinates for each segment
1216  Boundary_segment_initial_coordinate[b].push_back(
1217  initial_coordinate);
1218  Boundary_segment_final_coordinate[b].push_back(
1219  final_coordinate);
1220 
1221  // Check if the boundary has an associated GeomObject
1222  if (this->boundary_geom_object_pt(b) != 0)
1223  {
1224  // Copy the initial zeta value for the segment
1225  Boundary_segment_initial_zeta[b].push_back(
1226  original_mesh_segment_initial_zeta[orig_s]);
1227  Boundary_segment_final_zeta[b].push_back(
1228  original_mesh_segment_final_zeta[orig_s]);
1229  }
1230  else
1231  {
1232  // Copy the initial and final arclength for each
1233  // segment
1234  Boundary_segment_initial_arclength[b].push_back(
1235  original_mesh_segment_initial_arclength[orig_s]);
1236  Boundary_segment_final_arclength[b].push_back(
1237  original_mesh_segment_final_arclength[orig_s]);
1238  }
1239  // Mark the segment as done
1240  segment_done[orig_s] = true;
1241 #ifdef PARANOID
1242  found_original_segment = true;
1243 #endif
1244  break;
1245  } // The final(current) node matched with the
1246  // final(original) node
1247  } // The initial(current) node matched with the
1248  // initial(original) node
1249  else
1250  {
1251  // Check the inverted case Compute the distance
1252  // initial(current)-final(original) coordinates
1253  double dist_inv =
1254  ((current_seg_initial_coord[0] - final_coordinate[0]) *
1255  (current_seg_initial_coord[0] - final_coordinate[0])) +
1256  ((current_seg_initial_coord[1] - final_coordinate[1]) *
1257  (current_seg_initial_coord[1] - final_coordinate[1]));
1258  dist_inv = sqrt(dist_inv);
1259 
1260  // If the initial node is the same as the final node of
1261  // the segment, check for the last node
1262  if (dist_inv <
1263  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1264  {
1265  // Compute the distance final(current)-initial(original)
1266  // coordinates
1267  dist_inv =
1268  ((current_seg_final_coord[0] - initial_coordinate[0]) *
1269  (current_seg_final_coord[0] - initial_coordinate[0])) +
1270  ((current_seg_final_coord[1] - initial_coordinate[1]) *
1271  (current_seg_final_coord[1] - initial_coordinate[1]));
1272  dist_inv = sqrt(dist_inv);
1273 
1274  // The final node is the same as the initial node, we
1275  // have identified the segments
1276  if (dist_inv <
1277  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1278  {
1279  // Store the index that related the previous index with the
1280  // current one
1281  current_segment_to_original_segment_index[is] = orig_s;
1282 
1283  // In this case the segment is inverted
1284  Boundary_segment_inverted[b].push_back(1);
1285 
1286  // Copy the initial and final coordinates for each segment
1287  Boundary_segment_initial_coordinate[b].push_back(
1288  initial_coordinate);
1289  Boundary_segment_final_coordinate[b].push_back(
1290  final_coordinate);
1291 
1292  // Check that the boudary has an associated GeomObject
1293  if (this->boundary_geom_object_pt(b) != 0)
1294  {
1295  // Copy the initial zeta value for the segments
1296  Boundary_segment_initial_zeta[b].push_back(
1297  original_mesh_segment_initial_zeta[orig_s]);
1298  Boundary_segment_final_zeta[b].push_back(
1299  original_mesh_segment_final_zeta[orig_s]);
1300  }
1301  else
1302  {
1303  // Copy the initial and final arclength for each segment
1304  Boundary_segment_initial_arclength[b].push_back(
1305  original_mesh_segment_initial_arclength[orig_s]);
1306  Boundary_segment_final_arclength[b].push_back(
1307  original_mesh_segment_final_arclength[orig_s]);
1308  }
1309  // Mark the segment as done
1310  segment_done[orig_s] = true;
1311 #ifdef PARANOID
1312  found_original_segment = true;
1313 #endif
1314  break;
1315  } // The final(current) node matched with the
1316  // initial(original) node
1317  } // The initial(current) node matched with the
1318  // final(original) node
1319  } // else (the first(current) node did not matched with the
1320  // first(original) node. Else do the inverted case
1321 
1322  } // (!segment_done[orig_s])
1323 
1324  } // (orig_s < nsegments)
1325 
1326 #ifdef PARANOID
1327  if (!found_original_segment)
1328  {
1329  std::stringstream error_message;
1330  error_message
1331  << "The (" << is << ")-th segment on the current segment was not\n"
1332  << "found when trying to identify it with the original mesh's\n"
1333  << "segment coordinates\n";
1334  throw OomphLibError(error_message.str(),
1335  OOMPH_CURRENT_FUNCTION,
1336  OOMPH_EXCEPTION_LOCATION);
1337  } // if (!found_original_segment)
1338 #endif
1339  } // for (is < nsegments)
1340 
1341  } // if (nsegments > 0)
1342 
1343  // -------------------------------------------------------------------
1344  // Fourth: The original mesh is different from the current mesh
1345  // (this). For boundaries with no geom object associated check if it
1346  // is required to reverse the zeta values. In order to reverse the
1347  // zeta values it is required to previously compute the arclength of
1348  // the segments and store the nodes in a container (set). NOTE that
1349  // the setup_boundary_coordinate() method is not called for
1350  // boundaries with NO GeomObject associated, so this is the LAST
1351  // CHANCE to do it
1352  // -------------------------------------------------------------------
1353  // The original mesh is the same as the current mesh (this). The
1354  // setup_boundary_method() will be called only for the boundaries
1355  // with NO GeomObject associated
1356  // -------------------------------------------------------------------
1357  if (this != original_mesh_pt)
1358  {
1359  // Get the boundary arclength
1360 
1361  // Get the initial and final zeta values for the boundary
1362  // (arclength) from the original mesh
1363  Vector<double> first_node_zeta_coordinate =
1364  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1365  Vector<double> last_node_zeta_coordinate =
1366  original_mesh_pt->boundary_final_zeta_coordinate(b);
1367 
1368  // The boundary arclength is the maximum of the initial and final
1369  // zeta coordinate
1370  const double boundary_arclength =
1371  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
1372 
1373  for (unsigned is = 0; is < nsegments; is++)
1374  {
1375  // Here check if need to invert the elements and the boundary
1376  // coordinates for the segments in a boundary with no GeomObject
1377  // associated
1378  if (boundary_geom_object_pt(b) == 0)
1379  {
1380  // This case only applies for the initial and iterative mesh in
1381  // the adaptation process because the method
1382  // setup_boundary_coordinates() is called by the original mesh
1383  // for boundaries with no GeomObject associated
1384 
1385  // We are goind to check if it is necessary to invert the order
1386  // of the zeta values
1387 
1388  // Get the first and last node of the current segment and their
1389  // zeta values (arclength)
1390 
1391  // There is no need to check for nonhalo elements since the
1392  // container has only nonhalo face elements
1393 
1394  // Get access to the first element on the segment
1395  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
1396 
1397  // Number of nodes
1398  const unsigned nnod = first_ele_pt->nnode();
1399 
1400  // Get the first node of the current segment
1401  Node* first_node_pt = first_ele_pt->node_pt(0);
1402  if (is_inverted[first_ele_pt])
1403  {
1404  first_node_pt = first_ele_pt->node_pt(nnod - 1);
1405  }
1406 
1407  // Get access to the last element on the segment
1408  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
1409 
1410  // Get the last node of the current segment
1411  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
1412  if (is_inverted[last_ele_pt])
1413  {
1414  last_node_pt = last_ele_pt->node_pt(0);
1415  }
1416 
1417  // Get the zeta coordinates for the first and last node
1418  Vector<double> current_segment_initial_arclen(1);
1419  Vector<double> current_segment_final_arclen(1);
1420  // Is the segment in the current mesh (this) inverted?
1421  if (!Boundary_segment_inverted[b][is]) // Not inverted
1422  {
1423  first_node_pt->get_coordinates_on_boundary(
1424  b, current_segment_initial_arclen);
1425  last_node_pt->get_coordinates_on_boundary(
1426  b, current_segment_final_arclen);
1427  }
1428  else // Inverted
1429  {
1430  first_node_pt->get_coordinates_on_boundary(
1431  b, current_segment_final_arclen);
1432  last_node_pt->get_coordinates_on_boundary(
1433  b, current_segment_initial_arclen);
1434  }
1435 
1436  // Once the zeta values have been obtained check if they are set
1437  // in increasing or decreasing order
1438 
1439  // Flag to state that the values in the segment are in increasing
1440  // order
1441  bool increasing_order = false;
1442 
1443  // If the initial zeta value is smaller than the final zeta
1444  // value then they are in increasing order
1445  if (current_segment_initial_arclen[0] <
1446  current_segment_final_arclen[0])
1447  {
1448  increasing_order = true;
1449  }
1450  // If the initial zeta value is greater than the initial zeta
1451  // value then they are in decreasing order
1452  else if (current_segment_initial_arclen[0] >
1453  current_segment_final_arclen[0])
1454  {
1455  increasing_order = false;
1456  }
1457 #ifdef PARANOID
1458  else
1459  {
1460  std::stringstream error_message;
1461  error_message
1462  << "It was not possible to identify if the zeta values on "
1463  << "boundary (" << b << ")\nand segment (" << is
1464  << ") should go in "
1465  << "increasing or decreasing order.\n--- New mesh ---\n"
1466  << "Current segment initial arclength: ("
1467  << current_segment_initial_arclen[0] << ")\n"
1468  << "First node coordinates: (" << first_node_pt->x(0) << ", "
1469  << first_node_pt->x(1) << ")\n"
1470  << "Current segment final arclength: ("
1471  << current_segment_final_arclen[0] << ")\n"
1472  << "Last node coordinates: (" << last_node_pt->x(0) << ", "
1473  << last_node_pt->x(1) << ")\n"
1474  << "Current segment arclength: (" << segment_arclength[is]
1475  << ")\n";
1476  throw OomphLibError(error_message.str(),
1477  OOMPH_CURRENT_FUNCTION,
1478  OOMPH_EXCEPTION_LOCATION);
1479  }
1480 #endif
1481 
1482  // Now get the original initial and final arclengths and check
1483  // if they are in increasing or decreasing order
1484  const unsigned prev_s = current_segment_to_original_segment_index[is];
1485  const double original_segment_initial_arclength =
1486  original_mesh_pt->boundary_segment_initial_arclength(b)[prev_s];
1487  const double original_segment_final_arclength =
1488  original_mesh_pt->boundary_segment_final_arclength(b)[prev_s];
1489 
1490  // Flag to check if the values go in increasing or decreasing
1491  // order in the original mesh segment
1492  bool original_increasing_order = false;
1493 
1494  // Now check if the arclengths on the original mesh go in
1495  // increase or decrease order, this is also used to choose the
1496  // starting value to map the values in the current segment
1497  double starting_arclength = 0.0;
1498  if (original_segment_final_arclength >
1499  original_segment_initial_arclength)
1500  {
1501  // ... in increasing order in the original mesh ...
1502  original_increasing_order = true;
1503  // Select the starting arclength
1504  starting_arclength = original_segment_initial_arclength;
1505  }
1506  else if (original_segment_final_arclength <
1507  original_segment_initial_arclength)
1508  {
1509  // ... in decreasing order in the original mesh ...
1510  original_increasing_order = false;
1511  // Select the starting arclength
1512  starting_arclength = original_segment_final_arclength;
1513  }
1514 #ifdef PARANOID
1515  else
1516  {
1517  std::stringstream error_message;
1518  error_message
1519  << "It was not possible to identify if the zeta values on "
1520  << "boundary (" << b << ")\nand segment (" << is
1521  << ") should go in "
1522  << "increasing or decreasing order.\n--- Original mesh ---\n"
1523  << "Original segment initial arclength: ("
1524  << original_segment_initial_arclength << ")\n"
1525  << "Original segment final arclength: ("
1526  << original_segment_final_arclength << ")\n";
1527  throw OomphLibError(error_message.str(),
1528  OOMPH_CURRENT_FUNCTION,
1529  OOMPH_EXCEPTION_LOCATION);
1530  }
1531 #endif
1532 
1533  // Now scale the zeta values based considering if the zeta
1534  // values from the current mesh (this) go in the same order as
1535  // in the original mesh
1536  if (increasing_order && original_increasing_order)
1537  {
1538  // Current seg
1539  // |------|
1540  // 0 ---- 1
1541  //
1542  // Is mapped to the new values
1543  // |------|
1544  // a ---- b
1545  // a = original_segment_initial_arclength
1546  // b = original_segment_final_arclength
1547  // s = starting_arclength
1548  // The mapping is given by
1549  // new_z = s + z_old * (b - a)
1550 
1551  // Get the nodes associated to the segment
1552  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1553  // Go through all the nodes in the segment an change their
1554  // zeta values
1555  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1556  it != seg_nodes_pt.end();
1557  it++)
1558  {
1559  // Storing for the zeta value
1560  Vector<double> zeta(1);
1561  // Get each node
1562  Node* nod_pt = (*it);
1563  // Get the zeta value of the current node
1564  nod_pt->get_coordinates_on_boundary(b, zeta);
1565  // ... and re-assign it
1566  const double temp =
1567  starting_arclength + (zeta[0] * segment_arclength[is]);
1568  // The zeta value
1569  zeta[0] = temp / boundary_arclength;
1570  // Correct
1571  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1572  {
1573  zeta[0] = 1.0;
1574  }
1575  else if (std::fabs(zeta[0]) < 1.0e-14)
1576  {
1577  zeta[0] = 0.0;
1578  }
1579 
1580  // Set the new value
1581  nod_pt->set_coordinates_on_boundary(b, zeta);
1582  } // Go through all the nodes
1583  } // if (increasing_order && original_increasing_order)
1584  else if (!increasing_order && original_increasing_order)
1585  {
1586  // Current seg
1587  // |------|
1588  // 1 ---- 0
1589  //
1590  // Is mapped to the new values
1591  // |------|
1592  // a ---- b
1593  // a = original_segment_initial_arclength
1594  // b = original_segment_final_arclength
1595  // s = starting_arclength
1596  // The mapping is given by
1597  // new_z = s + (1.0 - z_old) * (b - a)
1598 
1599  // Get the nodes associated to the segment
1600  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1601  // Go through all the nodes in the segment an change their
1602  // zeta values
1603  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1604  it != seg_nodes_pt.end();
1605  it++)
1606  {
1607  // Storing for the zeta value
1608  Vector<double> zeta(1);
1609  // Get each node
1610  Node* nod_pt = (*it);
1611  // Get the zeta value of the current node
1612  nod_pt->get_coordinates_on_boundary(b, zeta);
1613  // ... and re-assign it
1614  const double temp =
1615  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1616  // The zeta value
1617  zeta[0] = temp / boundary_arclength;
1618  // Correct
1619  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1620  {
1621  zeta[0] = 1.0;
1622  }
1623  else if (std::fabs(zeta[0]) < 1.0e-14)
1624  {
1625  zeta[0] = 0.0;
1626  }
1627  // Set the new value
1628  nod_pt->set_coordinates_on_boundary(b, zeta);
1629  } // Go through all the nodes
1630  } // else if (!increasing_order && original_increasing_order)
1631  else if (increasing_order && !original_increasing_order)
1632  {
1633  // Current seg
1634  // |------|
1635  // 0 ---- 1
1636  //
1637  // Is mapped to the new values
1638  // |------|
1639  // b ---- a
1640  // a = original_segment_initial_arclength
1641  // b = original_segment_final_arclength
1642  // s = starting_arclength
1643  // The mapping is given by
1644  // new_z = s + (1.0 - z_old) * |(b - a)|
1645 
1646  // Get the nodes associated to the segment
1647  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1648  // Go through all the nodes in the segment an change their
1649  // zeta values
1650  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1651  it != seg_nodes_pt.end();
1652  it++)
1653  {
1654  // Storing for the zeta value
1655  Vector<double> zeta(1);
1656  // Get each node
1657  Node* nod_pt = (*it);
1658  // Get the zeta value of the current node
1659  nod_pt->get_coordinates_on_boundary(b, zeta);
1660  // ... and re-assign it
1661  const double temp =
1662  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1663  // The zeta value
1664  zeta[0] = temp / boundary_arclength;
1665  // Correct
1666  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1667  {
1668  zeta[0] = 1.0;
1669  }
1670  else if (std::fabs(zeta[0]) < 1.0e-14)
1671  {
1672  zeta[0] = 0.0;
1673  }
1674  // Set the new value
1675  nod_pt->set_coordinates_on_boundary(b, zeta);
1676  } // Go through all the nodes
1677  } // else if (increasing_order && !original_increasing_order)
1678  else if (!increasing_order && !original_increasing_order)
1679  {
1680  // Current seg
1681  // |------|
1682  // 0 ---- 1
1683  //
1684  // Is mapped to the new values
1685  // |------|
1686  // a ---- b
1687  // a = original_segment_initial_arclength
1688  // b = original_segment_final_arclength
1689  // s = starting_arclength
1690  // The mapping is given by
1691  // new_z = s + z_old * |(b - a)|
1692 
1693  // Get the nodes associated to the segment
1694  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1695  // Go through all the nodes in the segment an change their
1696  // zeta values
1697  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1698  it != seg_nodes_pt.end();
1699  it++)
1700  {
1701  // Storing for the zeta value
1702  Vector<double> zeta(1);
1703  // Get each node
1704  Node* nod_pt = (*it);
1705  // Get the zeta value of the current node
1706  nod_pt->get_coordinates_on_boundary(b, zeta);
1707  // ... and re-assign it
1708  const double temp =
1709  starting_arclength + (zeta[0] * segment_arclength[is]);
1710  // The zeta value
1711  zeta[0] = temp / boundary_arclength;
1712  // Correct
1713  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1714  {
1715  zeta[0] = 1.0;
1716  }
1717  else if (std::fabs(zeta[0]) < 1.0e-14)
1718  {
1719  zeta[0] = 0.0;
1720  }
1721  // Set the new value
1722  nod_pt->set_coordinates_on_boundary(b, zeta);
1723  } // Go through all the nodes
1724  } // else if (!increasing_order && !original_increasing_order)
1725 
1726 #ifdef PARANOID
1727  // Verify that the z values of the first and last node are not
1728  // out of the range [0,1]
1729  for (std::list<FiniteElement*>::iterator it_list =
1730  segment_sorted_ele_pt[is].begin();
1731  it_list != segment_sorted_ele_pt[is].end();
1732  it_list++)
1733  {
1734  // Number of nodes in the segment
1735  const unsigned nnod = (*it_list)->nnode();
1736 
1737  // Get the first node of the current segment
1738  Node* first_node_pt = (*it_list)->node_pt(0);
1739  if (is_inverted[(*it_list)])
1740  {
1741  first_node_pt = (*it_list)->node_pt(nnod - 1);
1742  }
1743 
1744  // Get the last node of the current segment
1745  Node* last_node_pt = (*it_list)->node_pt(nnod - 1);
1746  if (is_inverted[(*it_list)])
1747  {
1748  last_node_pt = (*it_list)->node_pt(0);
1749  }
1750 
1751  // The z value for the first node
1752  Vector<double> zeta(1);
1753  first_node_pt->get_coordinates_on_boundary(b, zeta);
1754  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1755  {
1756  std::ostringstream error_message;
1757  error_message
1758  << "The boundary coordinate of the first node on boundary ("
1759  << b << ")\nand segment (" << is << ") is out of the "
1760  << "allowed values [0,1]\n"
1761  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1762  << "The vertex coordinates are: (" << first_node_pt->x(0)
1763  << ", " << first_node_pt->x(1) << ")\n";
1764  throw OomphLibError(error_message.str(),
1765  OOMPH_CURRENT_FUNCTION,
1766  OOMPH_EXCEPTION_LOCATION);
1767  }
1768 
1769  // The z value for the last node
1770  last_node_pt->get_coordinates_on_boundary(b, zeta);
1771  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1772  {
1773  std::ostringstream error_message;
1774  error_message
1775  << "The boundary coordinate of the last node on boundary (" << b
1776  << ")\nand segment (" << is << ") is out of the "
1777  << "allowed values [0,1]\n"
1778  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1779  << "The vertex coordinates are: (" << last_node_pt->x(0) << ", "
1780  << last_node_pt->x(1) << ")\n";
1781  throw OomphLibError(error_message.str(),
1782  OOMPH_CURRENT_FUNCTION,
1783  OOMPH_EXCEPTION_LOCATION);
1784  }
1785  }
1786 #endif // #ifdef PARANOID
1787 
1788  } // if (boundary_geom_object_pt(b)==0)
1789 
1790  } // for (is < nsegments)
1791 
1792  } // if (this != original_mesh_pt)
1793 
1794  // ------------------------------------------------------------------
1795  // Copy the corrected (possible reversed) info. to the containers of
1796  // the current mesh
1797  // ------------------------------------------------------------------
1798  // Check if there are segments of b boundary in this processor
1799  if (nsegments > 0)
1800  {
1801  // Copy the initial and final coordinates
1802  Boundary_initial_coordinate[b] =
1803  original_mesh_pt->boundary_initial_coordinate(b);
1804 
1805  Boundary_final_coordinate[b] =
1806  original_mesh_pt->boundary_final_coordinate(b);
1807 
1808  // The initial and final zeta coordinates (In case of a geometric
1809  // object those are the limits of the geom object)
1810  Boundary_initial_zeta_coordinate[b] =
1811  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1812 
1813  Boundary_final_zeta_coordinate[b] =
1814  original_mesh_pt->boundary_final_zeta_coordinate(b);
1815 
1816  } // if (nsegments > 0)
1817 
1818  // Set the flag to indicate that the zeta values have been assigned
1819  // for the current boundary
1820  Assigned_segments_initial_zeta_values[b] = true;
1821 
1822  // Clean all the created face elements
1823  for (unsigned i = 0; i < nele; i++)
1824  {
1825  delete face_el_pt[i];
1826  face_el_pt[i] = 0;
1827  }
1828  }
1829 
1830  //======================================================================
1831  /// Compute the boundary segments connectivity for those
1832  /// boundaries that were splited during the distribution process
1833  /// and also the initial zeta values for each segment (the initial
1834  /// and final boundary nodes coordinates)
1835  //======================================================================
1836  template<class ELEMENT>
1839  const unsigned& b)
1840  {
1841  // ------------------------------------------------------------------
1842  // First: Get the face elements associated with the current boundary
1843  // ------------------------------------------------------------------
1844 
1845  // Get the communicator of the mesh
1846  OomphCommunicator* comm_pt = this->communicator_pt();
1847 
1848  // Get the number of processors
1849  const unsigned nproc = comm_pt->nproc();
1850  // Get the rank of the current processor
1851  const unsigned my_rank = comm_pt->my_rank();
1852 
1853  // Temporary storage for face elements
1854  Vector<FiniteElement*> all_face_ele_pt;
1855 
1856  // Flag to know whether we are working with an internal open curve
1857  // and then re-assign the initial and final zeta coordinates for
1858  // each segment (only used when the mesh is distributed)
1859  bool is_internal_boundary = false;
1860 
1861  // map to associate the face element to the bulk element, necessary
1862  // to attach halo face elements at both sides of each found segment
1863  std::map<FiniteElement*, FiniteElement*> face_to_bulk_element_pt;
1864 
1865  // Select the boundary face elements, using the criteria of highest
1866  // processor in charge and bottom-left element
1867  select_boundary_face_elements(
1868  all_face_ele_pt, b, is_internal_boundary, face_to_bulk_element_pt);
1869 
1870  // Get the number of face elements
1871  const unsigned n_all_face_ele = all_face_ele_pt.size();
1872 
1873  // ----------------------------------------------------------------
1874  // Second: Sort the face elements, only consider nonhalo elements
1875  // ----------------------------------------------------------------
1876 
1877  // A flag vector to mark those face elements that are considered as
1878  // halo in the current processor
1879  std::vector<bool> is_halo_face_element(n_all_face_ele, false);
1880 
1881  // Count the total number of non halo face elements
1882  unsigned nnon_halo_face_elements = 0;
1883 
1884  // Only mark the face elements as halo if the mesh is marked as
1885  // distributed
1886  for (unsigned ie = 0; ie < n_all_face_ele; ie++)
1887  {
1888  FiniteElement* face_ele_pt = all_face_ele_pt[ie];
1889  // Get the bulk element
1890  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
1891  // Check if the bulk element is halo
1892  if (!tmp_bulk_ele_pt->is_halo())
1893  {
1894  // Set the flag for non halo element
1895  is_halo_face_element[ie] = false;
1896  // Increase the non halo elements counter
1897  nnon_halo_face_elements++;
1898  }
1899  else
1900  {
1901  // Mark the face element as halo
1902  is_halo_face_element[ie] = true;
1903  }
1904 
1905  } // for (ie < n_ele)
1906 
1907  // Get the total number of halo face elements
1908  const unsigned nhalo_face_element =
1909  n_all_face_ele - nnon_halo_face_elements;
1910 
1911  // The vector of list to store the "segments" that compound the
1912  // boundary (segments may appear only in a distributed mesh)
1913  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
1914 
1915  // Number of already sorted face elements (only nonhalo elements for
1916  // a distributed mesh)
1917  unsigned nsorted_face_elements = 0;
1918 
1919  // Keep track of who's done (this apply to nonhalo only, remember we
1920  // are only working with halo elements)
1921  std::map<FiniteElement*, bool> done_el;
1922 
1923  // Keep track of which element is inverted (in distributed mesh the
1924  // elements may be inverted with respect to the segment they belong)
1925  std::map<FiniteElement*, bool> is_inverted;
1926 
1927  // Iterate until all possible segments have been created
1928  while (nsorted_face_elements < nnon_halo_face_elements)
1929  {
1930  // The ordered list of face elements (in a distributed mesh a
1931  // collection of contiguous face elements define a segment)
1932  std::list<FiniteElement*> sorted_el_pt;
1933  sorted_el_pt.clear();
1934 
1935 #ifdef PARANOID
1936  // Select an initial element for the segment (the first not done
1937  // nonhalo element)
1938  bool found_initial_face_element = false;
1939 #endif
1940 
1941  FiniteElement* ele_face_pt = 0;
1942 
1943  unsigned iface = 0;
1944  for (iface = 0; iface < n_all_face_ele; iface++)
1945  {
1946  if (!is_halo_face_element[iface])
1947  {
1948  ele_face_pt = all_face_ele_pt[iface];
1949  // If not done then take it as initial face element
1950  if (!done_el[ele_face_pt])
1951  {
1952 #ifdef PARANOID
1953  found_initial_face_element = true;
1954 #endif
1955  nsorted_face_elements++;
1956  iface++; // The next element number
1957  sorted_el_pt.push_back(ele_face_pt);
1958  // Mark as done
1959  done_el[ele_face_pt] = true;
1960  break;
1961  }
1962  }
1963  } // for (iface < nele)
1964 
1965 #ifdef PARANOID
1966  if (!found_initial_face_element)
1967  {
1968  std::ostringstream error_message;
1969  error_message
1970  << "Could not find an initial face element for the current segment\n";
1971  // << "----- Possible memory leak -----\n";
1972  throw OomphLibError(error_message.str(),
1973  OOMPH_CURRENT_FUNCTION,
1974  OOMPH_EXCEPTION_LOCATION);
1975  }
1976 #endif
1977 
1978  // Number of nodes
1979  const unsigned nnod = ele_face_pt->nnode();
1980 
1981  // Left and rightmost nodes (the left and right nodes of the
1982  // current face element)
1983  Node* left_node_pt = ele_face_pt->node_pt(0);
1984  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
1985 
1986  // Continue iterating if a new face element has been added to the
1987  // list
1988  bool face_element_added = false;
1989 
1990  // While a new face element has been added to the set of sorted
1991  // face elements then re-iterate
1992  do
1993  {
1994  // Start from the next face element since we have already added
1995  // the previous one as the initial face element (any previous
1996  // face element had to be added on previous iterations)
1997  for (unsigned iiface = iface; iiface < n_all_face_ele; iiface++)
1998  {
1999  // Re-start flag
2000  face_element_added = false;
2001 
2002  // Get the candidate element
2003  ele_face_pt = all_face_ele_pt[iiface];
2004 
2005  // Check that the candidate element has not been done and is
2006  // not a halo element
2007  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2008  {
2009  // Get the left and right nodes of the current element
2010  Node* local_left_node_pt = ele_face_pt->node_pt(0);
2011  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
2012 
2013  // New element fits at the left of segment and is not inverted
2014  if (left_node_pt == local_right_node_pt)
2015  {
2016  left_node_pt = local_left_node_pt;
2017  sorted_el_pt.push_front(ele_face_pt);
2018  is_inverted[ele_face_pt] = false;
2019  face_element_added = true;
2020  }
2021  // New element fits at the left of segment and is inverted
2022  else if (left_node_pt == local_left_node_pt)
2023  {
2024  left_node_pt = local_right_node_pt;
2025  sorted_el_pt.push_front(ele_face_pt);
2026  is_inverted[ele_face_pt] = true;
2027  face_element_added = true;
2028  }
2029  // New element fits on the right of segment and is not inverted
2030  else if (right_node_pt == local_left_node_pt)
2031  {
2032  right_node_pt = local_right_node_pt;
2033  sorted_el_pt.push_back(ele_face_pt);
2034  is_inverted[ele_face_pt] = false;
2035  face_element_added = true;
2036  }
2037  // New element fits on the right of segment and is inverted
2038  else if (right_node_pt == local_right_node_pt)
2039  {
2040  right_node_pt = local_left_node_pt;
2041  sorted_el_pt.push_back(ele_face_pt);
2042  is_inverted[ele_face_pt] = true;
2043  face_element_added = true;
2044  }
2045 
2046  if (face_element_added)
2047  {
2048  done_el[ele_face_pt] = true;
2049  nsorted_face_elements++;
2050  break;
2051  }
2052 
2053  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2054  } // for (iiface<nnon_halo_face_element)
2055  } while (face_element_added &&
2056  (nsorted_face_elements < nnon_halo_face_elements));
2057 
2058  // Store the created segment in the vector of segments
2059  segment_sorted_ele_pt.push_back(sorted_el_pt);
2060 
2061  } // while(nsorted_face_elements < nnon_halo_face_elements);
2062 
2063  // -----------------------------------------------------------------
2064  // Third: We have the face elements sorted (in segments), now assign
2065  // boundary coordinates to the nodes in the segments, this is the
2066  // LOCAL boundary coordinate and further communication is needed to
2067  // compute the GLOBAL boundary coordinates
2068  // -----------------------------------------------------------------
2069 
2070  // Vector of sets that stores the nodes of each segment based on a
2071  // lexicographically order starting from the bottom left node of
2072  // each segment
2073  Vector<std::set<Node*>> segment_all_nodes_pt;
2074 
2075  // The number of segments in this processor
2076  const unsigned nsegments = segment_sorted_ele_pt.size();
2077  // DEBP(nsegments);
2078 
2079 #ifdef PARANOID
2080  if (nnon_halo_face_elements > 0 && nsegments == 0)
2081  {
2082  std::ostringstream error_message;
2083  error_message
2084  << "The number of segments is zero, but the number of nonhalo\n"
2085  << "elements is: (" << nnon_halo_face_elements << ")\n";
2086  throw OomphLibError(
2087  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2088  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
2089 #endif
2090 
2091  // The arclength of each segment in the current processor
2092  Vector<double> segment_arclength(nsegments);
2093 
2094  // The number of vertices of each segment
2095  Vector<unsigned> nvertices_per_segment(nsegments);
2096 
2097  // The initial zeta for the segment
2098  Vector<double> initial_zeta_segment(nsegments);
2099 
2100  // The final zeta for the segment
2101  Vector<double> final_zeta_segment(nsegments);
2102 
2103  // Go through all the segments and compute its ARCLENGTH (if the
2104  // boundary has a GeomObject associated then assign the initial and
2105  // final zeta values for the segment)
2106  for (unsigned is = 0; is < nsegments; is++)
2107  {
2108 #ifdef PARANOID
2109  if (segment_sorted_ele_pt[is].size() == 0)
2110  {
2111  std::ostringstream error_message;
2112  error_message << "The (" << is << ")-th segment has no elements\n";
2113  throw OomphLibError(error_message.str(),
2114  OOMPH_CURRENT_FUNCTION,
2115  OOMPH_EXCEPTION_LOCATION);
2116  } // if (segment_sorted_ele_pt[is].size() == 0)
2117 #endif
2118 
2119  // Get access to the first element on the segment
2120  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2121 
2122  // Number of nodes
2123  const unsigned nnod = first_ele_pt->nnode();
2124 
2125  // Get the first node of the current segment
2126  Node* first_node_pt = first_ele_pt->node_pt(0);
2127  if (is_inverted[first_ele_pt])
2128  {
2129  first_node_pt = first_ele_pt->node_pt(nnod - 1);
2130  }
2131 
2132  // Coordinates of left node
2133  double x_left = first_node_pt->x(0);
2134  double y_left = first_node_pt->x(1);
2135 
2136  // Initialise boundary coordinate (local boundary coordinate for
2137  // boundaries with more than one segment)
2138  Vector<double> zeta(1, 0.0);
2139 
2140  // If we have associated a GeomObject then it is not necessary to
2141  // compute the arclength, only read the values from the nodes at
2142  // the edges and set the initial and final zeta segment values
2143  if (this->boundary_geom_object_pt(b) != 0)
2144  {
2145  // Get the initial node coordinate
2146  first_node_pt->get_coordinates_on_boundary(b, zeta);
2147  // Set the initial zeta segment value
2148  initial_zeta_segment[is] = zeta[0];
2149 
2150  // Get access to the last element on the segment
2151  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2152 
2153  // Get the last node of the current segment
2154  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
2155  if (is_inverted[last_ele_pt])
2156  {
2157  last_node_pt = last_ele_pt->node_pt(0);
2158  }
2159 
2160  // Get the final node coordinate
2161  last_node_pt->get_coordinates_on_boundary(b, zeta);
2162  // Set the final zeta segment value
2163  final_zeta_segment[is] = zeta[0];
2164  }
2165 
2166  // Sort the nodes in the segment (lexicographically bottom left
2167  // node)
2168  std::set<Node*> local_nodes_pt;
2169  // Insert the first node
2170  local_nodes_pt.insert(first_node_pt);
2171 
2172  // Now loop over nodes in order and increase the ARCLENGTH
2173  for (std::list<FiniteElement*>::iterator it =
2174  segment_sorted_ele_pt[is].begin();
2175  it != segment_sorted_ele_pt[is].end();
2176  it++)
2177  {
2178  // Get the pointer to the element
2179  FiniteElement* el_pt = (*it);
2180 
2181  // Start node and increment
2182  unsigned k_nod = 1;
2183  int nod_diff = 1;
2184  // Access nodes in reverse?
2185  if (is_inverted[el_pt])
2186  {
2187  k_nod = nnod - 2;
2188  nod_diff = -1;
2189  }
2190 
2191  // Loop over nodes in the face element
2192  for (unsigned j = 1; j < nnod; j++)
2193  {
2194  Node* nod_pt = el_pt->node_pt(k_nod);
2195  k_nod += nod_diff;
2196 
2197  // Coordinates of right node
2198  double x_right = nod_pt->x(0);
2199  double y_right = nod_pt->x(1);
2200 
2201  // Increment boundary coordinate (the arclength)
2202  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
2203  (y_right - y_left) * (y_right - y_left));
2204 
2205  // When we have a GeomObject associated to the boundary we already
2206  // know the zeta values for the nodes, there is no need to compute
2207  // the arclength
2208  // if (this->boundary_geom_object_pt(b)==0)
2209  // {
2210  // // Set boundary coordinate
2211  // // nod_pt->set_coordinates_on_boundary(b, zeta);
2212  // }
2213 
2214  // Increment reference coordinate
2215  x_left = x_right;
2216  y_left = y_right;
2217 
2218  // Get lexicographically bottom left node but only
2219  // use vertex nodes as candidates
2220  local_nodes_pt.insert(nod_pt);
2221 
2222  } // for (j < nnod)
2223 
2224  } // iterator over the elements in the segment
2225 
2226  // Info. to be passed to other processors
2227  // The initial arclength for the segment that goes after this depends
2228  // on the current segment arclength
2229  segment_arclength[is] = zeta[0];
2230 
2231  // Info. to be passed to the other processors
2232  // The initial vertex number for the segment that goes after this
2233  // depends on the current segment vertices number
2234  nvertices_per_segment[is] = local_nodes_pt.size();
2235 
2236  // Add the nodes for the corresponding segment in the container
2237  segment_all_nodes_pt.push_back(local_nodes_pt);
2238 
2239  // The attaching of the halo elements at both sides of the segments is
2240  // performed only if segments connectivity needs to be computed
2241 
2242  } // for (is < nsegments)
2243 
2244  // Container to store the number of vertices before each segment,
2245  // initialise to zero in case we have a non distributed boundary
2246  Vector<unsigned> nvertices_before_segment(nsegments, 0);
2247 
2248  // Store the initial arclength for each segment of boundary in the
2249  // current processor, initalise to zero in case we have a non
2250  // distributed boundary
2251  Vector<double> initial_segment_arclength(nsegments, 0.0);
2252 
2253  // Info. to be passed to other processors
2254  // If the boundary is distributed we need to know which processors does
2255  // have the initial and final segments, this helps to get the first and
2256  // last nodes coordinates (info. used to scale the bound coordinates)
2257 
2258  // Processors with the initial and final segment
2259  unsigned proc_with_initial_seg = 0;
2260  unsigned proc_with_final_seg = 0;
2261 
2262  // ... and the index of those segments (only of interest in the
2263  // processors that have the initial and final segments)
2264  unsigned initial_segment = 0;
2265  unsigned final_segment = 0;
2266 
2267  // Each segment needs to know whether it has to be inverted or not
2268  // Store whether a segment needs to be inverted or not
2269  Vector<unsigned> segment_inverted(nsegments);
2270 
2271  // Before attaching the halo elements create a copy of the data
2272  // structure without halo elements
2273  Vector<std::list<FiniteElement*>> segment_sorted_nonhalo_ele_pt(nsegments);
2274  for (unsigned is = 0; is < nsegments; is++)
2275  {
2276  for (std::list<FiniteElement*>::iterator it_seg =
2277  segment_sorted_ele_pt[is].begin();
2278  it_seg != segment_sorted_ele_pt[is].end();
2279  it_seg++)
2280  {
2281  segment_sorted_nonhalo_ele_pt[is].push_back((*it_seg));
2282  }
2283 
2284  } // for (is < nsegments)
2285 
2286  // --------------------------------------------------------------
2287  // Attach the halo elements at both sides of the segments
2288  for (unsigned is = 0; is < nsegments; is++)
2289  {
2290  // Get access to the first element on the segment
2291  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2292 
2293  // Number of nodes
2294  const unsigned nnod = first_ele_pt->nnode();
2295 
2296  // Get the first node of the current segment
2297  Node* first_node_pt = first_ele_pt->node_pt(0);
2298  if (is_inverted[first_ele_pt])
2299  {
2300  first_node_pt = first_ele_pt->node_pt(nnod - 1);
2301  }
2302 
2303  // Get access to the last element on the segment
2304  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2305 
2306  // Get the last node of the current segment
2307  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
2308  if (is_inverted[last_ele_pt])
2309  {
2310  last_node_pt = last_ele_pt->node_pt(0);
2311  }
2312 
2313  // -----------------------------------------------------------------
2314  // Fourth: Now attach the halo elements to the left and right side
2315  // of each segment
2316  // -----------------------------------------------------------------
2317  bool attached_left_halo = false;
2318  bool attached_right_halo = false;
2319  if (nhalo_face_element > 0)
2320  {
2321  for (unsigned iiface = 0; iiface < n_all_face_ele; iiface++)
2322  {
2323  // Get the candidate element
2324  FiniteElement* halo_face_ele_pt = all_face_ele_pt[iiface];
2325 
2326  // Check that the element is a halo face element, we do not check
2327  // if the element has been already done since the halo elements
2328  // may be connected to more than one segment (2 at most), to the
2329  // left and right of different segments
2330  //
2331  // Segment k Halo Segment r
2332  // |---|---|---| |xxx| |---|---|---|
2333  //
2334  // Segment k Halo Segment r
2335  // |---|---|---|xxx|---|---|---|
2336  //
2337  if (is_halo_face_element[iiface])
2338  {
2339  // Get its left and right nodes
2340  Node* left_node_pt = halo_face_ele_pt->node_pt(0);
2341  Node* right_node_pt = halo_face_ele_pt->node_pt(nnod - 1);
2342  // The halo element fits to the left of segment
2343  if (!attached_left_halo && (first_node_pt == right_node_pt ||
2344  first_node_pt == left_node_pt))
2345  {
2346  // Add the halo element to the left of the segment
2347  segment_sorted_ele_pt[is].push_front(halo_face_ele_pt);
2348 
2349  // Once a halo face element has been added to the left
2350  // mark as found halo to the left
2351  attached_left_halo = true;
2352  }
2353  // The halo element fits to the right of the segment
2354  else if (!attached_right_halo && (last_node_pt == left_node_pt ||
2355  last_node_pt == right_node_pt))
2356  {
2357  // Add the halo element to the right of the segment
2358  segment_sorted_ele_pt[is].push_back(halo_face_ele_pt);
2359  // Once a halo face element has been added to the right
2360  // mark as found halo to the right
2361  attached_right_halo = true;
2362  }
2363  // If we have already found elements to left and right then
2364  // break the loop
2365  if (attached_left_halo && attached_right_halo)
2366  {
2367  break;
2368  }
2369 
2370  } // if (is_halo_face_element[iiface])
2371 
2372  } // for (iiface < nel)
2373 
2374  } // if (nhalo_face_element > 0)
2375 
2376  } // for (is < nsegments)
2377 
2378  // The segments now have local coordinates assigned and halo
2379  // elements attached to them. Store that info. in the corresponding
2380  // data structures and be ready to send that info. to a root
2381  // processor. The root processor will be in charge of computing the
2382  // boundary coordinates for each segment of the boundary.
2383 
2384  // For each segment store the following information
2385  // --------------------------------------------------------------------
2386  // Stores the "rank" of the processor to the left of each segment,
2387  // zero if there is no processor to the left which states that the
2388  // segment is the first one on the boundary
2389  Vector<unsigned> left_processor_plus_one(nsegments);
2390 
2391  // Stores the "rank" of the processor to the right of each segment,
2392  // zero if there is no processor to the right which states that the
2393  // segment is the last one on the boundary
2394  Vector<unsigned> right_processor_plus_one(nsegments);
2395 
2396  // The id. of the halo element to the left of the segment, note that
2397  // this info. is not necessary if there is no processor to the left
2398  // of the segment
2399  Vector<unsigned> left_halo_element(nsegments);
2400 
2401  // The id. of the halo element to the right of the segment, note that
2402  // this info. is not necessary if there is no processor to the right
2403  // of the segment
2404  Vector<unsigned> right_halo_element(nsegments);
2405 
2406  // The id. of the haloed element to the left of the segment, note that
2407  // this info. is not necessary if there is no processor to the left
2408  // of the segment
2409  Vector<unsigned> left_haloed_element(nsegments);
2410 
2411  // The id. of the haloed element to the right of the segment, note
2412  // that this info. is not necessary if there is no processor to the
2413  // right of the segment
2414  Vector<unsigned> right_haloed_element(nsegments);
2415 
2416  // Go through all the segments and get the info.
2417  for (unsigned is = 0; is < nsegments; is++)
2418  {
2419  // Get access to the left most face element on the segment
2420  FiniteElement* left_face_ele_pt = segment_sorted_ele_pt[is].front();
2421 
2422  // Get the corresponding bulk element and check whether it is a halo
2423  // element or not
2424  FiniteElement* tmp_left_bulk_ele_pt =
2425  face_to_bulk_element_pt[left_face_ele_pt];
2426 
2427  // Check if the bulk element is halo
2428  if (tmp_left_bulk_ele_pt->is_halo())
2429  {
2430  // Then store the corresponding info.
2431  int left_proc = tmp_left_bulk_ele_pt->non_halo_proc_ID();
2432 #ifdef PARANOID
2433  if (left_proc < 0)
2434  {
2435  std::ostringstream error_message;
2436  error_message
2437  << "The current bulk element (left) is marked as halo but "
2438  << "the processor holding\nthe non-halo counterpart is "
2439  << "negative!\n";
2440  throw OomphLibError(error_message.str(),
2441  OOMPH_CURRENT_FUNCTION,
2442  OOMPH_EXCEPTION_LOCATION);
2443  }
2444 #endif
2445  // The processor "rank" to the left
2446  unsigned left_processor = static_cast<unsigned>(left_proc);
2447  left_processor_plus_one[is] = left_processor + 1;
2448 
2449  // Now get the id of the halo element to the left
2450  GeneralisedElement* left_element_pt = tmp_left_bulk_ele_pt;
2451 
2452  // Get the halo elements with left processor
2453  Vector<GeneralisedElement*> left_halo_element_pt =
2454  this->halo_element_pt(left_processor);
2455 
2456 #ifdef PARANOID
2457  // Flag to state that the halo element was found
2458  bool left_halo_element_found = false;
2459 #endif
2460 
2461  const unsigned n_halo_left = left_halo_element_pt.size();
2462  for (unsigned lh = 0; lh < n_halo_left; lh++)
2463  {
2464  if (left_element_pt == left_halo_element_pt[lh])
2465  {
2466  left_halo_element[is] = lh;
2467 #ifdef PARANOID
2468  left_halo_element_found = true;
2469 #endif
2470  break;
2471  }
2472  } // for (lh < n_halo_left)
2473 
2474 #ifdef PARANOID
2475  if (!left_halo_element_found)
2476  {
2477  std::ostringstream error_message;
2478  error_message
2479  << "The current bulk element (left) marked as halo was "
2480  << "not found in the vector of halo\nelements associated "
2481  << "with the (" << left_processor << ") processor.\n\n";
2482  throw OomphLibError(error_message.str(),
2483  OOMPH_CURRENT_FUNCTION,
2484  OOMPH_EXCEPTION_LOCATION);
2485  } // if (!left_halo_element_found)
2486 #endif
2487 
2488  // Get the left-most nonhalo element (use the backup list of
2489  // nonhalo elements)
2490  left_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].front();
2491 
2492  // Get the corresponding bulk element
2493  tmp_left_bulk_ele_pt = face_to_bulk_element_pt[left_face_ele_pt];
2494 
2495 #ifdef PARANOID
2496  // This element should not be marked as halo
2497  if (tmp_left_bulk_ele_pt->is_halo())
2498  {
2499  std::ostringstream error_message;
2500  error_message
2501  << "The bulk element represetation of the left-most nonhalo face\n"
2502  << "element of the current segment (" << is
2503  << ") is marked as halo,\n"
2504  << "but the face element created from it is nonhalo\n";
2505  throw OomphLibError(error_message.str(),
2506  OOMPH_CURRENT_FUNCTION,
2507  OOMPH_EXCEPTION_LOCATION);
2508  } // if (tmp_left_bulk_ele_pt->is_halo())
2509 #endif
2510 
2511  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2512  // to search in the haloed vector
2513  left_element_pt = tmp_left_bulk_ele_pt;
2514 
2515 #ifdef PARANOID
2516  // Flag to state that the haloed element was found
2517  bool left_haloed_element_found = false;
2518 #endif
2519 
2520  // Now get the id for the haloed element to the left, get the
2521  // haloed elements from the processor to the left
2522  Vector<GeneralisedElement*> left_haloed_element_pt =
2523  this->haloed_element_pt(left_processor);
2524 
2525  const unsigned nhaloed_left = left_haloed_element_pt.size();
2526  for (unsigned lhd = 0; lhd < nhaloed_left; lhd++)
2527  {
2528  if (left_element_pt == left_haloed_element_pt[lhd])
2529  {
2530  left_haloed_element[is] = lhd;
2531 #ifdef PARANOID
2532  left_haloed_element_found = true;
2533 #endif
2534  break;
2535  }
2536  } // for (lhd < nhaloed_left)
2537 
2538 #ifdef PARANOID
2539  if (!left_haloed_element_found)
2540  {
2541  std::ostringstream error_message;
2542  error_message
2543  << "The current bulk element (left) marked as haloed was "
2544  << "not found in the vector of haloed\nelements associated "
2545  << "with processor (" << left_processor << ").\n";
2546  throw OomphLibError(error_message.str(),
2547  OOMPH_CURRENT_FUNCTION,
2548  OOMPH_EXCEPTION_LOCATION);
2549  }
2550 #endif
2551  } // if (tmp_left_bulk_ele_pt->is_halo())
2552  else
2553  {
2554  // If not halo then state the info. to indicate that
2555  left_processor_plus_one[is] = 0;
2556  // Null this info.
2557  left_halo_element[is] = 0;
2558  // Null this info.
2559  left_haloed_element[is] = 0;
2560  }
2561 
2562  // Get access to the right most face element on the segment
2563  FiniteElement* right_face_ele_pt = segment_sorted_ele_pt[is].back();
2564 
2565  // Get the corresponding bulk element and check whether it is
2566  // a halo element or not
2567  FiniteElement* tmp_right_bulk_ele_pt =
2568  face_to_bulk_element_pt[right_face_ele_pt];
2569 
2570  // Check if the bulk element is halo
2571  if (tmp_right_bulk_ele_pt->is_halo())
2572  {
2573  // Then store the corresponding info.
2574  int right_proc = tmp_right_bulk_ele_pt->non_halo_proc_ID();
2575 #ifdef PARANOID
2576  if (right_proc < 0)
2577  {
2578  std::ostringstream error_message;
2579  error_message
2580  << "The current bulk element (right) is marked as halo but "
2581  << "the processor holding\nthe non-halo counterpart is "
2582  << "negative!\n";
2583  throw OomphLibError(error_message.str(),
2584  "TriangleMesh::compute_boundary_segments_"
2585  "connectivity_and_initial_zeta_values()",
2586  OOMPH_EXCEPTION_LOCATION);
2587  }
2588 #endif
2589  // The processor "rank" to the right
2590  unsigned right_processor = static_cast<unsigned>(right_proc);
2591  right_processor_plus_one[is] = right_processor + 1;
2592 
2593  // Now get the id of the halo element to the right
2594  GeneralisedElement* right_element_pt = tmp_right_bulk_ele_pt;
2595 
2596  // Get the halo elements with right processor
2597  Vector<GeneralisedElement*> right_halo_element_pt =
2598  this->halo_element_pt(right_processor);
2599 
2600 #ifdef PARANOID
2601  // Flag to state that the halo element was found
2602  bool right_halo_element_found = false;
2603 #endif
2604 
2605  const unsigned nhalo_right = right_halo_element_pt.size();
2606  for (unsigned rh = 0; rh < nhalo_right; rh++)
2607  {
2608  if (right_element_pt == right_halo_element_pt[rh])
2609  {
2610  right_halo_element[is] = rh;
2611 #ifdef PARANOID
2612  right_halo_element_found = true;
2613 #endif
2614  break;
2615  }
2616  } // for (rh < nhalo_right)
2617 #ifdef PARANOID
2618  if (!right_halo_element_found)
2619  {
2620  std::ostringstream error_message;
2621  error_message
2622  << "The current bulk element (right) marked as halo was not "
2623  << "found in the vector of halo\nelements associated with "
2624  << "the (" << right_processor << ") processor.\n\n";
2625  throw OomphLibError(error_message.str(),
2626  "TriangleMesh::compute_boundary_segments_"
2627  "connectivity_and_initial_zeta_values()",
2628  OOMPH_EXCEPTION_LOCATION);
2629  }
2630 #endif
2631 
2632  // Get the right-most nonhalo element (use the backup list of
2633  // nonhalo elements)
2634  right_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
2635 
2636  // Get the corresponding bulk element
2637  tmp_right_bulk_ele_pt = face_to_bulk_element_pt[right_face_ele_pt];
2638 #ifdef PARANOID
2639  // This element should not be marked as halo
2640  if (tmp_right_bulk_ele_pt->is_halo())
2641  {
2642  std::ostringstream error_message;
2643  error_message
2644  << "The bulk element represetation of the right-most nonhalo face\n"
2645  << "element of the current segment (" << is
2646  << ") is marked as halo,\n"
2647  << "but the face element created from it is nonhalo\n";
2648  throw OomphLibError(error_message.str(),
2649  "TriangleMesh::compute_boundary_segments_"
2650  "connectivity_and_initial_zeta_values()",
2651  OOMPH_EXCEPTION_LOCATION);
2652  } // if (tmp_right_bulk_ele_pt->is_halo())
2653 #endif
2654 
2655  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2656  // to search in the haloed vector
2657  right_element_pt = tmp_right_bulk_ele_pt;
2658 
2659 #ifdef PARANOID
2660  // Flag to state that the haloed element was found
2661  bool right_haloed_element_found = false;
2662 #endif
2663 
2664  // Now get the id for the haloed element to the right
2665  Vector<GeneralisedElement*> right_haloed_element_pt =
2666  this->haloed_element_pt(right_processor);
2667 
2668  const unsigned nhaloed_right = right_haloed_element_pt.size();
2669  for (unsigned rhd = 0; rhd < nhaloed_right; rhd++)
2670  {
2671  if (right_element_pt == right_haloed_element_pt[rhd])
2672  {
2673  right_haloed_element[is] = rhd;
2674 #ifdef PARANOID
2675  right_haloed_element_found = true;
2676 #endif
2677  break;
2678  }
2679  } // for (rhd < nhaloed_right)
2680 
2681 #ifdef PARANOID
2682  if (!right_haloed_element_found)
2683  {
2684  std::ostringstream error_message;
2685  error_message
2686  << "The current bulk element (right) marked as haloed was not "
2687  << "found in the vector of haloed\nelements associated with "
2688  << "the (" << right_processor << ") processor.\n\n";
2689  throw OomphLibError(error_message.str(),
2690  "TriangleMesh::compute_boundary_segments_"
2691  "connectivity_and_initial_zeta_values()",
2692  OOMPH_EXCEPTION_LOCATION);
2693  }
2694 #endif
2695 
2696  } // if (tmp_right_bulk_ele_pt->is_halo())
2697  else
2698  {
2699  // If not halo then state the info. to indicate that
2700  right_processor_plus_one[is] = 0;
2701  // Null this info.
2702  right_halo_element[is] = 0;
2703  // Null this info.
2704  right_haloed_element[is] = 0;
2705  }
2706 
2707  } // for (is < nsegments). Used to get the halo info. of the
2708  // segments
2709 
2710  // Now we have all the info. to be sent to the root processor and
2711  // compute the correct (global) boundary coordinates for the current
2712  // boundary
2713 
2714  // The root processor will be in charge of performing the computing
2715  // of the coordinate values along the boundary, all the other
2716  // processors only send their info. and wait for receiving the new
2717  // starting values for each of its segments
2718 
2719  // Choose the root processor
2720  const unsigned root_processor = 0;
2721  // ------------------------------------------------------------------
2722  // Starts the MPI stage
2723 
2724  // The root processor receives the number of segments of each
2725  // processor associated to the current boundary
2726  Vector<unsigned> root_nsegments_per_processor(nproc);
2727  unsigned nsegments_mpi = nsegments;
2728  MPI_Gather(&nsegments_mpi,
2729  1,
2730  MPI_UNSIGNED,
2731  &root_nsegments_per_processor[0],
2732  1,
2733  MPI_UNSIGNED,
2734  root_processor,
2735  comm_pt->mpi_comm());
2736 
2737  // Package the info. and prepare it to be sent
2738  // For the packaged info. we send 7 data per each segment, the indexes
2739  // are as follow; 0 left proc, 1 right proc, 2 left halo, 3 right
2740  // halo, 4 left haloed, 5 right haloed and 6 for nvertices per
2741  // segment
2742  // The size of the package (unsigned)
2743  const unsigned spu = 7;
2744  Vector<unsigned> flat_packed_unsigned_send_data(nsegments * spu);
2745  for (unsigned is = 0; is < nsegments; is++)
2746  {
2747  flat_packed_unsigned_send_data[(spu * is) + 0] =
2748  left_processor_plus_one[is];
2749  flat_packed_unsigned_send_data[(spu * is) + 1] =
2750  right_processor_plus_one[is];
2751  flat_packed_unsigned_send_data[(spu * is) + 2] = left_halo_element[is];
2752  flat_packed_unsigned_send_data[(spu * is) + 3] = right_halo_element[is];
2753  flat_packed_unsigned_send_data[(spu * is) + 4] = left_haloed_element[is];
2754  flat_packed_unsigned_send_data[(spu * is) + 5] = right_haloed_element[is];
2755  flat_packed_unsigned_send_data[(spu * is) + 6] =
2756  nvertices_per_segment[is];
2757  }
2758 
2759  // How many data will this processor send
2760  const unsigned nudata_to_send = flat_packed_unsigned_send_data.size();
2761 
2762  // How many data does the root processor will receive from each
2763  // processor
2764  Vector<int> root_nudata_to_receive(nproc, 0);
2765  // Total number of data to receive from all processors
2766  unsigned root_nutotal_data_receive = 0;
2767  for (unsigned ip = 0; ip < nproc; ip++)
2768  {
2769  // Compute the number of data the root processor will receive from
2770  // each processor
2771  root_nudata_to_receive[ip] = root_nsegments_per_processor[ip] * spu;
2772  // Add on the total number of data to receive
2773  root_nutotal_data_receive += root_nudata_to_receive[ip];
2774  }
2775 
2776  // Stores and compute the offsets (in root) for the data received
2777  // from each processor
2778  Vector<int> root_uoffsets_receive(nproc, 0);
2779  root_uoffsets_receive[0] = 0;
2780  for (unsigned ip = 1; ip < nproc; ip++)
2781  {
2782  // Compute the offset to store the values from each processor
2783  root_uoffsets_receive[ip] =
2784  root_uoffsets_receive[ip - 1] + root_nudata_to_receive[ip - 1];
2785  }
2786 
2787  // Create at least one entry so we don't get a seg fault below
2788  if (flat_packed_unsigned_send_data.size() == 0)
2789  {
2790  flat_packed_unsigned_send_data.resize(1);
2791  }
2792 
2793  // Vector where to receive the info.
2794  Vector<unsigned> flat_packed_unsigned_receive_data(
2795  root_nutotal_data_receive);
2796  if (my_rank != root_processor)
2797  {
2798  // Create at least one entry so we don't get a seg fault below
2799  if (flat_packed_unsigned_receive_data.size() == 0)
2800  {
2801  flat_packed_unsigned_receive_data.resize(1);
2802  }
2803  } // if (my_rank!=root_processor)
2804 
2805  MPI_Gatherv(&flat_packed_unsigned_send_data[0], // Flat package to
2806  // send info. from
2807  // each processor
2808  nudata_to_send, // Total number of data to send from
2809  // each processor
2810  MPI_UNSIGNED,
2811  &flat_packed_unsigned_receive_data[0], // Container
2812  // where to
2813  // receive the
2814  // info. from all
2815  // the processors
2816  &root_nudata_to_receive[0], // Number of data to receive
2817  // from each processor
2818  &root_uoffsets_receive[0], // The offset to store the
2819  // info. from each processor
2820  MPI_UNSIGNED,
2821  root_processor, // The processor that receives all the
2822  // info.
2823  comm_pt->mpi_comm());
2824 
2825  // Clear the flat package to send
2826  flat_packed_unsigned_send_data.clear();
2827  flat_packed_unsigned_send_data.resize(0);
2828 
2829  // Package the info. and prepare it to be sent
2830  // For the packaged info. we send 1 data per each segment which is
2831  // at the moment the arclength of each segment
2832  // The size of the package
2833  const unsigned spd = 1;
2834  Vector<double> flat_packed_double_send_data(nsegments * spd);
2835  for (unsigned is = 0; is < nsegments; is++)
2836  {
2837  flat_packed_double_send_data[(spd * is) + 0] = segment_arclength[is];
2838  }
2839 
2840  // How many data will this processor send
2841  const unsigned nddata_to_send = flat_packed_double_send_data.size();
2842  // How many data does the root processor will receive from each
2843  // processor
2844  Vector<int> root_nddata_to_receive(nproc, 0);
2845  // Total number of data to receive from all processors
2846  unsigned root_ndtotal_data_receive = 0;
2847  for (unsigned ip = 0; ip < nproc; ip++)
2848  {
2849  root_nddata_to_receive[ip] = root_nsegments_per_processor[ip] * spd;
2850  root_ndtotal_data_receive += root_nddata_to_receive[ip];
2851  }
2852 
2853  // Stores and compute the offsets for the data received from each
2854  // processor
2855  Vector<int> root_doffsets_receive(nproc, 0);
2856  root_doffsets_receive[0] = 0;
2857  for (unsigned ip = 1; ip < nproc; ip++)
2858  {
2859  // Compute the offset to store the values from each processor
2860  root_doffsets_receive[ip] =
2861  root_doffsets_receive[ip - 1] + root_nddata_to_receive[ip - 1];
2862  }
2863 
2864  // Create at least one entry so we don't get a seg fault below
2865  if (flat_packed_double_send_data.size() == 0)
2866  {
2867  flat_packed_double_send_data.resize(1);
2868  }
2869 
2870  // Vector where to receive the info.
2871  Vector<double> flat_packed_double_receive_data(root_ndtotal_data_receive);
2872  if (my_rank != root_processor)
2873  {
2874  // Create at least one entry so we don't get a seg fault below
2875  if (flat_packed_double_receive_data.size() == 0)
2876  {
2877  flat_packed_double_receive_data.resize(1);
2878  }
2879  }
2880 
2881  MPI_Gatherv(&flat_packed_double_send_data[0], // Flat package to
2882  // send info. from
2883  // each processor
2884  nddata_to_send, // Total number of data to send from
2885  // each processor
2886  MPI_DOUBLE,
2887  &flat_packed_double_receive_data[0], // Container where
2888  // to receive the
2889  // info. from all
2890  // the processors
2891  &root_nddata_to_receive[0], // Number of data to receive
2892  // from each processor
2893  &root_doffsets_receive[0], // The offset to store the
2894  // info. from each processor
2895  MPI_DOUBLE,
2896  root_processor, // The processor that receives all the
2897  // info.
2898  comm_pt->mpi_comm());
2899 
2900  // Clear the flat package to send
2901  flat_packed_double_send_data.clear();
2902  flat_packed_double_send_data.resize(0);
2903 
2904  // The next three containers are only used by the root processor at
2905  // the end of its computations but it is necessary that all the
2906  // processors know them when calling back the info.
2907 
2908  // Container that state the initial arclength for each segments
2909  // of each processor
2910  Vector<Vector<double>> root_initial_segment_arclength(nproc);
2911 
2912  // Container that state the number of vertices before each segment
2913  // in a given processor
2914  Vector<Vector<unsigned>> root_nvertices_before_segment(nproc);
2915 
2916  // The root processor needs to tell the other processor if it was
2917  // necessary to reverse a segment. Each processor should therefore
2918  // invert the face elements that compose every segment that was
2919  // inverted by the root processor
2920  Vector<Vector<unsigned>> root_segment_inverted(nproc);
2921 
2922  // Used to store the accumulated arclength, used at the end of
2923  // communications to store the total arclength
2924  double root_accumulated_arclength = 0.0;
2925 
2926  // Store the accumulated number of vertices, it means the total number
2927  // of vertices before each segment (counter)
2928  unsigned root_accumulated_vertices_before_segment = 0;
2929 
2930  // The root processor is in charge of performing the connections
2931  // of the segments that define the complete boundary
2932  if (my_rank == root_processor)
2933  {
2934  // From the flat packaged received data re-create the data
2935  // structures storing the info. regarding the connectivity of the
2936  // segments, the number of vertices per segment and the local
2937  // arclength of each segment
2938 
2939  // Stores the "rank" of the processor to the left of each segment,
2940  // zero if there is no processor to the left which states that the
2941  // segment is the first one on the boundary
2942  Vector<Vector<unsigned>> root_left_processor_plus_one(nproc);
2943 
2944  // Stores the "rank" of the processor to the right of each segment,
2945  // zero if there is no processor to the right which states that the
2946  // segment is the last one on the boundary
2947  Vector<Vector<unsigned>> root_right_processor_plus_one(nproc);
2948 
2949  // The id. of the halo element to the left of the segment, note that
2950  // this info. is not necessary if there is no processor to the left
2951  // of the segment or if the processor has no info about the boundary
2952  Vector<Vector<unsigned>> root_left_halo_element(nproc);
2953 
2954  // The id. of the halo element to the right of the segment, note
2955  // that this info. is not necessary if there is no processor to
2956  // the right of the segment or if the processor has no info about
2957  // the boundary
2958  Vector<Vector<unsigned>> root_right_halo_element(nproc);
2959 
2960  // The id. of the haloed element to the left of the segment, note
2961  // that this info. is not necessary if there is no processor to
2962  // the left of the segment or if the processor has no info about
2963  // the boundary
2964  Vector<Vector<unsigned>> root_left_haloed_element(nproc);
2965 
2966  // The id. of the haloed element to the right of the segment, note
2967  // that this info. is not necessary if there is no processor to the
2968  // right of the segment or if the processor has no info about the
2969  // boundary
2970  Vector<Vector<unsigned>> root_right_haloed_element(nproc);
2971 
2972  // The number of vertices per segment in each processor
2973  Vector<Vector<unsigned>> root_nvertices_per_segment(nproc);
2974 
2975  // The arclength of each of the segments in the processors
2976  Vector<Vector<double>> root_segment_arclength(nproc);
2977 
2978  unsigned ucounter = 0;
2979  unsigned dcounter = 0;
2980  for (unsigned ip = 0; ip < nproc; ip++)
2981  {
2982  // Get the number of segments in the current processor
2983  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
2984 
2985  root_left_processor_plus_one[ip].resize(nsegs_iproc);
2986  root_right_processor_plus_one[ip].resize(nsegs_iproc);
2987  root_left_halo_element[ip].resize(nsegs_iproc);
2988  root_right_halo_element[ip].resize(nsegs_iproc);
2989  root_left_haloed_element[ip].resize(nsegs_iproc);
2990  root_right_haloed_element[ip].resize(nsegs_iproc);
2991 
2992  // Additional info.
2993  root_nvertices_per_segment[ip].resize(nsegs_iproc);
2994  root_segment_arclength[ip].resize(nsegs_iproc);
2995  root_segment_inverted[ip].resize(nsegs_iproc);
2996 
2997  // Extract the info. from the BIG package received from all
2998  // processors
2999  for (unsigned is = 0; is < nsegs_iproc; is++)
3000  {
3001  // ------ The flat unsigned package ------
3002  root_left_processor_plus_one[ip][is] =
3003  flat_packed_unsigned_receive_data[ucounter++];
3004  root_right_processor_plus_one[ip][is] =
3005  flat_packed_unsigned_receive_data[ucounter++];
3006  root_left_halo_element[ip][is] =
3007  flat_packed_unsigned_receive_data[ucounter++];
3008  root_right_halo_element[ip][is] =
3009  flat_packed_unsigned_receive_data[ucounter++];
3010  root_left_haloed_element[ip][is] =
3011  flat_packed_unsigned_receive_data[ucounter++];
3012  root_right_haloed_element[ip][is] =
3013  flat_packed_unsigned_receive_data[ucounter++];
3014  root_nvertices_per_segment[ip][is] =
3015  flat_packed_unsigned_receive_data[ucounter++];
3016 
3017  // ------ The flat double package ------
3018  root_segment_arclength[ip][is] =
3019  flat_packed_double_receive_data[dcounter++];
3020  } // for (is < nsegs_iproc)
3021  } // for (ip < nproc)
3022 
3023  // Now the root processor has all the info. to find out the
3024  // CONNECTIVITY of the segments in each processor
3025 
3026  // Container that stores the info. related with the connectivity
3027  // of the segments of each processor
3028  Vector<Vector<int>> left_connected_segment_plus_one(nproc);
3029  Vector<Vector<int>> right_connected_segment_plus_one(nproc);
3030  for (unsigned ip = 0; ip < nproc; ip++)
3031  {
3032  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3033  left_connected_segment_plus_one[ip].resize(nsegs_iproc, -1);
3034  right_connected_segment_plus_one[ip].resize(nsegs_iproc, -1);
3035  } // for (ip < nprocs)
3036 
3037  // In charge of storing the connectivity of the segments, the pair
3038  // indicates the processor and the segment number
3039  std::list<std::pair<unsigned, unsigned>> proc_seg_connectivity;
3040  proc_seg_connectivity.clear();
3041 
3042  // Done segments on processor
3043  std::map<std::pair<unsigned, unsigned>, bool> done_segment;
3044 
3045  // Take the first segment of the first processor with segments and
3046  // add it to the list of segments
3047  unsigned left_proc = 0;
3048  unsigned right_proc = 0;
3049  unsigned left_seg = 0;
3050  unsigned right_seg = 0;
3051  for (unsigned ip = 0; ip < nproc; ip++)
3052  {
3053  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3054  if (nsegs_iproc > 0)
3055  {
3056  right_proc = left_proc = ip;
3057  right_seg = left_seg = 0;
3058  break; // Break because it is the first processor with at
3059  // least one segment
3060  }
3061  } // for (ip < nproc)
3062 
3063  // ... and add it to the list of segments
3064  std::pair<unsigned, unsigned> add_segment =
3065  std::make_pair(left_proc, left_seg);
3066  done_segment[add_segment] = true;
3067  proc_seg_connectivity.push_back(add_segment);
3068 
3069  // Flags to indicate when a segment was added to the left or right
3070  // of the current list of segments
3071  bool added_segment_to_the_left = false;
3072  bool added_segment_to_the_right = false;
3073 
3074  do // while(added_segment_to_the_left || added_segment_to_the_right)
3075  {
3076  // Read the left-most processor and segment in the list
3077  std::pair<unsigned, unsigned> left_pair = proc_seg_connectivity.front();
3078  left_proc = left_pair.first;
3079  left_seg = left_pair.second;
3080 
3081  // Get the processor number to the left of the left-most
3082  // segment in the list
3083  const unsigned new_left_proc =
3084  root_left_processor_plus_one[left_proc][left_seg];
3085 
3086  if (new_left_proc != 0)
3087  {
3088  // Initialise flag
3089  added_segment_to_the_left = false;
3090  // Get the left halo element id
3091  const unsigned left_halo_id =
3092  root_left_halo_element[left_proc][left_seg];
3093 
3094  // Get the left haloed element id
3095  const unsigned left_haloed_id =
3096  root_left_haloed_element[left_proc][left_seg];
3097 
3098  // Go through the segments on the new left processor and look
3099  // for the corresponding left_halo_id in the haloed_ids
3100  const unsigned nsegs_new_left_proc =
3101  root_nsegments_per_processor[new_left_proc - 1];
3102 
3103  for (unsigned ils = 0; ils < nsegs_new_left_proc; ils++)
3104  {
3105  std::pair<unsigned, unsigned> candidate_seg =
3106  std::make_pair(new_left_proc - 1, ils);
3107 
3108  // Check that the segment has not been already added
3109  if (!done_segment[candidate_seg])
3110  {
3111  // Only consider the segments on new left processor which
3112  // right processor is the current one (left_proc)
3113  const unsigned right_proc_of_new_left_proc =
3114  root_right_processor_plus_one[new_left_proc - 1][ils];
3115  // Also get the left_proc_of_new_left_proc (in case that it
3116  // be necessary to invert the segment)
3117  const unsigned left_proc_of_new_left_proc =
3118  root_left_processor_plus_one[new_left_proc - 1][ils];
3119  // Check the not inverted case (to the left and not
3120  // inverted)
3121  if (right_proc_of_new_left_proc != 0 &&
3122  right_proc_of_new_left_proc - 1 == left_proc)
3123  {
3124  // Get the haloed/haloed element id of the current segment
3125  // in the new left processor and compare it to the
3126  // halo/haloed element id of the left_processor
3127  const unsigned right_halo_id =
3128  root_right_halo_element[new_left_proc - 1][ils];
3129  const unsigned right_haloed_id =
3130  root_right_haloed_element[new_left_proc - 1][ils];
3131  if (left_halo_id == right_haloed_id &&
3132  left_haloed_id == right_halo_id)
3133  {
3134  // We have a match of the segments (store the segment
3135  // number plus one on the processor to the left)
3136  left_connected_segment_plus_one[left_proc][left_seg] =
3137  ils + 1;
3138  // Add the pair to the connectivity list
3139  proc_seg_connectivity.push_front(candidate_seg);
3140  added_segment_to_the_left = true;
3141  break;
3142  }
3143  } // if (right_proc_of_new_left_proc-1 == left_proc)
3144 
3145  // Check the inverted case (to the left and inverted)
3146  if (left_proc_of_new_left_proc != 0 &&
3147  left_proc_of_new_left_proc - 1 == left_proc)
3148  {
3149  // Get the haloed element id of the current segment
3150  // (inverted version) in the new left processor and
3151  // compare it to the halo element id of the left_processor
3152  const unsigned inv_left_halo_id =
3153  root_left_halo_element[new_left_proc - 1][ils];
3154  const unsigned inv_left_haloed_id =
3155  root_left_haloed_element[new_left_proc - 1][ils];
3156  if (left_halo_id == inv_left_haloed_id &&
3157  left_haloed_id == inv_left_halo_id)
3158  {
3159  // We have a match of the segments (store the segment
3160  // number plus one on the processor to the left)
3161  left_connected_segment_plus_one[left_proc][left_seg] =
3162  ils + 1;
3163  // Add the pair to the connectivity list
3164  proc_seg_connectivity.push_front(candidate_seg);
3165 
3166  // In addition to the connectivity we need to invert the
3167  // segment (the information)
3168  const unsigned tmp_proc =
3169  root_left_processor_plus_one[new_left_proc - 1][ils];
3170  const unsigned tmp_halo =
3171  root_left_halo_element[new_left_proc - 1][ils];
3172  const unsigned tmp_haloed =
3173  root_left_haloed_element[new_left_proc - 1][ils];
3174 
3175  root_left_processor_plus_one[new_left_proc - 1][ils] =
3176  root_right_processor_plus_one[new_left_proc - 1][ils];
3177  root_left_halo_element[new_left_proc - 1][ils] =
3178  root_right_halo_element[new_left_proc - 1][ils];
3179  root_left_haloed_element[new_left_proc - 1][ils] =
3180  root_right_haloed_element[new_left_proc - 1][ils];
3181 
3182  root_right_processor_plus_one[new_left_proc - 1][ils] =
3183  tmp_proc;
3184  root_right_halo_element[new_left_proc - 1][ils] = tmp_halo;
3185  root_right_haloed_element[new_left_proc - 1][ils] =
3186  tmp_haloed;
3187 
3188  // ... and mark the segment as inverted in the root
3189  // processor to inform back to the owner processor
3190  root_segment_inverted[new_left_proc - 1][ils] = 1;
3191 
3192  added_segment_to_the_left = true;
3193  break;
3194  }
3195  } // if (left_proc_of_new_left_proc-1 == left_proc)
3196  } // if (!done_segment[candidate_segment])
3197  } // for (ils < nsegs_new_left_proc)
3198 
3199 #ifdef PARANOID
3200  if (!added_segment_to_the_left)
3201  {
3202  std::ostringstream error_message;
3203  error_message
3204  << "The corresponding processor and segment to the left of "
3205  << "the current left\nmost segment was not found\n";
3206  throw OomphLibError(error_message.str(),
3207  "TriangleMesh::compute_boundary_segments_"
3208  "connectivity_and_initial_zeta_values()",
3209  OOMPH_EXCEPTION_LOCATION);
3210  }
3211 #endif
3212  } // if (new_left_proc != 0)
3213  else
3214  {
3215  // No more segments to the left
3216  added_segment_to_the_left = false;
3217  }
3218 
3219  // Read the info. of the right processor and the right segment
3220  std::pair<unsigned, unsigned> right_pair = proc_seg_connectivity.back();
3221  right_proc = right_pair.first;
3222  right_seg = right_pair.second;
3223 
3224  // Get the processor number to the right of the right-most
3225  // segment in the list
3226  const unsigned new_right_proc =
3227  root_right_processor_plus_one[right_proc][right_seg];
3228 
3229  if (new_right_proc != 0)
3230  {
3231  // Initialise flag
3232  added_segment_to_the_right = false;
3233  // Get the right halo element id
3234  const unsigned right_halo_id =
3235  root_right_halo_element[right_proc][right_seg];
3236 
3237  // Get the right halo element id
3238  const unsigned right_haloed_id =
3239  root_right_haloed_element[right_proc][right_seg];
3240 
3241  // Go through the segments on the new right processor and look
3242  // for the corresponding right_halo_id in the haloed_ids
3243  const unsigned nsegs_new_right_proc =
3244  root_nsegments_per_processor[new_right_proc - 1];
3245 
3246  for (unsigned irs = 0; irs < nsegs_new_right_proc; irs++)
3247  {
3248  std::pair<unsigned, unsigned> candidate_seg =
3249  std::make_pair(new_right_proc - 1, irs);
3250 
3251  // Check that the segment has not been already added
3252  if (!done_segment[candidate_seg])
3253  {
3254  // Only consider the segments on new right processor which
3255  // left processor is the current one (right_proc)
3256  const unsigned left_proc_of_new_right_proc =
3257  root_left_processor_plus_one[new_right_proc - 1][irs];
3258  // Also get the right_proc_of_new_right_proc (in case
3259  // that it be necessary to invert the segment)
3260  const unsigned right_proc_of_new_right_proc =
3261  root_right_processor_plus_one[new_right_proc - 1][irs];
3262  // Check the not inverted case (to the right and not
3263  // inverted)
3264  if (left_proc_of_new_right_proc != 0 &&
3265  left_proc_of_new_right_proc - 1 == right_proc)
3266  {
3267  // Get the haloed element id of the current segment in the
3268  // new right processor and compare it to the halo element
3269  // id of the right_processor
3270  const unsigned left_halo_id =
3271  root_left_halo_element[new_right_proc - 1][irs];
3272  const unsigned left_haloed_id =
3273  root_left_haloed_element[new_right_proc - 1][irs];
3274 
3275  if (right_halo_id == left_haloed_id &&
3276  right_haloed_id == left_halo_id)
3277  {
3278  // We have a match of the segments (store the segment
3279  // number plus one on the processor to the right)
3280  right_connected_segment_plus_one[right_proc][right_seg] =
3281  irs + 1;
3282  // Add the connectivity information to the list
3283  proc_seg_connectivity.push_back(candidate_seg);
3284  added_segment_to_the_right = true;
3285  break;
3286  }
3287  } // if (left_proc_of_new_right_proc-1 == right_proc)
3288 
3289  // Check the inverted case (to the right and inverted)
3290  if (right_proc_of_new_right_proc != 0 &&
3291  right_proc_of_new_right_proc - 1 == right_proc)
3292  {
3293  // Get the haloed element id of the current segment
3294  // (inverted version) in the new right processor and
3295  // compare it to the halo element id of the
3296  // right_processor
3297  const unsigned inv_right_halo_id =
3298  root_right_halo_element[new_right_proc - 1][irs];
3299  const unsigned inv_right_haloed_id =
3300  root_right_haloed_element[new_right_proc - 1][irs];
3301  if (right_halo_id == inv_right_haloed_id &&
3302  right_haloed_id == inv_right_halo_id)
3303  {
3304  // We have a match of the segments (store the segment
3305  // number plus one on the processor to the right)
3306  right_connected_segment_plus_one[right_proc][right_seg] =
3307  irs + 1;
3308  // Add the connectivity information to the list
3309  proc_seg_connectivity.push_back(candidate_seg);
3310  // In addition to the connectivity we need to invert the
3311  // segment
3312  const unsigned tmp_proc =
3313  root_left_processor_plus_one[new_right_proc - 1][irs];
3314  const unsigned tmp_halo =
3315  root_left_halo_element[new_right_proc - 1][irs];
3316  const unsigned tmp_haloed =
3317  root_left_haloed_element[new_right_proc - 1][irs];
3318 
3319  root_left_processor_plus_one[new_right_proc - 1][irs] =
3320  root_right_processor_plus_one[new_right_proc - 1][irs];
3321  root_left_halo_element[new_right_proc - 1][irs] =
3322  root_right_halo_element[new_right_proc - 1][irs];
3323  root_left_haloed_element[new_right_proc - 1][irs] =
3324  root_right_haloed_element[new_right_proc - 1][irs];
3325 
3326  root_right_processor_plus_one[new_right_proc - 1][irs] =
3327  tmp_proc;
3328  root_right_halo_element[new_right_proc - 1][irs] = tmp_halo;
3329  root_right_haloed_element[new_right_proc - 1][irs] =
3330  tmp_haloed;
3331 
3332  // ... and mark the segment as inverted in the root
3333  // processor to inform back to the owner processor
3334  root_segment_inverted[new_right_proc - 1][irs] = 1;
3335 
3336  added_segment_to_the_right = true;
3337  break;
3338  }
3339  } // if (right_proc_of_new_right_proc-1 == right_proc)
3340  } // if (!done_segment[candidate_segment])
3341  } // for (irs < nsegs_new_left_proc)
3342 
3343 #ifdef PARANOID
3344  if (!added_segment_to_the_right)
3345  {
3346  std::ostringstream error_message;
3347  error_message
3348  << "The corresponding processor and segment to the right of "
3349  << "the current right\nmost segment was not found\n";
3350  throw OomphLibError(error_message.str(),
3351  "TriangleMesh::compute_boundary_segments_"
3352  "connectivity_and_initial_zeta_values()",
3353  OOMPH_EXCEPTION_LOCATION);
3354  }
3355 #endif
3356  } // if (new_right_proc != 0)
3357  else
3358  {
3359  // No more segments to the left
3360  added_segment_to_the_right = false;
3361  }
3362 
3363  } while (added_segment_to_the_left || added_segment_to_the_right);
3364 
3365  // Once we have connected the segments then we can compute the
3366  // initial and final zeta values based on the arclength of each
3367  // individual segment
3368 
3369  // Get the total number of segments, which MUST be the same as the
3370  // total number of segments in all processors
3371  const unsigned ntotal_segments = proc_seg_connectivity.size();
3372 #ifdef PARANOID
3373  unsigned tmp_total_segments = 0;
3374  for (unsigned ip = 0; ip < nproc; ip++)
3375  {
3376  tmp_total_segments += root_nsegments_per_processor[ip];
3377  }
3378 
3379  // Check that the total number of segments in all processors is
3380  // the same as the number of segments that form the boundary
3381  if (ntotal_segments != tmp_total_segments)
3382  {
3383  std::ostringstream error_message;
3384  error_message << "The number of sorted segments (" << ntotal_segments
3385  << ") on "
3386  << "boundary (" << b
3387  << ")\nis different from the total number of "
3388  << "segments (" << tmp_total_segments
3389  << ") in all\nprocessors.\n\n";
3390  throw OomphLibError(error_message.str(),
3391  OOMPH_CURRENT_FUNCTION,
3392  OOMPH_EXCEPTION_LOCATION);
3393  } // if (ntotal_segments!=tmp_total_segments)
3394 #endif
3395 
3396  // Now that we know the connectivity of the segments we can
3397  // compute the initial arclength of each segment in the
3398  // processors. Additionally we also get the number of vertices
3399  // before each of the segments. Resize the containers considering
3400  // the number of segments in each processor
3401  for (unsigned ip = 0; ip < nproc; ip++)
3402  {
3403  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3404  root_initial_segment_arclength[ip].resize(nsegs_iproc);
3405  root_nvertices_before_segment[ip].resize(nsegs_iproc);
3406  }
3407 
3408  Vector<double> aux_initial_segment_arclength(ntotal_segments);
3409  Vector<unsigned> aux_nvertices_before_segment(ntotal_segments);
3410 
3411  ucounter = 0;
3412  for (std::list<std::pair<unsigned, unsigned>>::iterator it_list =
3413  proc_seg_connectivity.begin();
3414  it_list != proc_seg_connectivity.end();
3415  it_list++)
3416  {
3417  const unsigned iproc = static_cast<unsigned>((*it_list).first);
3418  const unsigned iseg = static_cast<unsigned>((*it_list).second);
3419  const double iseg_arclength = root_segment_arclength[iproc][iseg];
3420  const unsigned iseg_nvertices = root_nvertices_per_segment[iproc][iseg];
3421 
3422  aux_initial_segment_arclength[ucounter] = root_accumulated_arclength;
3423  aux_nvertices_before_segment[ucounter] =
3424  root_accumulated_vertices_before_segment;
3425 
3426  // Set the initial zeta value for the segment
3427  root_initial_segment_arclength[iproc][iseg] =
3428  root_accumulated_arclength;
3429  // Set the number of vertices before the current segment
3430  root_nvertices_before_segment[iproc][iseg] =
3431  root_accumulated_vertices_before_segment;
3432 
3433  // Add the arclength of the segment to the global arclength
3434  root_accumulated_arclength += iseg_arclength;
3435  // Add the number of vertices to the global number of vertices
3436  root_accumulated_vertices_before_segment += iseg_nvertices - 1;
3437 
3438  // Increase the counter
3439  ucounter++;
3440  } // for (loop over the sorted segments to assigne initial
3441  // arlength and initial number of vertices)
3442 
3443  // Increase by one to get the total number of vertices on the
3444  // boundary
3445  root_accumulated_vertices_before_segment++;
3446 
3447  // Get the processors with the initial and final segment.
3448  proc_with_initial_seg = proc_seg_connectivity.front().first;
3449  proc_with_final_seg = proc_seg_connectivity.back().first;
3450  // Also get the corresponding initial and final segment indexes
3451  // (on the initial and final processors)
3452  initial_segment = proc_seg_connectivity.front().second;
3453  final_segment = proc_seg_connectivity.back().second;
3454 
3455  } // if (my_rank == root_processor)
3456 
3457  // Get the total number of segments
3458  unsigned root_ntotal_segments = 0;
3459  for (unsigned ip = 0; ip < nproc; ip++)
3460  {
3461  root_ntotal_segments += root_nsegments_per_processor[ip];
3462  }
3463 
3464  // Package the info. that will be sent to each processor. For the
3465  // unsigned package we send the number of vertices before each
3466  // segment in each processor and whether it was inverted or not
3467  // Package size
3468  const unsigned rspu = 2;
3469  flat_packed_unsigned_send_data.clear();
3470  flat_packed_unsigned_send_data.resize(root_ntotal_segments * rspu);
3471  unsigned ucounter = 0;
3472  // Collect the info. from all the segments in the processors
3473  for (unsigned ip = 0; ip < nproc; ip++)
3474  {
3475  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3476  for (unsigned is = 0; is < nsegs_iproc; is++)
3477  {
3478  flat_packed_unsigned_send_data[ucounter++] =
3479  root_nvertices_before_segment[ip][is];
3480  flat_packed_unsigned_send_data[ucounter++] =
3481  root_segment_inverted[ip][is];
3482  } // for (is < nsegs_iproc)
3483  } // for (ip < nproc)
3484 
3485  // How many data does the root processor will send to each processor
3486  Vector<int> root_nudata_to_send(nproc, 0);
3487  for (unsigned ip = 0; ip < nproc; ip++)
3488  {
3489  // Get the number of data to send to ip processor
3490  root_nudata_to_send[ip] = root_nsegments_per_processor[ip] * rspu;
3491  }
3492 
3493  // Store and compute the offsets for the data sent to each processor
3494  Vector<int> root_uoffsets_send(nproc, 0);
3495  root_uoffsets_send[0] = 0;
3496  for (unsigned ip = 1; ip < nproc; ip++)
3497  {
3498  // Compute the offset to send the values to each processor
3499  root_uoffsets_send[ip] =
3500  root_uoffsets_send[ip - 1] + root_nudata_to_send[ip - 1];
3501  }
3502 
3503  // Number of data to receive from root
3504  unsigned nutotal_data_receive = nsegments * rspu;
3505 
3506  if (my_rank != root_processor)
3507  {
3508  // Create at least one entry so we don't get a seg fault below
3509  if (flat_packed_unsigned_send_data.size() == 0)
3510  {
3511  flat_packed_unsigned_send_data.resize(1);
3512  }
3513  }
3514 
3515  // Clear and resize the vector where to receive the info.
3516  flat_packed_unsigned_receive_data.clear();
3517  flat_packed_unsigned_receive_data.resize(nutotal_data_receive);
3518  // Create at least one entry so we don't get a seg fault below
3519  if (flat_packed_unsigned_receive_data.size() == 0)
3520  {
3521  flat_packed_unsigned_receive_data.resize(1);
3522  }
3523 
3524  MPI_Scatterv(&flat_packed_unsigned_send_data[0],
3525  &root_nudata_to_send[0],
3526  &root_uoffsets_send[0],
3527  MPI_UNSIGNED,
3528  &flat_packed_unsigned_receive_data[0],
3529  nutotal_data_receive,
3530  MPI_UNSIGNED,
3531  root_processor,
3532  comm_pt->mpi_comm());
3533 
3534  // Package the info. that will be sent to each processor, for the
3535  // double package we send (one data per segment) the initial
3536  // arclength for each segment
3537  const unsigned rspd = 1;
3538  flat_packed_double_send_data.clear();
3539  flat_packed_double_send_data.resize(root_ntotal_segments * rspd);
3540  unsigned dcounter = 0;
3541  // Collect the info. from all the segments in the processors
3542  for (unsigned ip = 0; ip < nproc; ip++)
3543  {
3544  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3545  for (unsigned is = 0; is < nsegs_iproc; is++)
3546  {
3547  flat_packed_double_send_data[dcounter++] =
3548  root_initial_segment_arclength[ip][is];
3549  }
3550  }
3551 
3552  // How many data does the root processor will send to each processor
3553  Vector<int> root_nddata_to_send(nproc, 0);
3554  for (unsigned ip = 0; ip < nproc; ip++)
3555  {
3556  // Number of data send to ip processor
3557  root_nddata_to_send[ip] = root_nsegments_per_processor[ip] * rspd;
3558  }
3559 
3560  // Store and compute the offsets for the data sent to each processor
3561  Vector<int> root_doffsets_send(nproc, 0);
3562  root_doffsets_send[0] = 0;
3563  for (unsigned ip = 1; ip < nproc; ip++)
3564  {
3565  // Compute the offset to send the values to each processor
3566  root_doffsets_send[ip] =
3567  root_doffsets_send[ip - 1] + root_nddata_to_send[ip - 1];
3568  }
3569 
3570  // Number of double data to receive from root
3571  unsigned ndtotal_data_receive = nsegments * rspd;
3572 
3573  if (my_rank != root_processor)
3574  {
3575  // Create at least one entry so we don't get a seg fault below
3576  if (flat_packed_double_send_data.size() == 0)
3577  {
3578  flat_packed_double_send_data.resize(1);
3579  }
3580  }
3581 
3582  // Clear and resize the vector where to receive the info.
3583  flat_packed_double_receive_data.clear();
3584  flat_packed_double_receive_data.resize(ndtotal_data_receive);
3585  // Create at least one entry so we don't get a seg fault below
3586  if (flat_packed_double_receive_data.size() == 0)
3587  {
3588  flat_packed_double_receive_data.resize(1);
3589  }
3590 
3591  MPI_Scatterv(&flat_packed_double_send_data[0],
3592  &root_nddata_to_send[0],
3593  &root_doffsets_send[0],
3594  MPI_DOUBLE,
3595  &flat_packed_double_receive_data[0],
3596  ndtotal_data_receive,
3597  MPI_DOUBLE,
3598  root_processor,
3599  comm_pt->mpi_comm());
3600 
3601  // Read if the segments need to be inverted and read the initial
3602  // arclengths
3603  ucounter = 0;
3604  dcounter = 0;
3605 
3606  // Read the info. from the flat package and store it in their
3607  // corresponding containers
3608  for (unsigned is = 0; is < nsegments; is++)
3609  {
3610  // The flat unsigned package
3611  nvertices_before_segment[is] =
3612  flat_packed_unsigned_receive_data[ucounter++];
3613  // The segment inverted flag
3614  segment_inverted[is] = flat_packed_unsigned_receive_data[ucounter++];
3615  // The flat double package
3616  initial_segment_arclength[is] =
3617  flat_packed_double_receive_data[dcounter++];
3618  } // for (is < nsegments)
3619 
3620  // Perform two additional communications to get the total number of
3621  // vertices, the processors with the initial and final segments, the
3622  // corresponding initial and final segments ...
3623  const unsigned numore_info = 5;
3624  Vector<unsigned> flat_package_unsigned_more_info(numore_info);
3625  // Prepare the info ...
3626  flat_package_unsigned_more_info[0] =
3627  root_accumulated_vertices_before_segment;
3628  flat_package_unsigned_more_info[1] = proc_with_initial_seg;
3629  flat_package_unsigned_more_info[2] = proc_with_final_seg;
3630  flat_package_unsigned_more_info[3] = initial_segment;
3631  flat_package_unsigned_more_info[4] = final_segment;
3632 
3633  // Send the info. to all processors
3634  MPI_Bcast(&flat_package_unsigned_more_info[0],
3635  numore_info,
3636  MPI_UNSIGNED,
3637  root_processor,
3638  comm_pt->mpi_comm());
3639 
3640  // ... and store the info. in the proper containers
3641  root_accumulated_vertices_before_segment =
3642  flat_package_unsigned_more_info[0];
3643  proc_with_initial_seg = flat_package_unsigned_more_info[1];
3644  proc_with_final_seg = flat_package_unsigned_more_info[2];
3645  initial_segment = flat_package_unsigned_more_info[3];
3646  final_segment = flat_package_unsigned_more_info[4];
3647 
3648  // Do the same for the maximum zeta value
3649  MPI_Bcast(&root_accumulated_arclength,
3650  1,
3651  MPI_DOUBLE,
3652  root_processor,
3653  comm_pt->mpi_comm());
3654 
3655  // -----------------------------------------------------------------
3656  // Clear the storage to store the data that will be used by the
3657  // setup boundary coordinates method, if we do not perform the
3658  // cleaning then previous data from previous iterations will remain
3659  // there
3660  // -----------------------------------------------------------------
3661  // The info. for the boundary
3662  Boundary_initial_coordinate[b].clear();
3663  Boundary_final_coordinate[b].clear();
3664 
3665  Boundary_initial_zeta_coordinate[b].clear();
3666  Boundary_final_zeta_coordinate[b].clear();
3667 
3668  // The info. for the segments
3669  Boundary_segment_inverted[b].clear();
3670  Boundary_segment_initial_coordinate[b].clear();
3671  Boundary_segment_final_coordinate[b].clear();
3672 
3673  Boundary_segment_initial_zeta[b].clear();
3674  Boundary_segment_final_zeta[b].clear();
3675 
3676  Boundary_segment_initial_arclength[b].clear();
3677  Boundary_segment_final_arclength[b].clear();
3678 
3679  // Now copy all the info. to the containers to be sent to any other
3680  // mesh (in the adaptation method)
3681  for (unsigned is = 0; is < nsegments; is++)
3682  {
3683  // At this point we can get the initial and final coordinates for
3684  // each segment
3685  Vector<double> first_seg_coord(2);
3686  Vector<double> last_seg_coord(2);
3687 
3688  // In order to get the first and last coordinates of each segment we
3689  // first need to identify the first and last nonhalo element of each
3690  // segment, and then get the first and last node of the segment
3691 
3692  // Get the first nonhalo face element on the segment
3693  FiniteElement* first_seg_ele_pt =
3694  segment_sorted_nonhalo_ele_pt[is].front();
3695 
3696 #ifdef PARANOID
3697  // Check if the face element is nonhalo, it shouldn't, but better
3698  // check
3699  if (first_seg_ele_pt->is_halo())
3700  {
3701  std::ostringstream error_message;
3702  error_message << "The first face element in the (" << is
3703  << ")-th segment is halo\n";
3704  throw OomphLibError(error_message.str(),
3705  "TriangleMesh::compute_boundary_segments_"
3706  "connectivity_and_initial_zeta_values()",
3707  OOMPH_EXCEPTION_LOCATION);
3708  } // if (tmp_first_bulk_ele_pt->is_halo())
3709 #endif
3710 
3711  // Number of nodes
3712  const unsigned nnod = first_seg_ele_pt->nnode();
3713 
3714  // Get the first node of the current segment
3715  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
3716  if (is_inverted[first_seg_ele_pt])
3717  {
3718  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod - 1);
3719  }
3720 
3721  // Get the last nonhalo face element on the segment
3722  FiniteElement* last_seg_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
3723 
3724 #ifdef PARANOID
3725  // Check if the face element is nonhalo, it shouldn't, but better
3726  // check
3727  if (last_seg_ele_pt->is_halo())
3728  {
3729  std::ostringstream error_message;
3730  error_message << "The last face element in the (" << is
3731  << ")-th segment is halo\n";
3732  throw OomphLibError(error_message.str(),
3733  "TriangleMesh::compute_boundary_segments_"
3734  "connectivity_and_initial_zeta_values()",
3735  OOMPH_EXCEPTION_LOCATION);
3736  } // if (tmp_first_bulk_ele_pt->is_halo())
3737 #endif
3738 
3739  // Get the last node of the current segment
3740  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod - 1);
3741  if (is_inverted[last_seg_ele_pt])
3742  {
3743  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
3744  }
3745 
3746  // Get the coordinates for the first and last segment's node
3747  for (unsigned i = 0; i < 2; i++)
3748  {
3749  first_seg_coord[i] = first_seg_node_pt->x(i);
3750  last_seg_coord[i] = last_seg_node_pt->x(i);
3751  }
3752 
3753  // -----------------------------------------------------------------
3754  // Copy the info. if the segment is inverted
3755  Boundary_segment_inverted[b].push_back(segment_inverted[is]);
3756 
3757  // Check if the segment is inverted, if that is the case then invert
3758  // the first and last seg. coordinates
3759  if (!segment_inverted[is])
3760  {
3761  // Store the initial and final coordinates that will help to
3762  // identify the segments in the new meshes created from this one
3763  Boundary_segment_initial_coordinate[b].push_back(first_seg_coord);
3764  Boundary_segment_final_coordinate[b].push_back(last_seg_coord);
3765  }
3766  else
3767  {
3768  // Store the initial and final coordinates that will help to
3769  // identify the segments in the new meshes created from this one
3770  // Invert the initial and final coordinates
3771  Boundary_segment_initial_coordinate[b].push_back(last_seg_coord);
3772  Boundary_segment_final_coordinate[b].push_back(first_seg_coord);
3773  }
3774 
3775  // Now assign initial and final zeta boundary coordinates for each
3776  // segment
3777  // -----------------------------------------------------------------
3778  // If there is a geom object then
3779  if (boundary_geom_object_pt(b) != 0)
3780  {
3781  // Store the initial and final zeta for the current segments (we
3782  // got this when we assigned arclength to the segments in the
3783  // current processor)
3784  if (segment_inverted[is])
3785  {
3786  Boundary_segment_initial_zeta[b].push_back(final_zeta_segment[is]);
3787  Boundary_segment_final_zeta[b].push_back(initial_zeta_segment[is]);
3788  }
3789  else
3790  {
3791  Boundary_segment_initial_zeta[b].push_back(initial_zeta_segment[is]);
3792  Boundary_segment_final_zeta[b].push_back(final_zeta_segment[is]);
3793  }
3794  } // if (boundary_geom_object_pt(b)!=0)
3795  else
3796  {
3797  // Store the initial arclength and vertices number for the
3798  // current segment
3799  Boundary_segment_initial_arclength[b].push_back(
3800  initial_segment_arclength[is]);
3801 
3802  Boundary_segment_final_arclength[b].push_back(
3803  initial_segment_arclength[is] + segment_arclength[is]);
3804 
3805  } // else if (boundary_geom_object_pt(b)!=0)
3806 
3807  } // // for (is < nsegments)
3808 
3809  // Get the number of segments from the sets of nodes
3810 #ifdef PARANOID
3811  if (segment_all_nodes_pt.size() != nsegments)
3812  {
3813  std::ostringstream error_message;
3814  error_message << "The number of segments (" << nsegments
3815  << ") and the number of "
3816  << "set of nodes (" << segment_all_nodes_pt.size()
3817  << ") representing\n"
3818  << "the\nsegments is different!!!\n\n";
3819  throw OomphLibError(error_message.str(),
3820  "TriangleMesh::compute_boundary_segments_"
3821  "connectivity_and_initial_zeta_values()",
3822  OOMPH_EXCEPTION_LOCATION);
3823  }
3824 #endif
3825 
3826  // The nodes have been assigned arc-length coordinates from one end
3827  // or the other of the connected segment.
3828 
3829  // -----------------------------------------------------------------
3830  // If mesh is distributed get the info. regarding the initial and
3831  // final nodes coordinates on the boundary, same as the zeta
3832  // boundary values for those nodes
3833 
3834  // Storage for the coordinates of the first and last nodes on the
3835  // boundary
3836  Vector<double> first_coordinate(2);
3837  Vector<double> last_coordinate(2);
3838 
3839  // Storage for the zeta coordinate of the first and last nodes on
3840  // the boundary
3841  Vector<double> first_node_zeta_coordinate(1, 0.0);
3842  Vector<double> last_node_zeta_coordinate(1, 0.0);
3843 
3844  // Send three data to all processors, the x[0], x[1] coordinate and
3845  // the zeta coordinate
3846  const unsigned ndtotal_data = 3;
3847  Vector<double> flat_packed_double_data_initial_seg(ndtotal_data);
3848 
3849  // If the mesh is distributed then check if this processor has the
3850  // initial segment
3851  if (my_rank == proc_with_initial_seg)
3852  {
3853  // Stores the firts element of the segment
3854  FiniteElement* first_ele_pt = 0;
3855  // Stores the first node of the boundary
3856  Node* first_node_pt = 0;
3857  // Check if the segment is inverted
3858  if (!segment_inverted[initial_segment])
3859  {
3860  // Get access to the first element on the segment marked as
3861  // initial
3862  first_ele_pt = segment_sorted_ele_pt[initial_segment].front();
3863 
3864  // Number of nodes
3865  const unsigned nnod = first_ele_pt->nnode();
3866 
3867  // Get the first node of the current segment
3868  first_node_pt = first_ele_pt->node_pt(0);
3869  if (is_inverted[first_ele_pt])
3870  {
3871  first_node_pt = first_ele_pt->node_pt(nnod - 1);
3872  }
3873  } // if (!segment_inverted[initial_segment])
3874  else
3875  {
3876  // Get access to the first element on the segment marked as
3877  // initial
3878  first_ele_pt = segment_sorted_ele_pt[initial_segment].back();
3879 
3880  // Number of nodes
3881  const unsigned nnod = first_ele_pt->nnode();
3882 
3883  // Get the first node of the current segment
3884  first_node_pt = first_ele_pt->node_pt(nnod - 1);
3885  if (is_inverted[first_ele_pt])
3886  {
3887  first_node_pt = first_ele_pt->node_pt(0);
3888  }
3889  } // else if (!segment_inverted[initial_segment])
3890 
3891  // Get the coordinates for the first node
3892  for (unsigned i = 0; i < 2; i++)
3893  {
3894  flat_packed_double_data_initial_seg[i] = first_node_pt->x(i);
3895  }
3896 
3897  // Get the zeta coordinates for the first node
3898  Vector<double> tmp_zeta(1);
3899  first_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3900 
3901  // If there is a geometric object associated to the boundary then
3902  // further process is necessary
3903  if (this->boundary_geom_object_pt(b) != 0)
3904  {
3905  // tmp_zeta[0] = this->boundary_coordinate_limits(b)[0];
3906  }
3907  else
3908  {
3909  // Check if the initial boundary coordinate is different from
3910  // zero, if that is the case then we need to set it to zero
3911  if (tmp_zeta[0] >= 1.0e-14)
3912  {
3913  tmp_zeta[0] = 0;
3914  }
3915  } // if (this->boundary_geom_object_pt(b)!=0)
3916 
3917  // Store the initial zeta value
3918  flat_packed_double_data_initial_seg[2] = tmp_zeta[0];
3919 
3920  } // if (my_rank == proc_with_initial_seg)
3921 
3922  // All processor receive the info. from the processor that has the
3923  // initial segment
3924  MPI_Bcast(&flat_packed_double_data_initial_seg[0],
3925  ndtotal_data,
3926  MPI_DOUBLE,
3927  proc_with_initial_seg,
3928  comm_pt->mpi_comm());
3929 
3930  // ... and all processor put that info. into the appropriate
3931  // storages
3932  for (unsigned i = 0; i < 2; i++)
3933  {
3934  first_coordinate[i] = flat_packed_double_data_initial_seg[i];
3935  }
3936  first_node_zeta_coordinate[0] = flat_packed_double_data_initial_seg[2];
3937 
3938  // -----------------------------------------------------------------
3939  // Send three data to all processors, the x[0], x[1] coordinate and
3940  // the zeta coordinate
3941  Vector<double> flat_packed_double_data_final_seg(ndtotal_data);
3942 
3943  // If the mesh is distributed then check if this processor has the
3944  // final segment
3945  if (my_rank == proc_with_final_seg)
3946  {
3947  // Get access to the last element on the segment
3948  FiniteElement* last_ele_pt = 0;
3949 
3950  // Get the last node of the current segment
3951  Node* last_node_pt = 0;
3952 
3953  // Check if the segment is inverted
3954  if (!segment_inverted[final_segment])
3955  {
3956  // Get access to the last element on the segment marked as
3957  // final
3958  last_ele_pt = segment_sorted_ele_pt[final_segment].back();
3959 
3960  // Number of nodes
3961  const unsigned nnod = last_ele_pt->nnode();
3962 
3963  // Get the last node of the current segment
3964  last_node_pt = last_ele_pt->node_pt(nnod - 1);
3965  if (is_inverted[last_ele_pt])
3966  {
3967  last_node_pt = last_ele_pt->node_pt(0);
3968  }
3969  } // if (!segment_inverted[final_segment])
3970  else
3971  {
3972  // Get access to the first element on the segment marked as
3973  // initial
3974  last_ele_pt = segment_sorted_ele_pt[final_segment].front();
3975 
3976  // Number of nodes
3977  const unsigned nnod = last_ele_pt->nnode();
3978 
3979  // Get the first node of the current segment
3980  last_node_pt = last_ele_pt->node_pt(0);
3981  if (is_inverted[last_ele_pt])
3982  {
3983  last_node_pt = last_ele_pt->node_pt(nnod - 1);
3984  }
3985  } // if (!segment_inverted[final_segment])
3986 
3987  // Get the coordinates for the last node
3988  for (unsigned i = 0; i < 2; i++)
3989  {
3990  flat_packed_double_data_final_seg[i] = last_node_pt->x(i);
3991  }
3992 
3993  // Get the zeta coordinates for the last node
3994  Vector<double> tmp_zeta(1);
3995  last_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3996 
3997  // If there is not a geometric object associated to the boundary
3998  // then further process is required
3999  if (this->boundary_geom_object_pt(b) != 0)
4000  {
4001  // Do nothing
4002  } // if (this->boundary_geom_object_pt(b)!=0)
4003  else
4004  {
4005  // Check if the final boundary coordinate is different from
4006  // the boundary arclength, if that is the case then we need
4007  // to set it to the accumulated arclength
4008  if (std::fabs(tmp_zeta[0] - root_accumulated_arclength) >= 1.0e-14)
4009  {
4010  tmp_zeta[0] = root_accumulated_arclength;
4011  }
4012  } // else if (this->boundary_geom_object_pt(b)!=0)
4013 
4014  // Store the final zeta value
4015  flat_packed_double_data_final_seg[2] = tmp_zeta[0];
4016 
4017  } // if (my_rank == proc_with_final_seg)
4018 
4019  // All processor receive the info. from the processor that has the
4020  // final segment
4021  MPI_Bcast(&flat_packed_double_data_final_seg[0],
4022  ndtotal_data,
4023  MPI_DOUBLE,
4024  proc_with_final_seg,
4025  comm_pt->mpi_comm());
4026 
4027  // All processor receive the info. from the processor that has the
4028  // final segment
4029  for (unsigned i = 0; i < 2; i++)
4030  {
4031  last_coordinate[i] = flat_packed_double_data_final_seg[i];
4032  }
4033  last_node_zeta_coordinate[0] = flat_packed_double_data_final_seg[2];
4034 
4035  // -----------------------------------------------------------------
4036  // Copy the values to the permanent storage
4037  Boundary_initial_coordinate[b] = first_coordinate;
4038  Boundary_final_coordinate[b] = last_coordinate;
4039 
4040  Boundary_initial_zeta_coordinate[b] = first_node_zeta_coordinate;
4041  Boundary_final_zeta_coordinate[b] = last_node_zeta_coordinate;
4042 
4043  // If we are dealing with an internal boundary then re-assign the
4044  // initial and final zeta values for the segments
4045  if (is_internal_boundary)
4046  {
4047  // Only re-assign zeta values if there are at least one nonhalo
4048  // segment, if all the possible segments are halo then the
4049  // synchronisation method will be in charge of assigning the
4050  // correct boundary coordinates
4051  if (nsegments > 0)
4052  {
4053  // Call the following method to re-construct the segments but
4054  // using only the nonhalo elements, therefore the boundary
4055  // coordinates need to be re-assigned
4056  re_assign_initial_zeta_values_for_internal_boundary(
4057  b, segment_sorted_nonhalo_ele_pt, is_inverted);
4058  }
4059 
4060  } // if (is_internal_boundary)
4061 
4062  // Now identify the boundary segments
4063  if (nsegments > 0)
4064  {
4065  // Identify the boundary segments in the current mesh
4066  // identify_boundary_segments_and_assign_initial_zeta_values(
4067  // b, all_face_ele_pt, is_internal_boundary, face_to_bulk_element_pt);
4068  identify_boundary_segments_and_assign_initial_zeta_values(b, this);
4069  } // if (nsegments > 0)
4070 
4071  // Clean all the created face elements
4072  for (unsigned i = 0; i < n_all_face_ele; i++)
4073  {
4074  delete all_face_ele_pt[i];
4075  all_face_ele_pt[i] = 0;
4076  }
4077  }
4078 
4079  //======================================================================
4080  /// Re-assign the boundary segments initial zeta (arclength)
4081  /// for those internal boundaries that were splited during the
4082  /// distribution process. Those boundaries that have one face element
4083  /// at each side of the boundary. Here we create the segments only
4084  /// with the nonhalo elements, therefore the boundary coordinates
4085  /// need to be re-assigned to be passed to the new meshes
4086  //======================================================================
4087  template<class ELEMENT>
4090  const unsigned& b,
4091  Vector<std::list<FiniteElement*>>& old_segment_sorted_ele_pt,
4092  std::map<FiniteElement*, bool>& old_is_inverted)
4093  {
4094  // ------------------------------------------------------------------
4095  // First: Get the face elements associated with the current boundary
4096  // Only include nonhalo face elements
4097  // ------------------------------------------------------------------
4098  // Temporary storage for face elements
4099  Vector<FiniteElement*> face_el_pt;
4100 
4101  // Temporary storage for the number of elements adjacent to the
4102  // boundary
4103  unsigned nele = 0;
4104 
4105  // Temporary storage for elements adjacent to the boundary that have
4106  // a common edge (related with internal boundaries)
4107  unsigned n_repeated_ele = 0;
4108 
4109  const unsigned n_regions = this->nregion();
4110 
4111  // Temporary storage for already done nodes
4112  Vector<std::pair<Node*, Node*>> done_nodes_pt;
4113 
4114  // If there is more than one region then only use boundary
4115  // coordinates from the bulk side (region 0)
4116  if (n_regions > 1)
4117  {
4118  for (unsigned rr = 0; rr < n_regions; rr++)
4119  {
4120  const unsigned region_id =
4121  static_cast<unsigned>(this->Region_attribute[rr]);
4122 
4123  // Loop over all elements on boundaries in region i_r
4124  const unsigned nel_in_region =
4125  this->nboundary_element_in_region(b, region_id);
4126 
4127  unsigned nel_repetead_in_region = 0;
4128 
4129  // Only bother to do anything else, if there are elements
4130  // associated with the boundary and the current region
4131  if (nel_in_region > 0)
4132  {
4133  bool repeated = false;
4134 
4135  // Loop over the bulk elements adjacent to boundary b
4136  for (unsigned e = 0; e < nel_in_region; e++)
4137  {
4138  // Get pointer to the bulk element that is adjacent to
4139  // boundary b
4140  FiniteElement* bulk_elem_pt =
4141  this->boundary_element_in_region_pt(b, region_id, e);
4142 
4143  // Remember only work with non halo elements
4144  if (bulk_elem_pt->is_halo())
4145  {
4146  n_repeated_ele++;
4147  continue;
4148  }
4149 
4150  // Find the index of the face of element e along boundary b
4151  int face_index =
4152  this->face_index_at_boundary_in_region(b, region_id, e);
4153 
4154  // Before adding the new element we need to be sure that the
4155  // edge that this element represent has not been already
4156  // added
4157  FiniteElement* tmp_ele_pt =
4158  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4159 
4160  const unsigned n_nodes = tmp_ele_pt->nnode();
4161 
4162  std::pair<Node*, Node*> tmp_pair = std::make_pair(
4163  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
4164 
4165  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
4166  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
4167 
4168  // Search for repeated nodes
4169  const unsigned repeated_nodes_size = done_nodes_pt.size();
4170  for (unsigned l = 0; l < repeated_nodes_size; l++)
4171  {
4172  if (tmp_pair == done_nodes_pt[l] ||
4173  tmp_pair_inverse == done_nodes_pt[l])
4174  {
4175  nel_repetead_in_region++;
4176  repeated = true;
4177  break;
4178  }
4179  }
4180 
4181  // Create new face element
4182  if (!repeated)
4183  {
4184  // Add the pair of nodes (edge) to the node dones
4185  done_nodes_pt.push_back(tmp_pair);
4186  // Add the element to the face elements
4187  face_el_pt.push_back(tmp_ele_pt);
4188  }
4189  else
4190  {
4191  // Clean up
4192  delete tmp_ele_pt;
4193  tmp_ele_pt = 0;
4194  }
4195 
4196  // Re-start
4197  repeated = false;
4198 
4199  } // for nel
4200 
4201  nele += nel_in_region;
4202 
4203  n_repeated_ele += nel_repetead_in_region;
4204 
4205  } // if (nel_in_region > 0)
4206  } // for (rr < n_regions)
4207  } // if (n_regions > 1)
4208  // Otherwise it's just the normal boundary functions
4209  else
4210  {
4211  // Loop over all elements on boundaries
4212  nele = this->nboundary_element(b);
4213 
4214  // Only bother to do anything else, if there are elements
4215  if (nele > 0)
4216  {
4217  // Check for repeated ones
4218  bool repeated = false;
4219 
4220  // Loop over the bulk elements adjacent to boundary b
4221  for (unsigned e = 0; e < nele; e++)
4222  {
4223  // Get pointer to the bulk element that is adjacent to
4224  // boundary b
4225  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
4226 
4227  // Skip the halo elements, they are not included
4228  if (bulk_elem_pt->is_halo())
4229  {
4230  n_repeated_ele++;
4231  continue;
4232  }
4233 
4234  // Find the index of the face of element e along boundary b
4235  int face_index = this->face_index_at_boundary(b, e);
4236 
4237  // Before adding the new element we need to be sure that the
4238  // edge that this element represents has not been already
4239  // added (only applies for internal boundaries)
4240  FiniteElement* tmp_ele_pt =
4241  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4242 
4243  const unsigned n_nodes = tmp_ele_pt->nnode();
4244 
4245  std::pair<Node*, Node*> tmp_pair = std::make_pair(
4246  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
4247 
4248  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
4249  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
4250 
4251  // Search for repeated nodes
4252  const unsigned repeated_nodes_size = done_nodes_pt.size();
4253  for (unsigned l = 0; l < repeated_nodes_size; l++)
4254  {
4255  if (tmp_pair == done_nodes_pt[l] ||
4256  tmp_pair_inverse == done_nodes_pt[l])
4257  {
4258  // Increase the number of repeated elements
4259  n_repeated_ele++;
4260  // Mark the element as repeated
4261  repeated = true;
4262  break;
4263  }
4264  }
4265 
4266  // Create new face element
4267  if (!repeated)
4268  {
4269  // Add the pair of nodes (edge) to the node dones
4270  done_nodes_pt.push_back(tmp_pair);
4271  // Add the element to the face elements
4272  face_el_pt.push_back(tmp_ele_pt);
4273  }
4274  else
4275  {
4276  // Free the repeated bulk element!!
4277  delete tmp_ele_pt;
4278  tmp_ele_pt = 0;
4279  }
4280 
4281  // Re-start
4282  repeated = false;
4283 
4284  } // for (e < nel)
4285  } // if (nel > 0)
4286 
4287  } // else (n_regions > 1)
4288 
4289  // Do not consider the repeated elements
4290  nele -= n_repeated_ele;
4291 
4292 #ifdef PARANOID
4293  if (nele != face_el_pt.size())
4294  {
4295  std::ostringstream error_message;
4296  error_message
4297  << "The independet counting of face elements (" << nele << ") for "
4298  << "boundary (" << b << ") is different\n"
4299  << "from the real number of face elements in the container ("
4300  << face_el_pt.size() << ")\n";
4301  //<< "Possible memory leak\n"
4302  throw OomphLibError(
4303  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4304  }
4305 #endif
4306 
4307  // ----------------------------------------------------------------
4308  // Second: Sort the face elements, only consider nonhalo elements
4309  // ----------------------------------------------------------------
4310 
4311  // Get the total number of nonhalo face elements
4312  const unsigned nnon_halo_face_elements = face_el_pt.size();
4313 
4314  // The vector of list to store the "segments" that compound the
4315  // boundary (segments may appear only in a distributed mesh)
4316  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
4317 
4318  // Number of already sorted face elements
4319  unsigned nsorted_face_elements = 0;
4320 
4321  // Keep track of who's done
4322  std::map<FiniteElement*, bool> done_el;
4323 
4324  // Keep track of which element is inverted
4325  std::map<FiniteElement*, bool> is_inverted;
4326 
4327  // Iterate until all possible segments have been created
4328  while (nsorted_face_elements < nnon_halo_face_elements)
4329  {
4330  // The ordered list of face elements (in a distributed mesh a
4331  // collection of contiguous face elements define a segment)
4332  std::list<FiniteElement*> sorted_el_pt;
4333 
4334 #ifdef PARANOID
4335  // Select an initial element for the segment
4336  bool found_initial_face_element = false;
4337 #endif
4338 
4339  FiniteElement* ele_face_pt = 0;
4340 
4341  unsigned iface = 0;
4342  for (iface = 0; iface < nele; iface++)
4343  {
4344  ele_face_pt = face_el_pt[iface];
4345  // If not done then take it as initial face element
4346  if (!done_el[ele_face_pt])
4347  {
4348 #ifdef PARANOID
4349  // Mark as found the root face element
4350  found_initial_face_element = true;
4351 #endif
4352  // Increase the number of sorted face elements
4353  nsorted_face_elements++;
4354  // Increase the counter to mark the position of the next
4355  // element number
4356  iface++;
4357  // Add the face element in the list of sorted face elements
4358  sorted_el_pt.push_back(ele_face_pt);
4359  // Mark as done
4360  done_el[ele_face_pt] = true;
4361  break;
4362  } // if (!done_el[ele_face_pt])
4363  } // for (iface < nele)
4364 
4365 #ifdef PARANOID
4366  if (!found_initial_face_element)
4367  {
4368  std::ostringstream error_message;
4369  error_message
4370  << "Could not find an initial face element for the current segment\n";
4371  throw OomphLibError(
4372  error_message.str(),
4373  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4374  OOMPH_EXCEPTION_LOCATION);
4375  }
4376 #endif
4377 
4378  // Number of nodes
4379  const unsigned nnod = ele_face_pt->nnode();
4380 
4381  // Left and rightmost nodes (the left and right nodes of the
4382  // current face element)
4383  Node* left_node_pt = ele_face_pt->node_pt(0);
4384  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
4385 
4386  // Continue iterating if a new face element has been added to the
4387  // list
4388  bool face_element_added = false;
4389 
4390  // While a new face element has been added to the set of sorted
4391  // face elements then re-iterate
4392  do
4393  {
4394  // Start from the next face element since we have already added
4395  // the previous one as the initial face element (any previous
4396  // face element had to be added on previous iterations)
4397  for (unsigned iiface = iface; iiface < nele; iiface++)
4398  {
4399  // Re-start flag
4400  face_element_added = false;
4401 
4402  // Get the candidate element
4403  ele_face_pt = face_el_pt[iiface];
4404 
4405  // Check that the candidate element has not been done and is
4406  // not a halo element
4407  if (!(done_el[ele_face_pt]))
4408  {
4409  // Get the left and right nodes of the current element
4410  Node* local_left_node_pt = ele_face_pt->node_pt(0);
4411  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
4412 
4413  // New element fits at the left of segment and is not inverted
4414  if (left_node_pt == local_right_node_pt)
4415  {
4416  left_node_pt = local_left_node_pt;
4417  sorted_el_pt.push_front(ele_face_pt);
4418  is_inverted[ele_face_pt] = false;
4419  face_element_added = true;
4420  }
4421  // New element fits at the left of segment and is inverted
4422  else if (left_node_pt == local_left_node_pt)
4423  {
4424  left_node_pt = local_right_node_pt;
4425  sorted_el_pt.push_front(ele_face_pt);
4426  is_inverted[ele_face_pt] = true;
4427  face_element_added = true;
4428  }
4429  // New element fits on the right of segment and is not inverted
4430  else if (right_node_pt == local_left_node_pt)
4431  {
4432  right_node_pt = local_right_node_pt;
4433  sorted_el_pt.push_back(ele_face_pt);
4434  is_inverted[ele_face_pt] = false;
4435  face_element_added = true;
4436  }
4437  // New element fits on the right of segment and is inverted
4438  else if (right_node_pt == local_right_node_pt)
4439  {
4440  right_node_pt = local_left_node_pt;
4441  sorted_el_pt.push_back(ele_face_pt);
4442  is_inverted[ele_face_pt] = true;
4443  face_element_added = true;
4444  }
4445 
4446  if (face_element_added)
4447  {
4448  done_el[ele_face_pt] = true;
4449  nsorted_face_elements++;
4450  break;
4451  } // if (face_element_added)
4452 
4453  } // if (!(done_el[ele_face_pt]))
4454 
4455  } // for (iiface<nnon_halo_face_element)
4456 
4457  } while (face_element_added &&
4458  (nsorted_face_elements < nnon_halo_face_elements));
4459 
4460  // Store the created segment in the vector of segments
4461  segment_sorted_ele_pt.push_back(sorted_el_pt);
4462 
4463  } // while(nsorted_face_elements < nnon_halo_face_elements);
4464 
4465  // --------------------------------------------------------------
4466  // Third: We have the face elements sorted, now assign boundary
4467  // coordinates to the nodes in the segments and compute the
4468  // arclength of the segment.
4469  // --------------------------------------------------------------
4470 
4471  // The number of segments in this processor
4472  const unsigned nsegments = segment_sorted_ele_pt.size();
4473 
4474 #ifdef PARANOID
4475  if (nnon_halo_face_elements > 0 && nsegments == 0)
4476  {
4477  std::ostringstream error_message;
4478  error_message
4479  << "The number of segments is zero, but the number of nonhalo\n"
4480  << "elements is: (" << nnon_halo_face_elements << ")\n";
4481  throw OomphLibError(
4482  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
4483  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
4484 #endif
4485 
4486  // Vector of sets that stores the nodes of each segment based on a
4487  // lexicographically order starting from the bottom left node of
4488  // each segment
4489  Vector<std::set<Node*>> segment_all_nodes_pt(nsegments);
4490 
4491  // Stores the nodes on each segment in the order they appear in the
4492  // face elements
4493  Vector<Vector<Node*>> sorted_segment_all_nodes_pt(nsegments);
4494 
4495  // Associate and arclength to each node on each segment of the
4496  // boundary, the nodes and therefore the arclength come in the same
4497  // order as the face elements
4498  Vector<Vector<double>> sorted_segment_node_arclength(nsegments);
4499 
4500  // The arclength of each segment in the current processor
4501  Vector<double> segment_arclength(nsegments);
4502 
4503  // The number of vertices of each segment
4504  Vector<unsigned> nvertices_per_segment(nsegments);
4505 
4506  // The initial zeta for the segment
4507  Vector<double> initial_zeta_segment(nsegments);
4508 
4509  // The final zeta for the segment
4510  Vector<double> final_zeta_segment(nsegments);
4511 
4512  // Go through all the segments and compute the LOCAL boundary
4513  // coordinates
4514  for (unsigned is = 0; is < nsegments; is++)
4515  {
4516 #ifdef PARANOID
4517  if (segment_sorted_ele_pt[is].size() == 0)
4518  {
4519  std::ostringstream error_message;
4520  error_message << "The (" << is << ")-th segment has no elements\n";
4521  throw OomphLibError(
4522  error_message.str(),
4523  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4524  OOMPH_EXCEPTION_LOCATION);
4525  } // if (segment_sorted_ele_pt[is].size() == 0)
4526 #endif
4527 
4528  // Get access to the first element on the segment
4529  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
4530 
4531  // Number of nodes
4532  const unsigned nnod = first_ele_pt->nnode();
4533 
4534  // Get the first node of the current segment
4535  Node* first_node_pt = first_ele_pt->node_pt(0);
4536  if (is_inverted[first_ele_pt])
4537  {
4538  first_node_pt = first_ele_pt->node_pt(nnod - 1);
4539  }
4540 
4541  // Coordinates of left node
4542  double x_left = first_node_pt->x(0);
4543  double y_left = first_node_pt->x(1);
4544 
4545  // Initialise boundary coordinate (local boundary coordinate for
4546  // boundaries with more than one segment)
4547  Vector<double> zeta(1, 0.0);
4548 
4549  // If we have associated a GeomObject then it is not necessary
4550  // to compute the arclength, only read the values from the nodes at
4551  // the edges
4552  if (this->boundary_geom_object_pt(b) != 0)
4553  {
4554  first_node_pt->get_coordinates_on_boundary(b, zeta);
4555  initial_zeta_segment[is] = zeta[0];
4556 
4557  // Get access to the last element on the segment
4558  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
4559 
4560  // Get the last node of the current segment
4561  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
4562  if (is_inverted[last_ele_pt])
4563  {
4564  last_node_pt = last_ele_pt->node_pt(0);
4565  }
4566 
4567  last_node_pt->get_coordinates_on_boundary(b, zeta);
4568  final_zeta_segment[is] = zeta[0];
4569  }
4570 
4571  // Sort the nodes in the segment (lexicographically bottom left
4572  // node)
4573  std::set<Node*> local_nodes_pt;
4574  local_nodes_pt.insert(first_node_pt);
4575 
4576  // Associate and arclength to the sorted nodes
4577  Vector<double> sorted_node_arclength;
4578  sorted_node_arclength.push_back(0.0);
4579 
4580  // Sorts the nodes in the segments according their sorting in the
4581  // face elements
4582  Vector<Node*> sorted_nodes_pt;
4583  sorted_nodes_pt.push_back(first_node_pt);
4584 
4585  // Now loop over nodes in order
4586  for (std::list<FiniteElement*>::iterator it =
4587  segment_sorted_ele_pt[is].begin();
4588  it != segment_sorted_ele_pt[is].end();
4589  it++)
4590  {
4591  // Get the face element
4592  FiniteElement* el_pt = *it;
4593 
4594  // Start node and increment
4595  unsigned k_nod = 1;
4596  int nod_diff = 1;
4597  if (is_inverted[el_pt])
4598  {
4599  k_nod = nnod - 2;
4600  nod_diff = -1;
4601  }
4602 
4603  // Loop over nodes
4604  for (unsigned j = 1; j < nnod; j++)
4605  {
4606  Node* nod_pt = el_pt->node_pt(k_nod);
4607  k_nod += nod_diff;
4608 
4609  // Coordinates of right node
4610  double x_right = nod_pt->x(0);
4611  double y_right = nod_pt->x(1);
4612 
4613  // Increment boundary coordinate
4614  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
4615  (y_right - y_left) * (y_right - y_left));
4616 
4617  // When we have a GeomObject associated to the boundary we already
4618  // know the zeta values for the nodes, there is no need to compute
4619  // the arclength
4620  if (this->boundary_geom_object_pt(b) == 0)
4621  {
4622  // Set boundary coordinate
4623  // nod_pt->set_coordinates_on_boundary(b, zeta);
4624  }
4625 
4626  // Increment reference coordinate
4627  x_left = x_right;
4628  y_left = y_right;
4629 
4630  // Get lexicographically bottom left node but only
4631  // use vertex nodes as candidates
4632  local_nodes_pt.insert(nod_pt);
4633 
4634  // Associate the arclength for the current node
4635  sorted_node_arclength.push_back(zeta[0]);
4636 
4637  // Store the node in the sorted nodes storage
4638  sorted_nodes_pt.push_back(nod_pt);
4639 
4640  } // for (j < nnod)
4641 
4642  } // iterator over the elements in the segment
4643 
4644  // Info. to be passed to the other processors
4645  // The initial arclength for the segment that goes after this depends
4646  // on the current segment arclength
4647  segment_arclength[is] = zeta[0];
4648 
4649  // Info. to be passed to the other processors
4650  // The initial vertex number for the segment that goes after this
4651  // depends on the current sement vertices number
4652  nvertices_per_segment[is] = local_nodes_pt.size();
4653 
4654  // Add the nodes for the corresponding segment in the container
4655  segment_all_nodes_pt[is] = local_nodes_pt;
4656 
4657  // Add the arclengths to the nodes in the segment
4658  sorted_segment_node_arclength[is] = sorted_node_arclength;
4659 
4660  // Add the sorted nodes to the storage
4661  sorted_segment_all_nodes_pt[is] = sorted_nodes_pt;
4662 
4663  // The attaching of the halo elements at both sides of the segments is
4664  // performed only if segments connectivity needs to be computed
4665 
4666  } // for (is < nsegments)
4667 
4668  // ------------------------------------------------------------------
4669  // Fourth: Now we have the segments sorted, with arclength and with
4670  // LOCAL boundary coordinates assigned to the nodes. Identify the
4671  // nodes on the segments with the input segments and re-assign all
4672  // the info. related with the identification of segments
4673  // ------------------------------------------------------------------
4674 
4675  // Get the number of segments for the old sorted segments
4676  const unsigned old_nsegments = old_segment_sorted_ele_pt.size();
4677 
4678  // ------------------------------------------------------------------
4679  // Copy the old info. in temporary storages
4680  Vector<unsigned> old_boundary_segment_inverted(old_nsegments);
4681 
4682  Vector<Vector<double>> old_boundary_segment_initial_coordinate(
4683  old_nsegments);
4684  Vector<Vector<double>> old_boundary_segment_final_coordinate(old_nsegments);
4685 
4686  Vector<double> old_boundary_segment_initial_zeta(old_nsegments);
4687  Vector<double> old_boundary_segment_final_zeta(old_nsegments);
4688 
4689  Vector<double> old_boundary_segment_initial_arclength(old_nsegments);
4690  Vector<double> old_boundary_segment_final_arclength(old_nsegments);
4691 
4692  // Back-up the information
4693  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4694  {
4695  old_boundary_segment_inverted[old_is] =
4696  boundary_segment_inverted(b)[old_is];
4697 
4698  old_boundary_segment_initial_coordinate[old_is].resize(2);
4699  old_boundary_segment_final_coordinate[old_is].resize(2);
4700  for (unsigned i = 0; i < 2; i++)
4701  {
4702  old_boundary_segment_initial_coordinate[old_is][i] =
4703  boundary_segment_initial_coordinate(b)[old_is][i];
4704 
4705  old_boundary_segment_final_coordinate[old_is][i] =
4706  boundary_segment_final_coordinate(b)[old_is][i];
4707  }
4708 
4709  // Check if the boundary has an associated GeomObject
4710  if (this->boundary_geom_object_pt(b) != 0)
4711  {
4712  old_boundary_segment_initial_zeta[old_is] =
4713  boundary_segment_initial_zeta(b)[old_is];
4714 
4715  old_boundary_segment_final_zeta[old_is] =
4716  boundary_segment_final_zeta(b)[old_is];
4717 
4718  } // if (this->boundary_geom_object_pt(b)!=0)
4719  else
4720  {
4721  old_boundary_segment_initial_arclength[old_is] =
4722  boundary_segment_initial_arclength(b)[old_is];
4723 
4724  old_boundary_segment_final_arclength[old_is] =
4725  boundary_segment_final_arclength(b)[old_is];
4726 
4727  } // else if (this->boundary_geom_object_pt(b)!=0)
4728 
4729  } // for (old_is < old_nsegments)
4730 
4731  // ------------------------------------------------------------------
4732  // Now clear the original storages
4733  Boundary_segment_inverted[b].clear();
4734  Boundary_segment_initial_coordinate[b].clear();
4735  Boundary_segment_final_coordinate[b].clear();
4736 
4737  Boundary_segment_initial_zeta[b].clear();
4738  Boundary_segment_final_zeta[b].clear();
4739 
4740  Boundary_segment_initial_arclength[b].clear();
4741  Boundary_segment_final_arclength[b].clear();
4742  // ------------------------------------------------------------------
4743  // .. and resize the storages for the new number of segments
4744  Boundary_segment_inverted[b].resize(nsegments);
4745  Boundary_segment_initial_coordinate[b].resize(nsegments);
4746  Boundary_segment_final_coordinate[b].resize(nsegments);
4747 
4748  // Check if the boundary has an associated GeomObject
4749  if (this->boundary_geom_object_pt(b) != 0)
4750  {
4751  Boundary_segment_initial_zeta[b].resize(nsegments);
4752  Boundary_segment_final_zeta[b].resize(nsegments);
4753  }
4754  else
4755  {
4756  Boundary_segment_initial_arclength[b].resize(nsegments);
4757  Boundary_segment_final_arclength[b].resize(nsegments);
4758  }
4759  // ------------------------------------------------------------------
4760  // map to know if the new segment has been re-assigned the info.
4761  std::map<unsigned, bool> done_segment;
4762 
4763  // Count the number of re-assigned segments with the new values
4764  unsigned re_assigned_segments = 0;
4765 
4766  // Go through all the old segments (the input segments)
4767  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4768  {
4769  // Get the first and last zeta values for the current segment
4770  const double old_initial_arclength =
4771  old_boundary_segment_initial_arclength[old_is];
4772  const double old_final_arclength =
4773  old_boundary_segment_final_arclength[old_is];
4774  // Get the "is inverted" segment information
4775  const unsigned old_inverted_segment =
4776  old_boundary_segment_inverted[old_is];
4777 
4778  // Check if the boundary coordinates in the segment go in
4779  // increasing or decreasing order
4780  bool old_increasing_order = false;
4781  if (old_initial_arclength < old_final_arclength)
4782  {
4783  old_increasing_order = true;
4784  }
4785 
4786  // Now get the first and last node of the current segment
4787  // Get the first element
4788  FiniteElement* first_old_seg_ele_pt =
4789  old_segment_sorted_ele_pt[old_is].front();
4790 
4791  // Number of nodes
4792  const unsigned nnod = first_old_seg_ele_pt->nnode();
4793 
4794  // Get the first node of the current segment
4795  Node* first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(0);
4796  if (old_is_inverted[first_old_seg_ele_pt])
4797  {
4798  first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(nnod - 1);
4799  }
4800 
4801  // Get access to the last element on the segment
4802  FiniteElement* last_old_seg_ele_pt =
4803  old_segment_sorted_ele_pt[old_is].back();
4804 
4805  // Get the last node of the current segment
4806  Node* last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(nnod - 1);
4807  if (old_is_inverted[last_old_seg_ele_pt])
4808  {
4809  last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(0);
4810  }
4811  // Check if the segment is inverted, if that is the case then
4812  // also invert the nodes
4813  if (old_inverted_segment)
4814  {
4815  Node* temp_node_pt = first_old_seg_node_pt;
4816  first_old_seg_node_pt = last_old_seg_node_pt;
4817  last_old_seg_node_pt = temp_node_pt;
4818  }
4819 
4820  // We have the first and last node of the old segment (input
4821  // segment), now identify in which segment, of those with only
4822  // nonhalo face elements, they are
4823  for (unsigned is = 0; is < nsegments; is++)
4824  {
4825  if (!done_segment[is])
4826  {
4827  // Go through the nodes of the current segment and try to find
4828  // the old nodes
4829  bool found_first_old_seg_node = false;
4830  bool found_last_old_seg_node = false;
4831  bool same_order = false;
4832 
4833  // Get the first node of the current segment
4834  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
4835  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
4836  if (is_inverted[first_seg_ele_pt])
4837  {
4838  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod - 1);
4839  }
4840 
4841  // Get the arclength for the first node
4842  const double segment_first_node_zeta =
4843  sorted_segment_node_arclength[is][0];
4844 
4845  // Get the node coordinates for the first node
4846  Vector<double> first_node_coord(2);
4847  for (unsigned i = 0; i < 2; i++)
4848  {
4849  first_node_coord[i] = first_seg_node_pt->x(i);
4850  }
4851 
4852  // Get the last node of the current segment
4853  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
4854  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod - 1);
4855  if (is_inverted[last_seg_ele_pt])
4856  {
4857  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
4858  }
4859 
4860  // Get the arclength for the last node
4861  const double segment_final_node_zeta = segment_arclength[is];
4862 
4863  // Get the node coordinates for the last node
4864  Vector<double> last_node_coord(2);
4865  for (unsigned i = 0; i < 2; i++)
4866  {
4867  last_node_coord[i] = last_seg_node_pt->x(i);
4868  }
4869 
4870  // Temporary storage for the nodes of the current segment
4871  Vector<Node*> segment_node_pt = sorted_segment_all_nodes_pt[is];
4872  // Get the number of nodes in the segment
4873  const unsigned nsegment_node = segment_node_pt.size();
4874  for (unsigned in = 0; in < nsegment_node; in++)
4875  {
4876  Node* current_node_pt = segment_node_pt[in];
4877  if (!found_first_old_seg_node &&
4878  first_old_seg_node_pt == current_node_pt)
4879  {
4880  // Get the arclength assigned to the node on the old
4881  // segment
4882  const double current_node_zeta =
4883  sorted_segment_node_arclength[is][in];
4884 
4885  // Now check if the new segment has the same orientation
4886  // as the old one
4887  if (!found_last_old_seg_node) // has the same orientation
4888  {
4889  // Re-assign the first node coordinates
4890  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
4891 
4892  // Check if the boundary has an associated GeomObject
4893  if (this->boundary_geom_object_pt(b) != 0)
4894  {
4895  // Assign the zeta values if the current segment has the
4896  // nodes of the old one
4897 
4898  // If we are in the same order then pass the values as
4899  // they are
4900  Boundary_segment_initial_zeta[b][is] =
4901  initial_zeta_segment[is];
4902 
4903  } // if (this->boundary_geom_object_pt(b)!=0)
4904  else
4905  {
4906  // Get the distance to the first node
4907  const double distance =
4908  std::fabs(current_node_zeta - segment_first_node_zeta);
4909 
4910  double new_initial_arclength = old_initial_arclength;
4911 
4912  // Now check if the zeta values are in increasing order
4913  if (old_increasing_order)
4914  {
4915  // Substract the distance
4916  new_initial_arclength -= distance;
4917  }
4918  else
4919  {
4920  // Add the distance
4921  new_initial_arclength += distance;
4922  }
4923 
4924  // Re-assign the initial arclength for the current segment
4925  Boundary_segment_initial_arclength[b][is] =
4926  new_initial_arclength;
4927 
4928  } // else if (this->boundary_geom_object_pt(b)!=0)
4929  } // if (!found_last_old_seg_node)
4930  else // has different orientation
4931  {
4932  // Re-assign the first node coordinates
4933  Boundary_segment_initial_coordinate[b][is] = last_node_coord;
4934 
4935  // Check if the boundary has an associated GeomObject
4936  if (this->boundary_geom_object_pt(b) != 0)
4937  {
4938  // Assign the zeta values if the current segment has the
4939  // nodes of the old one
4940 
4941  // Not the same order, we need to copy the zeta values
4942  // from the other end, the inverted flag is changed at
4943  // the end. Copy the value from the final end
4944  Boundary_segment_initial_zeta[b][is] = final_zeta_segment[is];
4945 
4946  } // if (this->boundary_geom_object_pt(b)!=0)
4947  else
4948  {
4949  // Get the distance to the final node
4950  const double distance =
4951  std::fabs(current_node_zeta - segment_final_node_zeta);
4952 
4953  double new_initial_arclength = old_initial_arclength;
4954 
4955  // Now check if the zeta values are in increasing order
4956  if (old_increasing_order)
4957  {
4958  // Substract the distance
4959  new_initial_arclength -= distance;
4960  }
4961  else
4962  {
4963  // Add the distance
4964  new_initial_arclength += distance;
4965  }
4966 
4967  // Re-assign the initial arclength for the current segment
4968  Boundary_segment_initial_arclength[b][is] =
4969  new_initial_arclength;
4970 
4971  } // else if (this->boundary_geom_object_pt(b)!=0)
4972  } // else if (!found_last_old_seg_node)
4973 
4974  // Mark as found the first node
4975  found_first_old_seg_node = true;
4976  }
4977  // if (!found_first_old_seg_node &&
4978  // first_old_seg_node_pt == current_node_pt)
4979 
4980  // If we found first the first node then the segments have
4981  // the same order
4982  if (found_first_old_seg_node && !found_last_old_seg_node)
4983  {
4984  same_order = true;
4985  }
4986 
4987  if (!found_last_old_seg_node &&
4988  last_old_seg_node_pt == current_node_pt)
4989  {
4990  // Get the boundary coordinates assigned to the node on
4991  // the old segment
4992  const double current_node_zeta =
4993  sorted_segment_node_arclength[is][in];
4994 
4995  // Now check if the new segment has the same orientation
4996  // as the old one
4997  if (found_first_old_seg_node) // has the same orientation
4998  {
4999  // Re-assign the last node coordinates
5000  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5001 
5002  // Check if the boundary has an associated GeomObject
5003  if (this->boundary_geom_object_pt(b) != 0)
5004  {
5005  // Assign the zeta values if the current segment has the
5006  // nodes of the old one
5007 
5008  // If we are in the same order then pass the values as
5009  // they are
5010  Boundary_segment_final_zeta[b][is] = final_zeta_segment[is];
5011 
5012  } // if (this->boundary_geom_object_pt(b)!=0)
5013  else
5014  {
5015  // Get the distance to the last node
5016  const double distance =
5017  std::fabs(current_node_zeta - segment_final_node_zeta);
5018 
5019  double new_final_arclength = old_final_arclength;
5020 
5021  // Now check if the zeta values are in increasing order
5022  if (old_increasing_order)
5023  {
5024  // Add the distance
5025  new_final_arclength += distance;
5026  }
5027  else
5028  {
5029  // Substract the distance
5030  new_final_arclength -= distance;
5031  }
5032 
5033  // Re-assign the final arclength for the current segment
5034  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5035 
5036  } // else if (this->boundary_geom_object_pt(b)!=0)
5037  } // if (found_first_old_seg_node)
5038  else
5039  {
5040  // Re-assign the last node coordinates
5041  Boundary_segment_final_coordinate[b][is] = first_node_coord;
5042 
5043  // Check if the boundary has an associated GeomObject
5044  if (this->boundary_geom_object_pt(b) != 0)
5045  {
5046  // Assign the zeta values if the current segment has the
5047  // nodes of the old one
5048 
5049  // Not the same order, we need to copy the zeta values
5050  // from the other end, the inverted flag is changed at
5051  // the end. Copy the value from the initial end
5052  Boundary_segment_final_zeta[b][is] = initial_zeta_segment[is];
5053 
5054  } // if (this->boundary_geom_object_pt(b)!=0)
5055  else
5056  {
5057  // Get the distance to the last node
5058  const double distance =
5059  std::fabs(current_node_zeta - segment_first_node_zeta);
5060 
5061  double new_final_arclength = old_final_arclength;
5062 
5063  // Now check if the zeta values are in increasing order
5064  if (old_increasing_order)
5065  {
5066  // Add the distance
5067  new_final_arclength += distance;
5068  }
5069  else
5070  {
5071  // Substract the distance
5072  new_final_arclength -= distance;
5073  }
5074 
5075  // Re-assign the final arclength for the current segment
5076  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5077 
5078  } // else if (this->boundary_geom_object_pt(b)!=0)
5079  } // if (found_first_old_seg_node)
5080 
5081  // Mark as found the last node
5082  found_last_old_seg_node = true;
5083 
5084  } // if (!found_last_old_seg_node &&
5085  // last_old_seg_node_pt == current_node_pt)
5086 
5087  // If we found the last node first then the segments have
5088  // not the same order
5089  if (!found_first_old_seg_node && found_last_old_seg_node)
5090  {
5091  same_order = false;
5092  }
5093 
5094  if (found_first_old_seg_node && found_last_old_seg_node)
5095  {
5096  // Check if necessary to change the information that
5097  // states if a segment is inverted or not
5098  if (same_order)
5099  {
5100  Boundary_segment_inverted[b][is] = old_inverted_segment;
5101  }
5102  else
5103  {
5104  Boundary_segment_inverted[b][is] = !old_inverted_segment;
5105  }
5106 
5107  // Mark the segment as done
5108  done_segment[is] = true;
5109 
5110  // Increase the number of re-assigned segments
5111  re_assigned_segments++;
5112 
5113  // Break the for that look for the nodes in the segments
5114  break;
5115  }
5116 
5117  } // for (in < nsegment_node)
5118 
5119 #ifdef PARANOID
5120  if ((found_first_old_seg_node && !found_last_old_seg_node) ||
5121  (!found_first_old_seg_node && found_last_old_seg_node))
5122  {
5123  std::stringstream error_message;
5124  error_message
5125  << "Working with boundary (" << b << ").\nOnly the first node or "
5126  << "the last node of the old segment (" << old_is << ") was\n"
5127  << "found. Both, first and last node should have been found in "
5128  << "the same segment!!!.\n"
5129  << "Found first seg node:" << found_first_old_seg_node << "\n"
5130  << "Found last seg node:" << found_last_old_seg_node << "\n\n";
5131  throw OomphLibError(error_message.str(),
5132  "TriangleMesh::re_assign_initial_zeta_values_"
5133  "for_internal_boundary()",
5134  OOMPH_EXCEPTION_LOCATION);
5135  }
5136 #endif
5137 
5138  } // if (!done_segment[is])
5139  } // for (is < nsegments)
5140  } // for (old_is < old_nsegments)
5141 
5142  // For those segments not identified set dummy values, the boundary
5143  // coordinates should be corrected at the synchronisation stage
5144 
5145  // loop over the new segments and check if there not identified
5146  // segments
5147  for (unsigned is = 0; is < nsegments; is++)
5148  {
5149  // Was the segment identified
5150  if (!done_segment[is])
5151  {
5152  // Get the first node of the current segment
5153  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
5154  // Number of nodes
5155  const unsigned nnod = first_seg_ele_pt->nnode();
5156 
5157  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
5158  if (is_inverted[first_seg_ele_pt])
5159  {
5160  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod - 1);
5161  }
5162 
5163  // Get the arclength for the first node
5164  const double segment_first_node_zeta =
5165  sorted_segment_node_arclength[is][0];
5166 
5167  // Get the node coordinates for the first node
5168  Vector<double> first_node_coord(2);
5169  for (unsigned i = 0; i < 2; i++)
5170  {
5171  first_node_coord[i] = first_seg_node_pt->x(i);
5172  }
5173 
5174  // Get the last node of the current segment
5175  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
5176  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod - 1);
5177  if (is_inverted[last_seg_ele_pt])
5178  {
5179  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
5180  }
5181 
5182  // Get the arclength for the last node
5183  const double segment_final_node_zeta = segment_arclength[is];
5184 
5185  // Get the node coordinates for the last node
5186  Vector<double> last_node_coord(2);
5187  for (unsigned i = 0; i < 2; i++)
5188  {
5189  last_node_coord[i] = last_seg_node_pt->x(i);
5190  }
5191 
5192  // Re-assign the initial node coordinates
5193  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
5194 
5195  // Check if the boundary has an associated GeomObject
5196  if (this->boundary_geom_object_pt(b) != 0)
5197  {
5198  // Assign the zeta values if the current segment has the
5199  // nodes of the old one
5200 
5201  // If we are in the same order then pass the values as
5202  // they are
5203  Boundary_segment_initial_zeta[b][is] = initial_zeta_segment[is];
5204 
5205  } // if (this->boundary_geom_object_pt(b)!=0)
5206  else
5207  {
5208  // Re-assign the initial arclength for the current segment
5209  Boundary_segment_initial_arclength[b][is] = segment_first_node_zeta;
5210 
5211  } // else if (this->boundary_geom_object_pt(b)!=0)
5212 
5213  // Re-assign the initial node coordinates
5214  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5215 
5216  // Check if the boundary has an associated GeomObject
5217  if (this->boundary_geom_object_pt(b) != 0)
5218  {
5219  // Assign the zeta values if the current segment has the
5220  // nodes of the old one
5221 
5222  // If we are in the same order then pass the values as
5223  // they are
5224  Boundary_segment_final_zeta[b][is] = final_zeta_segment[is];
5225 
5226  } // if (this->boundary_geom_object_pt(b)!=0)
5227  else
5228  {
5229  // Re-assign the final arclength for the current segment
5230  Boundary_segment_final_arclength[b][is] = segment_final_node_zeta;
5231 
5232  } // else if (this->boundary_geom_object_pt(b)!=0)
5233 
5234  Boundary_segment_inverted[b][is] = 0;
5235 
5236  // Mark the segment as done
5237  done_segment[is] = true;
5238 
5239  // Increase the number of re-assigned segments
5240  re_assigned_segments++;
5241 
5242  } // if (!done_segment[is])
5243 
5244  } // for (is < nsegments)
5245 
5246 #ifdef PARANOID
5247  // Compare the number of new segments identified with the old segments
5248  if (re_assigned_segments != nsegments)
5249  {
5250  std::stringstream error_message;
5251  error_message << "Working with boundary (" << b
5252  << ").\nThe number of re-assigned "
5253  << "segments (" << re_assigned_segments
5254  << ") is different from the number\nof segments ("
5255  << nsegments << ")\n\n";
5256  throw OomphLibError(
5257  error_message.str(),
5258  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5259  OOMPH_EXCEPTION_LOCATION);
5260  } // if (re_assigned_segments != nsegments)
5261 #endif
5262 
5263  // Clean all the created face elements
5264  for (unsigned i = 0; i < nele; i++)
5265  {
5266  delete face_el_pt[i];
5267  face_el_pt[i] = 0;
5268  }
5269  }
5270 
5271  /// =====================================================================
5272  /// Select face elements from a given boundary. In case the we are
5273  /// dealing with an internal boundary we use a set of criterias to
5274  /// decide which of the two face elements should be used on represent
5275  /// the internal boundary. We return the face elements, halo or
5276  /// haloed on this processor that form the boundary. The caller method
5277  /// should be in charge of selecting nonhalo elements and deleting the face
5278  /// elements created by this method
5279  /// =====================================================================
5280  template<class ELEMENT>
5282  Vector<FiniteElement*>& face_ele_pt,
5283  const unsigned& b,
5284  bool& is_internal_boundary,
5285  std::map<FiniteElement*, FiniteElement*>& face_to_bulk_element_pt)
5286  {
5287  // Get the communicator of the mesh
5288  OomphCommunicator* comm_pt = this->communicator_pt();
5289 
5290  const unsigned my_rank = comm_pt->my_rank();
5291 
5292  // ------------------------------------------------------------------
5293  // 1) Get the face elements associated with the current boundary
5294  // ------------------------------------------------------------------
5295 
5296  // Temporary storage for face elements (do not take care of
5297  // repeated face elements)
5298  Vector<FiniteElement*> tmp_face_ele_pt;
5299 
5300  const unsigned nregions = this->nregion();
5301 
5302  // If there is more than one region then only use boundary
5303  // coordinates from the bulk side (region 0)
5304  if (nregions > 1)
5305  {
5306  for (unsigned ir = 0; ir < nregions; ir++)
5307  {
5308  const unsigned region_id =
5309  static_cast<unsigned>(this->Region_attribute[ir]);
5310 
5311  // Loop over all elements on boundaries in region -ir-
5312  const unsigned nele_in_region =
5313  this->nboundary_element_in_region(b, region_id);
5314 
5315  // Only bother to do anything else, if there are elements
5316  // associated with the boundary and the current region
5317  if (nele_in_region > 0)
5318  {
5319  // Loop over the bulk elements adjacent to boundary b
5320  for (unsigned e = 0; e < nele_in_region; e++)
5321  {
5322  // Get pointer to the bulk element that is adjacent
5323  // to boundary b
5324  FiniteElement* bulk_ele_pt =
5325  this->boundary_element_in_region_pt(b, region_id, e);
5326 
5327  // Get the index of the face of element e along
5328  // boundary b
5329  int face_index =
5330  this->face_index_at_boundary_in_region(b, region_id, e);
5331 
5332  // Create the face element
5333  FiniteElement* tmp_face_el_pt =
5334  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5335 
5336  // Associated the face element with the bulk
5337  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5338 
5339  // ... and add it to the tmp storage for all the
5340  // face elements, do not take care for repeated
5341  // ones (at the moment)
5342  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5343 
5344  } // for (e < nele_in_region)
5345 
5346  } // if (nele_in_region > 0)
5347 
5348  } // for (ir < n_regions)
5349 
5350  } // if (n_regions > 1)
5351 
5352  // Otherwise it's just the normal boundary functions
5353  else
5354  {
5355  // Loop over all elements on boundaries
5356  const unsigned nbound_ele = this->nboundary_element(b);
5357 
5358  // Only bother to do anything else, if there are elements
5359  if (nbound_ele > 0)
5360  {
5361  // Loop over the bulk elements adjacent to boundary b
5362  for (unsigned e = 0; e < nbound_ele; e++)
5363  {
5364  // Get pointer to the bulk element that is adjacent to
5365  // boundary b
5366  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5367 
5368  // Get the index of the face of element e along
5369  // boundary b
5370  int face_index = this->face_index_at_boundary(b, e);
5371 
5372  // Create the face element
5373  FiniteElement* tmp_face_el_pt =
5374  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5375 
5376  // Associated the face element with the bulk
5377  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5378 
5379  // ... and add it to the tmp storage for all the face
5380  // elements, do not care for repeated ones (at the
5381  // moment)
5382  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5383 
5384  } // (e < nbound_ele)
5385 
5386  } // (nbound_ele > 0)
5387 
5388  } // else (n_regions > 1)
5389 
5390  // map to know which face element has been already done
5391  std::map<FiniteElement*, bool> done_face;
5392 
5393  // Set the flag to indicate if we are working with an internal
5394  // boundary
5395  is_internal_boundary = false;
5396 
5397  // Free the memory of the elements in this container (only used
5398  // when working with internal boundaries)
5399  Vector<FiniteElement*> free_memory_face_ele_pt;
5400 
5401  // Get the number of face elements in the boundary (including
5402  // repeated)
5403  const unsigned n_tmp_face_ele = tmp_face_ele_pt.size();
5404  for (unsigned ie = 0; ie < n_tmp_face_ele; ie++)
5405  {
5406  // Get the possible main element
5407  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5408  if (!done_face[main_face_ele_pt])
5409  {
5410  // Mark the face element as done
5411  done_face[main_face_ele_pt] = true;
5412  // Get the number of nodes for the face element
5413  const unsigned nnodes = main_face_ele_pt->nnode();
5414  // Get the first and last node of the main face element
5415  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5416  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes - 1);
5417  // Look for the other side face element (we can start from
5418  // the next one, all previous face elements have been
5419  // already identified with its other side face)
5420  for (unsigned iie = ie + 1; iie < n_tmp_face_ele; iie++)
5421  {
5422  // Get the possible dependant element
5423  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5424  if (!done_face[dependant_face_ele_pt])
5425  {
5426  // Get the first and last node of the dependant
5427  // face element
5428  Node* dependant_first_node_pt = dependant_face_ele_pt->node_pt(0);
5429  Node* dependant_last_node_pt =
5430  dependant_face_ele_pt->node_pt(nnodes - 1);
5431  // Check if the nodes at the ends of both face
5432  // elements match (also check the reversed case)
5433  if (((dependant_first_node_pt == main_first_node_pt) &&
5434  (dependant_last_node_pt == main_last_node_pt)) ||
5435  ((dependant_first_node_pt == main_last_node_pt) &&
5436  (dependant_last_node_pt == main_first_node_pt)))
5437  {
5438  // Set the flag to indicate we are working with an
5439  // internal boundary
5440  is_internal_boundary = true;
5441  // Mark the face element as done
5442  done_face[dependant_face_ele_pt] = true;
5443 
5444  // Now choose which face element will be used
5445  // as the main element. We get the processor in
5446  // charge of the element and choose the one
5447  // with the highest processor in charge or the
5448  // bottom-left bulk element in case the both
5449  // faces are on the same processor
5450 
5451  // Get the bulk element for each face element
5452  // (the main and the dependant face element)
5453  FiniteElement* main_bulk_ele_pt =
5454  face_to_bulk_element_pt[main_face_ele_pt];
5455  FiniteElement* dependant_bulk_ele_pt =
5456  face_to_bulk_element_pt[dependant_face_ele_pt];
5457 
5458  // Get the processor in charge for each bulk
5459  // element
5460  int processor_in_charge_main_bulk_ele =
5461  main_bulk_ele_pt->non_halo_proc_ID();
5462  int processor_in_charge_dependant_bulk_ele =
5463  dependant_bulk_ele_pt->non_halo_proc_ID();
5464 
5465  // If the processor in charge is negative the
5466  // element is not halo, therefore the processor
5467  // in charge is the current one
5468  if (processor_in_charge_main_bulk_ele < 0)
5469  {
5470  processor_in_charge_main_bulk_ele = static_cast<int>(my_rank);
5471  }
5472  if (processor_in_charge_dependant_bulk_ele < 0)
5473  {
5474  processor_in_charge_dependant_bulk_ele =
5475  static_cast<int>(my_rank);
5476  }
5477 
5478  // Flag to know if add the main or dependant
5479  // face element
5480  bool add_main_face_element = true;
5481  if (processor_in_charge_dependant_bulk_ele >
5482  processor_in_charge_main_bulk_ele)
5483  {
5484  // Include the dependant element
5485  add_main_face_element = false;
5486  }
5487  else if (processor_in_charge_main_bulk_ele ==
5488  processor_in_charge_dependant_bulk_ele)
5489  {
5490  // When the processor in charge for both
5491  // elements is the same then use the
5492  // bottom-left criteria on the bulk
5493  // elements to choose the main face element
5494  Vector<double> main_ele_coordinates(2);
5495  Vector<double> dependant_ele_coordinates(2);
5496  // Get the number of nodes on the bulk
5497  // elements
5498  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5499  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5500  {
5501  for (unsigned idim = 0; idim < 2; idim++)
5502  {
5503  main_ele_coordinates[idim] +=
5504  main_bulk_ele_pt->node_pt(inode)->x(idim);
5505  dependant_ele_coordinates[idim] +=
5506  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5507  } // (idim < 2)
5508 
5509  } // (inode < n_bulk_nodes)
5510 
5511  // Get the average of the nodes coordinates
5512  for (unsigned idim = 0; idim < 2; idim++)
5513  {
5514  main_ele_coordinates[idim] /= (double)n_bulk_nodes;
5515  dependant_ele_coordinates[idim] /= (double)n_bulk_nodes;
5516  }
5517 
5518  // Once we know the average coordinates for
5519  // each element then we choose the one with
5520  // the bottom-left averaged coordinates
5521  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5522  {
5523  add_main_face_element = false;
5524  }
5525  else if (dependant_ele_coordinates[1] ==
5526  main_ele_coordinates[1])
5527  {
5528  // The left-most element
5529  if (dependant_ele_coordinates[0] < main_ele_coordinates[0])
5530  {
5531  add_main_face_element = false;
5532  }
5533  }
5534  } // else -- The processor in charge is the
5535  // same for both elements
5536 
5537  if (add_main_face_element)
5538  {
5539  // Add the main face element to the storage
5540  // so we get the halo and haloed nodes from
5541  // it
5542  face_ele_pt.push_back(main_face_ele_pt);
5543  // Mark the dependat face element to free
5544  // its memory
5545  free_memory_face_ele_pt.push_back(dependant_face_ele_pt);
5546  }
5547  else
5548  {
5549  // Add the dependant face element to the
5550  // storage so we get the halo and haloed
5551  // nodes from it
5552  face_ele_pt.push_back(dependant_face_ele_pt);
5553  // Mark the main face element to free its
5554  // memory
5555  free_memory_face_ele_pt.push_back(main_face_ele_pt);
5556  }
5557 
5558  // Break the for to look for the next face
5559  // element
5560  break;
5561 
5562  } // if -- matching of nodes from main ele and
5563  // dependant ele
5564 
5565  } // if (!done_face[dependant_face_ele_pt])
5566 
5567  } // for (iie < n_tmp_face_ele)
5568 
5569  } // if (!done_face[main_face_ele_pt])
5570 
5571  } // for (ie < n_tmp_face_ele)
5572 
5573  // Are there any face element to free its memory
5574  const unsigned n_free_face_ele = free_memory_face_ele_pt.size();
5575  if (n_free_face_ele == 0)
5576  {
5577  // If there is not face elements to free memory that means that
5578  // we are not working with an internal boundary, therefore copy
5579  // all the element from the tmp face elements into the face
5580  // elements container
5581 
5582  // Resize the container
5583  face_ele_pt.resize(n_tmp_face_ele);
5584  // loop over the elements and copy them
5585  for (unsigned i = 0; i < n_tmp_face_ele; i++)
5586  {
5587  face_ele_pt[i] = tmp_face_ele_pt[i];
5588  } // for (i < n_tmp_face_ele)
5589 
5590  } // if (n_free_face_ele == 0)
5591  else
5592  {
5593  // ... otherwise free the memory of the indicated elements
5594  // loop over the elements to free its memory
5595  for (unsigned i = 0; i < n_free_face_ele; i++)
5596  {
5597  delete free_memory_face_ele_pt[i];
5598  free_memory_face_ele_pt[i] = 0;
5599  } // for (i < n_free_face_ele)
5600  }
5601  }
5602 
5603  /// ========================================================================
5604  /// In charge of sinchronize the boundary coordinates for internal
5605  /// boundaries that were split as part of the distribution
5606  /// process. Called after setup_boundary_coordinates() for the
5607  /// original mesh only
5608  /// ========================================================================
5609  template<class ELEMENT>
5611  const unsigned& b)
5612  {
5613  // ------------------------------------------------------------------
5614  // First: Get the face elements associated with the current boundary
5615  // ------------------------------------------------------------------
5616 
5617  // Get the communicator of the mesh
5618  OomphCommunicator* comm_pt = this->communicator_pt();
5619 
5620  const unsigned nproc = comm_pt->nproc();
5621  const unsigned my_rank = comm_pt->my_rank();
5622 
5623  // Temporary storage for face elements (do not take care of repeated
5624  // face elements)
5625  Vector<FiniteElement*> tmp_face_ele_pt;
5626 
5627  const unsigned nregions = this->nregion();
5628 
5629  // map to associate the face element to the bulk element, necessary
5630  // to get the processor in charge for the halo elements
5631  std::map<FiniteElement*, FiniteElement*> face_to_bulk_element_pt;
5632 
5633  // If there is more than one region then only use boundary
5634  // coordinates from the bulk side (region 0)
5635  if (nregions > 1)
5636  {
5637  for (unsigned ir = 0; ir < nregions; ir++)
5638  {
5639  const unsigned region_id =
5640  static_cast<unsigned>(this->Region_attribute[ir]);
5641 
5642  // Loop over all elements on boundaries in region -ir-
5643  const unsigned nele_in_region =
5644  this->nboundary_element_in_region(b, region_id);
5645 
5646  // Only bother to do anything else, if there are elements
5647  // associated with the boundary and the current region
5648  if (nele_in_region > 0)
5649  {
5650  // Loop over the bulk elements adjacent to boundary b
5651  for (unsigned e = 0; e < nele_in_region; e++)
5652  {
5653  // Get pointer to the bulk element that is adjacent to boundary b
5654  FiniteElement* bulk_ele_pt =
5655  this->boundary_element_in_region_pt(b, region_id, e);
5656 
5657  // Get the index of the face of element e along boundary b
5658  int face_index =
5659  this->face_index_at_boundary_in_region(b, region_id, e);
5660 
5661  // Create the face element
5662  FiniteElement* tmp_face_el_pt =
5663  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5664 
5665  // ... and add it to the tmp storage for all the face
5666  // elements, do not take care for repeated ones (at the
5667  // moment)
5668  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5669  // Create the map to know if the element is halo
5670  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5671 
5672  } // for (e < nele_in_region)
5673 
5674  } // if (nele_in_region > 0)
5675 
5676  } // for (ir < n_regions)
5677 
5678  } // if (n_regions > 1)
5679 
5680  // Otherwise it's just the normal boundary functions
5681  else
5682  {
5683  // Loop over all elements on boundaries
5684  const unsigned nbound_ele = this->nboundary_element(b);
5685 
5686  // Only bother to do anything else, if there are elements
5687  if (nbound_ele > 0)
5688  {
5689  // Loop over the bulk elements adjacent to boundary b
5690  for (unsigned e = 0; e < nbound_ele; e++)
5691  {
5692  // Get pointer to the bulk element that is adjacent to boundary b
5693  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5694 
5695  // Get the index of the face of element e along boundary b
5696  int face_index = this->face_index_at_boundary(b, e);
5697 
5698  // Create the face element
5699  FiniteElement* tmp_face_el_pt =
5700  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5701 
5702  // ... and add it to the tmp storage for all the face
5703  // elements, do not care for repeated ones (at the moment)
5704  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5705  // Create the map to know if the element is halo
5706  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5707 
5708  } // (e < nbound_ele)
5709 
5710  } // (nbound_ele > 0)
5711 
5712  } // else (n_regions > 1)
5713 
5714  // Temporary storage for one side face elements. In case we are
5715  // working with an internal boundary here we store only one of the
5716  // face elements that are at each side of the boundary
5717  Vector<FiniteElement*> face_ele_pt;
5718 
5719  // map to know which face element has been already done
5720  std::map<FiniteElement*, bool> done_face;
5721 
5722  // Flag to indicate if we are working with an internal boundary
5723  bool is_internal_boundary = false;
5724 
5725 #ifdef PARANOID
5726  // Flag to indicate if we are working with an internal boundary (paranoid)
5727  bool is_internal_boundary_paranoid = false;
5728 
5729  // Count the number of other side face elements found in case we are
5730  // working with an internal boundary
5731  unsigned nfound_face_elements = 0;
5732 #endif
5733 
5734  // Get the number of face elements in the boundary
5735  const unsigned nbound_ele = tmp_face_ele_pt.size();
5736  for (unsigned ie = 0; ie < nbound_ele; ie++)
5737  {
5738  // Get the possible main element
5739  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5740  if (!done_face[main_face_ele_pt])
5741  {
5742  // Mark the face element as done
5743  done_face[main_face_ele_pt] = true;
5744  // Get the number of nodes for the face element
5745  const unsigned nnodes = main_face_ele_pt->nnode();
5746  // Get the first and last node of the main face element
5747  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5748  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes - 1);
5749  // Look for the other side face element
5750  for (unsigned iie = ie + 1; iie < nbound_ele; iie++)
5751  {
5752  // Get the possible dependant element
5753  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5754  if (!done_face[dependant_face_ele_pt])
5755  {
5756  // Get the first and last node of the dependant face element
5757  Node* dependant_first_node_pt = dependant_face_ele_pt->node_pt(0);
5758  Node* dependant_last_node_pt =
5759  dependant_face_ele_pt->node_pt(nnodes - 1);
5760  // Check if the nodes at the ends of both face elements
5761  // match (also check the reversed case)
5762  if (((dependant_first_node_pt == main_first_node_pt) &&
5763  (dependant_last_node_pt == main_last_node_pt)) ||
5764  ((dependant_first_node_pt == main_last_node_pt) &&
5765  (dependant_last_node_pt == main_first_node_pt)))
5766  {
5767 #ifdef PARANOID
5768  // Increase the number of found face elements
5769  nfound_face_elements += 2;
5770 #endif
5771  // Set the flag to indicate we are working with an
5772  // internal boundary
5773  is_internal_boundary = true;
5774  // Mark the face element as done
5775  done_face[dependant_face_ele_pt] = true;
5776 
5777  // Now choose which face element will be used as the main
5778  // element. Use the same criteria as the compute segments
5779  // connectivity method (highest processor in charge or
5780  // bottom-left bulk element)
5781 
5782  // Get the bulk element for each face element (the main
5783  // and the dependant face element)
5784  FiniteElement* main_bulk_ele_pt =
5785  face_to_bulk_element_pt[main_face_ele_pt];
5786  FiniteElement* dependant_bulk_ele_pt =
5787  face_to_bulk_element_pt[dependant_face_ele_pt];
5788 
5789  // Get the processor in charge for each bulk element
5790  int processor_in_charge_main_bulk_ele =
5791  main_bulk_ele_pt->non_halo_proc_ID();
5792  int processor_in_charge_dependant_bulk_ele =
5793  dependant_bulk_ele_pt->non_halo_proc_ID();
5794 
5795  // If the processor in charge is negative the element is
5796  // not halo, therefore the processor in charge is the
5797  // current one
5798  if (processor_in_charge_main_bulk_ele < 0)
5799  {
5800  processor_in_charge_main_bulk_ele = static_cast<int>(my_rank);
5801  }
5802  if (processor_in_charge_dependant_bulk_ele < 0)
5803  {
5804  processor_in_charge_dependant_bulk_ele =
5805  static_cast<int>(my_rank);
5806  }
5807 
5808  // Flag to know if add the main or dependant face element
5809  bool add_main_face_element = true;
5810  if (processor_in_charge_dependant_bulk_ele >
5811  processor_in_charge_main_bulk_ele)
5812  {
5813  // Include the dependant element
5814  add_main_face_element = false;
5815  }
5816  else if (processor_in_charge_main_bulk_ele ==
5817  processor_in_charge_dependant_bulk_ele)
5818  {
5819  // When the processor in charge for both elements is the same
5820  // then use the bottom-left criteria on the bulk elements to
5821  // choose the main face element
5822  Vector<double> main_ele_coordinates(2);
5823  Vector<double> dependant_ele_coordinates(2);
5824  // Get the number of nodes on the bulk elements
5825  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5826  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5827  {
5828  for (unsigned idim = 0; idim < 2; idim++)
5829  {
5830  main_ele_coordinates[idim] +=
5831  main_bulk_ele_pt->node_pt(inode)->x(idim);
5832  dependant_ele_coordinates[idim] +=
5833  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5834  } // (idim < 2)
5835  } // (inode < n_bulk_nodes)
5836 
5837  // Get the average of the nodes coordinates
5838  for (unsigned idim = 0; idim < 2; idim++)
5839  {
5840  main_ele_coordinates[idim] /= (double)n_bulk_nodes;
5841  dependant_ele_coordinates[idim] /= (double)n_bulk_nodes;
5842  }
5843 
5844  // Once we know the average coordinates for each element
5845  // then we choose the one with the bottom-left averaged
5846  // coordinates
5847  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5848  {
5849  add_main_face_element = false;
5850  }
5851  else if (dependant_ele_coordinates[1] ==
5852  main_ele_coordinates[1])
5853  {
5854  // The left-most element
5855  if (dependant_ele_coordinates[0] < main_ele_coordinates[0])
5856  {
5857  add_main_face_element = false;
5858  }
5859  }
5860  } // else -- The processor in charge is the same for both
5861  // elements
5862 
5863  if (add_main_face_element)
5864  {
5865  // Add the main face element to the storage so we get
5866  // the halo and haloed nodes from these face element
5867  face_ele_pt.push_back(main_face_ele_pt);
5868  }
5869  else
5870  {
5871  // Add the main face element to the storage so we get
5872  // the halo and haloed nodes from these face element
5873  face_ele_pt.push_back(dependant_face_ele_pt);
5874  }
5875 
5876  // Break the for to look for the next face element
5877  break;
5878 
5879  } // if -- matching of nodes from main ele and dependant ele
5880  } // if (!done_face[dependant_face_ele_pt])
5881  } // for (iie < nbound_ele)
5882  } // if (!done_face[main_face_ele_pt])
5883  } // for (ie < nbound_ele)
5884 
5885  // Get the number of face elements
5886  const unsigned nface_ele = face_ele_pt.size();
5887 
5888 #ifdef PARANOID
5889  // Check if we are working with an internal open curve. First check
5890  // if there are elements, in a distributed approach they may be no
5891  // elements associated to the boundary
5892  if (nbound_ele > 0 && nfound_face_elements == nbound_ele)
5893  {
5894  is_internal_boundary_paranoid = true;
5895  }
5896 
5897  if (nbound_ele > 0 && is_internal_boundary_paranoid &&
5898  nbound_ele != nface_ele * 2)
5899  {
5900  std::ostringstream error_message;
5901  error_message
5902  << "The info. to perform the synchronisation of the boundary "
5903  << "coordinates was not completely established\n"
5904  << "In this case it was the number of non repeated boundary elements\n"
5905  << "Number of boundary elements: (" << nbound_ele << ")\n"
5906  << "Number of nonrepeated boundary elements: (" << nface_ele << ")\n";
5907  throw OomphLibError(error_message.str(),
5908  "TriangleMesh::synchronize_boundary_coordinates()",
5909  OOMPH_EXCEPTION_LOCATION);
5910  }
5911 #endif
5912 
5913  // ----------------------------------------------------------------
5914  // Second: Identify the halo face elements
5915  // ----------------------------------------------------------------
5916 
5917  // A flag vector to mark those face elements that are considered as
5918  // halo in the current processor
5919  std::vector<bool> is_halo_face_element(nface_ele, false);
5920 
5921  // Count the total number of non halo face elements
5922  unsigned nnon_halo_face_elements = 0;
5923 
5924  for (unsigned ie = 0; ie < nface_ele; ie++)
5925  {
5926  FiniteElement* face_el_pt = face_ele_pt[ie];
5927  // Get the bulk element
5928  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_el_pt];
5929  // Check if the bulk element is halo
5930  if (!tmp_bulk_ele_pt->is_halo())
5931  {
5932  is_halo_face_element[ie] = false;
5933  nnon_halo_face_elements++;
5934  }
5935  else
5936  {
5937  // Mark the face element as halo
5938  is_halo_face_element[ie] = true;
5939  }
5940  } // for (ie < nface_ele)
5941 
5942  // -----------------------------------------------------------------
5943  // Third: Go through the face elements and get the nodes from the
5944  // elements. The boundary coordinate from each node is sent to its
5945  // processor in charge, then that processor will be responsible to
5946  // send the bound coordinate to all the processors that have a halo
5947  // representation of the node
5948  // -----------------------------------------------------------------
5949 
5950  // A map to know which nodes are already done
5951  std::map<Node*, bool> done_node;
5952 
5953  // The storage for the halo nodes on face elements in this processor
5954  // with other processors
5955  Vector<Vector<Node*>> face_halo_node_pt(nproc);
5956 
5957  // The storage for the ids of the halo nodes on face elements in
5958  // this processor with other processors
5959  Vector<Vector<unsigned>> face_halo_node_id(nproc);
5960 
5961  // The storage for the haloed nodes on face elements in this
5962  // processor with other processors
5963  Vector<Vector<Node*>> face_haloed_node_pt(nproc);
5964 
5965  // The storage for the ids of the haloed nodes on face elements in
5966  // this processor with other processors
5967  Vector<Vector<unsigned>> face_haloed_node_id(nproc);
5968 
5969  // A map to know which nodes are face nodes and the processor in
5970  // charge is the current one
5971  std::map<Node*, bool> done_haloed_face_node;
5972 
5973  // Go through all the face elements
5974  for (unsigned iface = 0; iface < nface_ele; iface++)
5975  {
5976  // Only work with the non halo face elements
5977  if (!is_halo_face_element[iface])
5978  {
5979  // Get the face element
5980  FiniteElement* ele_face_pt = face_ele_pt[iface];
5981  // The number of nodes of the face elements
5982  const unsigned nnodes = ele_face_pt->nnode();
5983  // Go through all the nodes in the face element
5984  for (unsigned in = 0; in < nnodes; in++)
5985  {
5986  Node* face_node_pt = ele_face_pt->node_pt(in);
5987  // Check if node is done
5988  if (!done_node[face_node_pt])
5989  {
5990  // Mark the node as done
5991  done_node[face_node_pt] = true;
5992  // First check if the node is halo
5993  if (face_node_pt->is_halo())
5994  {
5995  // Get the processor in charge for the current node
5996  int int_nonhalo_ID = face_node_pt->non_halo_proc_ID();
5997 #ifdef PARANOID
5998  if (int_nonhalo_ID < 0)
5999  {
6000  std::ostringstream error_message;
6001  error_message
6002  << "The node was marked to be halo but the processor in "
6003  << "charge was found to be -1\n\n";
6004  throw OomphLibError(
6005  error_message.str(),
6006  "TriangleMesh::synchronize_boundary_coordinates()",
6007  OOMPH_EXCEPTION_LOCATION);
6008  }
6009 #endif
6010  const unsigned ip = static_cast<unsigned>(int_nonhalo_ID);
6011  // Add the node to the structure that holds the halo
6012  // nodes, the current processor will need to send the
6013  // info. to the processor in charge.
6014  face_halo_node_pt[ip].push_back(face_node_pt);
6015  // ... finally look for the halo id with the processor in
6016  // charge
6017 #ifdef PARANOID
6018  bool found_halo_node = false;
6019 #endif
6020  const unsigned nhalo_iproc = this->nhalo_node(ip);
6021  for (unsigned ihn = 0; ihn < nhalo_iproc; ihn++)
6022  {
6023  Node* compare_face_node_pt = this->halo_node_pt(ip, ihn);
6024  if (compare_face_node_pt == face_node_pt)
6025  {
6026  // Once found the id of the node with the processor
6027  // store the id in the proper storage
6028  face_halo_node_id[ip].push_back(ihn);
6029 #ifdef PARANOID
6030  // Set the flag to mark as found the halo node
6031  found_halo_node = true;
6032 #endif
6033  // Break the loop
6034  break;
6035  }
6036  } // for (ih < nhalo_iproc)
6037 #ifdef PARANOID
6038  if (!found_halo_node)
6039  {
6040  std::ostringstream error_message;
6041  error_message
6042  << "The halo id of the current node: (" << face_node_pt->x(0)
6043  << ", " << face_node_pt->x(1) << ") with processor (" << ip
6044  << ") was not found!!!\n\n";
6045  throw OomphLibError(
6046  error_message.str(),
6047  "TriangleMesh::synchronize_boundary_coordinates()",
6048  OOMPH_EXCEPTION_LOCATION);
6049  }
6050 #endif
6051  } // if (face_node_pt->is_halo())
6052  // If the node is not halo then it could be haloed. If that
6053  // is the case then store the processors at which the node
6054  // is haloed and its id. The info. of these nodes will be
6055  // sent to all the processors with a halo counterpart
6056  else
6057  {
6058  for (unsigned ip = 0; ip < nproc; ip++)
6059  {
6060  // Only work with processors different that the current one
6061  if (ip != my_rank)
6062  {
6063  // If the node is found to be haloed with the "ip"
6064  // processor then save the haloed id in the storage.
6065  // The current processor needs to send info. to the
6066  // other processors to establish the boundary
6067  // coordinates
6068 
6069  // Get the number of haloed nodes with processor ip
6070  const unsigned nhaloed_iproc = this->nhaloed_node(ip);
6071  for (unsigned ihdn = 0; ihdn < nhaloed_iproc; ihdn++)
6072  {
6073  Node* compare_face_node_pt = this->haloed_node_pt(ip, ihdn);
6074  if (face_node_pt == compare_face_node_pt)
6075  {
6076  // Store the node on the haloed node vector for
6077  // the corresponding processor
6078  face_haloed_node_pt[ip].push_back(face_node_pt);
6079  // Now store the halo id of the node with the
6080  // current processor
6081  face_haloed_node_id[ip].push_back(ihdn);
6082  // Mark the node as haloed with other processors,
6083  // so we know the processor in charge is the
6084  // current one "my_rank".
6085  done_haloed_face_node[face_node_pt] = true;
6086  // Break looking in the current processor, look in
6087  // the next one
6088  break;
6089  } // if (face_node_pt == compare_face_node_pt)
6090  } // for (ihdn < nhaloed_node_iproc)
6091  } // if (ip != my_rank)
6092  } // for (ip < nproc)
6093  } // else (non halo node)
6094  } // if (!done_node[node_face_pt])
6095  } // for (in < nnodes)
6096  } // if (!is_halo_face_element[iface])
6097  } // for (iface < nface_ele)
6098 
6099  // -----------------------------------------------------------------
6100  // Fourth: Go through the halo nodes, package and send the
6101  // info. necessary to identify the face nodes in the processor in
6102  // charge. Identify the haloed nodes in the processor in charge and
6103  // establish the boundary coordinates, check if those nodes are
6104  // (already) marked as faced nodes, if that is the case then do not
6105  // establish the boundary coordinates but register them to send back
6106  // the info. to all the processors that have a halo representation
6107  // of the face node
6108  // -----------------------------------------------------------------
6109 
6110  // Go through all processors
6111  for (unsigned ip = 0; ip < nproc; ip++)
6112  {
6113  // Only work with processors different than the current one
6114  if (ip != my_rank)
6115  {
6116  const unsigned nhalo_face_nodes = face_halo_node_pt[ip].size();
6117 #ifdef PARANOID
6118  if (nhalo_face_nodes != face_halo_node_id[ip].size())
6119  {
6120  std::ostringstream error_message;
6121  error_message
6122  << "The number of found halo face nodes (" << nhalo_face_nodes
6123  << ") is different from the number of\nfound halo face ids ("
6124  << face_halo_node_id[ip].size() << ")!!!\n\n";
6125  throw OomphLibError(
6126  error_message.str(),
6127  "TriangleMesh::synchronize_boundary_coordinates()",
6128  OOMPH_EXCEPTION_LOCATION);
6129  }
6130 #endif
6131 
6132  // Container to send the info. related with the halo nodes to be
6133  // identified in the processors in charge
6134  Vector<unsigned> flat_unsigned_send_packed_data;
6135  Vector<double> flat_double_send_packed_data;
6136 
6137  // Go through the halo face nodes in the "ip" processor
6138  for (unsigned ihfn = 0; ihfn < nhalo_face_nodes; ihfn++)
6139  {
6140  // Get the "ihfn"-th face node with the "ip" processor
6141  Node* halo_face_node_pt = face_halo_node_pt[ip][ihfn];
6142  // Get the halo id with the "ip" processor
6143  const unsigned halo_id = face_halo_node_id[ip][ihfn];
6144  // Get the boundary coordinate of the node
6145  Vector<double> zeta(1);
6146  halo_face_node_pt->get_coordinates_on_boundary(b, zeta);
6147  // Store the info. in the containers
6148  flat_unsigned_send_packed_data.push_back(halo_id);
6149  flat_double_send_packed_data.push_back(zeta[0]);
6150  }
6151 
6152  // Send the info.
6153  MPI_Status status;
6154  MPI_Request request;
6155 
6156  // Processor to which send the info
6157  int send_proc = static_cast<int>(ip);
6158  // Processor from which receive the info
6159  int receive_proc = static_cast<int>(ip);
6160 
6161  // Storage to receive the info.
6162  Vector<unsigned> flat_unsigned_receive_packed_data;
6163  Vector<double> flat_double_receive_packed_data;
6164 
6165  // --------------
6166  // Unsigned data
6167  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6168  MPI_Isend(&nflat_unsigned_send,
6169  1,
6170  MPI_UNSIGNED,
6171  send_proc,
6172  1,
6173  comm_pt->mpi_comm(),
6174  &request);
6175 
6176  unsigned nflat_unsigned_receive = 0;
6177  MPI_Recv(&nflat_unsigned_receive,
6178  1,
6179  MPI_UNSIGNED,
6180  receive_proc,
6181  1,
6182  comm_pt->mpi_comm(),
6183  &status);
6184 
6185  MPI_Wait(&request, MPI_STATUS_IGNORE);
6186 
6187  if (nflat_unsigned_send != 0)
6188  {
6189  MPI_Isend(&flat_unsigned_send_packed_data[0],
6190  nflat_unsigned_send,
6191  MPI_UNSIGNED,
6192  send_proc,
6193  2,
6194  comm_pt->mpi_comm(),
6195  &request);
6196  }
6197 
6198  if (nflat_unsigned_receive != 0)
6199  {
6200  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6201  MPI_Recv(&flat_unsigned_receive_packed_data[0],
6202  nflat_unsigned_receive,
6203  MPI_UNSIGNED,
6204  receive_proc,
6205  2,
6206  comm_pt->mpi_comm(),
6207  &status);
6208  }
6209 
6210  if (nflat_unsigned_send != 0)
6211  {
6212  MPI_Wait(&request, MPI_STATUS_IGNORE);
6213  }
6214 
6215  // --------------
6216 
6217 
6218  // Work-around for odd seg fault when calling MPI_Wait below.
6219  MPI_Request my_request;
6220 
6221  // Double data
6222  unsigned nflat_double_send = flat_double_send_packed_data.size();
6223  MPI_Isend(&nflat_double_send,
6224  1,
6225  MPI_DOUBLE,
6226  send_proc,
6227  3,
6228  comm_pt->mpi_comm(),
6229  &my_request);
6230 
6231  unsigned nflat_double_receive = 0;
6232  MPI_Recv(&nflat_double_receive,
6233  1,
6234  MPI_DOUBLE,
6235  receive_proc,
6236  3,
6237  comm_pt->mpi_comm(),
6238  &status);
6239 
6240  // this is where it used to die without separate MPI request
6241  MPI_Wait(&my_request, MPI_STATUS_IGNORE);
6242 
6243  if (nflat_double_send != 0)
6244  {
6245  MPI_Isend(&flat_double_send_packed_data[0],
6246  nflat_double_send,
6247  MPI_DOUBLE,
6248  send_proc,
6249  4,
6250  comm_pt->mpi_comm(),
6251  &my_request);
6252  }
6253 
6254  if (nflat_double_receive != 0)
6255  {
6256  flat_double_receive_packed_data.resize(nflat_double_receive);
6257  MPI_Recv(&flat_double_receive_packed_data[0],
6258  nflat_double_receive,
6259  MPI_DOUBLE,
6260  receive_proc,
6261  4,
6262  comm_pt->mpi_comm(),
6263  &status);
6264  }
6265 
6266  if (nflat_double_send != 0)
6267  {
6268  MPI_Wait(&my_request, MPI_STATUS_IGNORE);
6269  }
6270  // --------------
6271 
6272 #ifdef PARANOID
6273  if (nflat_unsigned_receive != nflat_double_receive)
6274  {
6275  std::ostringstream error_message;
6276  error_message << "The number of unsigned received data ("
6277  << nflat_unsigned_receive << ") is different from the "
6278  << "number\nof double received data ("
6279  << nflat_double_receive << ")!!!\n\n";
6280  throw OomphLibError(
6281  error_message.str(),
6282  "TriangleMesh::synchronize_boundary_coordinates()",
6283  OOMPH_EXCEPTION_LOCATION);
6284  }
6285 #endif
6286 
6287  // With the received info. establish the boundary coordinates
6288  // for the face nodes that this processor is in charge (haloed
6289  // nodes)
6290  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6291  iflat_packed++)
6292  {
6293  // Get the haloed id for the node
6294  const unsigned haloed_id =
6295  flat_unsigned_receive_packed_data[iflat_packed];
6296  // Get the boundary coordinates
6297  Vector<double> zeta(1);
6298  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6299 
6300  // Get the haloed node
6301  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6302 
6303  // If the node has already set the boundary coordinates then
6304  // do not establish it. This is the case for the nodes that
6305  // lie on the boundary, for those nodes not identified on the
6306  // boundary since no elements lie on the boundary but the node
6307  // is on the boundary (a corner of an element lies on the
6308  // boundary) set boundary coordinates and register them to
6309  // send their info. to the processors with a halo counterpart
6310 
6311  // If the node is not haloed face in the procesor in charge
6312  // then set the boundary coordinates and register the node to
6313  // send back the boundary coordinates to the processors with a
6314  // halo counterpart
6315  if (!done_haloed_face_node[haloed_face_node_pt])
6316  {
6317  // Establish the boundary coordinates
6318  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6319 
6320  // Look in all processors where the node could be halo
6321  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6322  {
6323  // Only work with processors different than the current one
6324  if (iiproc != my_rank)
6325  {
6326  // Get the number of haloed nodes with processor iiproc
6327  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6328  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6329  {
6330  Node* compare_haloed_node_pt =
6331  this->haloed_node_pt(iiproc, ihdn);
6332  if (haloed_face_node_pt == compare_haloed_node_pt)
6333  {
6334  // Store the node on the haloed node vector for the
6335  // corresponding processor
6336  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6337  // Now store the halo id of the node with the current
6338  // processor
6339  face_haloed_node_id[iiproc].push_back(ihdn);
6340  // Break searching in the current processor, search in
6341  // the next one
6342  break;
6343  } // if (haloed_face_node_pt==compare_haloed_face_node_pt)
6344  } // for (ihdn < nhaloed_node_iproc)
6345  } // if (iiproc != my_rank)
6346  } // for (iiproc < nproc)
6347  } // if (!done_haloed_face_node[haloed_face_node_pt])
6348  } // for (iflat_packed < nflat_unsigned_receive)
6349  } // if (ip != my_rank)
6350  } // for (ip < nproc)
6351 
6352  // -----------------------------------------------------------------
6353  // Fifth: The boundary coordinates have been established in the
6354  // processors in charge of the nodes. Now each processor send back
6355  // the boundary coordinates to all the processors where there is a
6356  // halo representation of the node
6357  // -----------------------------------------------------------------
6358 
6359  // Go through all processors
6360  for (unsigned ip = 0; ip < nproc; ip++)
6361  {
6362  // Only work with processors different than the current one
6363  if (ip != my_rank)
6364  {
6365  // Container to send the info. of the haloed nodes to all the
6366  // processors
6367  Vector<unsigned> flat_unsigned_send_packed_data;
6368  Vector<double> flat_double_send_packed_data;
6369 
6370  // Get the total number of haloed face nodes with the "ip"
6371  // processor
6372  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6373  // Go through the haloed face nodes in the "ip" processor
6374  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6375  {
6376  // Get the "ihdfn"-th face node with the "ip" processor
6377  Node* haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6378  // Get the haloed id with the "ip" processor
6379  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6380  // Get the boundary coordinate of the node
6381  Vector<double> zeta(1);
6382  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6383  // Store the info. in the containers
6384  flat_unsigned_send_packed_data.push_back(haloed_id);
6385  flat_double_send_packed_data.push_back(zeta[0]);
6386  }
6387 
6388  // Send the info.
6389  MPI_Status status;
6390  MPI_Request request;
6391 
6392  // Processor to which send the info
6393  int send_proc = static_cast<int>(ip);
6394  // Processor from which receive the info
6395  int receive_proc = static_cast<int>(ip);
6396 
6397  // Storage to receive the info.
6398  Vector<unsigned> flat_unsigned_receive_packed_data;
6399  Vector<double> flat_double_receive_packed_data;
6400 
6401  // --------------
6402  // Unsigned data
6403  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6404  MPI_Isend(&nflat_unsigned_send,
6405  1,
6406  MPI_UNSIGNED,
6407  send_proc,
6408  1,
6409  comm_pt->mpi_comm(),
6410  &request);
6411 
6412  unsigned nflat_unsigned_receive = 0;
6413  MPI_Recv(&nflat_unsigned_receive,
6414  1,
6415  MPI_UNSIGNED,
6416  receive_proc,
6417  1,
6418  comm_pt->mpi_comm(),
6419  &status);
6420 
6421  MPI_Wait(&request, MPI_STATUS_IGNORE);
6422 
6423  if (nflat_unsigned_send != 0)
6424  {
6425  MPI_Isend(&flat_unsigned_send_packed_data[0],
6426  nflat_unsigned_send,
6427  MPI_UNSIGNED,
6428  send_proc,
6429  2,
6430  comm_pt->mpi_comm(),
6431  &request);
6432  }
6433 
6434  if (nflat_unsigned_receive != 0)
6435  {
6436  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6437  MPI_Recv(&flat_unsigned_receive_packed_data[0],
6438  nflat_unsigned_receive,
6439  MPI_UNSIGNED,
6440  receive_proc,
6441  2,
6442  comm_pt->mpi_comm(),
6443  &status);
6444  }
6445 
6446  if (nflat_unsigned_send != 0)
6447  {
6448  MPI_Wait(&request, MPI_STATUS_IGNORE);
6449  }
6450 
6451  // --------------
6452  // Double data
6453  unsigned nflat_double_send = flat_double_send_packed_data.size();
6454  MPI_Isend(&nflat_double_send,
6455  1,
6456  MPI_DOUBLE,
6457  send_proc,
6458  3,
6459  comm_pt->mpi_comm(),
6460  &request);
6461 
6462  unsigned nflat_double_receive = 0;
6463  MPI_Recv(&nflat_double_receive,
6464  1,
6465  MPI_DOUBLE,
6466  receive_proc,
6467  3,
6468  comm_pt->mpi_comm(),
6469  &status);
6470 
6471  MPI_Wait(&request, MPI_STATUS_IGNORE);
6472 
6473  if (nflat_double_send != 0)
6474  {
6475  MPI_Isend(&flat_double_send_packed_data[0],
6476  nflat_double_send,
6477  MPI_DOUBLE,
6478  send_proc,
6479  4,
6480  comm_pt->mpi_comm(),
6481  &request);
6482  }
6483 
6484  if (nflat_double_receive != 0)
6485  {
6486  flat_double_receive_packed_data.resize(nflat_double_receive);
6487  MPI_Recv(&flat_double_receive_packed_data[0],
6488  nflat_double_receive,
6489  MPI_DOUBLE,
6490  receive_proc,
6491  4,
6492  comm_pt->mpi_comm(),
6493  &status);
6494  }
6495 
6496  if (nflat_double_send != 0)
6497  {
6498  MPI_Wait(&request, MPI_STATUS_IGNORE);
6499  }
6500  // --------------
6501 
6502 #ifdef PARANOID
6503  if (nflat_unsigned_receive != nflat_double_receive)
6504  {
6505  std::ostringstream error_message;
6506  error_message << "The number of unsigned received data ("
6507  << nflat_unsigned_receive << ") is different from the "
6508  << "number\nof double received data ("
6509  << nflat_double_receive << ")!!!\n\n";
6510  throw OomphLibError(
6511  error_message.str(),
6512  "TriangleMesh::synchronize_boundary_coordinates()",
6513  OOMPH_EXCEPTION_LOCATION);
6514  }
6515 #endif
6516 
6517  // With the received info. establish the boundary coordinates
6518  // received for the face nodes that this processor is not in
6519  // charge (halo nodes)
6520  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6521  iflat_packed++)
6522  {
6523  // Get the halo id for the node
6524  const unsigned halo_id =
6525  flat_unsigned_receive_packed_data[iflat_packed];
6526  // Get the boundary coordinates
6527  Vector<double> zeta(1);
6528  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6529 
6530  // Get the halo node
6531  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6532 
6533  // It could be possible that the node has been already
6534  // established boundary coordinates since it is a halo face
6535  // node. However, for those elements not on the boundary, but
6536  // having a corner node on the boundary this procedure will
6537  // establish boundary coordinates for those nodes
6538 
6539  // this->add_boundary_node(b, halo_face_node_pt);
6540 
6541  // Establish the boundary coordinates
6542  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6543  } // for (iflat_packed < nflat_unsigned_receive)
6544  } // if (ip != my_rank)
6545  } // for (ip < nproc)
6546 
6547  // Clean all the created face elements
6548  for (unsigned ie = 0; ie < nbound_ele; ie++)
6549  {
6550  delete tmp_face_ele_pt[ie];
6551  tmp_face_ele_pt[ie] = 0;
6552  }
6553 
6554  // Now get a new face mesh representation and fill the data for those
6555  // processors with halo segments
6556  if (is_internal_boundary)
6557  {
6558  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6559  }
6560  }
6561 
6562  //======================================================================
6563  /// Re-assign the boundary segments initial zeta (arclength)
6564  /// for those internal boundaries that were splited during the
6565  /// distribution process (only apply for internal boundaries that
6566  /// have one face element at each side of the boundary)
6567  //======================================================================
6568  template<class ELEMENT>
6571  const unsigned& b)
6572  {
6573  // ------------------------------------------------------------------
6574  // First: Get the face elements associated with the current boundary
6575  // Only include nonhalo face elements
6576  // ------------------------------------------------------------------
6577  // Temporary storage for face elements
6578  Vector<FiniteElement*> face_el_pt;
6579 
6580  // Temporary storage for the number of elements adjacent to the
6581  // boundary
6582  unsigned nele = 0;
6583 
6584  // Temporary storage for elements adjacent to the boundary that have
6585  // a common edge (related with internal boundaries)
6586  unsigned n_repeated_ele = 0;
6587 
6588  const unsigned n_regions = this->nregion();
6589 
6590  // Temporary storage for already done nodes
6591  Vector<std::pair<Node*, Node*>> done_nodes_pt;
6592 
6593  // If there is more than one region then only use boundary
6594  // coordinates from the bulk side (region 0)
6595  if (n_regions > 1)
6596  {
6597  for (unsigned rr = 0; rr < n_regions; rr++)
6598  {
6599  const unsigned region_id =
6600  static_cast<unsigned>(this->Region_attribute[rr]);
6601 
6602  // Loop over all elements on boundaries in region i_r
6603  const unsigned nel_in_region =
6604  this->nboundary_element_in_region(b, region_id);
6605 
6606  unsigned nel_repetead_in_region = 0;
6607 
6608  // Only bother to do anything else, if there are elements
6609  // associated with the boundary and the current region
6610  if (nel_in_region > 0)
6611  {
6612  bool repeated = false;
6613 
6614  // Loop over the bulk elements adjacent to boundary b
6615  for (unsigned e = 0; e < nel_in_region; e++)
6616  {
6617  // Get pointer to the bulk element that is adjacent to
6618  // boundary b
6619  FiniteElement* bulk_elem_pt =
6620  this->boundary_element_in_region_pt(b, region_id, e);
6621 
6622  // Remember only to work with nonhalo elements
6623  if (bulk_elem_pt->is_halo())
6624  {
6625  n_repeated_ele++;
6626  continue;
6627  }
6628 
6629  // Find the index of the face of element e along boundary b
6630  int face_index =
6631  this->face_index_at_boundary_in_region(b, region_id, e);
6632 
6633  // Before adding the new element we need to be sure that the
6634  // edge that this element represent has not been already
6635  // added
6636  FiniteElement* tmp_ele_pt =
6637  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6638 
6639  const unsigned n_nodes = tmp_ele_pt->nnode();
6640 
6641  std::pair<Node*, Node*> tmp_pair = std::make_pair(
6642  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
6643 
6644  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
6645  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
6646 
6647  // Search for repeated nodes
6648  const unsigned n_done_nodes = done_nodes_pt.size();
6649  for (unsigned l = 0; l < n_done_nodes; l++)
6650  {
6651  if (tmp_pair == done_nodes_pt[l] ||
6652  tmp_pair_inverse == done_nodes_pt[l])
6653  {
6654  nel_repetead_in_region++;
6655  repeated = true;
6656  break;
6657  }
6658  }
6659 
6660  // Create new face element
6661  if (!repeated)
6662  {
6663  // Add the pair of nodes (edge) to the node dones
6664  done_nodes_pt.push_back(tmp_pair);
6665  // Add the element to the face elements
6666  face_el_pt.push_back(tmp_ele_pt);
6667  }
6668  else
6669  {
6670  // Clean up
6671  delete tmp_ele_pt;
6672  tmp_ele_pt = 0;
6673  }
6674 
6675  // Re-start
6676  repeated = false;
6677 
6678  } // for nel
6679 
6680  nele += nel_in_region;
6681 
6682  n_repeated_ele += nel_repetead_in_region;
6683 
6684  } // if (nel_in_region > 0)
6685  } // for (rr < n_regions)
6686  } // if (n_regions > 1)
6687  // Otherwise it's just the normal boundary functions
6688  else
6689  {
6690  // Loop over all elements on boundaries
6691  nele = this->nboundary_element(b);
6692 
6693  // Only bother to do anything else, if there are elements
6694  if (nele > 0)
6695  {
6696  // Check for repeated ones
6697  bool repeated = false;
6698 
6699  // Loop over the bulk elements adjacent to boundary b
6700  for (unsigned e = 0; e < nele; e++)
6701  {
6702  // Get pointer to the bulk element that is adjacent to
6703  // boundary b
6704  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6705 
6706  // Remember only to work with nonhalo elements
6707  if (bulk_elem_pt->is_halo())
6708  {
6709  n_repeated_ele++;
6710  // Skip the halo element
6711  continue;
6712  }
6713 
6714  // Find the index of the face of element e along boundary b
6715  int face_index = this->face_index_at_boundary(b, e);
6716 
6717  // Before adding the new element we need to be sure that the
6718  // edge that this element represents has not been already
6719  // added (only applies for internal boundaries)
6720  FiniteElement* tmp_ele_pt =
6721  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6722 
6723  const unsigned n_nodes = tmp_ele_pt->nnode();
6724 
6725  std::pair<Node*, Node*> tmp_pair = std::make_pair(
6726  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
6727 
6728  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
6729  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
6730 
6731  // Search for repeated nodes
6732  const unsigned n_done_nodes = done_nodes_pt.size();
6733  for (unsigned l = 0; l < n_done_nodes; l++)
6734  {
6735  if (tmp_pair == done_nodes_pt[l] ||
6736  tmp_pair_inverse == done_nodes_pt[l])
6737  {
6738  // Increase the number of repeated elements
6739  n_repeated_ele++;
6740  // Mark the element as repeated
6741  repeated = true;
6742  break;
6743  }
6744  }
6745 
6746  // Create new face element
6747  if (!repeated)
6748  {
6749  // Add the pair of nodes (edge) to the node dones
6750  done_nodes_pt.push_back(tmp_pair);
6751  // Add the element to the face elements
6752  face_el_pt.push_back(tmp_ele_pt);
6753  }
6754  else
6755  {
6756  // Free the repeated bulk element!!
6757  delete tmp_ele_pt;
6758  tmp_ele_pt = 0;
6759  }
6760 
6761  // Re-start
6762  repeated = false;
6763 
6764  } // for (e < nel)
6765  } // if (nel > 0)
6766 
6767  } // else (n_regions > 1)
6768 
6769  // Do not consider the repeated elements
6770  nele -= n_repeated_ele;
6771 
6772 #ifdef PARANOID
6773  if (nele != face_el_pt.size())
6774  {
6775  std::ostringstream error_message;
6776  error_message
6777  << "The independet counting of face elements (" << nele << ") for "
6778  << "boundary (" << b << ") is different\n"
6779  << "from the real number of face elements in the container ("
6780  << face_el_pt.size() << ")\n";
6781  //<< "Possible memory leak\n"
6782  throw OomphLibError(error_message.str(),
6783  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6784  "values_for_internal_boundary()",
6785  OOMPH_EXCEPTION_LOCATION);
6786  }
6787 #endif
6788 
6789  // ----------------------------------------------------------------
6790  // Second: Sort the face elements (to create segments), only
6791  // consider nonhalo elements
6792  // ----------------------------------------------------------------
6793 
6794  // Get the total number of nonhalo face elements
6795  const unsigned nnon_halo_face_elements = face_el_pt.size();
6796 
6797  // The vector of list to store the "segments" that compound the
6798  // boundary (segments may appear only in a distributed mesh)
6799  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
6800 
6801  // Number of already sorted face elements
6802  unsigned nsorted_face_elements = 0;
6803 
6804  // Keep track of who's done
6805  std::map<FiniteElement*, bool> done_el;
6806 
6807  // Keep track of which element is inverted
6808  std::map<FiniteElement*, bool> is_inverted;
6809 
6810  // Iterate until all possible segments have been created
6811  while (nsorted_face_elements < nnon_halo_face_elements)
6812  {
6813  // The ordered list of face elements (in a distributed mesh a
6814  // collection of contiguous face elements define a segment)
6815  std::list<FiniteElement*> sorted_el_pt;
6816 
6817 #ifdef PARANOID
6818  // Select an initial element for the segment
6819  bool found_initial_face_element = false;
6820 #endif
6821 
6822  FiniteElement* ele_face_pt = 0;
6823 
6824  unsigned iface = 0;
6825  for (iface = 0; iface < nele; iface++)
6826  {
6827  ele_face_pt = face_el_pt[iface];
6828  // If not done then take it as initial face element
6829  if (!done_el[ele_face_pt])
6830  {
6831 #ifdef PARANOID
6832  found_initial_face_element = true;
6833 #endif
6834  nsorted_face_elements++;
6835  iface++; // The next element number
6836  sorted_el_pt.push_back(ele_face_pt);
6837  // Mark as done
6838  done_el[ele_face_pt] = true;
6839  break;
6840  }
6841  } // for (iface < nele)
6842 
6843 #ifdef PARANOID
6844  if (!found_initial_face_element)
6845  {
6846  std::ostringstream error_message;
6847  error_message
6848  << "Could not find an initial face element for the current segment\n";
6849  // << "----- Possible memory leak -----\n";
6850  throw OomphLibError(error_message.str(),
6851  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6852  "values_for_internal_boundary()",
6853  OOMPH_EXCEPTION_LOCATION);
6854  }
6855 #endif
6856 
6857  // Number of nodes
6858  const unsigned nnod = ele_face_pt->nnode();
6859 
6860  // Left and rightmost nodes (the left and right nodes of the
6861  // current face element)
6862  Node* left_node_pt = ele_face_pt->node_pt(0);
6863  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6864 
6865  // Continue iterating if a new face element has been added to the
6866  // list
6867  bool face_element_added = false;
6868 
6869  // While a new face element has been added to the set of sorted
6870  // face elements then re-iterate
6871  do
6872  {
6873  // Start from the next face element since we have already added
6874  // the previous one as the initial face element (any previous
6875  // face element had to be added on previous iterations)
6876  for (unsigned iiface = iface; iiface < nele; iiface++)
6877  {
6878  // Re-start flag
6879  face_element_added = false;
6880 
6881  // Get the candidate element
6882  ele_face_pt = face_el_pt[iiface];
6883 
6884  // Check that the candidate element has not been done
6885  if (!(done_el[ele_face_pt]))
6886  {
6887  // Get the left and right nodes of the current element
6888  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6889  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6890 
6891  // New element fits at the left of segment and is not inverted
6892  if (left_node_pt == local_right_node_pt)
6893  {
6894  left_node_pt = local_left_node_pt;
6895  sorted_el_pt.push_front(ele_face_pt);
6896  is_inverted[ele_face_pt] = false;
6897  face_element_added = true;
6898  }
6899  // New element fits at the left of segment and is inverted
6900  else if (left_node_pt == local_left_node_pt)
6901  {
6902  left_node_pt = local_right_node_pt;
6903  sorted_el_pt.push_front(ele_face_pt);
6904  is_inverted[ele_face_pt] = true;
6905  face_element_added = true;
6906  }
6907  // New element fits on the right of segment and is not inverted
6908  else if (right_node_pt == local_left_node_pt)
6909  {
6910  right_node_pt = local_right_node_pt;
6911  sorted_el_pt.push_back(ele_face_pt);
6912  is_inverted[ele_face_pt] = false;
6913  face_element_added = true;
6914  }
6915  // New element fits on the right of segment and is inverted
6916  else if (right_node_pt == local_right_node_pt)
6917  {
6918  right_node_pt = local_left_node_pt;
6919  sorted_el_pt.push_back(ele_face_pt);
6920  is_inverted[ele_face_pt] = true;
6921  face_element_added = true;
6922  }
6923 
6924  if (face_element_added)
6925  {
6926  done_el[ele_face_pt] = true;
6927  nsorted_face_elements++;
6928  break;
6929  }
6930 
6931  } // if (!(done_el[ele_face_pt]))
6932  } // for (iiface<nnon_halo_face_element)
6933  } while (face_element_added &&
6934  (nsorted_face_elements < nnon_halo_face_elements));
6935 
6936  // Store the created segment in the vector of segments
6937  segment_sorted_ele_pt.push_back(sorted_el_pt);
6938 
6939  } // while(nsorted_face_elements < nnon_halo_face_elements);
6940 
6941  // --------------------------------------------------------------
6942  // Third: We have the face elements sorted, now assign boundary
6943  // coordinates to the nodes in the segments and compute the
6944  // arclength of the segment
6945  // --------------------------------------------------------------
6946 
6947  // Vector of sets that stores the nodes of each segment based on a
6948  // lexicographically order starting from the bottom left node of
6949  // each segment
6950  Vector<std::set<Node*>> segment_all_nodes_pt;
6951 
6952  // The number of segments in this processor
6953  const unsigned nsegments = segment_sorted_ele_pt.size();
6954 
6955 #ifdef PARANOID
6956  if (nnon_halo_face_elements > 0 && nsegments == 0)
6957  {
6958  std::ostringstream error_message;
6959  error_message
6960  << "The number of segments is zero, but the number of nonhalo\n"
6961  << "elements is: (" << nnon_halo_face_elements << ")\n";
6962  throw OomphLibError(error_message.str(),
6963  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6964  "values_for_internal_boundary()",
6965  OOMPH_EXCEPTION_LOCATION);
6966  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6967 #endif
6968 
6969  // The arclength of each segment in the current processor
6970  Vector<double> segment_arclength(nsegments);
6971 
6972  // The initial zeta for the segment
6973  Vector<double> initial_zeta_segment(nsegments);
6974 
6975  // The final zeta for the segment
6976  Vector<double> final_zeta_segment(nsegments);
6977 
6978  // Go through all the segments and compute the LOCAL boundary
6979  // coordinates
6980  for (unsigned is = 0; is < nsegments; is++)
6981  {
6982 #ifdef PARANOID
6983  if (segment_sorted_ele_pt[is].size() == 0)
6984  {
6985  std::ostringstream error_message;
6986  error_message << "The (" << is << ")-th segment has no elements\n";
6987  throw OomphLibError(error_message.str(),
6988  "TriangleMesh::re_scale_re_assigned_initial_zeta_"
6989  "values_for_internal_boundary()",
6990  OOMPH_EXCEPTION_LOCATION);
6991  } // if (segment_sorted_ele_pt[is].size() == 0)
6992 #endif
6993 
6994  // Get access to the first element on the segment
6995  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6996 
6997  // Number of nodes
6998  const unsigned nnod = first_ele_pt->nnode();
6999 
7000  // Get the first node of the current segment
7001  Node* first_node_pt = first_ele_pt->node_pt(0);
7002  if (is_inverted[first_ele_pt])
7003  {
7004  first_node_pt = first_ele_pt->node_pt(nnod - 1);
7005  }
7006 
7007  // Get access to the last element on the segment
7008  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
7009 
7010  // Get the last node of the current segment
7011  Node* last_node_pt = last_ele_pt->node_pt(nnod - 1);
7012  if (is_inverted[last_ele_pt])
7013  {
7014  last_node_pt = last_ele_pt->node_pt(0);
7015  }
7016 
7017  // Coordinates of left node
7018  double x_left = first_node_pt->x(0);
7019  double y_left = first_node_pt->x(1);
7020 
7021  // Initialise boundary coordinate (local boundary coordinate for
7022  // boundaries with more than one segment)
7023  Vector<double> zeta(1, 0.0);
7024 
7025  // If we have associated a GeomObject then it is not necessary to
7026  // compute the arclength, only read the values from the nodes at
7027  // the edges
7028  if (this->boundary_geom_object_pt(b) != 0)
7029  {
7030  first_node_pt->get_coordinates_on_boundary(b, zeta);
7031  initial_zeta_segment[is] = zeta[0];
7032  last_node_pt->get_coordinates_on_boundary(b, zeta);
7033  final_zeta_segment[is] = zeta[0];
7034  }
7035 
7036  // Lexicographically bottom left node
7037  std::set<Node*> local_nodes_pt;
7038  local_nodes_pt.insert(first_node_pt);
7039 
7040  // Now loop over nodes in order
7041  for (std::list<FiniteElement*>::iterator it =
7042  segment_sorted_ele_pt[is].begin();
7043  it != segment_sorted_ele_pt[is].end();
7044  it++)
7045  {
7046  // Get element
7047  FiniteElement* el_pt = *it;
7048 
7049  // Start node and increment
7050  unsigned k_nod = 1;
7051  int nod_diff = 1;
7052  if (is_inverted[el_pt])
7053  {
7054  k_nod = nnod - 2;
7055  nod_diff = -1;
7056  }
7057 
7058  // Loop over nodes
7059  for (unsigned j = 1; j < nnod; j++)
7060  {
7061  Node* nod_pt = el_pt->node_pt(k_nod);
7062  k_nod += nod_diff;
7063 
7064  // Coordinates of right node
7065  double x_right = nod_pt->x(0);
7066  double y_right = nod_pt->x(1);
7067 
7068  // Increment boundary coordinate
7069  zeta[0] += sqrt((x_right - x_left) * (x_right - x_left) +
7070  (y_right - y_left) * (y_right - y_left));
7071 
7072  // Increment reference coordinate
7073  x_left = x_right;
7074  y_left = y_right;
7075 
7076  // Get lexicographically bottom left node but only
7077  // use vertex nodes as candidates
7078  local_nodes_pt.insert(nod_pt);
7079 
7080  } // for (j < nnod)
7081  } // iterator over the elements in the segment
7082 
7083  // Store the arclength of the segment
7084  segment_arclength[is] = zeta[0];
7085 
7086  // Add the nodes for the corresponding segment in the container
7087  segment_all_nodes_pt.push_back(local_nodes_pt);
7088 
7089  } // for (is < nsegments)
7090 
7091  // ------------------------------------------------------------------
7092  // Fourth: Now we have the segments sorted, with arclength and with
7093  // LOCAL arclength assigned to the nodes. Procced to re-scale the
7094  // coordinates on the nodes based on the arclength
7095  // ------------------------------------------------------------------
7096 
7097  // ------------------------------------------------------------------
7098  // Clear the original storages
7099  Boundary_segment_inverted[b].clear();
7100  Boundary_segment_initial_coordinate[b].clear();
7101  Boundary_segment_final_coordinate[b].clear();
7102 
7103  Boundary_segment_initial_zeta[b].clear();
7104  Boundary_segment_final_zeta[b].clear();
7105 
7106  Boundary_segment_initial_arclength[b].clear();
7107  Boundary_segment_final_arclength[b].clear();
7108 
7109  // Get the zeta values for the first and last node in the boundary
7110  Vector<double> first_node_zeta_coordinate(1, 0.0);
7111  Vector<double> last_node_zeta_coordinate(1, 0.0);
7112  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
7113  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
7114 
7115  // Get the boundary arclength
7116  const double boundary_arclength =
7117  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
7118 
7119  // Go through the segments and get the first and last node for each
7120  // segment
7121  for (unsigned is = 0; is < nsegments; is++)
7122  {
7123  // Get the first face element of the segment
7124  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
7125 
7126  // The number of nodes
7127  const unsigned nnod = first_face_ele_pt->nnode();
7128 
7129  // ... and the first node of the segment
7130  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7131  if (is_inverted[first_face_ele_pt])
7132  {
7133  first_node_pt = first_face_ele_pt->node_pt(nnod - 1);
7134  }
7135 
7136  // Get the bound coordinates of the node
7137  Vector<double> zeta_first(1);
7138  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7139 
7140  // Get the last face element of the segment
7141  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7142 
7143  // ... and the last node of the segment
7144  Node* last_node_pt = last_face_ele_pt->node_pt(nnod - 1);
7145  if (is_inverted[last_face_ele_pt])
7146  {
7147  last_node_pt = last_face_ele_pt->node_pt(0);
7148  }
7149 
7150  // Get the bound coordinates of the node
7151  Vector<double> zeta_last(1);
7152  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7153 
7154  // Now that we have the first and last node of the segment, get
7155  // the coordinates of the nodes
7156  Vector<double> first_node_coord(2);
7157  Vector<double> last_node_coord(2);
7158  for (unsigned i = 0; i < 2; i++)
7159  {
7160  first_node_coord[i] = first_node_pt->x(i);
7161  last_node_coord[i] = last_node_pt->x(i);
7162  }
7163 
7164  // Re-assign the values to identify the segments on the new mesh
7165  Boundary_segment_inverted[b].push_back(0);
7166  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7167  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7168 
7169  // Check if the boudary has an associated GeomObject
7170  if (this->boundary_geom_object_pt(b) != 0)
7171  {
7172  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7173  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7174  }
7175  else
7176  {
7177  // Re-assign the values and re-scale them
7178  Boundary_segment_initial_arclength[b].push_back(zeta_first[0] *
7179  boundary_arclength);
7180  Boundary_segment_final_arclength[b].push_back(zeta_last[0] *
7181  boundary_arclength);
7182  }
7183 
7184  } // for (is < nsegments)
7185 
7186  // Clean all the created face elements
7187  for (unsigned i = 0; i < nele; i++)
7188  {
7189  delete face_el_pt[i];
7190  face_el_pt[i] = 0;
7191  }
7192  }
7193 
7194 #endif // OOMPH_HAS_MPI
7195 
7196 
7197 #ifdef OOMPH_HAS_TRIANGLE_LIB
7198 
7199  //========================================================================
7200  /// Create TriangulateIO object via the .poly file
7201  //========================================================================
7202  template<class ELEMENT>
7204  const std::string& poly_file_name,
7205  TriangulateIO& triangulate_io,
7206  bool& use_attributes)
7207  {
7208  // Process poly file
7209  // -----------------
7210  std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
7211  if (!poly_file)
7212  {
7213  throw OomphLibError("Error opening .poly file\n",
7214  OOMPH_CURRENT_FUNCTION,
7215  OOMPH_EXCEPTION_LOCATION);
7216  }
7217 
7218  // Initialize triangulateio structure
7219  TriangleHelper::initialise_triangulateio(triangulate_io);
7220 
7221  // Ignore the first line with structure description
7222  poly_file.ignore(80, '\n');
7223 
7224  // Read and store number of nodes
7225  unsigned invertices;
7226  poly_file >> invertices;
7227  triangulate_io.numberofpoints = invertices;
7228 
7229  // Initialisation of the point list
7230  triangulate_io.pointlist =
7231  (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7232 
7233  // Read and store spatial dimension of nodes
7234  unsigned mesh_dim;
7235  poly_file >> mesh_dim;
7236 
7237  if (mesh_dim == 0)
7238  {
7239  mesh_dim = 2;
7240  }
7241 
7242 #ifdef PARANOID
7243  if (mesh_dim != 2)
7244  {
7245  throw OomphLibError("The dimension must be 2\n",
7246  OOMPH_CURRENT_FUNCTION,
7247  OOMPH_EXCEPTION_LOCATION);
7248  }
7249 #endif
7250 
7251  // Read and check the flag for attributes
7252  unsigned nextras;
7253  poly_file >> nextras;
7254 
7255  triangulate_io.numberofpointattributes = 0;
7256  triangulate_io.pointattributelist = (double*)NULL;
7257 
7258  // Read and check the flag for boundary markers
7259  unsigned nodemarkers;
7260  poly_file >> nodemarkers;
7261  triangulate_io.pointmarkerlist = (int*)NULL;
7262 
7263 #ifdef PARANOID
7264  // Reading the .poly with the oomph.lib we need
7265  // to set the point attribute and markers to 0
7266  if (nextras != 0 || nodemarkers != 0)
7267  {
7268  oomph_info << "===================================================="
7269  << std::endl
7270  << std::endl;
7271  oomph_info << "Reading the .poly file via oomph_lib \n"
7272  << "point's attribute and point's markers \n"
7273  << "are automatically set to 0" << std::endl;
7274  oomph_info << "===================================================="
7275  << std::endl;
7276  }
7277 #endif
7278 
7279  // Dummy for node number (and attribute or markers if included)
7280  unsigned dummy_value;
7281  unsigned count_point = 0;
7282  std::string test_string;
7283 
7284  // Skip line with commentary
7285  getline(poly_file, test_string, '#');
7286  poly_file.ignore(80, '\n');
7287 
7288  // Read and store all the nodes coordinates
7289  // (hole's vertices as well)
7290  for (unsigned count = 0; count < invertices; count++)
7291  {
7292  poly_file >> dummy_value;
7293  poly_file >> triangulate_io.pointlist[count_point];
7294  poly_file >> triangulate_io.pointlist[count_point + 1];
7295  if (nextras != 0 || nodemarkers != 0)
7296  {
7297  for (unsigned j = 0; j < nextras; j++)
7298  {
7299  poly_file >> dummy_value;
7300  }
7301  }
7302  else if (nextras != 0 && nodemarkers != 0)
7303  {
7304  for (unsigned j = 0; j < nextras; j++)
7305  {
7306  poly_file >> dummy_value;
7307  poly_file >> dummy_value;
7308  }
7309  }
7310  // Read the next line
7311  poly_file.ignore(80, '\n');
7312 
7313  // Skip line with commentary for internal box whether found
7314  if (poly_file.get() == '#')
7315  {
7316  poly_file.ignore(80, '\n');
7317  }
7318  // If read the char should be put back in the string
7319 
7320  else
7321  {
7322  poly_file.unget();
7323  }
7324  count_point += 2;
7325  }
7326 
7327  // The line with the segment's commentary has been skipped
7328  // by the command of the last loop
7329 
7330  // Read and store the number of segments
7331  unsigned dummy_seg;
7332  unsigned inelements;
7333  poly_file >> inelements;
7334 
7335  unsigned segment_markers;
7336  poly_file >> segment_markers;
7337 
7338  // Marker list should be provided by the user to assign
7339  // each segment to a boundary
7340 #ifdef PARANOID
7341  if (segment_markers != 1)
7342  {
7343  std::ostringstream error_stream;
7344  error_stream << "The segment marker should be provided \n"
7345  << "In order to assign each segment to a boundary \n "
7346  << std::endl;
7347 
7348  throw OomphLibError(
7349  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
7350  }
7351 #endif
7352 
7353  triangulate_io.numberofsegments = inelements;
7354  triangulate_io.segmentlist =
7355  (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7356  triangulate_io.segmentmarkerlist =
7357  (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
7358 
7359  // Read all the segments edges and markers
7360  for (unsigned i = 0; i < 2 * inelements; i += 2)
7361  {
7362  poly_file >> dummy_seg;
7363  poly_file >> triangulate_io.segmentlist[i];
7364  poly_file >> triangulate_io.segmentlist[i + 1];
7365  if (segment_markers != 0)
7366  {
7367  poly_file >> triangulate_io.segmentmarkerlist[i / 2];
7368  }
7369 
7370  // Skip line with commentary
7371  poly_file.ignore(80, '\n');
7372  }
7373 
7374  // Read and store the number of holes if given
7375  // Skip line with commentary
7376  if (getline(poly_file, test_string, '#'))
7377  {
7378  poly_file.ignore(80, '\n');
7379 
7380  unsigned dummy_hole;
7381  unsigned nhole;
7382  poly_file >> nhole;
7383 
7384  triangulate_io.numberofholes = nhole;
7385  triangulate_io.holelist =
7386  (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7387 
7388  // Loop over the holes to get centre coords and store value onto the
7389  // TriangulateIO object
7390  for (unsigned i = 0; i < 2 * nhole; i += 2)
7391  {
7392  poly_file >> dummy_hole;
7393  poly_file >> triangulate_io.holelist[i];
7394  poly_file >> triangulate_io.holelist[i + 1];
7395  }
7396  }
7397 
7398  // Read and store the number of regions if given
7399  // Skip line with commentary
7400  if (getline(poly_file, test_string, '#'))
7401  {
7402  poly_file.ignore(80, '\n');
7403 
7404  unsigned dummy_region;
7405  unsigned nregion;
7406  poly_file >> nregion;
7407  std::cerr << "Regions: " << nregion << std::endl;
7408  getchar();
7409 
7410  triangulate_io.numberofregions = nregion;
7411  triangulate_io.regionlist =
7412  (double*)malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7413 
7414  // Check for using regions
7415  if (nregion > 0)
7416  {
7417  use_attributes = true;
7418  }
7419 
7420  // Loop over the regions to get coords and store value onto the
7421  // TriangulateIO object
7422  for (unsigned i = 0; i < nregion; i++)
7423  {
7424  poly_file >> dummy_region;
7425  poly_file >> triangulate_io.regionlist[4 * i];
7426  poly_file >> triangulate_io.regionlist[4 * i + 1];
7427  poly_file >> triangulate_io.regionlist[4 * i + 2];
7428  triangulate_io.regionlist[4 * i + 3] = 0.0;
7429  }
7430  }
7431  }
7432 
7433 #endif
7434 
7435 #ifdef OOMPH_HAS_TRIANGLE_LIB
7436 #ifdef OOMPH_HAS_MPI
7437 
7438  //======================================================================
7439  /// Used to dump info. related with distributed triangle meshes
7440  //======================================================================
7441  template<class ELEMENT>
7443  std::ostream& dump_file)
7444  {
7445  // First check that the mesh is distributed
7446  if (this->is_mesh_distributed())
7447  {
7448  // Save the original number of boundaries
7449  const unsigned nboundary = this->nboundary();
7450  dump_file << nboundary << " # number of original boundaries" << std::endl;
7451 
7452  // Save the number of shared boundaries
7453  const unsigned nshared_boundaries = this->nshared_boundaries();
7454  dump_file << nshared_boundaries << " # number of shared boundaries"
7455  << std::endl;
7456 
7457  // Save the initial and final shared boundaries ids
7458  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7459  dump_file << init_shd_bnd_id << " # initial shared boundaries id"
7460  << std::endl;
7461 
7462  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7463  dump_file << final_shd_bnd_id << " # final shared boundaries id"
7464  << std::endl;
7465 
7466  // Save the number of processors
7467  const unsigned nprocs = this->shared_boundaries_ids().size();
7468  dump_file << nprocs << " # number of processors" << std::endl;
7469 
7470  // Now save the processors ids and the shared boundary created
7471  // by them
7472  for (unsigned ip = 0; ip < nprocs; ip++)
7473  {
7474  for (unsigned jp = 0; jp < nprocs; jp++)
7475  {
7476  if (ip != jp)
7477  {
7478  // Get the number of shared boundaries with it these two
7479  // processors
7480  const unsigned nshared_boundaries_iproc_jproc =
7481  this->shared_boundaries_ids(ip, jp).size();
7482 
7483  // Save the number of shared boundaries with in these two
7484  // processors
7485  dump_file << nshared_boundaries_iproc_jproc
7486  << " # number of shared boundaries with in two "
7487  << "processors" << std::endl;
7488  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7489  {
7490  const unsigned shared_boundary_id =
7491  this->shared_boundaries_ids(ip, jp, is);
7492  dump_file << ip << " " << jp << " " << shared_boundary_id
7493  << " # ip jp shared_boundary of processors ip and jp"
7494  << std::endl;
7495 
7496  } // for (is < nshared_boundaries_iproc_jproc)
7497  }
7498  } // for (jp < nprocs)
7499  } // for (ip < nprocs)
7500 
7501  // Now save the info. that states which shared boundary overlaps
7502  // an internal boundary
7503 
7504  // First check if there are shared boundaries overlapping internal
7505  // boundaries
7506  const unsigned nshared_boundaries_overlap_internal_boundaries =
7507  this->nshared_boundary_overlaps_internal_boundary();
7508  dump_file << nshared_boundaries_overlap_internal_boundaries
7509  << " # number of shared boundaries that overlap internal "
7510  << "boundaries" << std::endl;
7511 
7512  if (nshared_boundaries_overlap_internal_boundaries > 0)
7513  {
7514  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7515  {
7516  // Check if the current shared boundary overlaps an internal
7517  // boundary
7518  if (this->shared_boundary_overlaps_internal_boundary(isb))
7519  {
7520  // Which internal boundary is overlapped by the shared
7521  // boundary
7522  const unsigned overlapped_internal_boundary =
7523  shared_boundary_overlapping_internal_boundary(isb);
7524  // Save the shared boundary that overlaps the internal boundary
7525  dump_file << isb << " " << overlapped_internal_boundary
7526  << " # the shared boundary overlaps the internal "
7527  << "boundary " << std::endl;
7528 
7529  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7530  } // for (isb < final_shd_bnd_id)
7531  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7532 
7533  // Now save the info. related with the initial and final
7534  // boundary coordinates for each original boundary
7535 
7536  // Go through all the (original) boundaries to update the initial
7537  // and final boundary coordinates
7538  for (unsigned b = 0; b < nboundary; b++)
7539  {
7540  // Check if the boundary zeta coordinates for this boundary have
7541  // been already assigned, if that is the case then state the
7542  // flag to know that info. should be read
7543  if (Assigned_segments_initial_zeta_values[b])
7544  {
7545  // The boundary coordinates have been computed then state
7546  // the flag and save the info.
7547  dump_file << "1 # assigned boundary coordinates initial zeta values"
7548  << std::endl;
7549 
7550  // Save the initial and final boundary coordinates, same as
7551  // the initial and final zeta values for each boundary
7552 
7553  // First the vertices coordinates
7554  Vector<double> initial_coordinates =
7555  this->boundary_initial_coordinate(b);
7556 
7557  Vector<double> final_coordinates = this->boundary_final_coordinate(b);
7558 
7559  dump_file << std::setprecision(14) << initial_coordinates[0] << " "
7560  << initial_coordinates[1]
7561  << " # initial coordinates for the current boundary"
7562  << std::endl;
7563 
7564  dump_file << std::setprecision(14) << final_coordinates[0] << " "
7565  << final_coordinates[1]
7566  << " # final coordinates for the current boundary"
7567  << std::endl;
7568 
7569  // ... then the zeta values
7570 
7571 #ifdef PARANOID
7572  // Get the number of zeta coordinates (should be one)
7573  const unsigned zeta_size =
7574  this->boundary_initial_zeta_coordinate(b).size();
7575 
7576  if (zeta_size != 1)
7577  {
7578  std::ostringstream error_message;
7579  error_message
7580  << "The dimension for the zeta values container is different\n"
7581  << "from 1, the current implementation only supports\n"
7582  << "one-dimensioned zeta containers\n\n";
7583  throw OomphLibError(
7584  error_message.str(),
7585  "TriangleMesh::dump_distributed_info_for_restart()",
7586  OOMPH_EXCEPTION_LOCATION);
7587  }
7588 #endif
7589 
7590  Vector<double> zeta_initial =
7591  this->boundary_initial_zeta_coordinate(b);
7592  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7593 
7594  dump_file << std::setprecision(14) << zeta_initial[0]
7595  << " # initial zeta value for the current boundary"
7596  << std::endl;
7597 
7598  dump_file << std::setprecision(14) << zeta_final[0]
7599  << " # final zeta value for the current boundary"
7600  << std::endl;
7601 
7602  // Get the number of segments of the current boundary
7603  const unsigned nsegments = this->nboundary_segment(b);
7604  // Save the number of segments of the current boundary
7605  dump_file << b << " " << nsegments
7606  << " # of segments for the current boundary" << std::endl;
7607 
7608  // ... and then save that info for each segments
7609  for (unsigned is = 0; is < nsegments; is++)
7610  {
7611  // First the vertices coordinates
7612  Vector<double> initial_segment_coordinates =
7613  this->boundary_segment_initial_coordinate(b)[is];
7614  Vector<double> final_segment_coordinates =
7615  this->boundary_segment_final_coordinate(b)[is];
7616 
7617  dump_file
7618  << std::setprecision(14) << initial_segment_coordinates[0] << " "
7619  << initial_segment_coordinates[1]
7620  << " # initial segment coordinates for the current boundary"
7621  << std::endl;
7622 
7623  dump_file << std::setprecision(14) << final_segment_coordinates[0]
7624  << " " << final_segment_coordinates[1]
7625  << " # final segment coordinates for the current boundary"
7626  << std::endl;
7627 
7628  // ... then the zeta values
7629 
7630  if (this->boundary_geom_object_pt(b) != 0)
7631  {
7632  const double zeta_segment_initial =
7633  this->boundary_segment_initial_zeta(b)[is];
7634  const double zeta_segment_final =
7635  this->boundary_segment_final_zeta(b)[is];
7636 
7637  dump_file
7638  << std::setprecision(14) << zeta_segment_initial
7639  << " # initial segment zeta value for the current boundary"
7640  << std::endl;
7641 
7642  dump_file
7643  << std::setprecision(14) << zeta_segment_final
7644  << " # final segment zeta value for the current boundary"
7645  << std::endl;
7646  }
7647  else
7648  {
7649  const double arclength_segment_initial =
7650  this->boundary_segment_initial_arclength(b)[is];
7651  const double arclength_segment_final =
7652  this->boundary_segment_final_arclength(b)[is];
7653 
7654  dump_file
7655  << std::setprecision(14) << arclength_segment_initial
7656  << " # initial segment arclength for the current boundary"
7657  << std::endl;
7658 
7659  dump_file << std::setprecision(14) << arclength_segment_final
7660  << " # final segment arclength for the current boundary"
7661  << std::endl;
7662 
7663  } // else if (this->boundary_geom_object_pt(b)!=0)
7664 
7665  } // for (is < nsegments)
7666 
7667  } // if (Assigned_segments_initial_zeta_values[b])
7668  else
7669  {
7670  // The boundary coordinates have NOT been computed then state
7671  // the flag and save the info.
7672  dump_file << "0 # assigned boundary coordinates initial zeta values"
7673  << std::endl;
7674  }
7675 
7676  } // for (b < nboundary)
7677 
7678  } // if (this->is_mesh_distributed())
7679  }
7680 
7681  //======================================================================
7682  /// Used to read info. related with distributed triangle meshes
7683  //======================================================================
7684  template<class ELEMENT>
7686  std::istream& restart_file)
7687  {
7688  // First check that the mesh is distributed
7689  if (this->is_mesh_distributed())
7690  {
7691  // Read the number of original boundaries
7692  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7693 
7694 #ifdef PARANOID
7695  if (n_boundary != this->nboundary())
7696  {
7697  std::ostringstream error_message;
7698  error_message
7699  << "The number of boundaries (" << n_boundary << ") on the "
7700  << "file used for restarting is different\nfrom the number of "
7701  << "boundaries (" << this->nboundary() << ") on the current "
7702  << "mesh!!!\n\n\n";
7703  throw OomphLibError(error_message.str(),
7704  "TriangleMesh::read_distributed_info_for_restart()",
7705  OOMPH_EXCEPTION_LOCATION);
7706  }
7707 #endif
7708 
7709  // Read the number of shared boundaries
7710  unsigned n_shared_boundaries = read_unsigned_line_helper(restart_file);
7711  // We need to read the data because it comes in the file (add and
7712  // substract to avoid compilation warning)
7713  n_shared_boundaries++;
7714  n_shared_boundaries--;
7715 
7716  // Read the initial and final shared boundaries ids
7717  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7718  // We need to read the data because it comes in the file (add and
7719  // substract to avoid compilation warning)
7720  init_shd_bnd_id++;
7721  init_shd_bnd_id--;
7722  // Add and substract to avoid compilation warning
7723  unsigned final_shd_bnd_id = read_unsigned_line_helper(restart_file);
7724  // We need to read the data because it comes in the file (add and
7725  // substract to avoid compilation warning)
7726  final_shd_bnd_id++;
7727  final_shd_bnd_id--;
7728 
7729  // Read the number of processors involved in the generation of
7730  // mesh before restart
7731  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7732 
7733 #ifdef PARANOID
7734  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7735  {
7736  std::ostringstream error_message;
7737  error_message
7738  << "The number of previously used processors (" << n_procs
7739  << ") (read from the restart file) is different\nfrom the "
7740  << "number of current used processors ("
7741  << this->communicator_pt()->nproc() << ")\n\n";
7742  throw OomphLibError(error_message.str(),
7743  "TriangleMesh::read_distributed_info_for_restart()",
7744  OOMPH_EXCEPTION_LOCATION);
7745  }
7746 #endif
7747 
7748  // Clear all previuos info. related with shared boundaries
7749  this->shared_boundaries_ids().clear();
7750  this->shared_boundary_from_processors().clear();
7751  this->shared_boundary_overlaps_internal_boundary().clear();
7752 
7753  // Create the storage for the shared boundaries ids related with
7754  // the processors
7755  this->shared_boundaries_ids().resize(n_procs);
7756 
7757  // Now read the processors ids and the shared boundary created
7758  // by them
7759  for (unsigned ip = 0; ip < n_procs; ip++)
7760  {
7761  // Create the storage for the shared boundaries ids related with
7762  // the processors
7763  this->shared_boundaries_ids(ip).resize(n_procs);
7764  for (unsigned jp = 0; jp < n_procs; jp++)
7765  {
7766  if (ip != jp)
7767  {
7768  // Read the number of shared boundaries with in these two
7769  // processors
7770  const unsigned nshared_boundaries_iproc_jproc =
7771  read_unsigned_line_helper(restart_file);
7772  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7773  {
7774  // Get the processors
7775  unsigned tmp_ip;
7776  restart_file >> tmp_ip;
7777  unsigned tmp_jp;
7778  restart_file >> tmp_jp;
7779 
7780  // Get the shared boundary id created by these two
7781  // processors
7782  const unsigned shared_boundary_id =
7783  read_unsigned_line_helper(restart_file);
7784 
7785  // Update the info. of the processors that give rise to
7786  // the shared boundaries
7787  this->shared_boundaries_ids(ip, jp).push_back(shared_boundary_id);
7788 
7789  // Update the structure that states the processors that
7790  // gave rise to the shared boundary
7791  Vector<unsigned> processors(2);
7792  processors[0] = ip;
7793  processors[1] = jp;
7794  this->shared_boundary_from_processors()[shared_boundary_id] =
7795  processors;
7796 
7797  } // for (is < nshared_boundaries_iproc_jproc)
7798  }
7799  } // for (jp < n_procs)
7800  } // for (ip < n_procs)
7801 
7802  // Now read the info. that states which shared boundary overlaps
7803  // an internal boundary
7804 
7805  // First check if there are shared boundaries overlapping internal
7806  // boundaries
7807  const unsigned nshared_boundaries_overlap_internal_boundaries =
7808  read_unsigned_line_helper(restart_file);
7809 
7810  for (unsigned isb = 0;
7811  isb < nshared_boundaries_overlap_internal_boundaries;
7812  isb++)
7813  {
7814  // Read the shared boundary that overlaps an internal boundary
7815  unsigned shared_boundary_overlapping;
7816  restart_file >> shared_boundary_overlapping;
7817  // ... and read the internal boundary that overlaps
7818  const unsigned overlapped_internal_boundary =
7819  read_unsigned_line_helper(restart_file);
7820 
7821  // Re-establish the info. of the shared boundaries overlapped
7822  // by internal boundaries
7823  this->shared_boundary_overlaps_internal_boundary()
7824  [shared_boundary_overlapping] = overlapped_internal_boundary;
7825  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7826 
7827  // Now read the info. related with the initial and final
7828  // boundary coordinates for each original boundary
7829 
7830  // Go through all the (original) boundaries to update the initial
7831  // and final boundary coordinates
7832  for (unsigned b = 0; b < n_boundary; b++)
7833  {
7834  // For each boundary check if the boundary coordinates initial
7835  // and final zeta vales were assigned in the restart file
7836  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7837  read_unsigned_line_helper(restart_file);
7838 
7839  if (boundary_coordinates_initial_zeta_values_assigned)
7840  {
7841  // Clear any previous stored info. There should not be
7842  // info. already stored but better clear the info. for the
7843  // boundary
7844  Boundary_initial_coordinate[b].clear();
7845  Boundary_final_coordinate[b].clear();
7846 
7847  Boundary_initial_zeta_coordinate[b].clear();
7848  Boundary_final_zeta_coordinate[b].clear();
7849 
7850  // The info. for the segments
7851  Boundary_segment_inverted[b].clear();
7852  Boundary_segment_initial_coordinate[b].clear();
7853  Boundary_segment_final_coordinate[b].clear();
7854 
7855  Boundary_segment_initial_zeta[b].clear();
7856  Boundary_segment_final_zeta[b].clear();
7857 
7858  Boundary_segment_initial_arclength[b].clear();
7859  Boundary_segment_final_arclength[b].clear();
7860 
7861  // Read the initial and final boundary coordinates, same as
7862  // the initial and final zeta values for each boundary
7863 
7864  // First the vertices coordinates
7865  Vector<double> initial_coordinates(2);
7866 
7867  // Read the initial coordinates
7868  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7869 
7870  // Ignore rest of line
7871  restart_file.ignore(80, '\n');
7872 
7873  Vector<double> final_coordinates(2);
7874 
7875  // Read the final coordinates
7876  restart_file >> final_coordinates[0] >> final_coordinates[1];
7877 
7878  // Ignore rest of line
7879  restart_file.ignore(80, '\n');
7880 
7881  // Set the values in the containers
7882 
7883 
7884  this->boundary_initial_coordinate(b) = initial_coordinates;
7885  this->boundary_final_coordinate(b) = final_coordinates;
7886 
7887  // ... now read the zeta values
7888  Vector<double> zeta_initial(1);
7889  restart_file >> zeta_initial[0];
7890 
7891  // Ignore rest of line
7892  restart_file.ignore(80, '\n');
7893 
7894  Vector<double> zeta_final(1);
7895  restart_file >> zeta_final[0];
7896 
7897  // Ignore rest of line
7898  restart_file.ignore(80, '\n');
7899 
7900  // Set the values in the containers
7901  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7902  this->boundary_final_zeta_coordinate(b) = zeta_final;
7903 
7904  // Get the curent boundary id from the restart file
7905  unsigned current_boundary;
7906  restart_file >> current_boundary;
7907 
7908 #ifdef PARANOID
7909  if (current_boundary != b)
7910  {
7911  std::ostringstream error_message;
7912  error_message
7913  << "The current boundary id from the restart file ("
7914  << current_boundary << ") is different from\nthe boundary id "
7915  << b << "currently used to re-establish the initial and\nfinal "
7916  << "segment's zeta values\n\n";
7917  throw OomphLibError(
7918  error_message.str(),
7919  "TriangleMesh::read_distributed_info_for_restart()",
7920  OOMPH_EXCEPTION_LOCATION);
7921  }
7922 #endif
7923 
7924  // ... and its number of segments
7925  unsigned nsegments;
7926  restart_file >> nsegments;
7927 
7928  // Ignore rest of line
7929  restart_file.ignore(80, '\n');
7930 
7931  // Now read all the segments info.
7932 
7933  // ... and then save that info for each segments
7934  for (unsigned is = 0; is < nsegments; is++)
7935  {
7936  // First the vertices coordinates
7937  Vector<double> initial_segment_coordinates(2);
7938 
7939  // Read the initial coordinates
7940  restart_file >> initial_segment_coordinates[0] >>
7941  initial_segment_coordinates[1];
7942 
7943  // Ignore rest of line
7944  restart_file.ignore(80, '\n');
7945 
7946  Vector<double> final_segment_coordinates(2);
7947 
7948  // Read the final coordinates
7949  restart_file >> final_segment_coordinates[0] >>
7950  final_segment_coordinates[1];
7951 
7952  // Ignore rest of line
7953  restart_file.ignore(80, '\n');
7954 
7955  // Set the values in the containers
7956  this->boundary_segment_initial_coordinate(b).push_back(
7957  initial_segment_coordinates);
7958  this->boundary_segment_final_coordinate(b).push_back(
7959  final_segment_coordinates);
7960 
7961  // ... then the zeta values for the segment
7962  if (this->boundary_geom_object_pt(b) != 0)
7963  {
7964  Vector<double> zeta_segment_initial(1);
7965  restart_file >> zeta_segment_initial[0];
7966 
7967  // Ignore rest of line
7968  restart_file.ignore(80, '\n');
7969 
7970  Vector<double> zeta_segment_final(1);
7971  restart_file >> zeta_segment_final[0];
7972 
7973  // Ignore rest of line
7974  restart_file.ignore(80, '\n');
7975 
7976  // Set the values in the containers for the segment
7977  this->boundary_segment_initial_zeta(b).push_back(
7978  zeta_segment_initial[0]);
7979  this->boundary_segment_final_zeta(b).push_back(
7980  zeta_segment_final[0]);
7981  }
7982  else
7983  {
7984  Vector<double> arclength_segment_initial(1);
7985  restart_file >> arclength_segment_initial[0];
7986 
7987  // Ignore rest of line
7988  restart_file.ignore(80, '\n');
7989 
7990  Vector<double> arclength_segment_final(1);
7991  restart_file >> arclength_segment_final[0];
7992 
7993  // Ignore rest of line
7994  restart_file.ignore(80, '\n');
7995 
7996  // Set the values in the containers for the segment
7997  this->boundary_segment_initial_arclength(b).push_back(
7998  arclength_segment_initial[0]);
7999  this->boundary_segment_final_arclength(b).push_back(
8000  arclength_segment_final[0]);
8001  } // else if (this->boundary_geom_object_pt(b)!=0)
8002 
8003  } // for (is < nsegments)
8004 
8005  } // if (boundary_coordinates_initial_zeta_values_assigned)
8006 
8007  } // for (b < n_boundary)
8008 
8009  } // if (this->is_mesh_distributed())
8010  }
8011 
8012 #endif // #ifdef OOMPH_HAS_MPI
8013 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
8014 
8015  //===================================================================
8016  // Output the nodes on the boundaries and their / respective boundary
8017  // coordinates(into separate tecplot / zones)
8018  //===================================================================
8019  template<class ELEMENT>
8021  std::ostream& outfile)
8022  {
8023  // First get all the elements adjacent to the given boundary, then
8024  // the face elements and extract the nodes on the boundaries using
8025  // the face elements. We can not use the data structure
8026  // Boundary_node_pt since the multi_domain functions add nodes there
8027  // without assigning the required boundary coordinate
8028 
8029  // Store the nodes in a set so we do not have repeated nodes
8030  std::set<Node*> boundary_nodes_pt;
8031  const unsigned n_boundary_ele = this->nboundary_element(b);
8032  for (unsigned e = 0; e < n_boundary_ele; e++)
8033  {
8034  // Get the boundary bulk element
8035  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
8036 #ifdef OOMPH_HAS_MPI
8037  // Only work with nonhalo elements if the mesh is distributed
8038  if (!bulk_ele_pt->is_halo())
8039  {
8040 #endif
8041  // Get the face index
8042  int face_index = this->face_index_at_boundary(b, e);
8043  // Create the face element
8044  FiniteElement* face_ele_pt =
8045  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
8046 
8047  // Get the number of nodes on the face element
8048  const unsigned n_nodes = face_ele_pt->nnode();
8049  for (unsigned i = 0; i < n_nodes; i++)
8050  {
8051  // Get the nodes in the face elements
8052  Node* tmp_node_pt = face_ele_pt->node_pt(i);
8053  // Add the nodes to the set of boundary nodes
8054  boundary_nodes_pt.insert(tmp_node_pt);
8055  } // for (i < n_nodes)
8056 
8057  // Free the memory allocated for the face element
8058  delete face_ele_pt;
8059  face_ele_pt = 0;
8060 #ifdef OOMPH_HAS_MPI
8061  } // if (!bulk_ele_pt->is_halo())
8062 #endif
8063 
8064  } // for (e < n_boundary_ele)
8065 
8066  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
8067  // Set to store the boundary nodes in order
8068  std::set<Vector<double>> set_node_coord;
8069  // Loop over the nodes on the boundary and store them in the set
8070  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
8071  it != boundary_nodes_pt.end();
8072  it++)
8073  {
8074  Node* inode_pt = (*it);
8075 
8076  // Get the node coordinates
8077  const unsigned n_dim = inode_pt->ndim();
8078  Vector<double> node_coord(n_dim + 1);
8079 
8080  // Get the boundary coordinate
8081  Vector<double> zeta(1);
8082  inode_pt->get_coordinates_on_boundary(b, zeta);
8083  node_coord[0] = zeta[0];
8084  for (unsigned j = 0; j < n_dim; j++)
8085  {
8086  node_coord[j + 1] = inode_pt->x(j);
8087  }
8088  set_node_coord.insert(node_coord);
8089  }
8090 
8091  for (std::set<Vector<double>>::iterator it = set_node_coord.begin();
8092  it != set_node_coord.end();
8093  it++)
8094  {
8095  // Get the node coordinates
8096  Vector<double> node_coord = (*it);
8097 
8098  // Output the node coordinates
8099  const unsigned n_dim = node_coord.size() - 1;
8100  for (unsigned j = 0; j < n_dim; j++)
8101  {
8102  outfile << node_coord[j + 1] << " ";
8103  }
8104  // ... add an extra coordinate to avoid error with tecplot
8105  outfile << "0.0" << std::endl;
8106  }
8107 
8108  // ... loop again to plot the bound coordinates
8109  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
8110  for (std::set<Vector<double>>::iterator it = set_node_coord.begin();
8111  it != set_node_coord.end();
8112  it++)
8113  {
8114  // Get the node coordinates
8115  Vector<double> node_coord = (*it);
8116 
8117  // Output the node coordinates
8118  const unsigned n_dim = node_coord.size() - 1;
8119  for (unsigned j = 0; j < n_dim; j++)
8120  {
8121  outfile << node_coord[j + 1] << " ";
8122  }
8123 
8124  // Output the boundary coordinate
8125  outfile << node_coord[0] << std::endl;
8126  }
8127  }
8128 
8129 #ifdef OOMPH_HAS_MPI
8130  //====================================================================
8131  // Creates the distributed domain representation. Joins the
8132  // original boundaires, shared boundaries and creates connections among
8133  // them to create the new polygons that represent the distributed
8134  // domain
8135  //====================================================================
8136  template<class ELEMENT>
8138  Vector<TriangleMeshPolygon*>& polygons_pt,
8139  Vector<TriangleMeshOpenCurve*>& open_curves_pt)
8140  {
8141  // Get the outer polygons, internal polygons, internal open curves
8142  // and join them with the shared polylines to create the distributed
8143  // domain representation (the new outer, internal polygons, and new
8144  // internal open curves)
8145 
8146  // Get the rank of the current processor
8147  const unsigned my_rank = this->communicator_pt()->my_rank();
8148 
8149  // *********************************************************************
8150  // Step (2) Get the outer, internal and shared boundaries to create the
8151  // new polygons
8152  // *********************************************************************
8153 
8154  // *********************************************************************
8155  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8156  // a new representation (for example when the boundary was splitted in
8157  // the distribution process)
8158  // *********************************************************************
8159 
8160  // Storage for new created polylines, non sorted
8161  Vector<TriangleMeshPolyLine*> unsorted_outer_polyline_pt;
8162 
8163  // Storing for the polylines on the boundaries
8164  // The first index is for a set of connected polylines
8165  // The second index is for a polyline on a set of connected polylines
8166  Vector<Vector<TriangleMeshPolyLine*>> sorted_outer_curves_pt;
8167 
8168  // Copy the outer boundaries to the vector of polylines
8169  const unsigned nouter = this->Outer_boundary_pt.size();
8170  for (unsigned i = 0; i < nouter; i++)
8171  {
8172  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8173  for (unsigned p = 0; p < npolylines; p++)
8174  {
8175  // Pointer to the current polyline
8176  TriangleMeshPolyLine* tmp_polyline_pt =
8177  this->Outer_boundary_pt[i]->polyline_pt(p);
8178  const unsigned nvertex = tmp_polyline_pt->nvertex();
8179  if (nvertex > 0)
8180  {
8181  // Get the boundary id of the polyline and check if that boundary
8182  // needs a new representation (for example when the boundary was
8183  // splitted in the distribution process)
8184  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8185  if (!boundary_was_splitted(bound_id))
8186  {
8187  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8188  } // if (!boundary_was_splitted(bound_id))
8189  else
8190  {
8191  // Get the polylines that will represent this boundary
8192  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8193  boundary_subpolylines(bound_id);
8194  const unsigned nsub_poly = tmp_vector_polylines.size();
8195 #ifdef PARANOID
8196  if (nsub_poly <= 1)
8197  {
8198  std::ostringstream error_message;
8199  error_message << "The boundary (" << bound_id
8200  << ") was marked to be splitted but\n"
8201  << "there are only (" << nsub_poly
8202  << ") polylines to represent it.\n";
8203  throw OomphLibError(error_message.str(),
8204  OOMPH_CURRENT_FUNCTION,
8205  OOMPH_EXCEPTION_LOCATION);
8206  }
8207 #endif
8208  // Add the new representation of the polylines (sub-polylines)
8209  // to represent this boundary
8210  for (unsigned isub = 0; isub < nsub_poly; isub++)
8211  {
8212  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8213 #ifdef PARANOID
8214  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8215  if (nsvertex == 0)
8216  {
8217  std::ostringstream error_message;
8218  error_message
8219  << "The current chunk (" << isub << ") of the polyline with\n"
8220  << "boundary id (" << bound_id << ") has no vertices\n";
8221  throw OomphLibError(error_message.str(),
8222  OOMPH_CURRENT_FUNCTION,
8223  OOMPH_EXCEPTION_LOCATION);
8224  } // if (nsvertex == 0)
8225 #endif // #ifdef PARANOID
8226  } // for (isub < nsub_poly)
8227  } // else if (!boundary_was_splitted(bound_id))
8228  } // if (nvertex > 0)
8229  } // for (p < npolylines)
8230  } // for (i < nouter)
8231 
8232  // Get the number of unsorted polylines
8233  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8234  if (nunsorted_outer_polyline > 0)
8235  {
8236  // Now that we have all the new unsorted polylines it is time to sort them
8237  // so they be all contiguous
8238  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8239 
8240  } // if (nunsorted_outer_polyline > 0)
8241 
8242  // *********************************************************************
8243  // Step (2.2) Get the internal closed boundaries and check if it is
8244  // necessary to use a new representation (for example when the boundary
8245  // was splitted in the distribution process)
8246  // *********************************************************************
8247 
8248  // Storage for new created polylines, non sorted
8249  Vector<TriangleMeshPolyLine*> unsorted_internal_closed_polyline_pt;
8250 
8251  // Storing for the polylines on the boundaries
8252  // The first index is for a set of connected polylines
8253  // The second index is for a polyline on a set of connected polylines
8254  Vector<Vector<TriangleMeshPolyLine*>> sorted_internal_closed_curves_pt;
8255 
8256  // Copy the internal closed boundaries to the vector of polylines
8257  const unsigned ninternal_closed = this->Internal_polygon_pt.size();
8258  for (unsigned i = 0; i < ninternal_closed; i++)
8259  {
8260  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8261  for (unsigned p = 0; p < npolylines; p++)
8262  {
8263  // Pointer to the current polyline
8264  TriangleMeshPolyLine* tmp_polyline_pt =
8265  this->Internal_polygon_pt[i]->polyline_pt(p);
8266  const unsigned nvertex = tmp_polyline_pt->nvertex();
8267  if (nvertex > 0)
8268  {
8269  // Get the boundary id of the polyline and check if that boundary
8270  // needs a new representation (for example when the boundary was
8271  // splitted in the distribution process)
8272  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8273  if (!boundary_was_splitted(bound_id))
8274  {
8275  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8276  } // if (!boundary_was_splitted(bound_id))
8277  else
8278  {
8279  // Get the polylines that will represent this boundary
8280  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8281  boundary_subpolylines(bound_id);
8282  const unsigned nsub_poly = tmp_vector_polylines.size();
8283 #ifdef PARANOID
8284  if (nsub_poly <= 1)
8285  {
8286  std::ostringstream error_message;
8287  error_message << "The boundary (" << bound_id
8288  << ") was marked to be splitted but\n"
8289  << "there are only (" << nsub_poly
8290  << ") polylines to represent it.\n";
8291  throw OomphLibError(error_message.str(),
8292  OOMPH_CURRENT_FUNCTION,
8293  OOMPH_EXCEPTION_LOCATION);
8294  }
8295 #endif
8296  // Add the new representation of the polylines (sub-polylines)
8297  // to represent this boundary
8298  for (unsigned isub = 0; isub < nsub_poly; isub++)
8299  {
8300  unsorted_internal_closed_polyline_pt.push_back(
8301  tmp_vector_polylines[isub]);
8302 #ifdef PARANOID
8303  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8304  if (nsvertex == 0)
8305  {
8306  std::ostringstream error_message;
8307  error_message
8308  << "The current chunk (" << isub << ") of the polyline with\n"
8309  << "boundary id (" << bound_id << ") has no vertices\n";
8310  throw OomphLibError(error_message.str(),
8311  OOMPH_CURRENT_FUNCTION,
8312  OOMPH_EXCEPTION_LOCATION);
8313  } // if (nsvertex == 0)
8314 #endif // #ifdef PARANOID
8315  } // for (isub < nsub_poly)
8316  } // else if (!boundary_was_splitted(bound_id))
8317  } // if (nvertex > 0)
8318  } // for (p < npolylines)
8319  } // for (i < ninternal_closed)
8320 
8321  const unsigned nunsorted_internal_closed_polyline =
8322  unsorted_internal_closed_polyline_pt.size();
8323 
8324  if (nunsorted_internal_closed_polyline > 0)
8325  {
8326  // Now that we have all the new unsorted polylines it is time to sort them
8327  // so they be all contiguous
8328  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8329  sorted_internal_closed_curves_pt);
8330  }
8331 
8332  // *********************************************************************
8333  // Step (2.3) Get the internal open boundaries and check if it is
8334  // necessary to use a new representation (for example when the boundary
8335  // was splitted in the distribution process)
8336  // *********************************************************************
8337 
8338  // Storage for new created polylines, non sorted
8339  Vector<TriangleMeshPolyLine*> unsorted_internal_open_polyline_pt;
8340 
8341  // Storing for the polylines on the boundaries
8342  // The first index is for a set of connected polylines
8343  // The second index is for a polyline on a set of connected polylines
8344  Vector<Vector<TriangleMeshPolyLine*>> sorted_internal_open_curves_pt;
8345 
8346  // Copy the internal open boundaries to the vector of polylines
8347  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8348  for (unsigned i = 0; i < ninternal_open; i++)
8349  {
8350  const unsigned ncurve_section =
8351  this->Internal_open_curve_pt[i]->ncurve_section();
8352  for (unsigned p = 0; p < ncurve_section; p++)
8353  {
8354  // Pointer to the current polyline
8355  TriangleMeshPolyLine* tmp_polyline_pt =
8356  this->Internal_open_curve_pt[i]->polyline_pt(p);
8357  const unsigned nvertex = tmp_polyline_pt->nvertex();
8358  if (nvertex > 0)
8359  {
8360  // Get the boundary id of the polyline and check if that boundary
8361  // needs a new representation (for example when the boundary was
8362  // splitted in the distribution process)
8363  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8364  if (!boundary_was_splitted(bound_id))
8365  {
8366  // Only include as internal boundaries those not marked as
8367  // shared boundaries
8368  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8369  {
8370  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8371  }
8372  } // if (!boundary_was_splitted(bound_id))
8373  else
8374  {
8375  // Get the polylines that will represent this boundary
8376  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8377  boundary_subpolylines(bound_id);
8378  const unsigned nsub_poly = tmp_vector_polylines.size();
8379 #ifdef PARANOID
8380  if (nsub_poly <= 1)
8381  {
8382  std::ostringstream error_message;
8383  error_message << "The boundary (" << bound_id
8384  << ") was marked to be splitted but\n"
8385  << "there are only (" << nsub_poly
8386  << ") polylines to represent it.\n";
8387  throw OomphLibError(error_message.str(),
8388  OOMPH_CURRENT_FUNCTION,
8389  OOMPH_EXCEPTION_LOCATION);
8390  }
8391 #endif
8392  // Add the new representation of the polylines (sub-polylines)
8393  // to represent this boundary
8394  for (unsigned isub = 0; isub < nsub_poly; isub++)
8395  {
8396  // Only include as internal boundaries those not marked as
8397  // shared boundaries
8398  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8399  {
8400  unsorted_internal_open_polyline_pt.push_back(
8401  tmp_vector_polylines[isub]);
8402  }
8403 #ifdef PARANOID
8404  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8405  if (nsvertex == 0)
8406  {
8407  std::ostringstream error_message;
8408  error_message
8409  << "The current chunk (" << isub << ") of the polyline with\n"
8410  << "boundary id (" << bound_id << ") has no vertices\n";
8411  throw OomphLibError(error_message.str(),
8412  OOMPH_CURRENT_FUNCTION,
8413  OOMPH_EXCEPTION_LOCATION);
8414  } // if (nsvertex == 0)
8415 #endif // #ifdef PARANOID
8416  } // for (isub < nsub_poly)
8417  } // else if (!boundary_was_splitted(bound_id))
8418  } // if (nvertex > 0)
8419  } // for (p < npolylines)
8420  } // for (i < ninternal_open)
8421 
8422  const unsigned nunsorted_internal_open_polyline =
8423  unsorted_internal_open_polyline_pt.size();
8424 
8425  if (nunsorted_internal_open_polyline > 0)
8426  {
8427  // Now that we have all the new unsorted polylines it is time to sort them
8428  // so they be all contiguous
8429  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8430  sorted_internal_open_curves_pt);
8431  }
8432 
8433  // ********************************************************************
8434  // Step (2.4) Sort the polylines on the shared boundaries
8435  // ********************************************************************
8436 
8437  // Storage for new created polylines, non sorted
8438  Vector<TriangleMeshPolyLine*> unsorted_shared_polyline_pt;
8439 
8440  // Special storage for the shared polylines that will be also used
8441  // to connect with the internal boundaries
8442  Vector<TriangleMeshPolyLine*> unsorted_shared_to_internal_polyline_pt;
8443 
8444  // Storing for the polylines on the shared boundaries
8445  // The first index is for a set of connected polylines
8446  // The second index is for a polyline on a set of connected polylines
8447  Vector<Vector<TriangleMeshPolyLine*>> sorted_shared_curves_pt;
8448 
8449  // Copy the shared boudaries to the vector of polylines
8450  const unsigned ncurves = nshared_boundary_curves(my_rank);
8451  for (unsigned i = 0; i < ncurves; i++)
8452  {
8453  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8454  for (unsigned p = 0; p < npolylines; p++)
8455  {
8456  const unsigned nvertex =
8457  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8458  if (nvertex > 0)
8459  {
8460  TriangleMeshPolyLine* tmp_shared_poly_pt =
8461  shared_boundary_polyline_pt(my_rank, i, p);
8462 
8463  // First check if there are shared boundaries overlapping
8464  // internal boundaries
8465  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8466  {
8467  // Get the boundary id of the shared polyline
8468  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8469  // If the shared polyline is marked as internal boundary
8470  // then include it in the special storage to look for
8471  // connection with internal boundaries
8472  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8473  {
8474  unsorted_shared_to_internal_polyline_pt.push_back(
8475  tmp_shared_poly_pt);
8476  }
8477  }
8478  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8479  }
8480  }
8481  }
8482 
8483  // Get the total number of shared polylines
8484  const unsigned nunsorted_shared_polyline =
8485  unsorted_shared_polyline_pt.size();
8486 
8487  if (nunsorted_shared_polyline > 0)
8488  {
8489  // Now that we have all the new unsorted polylines it is time to
8490  // sort them so they be all contiguous
8491  sort_polylines_helper(unsorted_shared_polyline_pt,
8492  sorted_shared_curves_pt);
8493  }
8494 
8495  // ********************************************************************
8496  // Step (3) Join the boundaries (shared, internal and outer to
8497  // create the new polygons)
8498  // ********************************************************************
8499 
8500  // Create the set of curves that will be used to create the new polygons
8501  // Get the total number of curves
8502  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8503  const unsigned ninternal_closed_curves =
8504  sorted_internal_closed_curves_pt.size();
8505  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8506  const unsigned ntotal_curves =
8507  nouter_curves + ninternal_closed_curves + nshared_curves;
8508 
8509  // Add all the polylines to a container
8510  unsigned counter = 0;
8511  Vector<Vector<TriangleMeshPolyLine*>> all_curves_pt(ntotal_curves);
8512 
8513  // Add the shared curves first, this ensure the generation of
8514  // internal polygons defined by the shared boundaries
8515  for (unsigned i = 0; i < nshared_curves; i++, counter++)
8516  {
8517  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8518  }
8519 
8520  // Add the internal polygons (if any)
8521  for (unsigned i = 0; i < ninternal_closed_curves; i++, counter++)
8522  {
8523  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8524  }
8525 
8526  // Add the outer polygons
8527  for (unsigned i = 0; i < nouter_curves; i++, counter++)
8528  {
8529  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8530  }
8531 
8532  // Create the temporary version of the domain by joining the new
8533  // polylines
8534  this->create_tmp_polygons_helper(all_curves_pt, polygons_pt);
8535  // Create the new open curves
8536  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8537  unsorted_shared_to_internal_polyline_pt,
8538  open_curves_pt);
8539 
8540  // ********************************************************************
8541  // Step (4) Create connections among the outer boundaries
8542  // (intersections with themselves)
8543  // ********************************************************************
8544 
8545  // After creating the new boundaries representation (polylines)
8546  // establish the connections of the shared boundaries (with
8547  // themselves or with the original boundaries). This avoids the
8548  // multiple definition of vertices in the domain which cause
8549  // problems when calling Triangle
8550 
8551  this->create_shared_polylines_connections();
8552 
8553  // ------------------------------------------------------------------
8554  // Compute the new holes information. Those from the
8555  // extra_holes_coordinates container, and those from the original
8556  // closed boundaries. Add the holes created by the halo elements
8557  // adjacent to the shared boundaries
8558 
8559  // The storage for the new holes, get those from the
8560  // extra_holes_coordinates container and those from the internal
8561  // closed boundaries that are defined as holes
8562  Vector<Vector<double>> new_holes_coordinates;
8563 
8564  // Copy the holes (those defined by the original internal closed
8565  // boundaries and those in the extra holes container)
8566 
8567  // The holes defined by the original internal closed boundaries
8568  const unsigned n_holes = this->Internal_polygon_pt.size();
8569  for (unsigned h = 0; h < n_holes; h++)
8570  {
8571  Vector<double> hole_coordinates =
8572  this->Internal_polygon_pt[h]->internal_point();
8573  // If the closed boundary is a hole, then copy its hole
8574  if (!hole_coordinates.empty())
8575  {
8576  new_holes_coordinates.push_back(hole_coordinates);
8577  }
8578  } // for (h < n_holes)
8579 
8580  // Is this the first time we are going to copy the extra holes
8581  // coordinates
8582  if (First_time_compute_holes_left_by_halo_elements)
8583  {
8584  // The holes in the extra holes container
8585  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8586  for (unsigned h = 0; h < n_extra_holes; h++)
8587  {
8588  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8589  new_holes_coordinates.push_back(hole_coordinates);
8590  } // for (h < n_extra_holes)
8591 
8592  // Copy the extra holes coordinates
8593  Original_extra_holes_coordinates = Extra_holes_coordinates;
8594 
8595  // Set the flag to false
8596  First_time_compute_holes_left_by_halo_elements = false;
8597 
8598  } // if (First_time_compute_holes_left_by_halo_elements)
8599  else
8600  {
8601  // Not the first time, then only copy the original extra holes
8602  // coordinates
8603  const unsigned n_original_extra_holes =
8604  Original_extra_holes_coordinates.size();
8605  for (unsigned h = 0; h < n_original_extra_holes; h++)
8606  {
8607  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8608  new_holes_coordinates.push_back(hole_coordinates);
8609  } // for (h < n_original_extra_holes)
8610  }
8611 
8612  // Add the holes created by the halo elements adjacent to the shared
8613  // boundaries
8614  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8615 
8616  // Update the holes information, only use the coordinate inside the
8617  // poylgons that define the new domain
8618  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8619 
8620  // tachidok Clear the storage by now
8621  // new_holes_coordinates.clear();
8622 
8623  // Now copy the info. in the extra holes coordinates container
8624  Extra_holes_coordinates = new_holes_coordinates;
8625 
8626  // Do not delete halo(ed) info., this will be "deleted"
8627  // automatically by not passing that information to the new adapted
8628  // mesh. Once the transfer of target areas is performed the halo(ed)
8629  // information is no longer required
8630  }
8631 
8632  //======================================================================
8633  // Take the polylines from the shared boundaries and the boundaries
8634  // to create polygons
8635  //======================================================================
8636  template<class ELEMENT>
8638  Vector<Vector<TriangleMeshPolyLine*>>& polylines_pt,
8639  Vector<TriangleMeshPolygon*>& polygons_pt)
8640  {
8641  // Each vector of polylines (curve) is already sorted, it means that
8642  // all the polylines on the vector polylines_pt[i] point to the same
8643  // direction
8644 
8645  // --- Using this fact we should compare the first and last points from
8646  // these arrays of polylines (curves) and compare with the others
8647  // vectors of polylines (curves) end points
8648  // --- Once created a closed curve create a polygon
8649 
8650  // The number of curves
8651  const unsigned ncurves = polylines_pt.size();
8652 
8653  // The number of non sorted curves
8654  const unsigned nunsorted_curves = ncurves;
8655  // The number of sorted curves
8656  unsigned nsorted_curves = 0;
8657 
8658  // Vector to know which ncurve is already done
8659  std::vector<bool> done_curve(ncurves);
8660 
8661  do
8662  {
8663  // The list where to add the curves so that they be contiguous
8664  std::list<Vector<TriangleMeshPolyLine*>> list_building_polygon_pt;
8665 #ifdef PARANOID
8666  // Flag to indicate that a root curve was found
8667  bool root_curve_found = false;
8668 #endif
8669 
8670  // The index for the root_curve (we use it in further iterations as the
8671  // starting index so we dont need to search in already done curves)
8672  unsigned root_curve_idx = 0;
8673 
8674  // Get the root curve
8675  for (unsigned ic = 0; ic < ncurves; ic++)
8676  {
8677  if (!done_curve[ic])
8678  {
8679  root_curve_idx = ic;
8680  nsorted_curves++;
8681 #ifdef PARANOID
8682  root_curve_found = true;
8683 #endif
8684  done_curve[ic] = true;
8685  // ... break the loop
8686  break;
8687  }
8688  }
8689 
8690 #ifdef PARANOID
8691  if (!root_curve_found)
8692  {
8693  std::stringstream err;
8694  err << "The root curve to create a polygon from the shared and "
8695  << "original boundaries was not found!!!\n";
8696  throw OomphLibError(err.str(),
8697  "TriangleMesh::create_tmp_polygons_helper()",
8698  OOMPH_EXCEPTION_LOCATION);
8699  }
8700 #endif
8701 
8702  // Get the root curve
8703  Vector<TriangleMeshPolyLine*> root_curve_pt =
8704  polylines_pt[root_curve_idx];
8705 
8706  // Add the root curve to the list
8707  list_building_polygon_pt.push_back(root_curve_pt);
8708 
8709  // Get the initial and final vertices from the root curve
8710  Vector<double> root_curve_initial_vertex(2);
8711  Vector<double> root_curve_final_vertex(2);
8712 
8713  // We need to get the number of polylines that compose the root curve
8714  const unsigned nroot_curve_polyline = root_curve_pt.size();
8715  // ... and now get the initial and final vertex
8716  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8717  root_curve_pt[nroot_curve_polyline - 1]->final_vertex_coordinate(
8718  root_curve_final_vertex);
8719 
8720  // First check if it already create a polygon
8721  double diff =
8722  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0]) *
8723  (root_curve_initial_vertex[0] - root_curve_final_vertex[0])) +
8724  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1]) *
8725  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8726  diff = sqrt(diff);
8727  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8728  {
8729  // The polyline already create a Polygon, then create it!!!
8730  // Create the curve section representation of the current root curve
8731  Vector<TriangleMeshCurveSection*> curve_section_pt(
8732  nroot_curve_polyline);
8733 
8734  // Copy the polylines into its curve section representation
8735  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8736  {
8737  curve_section_pt[i] = root_curve_pt[i];
8738  }
8739 
8740  // ... and create the Polygon
8741  TriangleMeshPolygon* new_polygon_pt =
8742  new TriangleMeshPolygon(curve_section_pt);
8743 
8744  // Mark the polygon for deletion (in the destructor)
8745  this->Free_polygon_pt.insert(new_polygon_pt);
8746 
8747  // Add the polygon to the output polygons
8748  polygons_pt.push_back(new_polygon_pt);
8749  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8750  // when the curve creates a Polygon by itself
8751  else
8752  {
8753  // Flag to continue iterating while curves be added to the left
8754  // or right of the list of curves
8755  bool added_curve = false;
8756 #ifdef PARANOID
8757  // Flag to know if the "loop" finish because a polygon was
8758  // created or because no more curves can be added to the left or
8759  // right
8760  bool polygon_created = false;
8761 #endif
8762  do
8763  {
8764  added_curve = false;
8765  // If the root curve does not create a closed polygon then add curves
8766  // to the left or right until the curves create a closed polygon
8767  for (unsigned ic = root_curve_idx + 1; ic < ncurves; ic++)
8768  {
8769  if (!done_curve[ic])
8770  {
8771  // Get the current curve
8772  Vector<TriangleMeshPolyLine*> current_curve_pt = polylines_pt[ic];
8773 
8774  // We need to get the number of polylines that compose the
8775  // current curve
8776  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8777 
8778  // ... and get the initial and final coordinates for the current
8779  // curve
8780  Vector<double> current_curve_initial_vertex(2);
8781  Vector<double> current_curve_final_vertex(2);
8782 
8783  current_curve_pt[0]->initial_vertex_coordinate(
8784  current_curve_initial_vertex);
8785  current_curve_pt[ncurrent_curve_polyline - 1]
8786  ->final_vertex_coordinate(current_curve_final_vertex);
8787 
8788  // ---------------------------------------------------------------
8789  // Start adding curves to the left or right
8790  // ---------------------------------------------------------------
8791  diff = ((current_curve_final_vertex[0] -
8792  root_curve_initial_vertex[0]) *
8793  (current_curve_final_vertex[0] -
8794  root_curve_initial_vertex[0])) +
8795  ((current_curve_final_vertex[1] -
8796  root_curve_initial_vertex[1]) *
8797  (current_curve_final_vertex[1] -
8798  root_curve_initial_vertex[1]));
8799  diff = sqrt(diff);
8800  // CURRENT curve to the LEFT of the ROOT curve
8801  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8802  {
8803  // Add the current curve to the left
8804  list_building_polygon_pt.push_front(current_curve_pt);
8805  // Mark the curve as done
8806  done_curve[ic] = true;
8807  // Update the initial vertex values
8808  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8809  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8810  // Increase the number of sorted curves
8811  nsorted_curves++;
8812  // Set the flag to indicate that a curve was added to the list
8813  added_curve = true;
8814  break;
8815  }
8816 
8817  diff = ((current_curve_initial_vertex[0] -
8818  root_curve_initial_vertex[0]) *
8819  (current_curve_initial_vertex[0] -
8820  root_curve_initial_vertex[0])) +
8821  ((current_curve_initial_vertex[1] -
8822  root_curve_initial_vertex[1]) *
8823  (current_curve_initial_vertex[1] -
8824  root_curve_initial_vertex[1]));
8825  diff = sqrt(diff);
8826  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8827  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8828  {
8829  Vector<TriangleMeshPolyLine*> tmp_curve_pt(
8830  ncurrent_curve_polyline);
8831  // Reverse each polyline and back them up
8832  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8833  {
8834  current_curve_pt[it]->reverse();
8835  tmp_curve_pt[it] = current_curve_pt[it];
8836  }
8837  // Now copy them back but in reverse order
8838  unsigned count = 0;
8839  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--, count++)
8840  {
8841  current_curve_pt[count] = tmp_curve_pt[i];
8842  }
8843  // Add the current curve to the left
8844  list_building_polygon_pt.push_front(current_curve_pt);
8845  // Mark the curve as done
8846  done_curve[ic] = true;
8847  // Update the initial vertex values
8848  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8849  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8850  // Increase the number of sorted curves
8851  nsorted_curves++;
8852  // Set the flag to indicate that a curve was added to the list
8853  added_curve = true;
8854  break;
8855  }
8856 
8857  diff = ((current_curve_initial_vertex[0] -
8858  root_curve_final_vertex[0]) *
8859  (current_curve_initial_vertex[0] -
8860  root_curve_final_vertex[0])) +
8861  ((current_curve_initial_vertex[1] -
8862  root_curve_final_vertex[1]) *
8863  (current_curve_initial_vertex[1] -
8864  root_curve_final_vertex[1]));
8865  diff = sqrt(diff);
8866  // CURRENT curve to the RIGHT of the ROOT curve
8867  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8868  {
8869  // Add the current curve to the right
8870  list_building_polygon_pt.push_back(current_curve_pt);
8871  // Mark the curve as done
8872  done_curve[ic] = true;
8873  // Update the initial vertex values
8874  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8875  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8876  // Increase the number of sorted curves
8877  nsorted_curves++;
8878  // Set the flag to indicate that a curve was added to the list
8879  added_curve = true;
8880  break;
8881  }
8882 
8883  diff =
8884  ((current_curve_final_vertex[0] - root_curve_final_vertex[0]) *
8885  (current_curve_final_vertex[0] - root_curve_final_vertex[0])) +
8886  ((current_curve_final_vertex[1] - root_curve_final_vertex[1]) *
8887  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8888  diff = sqrt(diff);
8889  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8890  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8891  {
8892  Vector<TriangleMeshPolyLine*> tmp_curve_pt(
8893  ncurrent_curve_polyline);
8894  // Reverse each polyline and back them up
8895  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8896  {
8897  current_curve_pt[it]->reverse();
8898  tmp_curve_pt[it] = current_curve_pt[it];
8899  }
8900  // Now copy them back but in reverse order
8901  unsigned count = 0;
8902  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--, count++)
8903  {
8904  current_curve_pt[count] = tmp_curve_pt[i];
8905  }
8906  // Add the current curve to the right
8907  list_building_polygon_pt.push_back(current_curve_pt);
8908  // Mark the curve as done
8909  done_curve[ic] = true;
8910  // Update the initial vertex values
8911  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8912  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8913  // Increase the number of sorted curves
8914  nsorted_curves++;
8915  // Set the flag to indicate that a curve was added to the list
8916  added_curve = true;
8917  break;
8918  }
8919 
8920  } // if (!done_curve[ic])
8921 
8922  } // for (ic < ncurves)
8923 
8924  // After adding a curve check if it is possible to create a polygon
8925  double diff =
8926  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0]) *
8927  (root_curve_initial_vertex[0] - root_curve_final_vertex[0])) +
8928  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1]) *
8929  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8930  diff = sqrt(diff);
8931  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8932  {
8933  // If the curves already create a Polygon then go out of the
8934  // loop and create the Polygon
8935  added_curve = false;
8936 #ifdef PARANOID
8937  // Set the flag to indicate that a Polygon has been created
8938  polygon_created = true;
8939 #endif
8940  } // (diff <
8941  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8942  // when the curve creates a Polygon by itself
8943 
8944  } while (added_curve);
8945 
8946 #ifdef PARANOID
8947  if (!polygon_created)
8948  {
8949  std::stringstream error_message;
8950  error_message
8951  << "It was no possible to create a TriangleMeshPolygon with "
8952  << "the input set of curves\n"
8953  << "These are the initial and final vertices in the current "
8954  << "sorted list of\nTriangleMeshPolyLines\n\n";
8955  Vector<double> init_vertex(2);
8956  Vector<double> final_vertex(2);
8957  unsigned icurve = 0;
8958  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8959  list_building_polygon_pt.begin();
8960  it != list_building_polygon_pt.end();
8961  it++, icurve++)
8962  {
8963  const unsigned ncurrent_curve_polyline = (*it).size();
8964  error_message << "TriangleMeshCurve #" << icurve << "\n"
8965  << "-----------------------------------\n";
8966  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8967  {
8968  Vector<double> init_vertex(2);
8969  Vector<double> final_vertex(2);
8970  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8971  (*it)[ip]->final_vertex_coordinate(final_vertex);
8972  error_message << "TriangleMeshPolyLine #" << ip << "\n"
8973  << "Initial vertex: (" << init_vertex[0] << ","
8974  << init_vertex[1] << ")\n"
8975  << "Final vertex: (" << final_vertex[0] << ","
8976  << final_vertex[1] << ")\n";
8977  } // for (ip < ncurrent_curve_polyline)
8978  } // for (it != list_building_polygon_pt.end())
8979 
8980  throw OomphLibError(error_message.str(),
8981  "TriangleMesh::create_tmp_polygons_helper()",
8982  OOMPH_EXCEPTION_LOCATION);
8983 
8984  } // if (!polygon_created)
8985 #endif
8986 
8987  // Create the polygon after joining the curves
8988  unsigned ntotal_polylines = 0;
8989  // Get the total number of polylines
8990  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
8991  list_building_polygon_pt.begin();
8992  it != list_building_polygon_pt.end();
8993  it++)
8994  {
8995  ntotal_polylines += (*it).size();
8996  }
8997 
8998  // Create the curve section representation of the curves on the list
8999  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
9000 
9001  // Copy the polylines into its curve section representation
9002  unsigned counter = 0;
9003  for (std::list<Vector<TriangleMeshPolyLine*>>::iterator it =
9004  list_building_polygon_pt.begin();
9005  it != list_building_polygon_pt.end();
9006  it++)
9007  {
9008  const unsigned ncurrent_curve_polyline = (*it).size();
9009  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++, counter++)
9010  {
9011  curve_section_pt[counter] = (*it)[ip];
9012  } // for (ip < ncurrent_curve_polyline)
9013  } // Loop over the list of polylines
9014 
9015  // ... and create the Polygon
9016  TriangleMeshPolygon* new_polygon_pt =
9017  new TriangleMeshPolygon(curve_section_pt);
9018 
9019  // Mark the polygon for deletion (in the destructor)
9020  this->Free_polygon_pt.insert(new_polygon_pt);
9021 
9022  // Add the polygon to the output polygons
9023  polygons_pt.push_back(new_polygon_pt);
9024 
9025  } // else
9026  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
9027 
9028  } while (nsorted_curves < nunsorted_curves);
9029  }
9030 
9031  //======================================================================
9032  // Take the polylines from the original open curves and created
9033  // new temporaly representations of open curves with the bits of
9034  // original curves not overlapped by shared boundaries
9035  //======================================================================
9036  template<class ELEMENT>
9038  Vector<Vector<TriangleMeshPolyLine*>>& sorted_open_curves_pt,
9039  Vector<TriangleMeshPolyLine*>& unsorted_shared_to_internal_poly_pt,
9040  Vector<TriangleMeshOpenCurve*>& open_curves_pt)
9041  {
9042  // Here search for the connections of the open curves remaining as
9043  // open curves with the shared boundaries markes as internal
9044  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
9045 
9046  // Once identified the connections created with the new internal
9047  // boundaries representations add them to the open curves container
9048  for (unsigned i = 0; i < ninternal_open_curves; i++)
9049  {
9050  // Create the curve section representation of the polylines
9051  const unsigned npoly = sorted_open_curves_pt[i].size();
9052  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
9053  for (unsigned j = 0; j < npoly; j++)
9054  {
9055  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
9056  }
9057  // ... and create the Open Curve
9058  TriangleMeshOpenCurve* new_open_curve_pt =
9059  new TriangleMeshOpenCurve(tmp_curve_section);
9060 
9061  // Mark the open curve for deletion (in the destructor)
9062  this->Free_open_curve_pt.insert(new_open_curve_pt);
9063 
9064  // Add the open curve to the output open curves
9065  open_curves_pt.push_back(new_open_curve_pt);
9066 
9067  } // (i < ninternal_open_curves)
9068  }
9069 
9070  //======================================================================
9071  // Check for any possible connections that the array of sorted
9072  // nodes have with original boundary nodes, previous shared polyline
9073  // nodes or with itself polyline nodes. In case that there is a
9074  // connection, get the boundary id to which connects
9075  //======================================================================
9076  template<class ELEMENT>
9078  std::set<FiniteElement*>& element_in_processor_pt,
9079  const int& root_edge_bnd_id,
9080  std::map<std::pair<Node*, Node*>, bool>& overlapped_face,
9081  std::map<unsigned, std::map<Node*, bool>>&
9082  node_on_bnd_not_overlapped_by_shd_bnd,
9083  std::list<Node*>& current_polyline_nodes,
9084  std::map<unsigned, std::list<Node*>>& shared_bnd_id_to_sorted_list_node_pt,
9085  const unsigned& node_degree,
9086  Node*& new_node_pt,
9087  const bool called_from_load_balance)
9088  {
9089  // Initialize the flag to return
9090  int flag_to_return = -1;
9091 
9092  // --------------------------------------------------------------------
9093  // First try to find a connection with any original boundary (keep
9094  // in mind the case when internal boundaries may be overlapped by
9095  // shared boundaries)
9096  // --------------------------------------------------------------------
9097 
9098  // Check if the shared boundary is overlapping an internal boundary
9099  bool overlapping_internal_boundary = false;
9100  // The boundary id overlapped by the current shared boundary
9101  unsigned internal_overlaping_bnd_id = 0;
9102  if (root_edge_bnd_id != -1)
9103  {
9104  // Set the flat to true
9105  overlapping_internal_boundary = true;
9106  // Set the bnd id of the overlapped internal boundary
9107  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
9108  } // if (root_edge_bnd_id != -1)
9109 
9110  // ---------------------------------------------------------------
9111  // Check if the connection is with an original boundary by checking
9112  // if the new node is a boundary node, and it lives in an element
9113  // that is part of the domain
9114  // ---------------------------------------------------------------
9115  if (new_node_pt->is_on_boundary())
9116  {
9117  // Flag to indicate if the node lives in a non overlapped boundary
9118  bool is_node_living_in_non_overlapped_boundary = false;
9119 
9120  // If the node is a boundary node then check in which boundary it
9121  // is
9122  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
9123  for (unsigned bb = 0; bb < noriginal_bnd; bb++)
9124  {
9125  // If the shared boundary overlaps an internal boundary it will
9126  // be indicated by (root_edge_bnd_id != -1), the original
9127  // internal boundary that overlaps is given by the
9128  // root_edge_bnd_id value. We skip that original internal
9129  // boundary because the new node will be obviously ON the
9130  // internal boundary
9131  if (overlapping_internal_boundary)
9132  {
9133  // Is the node on boundary bb?
9134  if (new_node_pt->is_on_boundary(bb))
9135  {
9136  // If overlaping then check that the boundary is different
9137  // from the one that is being overlapped, or if overlapped
9138  // then check that the node is on an edge on the bb
9139  // boundary not overlapped by a shared boundary
9140  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9141  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9142  if (bb != internal_overlaping_bnd_id ||
9143  ((bb == internal_overlaping_bnd_id) &&
9144  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9145  {
9146  // Is the node living in a non overlapped boundary
9147  if (bb != internal_overlaping_bnd_id)
9148  {
9149  is_node_living_in_non_overlapped_boundary = true;
9150  }
9151 
9152  // Now we need to check that the node lies on a boundary
9153  // that still exist (the elements associated to the
9154  // boundary may have been removed at the mesh distribution
9155  // stage). The node may be still marked as a boundary node
9156  // but the boundary may not have elements associated.
9157 
9158  // Get the number of elements in the boundary
9159  const unsigned n_bound_ele = this->nboundary_element(bb);
9160  if (n_bound_ele > 0)
9161  {
9162  // Check that node lies on a nonhalo element, those are
9163  // the elements used to update the domain representation
9164  for (unsigned e = 0; e < n_bound_ele; e++)
9165  {
9166  // Get the boundary bulk element
9167  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9168  // Check if the element will be retained, it means it
9169  // is a nonhalo element
9170  std::set<FiniteElement*>::iterator it =
9171  element_in_processor_pt.find(bulk_ele_pt);
9172  // If found then check if the node live in the element
9173  if (it != element_in_processor_pt.end())
9174  {
9175  // Found the node in the nonhalo face element
9176  bool found_node = false;
9177  // Get the face index
9178  int face_index = this->face_index_at_boundary(bb, e);
9179  // Create the face element
9180  FiniteElement* face_ele_pt =
9181  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9182  // Get the number of nodes in the face element
9183  const unsigned n_node_face = face_ele_pt->nnode();
9184  // Get the first and last node of the face element
9185  Node* first_node_pt = face_ele_pt->node_pt(0);
9186  Node* last_node_pt = face_ele_pt->node_pt(n_node_face - 1);
9187  // Create the edge with the pair of nodes
9188  std::pair<Node*, Node*> tmp_edge =
9189  std::make_pair(first_node_pt, last_node_pt);
9190  // Check if the face element edge is overlapped by a
9191  // shared boundary
9192  // Is the face not overlapped?
9193  if (!overlapped_face[tmp_edge])
9194  {
9195  // Look for the node in the current face element
9196  for (unsigned n = 0; n < n_node_face; n++)
9197  {
9198  // Check for every individual node
9199  if (face_ele_pt->node_pt(n) == new_node_pt)
9200  {
9201  found_node = true;
9202  break;
9203  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9204  } // for (n < n_node_face)
9205  } // if (!overlapped_face[tmp_edge])
9206  // Free the memory of the face element
9207  delete face_ele_pt;
9208  if (found_node)
9209  {
9210  // return the first original boundary id found,
9211  // does not matter if the node lies on more than
9212  // one original boundary (with boundary
9213  // elements). This is the original boundary id
9214  // that will be used to create the connection
9215  flag_to_return = bb;
9216  return flag_to_return;
9217  } // if (found_node)
9218 
9219  } // if (it!=element_in_processor_pt.end())
9220 
9221  } // for (e < n_bound_ele)
9222 
9223  } // if (n_bound_ele > 0)
9224 
9225  } // if (bb != internal_overlaping_bnd_id ||
9226  // ((bb == internal_overlaping_bnd_id) &&
9227  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9228 
9229  } // if (nod_pt->is_on_boundary(bb))
9230 
9231  } // if (overlapping_internal_boundary)
9232  else
9233  {
9234  // Is the node on boundary bb?
9235  if (new_node_pt->is_on_boundary(bb))
9236  {
9237  // Now we need to check that the node lies on a boundary
9238  // that still exist (the elements associated to the boundary
9239  // may have been removed at the mesh distribution
9240  // stage). The node may be still marked as a boundary node
9241  // but the boundary may not have elements associated.
9242 
9243  // Get the number of elements in the boundary
9244  const unsigned n_bound_ele = this->nboundary_element(bb);
9245  if (n_bound_ele > 0)
9246  {
9247  // Check that node lies on a nonhalo element, those are
9248  // the elements used to update the domain representation
9249  for (unsigned e = 0; e < n_bound_ele; e++)
9250  {
9251  // Get the boundary bulk element
9252  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9253  // Check if the element will be retained, it means it is
9254  // a nonhalo element
9255  std::set<FiniteElement*>::iterator it =
9256  element_in_processor_pt.find(bulk_ele_pt);
9257  // If found then check if the node live in the element
9258  if (it != element_in_processor_pt.end())
9259  {
9260  // Found the node in the nonhalo face element
9261  bool found_node = false;
9262  // Get the face index
9263  int face_index = this->face_index_at_boundary(bb, e);
9264  // Create the face element
9265  FiniteElement* face_ele_pt =
9266  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9267  // Get the number of nodes in the face element
9268  const unsigned n_node_face = face_ele_pt->nnode();
9269  // Get the first and last node of the face element
9270  Node* first_node_pt = face_ele_pt->node_pt(0);
9271  Node* last_node_pt = face_ele_pt->node_pt(n_node_face - 1);
9272  // Create the edge with the pair of nodes
9273  std::pair<Node*, Node*> tmp_edge =
9274  std::make_pair(first_node_pt, last_node_pt);
9275  // Check if the face element edge is overlapped by a
9276  // shared boundary
9277  // Is the face not overlapped?
9278  if (!overlapped_face[tmp_edge])
9279  {
9280  // Look for the node in the current face element
9281  for (unsigned n = 0; n < n_node_face; n++)
9282  {
9283  // Check for every individual node
9284  if (face_ele_pt->node_pt(n) == new_node_pt)
9285  {
9286  found_node = true;
9287  break;
9288  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9289  } // for (n < n_node_face)
9290  } // if (!overlapped_face[tmp_edge])
9291  // Free the memory of the face element
9292  delete face_ele_pt;
9293  if (found_node)
9294  {
9295  // return the first original boundary id found, does
9296  // not matter if the node lies on more than one
9297  // original boundary (with boundary elements). This
9298  // is the original boundary id that will be used to
9299  // create the connection
9300  flag_to_return = bb;
9301  return flag_to_return;
9302  } // if (found_node)
9303 
9304  } // if (it!=element_in_processor_pt.end())
9305 
9306  } // for (e < n_bound_ele)
9307 
9308  } // if (n_bound_ele > 0)
9309 
9310  } // if (nod_pt->is_on_boundary(bb))
9311  } // else if (overlapping_internal_boundary)
9312  } // for (bb < noriginal_bnd)
9313 
9314  // We will only reach this stage when the node was found to be
9315  // connected to an original boundary but the element(s) on that
9316  // boundary where the node should live are not part of the domain.
9317  // Think in a corner of a triangle which touches the boundary
9318  // which elements will not be part of the domain
9319 
9320  // We need to break the currently forming polyline
9321  // flag_to_return = -3;
9322 
9323  // We need to break the currently forming polyline if and only if
9324  // the boundary(ies) in which the node is living is(are) not an
9325  // overlapped boundary
9326  if (!overlapping_internal_boundary)
9327  {
9328  // If the boundary(ies) in which the node is living is(are) an
9329  // overlapped boundary then break the break the formation of the
9330  // polyline
9331  flag_to_return = -3;
9332  }
9333  else
9334  {
9335  // The boundary is overlapped, if the node lives in a non
9336  // overlapped boundary then we can break the formation of the
9337  // polyline
9338  if (is_node_living_in_non_overlapped_boundary)
9339  {
9340  flag_to_return = -3;
9341  } // if (is_node_living_in_non_overlapped_boundar)y
9342 
9343  } // if (!overlapping_internal_boundary)
9344 
9345  } // if (new_node_pt->is_on_boundary())
9346 
9347  // Return inmediately if the connection is with an original boundary
9348  // whose elements are still part of the domain
9349  if (flag_to_return >= 0)
9350  {
9351  return flag_to_return;
9352  }
9353 
9354  // ----------------------------------------------------------------------
9355  // Secondly, if there is not a connection with any original
9356  // boundary, or if there is connection but with an original boundary
9357  // whose elements are not part of the domain, then check for
9358  // connections with previously created shared polylines
9359  // ----------------------------------------------------------------------
9360  // Store all the previous shared polylines to which the current
9361  // found is found to be connected
9362  Vector<unsigned> candidate_shared_bnd_to_connect;
9363  // Check for all the previous polylines except the current one
9364  for (std::map<unsigned, std::list<Node*>>::iterator it =
9365  shared_bnd_id_to_sorted_list_node_pt.begin();
9366  it != shared_bnd_id_to_sorted_list_node_pt.end();
9367  it++)
9368  {
9369  // Get the boundary id of the list of nodes that created the
9370  // polyline (the shared boundary id associated with the list of
9371  // nodes)
9372  const unsigned i_bnd_id = (*it).first;
9373  // Get an iterator pointer to the list of nodes of the shared
9374  // polyline
9375  std::list<Node*>::iterator it_list = (*it).second.begin();
9376  // Get the total number of nodes associated to the boundary
9377  const unsigned n_nodes = (*it).second.size();
9378  // Search for connections in the list of nodes
9379  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9380  {
9381  // Is the node already part of any other shared boundary
9382  if ((*it_list) == new_node_pt)
9383  {
9384  // Include the i-th boundary id in the list of candidate
9385  // shared boundaries to connect
9386  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9387  // Break the look with the i-th shared boundary, check with
9388  // the others shared boundaries
9389  break;
9390  } // if ((*it_list) == new_node_pt)
9391 
9392  } // for (i < nnodes)
9393 
9394  } // Loop over the shared boundaries and associated nodes
9395 
9396  // Get the number of candidate shared boundaries to connect
9397  const unsigned n_candidate_shared_bnd_to_connect =
9398  candidate_shared_bnd_to_connect.size();
9399 
9400  // Is there a connection with any previous shared polyline
9401  if (n_candidate_shared_bnd_to_connect > 0)
9402  {
9403  // If called from load balance we do not need to check if the
9404  // shared boundary is part of the processor since it certanily is,
9405  // only the shared boundaries that are pare of the processor are
9406  // used to created connection when creating the new shared
9407  // boundaries in the load balance rutine
9408  if (called_from_load_balance)
9409  {
9410  return candidate_shared_bnd_to_connect[0];
9411  }
9412 
9413  // We need to ensure that the shared boundary to which we are
9414  // connecting is part of the current processor, if none of the
9415  // found shared bundaries is in the current processor then return
9416  // the flag for "connection with boundary not in the current
9417  // processor"
9418 
9419  // Store the shared boundaries associated with the current processor
9420  Vector<unsigned> shared_bound_in_this_proc;
9421 
9422  // Get the shared boundaries associated with the current processor
9423  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9424 
9425  // If any of the candidate shared boundaries to connect is in the
9426  // current processor then return that shared boundary id
9427 
9428  // The number of shared boundaries in the current processor
9429  const unsigned n_shared_bound_in_this_proc =
9430  shared_bound_in_this_proc.size();
9431 
9432  // Loop over the candidate shared boundaries to connect
9433  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9434  {
9435  // Get the i-th candidate shared boundary to connect
9436  const unsigned i_candidate_shared_bnd =
9437  candidate_shared_bnd_to_connect[i];
9438 
9439  // Loop over the shared boundaries in the current processor
9440  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9441  {
9442  // Is the candidate boundary a shared boundary in this processor?
9443  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9444  {
9445  // Return the candidate shared boundary
9446  flag_to_return = i_candidate_shared_bnd;
9447  return flag_to_return;
9448  } // The candidate shared boundary is a boundary in the
9449  // current processor
9450 
9451  } // for (j < n_shared_bound_in_this_proc)
9452 
9453  } // for (i < n_candidate_shared_bnd_to_connect)
9454 
9455  // If non of the candidate shared boundaries to connect is in the
9456  // current processor the mark that we need to stop the addition of
9457  // vertices at this side of the polyline
9458  flag_to_return = -3;
9459 
9460  } // if (n_candidate_shared_bnd_to_connect > 0)
9461 
9462  // Return inmediately if the connection is with a previuos shared
9463  // boundary
9464  if (flag_to_return >= 0)
9465  {
9466  return flag_to_return;
9467  }
9468 
9469  // ------------------------------------------------------------------
9470  // Finally,check for connections with the same polyline (the shared
9471  // boundary that is being constructed). We are trying to avoid loops
9472  // or connections with the same shared boundary that is why this is
9473  // checked at the end
9474  // ------------------------------------------------------------------
9475  unsigned nrepeated = 0;
9476  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9477  it_list != current_polyline_nodes.end();
9478  it_list++)
9479  {
9480  // There must be at least one repeated node (the one that we have
9481  // just added, and it should be the first or last node)
9482  if ((*it_list) == new_node_pt)
9483  {
9484  nrepeated++;
9485  }
9486  }
9487  // If the number of repeated nodes is greater than one then the
9488  // polyline has a connection with itself
9489  if (nrepeated > 1)
9490  {
9491  // Return the flag value to indicate connection with itself, we
9492  // can not return the boundary id of the current polyline since it
9493  // has not been already assigned
9494  flag_to_return = -2;
9495  }
9496 
9497  // If there is no connection at all check the degree of the node, if
9498  // it is greater than 2 then return the flag to stop adding nodes
9499  // after this one
9500  if (node_degree > 2)
9501  {
9502  flag_to_return = -3;
9503  }
9504 
9505  // Return the flag
9506  return flag_to_return;
9507  }
9508 
9509  //======================================================================
9510  // Establish the connections of the polylines previously
9511  // marked as having connections. This connections were created in the
9512  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9513  // In case of doing load balancing the connections were created by the
9514  // function RefineableTriangleMesh::create_new_shared_boundaries()
9515  // ======================================================================
9516  template<class ELEMENT>
9518  {
9519  // Get the rank of the current processor
9520  const unsigned my_rank = this->communicator_pt()->my_rank();
9521 
9522  // Get the shared curves associated with this processor
9523  Vector<Vector<TriangleMeshPolyLine*>> shared_curves_pt =
9524  this->Shared_boundary_polyline_pt[my_rank];
9525 
9526  // Loop through the shared boundaries on the current processor and
9527  // check if they are marked to create a connection
9528  const unsigned ncurves = shared_curves_pt.size();
9529  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9530  {
9531  // Get the number of polylines in the current shared curve
9532  const unsigned npoly = shared_curves_pt[icurve].size();
9533  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9534  {
9535  // Get the polyline representation of the shared boundary
9536  TriangleMeshPolyLine* shd_poly_pt = shared_curves_pt[icurve][ipoly];
9537 
9538  // Get the boundary id of the current polyline
9539  const unsigned bound_id = shd_poly_pt->boundary_id();
9540 
9541  // Is the left vertex connected
9542  const bool is_connected_to_the_left =
9543  shd_poly_pt->is_initial_vertex_connected();
9544 
9545  // Is the right vertex connected
9546  const bool is_connected_to_the_right =
9547  shd_poly_pt->is_final_vertex_connected();
9548 
9549  // -----------------------------------------------------------------
9550  // If there is a connection at one of the ends we need to
9551  // establish that connection
9552  if (is_connected_to_the_left || is_connected_to_the_right)
9553  {
9554  // Now get the new left and right vertices of the shared
9555  // polyline
9556  const unsigned n_vertex = shd_poly_pt->nvertex();
9557 
9558  // Now get the polylines to where the current shared boundary is
9559  // connected and create the connections
9560 
9561  // --------------------------------------------------------------
9562  // Connection to the left
9563  if (is_connected_to_the_left)
9564  {
9565  // Get the unsigned version of the bound id to connect to
9566  // the left
9567  const unsigned uconnection_to_the_left =
9568  shd_poly_pt->initial_vertex_connected_bnd_id();
9569 
9570  // The pointer to the boundary to connect
9571  TriangleMeshPolyLine* poly_to_connect_pt = 0;
9572 
9573  // Flag to indicate we are trying to connect to an split
9574  // boundary
9575  bool connecting_to_an_split_boundary = false;
9576 
9577  // Flag to indicate we are trying to connecto to an internal
9578  // boundary that is overlaped by a shared boundary
9579  bool connecting_to_an_overlaped_boundary = false;
9580 
9581  // Check if the connection is with itself
9582  if (uconnection_to_the_left == bound_id)
9583  {
9584  // Set the pointer to the polyline to connect
9585  poly_to_connect_pt = shd_poly_pt;
9586  }
9587  else
9588  {
9589  // Get the initial shared boundary ids
9590  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9591  // Check if the boundary to connect is a shared polyline
9592  if (uconnection_to_the_left >= initial_shd_bnd_id)
9593  {
9594  // Get the polyline pointer representing the destination
9595  // boundary
9596  poly_to_connect_pt =
9597  boundary_polyline_pt(uconnection_to_the_left);
9598  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9599  else
9600  {
9601  // If we are going to connect to an original boundary
9602  // verify if the boundary was splitted during the
9603  // distribution process to consider all the chunks
9604  // (sub-polylines) of the boundary
9605  if (boundary_was_splitted(uconnection_to_the_left))
9606  {
9607  connecting_to_an_split_boundary = true;
9608  } // if (boundary_was_splitted(uconnection_to_the_left))
9609 
9610  // If we are going to connect to an original boundary
9611  // verify if the boundary, or any of its chunks is
9612  // marked to be overlapped by a shared boundary, if that
9613  // is the case we first check for connections in the
9614  // shared boundary that overlaps the internal boundary,
9615  // or the chunks, and then check for connections in the
9616  // original boundary
9617  if (connecting_to_an_split_boundary)
9618  {
9619  // Get the number of chucks that represent the
9620  // destination boundary
9621  const unsigned n_sub_poly =
9622  nboundary_subpolylines(uconnection_to_the_left);
9623  // Now loop over the chunks of the destination
9624  // boundary and if any of them is marked to be
9625  // overlaped by a shared boundary then set the flag
9626  // and break the loop
9627  for (unsigned ii = 0; ii < n_sub_poly; ii++)
9628  {
9629  if (boundary_marked_as_shared_boundary(
9630  uconnection_to_the_left, ii))
9631  {
9632  // Mark the boundary as being overlaped by a
9633  // shared boundary
9634  connecting_to_an_overlaped_boundary = true;
9635  // Break, no need to look for more overlapings
9636  break;
9637  } // if (boundary_marked_as_shared_boundary(...))
9638  } // for (ii < n_sub_poly)
9639  } // if (connecting_to_an_split_boundary)
9640  else
9641  {
9642  // If not connecting to an split boundary then check
9643  // if the whole destination boundary is overlaped by
9644  // an internal boundary
9645  if (boundary_marked_as_shared_boundary(
9646  uconnection_to_the_left, 0))
9647  {
9648  // Mark the boundary as being overlaped by a shared
9649  // boundary
9650  connecting_to_an_overlaped_boundary = true;
9651  } // if (boundary_marked_as_shared_boundary(...))
9652  } // else if (connecting_to_an_split_boundary)
9653 
9654  // If we are connecting neither to an split boundary nor
9655  // an overlaped boundary then get the pointer to the
9656  // original boundary
9657  if (!(connecting_to_an_split_boundary ||
9658  connecting_to_an_overlaped_boundary))
9659  {
9660  // Get the polyline pointer representing the
9661  // destination boundary
9662  poly_to_connect_pt =
9663  boundary_polyline_pt(uconnection_to_the_left);
9664  } // else if (NOT split, NOT overlaped)
9665  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9666 
9667  } // else if (uconnection_to_the_left == bound_id)
9668 
9669 #ifdef PARANOID
9670  // If we are not connecting to an original boundary
9671  // (connecting to the same shared boundary or to another
9672  // shared boundary) then the boundary should not be marked
9673  // as split
9674  if (!connecting_to_an_split_boundary)
9675  {
9676  if (boundary_was_splitted(uconnection_to_the_left))
9677  {
9678  std::stringstream error;
9679  error
9680  << "The current shared boundary (" << bound_id << ") was "
9681  << "marked to have a connection\nto the left with the "
9682  << "boundary (" << uconnection_to_the_left << ").\n"
9683  << "The problem is that the destination boundary (possibly\n"
9684  << "another shared boundary) is marked to be split\n"
9685  << "There should not be split shared boundaries\n\n";
9686  throw OomphLibError(
9687  error.str(),
9688  "TriangleMesh::create_shared_polylines_connections()",
9689  OOMPH_EXCEPTION_LOCATION);
9690  }
9691  } // if (!connecting_to_an_split_boundary)
9692 #endif
9693 
9694  // Now look for the vertex number on the destination
9695  // boundary(ies) -- in case that the boundary was split ---
9696 
9697  // Do not check for same orientation, that was previously
9698  // worked by interchanging the connections boundaries (if
9699  // necessary)
9700 
9701  // Get the left vertex in the shared boundary
9702  Vector<double> shd_bnd_left_vertex =
9703  shd_poly_pt->vertex_coordinate(0);
9704 
9705  // If the boundary was not split then ...
9706  if (!connecting_to_an_split_boundary)
9707  {
9708  // ... check if the boundary is marked to be overlaped by
9709  // a shared boundary
9710  if (!connecting_to_an_overlaped_boundary)
9711  {
9712  // If that is not the case then we can safely look for
9713  // the vertex number on the destination boundar
9714  unsigned vertex_index = 0;
9715 
9716  const bool found_vertex_index =
9717  get_connected_vertex_number_on_destination_polyline(
9718  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9719 
9720  // If we could not find the vertex index to connect then
9721  // we are in trouble
9722  if (!found_vertex_index)
9723  {
9724  std::stringstream error;
9725  error
9726  << "The current shared boundary (" << bound_id << ") was "
9727  << "marked to have a connection\nto the left with the "
9728  << "boundary (" << uconnection_to_the_left << ").\n"
9729  << "The problem is that the left vertex of the current\n"
9730  << "shared boundary is not in the list of vertices of the\n"
9731  << "boundary to connect.\n\n"
9732  << "This is the left vertex of the current shared "
9733  "boundary\n"
9734  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9735  << shd_bnd_left_vertex[1] << ")\n\n"
9736  << "This is the list of vertices on the destination "
9737  << "boundary\n";
9738  const unsigned n_v = poly_to_connect_pt->nvertex();
9739  for (unsigned i = 0; i < n_v; i++)
9740  {
9741  Vector<double> cvertex =
9742  poly_to_connect_pt->vertex_coordinate(i);
9743  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9744  << cvertex[1] << ")\n";
9745  }
9746  throw OomphLibError(
9747  error.str(),
9748  "TriangleMesh::create_shared_polylines_connections()",
9749  OOMPH_EXCEPTION_LOCATION);
9750  } // if (!found_vertex_index)
9751 
9752  // Create the connection, the left vertex of the current
9753  // shared boundary is connected with the vertex_index-th
9754  // vertex on the destination boundary
9755  shd_poly_pt->connect_initial_vertex_to_polyline(
9756  poly_to_connect_pt, vertex_index);
9757 
9758  } // if (!connecting_to_an_overlaped_boundary)
9759  else
9760  {
9761  // If the boundary is marked to be overlaped by a shared
9762  // boundary then get that shared boundary and look for
9763  // the connection in that boundary
9764 
9765  // The vertex where to store the index to connect
9766  unsigned vertex_index = 0;
9767  // A flag to indicate if the connection was found
9768  bool found_vertex_index = false;
9769 
9770  // Get the shared boundary id that is overlaping the
9771  // internal boundary
9772  Vector<unsigned> dst_shd_bnd_ids;
9773  get_shared_boundaries_overlapping_internal_boundary(
9774  uconnection_to_the_left, dst_shd_bnd_ids);
9775 
9776  // Get the number of shared polylines that were found to
9777  // overlap the internal boundary
9778  const unsigned n_shd_bnd_overlap_int_bnd =
9779  dst_shd_bnd_ids.size();
9780 
9781  // Loop over the shared boundaries that overlap the
9782  // internal boundary and look for the vertex to connect
9783  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9784  {
9785  // Get the shared polyline
9786  const unsigned new_connection_to_the_left =
9787  dst_shd_bnd_ids[ss];
9788 
9789  // Get the shared polyline that is overlaping the
9790  // internal boundary
9791  poly_to_connect_pt =
9792  boundary_polyline_pt(new_connection_to_the_left);
9793 
9794  if (poly_to_connect_pt != 0)
9795  {
9796  // Look for the vertex number in the destination
9797  // shared polyline
9798  found_vertex_index =
9799  get_connected_vertex_number_on_destination_polyline(
9800  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9801  } // if (poly_to_connect_pt!=0)
9802 
9803  // If we have found the vertex to connect then
9804  // break the loop
9805  if (found_vertex_index)
9806  {
9807  break;
9808  } // if (found_vertex_index)
9809 
9810  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9811 
9812 #ifdef PARANOID
9813  // If we could not find the vertex index to connect then
9814  // we are in trouble
9815  if (!found_vertex_index)
9816  {
9817  std::stringstream error;
9818  error
9819  << "The current shared boundary (" << bound_id << ") was "
9820  << "marked to have a connection\nto the left with the "
9821  << "boundary (" << uconnection_to_the_left << ").\n"
9822  << "This last boundary is marked to be overlaped by "
9823  << "shared boundaries\n"
9824  << "The problem is that the left vertex of the current\n"
9825  << "shared boundary is not in the list of vertices of the\n"
9826  << "boundary to connect.\n\n"
9827  << "This is the left vertex of the current shared "
9828  "boundary\n"
9829  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9830  << shd_bnd_left_vertex[1] << ")\n\n"
9831  << "This is the list of vertices on the destination "
9832  << "boundary\n";
9833  Vector<unsigned> dst_shd_bnd_ids;
9834  get_shared_boundaries_overlapping_internal_boundary(
9835  uconnection_to_the_left, dst_shd_bnd_ids);
9836  const unsigned n_shd_bnd_overlap_int_bnd =
9837  dst_shd_bnd_ids.size();
9838  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9839  {
9840  const unsigned new_connection_to_the_left =
9841  dst_shd_bnd_ids[ss];
9842  poly_to_connect_pt =
9843  boundary_polyline_pt(new_connection_to_the_left);
9844  if (poly_to_connect_pt != 0)
9845  {
9846  const unsigned shd_bnd_id_overlap =
9847  poly_to_connect_pt->boundary_id();
9848  error << "Shared boundary id(" << shd_bnd_id_overlap
9849  << ")\n";
9850  const unsigned n_v = poly_to_connect_pt->nvertex();
9851  for (unsigned i = 0; i < n_v; i++)
9852  {
9853  Vector<double> cvertex =
9854  poly_to_connect_pt->vertex_coordinate(i);
9855  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9856  << cvertex[1] << ")\n";
9857  }
9858  } // if (poly_to_connect_pt != 0)
9859  } // for (ss < n_shd_bnd_overlap_int_bnd)
9860 
9861  throw OomphLibError(
9862  error.str(),
9863  "TriangleMesh::create_shared_polylines_connections()",
9864  OOMPH_EXCEPTION_LOCATION);
9865 
9866  } // if (!found_vertex_index)
9867 #endif
9868 
9869  // Create the connection, the left vertex of the current
9870  // shared boundary is connected with the vertex_index-th
9871  // vertex on the destination boundary
9872  shd_poly_pt->connect_initial_vertex_to_polyline(
9873  poly_to_connect_pt, vertex_index);
9874 
9875  } // else if (!connecting_to_an_overlaped_boundary)
9876 
9877  } // if (!connecting_to_an_split_boundary)
9878  else
9879  {
9880  // If the boundary was split then we need to look for the
9881  // vertex in the sub-polylines
9882 
9883  // Get the sub-polylines vector
9884  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9885  boundary_subpolylines(uconnection_to_the_left);
9886 
9887  // Get the number of sub-polylines
9888  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9889 #ifdef PARANOID
9890  if (nsub_poly <= 1)
9891  {
9892  std::ostringstream error_message;
9893  error_message
9894  << "The boundary (" << uconnection_to_the_left << ") was "
9895  << "marked to be splitted but\n"
9896  << "there are only (" << nsub_poly << ") polylines to "
9897  << "represent it.\n";
9898  throw OomphLibError(
9899  error_message.str(),
9900  "TriangleMesh::create_shared_polylines_connections()",
9901  OOMPH_EXCEPTION_LOCATION);
9902  } // if (nsub_poly <= 1)
9903 #endif
9904  // We need to check if the boundary is marked to be
9905  // overlaped by an internal boundary, if that is the case
9906  // we need to check for each indivual subpolyline, and for
9907  // those overlaped by a shared polyline look for the
9908  // vertex in the shared polyline representation instead of
9909  // the original subpolyline
9910 
9911  // ... check if the boundary is marked to be overlaped by
9912  // a shared boundary
9913  if (!connecting_to_an_overlaped_boundary)
9914  {
9915  // We can work without checking the subpolylines
9916  // individually
9917 
9918  // The vertex where to store the index to connect
9919  unsigned vertex_index = 0;
9920  // The subpoly number to connect
9921  unsigned sub_poly_to_connect = 0;
9922  // A flag to indicate if the connection was found
9923  bool found_vertex_index = false;
9924 
9925  // Look for the vertex number to connect on each of the
9926  // subpolyines
9927  for (unsigned isub = 0; isub < nsub_poly; isub++)
9928  {
9929  // Assign the pointer to the sub-polyline
9930  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9931  // Search for the vertex in the current sub-polyline
9932  found_vertex_index =
9933  get_connected_vertex_number_on_destination_polyline(
9934  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9935  // If we have found the vertex to connect then break the
9936  // loop
9937  if (found_vertex_index)
9938  {
9939  // But first save the subpoly number (chunk), that
9940  // will be used to perform the connection
9941  sub_poly_to_connect = isub;
9942  break;
9943  } // if (found_vertex_index)
9944  } // for (isub < nsub_poly)
9945 
9946 #ifdef PARANOID
9947  // If we could not find the vertex index to connect then
9948  // we are in trouble
9949  if (!found_vertex_index)
9950  {
9951  std::stringstream error;
9952  error
9953  << "The current shared boundary (" << bound_id << ") was "
9954  << "marked to have a connection\nto the left with the "
9955  << "boundary (" << uconnection_to_the_left << ").\n"
9956  << "The problem is that the left vertex of the current\n"
9957  << "shared boundary is not in the list of vertices of any\n"
9958  << "of the sub polylines that represent the boundary to\n"
9959  << "connect.\n\n"
9960  << "This is the left vertex of the current shared "
9961  "boundary\n"
9962  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9963  << shd_bnd_left_vertex[1] << ")\n\n"
9964  << "This is the list of vertices on the destination "
9965  << "boundary\n";
9966  for (unsigned p = 0; p < nsub_poly; p++)
9967  {
9968  error << "Subpolyline #(" << p << ")\n";
9969  poly_to_connect_pt = tmp_vector_subpolylines[p];
9970  const unsigned n_v = poly_to_connect_pt->nvertex();
9971  for (unsigned i = 0; i < n_v; i++)
9972  {
9973  Vector<double> cvertex =
9974  poly_to_connect_pt->vertex_coordinate(i);
9975  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
9976  << cvertex[1] << ")\n";
9977  }
9978  } // for (p < nsub_poly)
9979  throw OomphLibError(
9980  error.str(),
9981  "TriangleMesh::create_shared_polylines_connections()",
9982  OOMPH_EXCEPTION_LOCATION);
9983  } // if (!found_vertex_index)
9984 #endif
9985 
9986  // Create the connection, the left vertex of the current
9987  // shared boundary is connected with the vertex_index-th
9988  // vertex of sub_poly_to_connect-th subpolyline of the
9989  // destination boundary
9990  shd_poly_pt->connect_initial_vertex_to_polyline(
9991  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9992 
9993  } // if (!connecting_to_an_overlaped_boundary)
9994  else
9995  {
9996  // We first look on the shared boundaries that overlap
9997  // the internal boundaries and the look for the
9998  // sub-polylines that are not marked as being overlaped
9999  // by shared boundaries
10000 
10001  // The vertex where to store the index to connect
10002  unsigned vertex_index = 0;
10003  // The subpoly number to connect
10004  unsigned sub_poly_to_connect = 0;
10005  // A flag to indicate if the connection was found
10006  bool found_vertex_index = false;
10007 
10008  // Get the shared boundaries id that are overlaping the
10009  // internal boundary
10010  Vector<unsigned> dst_shd_bnd_ids;
10011  get_shared_boundaries_overlapping_internal_boundary(
10012  uconnection_to_the_left, dst_shd_bnd_ids);
10013 
10014  // Get the number of shared polylines that were found to
10015  // overlap the internal boundary
10016  const unsigned n_shd_bnd_overlap_int_bnd =
10017  dst_shd_bnd_ids.size();
10018 
10019  // Loop over the shared boundaries that overlap the
10020  // internal boundary and look for the vertex to connect
10021  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10022  {
10023  // Get the shared polyline
10024  const unsigned new_connection_to_the_left =
10025  dst_shd_bnd_ids[ss];
10026 
10027  // Make sure that the destination polyline is not the
10028  // same as the current shared polyline
10029  if (bound_id != new_connection_to_the_left)
10030  {
10031  // Get the shared polyline that is overlaping the
10032  // internal boundary
10033  poly_to_connect_pt =
10034  boundary_polyline_pt(new_connection_to_the_left);
10035 
10036  if (poly_to_connect_pt != 0)
10037  {
10038  // Look for the vertex number in the destination
10039  // shared polyline
10040  found_vertex_index =
10041  get_connected_vertex_number_on_destination_polyline(
10042  poly_to_connect_pt,
10043  shd_bnd_left_vertex,
10044  vertex_index);
10045  } // if (poly_to_connect_pt != 0)
10046 
10047  // If we have found the vertex to connect then
10048  // break the loop
10049  if (found_vertex_index)
10050  {
10051  break;
10052  } // if (found_vertex_index)
10053 
10054  } // if (bound_id != new_connection_to_the_left)
10055 
10056  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10057 
10058  // If we have not yet found the vertex then look for it
10059  // in the sub-polylines that are not overlaped by shared
10060  // boundaries
10061  if (!found_vertex_index)
10062  {
10063  // Look for the vertex number to connect on each of
10064  // the subpolyines
10065  for (unsigned isub = 0; isub < nsub_poly; isub++)
10066  {
10067  // Only work with those sub-polylines that are not
10068  // overlaped by shared boundaries
10069  if (!boundary_marked_as_shared_boundary(
10070  uconnection_to_the_left, isub))
10071  {
10072  // Assign the pointer to the sub-polyline
10073  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10074  // Search for the vertex in the current sub-polyline
10075  found_vertex_index =
10076  get_connected_vertex_number_on_destination_polyline(
10077  poly_to_connect_pt,
10078  shd_bnd_left_vertex,
10079  vertex_index);
10080  // If we have found the vertex to connect then break the
10081  // loop
10082  if (found_vertex_index)
10083  {
10084  // But first save the subpoly number (chunk), that
10085  // will be used to perform the connection
10086  sub_poly_to_connect = isub;
10087  break;
10088  } // if (found_vertex_index)
10089 
10090  } // if (not overlaped by shared boundary)
10091 
10092  } // for (isub < nsub_poly)
10093 
10094  } // if (!found_vertex_index)
10095 
10096 #ifdef PARANOID
10097  // If we could not find the vertex index to connect then
10098  // we are in trouble
10099  if (!found_vertex_index)
10100  {
10101  std::stringstream error;
10102  error
10103  << "The current shared boundary (" << bound_id << ") was "
10104  << "marked to have a connection\nto the left with the "
10105  << "boundary (" << uconnection_to_the_left << ").\n"
10106  << "This last boundary is marked to be overlaped by "
10107  << "shared boundaries\n"
10108  << "The problem is that the left vertex of the current\n"
10109  << "shared boundary is not in the list of vertices of "
10110  << "the\nboundary to connect.\n\n"
10111  << "This is the left vertex of the current shared "
10112  << "boundary\n"
10113  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
10114  << shd_bnd_left_vertex[1] << ")\n\n"
10115  << "This is the list of vertices on the destination "
10116  << "boundary (only those subpolylines not marked as "
10117  << "overlaped by\nshared boundaries)\n";
10118  for (unsigned p = 0; p < nsub_poly; p++)
10119  {
10120  if (!boundary_marked_as_shared_boundary(
10121  uconnection_to_the_left, p))
10122  {
10123  error << "Subpolyline #(" << p << ")\n";
10124  poly_to_connect_pt = tmp_vector_subpolylines[p];
10125  const unsigned n_v = poly_to_connect_pt->nvertex();
10126  for (unsigned i = 0; i < n_v; i++)
10127  {
10128  Vector<double> cvertex =
10129  poly_to_connect_pt->vertex_coordinate(i);
10130  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10131  << cvertex[1] << ")\n";
10132  }
10133  } // Not marked as overlaped
10134  } // for (p < nsub_poly)
10135  error << "\nThis is the list of vertices of the shared "
10136  << "polylines that overlap\nthe internal "
10137  << "boundary\n";
10138  Vector<unsigned> dst_shd_bnd_ids;
10139  get_shared_boundaries_overlapping_internal_boundary(
10140  uconnection_to_the_left, dst_shd_bnd_ids);
10141  const unsigned n_shd_bnd_overlap_int_bnd =
10142  dst_shd_bnd_ids.size();
10143  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10144  {
10145  const unsigned new_connection_to_the_left =
10146  dst_shd_bnd_ids[ss];
10147  poly_to_connect_pt =
10148  boundary_polyline_pt(new_connection_to_the_left);
10149  if (poly_to_connect_pt != 0)
10150  {
10151  const unsigned shd_bnd_id_overlap =
10152  poly_to_connect_pt->boundary_id();
10153  error << "Shared boundary id(" << shd_bnd_id_overlap
10154  << ")\n";
10155  const unsigned n_v = poly_to_connect_pt->nvertex();
10156  for (unsigned i = 0; i < n_v; i++)
10157  {
10158  Vector<double> cvertex =
10159  poly_to_connect_pt->vertex_coordinate(i);
10160  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10161  << cvertex[1] << ")\n";
10162  }
10163  } // if (poly_to_connect_pt != 0)
10164  } // for (ss < n_shd_bnd_overlap_int_bnd)
10165 
10166  throw OomphLibError(
10167  error.str(),
10168  "TriangleMesh::create_shared_polylines_connections()",
10169  OOMPH_EXCEPTION_LOCATION);
10170  } // if (!found_vertex_index)
10171 #endif
10172 
10173  // Create the connection, the left vertex of the current
10174  // shared boundary is connected with the vertex_index-th
10175  // vertex of sub_poly_to_connect-th subpolyline of the
10176  // destination boundary
10177  shd_poly_pt->connect_initial_vertex_to_polyline(
10178  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10179 
10180  } // else if (!connecting_to_an_overlaped_boundary)
10181 
10182  } // else if (!connecting_to_an_split_boundary)
10183 
10184  } // if (connection_to_the_left != -1)
10185 
10186  // --------------------------------------------------------------
10187  // Connection to the right
10188  if (is_connected_to_the_right)
10189  {
10190  // Get the unsigned version of the bound id to connect to
10191  // the right
10192  const unsigned uconnection_to_the_right =
10193  shd_poly_pt->final_vertex_connected_bnd_id();
10194 
10195  // The pointer to the boundary to connect
10196  TriangleMeshPolyLine* poly_to_connect_pt = 0;
10197 
10198  // Flag to indicate we are trying to connect to an split
10199  // boundary
10200  bool connecting_to_an_split_boundary = false;
10201 
10202  // Flag to indicate we are trying to connecto to an internal
10203  // boundary that is overlaped by a shared boundary
10204  bool connecting_to_an_overlaped_boundary = false;
10205 
10206  // Check if the connection is with itself
10207  if (uconnection_to_the_right == bound_id)
10208  {
10209  // Set the pointer to the polyline to connect
10210  poly_to_connect_pt = shd_poly_pt;
10211  }
10212  else
10213  {
10214  // Get the initial shared boundary ids
10215  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10216  // Check if the boundary to connect is a shared polyline
10217  if (uconnection_to_the_right >= initial_shd_bnd_id)
10218  {
10219  // Get the polyline pointer representing the destination
10220  // boundary
10221  poly_to_connect_pt =
10222  boundary_polyline_pt(uconnection_to_the_right);
10223  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10224  else
10225  {
10226  // If we are going to connect to an original boundary
10227  // verify if the boundary was splitted during the
10228  // distribution process to consider all the chunks
10229  // (sub-polylines) of the boundary
10230  if (boundary_was_splitted(uconnection_to_the_right))
10231  {
10232  connecting_to_an_split_boundary = true;
10233  } // if (boundary_was_splitted(uconnection_to_the_right))
10234 
10235  // If we are going to connect to an original boundary
10236  // verify if the boundary, or any of its chunks is
10237  // marked to be overlapped by a shared boundary, if that
10238  // is the case we first check for connections in the
10239  // shared boundary that overlaps the internal boundary,
10240  // or the chunks, and then check for connections in the
10241  // original boundary
10242  if (connecting_to_an_split_boundary)
10243  {
10244  // Get the number of chucks that represent the
10245  // destination boundary
10246  const unsigned n_sub_poly =
10247  nboundary_subpolylines(uconnection_to_the_right);
10248  // Now loop over the chunks of the destination
10249  // boundary and if any of them is marked to be
10250  // overlaped by a shared boundary then set the flag
10251  // and break the loop
10252  for (unsigned ii = 0; ii < n_sub_poly; ii++)
10253  {
10254  if (boundary_marked_as_shared_boundary(
10255  uconnection_to_the_right, ii))
10256  {
10257  // Mark the boundary as being overlaped by a
10258  // shared boundary
10259  connecting_to_an_overlaped_boundary = true;
10260  // Break, no need to look for more overlapings
10261  break;
10262  } // if (boundary_marked_as_shared_boundary(...))
10263  } // for (ii < n_sub_poly)
10264  } // if (connecting_to_an_split_boundary)
10265  else
10266  {
10267  // If not connecting to an split boundary then check
10268  // if the whole destination boundary is overlaped by
10269  // an internal boundary
10270  if (boundary_marked_as_shared_boundary(
10271  uconnection_to_the_right, 0))
10272  {
10273  // Mark the boundary as being overlaped by a shared
10274  // boundary
10275  connecting_to_an_overlaped_boundary = true;
10276  } // if (boundary_marked_as_shared_boundary(...))
10277  } // else if (connecting_to_an_split_boundary)
10278 
10279  // If we are connecting neither to an split boundary nor
10280  // an overlaped boundary then get the pointer to the
10281  // original boundary
10282  if (!(connecting_to_an_split_boundary ||
10283  connecting_to_an_overlaped_boundary))
10284  {
10285  // Get the polyline pointer representing the
10286  // destination boundary
10287  poly_to_connect_pt =
10288  boundary_polyline_pt(uconnection_to_the_right);
10289  } // else if (NOT split, NOT overlaped)
10290  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10291 
10292  } // else if (uconnection_to_the_right == bound_id)
10293 
10294 #ifdef PARANOID
10295  // If we are not connecting to an original boundary
10296  // (connecting to the same shared boundary or to another
10297  // shared boundary) then the boundary should not be marked
10298  // as split
10299  if (!connecting_to_an_split_boundary)
10300  {
10301  if (boundary_was_splitted(uconnection_to_the_right))
10302  {
10303  std::stringstream error;
10304  error
10305  << "The current shared boundary (" << bound_id << ") was "
10306  << "marked to have a connection\nto the right with the "
10307  << "boundary (" << uconnection_to_the_right << ").\n"
10308  << "The problem is that the destination boundary (possibly\n"
10309  << "another shared boundary) is marked to be split\n"
10310  << "There should not be split shared boundaries\n\n";
10311  throw OomphLibError(
10312  error.str(),
10313  "TriangleMesh::create_shared_polylines_connections()",
10314  OOMPH_EXCEPTION_LOCATION);
10315  }
10316  } // if (!connecting_to_an_split_boundary)
10317 #endif
10318 
10319  // Now look for the vertex number on the destination
10320  // boundary(ies) -- in case that the boundary was split ---
10321 
10322  // Do not check for same orientation, that was previously
10323  // worked by interchanging the connections boundaries (if
10324  // necessary)
10325 
10326  // Get the right vertex in the shared boundary
10327  Vector<double> shd_bnd_right_vertex =
10328  shd_poly_pt->vertex_coordinate(n_vertex - 1);
10329 
10330  // If the boundary was not split then inmediately look for
10331  // the vertex index in the destination boundary
10332  if (!connecting_to_an_split_boundary)
10333  {
10334  // ... check if the boundary is marked to be overlaped by
10335  // a shared boundary
10336  if (!connecting_to_an_overlaped_boundary)
10337  {
10338  // If that is not the case then we can safely look for
10339  // the vertex number on the destination boundar
10340 
10341  unsigned vertex_index = 0;
10342  const bool found_vertex_index =
10343  get_connected_vertex_number_on_destination_polyline(
10344  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10345 
10346  // If we could not find the vertex index to connect then
10347  // we are in trouble
10348  if (!found_vertex_index)
10349  {
10350  std::stringstream error;
10351  error
10352  << "The current shared boundary (" << bound_id << ") was "
10353  << "marked to have a connection\nto the right with the "
10354  << "boundary (" << uconnection_to_the_right << ").\n"
10355  << "The problem is that the right vertex of the current\n"
10356  << "shared boundary is not in the list of vertices of the\n"
10357  << "boundary to connect.\n\n"
10358  << "This is the right vertex of the current shared "
10359  "boundary\n"
10360  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10361  << shd_bnd_right_vertex[1] << ")\n\n"
10362  << "This is the list of vertices on the destination "
10363  "boundary\n";
10364  const unsigned n_v = poly_to_connect_pt->nvertex();
10365  for (unsigned i = 0; i < n_v; i++)
10366  {
10367  Vector<double> cvertex =
10368  poly_to_connect_pt->vertex_coordinate(i);
10369  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10370  << cvertex[1] << ")\n";
10371  }
10372  throw OomphLibError(
10373  error.str(),
10374  "TriangleMesh::create_shared_polylines_connections()",
10375  OOMPH_EXCEPTION_LOCATION);
10376  } // if (!found_vertex_index)
10377 
10378  // Create the connection, the right vertex of the current
10379  // shared boundary is connected with the vertex_index-th
10380  // vertex on the destination boundary
10381  shd_poly_pt->connect_final_vertex_to_polyline(
10382  poly_to_connect_pt, vertex_index);
10383 
10384  } // if (!connecting_to_an_overlaped_boundary)
10385  else
10386  {
10387  // If the boundary is marked to be overlaped by a shared
10388  // boundary then get that shared boundary and look for
10389  // the connection in that boundary
10390 
10391  // The vertex where to store the index to connect
10392  unsigned vertex_index = 0;
10393  // A flag to indicate if the connection was found
10394  bool found_vertex_index = false;
10395 
10396  // Get the shared boundary id that is overlaping the
10397  // internal boundary
10398  Vector<unsigned> dst_shd_bnd_ids;
10399  get_shared_boundaries_overlapping_internal_boundary(
10400  uconnection_to_the_right, dst_shd_bnd_ids);
10401 
10402  // Get the number of shared polylines that were found to
10403  // overlap the internal boundary
10404  const unsigned n_shd_bnd_overlap_int_bnd =
10405  dst_shd_bnd_ids.size();
10406 
10407  // Loop over the shared boundaries that overlap the
10408  // internal boundary and look for the vertex to connect
10409  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10410  {
10411  // Get the shared polyline
10412  const unsigned new_connection_to_the_right =
10413  dst_shd_bnd_ids[ss];
10414 
10415  // Get the shared polyline that is overlaping the
10416  // internal boundary
10417  poly_to_connect_pt =
10418  boundary_polyline_pt(new_connection_to_the_right);
10419 
10420  if (poly_to_connect_pt != 0)
10421  {
10422  // Look for the vertex number in the destination
10423  // shared polyline
10424  found_vertex_index =
10425  get_connected_vertex_number_on_destination_polyline(
10426  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10427  } // if (poly_to_connect_pt!=0)
10428 
10429  // If we have found the vertex to connect then
10430  // break the loop
10431  if (found_vertex_index)
10432  {
10433  break;
10434  } // if (found_vertex_index)
10435 
10436  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10437 
10438 #ifdef PARANOID
10439  // If we could not find the vertex index to connect then
10440  // we are in trouble
10441  if (!found_vertex_index)
10442  {
10443  std::stringstream error;
10444  error
10445  << "The current shared boundary (" << bound_id << ") was "
10446  << "marked to have a connection\nto the right with the "
10447  << "boundary (" << uconnection_to_the_right << ").\n"
10448  << "This last boundary is marked to be overlaped by "
10449  << "shared boundaries\n"
10450  << "The problem is that the right vertex of the current\n"
10451  << "shared boundary is not in the list of vertices of the\n"
10452  << "boundary to connect.\n\n"
10453  << "This is the right vertex of the current shared "
10454  "boundary\n"
10455  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10456  << shd_bnd_right_vertex[1] << ")\n\n"
10457  << "This is the list of vertices on the destination "
10458  << "boundary\n";
10459  Vector<unsigned> dst_shd_bnd_ids;
10460  get_shared_boundaries_overlapping_internal_boundary(
10461  uconnection_to_the_right, dst_shd_bnd_ids);
10462  const unsigned n_shd_bnd_overlap_int_bnd =
10463  dst_shd_bnd_ids.size();
10464  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10465  {
10466  const unsigned new_connection_to_the_right =
10467  dst_shd_bnd_ids[ss];
10468  poly_to_connect_pt =
10469  boundary_polyline_pt(new_connection_to_the_right);
10470  if (poly_to_connect_pt != 0)
10471  {
10472  const unsigned shd_bnd_id_overlap =
10473  poly_to_connect_pt->boundary_id();
10474  error << "Shared boundary id(" << shd_bnd_id_overlap
10475  << ")\n";
10476  const unsigned n_v = poly_to_connect_pt->nvertex();
10477  for (unsigned i = 0; i < n_v; i++)
10478  {
10479  Vector<double> cvertex =
10480  poly_to_connect_pt->vertex_coordinate(i);
10481  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10482  << cvertex[1] << ")\n";
10483  }
10484  } // if (poly_to_connect_pt != 0)
10485  } // for (ss < n_shd_bnd_overlap_int_bnd)
10486 
10487  throw OomphLibError(
10488  error.str(),
10489  "TriangleMesh::create_shared_polylines_connections()",
10490  OOMPH_EXCEPTION_LOCATION);
10491 
10492  } // if (!found_vertex_index)
10493 #endif
10494 
10495  // Create the connection, the right vertex of the
10496  // current shared boundary is connected with the
10497  // vertex_index-th vertex on the destination boundary
10498  shd_poly_pt->connect_final_vertex_to_polyline(
10499  poly_to_connect_pt, vertex_index);
10500 
10501  } // else if (!connecting_to_an_overlaped_boundary)
10502 
10503  } // if (!connecting_to_an_split_boundary)
10504  else
10505  {
10506  // If the boundary was split then we need to look for the
10507  // vertex in the sub-polylines
10508 
10509  // Get the sub-polylines vector
10510  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10511  boundary_subpolylines(uconnection_to_the_right);
10512 
10513  // Get the number of sub-polylines
10514  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10515 #ifdef PARANOID
10516  if (nsub_poly <= 1)
10517  {
10518  std::ostringstream error_message;
10519  error_message
10520  << "The boundary (" << uconnection_to_the_right << ") was "
10521  << "marked to be splitted but\n"
10522  << "there are only (" << nsub_poly << ") polylines to "
10523  << "represent it.\n";
10524  throw OomphLibError(
10525  error_message.str(),
10526  "TriangleMesh::create_shared_polylines_connections()",
10527  OOMPH_EXCEPTION_LOCATION);
10528  } // if (nsub_poly <= 1)
10529 #endif
10530 
10531  // We need to check if the boundary is marked to be
10532  // overlaped by an internal boundary, if that is the case
10533  // we need to check for each indivual subpolyline, and for
10534  // those overlaped by a shared polyline look for the
10535  // vertex in the shared polyline representation instead of
10536  // the original subpolyline
10537 
10538  // ... check if the boundary is marked to be overlaped by
10539  // a shared boundary
10540  if (!connecting_to_an_overlaped_boundary)
10541  {
10542  // We can work without checking the subpolylines
10543  // individually
10544 
10545  // The vertex where to store the index to connect
10546  unsigned vertex_index = 0;
10547  // The subpoly number to connect
10548  unsigned sub_poly_to_connect = 0;
10549  // A flag to indicate if the connection was found
10550  bool found_vertex_index = false;
10551 
10552  // Look for the vertex number to connect on each of the
10553  // subpolyines
10554  for (unsigned isub = 0; isub < nsub_poly; isub++)
10555  {
10556  // Assign the pointer to the sub-polyline
10557  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10558  // Search for the vertex in the current sub-polyline
10559  found_vertex_index =
10560  get_connected_vertex_number_on_destination_polyline(
10561  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10562  // If we have found the vertex to connect then break the
10563  // loop
10564  if (found_vertex_index)
10565  {
10566  // But first save the subpoly number (chunk), that
10567  // will be used to perform the connection
10568  sub_poly_to_connect = isub;
10569  break;
10570  } // if (found_vertex_index)
10571  } // for (isub < nsub_poly)
10572 
10573 #ifdef PARANOID
10574  // If we could not find the vertex index to connect then
10575  // we are in trouble
10576  if (!found_vertex_index)
10577  {
10578  std::stringstream error;
10579  error
10580  << "The current shared boundary (" << bound_id << ") was "
10581  << "marked to have a connection\nto the right with the "
10582  << "boundary (" << uconnection_to_the_right << ").\n"
10583  << "The problem is that the right vertex of the current\n"
10584  << "shared boundary is not in the list of vertices of any\n"
10585  << "of the sub polylines that represent the boundary to\n"
10586  << "connect.\n\n"
10587  << "This is the right vertex of the current shared "
10588  "boundary\n"
10589  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10590  << shd_bnd_right_vertex[1] << ")\n\n"
10591  << "This is the list of vertices on the destination "
10592  << "boundary\n";
10593  for (unsigned p = 0; p < nsub_poly; p++)
10594  {
10595  error << "Subpolyline #(" << p << ")\n";
10596  poly_to_connect_pt = tmp_vector_subpolylines[p];
10597  const unsigned n_v = poly_to_connect_pt->nvertex();
10598  for (unsigned i = 0; i < n_v; i++)
10599  {
10600  Vector<double> cvertex =
10601  poly_to_connect_pt->vertex_coordinate(i);
10602  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10603  << cvertex[1] << ")\n";
10604  }
10605  } // for (p < nsub_poly)
10606  throw OomphLibError(
10607  error.str(),
10608  "TriangleMesh::create_shared_polylines_connections()",
10609  OOMPH_EXCEPTION_LOCATION);
10610  } // if (!found_vertex_index)
10611 #endif
10612 
10613  // Create the connection, the right vertex of the current
10614  // shared boundary is connected with the vertex_index-th
10615  // vertex of sub_poly_to_connect-th subpolyline of the
10616  // destination boundary
10617  shd_poly_pt->connect_final_vertex_to_polyline(
10618  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10619 
10620  } // if (!connecting_to_an_overlaped_boundary)
10621  else
10622  {
10623  // We first look on the shared boundaries that overlap
10624  // the internal boundaries and the look for the
10625  // sub-polylines that are not marked as being overlaped
10626  // by shared boundaries
10627 
10628  // The vertex where to store the index to connect
10629  unsigned vertex_index = 0;
10630  // The subpoly number to connect
10631  unsigned sub_poly_to_connect = 0;
10632  // A flag to indicate if the connection was found
10633  bool found_vertex_index = false;
10634 
10635  // Get the shared boundaries id that are overlaping the
10636  // internal boundary
10637  Vector<unsigned> dst_shd_bnd_ids;
10638  get_shared_boundaries_overlapping_internal_boundary(
10639  uconnection_to_the_right, dst_shd_bnd_ids);
10640 
10641  // Get the number of shared polylines that were found to
10642  // overlap the internal boundary
10643  const unsigned n_shd_bnd_overlap_int_bnd =
10644  dst_shd_bnd_ids.size();
10645 
10646  // Loop over the shared boundaries that overlap the
10647  // internal boundary and look for the vertex to connect
10648  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10649  {
10650  // Get the shared polyline
10651  const unsigned new_connection_to_the_right =
10652  dst_shd_bnd_ids[ss];
10653 
10654  // Make sure that the destination polyline is not the
10655  // same as the current shared polyline
10656  if (bound_id != new_connection_to_the_right)
10657  {
10658  // Get the shared polyline that is overlaping the
10659  // internal boundary
10660  poly_to_connect_pt =
10661  boundary_polyline_pt(new_connection_to_the_right);
10662 
10663  if (poly_to_connect_pt != 0)
10664  {
10665  // Look for the vertex number in the destination
10666  // shared polyline
10667  found_vertex_index =
10668  get_connected_vertex_number_on_destination_polyline(
10669  poly_to_connect_pt,
10670  shd_bnd_right_vertex,
10671  vertex_index);
10672  } // if (poly_to_connect_pt != 0)
10673 
10674  // If we have found the vertex to connect then
10675  // break the loop
10676  if (found_vertex_index)
10677  {
10678  break;
10679  } // if (found_vertex_index)
10680 
10681  } // if (bound_id != new_connection_to_the_right)
10682 
10683  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10684 
10685  // If we have not yet found the vertex then look for it
10686  // in the sub-polylines that are not overlaped by shared
10687  // boundaries
10688  if (!found_vertex_index)
10689  {
10690  // Look for the vertex number to connect on each of
10691  // the subpolyines
10692  for (unsigned isub = 0; isub < nsub_poly; isub++)
10693  {
10694  // Only work with those sub-polylines that are not
10695  // overlaped by shared boundaries
10696  if (!boundary_marked_as_shared_boundary(
10697  uconnection_to_the_right, isub))
10698  {
10699  // Assign the pointer to the sub-polyline
10700  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10701  // Search for the vertex in the current sub-polyline
10702  found_vertex_index =
10703  get_connected_vertex_number_on_destination_polyline(
10704  poly_to_connect_pt,
10705  shd_bnd_right_vertex,
10706  vertex_index);
10707  // If we have found the vertex to connect then break the
10708  // loop
10709  if (found_vertex_index)
10710  {
10711  // But first save the subpoly number (chunk), that
10712  // will be used to perform the connection
10713  sub_poly_to_connect = isub;
10714  break;
10715  } // if (found_vertex_index)
10716 
10717  } // if (not overlaped by shared boundary)
10718 
10719  } // for (isub < nsub_poly)
10720 
10721  } // if (!found_vertex_index)
10722 
10723 #ifdef PARANOID
10724  // If we could not find the vertex index to connect then
10725  // we are in trouble
10726  if (!found_vertex_index)
10727  {
10728  std::stringstream error;
10729  error
10730  << "The current shared boundary (" << bound_id << ") was "
10731  << "marked to have a connection\nto the right with the "
10732  << "boundary (" << uconnection_to_the_right << ").\n"
10733  << "This last boundary is marked to be overlaped by "
10734  << "shared boundaries\n"
10735  << "The problem is that the right vertex of the current\n"
10736  << "shared boundary is not in the list of vertices of "
10737  << "the\nboundary to connect.\n\n"
10738  << "This is the right vertex of the current shared "
10739  << "boundary\n"
10740  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10741  << shd_bnd_right_vertex[1] << ")\n\n"
10742  << "This is the list of vertices on the destination "
10743  << "boundary (only those subpolylines not marked as "
10744  << "overlaped by\nshared boundaries)\n";
10745  for (unsigned p = 0; p < nsub_poly; p++)
10746  {
10747  if (!boundary_marked_as_shared_boundary(
10748  uconnection_to_the_right, p))
10749  {
10750  error << "Subpolyline #(" << p << ")\n";
10751  poly_to_connect_pt = tmp_vector_subpolylines[p];
10752  const unsigned n_v = poly_to_connect_pt->nvertex();
10753  for (unsigned i = 0; i < n_v; i++)
10754  {
10755  Vector<double> cvertex =
10756  poly_to_connect_pt->vertex_coordinate(i);
10757  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10758  << cvertex[1] << ")\n";
10759  }
10760  } // Not marked as overlaped
10761  } // for (p < nsub_poly)
10762  error << "\nThis is the list of vertices of the shared "
10763  << "polylines that overlap\nthe internal "
10764  << "boundary\n";
10765  Vector<unsigned> dst_shd_bnd_ids;
10766  get_shared_boundaries_overlapping_internal_boundary(
10767  uconnection_to_the_right, dst_shd_bnd_ids);
10768  const unsigned n_shd_bnd_overlap_int_bnd =
10769  dst_shd_bnd_ids.size();
10770  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10771  {
10772  const unsigned new_connection_to_the_right =
10773  dst_shd_bnd_ids[ss];
10774  poly_to_connect_pt =
10775  boundary_polyline_pt(new_connection_to_the_right);
10776  if (poly_to_connect_pt != 0)
10777  {
10778  const unsigned shd_bnd_id_overlap =
10779  poly_to_connect_pt->boundary_id();
10780  error << "Shared boundary id(" << shd_bnd_id_overlap
10781  << ")\n";
10782  const unsigned n_v = poly_to_connect_pt->nvertex();
10783  for (unsigned i = 0; i < n_v; i++)
10784  {
10785  Vector<double> cvertex =
10786  poly_to_connect_pt->vertex_coordinate(i);
10787  error << "Vertex #" << i << ": (" << cvertex[0] << ", "
10788  << cvertex[1] << ")\n";
10789  }
10790  } // if (poly_to_connect_pt != 0)
10791  } // for (ss < n_shd_bnd_overlap_int_bnd)
10792 
10793  throw OomphLibError(
10794  error.str(),
10795  "TriangleMesh::create_shared_polylines_connections()",
10796  OOMPH_EXCEPTION_LOCATION);
10797  } // if (!found_vertex_index)
10798 #endif
10799 
10800  // Create the connection, the left vertex of the current
10801  // shared boundary is connected with the vertex_index-th
10802  // vertex of sub_poly_to_connect-th subpolyline of the
10803  // destination boundary
10804  shd_poly_pt->connect_final_vertex_to_polyline(
10805  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10806 
10807  } // else if (!connecting_to_an_overlaped_boundary)
10808 
10809  } // else if (!connecting_to_an_split_boundary)
10810 
10811  } // if (connection_to_the_right != -1)
10812 
10813  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10814 
10815  } // for (ipoly < npoly)
10816 
10817  } // for (icurve < ncurves)
10818  }
10819 
10820  //=======================================================================
10821  // Compute the holes left by the halo elements, those adjacent
10822  // to the shared boundaries
10823  //=======================================================================
10824  template<class ELEMENT>
10826  Vector<Vector<double>>& output_holes_coordinates)
10827  {
10828  // Storage for number of processors and current processor
10829  const unsigned n_proc = this->communicator_pt()->nproc();
10830  const unsigned my_rank = this->communicator_pt()->my_rank();
10831 
10832  // Mark those done elements, so we do not repeat any coordinate left
10833  // by repeated halo elements
10834  std::map<FiniteElement*, bool> done_ele;
10835 
10836  // Loop over the processors and get the shared boundaries ids that
10837  // the current processor has with the other processors
10838  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10839  {
10840  // There are shared boundaries only with the other processors
10841  if (iproc != my_rank)
10842  {
10843  // Get the number of shared boundaries with the iproc
10844  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10845 
10846 #ifdef PARANOID
10847  // Get the number of shared boundaries with the iproc, but
10848  // reversing the indexes
10849  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10850  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10851  {
10852  std::ostringstream error_stream;
10853  error_stream
10854  << "The number of shared boundaries of processor (" << my_rank
10855  << ") with processor(" << iproc << "): (" << n_shd_bnd_iproc
10856  << ")\n"
10857  << "is different from the number of shared boundaries of "
10858  << "processor (" << iproc << ")\nwith processor (" << my_rank
10859  << "): (" << n_shd_bnd_iproc << ")\n\n";
10860  throw OomphLibError(error_stream.str(),
10861  OOMPH_CURRENT_FUNCTION,
10862  OOMPH_EXCEPTION_LOCATION);
10863 
10864  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10865 #endif
10866 
10867  // Loop over the shared boundaries ids
10868  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10869  {
10870  // Get the shared boundary id
10871  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10872 
10873  // Get the number of shared boundary elements
10874  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10875 
10876  // Loop over the shared boundary elements
10877  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10878  {
10879  // Get the shared boundary element
10880  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10881 
10882  // Only work with halo elements
10883  if (ele_pt->is_halo())
10884  {
10885  // If the element has not been visited
10886  if (!done_ele[ele_pt])
10887  {
10888  // Get the number of nodes
10889  const unsigned n_nodes = ele_pt->nnode();
10890 
10891  // Compute the centroid of the element
10892  Vector<double> element_centroid(2, 0.0);
10893  // Loop over the nodes
10894  for (unsigned k = 0; k < n_nodes; k++)
10895  {
10896  Node* tmp_node_pt = ele_pt->node_pt(k);
10897  // Loop over the dimension
10898  for (unsigned d = 0; d < 2; d++)
10899  {
10900  element_centroid[d] += tmp_node_pt->x(d);
10901  } // for (d < 2)
10902  } // for (k < n_nodes)
10903 
10904  // Average the data
10905  for (unsigned d = 0; d < 2; d++)
10906  {
10907  element_centroid[d] = element_centroid[d] / (double)n_nodes;
10908  } // for (d < 2)
10909 
10910  // Add the centroid to the output holes
10911  output_holes_coordinates.push_back(element_centroid);
10912 
10913  } // if (!done_ele[ele_pt])
10914 
10915  } // if (ele_pt->is_halo())
10916 
10917  } // for1 (e < n_shd_bnd_ele)
10918 
10919  } // for (i < n_shd_bnd_iproc)
10920 
10921  } // if (iproc != my_rank)
10922 
10923  } // for (iproc < n_proc)
10924  }
10925 
10926  //======================================================================
10927  // Keeps those vertices that define a hole, those that are
10928  // inside closed internal boundaries in the new polygons that define
10929  // the domain. Delete those outside/inside the outer polygons (this
10930  // is required since Triangle can not deal with vertices that define
10931  // holes outside the new outer polygons of the domain)
10932  //======================================================================
10933  template<class ELEMENT>
10935  Vector<TriangleMeshPolygon*>& polygons_pt,
10936  Vector<Vector<double>>& output_holes_coordinates)
10937  {
10938  // General strategy
10939 
10940  // 1) Identify the inner closed boundaries
10941 
10942  // 2) Separate the vertices in three groups
10943 
10944  // --- 2.1) The vertices inside the inner closed boundaries, these
10945  // are not deleted because they define holes
10946 
10947  // --- 2.2) The vertices outside the outer boundaries, these are
10948  // deleted only if they are outside the convex hull defined
10949  // by all the polygons
10950 
10951  // --- 2.3) Any other vertex is deleted
10952 
10953  // Get the number of input holes
10954  const unsigned n_input_holes = output_holes_coordinates.size();
10955 
10956  // Only do something if there are holes
10957  if (n_input_holes == 0)
10958  {
10959  return;
10960  }
10961 
10962  // Get the number of input polygons
10963  const unsigned n_polygons = polygons_pt.size();
10964 
10965  // Store the vertices of all the input polygons
10966  // vertices_polygons[x][ ][ ]: Polygon number
10967  // vertices_polygons[ ][x][ ]: Vertex number
10968  // vertices_polygons[ ][ ][x]: Vertex coordinate
10969  Vector<Vector<Vector<double>>> vertices_polygons(n_polygons);
10970 
10971  // Loop over all the polygons and get the vertices
10972  for (unsigned p = 0; p < n_polygons; p++)
10973  {
10974  // Get the number of polylines associated to the polygon
10975  const unsigned n_polylines = polygons_pt[p]->npolyline();
10976  // Loop over the polylines and get the vertices
10977  for (unsigned pp = 0; pp < n_polylines; pp++)
10978  {
10979  // Get the polyline
10980  const TriangleMeshPolyLine* tmp_poly_pt =
10981  polygons_pt[p]->polyline_pt(pp);
10982  // Get the number of vertices in the polyline
10983  const unsigned n_vertices = tmp_poly_pt->nvertex();
10984  // Loop over the vertices but only add (n_vertices-1) vertices,
10985  // the last vertex of polyline (pp) is the first vertex of
10986  // polyline (pp+1)
10987  for (unsigned v = 0; v < n_vertices - 1; v++)
10988  {
10989  // Get the current vertex
10990  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10991  vertices_polygons[p].push_back(current_vertex);
10992  } // for (v < nvertex)
10993  } // for (p < nouter_polylines)
10994  } // for (p < n_polygons)
10995 
10996  // -------------------------------------------------------------------
10997  // 1) Identify the inner closed boundaries
10998  // -------------------------------------------------------------------
10999 
11000  // A container that indicates if a given polygon should be
11001  // considered as an outer or as an inner polygon. By default all the
11002  // polygons are considered as outer polygons
11003  std::vector<bool> is_outer_polygon(n_polygons, true);
11004 
11005  // We only check for innner polygons if there are more than one
11006  // polygon
11007  if (n_polygons > 1)
11008  {
11009  // Propose an inner polygon, if one of the middle points of its
11010  // edges lies inside any other polygon then the proposed inner
11011  // polygon is marked as an internal polygon
11012 
11013  // Pre-compute the middle points of the edges in the polygons
11014  Vector<Vector<Vector<double>>> polygon_edge_middle_vertex(n_polygons);
11015 
11016  for (unsigned p = 0; p < n_polygons; p++)
11017  {
11018  // Temporary store the vertices of the proposed inner polygon
11019  Vector<Vector<double>> tmp_inner_polygon = vertices_polygons[p];
11020 
11021  // Get the number of vertices in the current proposed inner polygon
11022  const unsigned n_vertices = tmp_inner_polygon.size();
11023 
11024  // Resize with the number of edges in the polygon
11025  polygon_edge_middle_vertex[p].resize(n_vertices - 1);
11026 
11027  // Loop over the vertices and compute the middle point in the edge
11028  // that joins each pair of contiguous vertices
11029  for (unsigned e = 0; e < n_vertices - 1; e++)
11030  {
11031  // The dimension
11032  const unsigned dim = 2;
11033  polygon_edge_middle_vertex[p][e].resize(dim);
11034  for (unsigned d = 0; d < dim; d++)
11035  {
11036  polygon_edge_middle_vertex[p][e][d] =
11037  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e + 1][d]) / 2.0;
11038  } // for (d < 2)
11039 
11040  } // for (e < n_vertices - 1)
11041 
11042  } // for (p < n_polygons)
11043 
11044  // Loop over the polygons and for every loop propose a different
11045  // inner polygon
11046  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
11047  {
11048  // Flag to indicate that ONE of the middle edge vertices of the
11049  // proposed inner polygon is inside another polygon, this will
11050  // set the proposed inner polygon as an actual inner polygon
11051  bool is_inner_polygon = false;
11052 
11053  // Loop over all the polygons, except the proposed one and check
11054  // if all the middle edges of its edges are inside any other
11055  // polygon
11056  for (unsigned i = 0; i < n_polygons; i++)
11057  {
11058  // Do not check with the polygon itself
11059  if (i != idx_inner)
11060  {
11061  // Get the number of edges of the proposed inner polygon
11062  const unsigned n_edges =
11063  polygon_edge_middle_vertex[idx_inner].size();
11064  // Loop over the middle points in the edges of the current
11065  // proposed inner polygon
11066  for (unsigned e = 0; e < n_edges; e++)
11067  {
11068  // Get the vertex in the current proposed inner polygon
11069  Vector<double> current_vertex =
11070  polygon_edge_middle_vertex[idx_inner][e];
11071  // Check if the current vertex is inside the current i-th
11072  // polygon
11073  const bool is_point_inside = is_point_inside_polygon_helper(
11074  vertices_polygons[i], current_vertex);
11075 
11076  // If one point is inside then the polygon is inside the
11077  // i-th polygon
11078  if (is_point_inside)
11079  {
11080  // The polygon is an inner polygon
11081  is_inner_polygon = true;
11082  // Break the loop
11083  break;
11084  } // if (is_point_inside)
11085 
11086  } // for (e < n_edges)
11087 
11088  } // if (i != idx_inner)
11089 
11090  // Are all the vertices of the current proposed inner polygon
11091  // inside the i-th polygon
11092  if (is_inner_polygon)
11093  {
11094  // The current proposed inner polygon is an actual inner
11095  // polygon, and is inside the i-th polygon
11096  break;
11097  }
11098 
11099  } // for (i < n_polygons)
11100 
11101  // Is the current proposed inner polygon an actual inner polygon
11102  if (is_inner_polygon)
11103  {
11104  // The current proposed inner polygon is a real inner polygon
11105  is_outer_polygon[idx_inner] = false;
11106  }
11107  else
11108  {
11109  // The current proposed inner polygon IS NOT a real inner
11110  // polygon
11111  is_outer_polygon[idx_inner] = true;
11112  }
11113 
11114  } // for (idx_outer < npolygons)
11115 
11116  } // if (n_polygons > 1)
11117 
11118  // Count the number of outer closed boundaries and inner closed
11119  // boundaries
11120  unsigned n_outer_polygons = 0;
11121  unsigned n_inner_polygons = 0;
11122  // Also get the indexes of the inner polygons
11123  Vector<unsigned> index_inner_polygon;
11124  // Loop over the polygons
11125  for (unsigned i = 0; i < n_polygons; i++)
11126  {
11127  if (is_outer_polygon[i])
11128  {
11129  // Increase the counter for outer polygons
11130  n_outer_polygons++;
11131  }
11132  else
11133  {
11134  // Increase the counter for inner polygons
11135  n_inner_polygons++;
11136  // Store the index of the inner polygon
11137  index_inner_polygon.push_back(i);
11138  }
11139  } // for (i < n_polygons)
11140 
11141  // -------------------------------------------------------------------
11142  // 2) Separate the vertices in three groups
11143 
11144  // --- 2.1) The vertices inside the inner closed boundaries, these are
11145  // not deleted because they define holes
11146 
11147  // --- 2.2) The vertices outside the outer boundaries, these are
11148  // deleted only if they are outside the convex hull defined
11149  // by all the polygons
11150 
11151  // --- 2.3) Any other vertex is deleted
11152  // -------------------------------------------------------------------
11153 
11154  // Keep track of the vertices inside the inner closed boundaries (by
11155  // default all vertices not inside the inner polygons)
11156  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11157 
11158  // Keep track of the vertices outside the outer closed boundaries
11159  // (by default all the vertices are outside the outer polygons)
11160  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11161 
11162  // Keep track of the vertices inside the convex hull (by default
11163  // all the vertices are not inside the convex hull)
11164  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11165 
11166  // Mark the vertices inside the inner closed boundaries
11167  Vector<Vector<Vector<double>>> vertex_inside_inner_polygon(
11168  n_inner_polygons);
11169 
11170  // -------------------------------------------------------------------
11171  // Loop over the inner polygons and find all the vertices inside
11172  // each one
11173  for (unsigned i = 0; i < n_inner_polygons; i++)
11174  {
11175  // Get the vertex of the inner polygon
11176  const unsigned ii = index_inner_polygon[i];
11177  // Loop over the vertices defining holes, mark and store those
11178  // inside the inner polygon
11179  for (unsigned h = 0; h < n_input_holes; h++)
11180  {
11181  // Check if the vertex has not been already marked as inside
11182  // another polygon
11183  if (!is_inside_an_inner_polygon[h])
11184  {
11185  // Check if the hole is inside the current inner polygon
11186  const bool is_inside_polygon = is_point_inside_polygon_helper(
11187  vertices_polygons[ii], output_holes_coordinates[h]);
11188 
11189  // If the vertex is inside the current inner polygon then mark
11190  // it and associate the vertices to the current inner polygon
11191  if (is_inside_polygon)
11192  {
11193  // Set as inside an inner polygon
11194  is_inside_an_inner_polygon[h] = true;
11195  // Associate the vertex to the current inner polygon
11196  vertex_inside_inner_polygon[i].push_back(
11197  output_holes_coordinates[h]);
11198  } // if (is_inside_polygon)
11199 
11200  } // if (!is_inside_an_inner_polygon[h])
11201 
11202  } // for (h < n_input_holes)
11203 
11204  } // for (i < n_polygons)
11205 
11206  // -------------------------------------------------------------------
11207  // Loop over the vertices defining holes and mark those as outside the
11208  // outer polygons
11209  for (unsigned h = 0; h < n_input_holes; h++)
11210  {
11211  // Check if the vertex has not been already marked as inside
11212  // another polygon
11213  if (!is_inside_an_inner_polygon[h])
11214  {
11215  // Loop over the polygons and check if the vertex is outside ALL
11216  // the outer polygons
11217  for (unsigned i = 0; i < n_polygons; i++)
11218  {
11219  // Only work with outer polygons
11220  if (is_outer_polygon[i])
11221  {
11222  // Check if the hole is inside the current outer polygon
11223  const bool is_inside_polygon = is_point_inside_polygon_helper(
11224  vertices_polygons[i], output_holes_coordinates[h]);
11225 
11226  // If the vertex is inside the current outer polygon then
11227  // mark it and break the loop (it is not outside ALL the
11228  // polygons)
11229  if (is_inside_polygon)
11230  {
11231  // Set as inside an outer polygon
11232  is_outside_the_outer_polygons[h] = false;
11233  // Break the loop
11234  break;
11235  } // if (is_inside_polygon)
11236 
11237  } // if (is_outer_polygon[i])
11238 
11239  } // for (i < n_polygons)
11240 
11241  } // if (!is_inside_an_inner_polygon[h])
11242  else
11243  {
11244  // If the vertex is inside an inner polygon then it is inside an
11245  // outer polygon
11246  is_outside_the_outer_polygons[h] = false;
11247  } // else if (!is_inside_an_inner_polygon[h])
11248 
11249  } // for (h < n_input_holes)
11250 
11251  // -------------------------------------------------------------------
11252  // Compute the convex hull Create the data structure
11253  std::vector<Point> input_vertices_convex_hull;
11254  // Copy ALL the vertices of the polygons
11255  // Loop over the polygons
11256  for (unsigned p = 0; p < n_polygons; p++)
11257  {
11258  // Get the number of vertices
11259  const unsigned n_vertices = vertices_polygons[p].size();
11260  // Loop over the vertices in the polygon
11261  for (unsigned v = 0; v < n_vertices; v++)
11262  {
11263  // Create a new "Point" to store in the input vertices
11264  Point point;
11265  // Assign the values to the "Point"
11266  point.x = vertices_polygons[p][v][0];
11267  point.y = vertices_polygons[p][v][1];
11268  // Add the "Point" to the input vertices
11269  input_vertices_convex_hull.push_back(point);
11270  } // for (v < n_vertices)
11271  } // for (p < n_polygons)
11272 
11273  // Compute the convex hull
11274  std::vector<Point> output_vertices_convex_hull =
11275  convex_hull(input_vertices_convex_hull);
11276 
11277  // Get the number of vertices in the convex hull
11278  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11279 
11280  // Copy the output to the used data structures
11281  Vector<Vector<double>> vertices_convex_hull(n_vertices_convex_hull);
11282  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11283  {
11284  // Resize the data structure
11285  vertices_convex_hull[i].resize(2);
11286  // Copy the data
11287  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11288  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11289  } // for (i < n_vertices_convex_hull)
11290 
11291  // Loop over the vertices defining holes, work only with those
11292  // outside ALL the outer boundaries and mark those inside the convex
11293  // hull
11294  for (unsigned h = 0; h < n_input_holes; h++)
11295  {
11296  // Only work with those outside ALL the outer polygons
11297  if (is_outside_the_outer_polygons[h])
11298  {
11299  // Check if the hole is inside the convex hull
11300  const bool is_inside_convex_hull = is_point_inside_polygon_helper(
11301  vertices_convex_hull, output_holes_coordinates[h]);
11302 
11303  // If the vertex is inside the convex hull then mark it
11304  if (is_inside_convex_hull)
11305  {
11306  // Set as inside the convex hull
11307  is_inside_the_convex_hull[h] = true;
11308  } // if (is_inside_convex_hull)
11309 
11310  } // if (is_outside_the_outer_polygons[h])
11311  else
11312  {
11313  // Any vertex inside any outer polygon is inside the convex hull
11314  is_inside_the_convex_hull[h] = true;
11315  } // else if (is_outside_the_outer_polygons[h])
11316 
11317  } // for (h < n_input_holes)
11318 
11319  // Store the output holes, only (those inside an inner polygon) OR
11320  // (those outside ALL the polygons AND inside the convex hull)
11321  Vector<Vector<double>> hole_kept;
11322  for (unsigned h = 0; h < n_input_holes; h++)
11323  {
11324  // Check if the hole should be kept
11325  if ((is_inside_an_inner_polygon[h]) ||
11326  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11327  {
11328  // Copy the hole information
11329  hole_kept.push_back(output_holes_coordinates[h]);
11330  } // if (keep_hole[h])
11331  } // for (h < n_input_holes)
11332 
11333  // Clear the previous storage
11334  output_holes_coordinates.clear();
11335  // Set the output holes
11336  output_holes_coordinates = hole_kept;
11337  }
11338 
11339  //======================================================================
11340  // Sorts the polylines so they be contiguous and then we can
11341  // create a closed or open curve from them
11342  //======================================================================
11343  template<class ELEMENT>
11345  Vector<TriangleMeshPolyLine*>& unsorted_polylines_pt,
11346  Vector<Vector<TriangleMeshPolyLine*>>& sorted_polylines_pt)
11347  {
11348  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11349  unsigned n_sorted_polylines = 0;
11350  unsigned curves_index = 0;
11351 
11352  // Map to know which polyline has been already sorted
11353  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11354 
11355  do
11356  {
11357  // Create the list that stores the polylines and allows to introduce
11358  // polylines to the left and to the right
11359  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11360  bool changes = false;
11361 
11362  // Create pointers to the left and right "side" of the sorted list of
11363  // new created TriangleMeshPolyLines
11364  TriangleMeshPolyLine* left_pt = 0;
11365  TriangleMeshPolyLine* right_pt = 0;
11366 
11367  // 1) Take the first non done polyline on the unsorted list of polylines
11368  unsigned pp = 0;
11369  bool found_root_polyline = false;
11370  while (pp < n_unsorted_polylines && !found_root_polyline)
11371  {
11372  if (!done_polyline[unsorted_polylines_pt[pp]])
11373  {
11374  found_root_polyline = true;
11375  }
11376  else
11377  {
11378  pp++;
11379  }
11380  }
11381 
11382  // Check if there are polylines to be sorted
11383  if (pp < n_unsorted_polylines)
11384  {
11385  // 2) Mark the polyline as done
11386  left_pt = right_pt = unsorted_polylines_pt[pp];
11387  done_polyline[left_pt] = true;
11388  // Increment the number of sorted polylines
11389  n_sorted_polylines++;
11390 
11391  // 3) Add this polyline to the sorted list and use it as root
11392  // to sort the other polylines
11393  sorted_polyline_list_pt.push_back(left_pt);
11394 
11395  do
11396  {
11397  changes = false;
11398 
11399  Vector<double> left_vertex(2);
11400  Vector<double> right_vertex(2);
11401 
11402  left_pt->initial_vertex_coordinate(left_vertex);
11403  right_pt->final_vertex_coordinate(right_vertex);
11404 
11405  for (unsigned i = pp + 1; i < n_unsorted_polylines; i++)
11406  {
11407  TriangleMeshPolyLine* current_polyline_pt =
11408  unsorted_polylines_pt[i];
11409  if (!done_polyline[current_polyline_pt])
11410  {
11411  Vector<double> initial_vertex(2);
11412  Vector<double> final_vertex(2);
11413  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11414  current_polyline_pt->final_vertex_coordinate(final_vertex);
11415 
11416  // Compare if the current polyline should go to the left or
11417  // to the right on the sorted polyline list
11418 
11419  // Go to the left
11420  if (left_vertex == final_vertex)
11421  {
11422  left_pt = current_polyline_pt;
11423  sorted_polyline_list_pt.push_front(left_pt);
11424  done_polyline[left_pt] = true;
11425  n_sorted_polylines++;
11426 
11427  // We have added one more polyline, go for another round
11428  changes = true;
11429  }
11430  // Go to the right
11431  else if (right_vertex == initial_vertex)
11432  {
11433  right_pt = current_polyline_pt;
11434  sorted_polyline_list_pt.push_back(right_pt);
11435  done_polyline[right_pt] = true;
11436  n_sorted_polylines++;
11437 
11438  // We have added one more polyline, go for another round
11439  changes = true;
11440  }
11441  // Go to the left but it is reversed
11442  else if (left_vertex == initial_vertex)
11443  {
11444  current_polyline_pt->reverse();
11445  left_pt = current_polyline_pt;
11446  sorted_polyline_list_pt.push_front(left_pt);
11447  done_polyline[left_pt] = true;
11448  n_sorted_polylines++;
11449 
11450  // We have added one more polyline, go for another round
11451  changes = true;
11452  }
11453  // Go to the right but it is reversed
11454  else if (right_vertex == final_vertex)
11455  {
11456  current_polyline_pt->reverse();
11457  right_pt = current_polyline_pt;
11458  sorted_polyline_list_pt.push_back(right_pt);
11459  done_polyline[right_pt] = true;
11460  n_sorted_polylines++;
11461 
11462  // We have added one more polyline, go for another round
11463  changes = true;
11464  }
11465  } // if (!done_polyline[current_polyline_pt])
11466  if (changes)
11467  {
11468  break;
11469  }
11470  } // for (i < n_unsorted_polylines)
11471  } while (changes);
11472 
11473  } // if (pp < n_unsorted_polylines)
11474  else
11475  {
11476  // All the polylines are now on the sorted list of polylines
11477 #ifdef PARANOID
11478  // This case comes when it was not possible to find a root polyline
11479  // since all of them are marked as done but the number of sorted and
11480  // unsorted polylines is not the same
11481  if (!found_root_polyline)
11482  {
11483  std::stringstream err;
11484  err << "It was not possible to find a root polyline to sort the "
11485  << "others around it.\nThe number of unsorted and sorted "
11486  << "polylines is different, it means that\nnot all the "
11487  << "polylines have been sorted.\n"
11488  << "Found root polyline: (" << found_root_polyline << ")\n"
11489  << "Sorted polylines: (" << n_sorted_polylines << ")\n"
11490  << "Unsorted polylines: (" << n_unsorted_polylines << ")\n";
11491  throw OomphLibError(err.str(),
11492  "TriangleMesh::sort_polylines_helper()",
11493  OOMPH_EXCEPTION_LOCATION);
11494  }
11495 #endif
11496  }
11497 
11498  // Create the storage for the new sorted polylines and copy them on the
11499  // vector structure for sorted polylines
11500  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11501 
11502  // Create the temporal vector that stores the sorted polylines
11503  Vector<TriangleMeshPolyLine*> tmp_sorted_polylines(
11504  n_sorted_polyline_on_list);
11505  unsigned counter = 0;
11506 
11507  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11508  for (it_polyline = sorted_polyline_list_pt.begin();
11509  it_polyline != sorted_polyline_list_pt.end();
11510  it_polyline++)
11511  {
11512  tmp_sorted_polylines[counter] = *it_polyline;
11513  counter++;
11514  }
11515 
11516  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11517 
11518  ++curves_index;
11519 
11520  } while (n_sorted_polylines < n_unsorted_polylines);
11521 
11522 #ifdef PARANOID
11523  // Verify that the number of polylines on the sorted list is the same
11524  // as the number of polylines on the unsorted list
11525  if (n_sorted_polylines != n_unsorted_polylines)
11526  {
11527  std::stringstream err;
11528  err << "The number of polylines on the unsorted and sorted vectors"
11529  << " is different,\n"
11530  << "it means that not all the polylines have been sorted.\n"
11531  << "Sorted polylines: " << n_sorted_polylines
11532  << "\nUnsorted polylines: " << n_unsorted_polylines;
11533  throw OomphLibError(err.str(),
11534  "TriangleMesh::sort_polylines_helper()",
11535  OOMPH_EXCEPTION_LOCATION);
11536  }
11537 #endif
11538  }
11539 
11540  //======================================================================
11541  // Creates the shared boundaries
11542  //======================================================================
11543  template<class ELEMENT>
11545  OomphCommunicator* comm_pt,
11546  const Vector<unsigned>& element_domain,
11547  const Vector<GeneralisedElement*>& backed_up_el_pt,
11548  const Vector<FiniteElement*>& backed_up_f_el_pt,
11549  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
11550  const bool& overrule_keep_as_halo_element_status)
11551  {
11552  // Storage for number of processors and current processor
11553  const unsigned nproc = comm_pt->nproc();
11554  const unsigned my_rank = comm_pt->my_rank();
11555 
11556  // Storage for all the halo elements on all processors
11557  // halo_element[iproc][jproc][ele_number]
11558  // Stores the "ele_number"-th halo element of processor "iproc" with
11559  // processor "jproc"
11560  Vector<Vector<Vector<GeneralisedElement*>>> halo_element_pt(nproc);
11561  // Create complete storage for the halo_element_pt container
11562  for (unsigned iproc = 0; iproc < nproc; iproc++)
11563  {
11564  halo_element_pt[iproc].resize(nproc);
11565  }
11566 
11567  // Store the global index of the element, used to check for possible
11568  // misclassification of halo elements in the above container
11569  // (halo_element_pt)
11570  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11571 
11572  // Get the halo elements on all processors
11573  this->get_halo_elements_on_all_procs(nproc,
11574  element_domain,
11575  backed_up_el_pt,
11576  processors_associated_with_data,
11577  overrule_keep_as_halo_element_status,
11578  element_to_global_index,
11579  halo_element_pt);
11580 
11581  // Resize the shared polylines container
11582  flush_shared_boundary_polyline_pt();
11583  Shared_boundary_polyline_pt.resize(nproc);
11584 
11585  // Create a set that store only the elements that will be kept in
11586  // the processor as nonhalo element, those whose element_domains is
11587  // equal to my_rank. This set is used when creating the shared
11588  // polylines and identify the connections to the original boundaries
11589  std::set<FiniteElement*> element_in_processor_pt;
11590  const unsigned n_ele = backed_up_f_el_pt.size();
11591  for (unsigned e = 0; e < n_ele; e++)
11592  {
11593  if (element_domain[e] == my_rank)
11594  {
11595  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11596  } // if (element_domain[e] == my_rank)
11597  } // for (e < n_elex)
11598 
11599  // Look for elements edges that may lie on internal boundaries
11600  // If that is the case then relate the face with the boundary on
11601  // which it lies
11602  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
11603  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11604 
11605  // Now we have all the halo elements on all processors. Use the
11606  // edges shared by the halo elements to create the shared boundaries.
11607  this->create_polylines_from_halo_elements_helper(
11608  element_domain,
11609  element_to_global_index,
11610  element_in_processor_pt,
11611  halo_element_pt,
11612  elements_edges_on_boundary,
11613  Shared_boundary_polyline_pt);
11614  }
11615 
11616  //======================================================================
11617  /// Creates the halo elements on all processors
11618  /// Gets the halo elements on all processors, these elements are then used
11619  /// on the function that computes the shared boundaries among the processors
11620  //======================================================================
11621  template<class ELEMENT>
11623  const unsigned& nproc,
11624  const Vector<unsigned>& element_domain,
11625  const Vector<GeneralisedElement*>& backed_up_el_pt,
11626  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
11627  const bool& overrule_keep_as_halo_element_status,
11628  std::map<GeneralisedElement*, unsigned>& element_to_global_index,
11629  Vector<Vector<Vector<GeneralisedElement*>>>& output_halo_elements_pt)
11630  {
11631  const unsigned n_ele = backed_up_el_pt.size();
11632 
11633  // Loop over all the processors
11634  for (unsigned iproc = 0; iproc < nproc; iproc++)
11635  {
11636  // Boolean to know which elements has been already added to the
11637  // halo scheme on "iproc" processor
11638  Vector<std::map<GeneralisedElement*, bool>> already_added(nproc);
11639 
11640  // Loop over all backed up elements
11641  for (unsigned e = 0; e < n_ele; e++)
11642  {
11643  // Get element and its domain
11644  GeneralisedElement* el_pt = backed_up_el_pt[e];
11645  unsigned el_domain = element_domain[e];
11646 
11647  // If element is NOT located on "iproc" processor then check if it is
11648  // halo with "el_domain" processor
11649  if (el_domain != iproc)
11650  {
11651  // If this current mesh has been told to keep all elements as halos,
11652  // OR the element itself knows that it must be kept then
11653  // keep it
11654  if ((this->Keep_all_elements_as_halos) ||
11655  (el_pt->must_be_kept_as_halo()))
11656  {
11657  if (!overrule_keep_as_halo_element_status)
11658  {
11659  // Add as halo element whose non-halo counterpart is
11660  // located on processor "el_domain"
11661  if (!already_added[el_domain][el_pt])
11662  {
11663  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11664  already_added[el_domain][el_pt] = true;
11665  element_to_global_index[el_pt] = e;
11666  }
11667  }
11668  }
11669  // Otherwise: Is one of the nodes associated with other processor?
11670  else
11671  {
11672  // Can only have nodes if this is a finite element
11673  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11674  if (finite_el_pt != 0)
11675  {
11676  unsigned n_node = finite_el_pt->nnode();
11677  for (unsigned n = 0; n < n_node; n++)
11678  {
11679  Node* nod_pt = finite_el_pt->node_pt(n);
11680 
11681  // Keep element?
11682  std::set<unsigned>::iterator it =
11683  processors_associated_with_data[nod_pt].find(iproc);
11684  if (it != processors_associated_with_data[nod_pt].end())
11685  {
11686  // Add as root halo element whose non-halo counterpart is
11687  // located on processor "el_domain"
11688  if (!already_added[el_domain][el_pt])
11689  {
11690  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11691  already_added[el_domain][el_pt] = true;
11692  element_to_global_index[el_pt] = e;
11693  }
11694  // Now break out of loop over nodes
11695  break;
11696  } // if (it!=processors_associated_with_data[nod_pt].end())
11697  } // for (n < n_node)
11698  } // if (finite_el_pt!=0)
11699  } // else (this->Keep_all_elements_as_halos)
11700  } // if (el_domain!=iproc)
11701  } // for (e < nele)
11702  } // for (iproc < nproc)
11703  }
11704 
11705  //====================================================================
11706  // Get the element edges (pair of nodes, edges) that lie
11707  // on a boundary (used to mark shared boundaries that lie on
11708  // internal boundaries)
11709  //====================================================================
11710  template<class ELEMENT>
11712  std::map<std::pair<Node*, Node*>, unsigned>& element_edges_on_boundary)
11713  {
11714  // The number of original boundaries
11715  const unsigned nbound = this->nboundary();
11716  // Loop over the boundaries
11717  for (unsigned b = 0; b < nbound; b++)
11718  {
11719  // Keep track of the pair of nodes done
11720  std::map<std::pair<Node*, Node*>, bool> edge_done;
11721  // Get the number of elements on the boundary
11722  const unsigned nbound_ele = this->nboundary_element(b);
11723  for (unsigned e = 0; e < nbound_ele; e++)
11724  {
11725  // Get the boundary bulk element
11726  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11727  // Get the face index
11728  int face_index = this->face_index_at_boundary(b, e);
11729  // Create the face element
11730  FiniteElement* face_ele_pt =
11731  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
11732  // Get the number of nodes on the face element
11733  const unsigned nnodes = face_ele_pt->nnode();
11734  // Get the first and last node
11735  Node* first_node_pt = face_ele_pt->node_pt(0);
11736  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
11737 
11738  // Create the pair to store the nodes
11739  std::pair<Node*, Node*> edge =
11740  std::make_pair(first_node_pt, last_node_pt);
11741 
11742  // Has the edge been included
11743  if (!edge_done[edge])
11744  {
11745  // Mark the edge as done
11746  edge_done[edge] = true;
11747 
11748  // Create the reversed version and mark it as done too
11749  std::pair<Node*, Node*> inv_edge =
11750  std::make_pair(last_node_pt, first_node_pt);
11751 
11752  // Mark the reversed edge as done
11753  edge_done[inv_edge] = true;
11754 
11755  // Mark the edge to belong to boundary b
11756  element_edges_on_boundary[edge] = b;
11757  } // if (!edge_done[edge])
11758 
11759  // Free the memory allocated for the face element
11760  delete face_ele_pt;
11761  face_ele_pt = 0;
11762 
11763  } // for (e < nbound_ele)
11764 
11765  } // for (b < nbound)
11766  }
11767 
11768  // ======================================================================
11769  // Creates polylines from the intersection of halo elements on
11770  // all processors. The new polylines define the shared boundaries in
11771  // the domain This method computes the polylines on ALL processors,
11772  // that is why the three dimensions in the structure
11773  // output_polylines_pt[iproc][ncurve][npolyline]
11774  // ======================================================================
11775  template<class ELEMENT>
11777  const Vector<unsigned>& element_domain,
11778  std::map<GeneralisedElement*, unsigned>& element_to_global_index,
11779  std::set<FiniteElement*>& element_in_processor_pt,
11780  Vector<Vector<Vector<GeneralisedElement*>>>& input_halo_elements,
11781  std::map<std::pair<Node*, Node*>, unsigned>& elements_edges_on_boundary,
11782  Vector<Vector<Vector<TriangleMeshPolyLine*>>>& output_polylines_pt)
11783  {
11784  const unsigned nproc = this->communicator_pt()->nproc();
11785  const unsigned my_rank = this->communicator_pt()->my_rank();
11786 
11787  // ---------------------------------------------------------------
11788  // Get the edges shared between each pair of processors
11789  // ---------------------------------------------------------------
11790 
11791  // Storage for the edges (pair of nodes) shared between a pair of
11792  // processors
11793  Vector<Vector<Vector<std::pair<Node*, Node*>>>> edges(nproc);
11794 
11795  // Each edge is associated to two elements, a haloi (halo element
11796  // in processors i) and a haloj (halo element in processors j)
11797  Vector<Vector<Vector<Vector<FiniteElement*>>>> edge_element_pt(nproc);
11798 
11799  // Each edge is associated to two elements, a haloi and a haloj,
11800  // the edge was created from a given face from each element, the
11801  // haloi face is stored at [0], the haloj face is stored at [1]
11802  Vector<Vector<Vector<Vector<int>>>> edge_element_face(nproc);
11803 
11804  // Store the possible internal boundary id associated to each edge
11805  // (-1 if there is no association). Some edges may overlap an
11806  // internal boundary (and only internal boundaries)
11807  Vector<Vector<Vector<int>>> edge_boundary(nproc);
11808 
11809  // Mark those edges (pair of nodes overlapped by a shared boundary)
11810  std::map<std::pair<Node*, Node*>, bool> overlapped_edge;
11811 
11812  // Resize the containers, they store info. for each pair of
11813  // processors
11814 
11815  // First resize the global container
11816  Shared_boundaries_ids.resize(nproc);
11817  for (unsigned j = 0; j < nproc; j++)
11818  {
11819  edges[j].resize(nproc);
11820  edge_element_pt[j].resize(nproc);
11821  edge_element_face[j].resize(nproc);
11822  edge_boundary[j].resize(nproc);
11823 
11824  // Resize the global container for shared boundaries ids
11825  Shared_boundaries_ids[j].resize(nproc);
11826 
11827  } // for (j < nproc)
11828 
11829  // Take the halo elements of processor "iproc" and compare their
11830  // edges with halo elements of other processors (except itself)
11831  for (unsigned iproc = 0; iproc < nproc; iproc++)
11832  {
11833  // Take the halo elements of processor iproc and compare with
11834  // other processors
11835  // Start from the iproc + 1,
11836  // 1) To avoid comparing with itself,
11837  // 2) To avoid generation of repeated boundaries
11838  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11839  {
11840  // **************************************************************
11841  // FIRST PART
11842  // 1) Get the halo elements of processor "iproc" with processor
11843  // "jproc"
11844  // 2) Get the halo elements of processor "jproc" with processor
11845  // "iproc"
11846  // 3) Compare their edges and those that match are the ones that
11847  // define the shared boundaries
11848  // **************************************************************
11849 
11850  // Storage for halo elements
11851  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11852  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11853 
11854  // Get the halo elements of "iproc" with "jproc"
11855  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11856 
11857  // If there are halo elements then there are shared boundaries
11858  const unsigned nhalo_elements_iproc_with_jproc =
11859  halo_elements_iproc_with_jproc.size();
11860  // DEBP(nhalo_elements_iproc_with_jproc);
11861  if (nhalo_elements_iproc_with_jproc > 0)
11862  {
11863  // Get the halo elements of "jproc" with "iproc"
11864  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11865 
11866  // If there are halo elements then there are shared
11867  // boundaries
11868  const unsigned nhalo_elements_jproc_with_iproc =
11869  halo_elements_jproc_with_iproc.size();
11870 // DEBP(nhalo_elements_jproc_with_iproc);
11871 #ifdef PARANOID
11872  if (nhalo_elements_jproc_with_iproc == 0)
11873  {
11874  // If there are halo elements of iproc with jproc there
11875  // MUST be halo elements on the other way round, not
11876  // necessary the same but at least one
11877  std::stringstream err;
11878  err << "There are no halo elements from processor (" << jproc
11879  << ") "
11880  << "with processor (" << iproc << ").\n"
11881  << "This is strange since there are halo elements from "
11882  << "processor (" << iproc << ") with processor (" << jproc
11883  << ").\n"
11884  << "Number of halo elements from (" << iproc << ") to ("
11885  << jproc << ") : (" << nhalo_elements_iproc_with_jproc << ")\n"
11886  << "Number of halo elements from (" << jproc << ") to ("
11887  << iproc << ") : (" << nhalo_elements_jproc_with_iproc << ")\n";
11888  throw OomphLibError(
11889  err.str(),
11890  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11891  OOMPH_EXCEPTION_LOCATION);
11892  }
11893 #endif
11894  // The edges are defined as pair of nodes
11895  Vector<Node*> halo_edges_iproc;
11896  unsigned halo_edges_counter_iproc = 0;
11897  Vector<Node*> halo_edges_jproc;
11898  unsigned halo_edges_counter_jproc = 0;
11899 
11900  // Map to associate the edge with the element used to create it
11901  std::map<std::pair<Node*, Node*>, FiniteElement*>
11902  edgesi_to_element_pt;
11903 
11904  // Map to associated the edge with the face number of the
11905  // element that created it
11906  std::map<std::pair<std::pair<Node*, Node*>, FiniteElement*>, int>
11907  edgesi_element_pt_to_face_index;
11908 
11909  // Map to associate the edge with the element used to create it
11910  std::map<std::pair<Node*, Node*>, FiniteElement*>
11911  edgesj_to_element_pt;
11912 
11913  // Map to associated the edge with the face number of the
11914  // element that created it
11915  std::map<std::pair<std::pair<Node*, Node*>, FiniteElement*>, int>
11916  edgesj_element_pt_to_face_index;
11917 
11918  // **************************************************************
11919  // 1.1) Store the edges of the "iproc" halo elements
11920  // **************************************************************
11921  // Go throught halo elements on "iproc" processor
11922  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11923  {
11924 #ifdef PARANOID
11925  unsigned e =
11926  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11927  // Only work with halo elements inside the "jproc" processor
11928  if (element_domain[e] != jproc)
11929  {
11930  // There was a problem on the ihalo-jhalo classification
11931  std::stringstream err;
11932  err << "There was a problem on the ihalo-jhalo classification.\n"
11933  << "One of the elements, (the one with the (" << e << ")-th "
11934  << "index ) is not on the (" << jproc << ")-th processor\n"
11935  << "but it was stored as a halo element of processor ("
11936  << iproc << ") with processor (" << jproc << ").\n";
11937  throw OomphLibError(
11938  err.str(),
11939  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11940  OOMPH_EXCEPTION_LOCATION);
11941  }
11942 #endif
11943 
11944  FiniteElement* el_pt =
11945  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11946 
11947  if (el_pt == 0)
11948  {
11949  std::stringstream err;
11950  err << "The halo element (" << ih
11951  << ") could not be casted to the "
11952  << "FiniteElement type.\n";
11953  throw OomphLibError(
11954  err.str(),
11955  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11956  OOMPH_EXCEPTION_LOCATION);
11957  }
11958 
11959 #ifdef PARANOID
11960  // Number of nodes on this element
11961  const unsigned n_nodes = el_pt->nnode();
11962 
11963  // The number of nodes on every element should be at least
11964  // three since we are going to work with the cornes nodes,
11965  // the ones with index 0, 1 and 2
11966  if (n_nodes < 3)
11967  {
11968  std::stringstream err;
11969  err << "The number of nodes of the " << ih
11970  << "-th halo element is"
11971  << " (" << n_nodes << ").\nWe can not work with triangle "
11972  << "elements with less than three nodes\n";
11973  throw OomphLibError(
11974  err.str(),
11975  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11976  OOMPH_EXCEPTION_LOCATION);
11977  }
11978 #endif
11979 
11980  // Get the corner nodes, the first three nodes
11981  Node* first_node_pt = el_pt->node_pt(0);
11982  Node* second_node_pt = el_pt->node_pt(1);
11983  Node* third_node_pt = el_pt->node_pt(2);
11984 
11985  // Store the edges
11986  halo_edges_iproc.push_back(first_node_pt);
11987  halo_edges_iproc.push_back(second_node_pt);
11988  halo_edges_counter_jproc++;
11989 
11990  halo_edges_iproc.push_back(second_node_pt);
11991  halo_edges_iproc.push_back(third_node_pt);
11992  halo_edges_counter_jproc++;
11993 
11994  halo_edges_iproc.push_back(third_node_pt);
11995  halo_edges_iproc.push_back(first_node_pt);
11996  halo_edges_counter_jproc++;
11997 
11998  // Store the info. of the element used to create these edges
11999  std::pair<Node*, Node*> edge1 =
12000  std::make_pair(first_node_pt, second_node_pt);
12001  edgesi_to_element_pt[edge1] = el_pt;
12002 
12003  std::pair<Node*, Node*> edge2 =
12004  std::make_pair(second_node_pt, third_node_pt);
12005  edgesi_to_element_pt[edge2] = el_pt;
12006 
12007  std::pair<Node*, Node*> edge3 =
12008  std::make_pair(third_node_pt, first_node_pt);
12009  edgesi_to_element_pt[edge3] = el_pt;
12010 
12011  // Store the face index of the edge in the element
12012  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
12013  std::make_pair(edge1, el_pt);
12014  edgesi_element_pt_to_face_index[edge_ele1] = 2;
12015 
12016  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
12017  std::make_pair(edge2, el_pt);
12018  edgesi_element_pt_to_face_index[edge_ele2] = 0;
12019 
12020  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
12021  std::make_pair(edge3, el_pt);
12022  edgesi_element_pt_to_face_index[edge_ele3] = 1;
12023 
12024  } // for (ih < nhalo_elements_iproc_with_jproc)
12025 
12026  // **************************************************************
12027  // 1.2) Store the edges of the "jproc" halo elements
12028  // **************************************************************
12029  // Go throught halo elements on "jproc" processor
12030  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
12031  {
12032 #ifdef PARANOID
12033  unsigned e =
12034  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
12035  // Only work with halo elements inside the "jproc" processor
12036  if (element_domain[e] != iproc)
12037  {
12038  // There was a problem on the jhalo-ihalo classification
12039  std::stringstream err;
12040  err << "There was a problem on the jhalo-ihalo classification.\n"
12041  << "One of the elements, (the one with the (" << e << ")-th "
12042  << "index ) is not on the (" << iproc << ")-th processor\n"
12043  << "but it was stored as a halo element of processor ("
12044  << jproc << ") with processor (" << iproc << ").\n";
12045  throw OomphLibError(
12046  err.str(),
12047  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12048  OOMPH_EXCEPTION_LOCATION);
12049  }
12050 #endif
12051 
12052  FiniteElement* el_pt =
12053  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
12054  if (el_pt == 0)
12055  {
12056  std::stringstream err;
12057  err << "The halo element (" << jh
12058  << ") could not be casted to the "
12059  << "FiniteElement type.\n";
12060  throw OomphLibError(
12061  err.str(),
12062  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12063  OOMPH_EXCEPTION_LOCATION);
12064  }
12065 
12066 #ifdef PARANOID
12067  // Number of nodes on this element
12068  const unsigned n_nodes = el_pt->nnode();
12069 
12070  // The number of nodes on every element should be at least
12071  // three since we are going to work with the cornes nodes,
12072  // the ones with index 0, 1 and 2
12073  if (n_nodes < 3)
12074  {
12075  std::stringstream err;
12076  err << "The number of nodes of the " << jh
12077  << "-th halo element is"
12078  << " (" << n_nodes << ").\nWe can not work with triangle "
12079  << "elements with less than three nodes\n";
12080  throw OomphLibError(
12081  err.str(),
12082  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12083  OOMPH_EXCEPTION_LOCATION);
12084  }
12085 #endif
12086 
12087  // Get the nodes pointers
12088  Node* first_node_pt = el_pt->node_pt(0);
12089  Node* second_node_pt = el_pt->node_pt(1);
12090  Node* third_node_pt = el_pt->node_pt(2);
12091 
12092  // Store the edges
12093  halo_edges_jproc.push_back(first_node_pt);
12094  halo_edges_jproc.push_back(second_node_pt);
12095  halo_edges_counter_iproc++;
12096 
12097  halo_edges_jproc.push_back(second_node_pt);
12098  halo_edges_jproc.push_back(third_node_pt);
12099  halo_edges_counter_iproc++;
12100 
12101  halo_edges_jproc.push_back(third_node_pt);
12102  halo_edges_jproc.push_back(first_node_pt);
12103  halo_edges_counter_iproc++;
12104 
12105  // Store the info. of the element used to create these edges
12106  std::pair<Node*, Node*> edge1 =
12107  std::make_pair(first_node_pt, second_node_pt);
12108  edgesj_to_element_pt[edge1] = el_pt;
12109 
12110  std::pair<Node*, Node*> edge2 =
12111  std::make_pair(second_node_pt, third_node_pt);
12112  edgesj_to_element_pt[edge2] = el_pt;
12113 
12114  std::pair<Node*, Node*> edge3 =
12115  std::make_pair(third_node_pt, first_node_pt);
12116  edgesj_to_element_pt[edge3] = el_pt;
12117 
12118  // Store the face index of the edge in the element
12119  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
12120  std::make_pair(edge1, el_pt);
12121  edgesj_element_pt_to_face_index[edge_ele1] = 2;
12122 
12123  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
12124  std::make_pair(edge2, el_pt);
12125  edgesj_element_pt_to_face_index[edge_ele2] = 0;
12126 
12127  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
12128  std::make_pair(edge3, el_pt);
12129  edgesj_element_pt_to_face_index[edge_ele3] = 1;
12130 
12131  } // for (jh < nhalo_elements_jproc_with_iproc)
12132 
12133  // ***************************************************************
12134  // SECOND PART
12135  // 1) We already have the information of the edges on the iproc
12136  // halo and jproc halo elements
12137  // 2) Identify the shared edges to create the shared boundaries
12138  // (Only store the information but do not create the polyline)
12139  // ***************************************************************
12140 
12141  // Get the number of edges from each processor
12142  unsigned nhalo_iedges = halo_edges_iproc.size();
12143  unsigned nhalo_jedges = halo_edges_jproc.size();
12144 
12145  // Start comparing the edges to check which of those are
12146  // shared between the "ihalo_edge" and the "jhalo_edge"
12147  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe += 2)
12148  {
12149  // Get the ihe-th edge (pair of nodes)
12150  Vector<Node*> ihalo_edge(2);
12151  ihalo_edge[0] = halo_edges_iproc[ihe];
12152  ihalo_edge[1] = halo_edges_iproc[ihe + 1];
12153 
12154  // Create the pair that defines the edge
12155  std::pair<Node*, Node*> tmp_edge =
12156  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12157 
12158  // Check if the edge lies on a boundary (default values is
12159  // -1 for no association with an internal boundary)
12160  int edge_boundary_id = -1;
12161  {
12162  std::map<std::pair<Node*, Node*>, unsigned>::iterator it;
12163  it = elements_edges_on_boundary.find(tmp_edge);
12164  // If the edges lie on a boundary then get the boundary id
12165  // on which the edges lie
12166  if (it != elements_edges_on_boundary.end())
12167  {
12168  // Assign the internal boundary id associated with the
12169  // edge
12170  edge_boundary_id = (*it).second;
12171  }
12172  else
12173  {
12174  // Look for the reversed version of the edge (the nodes
12175  // inverted)
12176  std::pair<Node*, Node*> rtmp_edge =
12177  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12178  it = elements_edges_on_boundary.find(rtmp_edge);
12179  if (it != elements_edges_on_boundary.end())
12180  {
12181  // Assign the internal boundary id associated with the
12182  // edge
12183  edge_boundary_id = (*it).second;
12184  }
12185  }
12186  }
12187 
12188  // Go through the jhalo_edge and compare with the
12189  // ihalo_edge
12190  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe += 2)
12191  {
12192  // Get the jhe-th edge (pair of nodes)
12193  Vector<Node*> jhalo_edge(2);
12194  jhalo_edge[0] = halo_edges_jproc[jhe];
12195  jhalo_edge[1] = halo_edges_jproc[jhe + 1];
12196 
12197  // Comparing pointer of nodes
12198  if (ihalo_edge[0] == jhalo_edge[0] &&
12199  ihalo_edge[1] == jhalo_edge[1])
12200  {
12201  // Create the edge (both nodes that make the edge)
12202  std::pair<Node*, Node*> new_edge =
12203  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12204 
12205  // Get the elements involved in the creation of the
12206  // edge to check that there are elements associated to
12207  // the edge
12208  FiniteElement* haloi_ele_pt = 0;
12209  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12210  FiniteElement* haloj_ele_pt = 0;
12211  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12212 
12213  // Verify that there is an element associated with it
12214  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12215  {
12216  std::stringstream err;
12217  err << "There is no associated elements with the new "
12218  << "shared boundary. This is an storing problem,\n"
12219  << "possibly related with a memory leak problem!!!\n"
12220  << "The nodes that compound the edge are these:\n"
12221  << "On processor (" << iproc << "):\n"
12222  << "(" << ihalo_edge[0]->x(0) << ", "
12223  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12224  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12225  << "On processor (" << jproc << "):\n"
12226  << "(" << jhalo_edge[0]->x(0) << ", "
12227  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12228  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12229  << "The nodes coordinates should be the same!!!\n";
12230  throw OomphLibError(err.str(),
12231  "TriangleMesh::create_polylines_from_"
12232  "halo_elements_helper()",
12233  OOMPH_EXCEPTION_LOCATION);
12234  }
12235 
12236  // Store the edge
12237  edges[iproc][jproc].push_back(new_edge);
12238 
12239  // Is the edge overlapped by a shared boundary
12240  if (edge_boundary_id >= 0)
12241  {
12242  // Mark the edge as overlapped
12243  overlapped_edge[new_edge] = true;
12244 
12245  // Also mark the reversed edge
12246  std::pair<Node*, Node*> rev_new_edge =
12247  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12248 
12249  // Mark the edge as overlapped
12250  overlapped_edge[rev_new_edge] = true;
12251 
12252  } // if (edge_boundary_id >= 0)
12253 
12254  // Store the internal boundary id (default -1)
12255  // associated to the edge
12256  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12257 
12258  // Store the two elements associated with the edge
12259  Vector<FiniteElement*> tmp_elements_pt;
12260  tmp_elements_pt.push_back(haloi_ele_pt);
12261  tmp_elements_pt.push_back(haloj_ele_pt);
12262 
12263  // Associate the edge with the elements that gave rise to it
12264  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12265 
12266  // Get the face index on each element that gave rise to
12267  // the edge
12268 
12269  // .. first create the pair (edge, finite_element)
12270  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12271  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12272 
12273  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12274  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12275 
12276  // Set default values to later check if values were
12277  // read from the map structure
12278  int face_index_haloi_ele = -1;
12279  face_index_haloi_ele =
12280  edgesi_element_pt_to_face_index[edge_elementi_pair];
12281  int face_index_haloj_ele = -1;
12282  face_index_haloj_ele =
12283  edgesj_element_pt_to_face_index[edge_elementj_pair];
12284  // Verify that there is an element associated with it
12285  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12286  {
12287  std::stringstream err;
12288  err << "There is no associated face indexes to the"
12289  << "elements that gave\nrise to the shared edge\n"
12290  << "The nodes that compound the edge are these:\n"
12291  << "On processor (" << iproc << "):\n"
12292  << "(" << ihalo_edge[0]->x(0) << ", "
12293  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12294  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12295  << "On processor (" << jproc << "):\n"
12296  << "(" << jhalo_edge[0]->x(0) << ", "
12297  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12298  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12299  << "The nodes coordinates should be the same!!!\n";
12300  throw OomphLibError(err.str(),
12301  "TriangleMesh::create_polylines_from_"
12302  "halo_elements_helper()",
12303  OOMPH_EXCEPTION_LOCATION);
12304  } // if (face_index_haloi_ele == -1 ||
12305  // face_index_haloj_ele == -1)
12306 
12307  // Get the face indexes from the map structure
12308  Vector<int> tmp_edge_element_face_index;
12309  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12310  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12311  // Store the face indexes
12312  edge_element_face[iproc][jproc].push_back(
12313  tmp_edge_element_face_index);
12314 
12315  break; // break for (jhe < nhalo_jedges) since edge
12316  // found
12317 
12318  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12319  // ihalo_edge[1] == jhalo_edge[1])
12320  // Comparing nodes pointers
12321  else if (ihalo_edge[0] == jhalo_edge[1] &&
12322  ihalo_edge[1] == jhalo_edge[0])
12323  {
12324  // Create the edge (both nodes that make the edge)
12325  std::pair<Node*, Node*> new_edge =
12326  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12327 
12328  // Get the elements involved in the creation of the
12329  // edge
12330  FiniteElement* haloi_ele_pt = 0;
12331  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12332 
12333  FiniteElement* haloj_ele_pt = 0;
12334  // Create the edge (reversed, that is how it was
12335  // originally stored)
12336  std::pair<Node*, Node*> new_edge_reversed =
12337  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12338  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12339 
12340  // Verify that there is an element associated with it
12341  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12342  {
12343  std::stringstream err;
12344  err << "There is no associated elements with the new "
12345  << "shared boundary (reversed version). This is an "
12346  << "storing problem, possibly related with a memory "
12347  << "leak problem!!!\n"
12348  << "The nodes that compound the edge are these:\n"
12349  << "On processor (" << iproc << "):\n"
12350  << "(" << ihalo_edge[0]->x(0) << ", "
12351  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12352  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12353  << "On processor (" << jproc << "):\n"
12354  << "(" << jhalo_edge[0]->x(0) << ", "
12355  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12356  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12357  << "The nodes coordinates should be the same!!!\n";
12358  throw OomphLibError(err.str(),
12359  "TriangleMesh::create_polylines_from_"
12360  "halo_elements_helper()",
12361  OOMPH_EXCEPTION_LOCATION);
12362  }
12363 
12364  // Store the edge
12365  edges[iproc][jproc].push_back(new_edge);
12366 
12367  // Is the edge overlapped by a shared boundary
12368  if (edge_boundary_id >= 0)
12369  {
12370  // Mark the edge as overlapped
12371  overlapped_edge[new_edge] = true;
12372 
12373  // Also mark the reversed edge
12374  std::pair<Node*, Node*> rev_new_edge =
12375  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12376 
12377  // Mark the edge as overlapped
12378  overlapped_edge[rev_new_edge] = true;
12379  } // if (edge_boundary_id >= 0)
12380 
12381  // Store the internal boundary id (default -1)
12382  // associated to the edge
12383  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12384 
12385  // Store the two elements associated with the edge
12386  Vector<FiniteElement*> tmp_elements_pt;
12387  tmp_elements_pt.push_back(haloi_ele_pt);
12388  tmp_elements_pt.push_back(haloj_ele_pt);
12389 
12390  // Associate the edge with the elements that gave rise to it
12391  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12392 
12393  // Get the face index on each element that gave rise to
12394  // the edge
12395 
12396  // .. first create the pair (edge, finite_element)
12397  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12398  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12399 
12400  std::pair<std::pair<Node*, Node*>, FiniteElement*>
12401  edge_elementj_pair =
12402  make_pair(new_edge_reversed, haloj_ele_pt);
12403 
12404  // Set default values to later check if values were
12405  // read from the map structure
12406  int face_index_haloi_ele = -1;
12407  face_index_haloi_ele =
12408  edgesi_element_pt_to_face_index[edge_elementi_pair];
12409  int face_index_haloj_ele = -1;
12410  face_index_haloj_ele =
12411  edgesj_element_pt_to_face_index[edge_elementj_pair];
12412  // Verify that there is an element associated with it
12413  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12414  {
12415  std::stringstream err;
12416  err << "There is no associated face indexes to the"
12417  << "elements that gave\nrise to the shared edge\n"
12418  << "The nodes that compound the edge are these:\n"
12419  << "On processor (" << iproc << "):\n"
12420  << "(" << ihalo_edge[0]->x(0) << ", "
12421  << ihalo_edge[0]->x(1) << ") and (" << ihalo_edge[1]->x(0)
12422  << ", " << ihalo_edge[1]->x(1) << ")\n\n"
12423  << "On processor (" << jproc << "):\n"
12424  << "(" << jhalo_edge[0]->x(0) << ", "
12425  << jhalo_edge[0]->x(1) << ") and (" << jhalo_edge[1]->x(0)
12426  << ", " << jhalo_edge[1]->x(1) << ")\n\n"
12427  << "The nodes coordinates should be the same!!!\n";
12428  throw OomphLibError(err.str(),
12429  "TriangleMesh::create_polylines_from_"
12430  "halo_elements_helper()",
12431  OOMPH_EXCEPTION_LOCATION);
12432  } // if (face_index_haloi_ele == -1 ||
12433  // face_index_haloj_ele == -1)
12434 
12435  // Get the face indexes from the map structure
12436  Vector<int> tmp_edge_element_face_index;
12437  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12438  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12439  // Store the face indexes
12440  edge_element_face[iproc][jproc].push_back(
12441  tmp_edge_element_face_index);
12442 
12443  break; // break for (jhe < nhalo_jedges) since edge found
12444 
12445  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12446  // ihalo_edge[1] == jhalo_edge[0])
12447 
12448  } // for (jhe < nhaloj_edges)
12449 
12450  } // for (ihe < nhaloi_edges)
12451 
12452  } // if (nhalo_elements_iproc_with_jproc > 0)
12453 
12454  } // for (jproc < nproc)
12455 
12456  } // for (iproc < nproc)
12457 
12458  // ------------------------------------------------------------------
12459  // Compute the degree of each node in the shared edges
12460  // ------------------------------------------------------------------
12461 
12462  // Visit all the shared edges between each pair of processors,
12463  // visit the nodes of each edge and compute the degree of each node
12464 
12465  // Store the degree (valency) of each node
12466  std::map<Node*, unsigned> global_shared_node_degree;
12467 
12468 #ifdef PARANOID
12469  // Map to check if an edge has been already visited
12470  std::map<std::pair<Node*, Node*>, bool> edge_done;
12471 #endif // #ifdef PARANOID
12472  // Map to check if a node has been already visited
12473  std::map<Node*, bool> node_done;
12474 
12475  // Loop over the processors and get the shared edged between each
12476  // pair of processors
12477  for (unsigned iproc = 0; iproc < nproc; iproc++)
12478  {
12479  // Start from iproc + 1 to avoid checking with itself (there is
12480  // no shared edges between the same processor), and to avoid
12481  // double counting the edges and nodes (the shared edges between
12482  // processor (iproc, jproc) are the same as those between
12483  // processor jproc, iproc)
12484  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12485  {
12486  // Get the number of edges shared between the pair of processors
12487  const unsigned nshd_edges = edges[iproc][jproc].size();
12488 #ifdef PARANOID
12489  // There must be the same number of information on each of the
12490  // containers
12491 
12492  // Get the number of edge elements
12493  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12494  if (nshd_edges != nedge_element)
12495  {
12496  std::stringstream error_message;
12497  error_message
12498  << "The number of shared edges between processor iproc and jproc\n"
12499  << "is different form the number of edge elements between the\n"
12500  << "pair of processors\n"
12501  << "iproc: (" << iproc << ")\n"
12502  << "jproc: (" << jproc << ")\n"
12503  << "# of shared edges: (" << nshd_edges << ")\n"
12504  << "# of edge elements: (" << nedge_element << ")\n\n";
12505  throw OomphLibError(
12506  error_message.str(),
12507  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12508  OOMPH_EXCEPTION_LOCATION);
12509  }
12510 
12511  // Get the number of edge element faces
12512  const unsigned nedge_element_face =
12513  edge_element_face[iproc][jproc].size();
12514  if (nshd_edges != nedge_element_face)
12515  {
12516  std::stringstream error_message;
12517  error_message
12518  << "The number of shared edges between processor iproc and jproc\n"
12519  << "is different form the number of edge element faces between "
12520  "the\n"
12521  << "pair of processors\n"
12522  << "iproc: (" << iproc << ")\n"
12523  << "jproc: (" << jproc << ")\n"
12524  << "# of shared edges: (" << nshd_edges << ")\n"
12525  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12526  throw OomphLibError(
12527  error_message.str(),
12528  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12529  OOMPH_EXCEPTION_LOCATION);
12530  }
12531 
12532  // Get the number of edge boundaries
12533  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12534  if (nshd_edges != nedge_boundary)
12535  {
12536  std::stringstream error_message;
12537  error_message
12538  << "The number of shared edges between processor iproc and jproc\n"
12539  << "is different form the number of edge boundaries ids between "
12540  "the\n"
12541  << "pair of processors\n"
12542  << "iproc: (" << iproc << ")\n"
12543  << "jproc: (" << jproc << ")\n"
12544  << "# of shared edges: (" << nshd_edges << ")\n"
12545  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12546  throw OomphLibError(
12547  error_message.str(),
12548  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12549  OOMPH_EXCEPTION_LOCATION);
12550  }
12551 
12552 #endif // #ifdef PARANOID
12553 
12554  // Loop over the shared edges between (iproc, jproc) processors
12555  for (unsigned se = 0; se < nshd_edges; se++)
12556  {
12557  // Get the edge
12558  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12559 #ifdef PARANOID
12560  // Check that the edge has not been previously visited
12561  if (edge_done[edge])
12562  {
12563  std::stringstream error_message;
12564  error_message
12565  << "The shared edge between processor iproc and processor\n"
12566  << "jproc has been already visited, this is weird since the\n"
12567  << "edge should not be shared by other pair of processors\n"
12568  << "iproc: (" << iproc << ")\n"
12569  << "jproc: (" << jproc << ")\n"
12570  << "First node of edge: (" << edge.first->x(0) << ", "
12571  << edge.first->x(1) << ")\n"
12572  << "Second node of edge: (" << edge.second->x(0) << ", "
12573  << edge.second->x(1) << ")\n"
12574  << "Associated edge boundary id: ("
12575  << edge_boundary[iproc][jproc][se] << ")\n\n";
12576  throw OomphLibError(
12577  error_message.str(),
12578  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12579  OOMPH_EXCEPTION_LOCATION);
12580  }
12581 
12582  // Mark the edge as done
12583  edge_done[edge] = true;
12584  // Create the reversed version and include it too
12585  std::pair<Node*, Node*> rev_edge =
12586  std::make_pair(edge.second, edge.first);
12587  // Mark reversed edge as done
12588  edge_done[rev_edge] = true;
12589 #endif // #ifdef PARANOID
12590 
12591  // Get each of the nodes that conform the edge
12592  Node* left_node_pt = edge.first;
12593  Node* right_node_pt = edge.second;
12594 
12595  // Check if the left node has been already done
12596  if (!node_done[left_node_pt])
12597  {
12598  // Set the degree of the node to once since this is the
12599  // first time it has been found
12600  global_shared_node_degree[left_node_pt] = 1;
12601 
12602  } // if (!done_node[left_node_pt])
12603  else
12604  {
12605  // Increase the degree of the node
12606  global_shared_node_degree[left_node_pt]++;
12607  }
12608 
12609  // Check if the right node has been already done
12610  if (!node_done[right_node_pt])
12611  {
12612  // Set the degree of the node to once since this is the
12613  // first time it has been found
12614  global_shared_node_degree[right_node_pt] = 1;
12615  } // if (!done_node[right_node_pt])
12616  else
12617  {
12618  // Increase the degree of the node
12619  global_shared_node_degree[right_node_pt]++;
12620  }
12621 
12622  } // for (se < nshd_edges)
12623 
12624  } // for (jproc < nproc)
12625 
12626  } // for (iproc < nproc)
12627 
12628  // -----------------------------------------------------------------
12629  // Identify those nodes living on edges of original boundaries not
12630  // overlapped by a shared boundary
12631 
12632  // Mark the nodes on original boundaries not overlapped by shared
12633  // boundaries
12634  std::map<unsigned, std::map<Node*, bool>>
12635  node_on_bnd_not_overlapped_by_shd_bnd;
12636 
12637  // Loop over the edges of the original boundaries
12638  for (std::map<std::pair<Node*, Node*>, unsigned>::iterator it_map =
12639  elements_edges_on_boundary.begin();
12640  it_map != elements_edges_on_boundary.end();
12641  it_map++)
12642  {
12643  // Get the edge
12644  std::pair<Node*, Node*> edge_pair = (*it_map).first;
12645 
12646  // Is the edge overlaped by a shared boundary
12647  if (!overlapped_edge[edge_pair])
12648  {
12649  // Mark the nodes of the edge as being on an edge not overlaped
12650  // by a shared boundary on the boundary the edge is
12651  unsigned b = (*it_map).second;
12652 
12653  // Get the left node
12654  Node* left_node_pt = edge_pair.first;
12655  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12656 
12657  // Get the right node
12658  Node* right_node_pt = edge_pair.second;
12659  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12660 
12661  } // if (!overlapped_edge[edge_pair])
12662 
12663  } // Loop over edges to mark those nodes on overlaped edge by
12664  // shared boundaries
12665 
12666  // ------------------------------------------------------------------
12667  // Now create the shared polylines but including the degree of the
12668  // nodes as a nw stop condition for adding more edges to the side
12669  // or a root edge
12670  // ------------------------------------------------------------------
12671 
12672  // Storage for new created polylines with "each processor", non
12673  // sorted (shared polylines of the current processor only)
12674  Vector<Vector<TriangleMeshPolyLine*>> unsorted_polylines_pt(nproc);
12675 
12676  // Map that associates the shared boundary id with the list of
12677  // nodes that create it (shared boundary of the current processor
12678  // only)
12679  std::map<unsigned, std::list<Node*>> shared_bnd_id_to_sorted_list_node_pt;
12680 
12681  // Get maximum user boundary id and set the initial shared boundary
12682  // id
12683  unsigned shared_boundary_id_start = this->nboundary();
12684  Initial_shared_boundary_id = shared_boundary_id_start;
12685 
12686  // Aqui
12687 
12688  // Loop over the processors and get the shared edged between each
12689  // pair of processors
12690  for (unsigned iproc = 0; iproc < nproc; iproc++)
12691  {
12692  // Start from iproc + 1 to avoid checking with itself (there is
12693  // no shared edges between the same processor), and to avoid
12694  // double counting the edges and nodes (the shared edges between
12695  // processor (iproc, jproc) are the same as those between
12696  // processor jproc, iproc)
12697  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12698  {
12699  // *************************************************************
12700  // THIRD PART
12701  // 1) Sort the edges (make them contiguous) so that they can
12702  // be used as the vertex coordinates that define a shared
12703  // boundary (polyline)
12704  // *************************************************************
12705  unsigned npolylines_counter = 0;
12706  const unsigned nedges = edges[iproc][jproc].size();
12707 
12708  // -----------------------------------------------------------
12709  // Compute all the SHARED POLYLINES
12710  // -----------------------------------------------------------
12711  // The number of sorted edges
12712  unsigned nsorted_edges = 0;
12713 
12714  // Keep track of the already done edges
12715  std::map<std::pair<Node*, Node*>, bool> edge_done;
12716 
12717  // Loop over all the edges to create all the polylines with
12718  // the current processors involved
12719  while (nsorted_edges < nedges)
12720  {
12721  // Temporaly storage for the elements associated to the
12722  // sorted edges
12723  std::list<FiniteElement*> tmp_boundary_element_pt;
12724  // Temporly storage for the face indexes on the element
12725  // that created the given edge
12726  std::list<int> tmp_face_index_element;
12727  // Get an initial pair of nodes to create an edge
12728  std::pair<Node*, Node*> edge;
12729 #ifdef PARANOID
12730  bool found_initial_edge = false;
12731 #endif
12732  int root_edge_bound_id = -1;
12733  unsigned iedge = 0;
12734  for (iedge = 0; iedge < nedges; iedge++)
12735  {
12736  edge = edges[iproc][jproc][iedge];
12737  // If not done then take it as initial edge
12738  if (!edge_done[edge])
12739  {
12740  // Get the boundary id that the edge may be overlapping
12741  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12742 #ifdef PARANOID
12743  found_initial_edge = true;
12744 #endif
12745  nsorted_edges++;
12746  iedge++;
12747  break;
12748  } // if (!edge_done[edge])
12749  } // for (iedge < nedges)
12750 
12751 #ifdef PARANOID
12752  if (!found_initial_edge)
12753  {
12754  std::ostringstream error_message;
12755  error_message
12756  << "All the edge are already done, but the number of done\n"
12757  << "edges (" << nsorted_edges
12758  << ") is still less than the total\n"
12759  << "number of edges (" << nedges << ").\n";
12760  // << "----- Possible memory leak -----\n";
12761  throw OomphLibError(
12762  error_message.str(),
12763  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12764  OOMPH_EXCEPTION_LOCATION);
12765  }
12766 #endif
12767 
12768  // Storing for the sorting nodes extracted from the
12769  // edges. The sorted nodes are used to create a polyline
12770  std::list<Node*> sorted_nodes;
12771  sorted_nodes.clear();
12772 
12773  // The initial and final nodes of the list
12774  Node* first_node_pt = edge.first;
12775  Node* last_node_pt = edge.second;
12776 
12777  // Push back on the list the new edge (nodes)
12778  sorted_nodes.push_back(first_node_pt);
12779  sorted_nodes.push_back(last_node_pt);
12780 
12781  // Get the elements associated to the edge and store them
12782  // in the temporaly boundary elements storage
12783  tmp_boundary_element_pt.push_back(
12784  edge_element_pt[iproc][jproc][iedge - 1][0]);
12785  tmp_boundary_element_pt.push_back(
12786  edge_element_pt[iproc][jproc][iedge - 1][1]);
12787 
12788  // ... then get the face index of the element from where
12789  // the edge came from
12790  tmp_face_index_element.push_back(
12791  edge_element_face[iproc][jproc][iedge - 1][0]);
12792  tmp_face_index_element.push_back(
12793  edge_element_face[iproc][jproc][iedge - 1][1]);
12794 
12795  // Mark edge as done
12796  edge_done[edge] = true;
12797 
12798  // Continue iterating if a new node (that creates a new
12799  // edge) is added to the list, we have just added two nodes
12800  // (the first and last of the root edge)
12801  bool node_added = true;
12802 
12803  // Flags to indicate at which end the node was added (left
12804  // or right)
12805  bool node_added_to_the_left = true;
12806  bool node_added_to_the_right = true;
12807 
12808  // The nodes that create a shared boundary are obtained by
12809  // connecting the edges shared by the halo and haloed
12810  // elements. These edges are connected to left or right of
12811  // the shared boundary. Every time a new edge is added to
12812  // the left (or right), the most left (or right) node is
12813  // searched in the list of nodes of previous shared
12814  // boundaries, if the node is found then it is said to be
12815  // shared with another boundary and a connection to that
12816  // boundary needs to be specified. We stop adding edges
12817  // (and nodes) to the side where that nodes was found to be
12818  // shared. Note that the intersection (shared node) may be
12819  // with the same shared boundary
12820 
12821  // Flag to indicate a node was found to be shared with
12822  // another boundary at the left end (most left node) of the
12823  // shared boundary
12824  bool connection_to_the_left = false;
12825 
12826  // Flag to indicate a node was found to be shared with
12827  // another boundary at the right end (most right node) of
12828  // the shared boundary
12829  bool connection_to_the_right = false;
12830 
12831  // Flag to stop the adding of edges (and nodes) to the
12832  // current shared boundary
12833  bool current_polyline_has_connections_at_both_ends = false;
12834 
12835  // Store the boundary ids of the polylines to connect (only
12836  // used when the polyline was found to have a connection)
12837  // -1: Indicates no connection
12838  // -2: Indicates connection with itself
12839  // Any other value: Boundary id to connect
12840  int bound_id_connection_to_the_left = -1;
12841  int bound_id_connection_to_the_right = -1;
12842 
12843  // Get the degree of the first node
12844  const unsigned first_node_degree =
12845  global_shared_node_degree[first_node_pt];
12846 
12847  // Check if the nodes of the root edge have connections
12848  // ... to the left
12849  bound_id_connection_to_the_left = check_connections_of_polyline_nodes(
12850  element_in_processor_pt,
12851  root_edge_bound_id,
12852  overlapped_edge,
12853  node_on_bnd_not_overlapped_by_shd_bnd,
12854  sorted_nodes,
12855  shared_bnd_id_to_sorted_list_node_pt,
12856  first_node_degree,
12857  first_node_pt);
12858 
12859  // If there is a connection then set the
12860  // corresponding flag
12861  // (-1): No connection
12862  // (-2): Connection with itself
12863  // (-3): No connection, stop adding nodes
12864  // (other value): Boundary id
12865  if (bound_id_connection_to_the_left != -1)
12866  {
12867  connection_to_the_left = true;
12868  } // if (bound_id_connection_to_the_left != -1)
12869 
12870  // Get the degree of the last node
12871  const unsigned last_node_degree =
12872  global_shared_node_degree[last_node_pt];
12873 
12874  // Check if the nodes of the root edge have connections
12875  // ... to the right
12876  bound_id_connection_to_the_right =
12877  check_connections_of_polyline_nodes(
12878  element_in_processor_pt,
12879  root_edge_bound_id,
12880  overlapped_edge,
12881  node_on_bnd_not_overlapped_by_shd_bnd,
12882  sorted_nodes,
12883  shared_bnd_id_to_sorted_list_node_pt,
12884  last_node_degree,
12885  last_node_pt);
12886 
12887  // If there is a connection then set the
12888  // corresponding flag
12889  // (-1): No connection
12890  // (-2): Connection with itself
12891  // (other value): Boundary id
12892  if (bound_id_connection_to_the_right != -1)
12893  {
12894  connection_to_the_right = true;
12895  } // if (bound_id_connection_to_the_right != -1)
12896 
12897  // If the current shared boundary has connections at both
12898  // ends then stop the adding of nodes
12899  if (connection_to_the_left && connection_to_the_right)
12900  {
12901  current_polyline_has_connections_at_both_ends = true;
12902  }
12903 
12904  // Continue searching for more edges if
12905  // 1) A new node was added at the left or right of the list
12906  // 2) There are more edges to possible add
12907  // 3) The added node is not part of any other previous
12908  // shared polyline
12909  while (node_added && (nsorted_edges < nedges) &&
12910  !current_polyline_has_connections_at_both_ends)
12911  {
12912  // Start from the next edge since we have already added
12913  // the previous one as the initial edge (any previous
12914  // edge had to be added to previous polylines)
12915  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12916  {
12917  // Reset the flags for added nodes, to the left and right
12918  node_added = false;
12919  node_added_to_the_left = false;
12920  node_added_to_the_right = false;
12921  // Get the current edge
12922  edge = edges[iproc][jproc][iiedge];
12923  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12924 
12925  // We need to ensure to connect with edges that share
12926  // the same bound id or with those that has no boundary
12927  // id associated (the default -1 value), may apply
12928  // exclusively to internal boundaries
12929  if (!edge_done[edge] && (edge_bound_id == root_edge_bound_id))
12930  {
12931  // Get each individual node
12932  Node* left_node_pt = edge.first;
12933  Node* right_node_pt = edge.second;
12934 
12935  // Pointer to the new added node
12936  Node* new_added_node_pt = 0;
12937 
12938  // Is the node to be added to the left?
12939  if (left_node_pt == first_node_pt && !connection_to_the_left)
12940  {
12941  // Push front the new node
12942  sorted_nodes.push_front(right_node_pt);
12943  // Update the new added node and the first node
12944  new_added_node_pt = first_node_pt = right_node_pt;
12945  // Set the node added flag to true
12946  node_added = true;
12947  // Indicate the node was added to the left
12948  node_added_to_the_left = true;
12949  }
12950  // Is the node to be added to the right?
12951  else if (left_node_pt == last_node_pt &&
12952  !connection_to_the_right)
12953  {
12954  // Push back the new node
12955  sorted_nodes.push_back(right_node_pt);
12956  // Update the new added node and the last node
12957  new_added_node_pt = last_node_pt = right_node_pt;
12958  // Set the node added flag to true
12959  node_added = true;
12960  // Indicate the node was added to the right
12961  node_added_to_the_right = true;
12962  }
12963  // Is the node to be added to the left?
12964  else if (right_node_pt == first_node_pt &&
12965  !connection_to_the_left)
12966  {
12967  // Push front the new node
12968  sorted_nodes.push_front(left_node_pt);
12969  // Update the new added node and the first node
12970  new_added_node_pt = first_node_pt = left_node_pt;
12971  // Set the node added flag to true
12972  node_added = true;
12973  // Indicate the node was added to the left
12974  node_added_to_the_left = true;
12975  }
12976  // Is the node to be added to the right?
12977  else if (right_node_pt == last_node_pt &&
12978  !connection_to_the_right)
12979  {
12980  // Push back the new node
12981  sorted_nodes.push_back(left_node_pt);
12982  // Update the new added node and the last node
12983  new_added_node_pt = last_node_pt = left_node_pt;
12984  // Set the node added flag to true
12985  node_added = true;
12986  // Indicate the node was added to the right
12987  node_added_to_the_right = true;
12988  }
12989 
12990  // If we added a new node then we need to check if
12991  // that node has been already added in other shared
12992  // boundaries (which may define a connection)
12993  if (node_added)
12994  {
12995  // Mark as done only if one of its nodes has been
12996  // added to the list
12997  edge_done[edge] = true;
12998  nsorted_edges++;
12999 
13000  // Get the degree of the added node
13001  const unsigned added_node_degree =
13002  global_shared_node_degree[new_added_node_pt];
13003 
13004  if (node_added_to_the_left)
13005  {
13006  // Add the bulk elements
13007  tmp_boundary_element_pt.push_front(
13008  edge_element_pt[iproc][jproc][iiedge][1]);
13009  tmp_boundary_element_pt.push_front(
13010  edge_element_pt[iproc][jproc][iiedge][0]);
13011  // Add the face elements
13012  tmp_face_index_element.push_front(
13013  edge_element_face[iproc][jproc][iiedge][1]);
13014  tmp_face_index_element.push_front(
13015  edge_element_face[iproc][jproc][iiedge][0]);
13016  }
13017 
13018  if (node_added_to_the_right)
13019  {
13020  // Add the bulk elements
13021  tmp_boundary_element_pt.push_back(
13022  edge_element_pt[iproc][jproc][iiedge][0]);
13023  tmp_boundary_element_pt.push_back(
13024  edge_element_pt[iproc][jproc][iiedge][1]);
13025  // Add the face elements
13026  tmp_face_index_element.push_back(
13027  edge_element_face[iproc][jproc][iiedge][0]);
13028  tmp_face_index_element.push_back(
13029  edge_element_face[iproc][jproc][iiedge][1]);
13030  }
13031 
13032  // Based on which side the node was added, look for
13033  // connections on that side
13034 
13035  // Verify for connections to the left (we need to
13036  // check for the connection variable too, since
13037  // after a connection has been done we no longer
13038  // need to verify for this condition)
13039  if (node_added_to_the_left && !connection_to_the_left)
13040  {
13041  // Check for connection
13042  bound_id_connection_to_the_left =
13043  check_connections_of_polyline_nodes(
13044  element_in_processor_pt,
13045  root_edge_bound_id,
13046  overlapped_edge,
13047  node_on_bnd_not_overlapped_by_shd_bnd,
13048  sorted_nodes,
13049  shared_bnd_id_to_sorted_list_node_pt,
13050  added_node_degree,
13051  new_added_node_pt);
13052 
13053  // If there is a connection then set the
13054  // corresponding flag
13055  // (-1): No connection
13056  // (-2): Connection with itself
13057  // (other value): Boundary id
13058  if (bound_id_connection_to_the_left != -1)
13059  {
13060  connection_to_the_left = true;
13061  } // if (bound_id_connection_to_the_left != -1)
13062 
13063  } // if (node_added_to_the_left &&
13064  // !connection_to_the_left)
13065 
13066  // Verify for connections to the right (we need to
13067  // check for the connection variable too, since
13068  // after a connection has been done we no longer
13069  // need to verify for this condition)
13070  if (node_added_to_the_right && !connection_to_the_right)
13071  {
13072  // Check for connection
13073  bound_id_connection_to_the_right =
13074  check_connections_of_polyline_nodes(
13075  element_in_processor_pt,
13076  root_edge_bound_id,
13077  overlapped_edge,
13078  node_on_bnd_not_overlapped_by_shd_bnd,
13079  sorted_nodes,
13080  shared_bnd_id_to_sorted_list_node_pt,
13081  added_node_degree,
13082  new_added_node_pt);
13083 
13084  // If there is a connection then set the
13085  // corresponding flag
13086  // (-1): No connection
13087  // (-2): Connection with itself
13088  // (other value): Boundary id
13089  if (bound_id_connection_to_the_right != -1)
13090  {
13091  connection_to_the_right = true;
13092  } // if (bound_id_connection_to_the_right != -1)
13093 
13094  } // if (node_added_to_the_right &&
13095  // !connection_to_the_right)
13096 
13097  // If the current shared boundary has connections
13098  // at both ends then stop the adding of nodes
13099  if (connection_to_the_left && connection_to_the_right)
13100  {
13101  current_polyline_has_connections_at_both_ends = true;
13102  }
13103 
13104  // Break the for and re-start to look more edges to
13105  // the left or right
13106  break;
13107 
13108  } // if (node_added)
13109 
13110  } // if (!edge_done[edge])
13111  } // for (iiedge < nedges)
13112 
13113  } // while(node_added && (nsorted_edges < nedges)
13114  // && !current_polyline_has_connections_at_both_ends)
13115 
13116  // ------------------------------------------------------------
13117  // If the sorted nodes of the shared polyline create a loop
13118  // it is necessary to break it by creating as many
13119  // polylines as required
13120 
13121  // Change the list to a vector representation of the
13122  // boundary elements and the face indexes
13123 
13124  // Get the number of boundary elements
13125  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
13126 
13127  // Storage for the boundary elements and face indexes
13128  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
13129  Vector<int> tmp_face_idx_ele(n_bnd_ele);
13130  // Helper counter
13131  unsigned help_counter = 0;
13132  // Fill the data structures
13133  for (std::list<FiniteElement*>::iterator it_bnd_ele =
13134  tmp_boundary_element_pt.begin();
13135  it_bnd_ele != tmp_boundary_element_pt.end();
13136  it_bnd_ele++)
13137  {
13138  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
13139  }
13140 
13141  // Restart counter
13142  help_counter = 0;
13143  for (std::list<int>::iterator it_face_idx =
13144  tmp_face_index_element.begin();
13145  it_face_idx != tmp_face_index_element.end();
13146  it_face_idx++)
13147  {
13148  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
13149  }
13150 
13151  // Store the nodes for the new shared polylines without
13152  // loops
13153  Vector<std::list<Node*>> final_sorted_nodes_pt;
13154  // Store the boundary elements of the shared polyline
13155  // without loops
13156  Vector<Vector<FiniteElement*>> final_boundary_element_pt;
13157  // Face indexes of the boundary elements without loops
13158  Vector<Vector<int>> final_face_index_element;
13159  // Connection flags (to the left) of the shared boundaries
13160  // without loops
13161  Vector<int> final_bound_id_connection_to_the_left;
13162  // Connection flags (to the right) of the shared boundaries
13163  // without loops
13164  Vector<int> final_bound_id_connection_to_the_right;
13165 
13166  // Break any possible loop created by the shared polyline
13167  break_loops_on_shared_polyline_helper(
13168  shared_boundary_id_start,
13169  sorted_nodes,
13170  tmp_bnd_ele_pt,
13171  tmp_face_idx_ele,
13172  bound_id_connection_to_the_left,
13173  bound_id_connection_to_the_right,
13174  final_sorted_nodes_pt,
13175  final_boundary_element_pt,
13176  final_face_index_element,
13177  final_bound_id_connection_to_the_left,
13178  final_bound_id_connection_to_the_right);
13179 
13180  // Get the number of final sorted nodes
13181  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
13182 
13183  // Loop over the list of final sorted nodes
13184  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13185  {
13186  // --------------------------------------------------------
13187  // Associate the list of sorted nodes with the boundary id
13188  // of the shared boundary that is going to be crated
13189  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13190  final_sorted_nodes_pt[i];
13191 
13192  // Create the shared polyline and fill the data
13193  // structured associated to it
13194  create_shared_polyline(my_rank,
13195  shared_boundary_id_start,
13196  iproc,
13197  jproc,
13198  final_sorted_nodes_pt[i],
13199  root_edge_bound_id,
13200  final_boundary_element_pt[i],
13201  final_face_index_element[i],
13202  unsorted_polylines_pt,
13203  final_bound_id_connection_to_the_left[i],
13204  final_bound_id_connection_to_the_right[i]);
13205 
13206  // Increase the register for the number of created shared
13207  // polylines
13208  npolylines_counter++;
13209 
13210  // Increase the boundary id (the one that will be used by
13211  // the next shared boundary)
13212  shared_boundary_id_start++;
13213 
13214  } // for (i < n_final_sorted_nodes)
13215 
13216  } // while(nsorted_edges < nedges);
13217 
13218  } // for (jproc < nproc)
13219 
13220  // We already have all the shared polylines (shared boundaries)
13221  // of processor iproc with processor jproc. Now we sort them so
13222  // that they be contiguous and can create polygons.
13223 
13224  // If there are polylines to be sorted then sort them
13225  if (unsorted_polylines_pt[iproc].size() > 0)
13226  {
13227  // Now that we have all the new unsorted polylines on "iproc"
13228  // processor it is time to sort them so they be all contiguous
13229  sort_polylines_helper(unsorted_polylines_pt[iproc],
13230  output_polylines_pt[iproc]);
13231  }
13232 
13233 #ifdef PARANOID
13234  const unsigned nunsorted_polylines_iproc =
13235  unsorted_polylines_pt[iproc].size();
13236 
13237  // Verify that all the polylines have been sorted
13238  unsigned tmp_ntotal_polylines = 0;
13239  // Count the total number of sorted polylines
13240  for (unsigned ii = 0; ii < output_polylines_pt[iproc].size(); ii++)
13241  {
13242  tmp_ntotal_polylines += output_polylines_pt[iproc][ii].size();
13243  }
13244  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13245  {
13246  std::ostringstream error_message;
13247  error_message << " The total number of unsorted polylines ("
13248  << nunsorted_polylines_iproc
13249  << ") in common with\nprocessor (" << iproc
13250  << ") is different from the total number of sorted "
13251  << "polylines (" << tmp_ntotal_polylines
13252  << ") with\nthe same "
13253  << "proessor\n";
13254  throw OomphLibError(error_message.str(),
13255  OOMPH_CURRENT_FUNCTION,
13256  OOMPH_EXCEPTION_LOCATION);
13257  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13258 #endif
13259 
13260  } // for (iproc < nproc)
13261 
13262  // Establish the last used boundary id
13263  this->Final_shared_boundary_id = shared_boundary_id_start;
13264  }
13265 
13266  // ======================================================================
13267  // Break any possible loop created by the sorted list of nodes
13268  // that is used to create a new shared polyline
13269  // ======================================================================
13270  template<class ELEMENT>
13272  const unsigned& initial_shd_bnd_id,
13273  std::list<Node*>& input_nodes,
13274  Vector<FiniteElement*>& input_boundary_element_pt,
13275  Vector<int>& input_face_index_element,
13276  const int& input_connect_to_the_left,
13277  const int& input_connect_to_the_right,
13278  Vector<std::list<Node*>>& output_sorted_nodes_pt,
13279  Vector<Vector<FiniteElement*>>& output_boundary_element_pt,
13280  Vector<Vector<int>>& output_face_index_element,
13281  Vector<int>& output_connect_to_the_left,
13282  Vector<int>& output_connect_to_the_right)
13283  {
13284  // Get the left and right node of the current list of sorted nodes
13285  Node* left_node_pt = input_nodes.front();
13286  Node* right_node_pt = input_nodes.back();
13287 
13288  // Temporary storage for list of nodes, boundary elements and face
13289  // element's indexes
13290  Vector<std::list<Node*>> tmp_sub_nodes;
13291  Vector<Vector<FiniteElement*>> tmp_sub_bnd_ele_pt;
13292  Vector<Vector<int>> tmp_sub_face_idx_ele;
13293 
13294  // Iterator for the list of input nodes
13295  std::list<Node*>::iterator it = input_nodes.begin();
13296 
13297  // Counter
13298  unsigned counter = 0;
13299 
13300  // Loop while not all nodes have been done
13301  while (it != input_nodes.end())
13302  {
13303  // Check if the current node is the final one
13304  it++;
13305  // Is the current node the final node?
13306  if (it == input_nodes.end())
13307  {
13308  // Break, add no more nodes
13309  break;
13310  }
13311  else
13312  {
13313  // Restore the iterator
13314  it--;
13315  }
13316 
13317  // Get a list of nonrepeated nodes
13318  std::list<Node*> sub_nodes;
13319  // The temporary vector of boundary elements associated with the
13320  // nodes
13321  Vector<FiniteElement*> sub_bnd_ele_pt;
13322  // The temporary vector of face indexes associated with the
13323  // boundary elements
13324  Vector<int> sub_face_idx_ele;
13325 
13326  // Add the current node to the list
13327  sub_nodes.push_back(*it);
13328 
13329  // Add nodes until found a repeated node (the left or right
13330  // node) or until reaching the end of the list of nodes
13331  do
13332  {
13333  // Go to the next node
13334  ++it;
13335 
13336  // Add the new node
13337  sub_nodes.push_back((*it));
13338 
13339  // Add the boundary elements
13340  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13341  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter + 1]);
13342 
13343  // Add the face indexes
13344  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13345  sub_face_idx_ele.push_back(input_face_index_element[counter + 1]);
13346 
13347  // Increase the counter
13348  counter += 2;
13349 
13350  // Continue adding until reaching a repeated node or the end
13351  // of the list of nodes
13352  } while ((*it) != left_node_pt && (*it) != right_node_pt &&
13353  it != input_nodes.end());
13354 
13355  // Add the sub-set of nodes to the temporary storage
13356  tmp_sub_nodes.push_back(sub_nodes);
13357  // Add the face elements to the temporary storage
13358  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13359  // Add the face indexes to the temporary storage
13360  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13361 
13362  } // while((*it) != input_nodes.end())
13363 
13364  // --------------------------------------------------
13365  // Now create as many shared boundaries as required
13366 
13367  // Get the number of sub-list of nodes created
13368  const unsigned n_sub_list = tmp_sub_nodes.size();
13369 
13370 #ifdef PARANOID
13371  if (n_sub_list > 3)
13372  {
13373  std::stringstream error_message;
13374  error_message
13375  << "The number of sub-list of nodes created from the shared\n"
13376  << "polyline with loops was (" << n_sub_list << ").\n"
13377  << "We can only handle up to three sub-list of nodes\n";
13378  throw OomphLibError(
13379  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
13380  }
13381 #endif
13382 
13383  // If there is only one list it may be because there are no loops or
13384  // there is only one loop (a circle)
13385  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13386  {
13387  // There are no loops, return just after filling the data
13388  // structures
13389 
13390  // This is the base case used most of the times
13391 
13392  // Set the vector of lists of nodes
13393  output_sorted_nodes_pt = tmp_sub_nodes;
13394  // Set the vector of boundary elements
13395  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13396  // Set the vector of face indexes
13397  output_face_index_element = tmp_sub_face_idx_ele;
13398 
13399  // Set the connection flags, change them by the proper connection
13400  // flag
13401 
13402 #ifdef PARANOID
13403  if (input_connect_to_the_left == -2)
13404  {
13405  std::stringstream error_message;
13406  error_message
13407  << "The connection flag to the left (" << input_connect_to_the_left
13408  << ") indicates a connection\n"
13409  << "with the same polyline.\n However, only one sub-polyline was "
13410  << "found and no loop\nwas identified\n\n";
13411  throw OomphLibError(error_message.str(),
13412  OOMPH_CURRENT_FUNCTION,
13413  OOMPH_EXCEPTION_LOCATION);
13414  }
13415 #endif
13416 
13417  // The left connection flag
13418  if (input_connect_to_the_left == -3)
13419  {
13420  output_connect_to_the_left.push_back(-1);
13421  }
13422  else
13423  {
13424  output_connect_to_the_left.push_back(input_connect_to_the_left);
13425  }
13426 
13427 #ifdef PARANOID
13428  if (input_connect_to_the_right == -2)
13429  {
13430  std::stringstream error_message;
13431  error_message
13432  << "The connection flag to the right (" << input_connect_to_the_right
13433  << ") indicates a connection\n"
13434  << "with the same polyline.\n However, only one sub-polyline was "
13435  << "found and no loop\nwas identified\n\n";
13436  throw OomphLibError(
13437  error_message.str(),
13438  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13439  OOMPH_EXCEPTION_LOCATION);
13440  }
13441 #endif
13442 
13443  // The right connection flag
13444  if (input_connect_to_the_right == -3)
13445  {
13446  output_connect_to_the_right.push_back(-1);
13447  }
13448  else
13449  {
13450  output_connect_to_the_right.push_back(input_connect_to_the_right);
13451  }
13452 
13453  // Return inmediately
13454  return;
13455  }
13456 
13457  // The temporary storage for the shared boundary id
13458  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13459 
13460  // -----------------------------------------------------------------
13461  // Check all the sub-list of nodes and create two shared boundaries
13462  // from those that make a loop (circle)
13463 
13464  // -----------------------------------------------------------
13465  // Get the left and right node of the first sub-list of nodes
13466  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13467  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13468 
13469  // Check if the sub-list of nodes creates a loop (circle)
13470  if (left_sub_node_pt == right_sub_node_pt)
13471  {
13472  // We need to create two shared polylines and therefore increase
13473  // the shared boundary id by two
13474 
13475  // The first and second half of nodes
13476  std::list<Node*> first_half_node_pt;
13477  std::list<Node*> second_half_node_pt;
13478  // The first and second half of boundary elements
13479  Vector<FiniteElement*> first_half_ele_pt;
13480  Vector<FiniteElement*> second_half_ele_pt;
13481  // The first and second half of face indexes
13482  Vector<int> first_half_face_idx;
13483  Vector<int> second_half_face_idx;
13484 
13485  // Get the number of sub-nodes in the sub-list of nodes
13486  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13487 
13488  // The number of sub-nodes for the first half of the shared
13489  // boundary
13490  const unsigned n_sub_nodes_half =
13491  static_cast<unsigned>(n_sub_nodes / 2.0);
13492 
13493  // Copy as many sub-nodes for the first half of the sub-polyline
13494 
13495  // Iterator to loop over the nodes
13496  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13497 
13498  // Add the first node
13499  first_half_node_pt.push_back(*it_sub);
13500 
13501  // Skip the first node
13502  it_sub++;
13503 
13504  // Counter
13505  unsigned counter_nodes = 0;
13506  unsigned counter2 = 0;
13507 
13508  // Loop to copy the nodes
13509  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
13510  {
13511  // Add the sub-node to the first half
13512  first_half_node_pt.push_back(*it_sub);
13513 
13514  // Add the boundary elements of the first half
13515  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13516  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2 + 1]);
13517  // Add the face indexes of the first half
13518  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13519  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2 + 1]);
13520 
13521  // Increase the counter of added nodes
13522  counter_nodes++;
13523 
13524  // Increase the other counter
13525  counter2 += 2;
13526 
13527  if (counter_nodes == n_sub_nodes_half)
13528  {
13529  // Stop adding to the first half of nodes
13530  break;
13531  }
13532 
13533  } // Copy the first half of nodes
13534 
13535  // The second half
13536 
13537  // Add the first node of the second half
13538  second_half_node_pt.push_back(*it_sub);
13539 
13540  // Skip the first node of the second half
13541  it_sub++;
13542 
13543  // Loop to copy the nodes
13544  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
13545  {
13546  // Add the sub-node to the first half
13547  second_half_node_pt.push_back(*it_sub);
13548 
13549  // Add the boundary elements of the first half
13550  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13551  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2 + 1]);
13552  // Add the face indexes of the first half
13553  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13554  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2 + 1]);
13555 
13556  // Increase the other counter
13557  counter2 += 2;
13558 
13559  } // Copy the second half of nodes
13560 
13561  // Add the sub-list of nodes to the vector of lists of nodes
13562  output_sorted_nodes_pt.push_back(first_half_node_pt);
13563  output_sorted_nodes_pt.push_back(second_half_node_pt);
13564  // Add the sub-vector of elements to the vector of boundary
13565  // elements
13566  output_boundary_element_pt.push_back(first_half_ele_pt);
13567  output_boundary_element_pt.push_back(second_half_ele_pt);
13568  // Add the sub-vector of face indexes to the vector of face
13569  // indexes
13570  output_face_index_element.push_back(first_half_face_idx);
13571  output_face_index_element.push_back(second_half_face_idx);
13572 
13573  // Set the connection flags, change them by the proper connection
13574  // flag
13575 
13576  // ----------------------------------------------------------------
13577  // Connections flags for the first half
13578 
13579  // The left connection flag
13580 
13581  // Connected with nothing but required to stop adding nodes
13582  if (input_connect_to_the_left == -3)
13583  {
13584  // Set connected to nothing
13585  output_connect_to_the_left.push_back(-1);
13586  }
13587  // Connected with itself
13588  else if (input_connect_to_the_left == -2)
13589  {
13590  // Set connected to nothing, this is the base node
13591  output_connect_to_the_left.push_back(-1);
13592  }
13593  else
13594  {
13595  // Any other value keep it
13596  output_connect_to_the_left.push_back(input_connect_to_the_left);
13597  }
13598 
13599  // The right connection flag
13600 
13601  // Set connected to nothing, this is the base node
13602  output_connect_to_the_right.push_back(-1);
13603 
13604  // Increase the shared boundary id
13605  tmp_shd_bnd_id++;
13606 
13607  // ----------------------------------------------------------------
13608  // Connections flags for the second half
13609 
13610  // The left connection flag
13611 
13612  // Set connected to the previous boundary
13613  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13614 
13615  // The right connection flag
13616 
13617  // Are we in the last sub-list of nodes, if that is the case we
13618  // need to respect the flag assigned to the right
13619  if (n_sub_list == 1)
13620  {
13621  if (input_connect_to_the_right == -3)
13622  {
13623  // Set connected to the previous shared boundary id
13624  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13625  }
13626  else if (input_connect_to_the_right == -2)
13627  {
13628  // Set connected to the previous shared boundary id
13629  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13630  }
13631  else if (input_connect_to_the_right == -1)
13632  {
13633  // Set connected to the previous shared boundary id
13634  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13635  }
13636  else
13637  {
13638  // Any other value keep it
13639  output_connect_to_the_right.push_back(input_connect_to_the_right);
13640  }
13641  } // if (n_sub_list == 1)
13642  else
13643  {
13644  // Set connected to the previous shared boundary id
13645  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13646  }
13647 
13648  // Increase the shared boundary id
13649  tmp_shd_bnd_id++;
13650 
13651  } // if (left_sub_node_pt == right_sub_node_pt)
13652  else
13653  {
13654  // No need to create two boundaries, create only one with the
13655  // sub-list of nodes
13656 
13657  // Add the sub-list of nodes to the vector of lists of nodes
13658  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13659  // Add the sub-vector of elements to the vector of boundary
13660  // elements
13661  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13662  // Add the sub-vector of face indexes to the vector of face
13663  // indexes
13664  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13665 
13666  // Set the connection flags, change them by the proper connection
13667  // flag
13668 
13669  // The left connection flag
13670 
13671  // Connected with nothing but required to stop adding nodes
13672  if (input_connect_to_the_left == -3)
13673  {
13674  // Set to connected to nothing
13675  output_connect_to_the_left.push_back(-1);
13676  }
13677  // Connected with itself
13678  else if (input_connect_to_the_left == -2)
13679  {
13680  // Set connected to the next shared polyline id
13681  output_connect_to_the_left.push_back(tmp_shd_bnd_id + 1);
13682  }
13683  else
13684  {
13685  // Any other value keep it
13686  output_connect_to_the_left.push_back(input_connect_to_the_left);
13687  }
13688 
13689  // The right connection flag
13690 
13691  // Set connected to the next shared polyline id
13692  output_connect_to_the_right.push_back(tmp_shd_bnd_id + 1);
13693 
13694  // Increase the shared boundary id by one
13695  tmp_shd_bnd_id++;
13696 
13697  } // else if (left_sub_node_pt == right_sub_node_pt)
13698 
13699  // At least two sub-list of nodes were created
13700  if (n_sub_list > 1)
13701  {
13702  // ------------------------------------------------------------
13703  // Get the left and right node of the second sub-list of nodes
13704  left_sub_node_pt = tmp_sub_nodes[1].front();
13705  right_sub_node_pt = tmp_sub_nodes[1].back();
13706 
13707  // Check if the sub-list of nodes creates a loop (circle)
13708  if (left_sub_node_pt == right_sub_node_pt)
13709  {
13710  // We need to create two shared polylines and therefore increase
13711  // the shared boundary id by two
13712 
13713  // The first and second half of nodes
13714  std::list<Node*> first_half_node_pt;
13715  std::list<Node*> second_half_node_pt;
13716  // The first and second half of boundary elements
13717  Vector<FiniteElement*> first_half_ele_pt;
13718  Vector<FiniteElement*> second_half_ele_pt;
13719  // The first and second half of face indexes
13720  Vector<int> first_half_face_idx;
13721  Vector<int> second_half_face_idx;
13722 
13723  // Get the number of sub-nodes in the sub-list of nodes
13724  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13725 
13726  // The number of sub-nodes for the first half of the shared
13727  // boundary
13728  const unsigned n_sub_nodes_half =
13729  static_cast<unsigned>(n_sub_nodes / 2.0);
13730 
13731  // Copy as many sub-nodes for the first half of the sub-polyline
13732 
13733  // Iterator to loop over the nodes
13734  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13735 
13736  // Add the first node
13737  first_half_node_pt.push_back(*it_sub);
13738 
13739  // Skip the first node
13740  it_sub++;
13741 
13742  // Counter
13743  unsigned counter_nodes = 0;
13744  unsigned counter2 = 0;
13745 
13746  // Loop to copy the nodes
13747  for (; it_sub != tmp_sub_nodes[1].end(); it_sub++)
13748  {
13749  // Add the sub-node to the first half
13750  first_half_node_pt.push_back(*it_sub);
13751  // Add the boundary elements of the first half
13752  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13753  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2 + 1]);
13754  // Add the face indexes of the first half
13755  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13756  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2 + 1]);
13757 
13758  // Increase the counter of added nodes
13759  counter_nodes++;
13760 
13761  // Increase the other counter
13762  counter2 += 2;
13763 
13764  if (counter_nodes == n_sub_nodes_half)
13765  {
13766  // Stop adding to the first half of nodes
13767  break;
13768  }
13769 
13770  } // Copy the first half of nodes
13771 
13772  // The second half
13773 
13774  // Add the first node of the second half
13775  second_half_node_pt.push_back(*it_sub);
13776 
13777  // Skip the first node of the second half
13778  it_sub++;
13779 
13780  // Loop to copy the nodes
13781  for (; it_sub != tmp_sub_nodes[1].end(); it_sub++)
13782  {
13783  // Add the sub-node to the first half
13784  second_half_node_pt.push_back(*it_sub);
13785  // Add the boundary elements of the first half
13786  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13787  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2 + 1]);
13788  // Add the face indexes of the first half
13789  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13790  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2 + 1]);
13791 
13792  // Increase the other counter
13793  counter2 += 2;
13794 
13795  } // Copy the second half of nodes
13796 
13797  // Add the sub-list of nodes to the vector of lists of nodes
13798  output_sorted_nodes_pt.push_back(first_half_node_pt);
13799  output_sorted_nodes_pt.push_back(second_half_node_pt);
13800  // Add the sub-vector of elements to the vector of boundary
13801  // elements
13802  output_boundary_element_pt.push_back(first_half_ele_pt);
13803  output_boundary_element_pt.push_back(second_half_ele_pt);
13804  // Add the sub-vector of face indexes to the vector of face
13805  // indexes
13806  output_face_index_element.push_back(first_half_face_idx);
13807  output_face_index_element.push_back(second_half_face_idx);
13808 
13809  // Set the connection flags, change them by the proper
13810  // connection flag
13811 
13812  // --------------------------------------
13813  // Connections flags for the first half
13814 
13815  // The left connection flag
13816 
13817  // Connected to the previous boundary
13818  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13819 
13820  // The right connection flag
13821 
13822  // Set connected to nothing, this is the base node
13823  output_connect_to_the_right.push_back(-1);
13824 
13825  // Increase the shared boundary id
13826  tmp_shd_bnd_id++;
13827 
13828  // --------------------------------------
13829  // Connections flags for the second half
13830 
13831  // The left connection flag
13832 
13833  // Set connected to the previous boundary
13834  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13835 
13836  // The right connection flag
13837 
13838  // Are we in the last sub-list of nodes, if that is the case we
13839  // need to respect the flag assigned to the right
13840  if (n_sub_list == 2)
13841  {
13842  // Connected with nothing
13843  if (input_connect_to_the_right == -1)
13844  {
13845  // Set connected to the previous shared boundary
13846  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13847  }
13848  // Connected with the same boundary
13849  else if (input_connect_to_the_right == -2)
13850  {
13851  // Set connected to the previous shared boundary
13852  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13853  }
13854  // Connetted with nothing but stop adding nodes
13855  else if (input_connect_to_the_right == -3)
13856  {
13857  // Set connected to the previous shared boundary
13858  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
13859  }
13860  else
13861  {
13862  // Any other value keep it
13863  output_connect_to_the_right.push_back(input_connect_to_the_right);
13864  }
13865 
13866  // Increase the shared boundary id
13867  tmp_shd_bnd_id++;
13868 
13869  } // if (n_sub_list == 2)
13870 #ifdef PARANOID
13871  else
13872  {
13873  std::stringstream error_message;
13874  error_message
13875  << "The second sub-list of nodes creates a loop but this is not\n"
13876  << "the last list of sub-nodes.\n"
13877  << "This configuration is not supported\n";
13878  throw OomphLibError(
13879  error_message.str(),
13880  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13881  OOMPH_EXCEPTION_LOCATION);
13882  }
13883 #endif
13884 
13885  } // if (left_sub_node_pt == right_sub_node_pt)
13886  else
13887  {
13888  // No need to create two boundaries, create only one with the
13889  // sub-list of nodes
13890 
13891  // Add the sub-list of nodes to the vector of lists of nodes
13892  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13893  // Add the sub-vector of elements to the vector of boundary
13894  // elements
13895  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13896  // Add the sub-vector of face indexes to the vector of face
13897  // indexes
13898  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13899 
13900  // Set the connection flags, change them by the proper connection
13901  // flag
13902 
13903  // The left connection flag
13904 
13905  // Set connected to the previous shared boundary id
13906  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
13907 
13908  // The right connection flag
13909 
13910  // Are we in the last sub-list of nodes, if that is the case we
13911  // need to respect the flag assigned to the right
13912  if (n_sub_list == 2)
13913  {
13914  // Connected with nothing but required to stop adding nodes
13915  if (input_connect_to_the_right == -3)
13916  {
13917  // Set to connected to nothing
13918  output_connect_to_the_right.push_back(-1);
13919  }
13920 #ifdef PARANOID
13921  // Connected with itself
13922  else if (input_connect_to_the_right == -2)
13923  {
13924  std::stringstream error_message;
13925  error_message
13926  << "The connection flag to the right ("
13927  << input_connect_to_the_right << ") indicates a connection\n"
13928  << "with the same polyline.\n However, the second sub-list of\n"
13929  << "nodes was found not making a loop so no connection with\n"
13930  << "itself should be marked\n\n";
13931  throw OomphLibError(
13932  error_message.str(),
13933  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13934  OOMPH_EXCEPTION_LOCATION);
13935  }
13936 #endif
13937  else
13938  {
13939  // Any other value keep it
13940  output_connect_to_the_right.push_back(input_connect_to_the_right);
13941  }
13942  } // if (n_sub_list == 2)
13943  else
13944  {
13945  // Set connected to the next shared boundary id
13946  output_connect_to_the_right.push_back(tmp_shd_bnd_id + 1);
13947  } // else if (n_sub_list == 2)
13948 
13949  // Increase the shared boundary id by one
13950  tmp_shd_bnd_id++;
13951 
13952  } // if (left_sub_node_pt == right_sub_node_pt)
13953 
13954  } // if (n_sub_list > 1)
13955 
13956  // Three sub-list of nodes were created
13957  if (n_sub_list > 2)
13958  {
13959  // ------------------------------------------------------------
13960  // Get the left and right node of the third sub-list of nodes
13961  left_sub_node_pt = tmp_sub_nodes[2].front();
13962  right_sub_node_pt = tmp_sub_nodes[2].back();
13963 
13964  // Check if the sub-list of nodes creates a loop (circle)
13965  if (left_sub_node_pt == right_sub_node_pt)
13966  {
13967  // We need to create two shared polylines and therefore increase
13968  // the shared boundary id by two
13969 
13970  // The first and second half of nodes
13971  std::list<Node*> first_half_node_pt;
13972  std::list<Node*> second_half_node_pt;
13973  // The first and second half of boundary elements
13974  Vector<FiniteElement*> first_half_ele_pt;
13975  Vector<FiniteElement*> second_half_ele_pt;
13976  // The first and second half of face indexes
13977  Vector<int> first_half_face_idx;
13978  Vector<int> second_half_face_idx;
13979 
13980  // Get the number of sub-nodes in the sub-list of nodes
13981  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13982 
13983  // The number of sub-nodes for the first half of the shared
13984  // boundary
13985  const unsigned n_sub_nodes_half =
13986  static_cast<unsigned>(n_sub_nodes / 2.0);
13987 
13988  // Copy as many sub-nodes for the first half of the sub-polyline
13989 
13990  // Iterator to loop over the nodes
13991  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13992 
13993  // Add the first node
13994  first_half_node_pt.push_back(*it_sub);
13995 
13996  // Skip the first node
13997  it_sub++;
13998 
13999  // Counter
14000  unsigned counter_nodes = 0;
14001  unsigned counter2 = 0;
14002 
14003  // Loop to copy the nodes
14004  for (; it_sub != tmp_sub_nodes[2].end(); it_sub++)
14005  {
14006  // Add the sub-node to the first half
14007  first_half_node_pt.push_back(*it_sub);
14008  // Add the boundary elements of the first half
14009  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
14010  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2 + 1]);
14011  // Add the face indexes of the first half
14012  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
14013  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2 + 1]);
14014 
14015  // Increase the counter of added nodes
14016  counter_nodes++;
14017 
14018  // Increase the other counter
14019  counter2 += 2;
14020 
14021  if (counter_nodes == n_sub_nodes_half)
14022  {
14023  // Stop adding to the first half of nodes
14024  break;
14025  }
14026 
14027  } // Copy the first half of nodes
14028 
14029  // The second half
14030 
14031  // Add the first node of the second half
14032  second_half_node_pt.push_back(*it_sub);
14033 
14034  // Skip the first node of the second half
14035  it_sub++;
14036 
14037  // Loop to copy the nodes
14038  for (; it_sub != tmp_sub_nodes[2].end(); it_sub++)
14039  {
14040  // Add the sub-node to the first half
14041  second_half_node_pt.push_back(*it_sub);
14042  // Add the boundary elements of the first half
14043  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
14044  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2 + 1]);
14045  // Add the face indexes of the first half
14046  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
14047  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2 + 1]);
14048 
14049  // Increase the other counter
14050  counter2 += 2;
14051 
14052  } // Copy the second half of nodes
14053 
14054  // Add the sub-list of nodes to the vector of lists of nodes
14055  output_sorted_nodes_pt.push_back(first_half_node_pt);
14056  output_sorted_nodes_pt.push_back(second_half_node_pt);
14057  // Add the sub-vector of elements to the vector of boundary
14058  // elements
14059  output_boundary_element_pt.push_back(first_half_ele_pt);
14060  output_boundary_element_pt.push_back(second_half_ele_pt);
14061  // Add the sub-vector of face indexes to the vector of face
14062  // indexes
14063  output_face_index_element.push_back(first_half_face_idx);
14064  output_face_index_element.push_back(second_half_face_idx);
14065 
14066  // --------------------------------------
14067  // Connections flags for the first half
14068 
14069  // The left connection flag
14070 
14071  // Connected to the previous shared boundary
14072  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14073 
14074  // The right connection flag
14075 
14076  // Set connected to nothing, this is the base node
14077  output_connect_to_the_right.push_back(-1);
14078 
14079  // Increase the shared boundary id
14080  tmp_shd_bnd_id++;
14081 
14082  // --------------------------------------
14083  // Connections flags for the second half
14084 
14085  // The left connection flag
14086 
14087  // Set connected to the previous boundary
14088  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14089 
14090  // The right connection flag
14091 
14092  if (input_connect_to_the_right == -3)
14093  {
14094  // Set connected to the previous shared boundary id
14095  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14096  }
14097  else if (input_connect_to_the_right == -2)
14098  {
14099  // Set connected to the previous shared boundary id
14100  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14101  }
14102  else if (input_connect_to_the_right == -1)
14103  {
14104  // Set connected to the previous shared boundary id
14105  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14106  }
14107  else
14108  {
14109  // Any other value keep it
14110  output_connect_to_the_right.push_back(input_connect_to_the_right);
14111  }
14112 
14113  // Increase the shared boundary id
14114  tmp_shd_bnd_id++;
14115 
14116  } // if (left_sub_node_pt == right_sub_node_pt)
14117  else
14118  {
14119  // No need to create two boundaries, create only one with the
14120  // sub-list of nodes
14121 
14122  // Add the sub-list of nodes to the vector of lists of nodes
14123  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
14124  // Add the sub-vector of elements to the vector of boundary
14125  // elements
14126  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
14127  // Add the sub-vector of face indexes to the vector of face
14128  // indexes
14129  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
14130 
14131  // Set the connection flags, change them by the proper
14132  // connection flag
14133 
14134  // The left connection flag
14135 
14136  // Set connected to the previous shared boundary id
14137  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14138 
14139  // The right connection flag
14140 
14141  // Connected with nothing but required to stop adding nodes
14142  if (input_connect_to_the_right == -3)
14143  {
14144  std::stringstream error_message;
14145  error_message
14146  << "The connection flag to the right ("
14147  << input_connect_to_the_right << ") indicates 'no connection and\n"
14148  << "stop adding nodes'.\n However, the thrid sub-list of\n"
14149  << "nodes must have a connection to the right with the same\n"
14150  << "shared polyline or with any other polyline\n\n";
14151  throw OomphLibError(
14152  error_message.str(),
14153  "TriangleMesh::break_loops_on_shared_polyline_helper()",
14154  OOMPH_EXCEPTION_LOCATION);
14155  }
14156  else if (input_connect_to_the_right == -1)
14157  {
14158  std::stringstream error_message;
14159  error_message
14160  << "The connection flag to the right ("
14161  << input_connect_to_the_right << ") indicates 'no connection.\n"
14162  << "However, the thrid sub-list of nodes must have a connection\n"
14163  << "to the right with the same shared polyline or with any other\n"
14164  << "polyline\n\n";
14165  throw OomphLibError(
14166  error_message.str(),
14167  "TriangleMesh::break_loops_on_shared_polyline_helper()",
14168  OOMPH_EXCEPTION_LOCATION);
14169  }
14170  // Connected with itself
14171  else if (input_connect_to_the_right == -2)
14172  {
14173  // Set connected to the previous shared boundary id
14174  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14175  }
14176  else
14177  {
14178  // Any other value keep it
14179  output_connect_to_the_right.push_back(input_connect_to_the_right);
14180  }
14181 
14182  // Increase the shared boundary id by one
14183  tmp_shd_bnd_id++;
14184 
14185  } // if (left_sub_node_pt == right_sub_node_pt)
14186 
14187  } // if (n_sub_list > 2)
14188  }
14189 
14190  // ======================================================================
14191  // Break any possible loop created by the sorted list of nodes
14192  // that is used to create a new shared polyline
14193  // ======================================================================
14194  template<class ELEMENT>
14197  const unsigned& initial_shd_bnd_id,
14198  std::list<Node*>& input_nodes,
14199  Vector<FiniteElement*>& input_boundary_element_pt,
14200  Vector<FiniteElement*>& input_boundary_face_element_pt,
14201  Vector<int>& input_face_index_element,
14202  const int& input_connect_to_the_left,
14203  const int& input_connect_to_the_right,
14204  Vector<std::list<Node*>>& output_sorted_nodes_pt,
14205  Vector<Vector<FiniteElement*>>& output_boundary_element_pt,
14206  Vector<Vector<FiniteElement*>>& output_boundary_face_element_pt,
14207  Vector<Vector<int>>& output_face_index_element,
14208  Vector<int>& output_connect_to_the_left,
14209  Vector<int>& output_connect_to_the_right)
14210  {
14211  // Get the left and right node of the current list of sorted nodes
14212  Node* left_node_pt = input_nodes.front();
14213  Node* right_node_pt = input_nodes.back();
14214 
14215  // Temporary storage for list of nodes, boundary elements, boundary
14216  // face elements and face element's indexes
14217  Vector<std::list<Node*>> tmp_sub_nodes;
14218  Vector<Vector<FiniteElement*>> tmp_sub_bnd_ele_pt;
14219  Vector<Vector<FiniteElement*>> tmp_sub_bnd_face_ele_pt;
14220  Vector<Vector<int>> tmp_sub_face_idx_ele;
14221 
14222  // Iterator for the list of input nodes
14223  std::list<Node*>::iterator it = input_nodes.begin();
14224 
14225  // Counter
14226  unsigned counter = 0;
14227 
14228  // Loop while not all nodes have been done
14229  while (it != input_nodes.end())
14230  {
14231  // Check if the current node is the final one
14232  it++;
14233  // Is the current node the final node?
14234  if (it == input_nodes.end())
14235  {
14236  // Break, add no more nodes
14237  break;
14238  }
14239  else
14240  {
14241  // Restore the iterator
14242  it--;
14243  }
14244 
14245  // Get a list of nonrepeated nodes
14246  std::list<Node*> sub_nodes;
14247  // The temporary vector of boundary elements associated with the
14248  // nodes
14249  Vector<FiniteElement*> sub_bnd_ele_pt;
14250  // The temporary vector of boundary face elements associated with
14251  // the nodes
14252  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14253  // The temporary vector of face indexes associated with the
14254  // boundary elements
14255  Vector<int> sub_face_idx_ele;
14256 
14257  // Add the current node to the list
14258  sub_nodes.push_back(*it);
14259 
14260  // Add nodes until found a repeated node (the left or right
14261  // node) or until reaching the end of the list of nodes
14262  do
14263  {
14264  // Go to the next node
14265  ++it;
14266 
14267  // Add the new node
14268  sub_nodes.push_back((*it));
14269 
14270  // Add the boundary elements
14271  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14272 
14273  // Add the boundary face elements
14274  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14275 
14276  // Add the face indexes
14277  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14278 
14279  // Increase the counter
14280  counter++;
14281 
14282  // Continue adding until reaching a repeated node or the end
14283  // of the list of nodes
14284  } while ((*it) != left_node_pt && (*it) != right_node_pt &&
14285  it != input_nodes.end());
14286 
14287  // Add the sub-set of nodes to the temporary storage
14288  tmp_sub_nodes.push_back(sub_nodes);
14289 
14290  // Add the boundary elements to the temporary storage
14291  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14292  // Add the boundary face elements to the temporary storage
14293  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14294  // Add the face indexes to the temporary storage
14295  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14296 
14297  } // while((*it) != input_nodes.end())
14298 
14299  // --------------------------------------------------
14300  // Now create as many shared boundaries as required
14301 
14302  // Get the number of sub-list of nodes created
14303  const unsigned n_sub_list = tmp_sub_nodes.size();
14304 
14305 #ifdef PARANOID
14306  if (n_sub_list > 1)
14307  {
14308  std::stringstream error_message;
14309  error_message
14310  << "The number of sub-list of nodes created from the shared\n"
14311  << "polyline with loops was (" << n_sub_list << ").\n"
14312  << "We can only handle one list which may still contain loops\n"
14313  << "(or repeated nodes)\n";
14314  throw OomphLibError(
14315  error_message.str(),
14316  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14317  OOMPH_EXCEPTION_LOCATION);
14318  }
14319 #endif
14320 
14321  // If there is only one list it may be because there are no loops or
14322  // there is only one loop (a circle)
14323  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14324  {
14325  // There are no loops, return just after filling the data
14326  // structures
14327 
14328  // This is the base case used most of the times
14329 
14330  // Set the vector of lists of nodes
14331  output_sorted_nodes_pt = tmp_sub_nodes;
14332  // Set the vector of boundary elements
14333  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14334  // Set the vector of boundary face elements
14335  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14336  // Set the vector of face indexes
14337  output_face_index_element = tmp_sub_face_idx_ele;
14338 
14339  // Set the connection flags, change them by the proper connection
14340  // flag
14341 
14342 #ifdef PARANOID
14343  if (input_connect_to_the_left == -2)
14344  {
14345  std::stringstream error_message;
14346  error_message
14347  << "The connection flag to the left (" << input_connect_to_the_left
14348  << ") indicates a connection\n"
14349  << "with the same polyline.\n However, only one sub-polyline was "
14350  << "found and no loops\nwere identified\n\n";
14351  throw OomphLibError(
14352  error_message.str(),
14353  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14354  OOMPH_EXCEPTION_LOCATION);
14355  }
14356 #endif
14357 
14358  // The left connection flag
14359  if (input_connect_to_the_left == -3)
14360  {
14361  output_connect_to_the_left.push_back(-1);
14362  }
14363  else
14364  {
14365  output_connect_to_the_left.push_back(input_connect_to_the_left);
14366  }
14367 
14368 #ifdef PARANOID
14369  if (input_connect_to_the_right == -2)
14370  {
14371  std::stringstream error_message;
14372  error_message
14373  << "The connection flag to the right (" << input_connect_to_the_right
14374  << ") indicates a connection\n"
14375  << "with the same polyline.\n However, only one sub-polyline was "
14376  << "found and no loops\nwere identified\n\n";
14377  throw OomphLibError(
14378  error_message.str(),
14379  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14380  OOMPH_EXCEPTION_LOCATION);
14381  }
14382 #endif
14383 
14384  // The right connection flag
14385  if (input_connect_to_the_right == -3)
14386  {
14387  output_connect_to_the_right.push_back(-1);
14388  }
14389  else
14390  {
14391  output_connect_to_the_right.push_back(input_connect_to_the_right);
14392  }
14393 
14394  // Return immediately
14395  return;
14396  }
14397 
14398  // The temporary storage for the shared boundary id
14399  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14400 
14401  // -----------------------------------------------------------------
14402  // Check all the sub-list of nodes and create two shared boundaries
14403  // from those that make a loop (circle)
14404 
14405  // -----------------------------------------------------------
14406  // Get the left and right node of the first sub-list of nodes
14407  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14408  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14409 
14410  // Check if the sub-list of nodes creates a loop (circle)
14411  if (left_sub_node_pt == right_sub_node_pt)
14412  {
14413  // We need to create two shared polylines and therefore increase
14414  // the shared boundary id by two
14415 
14416  // The first and second half of nodes
14417  std::list<Node*> first_half_node_pt;
14418  std::list<Node*> second_half_node_pt;
14419  // The first and second half of boundary elements
14420  Vector<FiniteElement*> first_half_ele_pt;
14421  Vector<FiniteElement*> second_half_ele_pt;
14422  // The first and second half of boundary face elements
14423  Vector<FiniteElement*> first_half_ele_face_pt;
14424  Vector<FiniteElement*> second_half_ele_face_pt;
14425  // The first and second half of face indexes
14426  Vector<int> first_half_face_idx;
14427  Vector<int> second_half_face_idx;
14428 
14429  // Get the number of sub-nodes in the sub-list of nodes
14430  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14431 
14432  // The number of sub-nodes for the first half of the shared
14433  // boundary
14434  const unsigned n_sub_nodes_half =
14435  static_cast<unsigned>(n_sub_nodes / 2.0);
14436 
14437  // Copy as many sub-nodes for the first half of the sub-polyline
14438 
14439  // Iterator to loop over the nodes
14440  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14441 
14442  // Add the first node
14443  first_half_node_pt.push_back(*it_sub);
14444 
14445  // Skip the first node
14446  it_sub++;
14447 
14448  // Counter
14449  unsigned counter_nodes = 0;
14450  unsigned counter2 = 0;
14451 
14452  // Loop to copy the nodes
14453  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
14454  {
14455  // Add the sub-node to the first half
14456  first_half_node_pt.push_back(*it_sub);
14457 
14458  // Add the boundary elements of the first half
14459  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14460  // Add the boundary face elements of the first half
14461  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14462  // Add the face indexes of the first half
14463  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14464 
14465  // Increase the counter of added nodes
14466  counter_nodes++;
14467 
14468  // Increase the other counter (of the elements/face)
14469  counter2++;
14470 
14471  if (counter_nodes == n_sub_nodes_half)
14472  {
14473  // Stop adding to the first half of nodes
14474  break;
14475  }
14476 
14477  } // Copy the first half of nodes
14478 
14479  // The second half
14480 
14481  // Add the first node of the second half
14482  second_half_node_pt.push_back(*it_sub);
14483 
14484  // Skip the first node of the second half
14485  it_sub++;
14486 
14487  // Loop to copy the nodes
14488  for (; it_sub != tmp_sub_nodes[0].end(); it_sub++)
14489  {
14490  // Add the sub-node to the first half
14491  second_half_node_pt.push_back(*it_sub);
14492 
14493  // Add the boundary elements of the first half
14494  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14495  // Add the boundary face elements of the first half
14496  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14497  // Add the face indexes of the first half
14498  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14499 
14500  // Increase the other counter
14501  counter2++;
14502 
14503  } // Copy the second half of nodes
14504 
14505  // Add the sub-list of nodes to the vector of lists of nodes
14506  output_sorted_nodes_pt.push_back(first_half_node_pt);
14507  output_sorted_nodes_pt.push_back(second_half_node_pt);
14508  // Add the sub-vector of elements to the vector of boundary
14509  // elements
14510  output_boundary_element_pt.push_back(first_half_ele_pt);
14511  output_boundary_element_pt.push_back(second_half_ele_pt);
14512  // Add the sub-vector of face elements to the vector of boundary
14513  // elements
14514  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14515  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14516  // Add the sub-vector of face indexes to the vector of face
14517  // indexes
14518  output_face_index_element.push_back(first_half_face_idx);
14519  output_face_index_element.push_back(second_half_face_idx);
14520 
14521  // Set the connection flags, change them by the proper connection
14522  // flag
14523 
14524  // ----------------------------------------------------------------
14525  // Connections flags for the first half
14526 
14527  // The left connection flag
14528 
14529  // Connected with nothing but required to stop adding nodes
14530  if (input_connect_to_the_left == -3)
14531  {
14532  // Set connected to nothing
14533  output_connect_to_the_left.push_back(-1);
14534  }
14535  // Connected with itself
14536  else if (input_connect_to_the_left == -2)
14537  {
14538  // Set connected to nothing, this is the base node
14539  output_connect_to_the_left.push_back(-1);
14540  }
14541  else
14542  {
14543  // Any other value keep it
14544  output_connect_to_the_left.push_back(input_connect_to_the_left);
14545  }
14546 
14547  // The right connection flag
14548 
14549  // Set connected to nothing, this is the base node
14550  output_connect_to_the_right.push_back(-1);
14551 
14552  // Increase the shared boundary id
14553  tmp_shd_bnd_id++;
14554 
14555  // ----------------------------------------------------------------
14556  // Connections flags for the second half
14557 
14558  // The left connection flag
14559 
14560  // Set connected to the previous boundary
14561  output_connect_to_the_left.push_back(tmp_shd_bnd_id - 1);
14562 
14563  // The right connection flag
14564 
14565  // Are we in the last sub-list of nodes, if that is the case we
14566  // need to respect the flag assigned to the right
14567  if (n_sub_list == 1)
14568  {
14569  if (input_connect_to_the_right == -3)
14570  {
14571  // Set connected to the previous shared boundary id
14572  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14573  }
14574  else if (input_connect_to_the_right == -2)
14575  {
14576  // Set connected to the previous shared boundary id
14577  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14578  }
14579  else if (input_connect_to_the_right == -1)
14580  {
14581  // Set connected to the previous shared boundary id
14582  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14583  }
14584  else
14585  {
14586  // Any other value keep it
14587  output_connect_to_the_right.push_back(input_connect_to_the_right);
14588  }
14589  } // if (n_sub_list == 1)
14590  else
14591  {
14592  // Set connected to the previous shared boundary id
14593  output_connect_to_the_right.push_back(tmp_shd_bnd_id - 1);
14594  }
14595 
14596  // Increase the shared boundary id
14597  tmp_shd_bnd_id++;
14598 
14599  } // if (left_sub_node_pt == right_sub_node_pt)
14600 #ifdef PARANOID
14601  else
14602  {
14603  std::stringstream error_message;
14604  error_message
14605  << "The initial and final node in the current shared polyline are not\n"
14606  << "the same and the number of sublists is (" << n_sub_list << ").\n"
14607  << "We can not handle more than one sublist in the method to break\n"
14608  << "loops at the load balance stage\n\n";
14609  throw OomphLibError(
14610  error_message.str(),
14611  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14612  OOMPH_EXCEPTION_LOCATION);
14613  }
14614 #endif
14615  }
14616 
14617  // ======================================================================
14618  // Create the shared polyline and fill the data structured
14619  // that keep all the information associated with the creationg of the
14620  // shared boundary
14621  // ======================================================================
14622  template<class ELEMENT>
14624  const unsigned& my_rank,
14625  const unsigned& shd_bnd_id,
14626  const unsigned& iproc,
14627  const unsigned& jproc,
14628  std::list<Node*>& sorted_nodes,
14629  const int& root_edge_bnd_id,
14630  Vector<FiniteElement*>& bulk_bnd_ele_pt,
14631  Vector<int>& face_index_ele,
14632  Vector<Vector<TriangleMeshPolyLine*>>& unsorted_polylines_pt,
14633  const int& connect_to_the_left_flag,
14634  const int& connect_to_the_right_flag)
14635  {
14636  // ----------------------------------------------------------------
14637  // Associate the shared boundary with the respective processors
14638  // ----------------------------------------------------------------
14639 
14640  // Setup the global look-up scheme, where all processors know the
14641  // associations of others processors and the shared boundaries they
14642  // created
14643 
14644  // Set up the boundary shared by "iproc" with "jproc" processor
14645  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14646 
14647  // Set up the boundary shared by "jproc" with "iproc" processor
14648  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14649 
14650  // Specify the processors involved on the creation of the shared
14651  // boundary
14652  Vector<unsigned> processors(2);
14653  processors[0] = iproc;
14654  processors[1] = jproc;
14655  Shared_boundary_from_processors[shd_bnd_id] = processors;
14656 
14657  // ----------------------------------------------------------------
14658  // If one of the processor associated with the shared boundary is
14659  // the current processor then it needs to create a polyline from the
14660  // input sorted nodes, other processors can skip this part
14661  if (iproc == my_rank || jproc == my_rank)
14662  {
14663  // ------------------------------------------------------------
14664  // Create a vertices representation from the sorted nodes list
14665  // ------------------------------------------------------------
14666 
14667  // Get the number of nodes on the list
14668  const unsigned n_nodes = sorted_nodes.size();
14669  // The vector to store the vertices (assign space)
14670  Vector<Vector<double>> vertices(n_nodes);
14671 
14672  // Copy the vertices from the nodes
14673  unsigned counter = 0;
14674 
14675  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14676  it != sorted_nodes.end();
14677  it++)
14678  {
14679  vertices[counter].resize(2);
14680  vertices[counter][0] = (*it)->x(0);
14681  vertices[counter][1] = (*it)->x(1);
14682  counter++;
14683  }
14684 
14685  // ---------------------------------------------
14686  // Create the polyline from the input vertices
14687  // ---------------------------------------------
14688  TriangleMeshPolyLine* polyline_pt =
14689  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14690 
14691  // ---------------------------------------------
14692  // Establish the internal boundary information
14693  // ---------------------------------------------
14694 
14695  // Check if the shared boundary is overlapping (or is part) of an
14696  // internal boundary
14697  if (root_edge_bnd_id != -1)
14698  {
14699  // If the shared boundary is part of an internal boundary then
14700  // mark the shared boundary
14701  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14702  static_cast<unsigned>(root_edge_bnd_id);
14703  } // if (root_edge_bnd_id != -1)
14704 
14705  // ---------------------------------------------
14706  // Store the boundary elements and face indexes
14707  // ---------------------------------------------
14708 
14709  // Store the shared boundary elements
14710  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14711 #ifdef PARANOID
14712  // Check that the number of shared boundy elements is the same as
14713  // the number of face indexes
14714  const unsigned n_face_index = face_index_ele.size();
14715  if (n_shared_boundary_elements != n_face_index)
14716  {
14717  std::ostringstream error_message;
14718  error_message
14719  << "The number of shared boundary elements is different from the\n"
14720  << "number of face indexes associated to the shared boundary\n"
14721  << "elements\n"
14722  << "Number of shared boundary elements: ("
14723  << n_shared_boundary_elements << ")\n"
14724  << "Number of face indexes: (" << n_face_index << ")\n\n";
14725  throw OomphLibError(error_message.str(),
14726  "TriangleMesh::create_shared_polyline()",
14727  OOMPH_EXCEPTION_LOCATION);
14728  } // if (n_shared_boundary_elements != n_face_index)
14729 #endif
14730 
14731  // Add the shared boundary elements and their respective face
14732  // indexes to their permanent containers
14733  for (unsigned i = 0; i < n_shared_boundary_elements; i++)
14734  {
14735  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14736  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14737  } // for (i < nshared_boundary_elements)
14738 
14739  // Store the shared boundary nodes
14740  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14741  it != sorted_nodes.end();
14742  it++)
14743  {
14744  add_shared_boundary_node(shd_bnd_id, (*it));
14745  } // for (it != sorted_nodes.end())
14746 
14747  // ----------------------------------------------------------
14748  // Create additional look-up schemes for the shared boundary
14749  // ----------------------------------------------------------
14750 
14751  // Updates bnd_id <---> curve section map
14752  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14753 
14754  // Check the size of the unsorted_polylines_pt structure. This
14755  // will have n_procs = 1 when it was called from the
14756  // create_new_shared_boundaries() methods
14757  const unsigned n_procs = unsorted_polylines_pt.size();
14758  if (n_procs > 1)
14759  {
14760  // Add the new created polyline to the list of unsorted
14761  // polylines
14762  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14763 
14764  // ... do this on both processors involved in the creation of
14765  // the shared boundary
14766  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14767  }
14768  else
14769  {
14770  // Add the new created polyline to the list of unsorted
14771  // polylines
14772  unsorted_polylines_pt[0].push_back(polyline_pt);
14773  }
14774 
14775  // Mark the polyline for deletion (when calling destructor)
14776  this->Free_curve_section_pt.insert(polyline_pt);
14777 
14778  // ----------------------------
14779  // Set connection information
14780  // ----------------------------
14781 
14782  // Check that the flags are correct, no connection or the boundary
14783  // id of the boundary to connect
14784 #ifdef PARANOID
14785  // Is the shared polyline not connected to the left
14786  if (connect_to_the_left_flag < 0)
14787  {
14788  // If not connected then should be specified by -1
14789  if (connect_to_the_left_flag != -1)
14790  {
14791  std::ostringstream error_message;
14792  error_message
14793  << "The only accepted values for the connection flags are:\n"
14794  << "POSITIVE values or -1, any other value is rejected, please\n"
14795  << "check that you previously called the methods to deal with\n"
14796  << "other flag values\n"
14797  << "The current flag value for connection to the left is: ("
14798  << connect_to_the_left_flag << ")\n\n";
14799  throw OomphLibError(error_message.str(),
14800  "TriangleMesh::create_shared_polyline()",
14801  OOMPH_EXCEPTION_LOCATION);
14802  } // if (connect_to_the_left_flag != -1)
14803  } // if (connect_to_the_left_flag < 0)
14804 
14805  // Is the shared polyline not connected to the right
14806  if (connect_to_the_right_flag < 0)
14807  {
14808  // If not connected then should be specified by -1
14809  if (connect_to_the_right_flag != -1)
14810  {
14811  std::ostringstream error_message;
14812  error_message
14813  << "The only accepted values for the connection flags are:\n"
14814  << "POSITIVE values or -1, any other value is rejected, please\n"
14815  << "check that you previously called the methods to deal with\n"
14816  << "other flag values\n"
14817  << "The current flag value for connection to the right is: ("
14818  << connect_to_the_right_flag << ")\n\n";
14819  throw OomphLibError(error_message.str(),
14820  "TriangleMesh::create_shared_polyline()",
14821  OOMPH_EXCEPTION_LOCATION);
14822  } // if (connect_to_the_right_flag != -1)
14823  } // if (connect_to_the_right_flag < 0)
14824 #endif
14825 
14826  // Set the connection to the left
14827  if (connect_to_the_left_flag != -1)
14828  {
14829  // Get the unsigned version of the boundary id to the left
14830  const unsigned bnd_id_connection_to_the_left =
14831  static_cast<unsigned>(connect_to_the_left_flag);
14832  // Set the initial vertex as connected
14833  polyline_pt->set_initial_vertex_connected();
14834  // Set the initial vertex connected boundary id
14835  polyline_pt->initial_vertex_connected_bnd_id() =
14836  bnd_id_connection_to_the_left;
14837  // Set the chunk number to zero
14838  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14839 
14840  } // if (connect_to_the_left_flag != -1)
14841 
14842  // Set the connection to the right
14843  if (connect_to_the_right_flag != -1)
14844  {
14845  // Get the unsigned version of the boundary id to the right
14846  const unsigned bnd_id_connection_to_the_right =
14847  static_cast<unsigned>(connect_to_the_right_flag);
14848  // Set the final vertex as connected
14849  polyline_pt->set_final_vertex_connected();
14850  // Set the final vertex connected boundary id
14851  polyline_pt->final_vertex_connected_bnd_id() =
14852  bnd_id_connection_to_the_right;
14853  // Set the chunk number to zero
14854  polyline_pt->final_vertex_connected_n_chunk() = 0;
14855 
14856  } // if (connect_to_the_right_flag != -1)
14857 
14858  } // if (iproc == my_rank || jproc == my_rank)
14859  }
14860 
14861  //======================================================================
14862  /// Reset the boundary elements info. after load balance have
14863  /// taken place
14864  //======================================================================
14865  template<class ELEMENT>
14867  Vector<unsigned>& ntmp_boundary_elements,
14868  Vector<Vector<unsigned>>& ntmp_boundary_elements_in_region,
14869  Vector<FiniteElement*>& deleted_elements)
14870  {
14871  // Get the number of boundaries
14872  const unsigned nbound = this->nboundary();
14873 
14874  // Are there regions?
14875  const unsigned n_regions = this->nregion();
14876 
14877  // Loop over the boundaries
14878  for (unsigned b = 0; b < nbound; b++)
14879  {
14880  // Get the boundary elements and back them up
14881  // -----------------------------------------------------------------
14882  // Get the number of boundary elements (mixed with the old and new)
14883  const unsigned nbound_ele = this->nboundary_element(b);
14884  // Back-up the boundary elements
14885  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14886  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14887  for (unsigned e = 0; e < nbound_ele; e++)
14888  {
14889  // Get the old boundary element
14890  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14891  // Get the old face index
14892  backed_up_face_index_at_boundary[e] =
14893  this->face_index_at_boundary(b, e);
14894  } // for (n < nold_boundary_elements)
14895 
14896  // Back up the elements in boundary for each region
14897  Vector<Vector<FiniteElement*>> backed_up_boundary_region_element_pt(
14898  n_regions);
14899  Vector<Vector<int>> backed_up_face_index_at_boundary_region(n_regions);
14900 
14901  // Loop over the regions and back up the boundary elements in
14902  // regions
14903  for (unsigned ir = 0; ir < n_regions; ir++)
14904  {
14905  // Get the region id
14906  const unsigned region_id =
14907  static_cast<unsigned>(this->region_attribute(ir));
14908  // Get the number of boundary region elements (mixed old and new)
14909  const unsigned nbnd_region_ele =
14910  this->nboundary_element_in_region(b, region_id);
14911 
14912  // Loop over the elements in the region
14913  for (unsigned e = 0; e < nbnd_region_ele; e++)
14914  {
14915  // Get the old boundary region element
14916  backed_up_boundary_region_element_pt[ir][e] =
14917  this->boundary_element_in_region_pt(b, region_id, e);
14918 
14919  // Get the old face index
14920  backed_up_face_index_at_boundary_region[ir][e] =
14921  this->face_index_at_boundary_in_region(b, region_id, e);
14922  } // for (e < nbnd_region_ele)
14923 
14924  } // for (ir < n_regions)
14925 
14926  // Clean all previous storages
14927  this->Boundary_element_pt[b].clear();
14928  this->Face_index_at_boundary[b].clear();
14929  if (n_regions > 0)
14930  {
14931  this->Boundary_region_element_pt[b].clear();
14932  this->Face_index_region_at_boundary[b].clear();
14933  }
14934 
14935  // -------------------------------------------------------------------
14936  // Now copy only the elements that are still alive, from those before
14937  // the re-establishment of halo and haloed elements
14938  // -------------------------------------------------------------------
14939  // Start with the boundary elements
14940  // Get the old number of boundary elements
14941  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14942  // Loop over the boundary elements and check those still alive
14943  for (unsigned e = 0; e < nold_bnd_ele; e++)
14944  {
14945  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14946  // Include only those elements still alive
14947  Vector<FiniteElement*>::iterator it = std::find(
14948  deleted_elements.begin(), deleted_elements.end(), tmp_ele_pt);
14949  // Only copy thoes elements not found on the deleted elements
14950  // container
14951  if (it == deleted_elements.end())
14952  {
14953  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14954  this->Boundary_element_pt[b].push_back(add_ele_pt);
14955  const int face_index = backed_up_face_index_at_boundary[e];
14956  this->Face_index_at_boundary[b].push_back(face_index);
14957  } // if (tmp_ele_pt != 0)
14958 
14959  } // for (n < nold_bnd_ele)
14960 
14961  // ... continue with the boundary elements in specific regions
14962 
14963  // Loop over the regions
14964  for (unsigned ir = 0; ir < n_regions; ir++)
14965  {
14966  // Get the region id
14967  const unsigned region_id =
14968  static_cast<unsigned>(this->region_attribute(ir));
14969 
14970  // Get the old number of boundary elements in region
14971  const unsigned nold_bnd_region_ele =
14972  ntmp_boundary_elements_in_region[b][ir];
14973 
14974  // Loop over the boundary region elements and check those still
14975  // alive
14976  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14977  {
14978  // Get the element
14979  FiniteElement* tmp_ele_pt =
14980  backed_up_boundary_region_element_pt[ir][e];
14981  // Include only those elements still alive
14982  Vector<FiniteElement*>::iterator it = std::find(
14983  deleted_elements.begin(), deleted_elements.end(), tmp_ele_pt);
14984  // Only copy those elements not found on the deleted elements
14985  // container
14986  if (it == deleted_elements.end())
14987  {
14988  FiniteElement* add_ele_pt =
14989  backed_up_boundary_region_element_pt[ir][e];
14990  this->Boundary_region_element_pt[b][region_id].push_back(
14991  add_ele_pt);
14992  const int face_index =
14993  backed_up_face_index_at_boundary_region[ir][e];
14994  this->Face_index_region_at_boundary[b][region_id].push_back(
14995  face_index);
14996  } // if (tmp_ele_pt != 0)
14997 
14998  } // for (n < nbound_ele)
14999 
15000  } // for (ir < n_regions)
15001 
15002  // ----------------------------------------------------------------
15003  // Now copy all those elements created after the re-establishment
15004  // of halo and haloed elements
15005  // ----------------------------------------------------------------
15006  // Loop over the boundary elements
15007  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
15008  {
15009  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
15010  this->Boundary_element_pt[b].push_back(add_ele_pt);
15011  const int face_index = backed_up_face_index_at_boundary[e];
15012  this->Face_index_at_boundary[b].push_back(face_index);
15013  } // for (e < nbound_ele)
15014 
15015  // Now add the boundary elements in regions
15016 
15017  // Loop over the regions
15018  for (unsigned ir = 0; ir < n_regions; ir++)
15019  {
15020  // Get the region id
15021  const unsigned region_id =
15022  static_cast<unsigned>(this->region_attribute(ir));
15023 
15024  // Get the old number of boundary elements in region
15025  const unsigned nold_bnd_region_ele =
15026  ntmp_boundary_elements_in_region[b][ir];
15027 
15028  // Get the new number of boundary elements in region
15029  const unsigned nbnd_region_ele =
15030  this->nboundary_element_in_region(b, region_id);
15031 
15032  // Loop over the boundary region elements and check those still
15033  // alive
15034  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
15035  {
15036  FiniteElement* add_ele_pt =
15037  backed_up_boundary_region_element_pt[ir][e];
15038  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
15039  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
15040  this->Face_index_region_at_boundary[b][region_id].push_back(
15041  face_index);
15042  } // for (e < nbnd_region_ele)
15043 
15044  } // for (ir < n_regions)
15045 
15046  } // for (b < nbound)
15047 
15048  // Lookup scheme has now been setup yet
15049  Lookup_for_elements_next_boundary_is_setup = true;
15050  }
15051 
15052 #endif // OOMPH_HAS_MPI
15053 
15054 #ifdef OOMPH_HAS_TRIANGLE_LIB
15055 
15056  //========================================================================
15057  /// Build a new TriangulateIO object based on target areas specified
15058  //========================================================================
15059  template<class ELEMENT>
15061  TriangulateIO& triangulate_io,
15062  const Vector<double>& target_area,
15063  struct TriangulateIO& triangle_refine)
15064  {
15065  // Initialize
15066  TriangleHelper::initialise_triangulateio(triangle_refine);
15067 
15068  // Store the global number of vertices and segments
15069  // in the list
15070  unsigned n_points = triangulate_io.numberofpoints;
15071  triangle_refine.numberofpoints = n_points;
15072 
15073  unsigned n_segments = triangulate_io.numberofsegments;
15074  triangle_refine.numberofsegments = n_segments;
15075 
15076  // Initialization of the TriangulateIO objects to store the values
15077  triangle_refine.pointlist =
15078  (double*)malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
15079  triangle_refine.pointmarkerlist =
15080  (int*)malloc(triangulate_io.numberofpoints * sizeof(int));
15081  triangle_refine.segmentlist =
15082  (int*)malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
15083  triangle_refine.segmentmarkerlist =
15084  (int*)malloc(triangulate_io.numberofsegments * sizeof(int));
15085 
15086  // Storing the point's coordinates in the list
15087  // and in two vectors with x and y coordinates
15088  Vector<double> x_coord(n_points);
15089  Vector<double> y_coord(n_points);
15090 
15091  for (unsigned count_point = 0; count_point < n_points * 2; count_point++)
15092  {
15093  triangle_refine.pointlist[count_point] =
15094  triangulate_io.pointlist[count_point];
15095 
15096  // Even vaules represent the x coordinate
15097  // Odd values represent the y coordinate
15098  if (count_point % 2 == 0)
15099  {
15100  x_coord[count_point / 2] = triangulate_io.pointlist[count_point];
15101  }
15102  else
15103  {
15104  y_coord[(count_point - 1) / 2] = triangulate_io.pointlist[count_point];
15105  }
15106  }
15107 
15108  // Store the point's markers in the list
15109  for (unsigned count_marker = 0; count_marker < n_points; count_marker++)
15110  {
15111  triangle_refine.pointmarkerlist[count_marker] =
15112  triangulate_io.pointmarkerlist[count_marker];
15113  }
15114 
15115  // Storing the segment's edges in the list
15116  for (unsigned count_seg = 0; count_seg < n_segments * 2; count_seg++)
15117  {
15118  triangle_refine.segmentlist[count_seg] =
15119  triangulate_io.segmentlist[count_seg];
15120  }
15121 
15122  // Store the segment's markers in the list
15123  for (unsigned count_markers = 0; count_markers < n_segments;
15124  count_markers++)
15125  {
15126  triangle_refine.segmentmarkerlist[count_markers] =
15127  triangulate_io.segmentmarkerlist[count_markers];
15128  }
15129 
15130  // Store the hole's center coordinates
15131  unsigned n_holes = triangulate_io.numberofholes;
15132  triangle_refine.numberofholes = n_holes;
15133 
15134  triangle_refine.holelist =
15135  (double*)malloc(triangulate_io.numberofholes * 2 * sizeof(double));
15136 
15137  // Loop over the holes to get centre coords
15138  for (unsigned count_hole = 0; count_hole < n_holes * 2; count_hole++)
15139  {
15140  triangle_refine.holelist[count_hole] =
15141  triangulate_io.holelist[count_hole];
15142  }
15143 
15144  // Store the triangles values
15145  unsigned n_triangles = triangulate_io.numberoftriangles;
15146  triangle_refine.numberoftriangles = n_triangles;
15147 
15148 #ifdef PARANOID
15149  if (n_triangles != target_area.size())
15150  {
15151  std::stringstream err;
15152  err << "Number of triangles in triangulate_io=" << n_triangles
15153  << " doesn't match\n"
15154  << "size of target area vector (" << target_area.size() << ")\n";
15155  throw OomphLibError(
15156  err.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
15157  }
15158 #endif
15159 
15160  unsigned n_corners = triangulate_io.numberofcorners;
15161  triangle_refine.numberofcorners = n_corners;
15162 
15163  triangle_refine.trianglelist =
15164  (int*)malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
15165 
15166  // Store the triangle's corners in the list and get element sizes
15167  for (unsigned count_tri = 0; count_tri < n_triangles * 3; count_tri++)
15168  {
15169  triangle_refine.trianglelist[count_tri] =
15170  triangulate_io.trianglelist[count_tri];
15171  }
15172 
15173  // Store the triangle's area in the list
15174  triangle_refine.trianglearealist =
15175  (double*)malloc(triangulate_io.numberoftriangles * sizeof(double));
15176  for (unsigned count_area = 0; count_area < n_triangles; count_area++)
15177  {
15178  triangle_refine.trianglearealist[count_area] = target_area[count_area];
15179  }
15180 
15181  // Store the triangles attributes in the list
15182  triangle_refine.numberoftriangleattributes =
15183  triangulate_io.numberoftriangleattributes;
15184 
15185  triangle_refine.triangleattributelist = (double*)malloc(
15186  triangulate_io.numberoftriangles *
15187  triangulate_io.numberoftriangleattributes * sizeof(double));
15188  for (unsigned count_attribute = 0;
15189  count_attribute <
15190  (n_triangles * triangulate_io.numberoftriangleattributes);
15191  count_attribute++)
15192  {
15193  triangle_refine.triangleattributelist[count_attribute] =
15194  triangulate_io.triangleattributelist[count_attribute];
15195  }
15196  }
15197 
15198 #ifdef OOMPH_HAS_MPI
15199 
15200  // ===================================================================
15201  // The comparison class for the map that sorts the nodes on the
15202  // shared boundary (using a lexicographic order)
15203  // ===================================================================
15204  struct classcomp
15205  {
15206  // Tolerance for lower-left comparison
15207  static double Tol;
15208 
15209 
15210  // Comparison operator for "lower left" ordering
15211  bool operator()(const std::pair<double, double>& lhs,
15212  const std::pair<double, double>& rhs) const
15213  {
15214  double diff_y = lhs.second - rhs.second;
15215  if (diff_y < -Tol) // (lhs.second < rhs.second)
15216  {
15217  return true;
15218  }
15219  else
15220  {
15221  // Are they "equal" with 1.0e-14 tolerance?
15222  if (diff_y < Tol) // (lhs.second == rhs.second)
15223  {
15224 #ifdef PARANOID
15225  double diff_x = lhs.first - rhs.first;
15226  if (fabs(diff_x) < Tol)
15227  {
15228  std::ostringstream warning_message;
15229  warning_message
15230  << "Dodgy \"lower left\" (lexicographic) comparison "
15231  << "of points with cooordinates: "
15232  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15233  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15234  << "x and y coordinates differ by less than tolerance!\n"
15235  << "diff_x = " << diff_x << "\n"
15236  << "diff_y = " << diff_y << "\n"
15237  << "Tol = " << Tol << "\n";
15238  OomphLibError(warning_message.str(),
15239  OOMPH_CURRENT_FUNCTION,
15240  OOMPH_EXCEPTION_LOCATION);
15241  }
15242 #endif
15243  if (lhs.first < rhs.first)
15244  {
15245  return true;
15246  }
15247  else
15248  {
15249  return false;
15250  }
15251  }
15252  else
15253  {
15254  return false;
15255  }
15256  }
15257 
15258 
15259  // if (lhs.second < rhs.second)
15260  // {
15261  // return true;
15262  // }
15263  // else
15264  // {
15265  // // // Are "equal" with 1.0e-14 tolerance
15266  // // if (lhs.second - rhs.second < 1.0e-14)
15267  // // Are equal?
15268  // if (lhs.second == rhs.second)
15269  // {
15270  // if (lhs.first < rhs.first)
15271  // {
15272  // return true;
15273  // }
15274  // else
15275  // {
15276  // return false;
15277  // }
15278  // }
15279  // else
15280  // {
15281  // return false;
15282  // }
15283  // }
15284  }
15285 
15286  } Bottom_left_sorter; // struct classcomp
15287 
15288 
15289  // Assign value for tolerance
15290  double classcomp::Tol = 1.0e-14;
15291 
15292 
15293  //======================================================================
15294  // Sort the nodes on shared boundaries so that the processors that share
15295  // a boundary agree with the order of the nodes on the boundary
15296  //======================================================================
15297  template<class ELEMENT>
15299  {
15300  // Get the shared boundaries in this processor
15301  Vector<unsigned> my_rank_shared_boundaries_ids;
15302  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15303 
15304  // Get the number of shared boundaries
15305  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15306 
15307  // Loop over the shared boundaries
15308  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15309  {
15310  // A map is used to sort the nodes using their coordinates as the key
15311  // of the map
15312  // std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15313  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15314 
15315 
15316 #ifdef PARANOID
15317 
15318  // Check min distance between nodes; had better be less than the
15319  // tolerance used for the bottom left sorting
15320  double min_distance_squared = DBL_MAX;
15321 
15322 #endif
15323 
15324  // Get the boundary id
15325  const unsigned b = my_rank_shared_boundaries_ids[i];
15326 
15327  // Get the number of nodes on the current boundary
15328  const unsigned nbnd_node = this->nshared_boundary_node(b);
15329 
15330  // Go through all the nodes on the boundary and temporarily store
15331  // them on the map container
15332  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15333  {
15334  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15335  std::pair<double, double> vertex =
15336  std::make_pair(node_pt->x(0), node_pt->x(1));
15337  sorted_nodes_pt[vertex] = node_pt;
15338 
15339 
15340 #ifdef PARANOID
15341 
15342  // Check for minimum distance
15343  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15344  {
15345  if (i_node != j_node)
15346  {
15347  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15348 
15349  // Squared distance
15350  double squared_distance = 0.0;
15351  for (unsigned ii = 0; ii < 2; ii++)
15352  {
15353  squared_distance += (node_pt->x(ii) - node2_pt->x(ii)) *
15354  (node_pt->x(ii) - node2_pt->x(ii));
15355  }
15356  if (squared_distance < min_distance_squared)
15357  {
15358  min_distance_squared = squared_distance;
15359  }
15360  }
15361  }
15362 
15363  if (sqrt(min_distance_squared) < Bottom_left_sorter.Tol)
15364  {
15365  std::ostringstream warning_message;
15366  warning_message << "Minimum distance between nodes on boundary " << b
15367  << "\n"
15368  << "is " << sqrt(min_distance_squared)
15369  << " which is less than "
15370  << "Bottom_left_sorter.Tol = "
15371  << Bottom_left_sorter.Tol << "\n"
15372  << "This may screw up the ordering of the nodes on "
15373  "shared boundaries\n";
15374  OomphLibWarning(warning_message.str(),
15375  OOMPH_CURRENT_FUNCTION,
15376  OOMPH_EXCEPTION_LOCATION);
15377  }
15378 
15379 #endif
15380  }
15381 
15382  unsigned counter = 0;
15383  // Resize the sorted shared boundary node vector
15384  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15385 
15386  // Now go through the map container, get the elements and store their
15387  // members on the Sorted_shared_boundary_node_pt container
15388  // The map has already sorted the nodes, now they keep the same sorting
15389  // on all processors
15390  for (std::map<std::pair<double, double>, Node*>::iterator it_map =
15391  sorted_nodes_pt.begin();
15392  it_map != sorted_nodes_pt.end();
15393  it_map++)
15394  {
15395  // Store the pointer to the node
15396  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15397  }
15398 
15399  } // for (i < nmy_rank_shd_bnd)
15400  }
15401 
15402  //========================================================================
15403  // Re-establish the shared boundary elements after the adaptation
15404  // process (the updating of shared nodes is optional and performed by
15405  // default)
15406  //========================================================================
15407  template<class ELEMENT>
15409  reset_shared_boundary_elements_and_nodes(const bool flush_elements,
15410  const bool update_elements,
15411  const bool flush_nodes,
15412  const bool update_nodes)
15413  {
15414  // Get the rank of the current processor
15415  const unsigned my_rank = this->communicator_pt()->my_rank();
15416 
15417  // Go through the boundaries know as shared boundaries and copy the
15418  // elements to the corresponding storage
15419 
15420  // Get the initial shared boundary id
15421  const unsigned initial_id = this->initial_shared_boundary_id();
15422 
15423  // Get the final shared boundary id
15424  const unsigned final_id = this->final_shared_boundary_id();
15425 
15426  if (flush_elements)
15427  {
15428  // Flush the shared boundaries storage for elements
15429  this->flush_shared_boundary_element();
15430  // .. and also flush the face indexes associated with the element
15431  this->flush_face_index_at_shared_boundary();
15432  } // if (flush_elements)
15433 
15434  if (flush_nodes)
15435  {
15436  // Flush the shared boundaries storage for nodes
15437  this->flush_shared_boundary_node();
15438  } // if (flush_nodes)
15439 
15440  for (unsigned b = initial_id; b < final_id; b++)
15441  {
15442  // Check if the boundary is on the current processor
15443  Vector<unsigned> procs_from_shrd_bnd;
15444  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15445  bool current_processor_has_b_boundary = false;
15446  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15447  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15448  {
15449  if (procs_from_shrd_bnd[p] == my_rank)
15450  {
15451  current_processor_has_b_boundary = true;
15452  break; // break for (p < n_procs_from_shrd_bnd)
15453  }
15454  } // for (p < n_procs_from_shrd_bnd)
15455 
15456  if (current_processor_has_b_boundary)
15457  {
15458  if (update_elements)
15459  {
15460  const unsigned nboundary_ele = this->nboundary_element(b);
15461  for (unsigned e = 0; e < nboundary_ele; e++)
15462  {
15463  // Get the boundary element and add it to the shared
15464  // boundary elements structure
15465  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15466  this->add_shared_boundary_element(b, bnd_ele_pt);
15467  // ... do the same with the face index information
15468  int face_index = this->face_index_at_boundary(b, e);
15469  this->add_face_index_at_shared_boundary(b, face_index);
15470  } // for (e < nboundary_element)
15471  } // if (update_elements)
15472 
15473  if (update_nodes)
15474  {
15475  const unsigned nboundary_node = this->nboundary_node(b);
15476  for (unsigned n = 0; n < nboundary_node; n++)
15477  {
15478  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15479  this->add_shared_boundary_node(b, bnd_node_pt);
15480  } // for (n < nboundary_node)
15481  } // if (update_nodes)
15482 
15483  } // if (current_processor_has_b_boundary)
15484  } // for (b < final_id)
15485  }
15486 
15487  //======================================================================
15488  // Sort the nodes on shared boundaries so that the processors that share
15489  // a boundary agree with the order of the nodes on the boundary
15490  //======================================================================
15491  template<class ELEMENT>
15493  {
15494  // Get the number of processors
15495  unsigned nproc = this->communicator_pt()->nproc();
15496  // Get the rank of the current processor
15497  unsigned my_rank = this->communicator_pt()->my_rank();
15498 
15499  // Get some timings
15500  double tt_start = 0.0;
15501  double tt_end = 0.0;
15502  if (Global_timings::Doc_comprehensive_timings)
15503  {
15504  tt_start = TimingHelpers::timer();
15505  }
15506 
15507  // -------------------------------------------------------------------
15508  // BEGIN: Get the node names and the shared nodes
15509  // -------------------------------------------------------------------
15510 
15511  // Container where to store the nodes on shared boundaries no
15512  // associated with the processor that receives the elements/nodes
15513  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15514  Vector<Vector<Vector<std::map<unsigned, Node*>>>>
15515  other_proc_shd_bnd_node_pt(nproc);
15516  // Resize the container
15517  for (unsigned iproc = 0; iproc < nproc; iproc++)
15518  {
15519  // Resize the container
15520  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15521  for (unsigned jproc = 0; jproc < nproc; jproc++)
15522  {
15523  // Get the number of shared boundaries
15524  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15525  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15526  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15527  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15528  } // for (jproc < nproc)
15529 
15530  } // for (iproc < nproc)
15531 
15532  // Store the global node names
15533  // global_node_name[x][ ][ ] Global node number
15534  // global_node_name[ ][x][ ] Global node names
15535  // global_node_name[ ][ ][x] Global node info.
15536  Vector<Vector<Vector<unsigned>>> global_node_names;
15537 
15538  // Creates a map between the node name and the index of the global
15539  // node so we can access all its node names
15540  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15541 
15542  // Store the global shared nodes pointers
15543  Vector<Node*> global_shared_node_pt;
15544 
15545  // Get the time for computation of global nodes names and shared
15546  // nodes
15547  double t_start_global_node_names_and_shared_nodes = TimingHelpers::timer();
15548 
15549  // Compute all the names of the nodes and fill in the
15550  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15551  // on this processor (my_rank) by looking over all their names
15552  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15553  global_node_names,
15554  node_name_to_global_index,
15555  global_shared_node_pt);
15556 
15557  // Compute the number of elements before adding new ones
15558  const unsigned n_ele = this->nelement();
15559 
15560  if (Print_timings_level_adaptation > 1)
15561  {
15562  // The total time for computation of global nodes names and
15563  // shared nodes
15564  double t_final_global_node_names_and_shared_nodes =
15565  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15566  oomph_info << "CPU for computing global node names and shared nodes "
15567  << "[n_ele=" << n_ele
15568  << "]: " << t_final_global_node_names_and_shared_nodes
15569  << std::endl;
15570  }
15571 
15572  // -------------------------------------------------------------------
15573  // END: Get the node names and the shared nodes
15574  // -------------------------------------------------------------------
15575 
15576  // -------------------------------------------------------------------
15577  // BEGIN: Using the global node names each processor sends info. of
15578  // the nodes shared with other processors regarding whether they are
15579  // on an original boundary or not. This is required so that at the
15580  // re-generation of halo(ed) elements stage they have the updated
15581  // information
15582  // -------------------------------------------------------------------
15583 
15584  // Get the time for sending info. of shared nodes on original
15585  // boundaries
15586  double t_start_send_info_shd_nodes_on_original_bnds =
15587  TimingHelpers::timer();
15588 
15589  // Send the boundary node info. of nodes on shared boundaries across
15590  // processors
15591  send_boundary_node_info_of_shared_nodes(
15592  global_node_names, node_name_to_global_index, global_shared_node_pt);
15593 
15594  if (Print_timings_level_adaptation > 1)
15595  {
15596  // The total time for sending info. of shared nodes lying on
15597  // original boundaries
15598  oomph_info
15599  << "CPU for sending info. of shared nodes on original boundaries: "
15600  << TimingHelpers::timer() - t_start_send_info_shd_nodes_on_original_bnds
15601  << std::endl;
15602  }
15603 
15604  // -------------------------------------------------------------------
15605  // END: Using the global node names each processor sends info. of
15606  // the nodes shared with other processors regarding whether they are
15607  // on an original boundary or not. This is required so that at the
15608  // re-generation of halo(ed) elements stage they have the updated
15609  // information
15610  // -------------------------------------------------------------------
15611 
15612  // -------------------------------------------------------------------
15613  // BEGIN: Identify the elements of the mesh that have nodes on the
15614  // shared boundaries
15615  // -------------------------------------------------------------------
15616 
15617  // Store the elements that have a node on a shared boundary with
15618  // other processors
15619  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15620  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15621  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15622  // boundary with iproc
15623  Vector<Vector<Vector<FiniteElement*>>> ele_with_node_on_shd_bnd_pt(nproc);
15624  // Resize the container with the number of shared boundaries within
15625  // each processor
15626 
15627  // loop over the processors
15628  for (unsigned iproc = 0; iproc < nproc; iproc++)
15629  {
15630  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15631  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15632  } // for (iproc < nproc)
15633 
15634  // Go through all the elements and check whether any of their nodes
15635  // lies on any of the shared boundaries
15636 
15637  // loop over the elements
15638  for (unsigned e = 0; e < n_ele; e++)
15639  {
15640  // Get the element
15641  FiniteElement* ele_pt = this->finite_element_pt(e);
15642  // Get the number of nodes
15643  const unsigned n_nodes = ele_pt->nnode();
15644  // loop over the nodes and check whether any of them lies on a
15645  // shared boundary
15646  for (unsigned n = 0; n < n_nodes; n++)
15647  {
15648  // Get the node
15649  Node* node_pt = ele_pt->node_pt(n);
15650 
15651  // Now check whether the current node lies on a shared boundary
15652  // within any other processor
15653 
15654  // loop over the processors
15655  for (unsigned iproc = 0; iproc < nproc; iproc++)
15656  {
15657  // The number of boundaries shared with the current processor
15658  // (if iproc==my_rank then there are no shared boundaries
15659  // between them)
15660  const unsigned n_shd_bnd_iproc =
15661  this->nshared_boundaries(my_rank, iproc);
15662 
15663  // There are no info. with myself
15664  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15665  {
15666  // Get the boundaries ids of the shared boundaries with
15667  // iproc processor
15668  Vector<unsigned> shd_bnd_ids =
15669  this->shared_boundaries_ids(my_rank, iproc);
15670 
15671  // Loop over shd bnds with processor "iproc"
15672  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15673  {
15674  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15675  const unsigned n_ele_shd_bnd =
15676  this->nshared_boundary_element(shd_bnd_id);
15677 
15678  // Check if the node is on this boundary only if there are
15679  // elements on it
15680  if (n_ele_shd_bnd > 0 &&
15681  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15682  {
15683  // Add the element into those that have a
15684  // node on the current shared boundary
15685  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15686 
15687  } // Are there elements on the boundary and the node lies
15688  // on this boundary
15689 
15690  } // for (isb < n_shd_bnd_iproc)
15691 
15692  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15693 
15694  } // for (iproc < nproc)
15695 
15696  } // for (n < n_nodes)
15697 
15698  } // for (e < n_ele)
15699 
15700  // -------------------------------------------------------------------
15701  // END: Identify the elements of the mesh that have nodes on the
15702  // shared boundaries
15703  // -------------------------------------------------------------------
15704 
15705  // -------------------------------------------------------------------
15706  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15707  // the shared boundaries within each processor. Get the elements on
15708  // the shared boundaries, mark them as haloed in this processor and
15709  // as halo on the element that will receive the info.
15710  // -------------------------------------------------------------------
15711 
15712  // ********************************************************************
15713  // General strategy:
15714  // 1) Go through all the elements on the shared boundaries, mark these
15715  // elements as haloed, same as their nodes.
15716  // 2) Package the info. of the nodes and the elements.
15717  // 3) Send and receive the info across processors
15718  // 4) Unpackage it and create halo elements and nodes as indicated by
15719  // the received info.
15720  // ********************************************************************
15721 
15722  // Keep track of the currently created nodes within each
15723  // processor. We need to keep track of these nodes so they can be
15724  // referred at a second stage.
15725  Vector<Vector<Node*>> iproc_currently_created_nodes_pt(nproc);
15726 
15727  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15728  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15729  TimingHelpers::timer();
15730 
15731  // Go through all processors
15732  for (unsigned iproc = 0; iproc < nproc; iproc++)
15733  {
15734  // Send and receive info. to/from other processors
15735  if (iproc != my_rank)
15736  {
15737  // Get the number of boundaries shared with the send proc (iproc)
15738  const unsigned nshared_boundaries_with_iproc =
15739  this->nshared_boundaries(my_rank, iproc);
15740 
15741  if (nshared_boundaries_with_iproc > 0)
15742  {
15743  // ******************************************************************
15744  // Stage 1
15745  // ******************************************************************
15746  // Step (1) Mark the elements adjacent to the shared boundaries as
15747  // haloed, mark the nodes on these elements as haloed nodes
15748  // Step (2) Create packages of information indicating the generation
15749  // of halo elements and nodes
15750  // ******************************************************************
15751 
15752  // Clean send and receive buffers
15753  Flat_packed_unsigneds.clear();
15754  Flat_packed_doubles.clear();
15755 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15756  Flat_packed_unsigneds_string.clear();
15757 #endif
15758 
15759  // Get the boundaries ids shared with "iproc"
15760  Vector<unsigned> bound_shared_with_iproc;
15761  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15762 
15763  // Loop over shared boundaries with processor "iproc"
15764  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15765  {
15766  const unsigned bnd_id = bound_shared_with_iproc[bs];
15767  // DEBP(bnd_id);
15768  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15769  // DEBP(nel_bnd);
15770 
15771  // Container to store the elements marked as haloed
15772  Vector<FiniteElement*> haloed_element;
15773 
15774  // All the elements adjacent to the boundary should be
15775  // marked as haloed elements
15776  if (nel_bnd > 0)
15777  {
15778  // Map to know which element have been already added
15779  std::map<FiniteElement*, bool> already_added;
15780 
15781  // Loop over the elements adjacent to boundary "bnd_id"
15782  for (unsigned e = 0; e < nel_bnd; e++)
15783  {
15784  // Get pointer to the element adjacent to boundary bnd_id
15785  FiniteElement* ele_pt =
15786  this->shared_boundary_element_pt(bnd_id, e);
15787 
15788  // Check if the element has been already added. Elemets
15789  // are repeated if they have two faces on the shared
15790  // boundary
15791  if (!already_added[ele_pt])
15792  {
15793  // Add the element to the container of haloed elements
15794  haloed_element.push_back(ele_pt);
15795  // Mark the element as already added
15796  already_added[ele_pt] = true;
15797  }
15798 
15799  } // for (e < nel_bnd)
15800 
15801  // In addition to the elements on the boundary we also
15802  // need to mark (as haloed) any element on the mesh with a
15803  // node on the shared boundary
15804 
15805  // Get the number of elements with a node on the current
15806  // shared boundary
15807  const unsigned n_ele_with_node_on_shd_bnd =
15808  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15809  // loop and add the elements that have a node on the
15810  // current shared boundary with the current processor
15811  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15812  {
15813  // Get the element
15814  FiniteElement* ele_pt =
15815  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15816  // Check if it has not been already added
15817  if (!already_added[ele_pt])
15818  {
15819  // Add it!!
15820  haloed_element.push_back(ele_pt);
15821  // Mark it as done
15822  already_added[ele_pt] = true;
15823  } // if (!already_added[ele_pt])
15824 
15825  } // for (iele < n_ele_with_node_on_shd_bnd)
15826 
15827  } // if (nel_bnd > 0)
15828 
15829  // Get the total number of haloed elements
15830  const unsigned nhaloed_ele = haloed_element.size();
15831  // DEBP(nhaloed_ele);
15832  // DEBP(my_rank);
15833  // DEBP(iproc);
15834  // The very first data of the flat packed is the number of haloed
15835  // elements, this will be the number of halo element to create on
15836  // the receiver processor
15837  Flat_packed_unsigneds.push_back(nhaloed_ele);
15838 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15839  std::stringstream junk;
15840  junk << "Number of haloed elements " << nhaloed_ele;
15841  Flat_packed_unsigneds_string.push_back(junk.str());
15842 #endif
15843 
15844  // Loop over the marked haloed elements
15845  for (unsigned e = 0; e < nhaloed_ele; e++)
15846  {
15847  // Get pointer to the marked haloed element
15848  FiniteElement* ele_pt = haloed_element[e];
15849  const unsigned nroot_haloed_ele =
15850  this->nroot_haloed_element(iproc);
15851 
15852  // Check if the element has been already added to the
15853  // halo(ed) scheme
15854  GeneralisedElement* gen_ele_pt = ele_pt;
15855  const unsigned haloed_ele_index =
15856  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15857 
15858  // Was the element added or only returned the index of the
15859  // element
15860  if (nroot_haloed_ele == haloed_ele_index)
15861  {
15862  Flat_packed_unsigneds.push_back(1);
15863 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15864  Flat_packed_unsigneds_string.push_back(
15865  "Haloed element needs to be constructed");
15866 #endif
15867 
15868  // Get additional info. related with the haloed element
15869  get_required_elemental_information_helper(iproc, ele_pt);
15870 
15871  // Get the nodes on the element
15872  const unsigned nnodes = ele_pt->nnode();
15873  for (unsigned j = 0; j < nnodes; j++)
15874  {
15875  Node* node_pt = ele_pt->node_pt(j);
15876 
15877  // Package the info. of the nodes
15878  // The destination processor goes in the arguments
15879  add_haloed_node_helper(iproc, node_pt);
15880 
15881  } // for (j < nnodes)
15882  } // add the element and send its nodes
15883  else // The haloed element already exists
15884  {
15885  Flat_packed_unsigneds.push_back(0);
15886 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15887  Flat_packed_unsigneds_string.push_back(
15888  "Haloed element already exists");
15889 #endif
15890  Flat_packed_unsigneds.push_back(haloed_ele_index);
15891 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15892  Flat_packed_unsigneds_string.push_back(
15893  "Index of existing haloed element");
15894 #endif
15895  } // else (next_haloed_ele == external_haloed_ele_index)
15896  } // for (e < nel_bnd)
15897 
15898  } // for (bs < nshared_boundaries_with_iproc)
15899 
15900  // *******************************************************************
15901  // Stage (2)
15902  // *******************************************************************
15903  // Step (1) Send and receive the data to create halo elements and
15904  // nodes
15905  // *******************************************************************
15906  // The processor to which send the elements
15907  int send_proc = static_cast<int>(iproc);
15908  // The processor from which receive the elements
15909  int recv_proc = static_cast<int>(iproc);
15910  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15911 
15912  // *******************************************************************
15913  // Stage (3)
15914  // *******************************************************************
15915  // Step (1) Unpackage the info and create the halo elements and nodes
15916  // *******************************************************************
15917 
15918  // Reset the counters
15919  Counter_for_flat_packed_doubles = 0;
15920  Counter_for_flat_packed_unsigneds = 0;
15921 
15922  // Loop over shared boundaries with processor "iproc"
15923  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15924  {
15925  // Get the number of halo element to be created
15926  const unsigned nhaloed_ele =
15927  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
15928 
15929 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15930  oomph_info
15931  << "Rec:" << Counter_for_flat_packed_unsigneds
15932  << " Number of elements need to be constructed "
15933  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
15934  << std::endl;
15935 #endif
15936 
15937  // Loop over boundaries shared with processor "urecv_proc"
15938  for (unsigned e = 0; e < nhaloed_ele; e++)
15939  {
15940  // Create halo element from received info. of "iproc"
15941  // processor on the current processor
15942  create_halo_element(iproc,
15943  iproc_currently_created_nodes_pt[iproc],
15944  other_proc_shd_bnd_node_pt,
15945  global_node_names,
15946  node_name_to_global_index,
15947  global_shared_node_pt);
15948 
15949  } // for (e < nhaloed_ele)
15950 
15951  } // for (bs < nshared_boundaries_with_iproc)
15952 
15953  } // if (nshared_bound_recv_proc > 0)
15954 
15955  } // if (iproc != my_rank)
15956 
15957  } // for (iproc < nproc) (general loop to send and receive info.)
15958 
15959  if (Print_timings_level_adaptation > 1)
15960  {
15961  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15962  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15963  TimingHelpers::timer() -
15964  t_start_regenerate_halo_ed_elements_nodes_first_stage;
15965 
15966  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15967  << "(first stage) [n_ele=" << n_ele << "]: "
15968  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15969  << std::endl;
15970  }
15971 
15972  // -------------------------------------------------------------------
15973  // END: Create the halo(ed) elements. Loop over the processors and
15974  // the shared boundaries within each processor. Get the elements on
15975  // the shared boundaries, mark them as haloed in this processor and
15976  // as halo on the element that will receive the info.
15977  // -------------------------------------------------------------------
15978 
15979  // -------------------------------------------------------------------
15980  // BEGIN: Create any additional haloed element, those that dont lie
15981  // on a shared boundary but that shared a node with other processor
15982  // -------------------------------------------------------------------
15983 
15984  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15985  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15986  TimingHelpers::timer();
15987 
15988  // Create any additional halo(ed) elements between processors that
15989  // have no shared boundaries but that have shared nodes
15990  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15991  iproc_currently_created_nodes_pt,
15992  global_node_names,
15993  node_name_to_global_index,
15994  global_shared_node_pt);
15995 
15996  if (Print_timings_level_adaptation > 1)
15997  {
15998  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15999  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
16000  TimingHelpers::timer() -
16001  t_start_regenerate_halo_ed_elements_nodes_second_stage;
16002 
16003  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
16004  << "(second stage) [n_ele=" << n_ele << "]: "
16005  << t_final_regenerate_halo_ed_elements_nodes_second_stage
16006  << std::endl;
16007  }
16008 
16009  // -------------------------------------------------------------------
16010  // END: Create any additional haloed element, those that dont lie on
16011  // a shared boundary but that shared a node with other processor
16012  // -------------------------------------------------------------------
16013 
16014  // Clean send and receive buffers
16015  Flat_packed_unsigneds.clear();
16016  Flat_packed_doubles.clear();
16017 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
16018  Flat_packed_unsigneds_string.clear();
16019 #endif
16020 
16021  // Document the timings for reseting halo and haloed scheme (without
16022  // classification of halo and haloed nodes)
16023  if (Print_timings_level_adaptation > 1)
16024  {
16025  tt_end = TimingHelpers::timer();
16026  oomph_info << "CPU for resetting halo-haloed scheme (without "
16027  "classification of halo and haloed nodes): "
16028  << tt_end - tt_start << std::endl;
16029  }
16030 
16031  // ------------------------------------------------------------------
16032  // BEGIN: Classify halo(ed) elements and nodes
16033  // ------------------------------------------------------------------
16034  const bool report_stats = true;
16035  DocInfo tmp_doc_info;
16036  tmp_doc_info.disable_doc();
16037 
16038  // Classify nodes
16039  this->classify_halo_and_haloed_nodes(tmp_doc_info, report_stats);
16040 
16041  // Document the timings for reseting halo and haloed scheme (with
16042  // classification of halo and haloed nodes)
16043  if (Print_timings_level_adaptation > 1)
16044  {
16045  tt_end = TimingHelpers::timer();
16046  oomph_info << "CPU for resetting halo-haloed scheme (with classification "
16047  "of halo and haloed nodes): "
16048  << tt_end - tt_start << std::endl;
16049  }
16050 
16051  // ------------------------------------------------------------------
16052  // END: Classify halo(ed) elements and nodes
16053  // ------------------------------------------------------------------
16054  }
16055 
16056  //======================================================================
16057  // Compute the alias of the nodes on shared boundaries in this
16058  // (my_rank) processor with other processors. Also compute the alias
16059  // of nodes on shared boundaries of other processors with other
16060  // processors (useful when there is an element that requires to be
16061  // sent to this (my_rank) processor because there is a shared node
16062  // between this (my_rank) and other processors BUT there is not a
16063  // shared boundary between this and the other processor
16064  // ======================================================================
16065  template<class ELEMENT>
16068  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
16069  other_proc_shd_bnd_node_pt,
16070  Vector<Vector<Vector<unsigned>>>& global_node_names,
16071  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
16072  Vector<Node*>& global_shared_node_pt)
16073  {
16074  // Get the number of processors
16075  const unsigned nproc = this->communicator_pt()->nproc();
16076  // Get the rank of the current processor
16077  const unsigned my_rank = this->communicator_pt()->my_rank();
16078  // Get the communicator of the mesh
16079  OomphCommunicator* comm_pt = this->communicator_pt();
16080 
16081  // ---------------------------------------------------------------
16082  // BEGIN: Get the elements adjacent to shared boundaries and give
16083  // a unique node number to the nodes on the shared boundaries in
16084  // this processor
16085  // ---------------------------------------------------------------
16086 
16087  // Counter for the nodes on shared boundaries in this (my_rank)
16088  // processor
16089  unsigned counter_nodes = 0;
16090  // Keep track of visited nodes
16091  std::map<Node*, bool> done_node;
16092  // ... and its local node number
16093  std::map<Node*, unsigned> local_node_number;
16094  // ... and the inverted relation from local node number to node_pt
16095  Vector<Node*> local_node_pt;
16096 
16097  // Stores the j-th node name associated with the i-th local node
16098  // on shared boundaries in this processor (my_rank)
16099  // local_node_names[i][j][0] = my_rank (this processor)
16100  // local_node_names[i][j][1] = iproc (the processor with which there
16101  // is a shared boundary)
16102  // local_node_names[i][j][2] = the shared boundary id between this
16103  // (my_rank) processor and iproc
16104  // processor
16105  // local_node_names[i][j][3] = the node index on the shared boundary
16106  // local_node_names[i][j][4] = the local node index (i). This may
16107  // be unnecessary since we alread know the
16108  // index but we also send this info. to
16109  // the root processor that is why we store
16110  // them here
16111  Vector<Vector<Vector<unsigned>>> local_node_names;
16112 
16113  // loop over the processors
16114  for (unsigned iproc = 0; iproc < nproc; iproc++)
16115  {
16116  // There are not shared boundaries with myself
16117  if (iproc != my_rank)
16118  {
16119  // Get the number of shared boundaries with iproc
16120  const unsigned n_shd_bnds_with_iproc =
16121  this->nshared_boundaries(my_rank, iproc);
16122 
16123  // Get the boundaries ids shared with iproc
16124  Vector<unsigned> bnd_shd_with_iproc =
16125  this->shared_boundaries_ids(my_rank, iproc);
16126 
16127  // Loop over the shared boundaries with processor iproc
16128  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
16129  {
16130  // Keep track of visited nodes with this shared boundary
16131  std::map<Node*, bool> done_node_shd_bnd;
16132  // The boundary id
16133  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
16134  // Get the number of element on the shared boundary
16135  const unsigned n_shd_bnd_ele =
16136  this->nshared_boundary_element(shd_bnd_id);
16137 
16138  // loop over the elements adjacent to the shared boundary
16139  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
16140  {
16141  // Get the element
16142  FiniteElement* ele_pt =
16143  this->shared_boundary_element_pt(shd_bnd_id, e);
16144 
16145  // Get the number of nodes on the element
16146  const unsigned n_nodes = ele_pt->nnode();
16147 
16148  // loop over the nodes of the current element
16149  for (unsigned n = 0; n < n_nodes; n++)
16150  {
16151  // Get the node
16152  Node* node_pt = ele_pt->node_pt(n);
16153 
16154  // Has the node been visited with this shared boundary?
16155  // And, is this a node on the shd_bnd_id shared boundary
16156  // with processor iproc?
16157  if (!done_node_shd_bnd[node_pt] &&
16158  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
16159  {
16160  // Mark the done as done with this shared boundary
16161  done_node_shd_bnd[node_pt] = true;
16162 
16163  // Get the index of the node on the shared boundary
16164  // -------------------------------------------------
16165  // Get the number of nodes on the shared boundary
16166  const unsigned n_nodes_shd_bnd =
16167  nsorted_shared_boundary_node(shd_bnd_id);
16168 
16169  // The index
16170  unsigned index = 0;
16171 
16172 #ifdef PARANOID
16173  // Flag to know if the node has been found
16174  bool found_node_on_shared_boundary = false;
16175 #endif
16176  // Loop over the nodes on the shared boundary to find
16177  // the node
16178  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16179  {
16180  // Get the k-th node on the shared boundary
16181  Node* shd_bnd_node_pt =
16182  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16183 
16184  // Is the same node?
16185  if (shd_bnd_node_pt == node_pt)
16186  {
16187  // This is the index
16188  index = k;
16189 #ifdef PARANOID
16190  // Mark as found
16191  found_node_on_shared_boundary = true;
16192 #endif
16193  break; // break
16194 
16195  } // if (shd_bnd_node_pt == node_pt)
16196 
16197  } // for (k < n_nodes_shd_bnd)
16198 
16199 #ifdef PARANOID
16200  if (!found_node_on_shared_boundary)
16201  {
16202  std::ostringstream error_message;
16203  error_message << "The index of the node on boundary ("
16204  << shd_bnd_id << ") was not found.\n"
16205  << "These are the node coordinates\n"
16206  << "(" << node_pt->x(0) << "," << node_pt->x(1)
16207  << ").\n";
16208  throw OomphLibError(error_message.str(),
16209  OOMPH_CURRENT_FUNCTION,
16210  OOMPH_EXCEPTION_LOCATION);
16211  }
16212 #endif
16213 
16214  // Create the node name
16215  Vector<unsigned> node_name(5);
16216  node_name[0] = my_rank;
16217  node_name[1] = iproc;
16218  node_name[2] = shd_bnd_id;
16219  node_name[3] = index;
16220  // The node number is filled in the following if/else
16221  // node_name[4] = ?;
16222 
16223  // Has the node already been visited?
16224  if (!done_node[node_pt])
16225  {
16226  // If not ...
16227 
16228  // Add the node to the local nodes
16229  local_node_pt.push_back(node_pt);
16230 
16231  // Assign a local node number to the node
16232  local_node_number[node_pt] = counter_nodes;
16233  // Store the local node number
16234  node_name[4] = counter_nodes;
16235  // Increase the counter of nodes
16236  counter_nodes++;
16237  // ... and mark it as visited
16238  done_node[node_pt] = true;
16239 
16240  // Push back the node name (the first
16241  // one found for this node)
16242  Vector<Vector<unsigned>> first_node_name(1);
16243  first_node_name[0] = node_name;
16244  local_node_names.push_back(first_node_name);
16245  }
16246  else
16247  {
16248  // If yes ...
16249 
16250  // Get the local node number
16251  unsigned node_number = local_node_number[node_pt];
16252 
16253  // Store the local node number
16254  node_name[4] = node_number;
16255 
16256  // Push back the node name for the
16257  // node number
16258  local_node_names[node_number].push_back(node_name);
16259  }
16260 
16261  } // Is on shared boundary?
16262 
16263  } // for (n < nnodes)
16264 
16265  } // for (e < n_shd_bnd_ele)
16266 
16267  } // for (ishd < n_shd_bnds_with_iproc)
16268 
16269  } // if (iproc != my_rank)
16270 
16271  } // for (iproc < nproc)
16272 
16273  // ---------------------------------------------------------------
16274  // END: Get the elements adjacent to shared boundaries and give
16275  // a unique node number to the nodes on the shared boundaries in
16276  // this processor
16277  // ---------------------------------------------------------------
16278 
16279  // ---------------------------------------------------------------
16280  // BEGIN: Package the names of the local nodes
16281  // ---------------------------------------------------------------
16282  // Counter for the number of names of the nodes
16283  unsigned n_total_local_names = 0;
16284  // Get the number of local nodes
16285  const unsigned n_local_nodes = local_node_names.size();
16286  // loop over the number of local nodes and get the number of names
16287  // of each node
16288  for (unsigned i = 0; i < n_local_nodes; i++)
16289  {
16290  // Get the number of names of the i-th local node
16291  const unsigned n_inode_names = local_node_names[i].size();
16292  // ... and add them to the total number of local names
16293  n_total_local_names += n_inode_names;
16294  } // for (i < n_local_nodes)
16295 
16296  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16297  // where node# is the node number on this processor (my_rank)
16298  const unsigned n_info_per_node_name = 5;
16299  // Storage for the flat package
16300  Vector<unsigned> flat_packed_send_udata(n_total_local_names *
16301  n_info_per_node_name);
16302  // A counter
16303  unsigned counter = 0;
16304  // loop over the local nodes
16305  for (unsigned i = 0; i < n_local_nodes; i++)
16306  {
16307  // Get the number of names of the i-th local node
16308  const unsigned n_inode_names = local_node_names[i].size();
16309  // loop over the names of the i-th local node
16310  for (unsigned j = 0; j < n_inode_names; j++)
16311  {
16312  // Store this processor id (my_rank)
16313  flat_packed_send_udata[counter++] = local_node_names[i][j][0];
16314  // Store the processor with which the shared boundary exist
16315  flat_packed_send_udata[counter++] = local_node_names[i][j][1];
16316  // Store the shared boundary id
16317  flat_packed_send_udata[counter++] = local_node_names[i][j][2];
16318  // Store the index of the node on the shared boundary
16319  flat_packed_send_udata[counter++] = local_node_names[i][j][3];
16320  // Store the local node number on this processor (my_rank)
16321  flat_packed_send_udata[counter++] = local_node_names[i][j][4];
16322  } // for (j < n_inode_names)
16323 
16324  } // for (i < n_local_nodes)
16325 
16326  // Reset the counter
16327  counter = 0;
16328 
16329  // The number of data that will be sent to root from this
16330  // (my_rank) processor
16331  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16332 
16333  // ---------------------------------------------------------------
16334  // END: Package the names of the local nodes
16335  // ---------------------------------------------------------------
16336  // ---------------------------------------------------------------
16337  // BEGIN: Send the data to the root processor
16338  // ---------------------------------------------------------------
16339 
16340  // The root processor is in charge of computing all the node names
16341  // of the nodes on the shared boundaries
16342 
16343  // Choose the root processor
16344  const unsigned root_processor = 0;
16345 
16346  // The vector where the root processor receives how many names
16347  // will receive from the other processors
16348  Vector<unsigned> root_n_names_per_processor(nproc);
16349 
16350  // Send the number of names that the root processor will receive
16351  // from each processor
16352  MPI_Gather(&n_total_local_names,
16353  1,
16354  MPI_UNSIGNED,
16355  &root_n_names_per_processor[0],
16356  1,
16357  MPI_UNSIGNED,
16358  root_processor,
16359  comm_pt->mpi_comm());
16360 
16361  // Get the total number of data to receive from all processor in
16362  // root
16363  unsigned root_n_total_udata_receive = 0;
16364  Vector<int> root_n_udata_to_receive(nproc, 0);
16365  for (unsigned iproc = 0; iproc < nproc; iproc++)
16366  {
16367  root_n_udata_to_receive[iproc] =
16368  root_n_names_per_processor[iproc] * n_info_per_node_name;
16369  root_n_total_udata_receive += root_n_udata_to_receive[iproc];
16370  }
16371 
16372  // Stores and compute the offsets (in root) for the data received
16373  // from each processor
16374  Vector<int> root_uoffsets_receive(nproc, 0);
16375  root_uoffsets_receive[0] = 0;
16376  for (unsigned iproc = 1; iproc < nproc; iproc++)
16377  {
16378  // Compute the offset to obtain the data from each processor
16379  root_uoffsets_receive[iproc] =
16380  root_uoffsets_receive[iproc - 1] + root_n_udata_to_receive[iproc - 1];
16381  }
16382 
16383  // Create at least one entry so we don't get a seg fault below
16384  if (flat_packed_send_udata.size() == 0)
16385  {
16386  flat_packed_send_udata.resize(1);
16387  }
16388 
16389  // Vector where to receive the info on root from all processors
16390  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16391  // Only root receive data, the others dont, then resize the
16392  // container to have at least one entry
16393  if (my_rank != root_processor)
16394  {
16395  // Create at least one entry so we don't get a seg fault below
16396  if (root_flat_packed_receive_udata.size() == 0)
16397  {
16398  root_flat_packed_receive_udata.resize(1);
16399  }
16400  } // if (my_rank!=root_processor)
16401 
16402  // Send the info. to the root processor
16403  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16404  // info. from each
16405  // processor
16406  n_udata_send_to_root, // Total number of data send
16407  // from each processor to root
16408  MPI_UNSIGNED,
16409  &root_flat_packed_receive_udata[0], // Container where
16410  // to receive the
16411  // info. from all
16412  // processors
16413  &root_n_udata_to_receive[0], // Number of data to
16414  // receive from each
16415  // processor
16416  &root_uoffsets_receive[0], // The offset to store the
16417  // info. from each
16418  // processor
16419  MPI_UNSIGNED,
16420  root_processor, // The processor that receives all the
16421  // info.
16422  comm_pt->mpi_comm());
16423 
16424  // Clear and resize the flat package to send
16425  flat_packed_send_udata.clear();
16426  flat_packed_send_udata.resize(0);
16427  // ---------------------------------------------------------------
16428  // END: Send the data to the root processor
16429  // ---------------------------------------------------------------
16430 
16431  // Container where root stores the info. that will be sent to all
16432  // processors. This includes the number of global nodes, the
16433  // number of names for each global node and the names
16434  Vector<unsigned> flat_packed_root_send_receive_udata;
16435 
16436  // ---------------------------------------------------------------
16437  // BEGIN: Unpackage the info. received on root. Compute the alias
16438  // of the nodes
16439  // ---------------------------------------------------------------
16440  if (my_rank == root_processor)
16441  {
16442  // Compute all the names of a node
16443  // root_global_node_name[x][ ][ ] Global node number
16444  // root_global_node_name[ ][x][ ] Global node names
16445  // root_global_node_name[ ][ ][x] Global node info.
16446  Vector<Vector<Vector<unsigned>>> root_global_node_names;
16447 
16448  // Store the info. extracted from the flat package sent to
16449  // root
16450  // root_local_node_names[x][ ] Node name
16451  // root_local_node_names[ ][x] Node info
16452  Vector<Vector<unsigned>> root_local_node_names;
16453 
16454  // Extract all the node names
16455  unsigned rcounter = 0;
16456  // loop over the processors
16457  for (unsigned iproc = 0; iproc < nproc; iproc++)
16458  {
16459  // Get the number of node names received from iproc
16460  const unsigned n_local_names_iproc = root_n_names_per_processor[iproc];
16461  for (unsigned i = 0; i < n_local_names_iproc; i++)
16462  {
16463  // Get the i-thnode name from iproc
16464  Vector<unsigned> node_name(n_info_per_node_name);
16465  for (unsigned j = 0; j < n_info_per_node_name; j++)
16466  {
16467  node_name[j] = root_flat_packed_receive_udata[rcounter++];
16468  }
16469 
16470  // Add the i-th node name
16471  root_local_node_names.push_back(node_name);
16472 
16473  } // for (i < n_local_names_iproc)
16474 
16475  } // for (iproc < nproc)
16476 
16477  // Get the number of node names received
16478  const unsigned n_root_local_node_names = root_local_node_names.size();
16479 
16480  // For each name of the node identify the position of its
16481  // counter-part
16482 
16483  // Given a node name on the iproc,
16484  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16485  // its counter part must live in jproc, so we look for the
16486  // node name
16487  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16488 
16489  // Store the index of the node name counter-part
16490  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16491 
16492  // Keep track of the names of nodes already done
16493  std::map<Vector<unsigned>, bool> done_name;
16494 
16495  // loop over the names of the nodes received from all
16496  // processors
16497  for (unsigned i = 0; i < n_root_local_node_names; i++)
16498  {
16499  // Get the i-th node name
16500  Vector<unsigned> node_name = root_local_node_names[i];
16501 
16502  // Check if this name node has been already done
16503  if (!done_name[node_name])
16504  {
16505  // Mark it as done
16506  done_name[node_name] = true;
16507 #ifdef PARANOID
16508  // Flag to indicate the counter-part name node was
16509  // found
16510  bool found_both_names_node = false;
16511 #endif
16512  // Find the counter-part name node (start from j+1
16513  // since all previous have been found, otherwise we
16514  // would not be here)
16515  for (unsigned j = i + 1; j < n_root_local_node_names; j++)
16516  {
16517  Vector<unsigned> node_name_r = root_local_node_names[j];
16518 
16519  // Check if this name node has been already done
16520  if (!done_name[node_name_r])
16521  {
16522  // Check whether this node is the
16523  // counter-part of the current name node
16524  if (node_name[0] == node_name_r[1] &&
16525  node_name[1] == node_name_r[0] &&
16526  node_name[2] == node_name_r[2] &&
16527  node_name[3] == node_name_r[3])
16528  {
16529  // Mark the name as node
16530  done_name[node_name_r] = true;
16531  // Store the index of the counter-part of
16532  // the current node name
16533  node_name_counter_part[i] = j;
16534  // ... and indicate the current node name
16535  // as the index of the counter-part
16536  node_name_counter_part[j] = i;
16537 #ifdef PARANOID
16538  // The node has been found
16539  found_both_names_node = true;
16540 #endif
16541  // Break the loop to find the
16542  // counter-part
16543  break;
16544  }
16545 
16546  } // if (!done_name[node_name_r])
16547 
16548  } // for (j < n_root_local_node_names)
16549 #ifdef PARANOID
16550  // Check whether the node counter-part was found
16551  if (!found_both_names_node)
16552  {
16553  std::ostringstream error_message;
16554  error_message << "The counter-part of the current name node was "
16555  << "not found,\nthe current node name is:\n"
16556  << "iproc:(" << node_name[0] << ")\n"
16557  << "jproc:(" << node_name[1] << ")\n"
16558  << "ishd_bnd:(" << node_name[2] << ")\n"
16559  << "index:(" << node_name[3] << ")\n";
16560  throw OomphLibError(error_message.str(),
16561  OOMPH_CURRENT_FUNCTION,
16562  OOMPH_EXCEPTION_LOCATION);
16563  } // if (!found_both_names_node)
16564 #endif
16565 
16566  } // if (!done_name[node_name])
16567 
16568  } // for (i < n_root_local_node_names)
16569 
16570  // -----------------------------------------------------------
16571  // Look for all the names of each node received and store them
16572  // in the "global node names" container
16573 
16574  // Keep track of the names of nodes already done
16575  done_name.clear();
16576  // loop over the names of the nodes received from all
16577  // processors
16578  for (unsigned i = 0; i < n_root_local_node_names; i++)
16579  {
16580  // Get the i-th node name
16581  Vector<unsigned> node_name = root_local_node_names[i];
16582 
16583  // Check if this name node has been already done
16584  if (!done_name[node_name])
16585  {
16586  // Store all the names of the current node
16587  Vector<Vector<unsigned>> all_node_names;
16588 
16589  // Add the name of the node as the initial node name
16590  all_node_names.push_back(node_name);
16591 
16592  // Get the index of the counter-part
16593  unsigned idx_c = node_name_counter_part[i];
16594  // Get the counter-part of the node name
16595  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16596 
16597  // Add the name of the counter-part of the node
16598  all_node_names.push_back(node_name_r);
16599  // We do not mark it as done since we are interested in
16600  // the names that the counter-part may generate
16601 
16602  // Get the number of names for the current node (two at
16603  // the first time)
16604  unsigned n_current_names = all_node_names.size();
16605  // Counter to ensure to visit all the names of the current
16606  // node
16607  unsigned icounter = 0;
16608 
16609  // Visit all the names of the current node
16610  while (icounter < n_current_names)
16611  {
16612  // Get the current node name
16613  Vector<unsigned> current_node_name = all_node_names[icounter];
16614 
16615  // Search for other names for the current name of the
16616  // node, but first check if this has been already
16617  // visited
16618  if (!done_name[current_node_name])
16619  {
16620  // Mark it as done
16621  done_name[current_node_name] = true;
16622 
16623  // loop over the names of the nodes (start from the
16624  // j+1 position, all previous node names have all
16625  // their names already assigned)
16626  for (unsigned j = i + 1; j < n_root_local_node_names; j++)
16627  {
16628  // Get the j-th node name
16629  Vector<unsigned> other_node_name = root_local_node_names[j];
16630 
16631  // Is this name node already done
16632  if (!done_name[other_node_name])
16633  {
16634  // Is this another name for the current name node?
16635  if ((current_node_name[0] == other_node_name[0]) &&
16636  (current_node_name[4] == other_node_name[4]))
16637  {
16638  // Mark it as done. If we search again using the
16639  // "other_node_name" as the current node name we
16640  // are not going to find new nodes to add
16641  done_name[other_node_name] = true;
16642  // Before adding it check that it is not already
16643  // part of the names of the node
16644  Vector<Vector<unsigned>>::iterator it =
16645  std::find(all_node_names.begin(),
16646  all_node_names.end(),
16647  other_node_name);
16648  if (it == all_node_names.end())
16649  {
16650  all_node_names.push_back(other_node_name);
16651  // Get the index of the counter-part
16652  unsigned k = node_name_counter_part[j];
16653  // Get the counter-part of the node name
16654  Vector<unsigned> other_node_name_r =
16655  root_local_node_names[k];
16656  // Add the name of the counter-part of the
16657  // node only if it has not been previously
16658  // done
16659  if (!done_name[other_node_name_r])
16660  {
16661  all_node_names.push_back(other_node_name_r);
16662  }
16663  }
16664 
16665  } // // Is this another name for the current name
16666  // node?
16667 
16668  } // if (!done_name[other_node_name])
16669 
16670  } // for (j < n_root_local_node_names)
16671 
16672  } // if (!done_name[current_node_name])
16673 
16674  // Get the number of names
16675  n_current_names = all_node_names.size();
16676  // Increase the icounter to indicate we have visited the
16677  // current name of the node
16678  icounter++;
16679 
16680  } // while(icounter < n_current_names)
16681 
16682  // We now have all the names for the i-th global node
16683  root_global_node_names.push_back(all_node_names);
16684 
16685  } // if (!done_name[node_name])
16686 
16687  } // for (i < n_root_local_node_names)
16688 
16689  // -------------------------------------------------------------
16690  // Prepare the info to be sent to all processors. The number
16691  // of global nodes, the number of names for each global node,
16692  // and their respective names
16693  // -------------------------------------------------------------
16694 
16695  // Clear the container
16696  flat_packed_root_send_receive_udata.clear();
16697  // Get the number of global nodes
16698  const unsigned n_global_nodes = root_global_node_names.size();
16699  // ... and store this info. to be sent from root to all
16700  // processors
16701  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16702 
16703  // loop over the nodes
16704  for (unsigned i = 0; i < n_global_nodes; i++)
16705  {
16706  // Get the names of the i-th global node
16707  Vector<Vector<unsigned>> global_inode_names = root_global_node_names[i];
16708  // Get the number of names for the i-th global node
16709  const unsigned n_names_global_inode = global_inode_names.size();
16710  // ... and store this info. to be sent from root to all
16711  // processors
16712  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16713  // loop over the names of the global i-th node
16714  for (unsigned j = 0; j < n_names_global_inode; j++)
16715  {
16716  // loop over the info. associated with each name
16717  for (unsigned k = 0; k < n_info_per_node_name; k++)
16718  {
16719  // Store the name info. of the current name in the
16720  // container to be sent from root to all processors
16721  flat_packed_root_send_receive_udata.push_back(
16722  global_inode_names[j][k]);
16723  } // for (k < n_info_per_node_name)
16724 
16725  } // for (j < n_names_inode)
16726 
16727  } // for (i < n_global_nodes)
16728 
16729  } // if (my_rank == root_processor)
16730 
16731  // ----------------------------------------------------------------
16732  // END: Unpackage the info. received on root. Compute the alias
16733  // of the nodes and prepare the info. to be sent back from
16734  // root to all processors
16735  // ----------------------------------------------------------------
16736 
16737  // ---------------------------------------------------------------
16738  // BEGIN: Send the info. back to all processors, unpackage the
16739  // info. and create the map from node name to global node
16740  // index
16741  // ---------------------------------------------------------------
16742  // The number of data that root send to other processors.
16743  unsigned root_n_udata_sent_to_all_proc =
16744  flat_packed_root_send_receive_udata.size();
16745 
16746  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16747  // receive
16748  1,
16749  MPI_UNSIGNED,
16750  root_processor,
16751  comm_pt->mpi_comm());
16752 
16753  // Resize the container if this is a processor that receives data
16754  if (my_rank != root_processor)
16755  {
16756  flat_packed_root_send_receive_udata.resize(root_n_udata_sent_to_all_proc);
16757  }
16758 
16759  // Send the info. from root and receive it on all processors
16760  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16761  // from root to
16762  // all
16763  // processors
16764  root_n_udata_sent_to_all_proc, // Number of data sent
16765  // from root to each
16766  // procesor
16767  MPI_UNSIGNED,
16768  root_processor, // The processor that sends all the info.
16769  comm_pt->mpi_comm());
16770 
16771  // Counter to extract the info.
16772  counter = 0;
16773  // Read the number of global nodes
16774  const unsigned n_global_nodes =
16775  flat_packed_root_send_receive_udata[counter++];
16776  // Store the global names of the nodes
16777  // global_node_name[x][ ][ ] Global node number
16778  // global_node_name[ ][x][ ] Global node names
16779  // global_node_name[ ][ ][x] Global node info.
16780  // Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16781  // Resize the input vector
16782  global_node_names.resize(n_global_nodes);
16783  // Now loop until all global nodes info. has been read
16784  unsigned n_read_global_nodes = 0;
16785  while (n_read_global_nodes < n_global_nodes)
16786  {
16787  // Read the number of names for the current global node
16788  const unsigned n_names_global_inode =
16789  flat_packed_root_send_receive_udata[counter++];
16790  // Counter for the global node
16791  const unsigned i = n_read_global_nodes;
16792  // Resize the container
16793  global_node_names[i].resize(n_names_global_inode);
16794  // loop over the names of the global inode
16795  for (unsigned j = 0; j < n_names_global_inode; j++)
16796  {
16797  // Resize the container
16798  global_node_names[i][j].resize(n_info_per_node_name);
16799  // loop over the info. of the j-th node name of the i-th
16800  // global node
16801  for (unsigned k = 0; k < n_info_per_node_name; k++)
16802  {
16803  // Read the k-th node info. from the j-th node name of
16804  // the i-th global node
16805  global_node_names[i][j][k] =
16806  flat_packed_root_send_receive_udata[counter++];
16807 
16808  } // for (k < n_info_per_node_name)
16809 
16810  // Create the map from the node name to the global node
16811  // index
16812  Vector<unsigned> node_name(n_info_per_node_name - 1);
16813  node_name[0] = global_node_names[i][j][0];
16814  node_name[1] = global_node_names[i][j][1];
16815  node_name[2] = global_node_names[i][j][2];
16816  node_name[3] = global_node_names[i][j][3];
16817  // Do not add the local index since it will not longer be
16818  // used. Additionally, we will not know the local node
16819  // index outside this method
16820  // node_name[4] = global_node_names[i][j][4];
16821  node_name_to_global_index[node_name] = i;
16822 
16823  } // for (j < n_names_global_inode)
16824 
16825  // Increase the counter for read global nodes
16826  n_read_global_nodes++;
16827 
16828  } // while (n_read_global_nodes < n_global_nodes)
16829 
16830 #ifdef PARANOID
16831  // Check we have read all the info.
16832  if (counter != root_n_udata_sent_to_all_proc)
16833  {
16834  std::ostringstream error_stream;
16835  error_stream
16836  << "The info. received from root regarding the global names of "
16837  << "the nodes\nwas not completely read.\n"
16838  << "The number of data sent/received from root is: ("
16839  << root_n_udata_sent_to_all_proc << ")\n"
16840  << "The number of data read from the received info. is: (" << counter
16841  << ")\n\n";
16842  throw OomphLibError(
16843  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
16844  } // if (counter != root_n_udata_sent_to_all_proc)
16845 #endif
16846 
16847  // ---------------------------------------------------------------
16848  // END: Send the info. back to all processors, unpackage the info.
16849  // and create the map from node name to global node index
16850  // ---------------------------------------------------------------
16851 
16852  // ---------------------------------------------------------------
16853  // BEGIN: Add the info. from the global node names into the
16854  // info. of the local node names. We do this because the
16855  // local node names have pointers to the nodes.
16856  // Additionally, create a map from the node name to the
16857  // index of its global node
16858  // ---------------------------------------------------------------
16859 
16860  // Resize the global shared node pointers container
16861  global_shared_node_pt.resize(n_global_nodes, 0);
16862 
16863  // loop over the number of global nodes
16864  for (unsigned i = 0; i < n_global_nodes; i++)
16865  {
16866  // Flag to indicate that the iglobal node is part of the nodes
16867  // on the current processor
16868  bool is_this_a_local_node_name = false;
16869  unsigned local_node_number;
16870  // Get the number of names of the i-th global node
16871  const unsigned n_names_global_inode = global_node_names[i].size();
16872  // loop over the names of the i-th global node
16873  for (unsigned j = 0; j < n_names_global_inode; j++)
16874  {
16875  // Get the node name info.
16876  const unsigned iproc = global_node_names[i][j][0];
16877  local_node_number = global_node_names[i][j][4];
16878 
16879  // Check if this node name lives on this processor
16880  if (my_rank == iproc)
16881  {
16882  // The node is part of the local node names
16883  is_this_a_local_node_name = true;
16884  // Break
16885  break;
16886  } // if (my_rank == iproc)
16887 
16888  } // for (j < n_names_global_inode)
16889 
16890  // If the node is part of the local nodes then add the
16891  // additional names of the node in the local container
16892  if (is_this_a_local_node_name)
16893  {
16894 #ifdef PARANOID
16895  // Check that the global node include at least all the names
16896  // of the node on this processor
16897  const unsigned n_names_local_node =
16898  local_node_names[local_node_number].size();
16899  unsigned n_names_found_on_global_name_node = 0;
16900 #endif
16901 
16902  // Add the pointer of the node into the global shared node
16903  // pointers container
16904  global_shared_node_pt[i] = local_node_pt[local_node_number];
16905 
16906  // Add all the global names of the node onto the local node
16907  // names
16908 
16909  // loop again over the names of the i-th global node
16910  for (unsigned j = 0; j < n_names_global_inode; j++)
16911  {
16912  // Get the node name info.
16913  const unsigned iproc = global_node_names[i][j][0];
16914 
16915  // Is this a node name on this processor?
16916  if (iproc != my_rank)
16917  {
16918  // Add the name
16919  local_node_names[local_node_number].push_back(
16920  global_node_names[i][j]);
16921  }
16922 #ifdef PARANOID
16923  else
16924  {
16925  const unsigned jproc = global_node_names[i][j][1];
16926  const unsigned ishd_bnd = global_node_names[i][j][2];
16927  const unsigned idx = global_node_names[i][j][3];
16928  const unsigned n_local_node = global_node_names[i][j][4];
16929  // loop over the names of the local node
16930  for (unsigned k = 0; k < n_names_local_node; k++)
16931  {
16932  if ((local_node_names[local_node_number][k][0] == iproc) &&
16933  (local_node_names[local_node_number][k][1] == jproc) &&
16934  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16935  (local_node_names[local_node_number][k][3] == idx) &&
16936  (local_node_names[local_node_number][k][4] == n_local_node))
16937  {
16938  // Increase the number of local nodes found on the
16939  // global nodes
16940  n_names_found_on_global_name_node++;
16941  } // found global node on local nodes
16942 
16943  } // for (k < n_names_local_node)
16944 
16945  } // if (iproc != my_rank)
16946 #endif
16947 
16948  } // for (j < n_names_global_inode)
16949 
16950 #ifdef PARANOID
16951  // The number of local nodes names must be the same as the the
16952  // number of global nodes names associated with this processor
16953  // (my_rank, that start with iproc = my_rank)
16954  if (n_names_local_node != n_names_found_on_global_name_node)
16955  {
16956  std::ostringstream error_stream;
16957  error_stream << "The local node names corresponding to the local "
16958  << "node (" << local_node_number << ") were\n"
16959  << "not found on the global node names.\n\n"
16960  << "These are the names of the local node\n"
16961  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16962  for (unsigned k = 0; k < n_names_local_node; k++)
16963  {
16964  error_stream << "Name(" << k
16965  << "): " << local_node_names[local_node_number][k][0]
16966  << ", " << local_node_names[local_node_number][k][1]
16967  << ", " << local_node_names[local_node_number][k][2]
16968  << ", " << local_node_names[local_node_number][k][3]
16969  << ", " << local_node_names[local_node_number][k][4]
16970  << "\n";
16971  }
16972 
16973  error_stream << "\n\nThese are the names of the global node\n"
16974  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16975  for (unsigned k = 0; k < n_names_global_inode; k++)
16976  {
16977  error_stream << "Name(" << k << "): " << global_node_names[i][k][0]
16978  << ", " << global_node_names[i][k][1] << ", "
16979  << global_node_names[i][k][2] << ", "
16980  << global_node_names[i][k][3] << ", "
16981  << global_node_names[i][k][4] << "\n";
16982  }
16983 
16984  throw OomphLibError(error_stream.str(),
16985  OOMPH_CURRENT_FUNCTION,
16986  OOMPH_EXCEPTION_LOCATION);
16987  }
16988 #endif
16989 
16990  } // if (is_this_a_local_node_name)
16991 
16992  } // for (i < n_global_nodes)
16993 
16994  // ---------------------------------------------------------------
16995  // END: Add the info. from the global node names into the info.
16996  // of the local node names. We do this because the local
16997  // node names have pointers to the nodes
16998  // ---------------------------------------------------------------
16999 
17000  // ---------------------------------------------------------------
17001  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
17002  // the local nodes.
17003  // ---------------------------------------------------------------
17004 
17005  // Loop over the local nodes and fill the
17006  // other_proc_shd_bnd_node_pt container with the corresponding
17007  // info. NOTE: We are using the old size of the local node names,
17008  // before adding the names of the global nodes so we only loop
17009  // over the local nodes and not global.
17010 
17011  // Compute the local shared boudary id
17012  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
17013 
17014  // loop over the local nodes names
17015  for (unsigned i = 0; i < n_local_nodes; i++)
17016  {
17017  // Get the number of names for the i-th local node
17018  const unsigned n_names = local_node_names[i].size();
17019  // Get a pointer to the first name of the node found on this
17020  // processor (this ensures that the node lives on this
17021  // processor)
17022  Node* node_pt = local_node_pt[i];
17023  // loop over the names of the i-th local node and add an entry
17024  // to the other_proc_shd_bnd_node_pt structure
17025  for (unsigned j = 0; j < n_names; j++)
17026  {
17027  // Get the node name info.
17028  const unsigned iproc = local_node_names[i][j][0];
17029  const unsigned jproc = local_node_names[i][j][1];
17030  const unsigned ishd_bnd =
17031  local_node_names[i][j][2] - initial_shd_bnd_id;
17032  const unsigned index = local_node_names[i][j][3];
17033  // We can ignore the last entry, it was just used to compute
17034  // the global node number by the root processor
17035 
17036  // Get the smallest processor number
17037  if (iproc < jproc)
17038  {
17039  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index] = node_pt;
17040  }
17041  else
17042  {
17043  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index] = node_pt;
17044  }
17045 
17046  } // for (j < n_names)
17047 
17048  } // for (i < n_local_node_names)
17049 
17050  // ---------------------------------------------------------------
17051  // END: Fill the data structure other_proc_shd_bnd_node_pt with
17052  // the local nodes.
17053  // ---------------------------------------------------------------
17054  }
17055 
17056  //======================================================================
17057  // Get the original boundaries to which is associated each
17058  // shared node, and send the info. to the related processors. We
17059  // need to do this so that at the reset of halo(ed) info. stage,
17060  // the info. is updated
17061  template<class ELEMENT>
17063  Vector<Vector<Vector<unsigned>>>& global_node_names,
17064  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
17065  Vector<Node*>& global_shared_node_pt)
17066  {
17067  // Get the rank and number of processors
17068  const unsigned nproc = this->communicator_pt()->nproc();
17069  const unsigned my_rank = this->communicator_pt()->my_rank();
17070 
17071  // The number of nodes on shared boundaries
17072  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
17073  // ---------------------------------------------------------
17074  // BEGIN: Get the shared nodes between each of processors
17075  // ---------------------------------------------------------
17076 
17077  // Store the nodes on shared boundaries in this processor with other
17078  // processors
17079  Vector<std::set<Node*>> node_on_shd_bnd_pt(nproc);
17080 
17081  // A map to get access to the global shared node number from the
17082  // node pointer
17083  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
17084 
17085  // loop over the global nodes names and get only those in this
17086  // processor
17087  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
17088  {
17089  // Get the number of names of the current node on shared
17090  // boundaries
17091  const unsigned n_names = global_node_names[i].size();
17092  // loop over the names
17093  for (unsigned j = 0; j < n_names; j++)
17094  {
17095  // Store the node name
17096  Vector<unsigned> node_name(4);
17097  node_name[0] = global_node_names[i][j][0];
17098  node_name[1] = global_node_names[i][j][1];
17099  node_name[2] = global_node_names[i][j][2];
17100  node_name[3] = global_node_names[i][j][3];
17101 
17102  // Check whether the node is in the current processor
17103  if (node_name[0] == my_rank)
17104  {
17105  // Check with which processor the node is shared
17106  const unsigned jproc = node_name[1];
17107 
17108 #ifdef PARANOID
17109  std::map<Vector<unsigned>, unsigned>::iterator it =
17110  node_name_to_global_index.find(node_name);
17111  if (it != node_name_to_global_index.end())
17112  {
17113  // Check whether the global node index correspond with that
17114  // of the current global node name
17115  if (i != (*it).second)
17116  {
17117  std::ostringstream error_message;
17118  error_message
17119  << "The global node number " << (*it).second
17120  << ") obtained from the current node\n"
17121  << "name is not the same as the current node number (" << i
17122  << ").\n\n"
17123  << "Node name:\n"
17124  << "iproc:" << node_name[0] << "\n"
17125  << "jproc:" << node_name[1] << "\n"
17126  << "shd_bnd_id:" << node_name[2] << "\n"
17127  << "index:" << node_name[3] << "\n\n";
17128  throw OomphLibError(error_message.str(),
17129  OOMPH_CURRENT_FUNCTION,
17130  OOMPH_EXCEPTION_LOCATION);
17131  }
17132  }
17133  else
17134  {
17135  std::ostringstream error_message;
17136  error_message
17137  << "The node name is not registerd as living in this processor.\n"
17138  << "Node name:\n"
17139  << "iproc:" << node_name[0] << "\n"
17140  << "jproc:" << node_name[1] << "\n"
17141  << "shd_bnd_id:" << node_name[2] << "\n"
17142  << "index:" << node_name[3] << "\n\n";
17143  throw OomphLibError(error_message.str(),
17144  OOMPH_CURRENT_FUNCTION,
17145  OOMPH_EXCEPTION_LOCATION);
17146  }
17147 
17148 #endif // #ifdef PARANOID
17149 
17150  // Get the node pointer
17151  Node* node_pt = global_shared_node_pt[i];
17152 
17153 #ifdef PARANOID
17154  if (node_pt == 0)
17155  {
17156  std::ostringstream error_message;
17157  error_message << "There is not global shared node within this\n"
17158  << "global node number (" << i
17159  << "). The global shared\n"
17160  << "node pointer is null\n\n";
17161  throw OomphLibError(error_message.str(),
17162  OOMPH_CURRENT_FUNCTION,
17163  OOMPH_EXCEPTION_LOCATION);
17164  }
17165 #endif // #ifdef PARANOID
17166 
17167  // Add the node to the nodes on shared boundaries in this
17168  // processor
17169  node_on_shd_bnd_pt[jproc].insert(node_pt);
17170 
17171  // And store the global node index
17172  node_pt_to_global_shd_bnd_index[node_pt] = i;
17173 
17174  } // if (node_name[0]==my_rank)
17175  else if (node_name[1] == my_rank)
17176  {
17177  // Check with which processor the node is shared
17178  const unsigned jproc = node_name[0];
17179 
17180 #ifdef PARANOID
17181  std::map<Vector<unsigned>, unsigned>::iterator it =
17182  node_name_to_global_index.find(node_name);
17183  if (it != node_name_to_global_index.end())
17184  {
17185  // Check whether the global node index correspond with that
17186  // of the current global node name
17187  if (i != (*it).second)
17188  {
17189  std::ostringstream error_message;
17190  error_message
17191  << "The global node number " << (*it).second
17192  << ") obtained from the current node\n"
17193  << "name is not the same as the current node number (" << i
17194  << ").\n\n"
17195  << "Node name:\n"
17196  << "iproc:" << node_name[0] << "\n"
17197  << "jproc:" << node_name[1] << "\n"
17198  << "shd_bnd_id:" << node_name[2] << "\n"
17199  << "index:" << node_name[3] << "\n\n";
17200  throw OomphLibError(error_message.str(),
17201  OOMPH_CURRENT_FUNCTION,
17202  OOMPH_EXCEPTION_LOCATION);
17203  }
17204  }
17205  else
17206  {
17207  std::ostringstream error_message;
17208  error_message
17209  << "The node name is not registerd as living in this processor.\n"
17210  << "Node name:\n"
17211  << "iproc:" << node_name[0] << "\n"
17212  << "jproc:" << node_name[1] << "\n"
17213  << "shd_bnd_id:" << node_name[2] << "\n"
17214  << "index:" << node_name[3] << "\n\n";
17215  throw OomphLibError(error_message.str(),
17216  OOMPH_CURRENT_FUNCTION,
17217  OOMPH_EXCEPTION_LOCATION);
17218  }
17219 
17220 #endif // #ifdef PARANOID
17221 
17222  // Get the node pointer
17223  Node* node_pt = global_shared_node_pt[i];
17224 
17225 #ifdef PARANOID
17226  if (node_pt == 0)
17227  {
17228  std::ostringstream error_message;
17229  error_message << "There is not global shared node within this\n"
17230  << "global node number (" << i
17231  << "). The global shared\n"
17232  << "node pointer is null\n\n";
17233  throw OomphLibError(error_message.str(),
17234  OOMPH_CURRENT_FUNCTION,
17235  OOMPH_EXCEPTION_LOCATION);
17236  }
17237 #endif // #ifdef PARANOID
17238 
17239  // Add the node to the nodes on shared boundaries in this
17240  // processor
17241  node_on_shd_bnd_pt[jproc].insert(node_pt);
17242 
17243  // And store the global node index
17244  node_pt_to_global_shd_bnd_index[node_pt] = i;
17245  }
17246 
17247  } // for (j < n_names)
17248 
17249  } // for (i < n_nodes_on_shd_bnds)
17250 
17251  // ---------------------------------------------------------
17252  // END: Get the shared nodes between each of processors
17253  // ---------------------------------------------------------
17254 
17255  // ---------------------------------------------------------
17256  // BEGIN: Get the original boundaries associated to each
17257  // node on a shared boundary
17258  // ---------------------------------------------------------
17259 
17260  // Store the global shared node number
17261  Vector<Vector<unsigned>> global_node_on_shared_bound(nproc);
17262  // Store the boundaries associated with the global shared node
17263  // number
17264  Vector<Vector<Vector<unsigned>>> global_node_original_boundaries(nproc);
17265  // Store the zeta boundary coordinate of the nodes on original
17266  // boundaries
17267  Vector<Vector<Vector<double>>> global_node_zeta_coordinate(nproc);
17268 
17269  // loop over the processors
17270  for (unsigned iproc = 0; iproc < nproc; iproc++)
17271  {
17272  // Get the nodes added to be shared with the iproc processor
17273  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17274 
17275  // loop over the nodes
17276  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17277  it != nodes_shared_pt.end();
17278  it++)
17279  {
17280  // Get the node
17281  Node* node_pt = (*it);
17282  // Store the boundaries on which it is stored
17283  Vector<unsigned> on_original_boundaries;
17284  // For each boundary get the corresponding z value of the node
17285  // on the boundary
17286  Vector<double> zeta_coordinate;
17287  // Get the number of boudandaries
17288  const unsigned n_bnd = this->initial_shared_boundary_id();
17289  // loop over the boundaries and register the boundaries to which
17290  // it is associated
17291  for (unsigned bb = 0; bb < n_bnd; bb++)
17292  {
17293  // Is the node on original boundary bb?
17294  if (node_pt->is_on_boundary(bb))
17295  {
17296  // Then save it as being on boundary bb
17297  on_original_boundaries.push_back(bb);
17298  // Get the boundary coordinate
17299  Vector<double> zeta(1);
17300  node_pt->get_coordinates_on_boundary(bb, zeta);
17301  // Save the boundary coordinate
17302  zeta_coordinate.push_back(zeta[0]);
17303  }
17304 
17305  } // for (bb < n_bnd)
17306 
17307  // Is the node on an original boundary
17308  if (on_original_boundaries.size() > 0)
17309  {
17310  // Get the global shared node number
17311  std::map<Node*, unsigned>::iterator it_index =
17312  node_pt_to_global_shd_bnd_index.find(node_pt);
17313 #ifdef PARANOID
17314  if (it_index == node_pt_to_global_shd_bnd_index.end())
17315  {
17316  std::ostringstream error_message;
17317  error_message
17318  << "We could not find the global shared node index associated\n"
17319  << "with the node pointer with vertices coordinates:\n"
17320  << "(" << node_pt->x(0) << ", " << node_pt->x(1) << ")\n\n";
17321  throw OomphLibError(error_message.str(),
17322  OOMPH_CURRENT_FUNCTION,
17323  OOMPH_EXCEPTION_LOCATION);
17324  }
17325 #endif
17326  // The global shared node index
17327  const unsigned global_shared_node_number = (*it_index).second;
17328  // Store the global shared node number
17329  global_node_on_shared_bound[iproc].push_back(
17330  global_shared_node_number);
17331  // And store the original boundaries to which it is associated
17332  global_node_original_boundaries[iproc].push_back(
17333  on_original_boundaries);
17334  // and the corresponding zeta coordinate
17335  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17336  }
17337 
17338  } // loop over nodes on shared boundaries with iproc
17339 
17340  } // for (iproc < nproc)
17341 
17342  // ---------------------------------------------------------
17343  // END: Get the original boundaries associated to each
17344  // node on a shared boundary
17345  // ---------------------------------------------------------
17346 
17347  // ---------------------------------------------------------
17348  // BEGIN: Send the info. to the corresponding processors,
17349  // package the info, send it and receive it in the
17350  // corresponding processor, unpackage and set the
17351  // boundaries associated with the received nodes
17352  // ---------------------------------------------------------
17353 
17354  // Get the communicator of the mesh
17355  OomphCommunicator* comm_pt = this->communicator_pt();
17356 
17357  // Set MPI info
17358  MPI_Status status;
17359  MPI_Request request;
17360 
17361  // loop over the processors
17362  for (unsigned iproc = 0; iproc < nproc; iproc++)
17363  {
17364  // The number of nodes shared between the pair of processors
17365  const unsigned n_shd_nodes_my_rank_iproc =
17366  node_on_shd_bnd_pt[iproc].size();
17367 
17368  // Are there shared nodes between these pair of processors
17369  // (my_rank, iproc)? Also ensure not to send info. within myself
17370  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17371  {
17372  // The flat package to send the info, to the iproc processor
17373  Vector<unsigned> flat_package_unsigned_send;
17374  // The very first entry is the number of nodes shared by the
17375  // pair of processors (my_rank, iproc)
17376  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17377 
17378  // Get the number of shared nodes on original boundaries
17379  const unsigned n_global_shared_node_on_original_boundary =
17380  global_node_on_shared_bound[iproc].size();
17381 
17382  // The second data is the number of shared nodes on original
17383  // boundaries
17384  flat_package_unsigned_send.push_back(
17385  n_global_shared_node_on_original_boundary);
17386 
17387  // ... also send the zeta coordinates associated with the
17388  // original boundaries
17389  Vector<double> flat_package_double_send;
17390 
17391  // loop over the nodes shared between this pair of processors
17392  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17393  {
17394  // Get the global shared node index
17395  const unsigned global_shared_node_index =
17396  global_node_on_shared_bound[iproc][i];
17397 
17398  // Put in the package the shared node index of the current
17399  // node
17400  flat_package_unsigned_send.push_back(global_shared_node_index);
17401 
17402  // Get the original boundaries to which the node is associated
17403  Vector<unsigned> on_original_boundaries =
17404  global_node_original_boundaries[iproc][i];
17405 
17406  // Get the associated zeta boundary coordinates
17407  Vector<double> zeta_coordinate =
17408  global_node_zeta_coordinate[iproc][i];
17409 
17410  // Get the number of original boundaries to which the node is
17411  // associated
17412  const unsigned n_original_boundaries = on_original_boundaries.size();
17413 
17414  // Put in the package the number of original boundaries the
17415  // node is associated
17416  flat_package_unsigned_send.push_back(n_original_boundaries);
17417 
17418  // loop over the original boundaries ids and include them in
17419  // the package
17420  for (unsigned j = 0; j < n_original_boundaries; j++)
17421  {
17422  // Put in the package each of the original boundaries to
17423  // which it is associated
17424  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17425  // The zeta coordinate on the boundary
17426  flat_package_double_send.push_back(zeta_coordinate[j]);
17427  } // for (j < n_original_boundaries)
17428 
17429  } // for (i < n_global_shared_node_on_original_boundary)
17430 
17431  // Send data UNSIGNED -----------------------------------------
17432  // Get the size of the package to communicate to the iproc
17433  // processor
17434  const unsigned n_udata_send = flat_package_unsigned_send.size();
17435  int n_udata_send_int = n_udata_send;
17436 
17437  // Send/receive data to/from iproc processor
17438  MPI_Isend(&n_udata_send_int,
17439  1,
17440  MPI_UNSIGNED,
17441  iproc,
17442  1,
17443  comm_pt->mpi_comm(),
17444  &request);
17445 
17446  int n_udata_received_int = 0;
17447  MPI_Recv(&n_udata_received_int,
17448  1,
17449  MPI_UNSIGNED,
17450  iproc,
17451  1,
17452  comm_pt->mpi_comm(),
17453  &status);
17454  MPI_Wait(&request, MPI_STATUS_IGNORE);
17455 
17456  if (n_udata_send != 0)
17457  {
17458  MPI_Isend(&flat_package_unsigned_send[0],
17459  n_udata_send,
17460  MPI_UNSIGNED,
17461  iproc,
17462  2,
17463  comm_pt->mpi_comm(),
17464  &request);
17465  }
17466 
17467  const unsigned n_udata_received =
17468  static_cast<unsigned>(n_udata_received_int);
17469 
17470  // Where to receive the data from the iproc processor
17471  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17472 
17473  if (n_udata_received != 0)
17474  {
17475  MPI_Recv(&flat_package_unsigned_receive[0],
17476  n_udata_received,
17477  MPI_UNSIGNED,
17478  iproc,
17479  2,
17480  comm_pt->mpi_comm(),
17481  &status);
17482  }
17483 
17484  if (n_udata_send != 0)
17485  {
17486  MPI_Wait(&request, MPI_STATUS_IGNORE);
17487  }
17488 
17489  // Send data DOUBLE -----------------------------------------
17490  // Get the size of the package to communicate to the iproc
17491  // processor
17492  const unsigned n_ddata_send = flat_package_double_send.size();
17493  int n_ddata_send_int = n_ddata_send;
17494 
17495  // Send/receive data to/from iproc processor
17496  MPI_Isend(&n_ddata_send_int,
17497  1,
17498  MPI_UNSIGNED,
17499  iproc,
17500  1,
17501  comm_pt->mpi_comm(),
17502  &request);
17503 
17504  int n_ddata_received_int = 0;
17505  MPI_Recv(&n_ddata_received_int,
17506  1,
17507  MPI_UNSIGNED,
17508  iproc,
17509  1,
17510  comm_pt->mpi_comm(),
17511  &status);
17512  MPI_Wait(&request, MPI_STATUS_IGNORE);
17513 
17514  if (n_ddata_send != 0)
17515  {
17516  MPI_Isend(&flat_package_double_send[0],
17517  n_ddata_send,
17518  MPI_DOUBLE,
17519  iproc,
17520  2,
17521  comm_pt->mpi_comm(),
17522  &request);
17523  }
17524 
17525  const unsigned n_ddata_received =
17526  static_cast<unsigned>(n_ddata_received_int);
17527 
17528  // Where to receive the data from the iproc processor
17529  Vector<double> flat_package_double_receive(n_ddata_received);
17530 
17531  if (n_ddata_received != 0)
17532  {
17533  MPI_Recv(&flat_package_double_receive[0],
17534  n_ddata_received,
17535  MPI_DOUBLE,
17536  iproc,
17537  2,
17538  comm_pt->mpi_comm(),
17539  &status);
17540  }
17541 
17542  if (n_ddata_send != 0)
17543  {
17544  MPI_Wait(&request, MPI_STATUS_IGNORE);
17545  }
17546 
17547  // Unpackage -------------------------------------------------
17548  // ... and associate the nodes to the corresponding original
17549  // boundaries
17550 
17551  // The number of nodes to be received
17552  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17553 
17554  // Increase and decrease the number of received shared nodes to
17555  // avoid the warning when compiling without PARANOID
17556  n_shared_nodes_received++;
17557  n_shared_nodes_received--;
17558 
17559 #ifdef PARANOID
17560  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17561  {
17562  std::ostringstream error_message;
17563  error_message
17564  << "The number of shared nodes between the pair of processors is\n"
17565  << "not the same\n"
17566  << "N.shared nodes proc (" << my_rank << ") with proc (" << iproc
17567  << "): (" << n_shd_nodes_my_rank_iproc << "\n"
17568  << "N.shared nodes proc (" << iproc << ") with proc (" << my_rank
17569  << "): (" << n_shared_nodes_received << "\n\n"
17570  << "You should have got the same error in proc: (" << iproc
17571  << ")\n\n";
17572  throw OomphLibError(error_message.str(),
17573  OOMPH_CURRENT_FUNCTION,
17574  OOMPH_EXCEPTION_LOCATION);
17575  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17576 #endif
17577 
17578  // Skip the number of nodes on shared boundaries on original
17579  // boundaries received (that is why next lines are commented)
17580 
17581  // The number of nodes on shared boundaries on original
17582  // boundaries
17583  // const unsigned n_shared_nodes_on_original_boundaries_received =
17584  // flat_package_unsigned_receive[1];
17585 
17586  // loop over the received info.
17587  unsigned current_index_data = 2;
17588  unsigned current_index_ddata = 0;
17589  while (current_index_data < n_udata_received)
17590  {
17591  // The global shared node number
17592  const unsigned global_shared_node_index =
17593  flat_package_unsigned_receive[current_index_data++];
17594 
17595  // The pointer to the node
17596  Node* node_pt = 0;
17597 
17598  // The number of original boundaries the node is associated
17599  // with
17600  const unsigned n_original_boundaries =
17601  flat_package_unsigned_receive[current_index_data++];
17602 
17603  // Get the node pointer
17604  node_pt = global_shared_node_pt[global_shared_node_index];
17605 #ifdef PARANOID
17606  if (node_pt == 0)
17607  {
17608  std::ostringstream error_message;
17609  error_message
17610  << "The global shared node (" << global_shared_node_index << ") "
17611  << "could not be found in this processor!!!\n"
17612  << "However, it was found in processor (" << iproc << "). The "
17613  << "data may be no synchronised,\ntherefore "
17614  << "we may be looking for a global shared node number that "
17615  << "do not\ncorrespond with the one that was sent by "
17616  << "processor (" << iproc << ")\n\n";
17617  throw OomphLibError(error_message.str(),
17618  OOMPH_CURRENT_FUNCTION,
17619  OOMPH_EXCEPTION_LOCATION);
17620  }
17621 #endif // #ifdef PARANOID
17622 
17623  // loop over the number of original boundaries and associate
17624  // the node to each of those boundaries
17625  for (unsigned i = 0; i < n_original_boundaries; i++)
17626  {
17627  // Get the original boundary to which the node is associated
17628  // with
17629  const unsigned original_bound_id =
17630  flat_package_unsigned_receive[current_index_data++];
17631 
17632  // Associate the node with the boundary
17633  this->add_boundary_node(original_bound_id, node_pt);
17634 
17635  // Get the zeta boundary coordinate
17636  Vector<double> zeta(1);
17637  zeta[0] = flat_package_double_receive[current_index_ddata++];
17638  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17639  }
17640 
17641  } // while(current_data < n_data_received)
17642 
17643  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17644 
17645  } // for (iproc < nproc)
17646 
17647  // ---------------------------------------------------------
17648  // END: Send the info. to the corresponding processors,
17649  // package the info, send it and receive it in the
17650  // corresponding processor, unpackage and set the
17651  // boundaries associated with the received nodes
17652  // ---------------------------------------------------------
17653  }
17654 
17655  //======================================================================
17656  // In charge of creating additional halo(ed) elements on those
17657  // processors that have no shared boundaries in common but have
17658  // shared nodes
17659  // ======================================================================
17660  template<class ELEMENT>
17662  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
17663  other_proc_shd_bnd_node_pt,
17664  Vector<Vector<Node*>>& iproc_currently_created_nodes_pt,
17665  Vector<Vector<Vector<unsigned>>>& global_node_names,
17666  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
17667  Vector<Node*>& global_shared_node_pt)
17668  {
17669  // Get the rank and number of processors
17670  const unsigned nproc = this->communicator_pt()->nproc();
17671  const unsigned my_rank = this->communicator_pt()->my_rank();
17672 
17673  // ---------------------------------------------------------------
17674  // BEGIN: Create a map to check whether a node is on the global
17675  // shared nodes. Also set a map to obtain the global
17676  // shared node index (this index is the same as the global
17677  // node name)
17678  // ---------------------------------------------------------------
17679  std::map<Node*, bool> is_global_shared_node;
17680  std::map<Node*, unsigned> global_shared_node_index;
17681 
17682  // Get the number of global shared nodes
17683  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17684  // loop over the global shared nodes
17685  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17686  {
17687  // Get the node
17688  Node* node_pt = global_shared_node_pt[i];
17689  // Indicate this is a shared global node
17690  is_global_shared_node[node_pt] = true;
17691  // Set the map to obtain the index of the global shared node
17692  global_shared_node_index[node_pt] = i;
17693 
17694  } // for (i < n_global_shared_nodes)
17695 
17696  // ---------------------------------------------------------------
17697  // END: Create a map to check whether a node is on the global
17698  // shared nodes. Also set a map to obtain the global
17699  // shared node index (this index is the same as the global
17700  // node name)
17701  // ---------------------------------------------------------------
17702 
17703  // ---------------------------------------------------------------
17704  // BEGIN: Loop over the haloed elements and check whether the nodes
17705  // on the haloed elements are part of the global shared
17706  // nodes. If that is the case then check whether the
17707  // element should be sent to the processors with which the
17708  // node is shared
17709  // ---------------------------------------------------------------
17710 
17711  // Elements that may be sent to other processors
17712  Vector<std::set<GeneralisedElement*>> additional_elements_pt(nproc);
17713 
17714  // loop over the processors
17715  for (unsigned iproc = 0; iproc < nproc; iproc++)
17716  {
17717  if (iproc != my_rank)
17718  {
17719  // Get the haloed element with iproc
17720  Vector<GeneralisedElement*> haloed_ele_pt =
17721  this->root_haloed_element_pt(iproc);
17722 
17723  // Get the number of haloed elements
17724  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17725 
17726  // loop over the haloed elements with iproc
17727  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17728  {
17729  // A pointer to the generalised element
17730  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17731  // Get the finite element representation of the element
17732  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17733  // Get the number of nodes
17734  const unsigned n_nodes = ele_pt->nnode();
17735  // loop over the nodes of the element
17736  for (unsigned n = 0; n < n_nodes; n++)
17737  {
17738  // Get the node
17739  Node* node_pt = ele_pt->node_pt(n);
17740  // Is the node a global shared node?
17741  if (is_global_shared_node[node_pt])
17742  {
17743  // Get the index of the global shared node
17744  const unsigned global_index = global_shared_node_index[node_pt];
17745  // Get the global names of the node
17746  Vector<Vector<unsigned>> iglobal_names =
17747  global_node_names[global_index];
17748 
17749  // Get the number of names
17750  const unsigned n_names = iglobal_names.size();
17751  // loop over the names and check which processors share
17752  // this node (the processors to which the element may be
17753  // sent
17754  for (unsigned j = 0; j < n_names; j++)
17755  {
17756  // Get the processors to which the element should be
17757  // sent
17758  const unsigned proc1 = iglobal_names[j][0];
17759  const unsigned proc2 = iglobal_names[j][1];
17760  // Add the element to the set of additional elements to
17761  // sent from proc1 to proc2
17762  additional_elements_pt[proc1].insert(gele_pt);
17763  additional_elements_pt[proc2].insert(gele_pt);
17764 
17765  } // for (j < n_names)
17766 
17767  } // if (is_global_shared_node[node_pt])
17768 
17769  } // for (n < n_nodes)
17770 
17771  } // for (ihd < n_haloed_ele)
17772 
17773  } // if (iproc!=my_rank)
17774 
17775  } // for (iproc < nproc)
17776 
17777  // ---------------------------------------------------------------
17778  // Now check whether the element should really be sent to the
17779  // indicated processors
17780 
17781  // The elements from this (my_rank) processor that will be sent to
17782  // other processors
17783  Vector<Vector<FiniteElement*>> send_haloed_ele_pt(nproc);
17784 
17785  // loop over the processors
17786  for (unsigned iproc = 0; iproc < nproc; iproc++)
17787  {
17788  if (iproc != my_rank)
17789  {
17790  // Get the set of element that may be sent to the iproc
17791  // processor
17792  std::set<GeneralisedElement*> iproc_ele_pt =
17793  additional_elements_pt[iproc];
17794  // loop over the element that may be sent to the iproc
17795  // processor
17796  for (std::set<GeneralisedElement*>::iterator it = iproc_ele_pt.begin();
17797  it != iproc_ele_pt.end();
17798  it++)
17799  {
17800  // Get a pointer to the element
17801  GeneralisedElement* gele_pt = (*it);
17802 
17803  // Get the haloed element with iproc
17804  Vector<GeneralisedElement*> haloed_ele_pt =
17805  this->root_haloed_element_pt(iproc);
17806 
17807  // Get the number of haloed elements
17808  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17809 
17810  // Flag to indicate whether the element has been already sent
17811  // to the iproc processor
17812  bool send_ele_to_iproc_processor = true;
17813  // loop over the haloed elements with iproc and check whether
17814  // the element has been already sent to iproc (if it is
17815  // already a haloed element with iproc then it has been
17816  // already sent)
17817  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17818  {
17819  // A pointer to the generalised element
17820  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17821  if (gele_pt == ghd_ele_pt)
17822  {
17823  // Mark the element as not required to be sent
17824  send_ele_to_iproc_processor = false;
17825  // Break the loop that searchs for the element on the
17826  // haloed elements with iproc
17827  break;
17828  }
17829 
17830  } // for (ihd < n_haloed_ele)
17831 
17832  // Do we need to sent the element?
17833  if (send_ele_to_iproc_processor)
17834  {
17835  // Get the finite element representation of the element
17836  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17837  // Add the element to those that will be sent to the iproc
17838  // processor
17839  send_haloed_ele_pt[iproc].push_back(ele_pt);
17840  }
17841 
17842  } // loop over the elements that may be sent to the iproc
17843  // processor
17844 
17845  } // if (iproc!=my_rank)
17846 
17847  } // for (iproc < nproc)
17848 
17849  // ---------------------------------------------------------------
17850  // END: Loop over the haloed element and check whether the nodes
17851  // on the haloed elements are part of the global shared
17852  // nodes. If that is the case then check whether the element
17853  // should be sent to the processors with which the node is
17854  // shared
17855  // ---------------------------------------------------------------
17856 
17857  // ============================================================
17858  // Now send the additional elements
17859  // ============================================================
17860  // Loop over the processors to send data
17861  for (unsigned iproc = 0; iproc < nproc; iproc++)
17862  {
17863  // There are no elements to send with myself
17864  if (iproc != my_rank)
17865  {
17866  // Get the number of additional haloed elements to send
17867  const unsigned n_additional_haloed_ele =
17868  send_haloed_ele_pt[iproc].size();
17869 
17870  // Clear send and receive buffers
17871  Flat_packed_unsigneds.clear();
17872  Flat_packed_doubles.clear();
17873 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17874  Flat_packed_unsigneds_string.clear();
17875 #endif
17876 
17877  // The very first data of the flat packed is the number of
17878  // additional haloed elements, this will be the number of
17879  // additional halo elements to create on the receiver processor
17880  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17881 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17882  std::stringstream junk;
17883  junk << "Number of haloed elements " << nhaloed_ele;
17884  Flat_packed_unsigneds_string.push_back(junk.str());
17885 #endif
17886 
17887  // Loop over the additioanl haloed elements
17888  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17889  {
17890  // Get pointer to the additional haloed element
17891  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17892  const unsigned nroot_haloed_ele = this->nroot_haloed_element(iproc);
17893 
17894  // Check if the element has been already added to the
17895  // halo(ed) scheme
17896 
17897  // Get the generalised version of the element
17898  GeneralisedElement* gen_ele_pt = ele_pt;
17899  // Try to add the haloed element
17900  const unsigned haloed_ele_index =
17901  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17902 
17903  // Was the element added or only returned the index of the
17904  // element
17905  if (nroot_haloed_ele == haloed_ele_index)
17906  {
17907  Flat_packed_unsigneds.push_back(1);
17908 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17909  Flat_packed_unsigneds_string.push_back(
17910  "Haloed element needs to be constructed");
17911 #endif
17912 
17913  // Get additional info. related with the haloed element
17914  get_required_elemental_information_helper(iproc, ele_pt);
17915 
17916  // Get the nodes on the element
17917  const unsigned nnodes = ele_pt->nnode();
17918  for (unsigned j = 0; j < nnodes; j++)
17919  {
17920  Node* node_pt = ele_pt->node_pt(j);
17921 
17922  // Package the info. of the nodes
17923  // The destination processor goes in the arguments
17924  add_haloed_node_helper(iproc, node_pt);
17925 
17926  } // for (j < nnodes)
17927 
17928  } // add the element and send its nodes
17929  else // The haloed element already exists
17930  {
17931  Flat_packed_unsigneds.push_back(0);
17932 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17933  Flat_packed_unsigneds_string.push_back(
17934  "Haloed element already exists");
17935 #endif
17936  Flat_packed_unsigneds.push_back(haloed_ele_index);
17937 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17938  Flat_packed_unsigneds_string.push_back(
17939  "Index of existing haloed element");
17940 #endif
17941  } // else (next_haloed_ele == external_haloed_ele_index)
17942 
17943  } // for (e < n_additional_haloed_ele)
17944 
17945  // Send and received the additional haloed elements (all
17946  // processors send and receive)
17947 
17948  // The processor to which send the elements
17949  int send_proc = static_cast<int>(iproc);
17950  // The processor from which receive the elements
17951  int recv_proc = static_cast<int>(iproc);
17952  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17953 
17954  // Reset the counters
17955  Counter_for_flat_packed_doubles = 0;
17956  Counter_for_flat_packed_unsigneds = 0;
17957 
17958  // Get the number of additional halo element to be created
17959  const unsigned n_additional_halo_ele =
17960  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
17961 
17962 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17963  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
17964  << " Number of elements need to be constructed "
17965  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
17966  << std::endl;
17967 #endif
17968 
17969  // Create the additional halo elements
17970  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17971  {
17972  // Create halo element from received info. of "iproc"
17973  // processor on the current processor
17974  create_halo_element(iproc,
17975  iproc_currently_created_nodes_pt[iproc],
17976  other_proc_shd_bnd_node_pt,
17977  global_node_names,
17978  node_name_to_global_index,
17979  global_shared_node_pt);
17980 
17981  } // for (e < n_additional_halo_ele)
17982 
17983  } // if (iproc != my_rank)
17984 
17985  } // for (iproc < nproc)
17986  }
17987 
17988  // *********************************************************************
17989  // Start communication functions
17990  // *********************************************************************
17991 
17992  //========start of get_required_elemental_information_helper==============
17993  /// Helper function to get the required elemental information from
17994  /// an haloed element. This info. involves the association of the element
17995  /// to a boundary or region.
17996  //========================================================================
17997  template<class ELEMENT>
17999  ELEMENT>::get_required_elemental_information_helper(unsigned& iproc,
18000  FiniteElement* ele_pt)
18001  {
18002  // Check if the element is associated with the original boundaries
18003  const unsigned nbound = this->initial_shared_boundary_id();
18004 
18005  // ------------------------------------------------------------------
18006  // Stores the information regarding the boundaries associated to the
18007  // element (it that is the case)
18008  Vector<unsigned> associated_boundaries;
18009  Vector<unsigned> face_index_on_boundary;
18010 
18011  unsigned counter_face_indexes = 0;
18012 
18013  for (unsigned b = 0; b < nbound; b++)
18014  {
18015  // Get the number of elements associated to boundary i
18016  const unsigned nboundary_ele = nboundary_element(b);
18017  for (unsigned e = 0; e < nboundary_ele; e++)
18018  {
18019  if (ele_pt == this->boundary_element_pt(b, e))
18020  {
18021  // Keep track of the boundaries associated to the element
18022  associated_boundaries.push_back(b);
18023  // Get the face index
18024  face_index_on_boundary.push_back(face_index_at_boundary(b, e));
18025  counter_face_indexes++;
18026 #ifdef PARANOID
18027  if (counter_face_indexes > 2)
18028  {
18029  std::stringstream error_message;
18030  error_message
18031  << "A triangular element can not have more than two of its faces "
18032  << "on a boundary!!!\n\n";
18033  throw OomphLibError(error_message.str(),
18034  OOMPH_CURRENT_FUNCTION,
18035  OOMPH_EXCEPTION_LOCATION);
18036  }
18037 #else
18038  // Already found 2 face indexes on the same boundary?
18039  if (counter_face_indexes == 2)
18040  {
18041  break;
18042  }
18043 #endif // #ifdef PARANOID
18044 
18045  } // if (ele_pt == this->boundary_element_pt(b,e))
18046 
18047  } // (e < nboundary_ele)
18048 
18049  } // (b < nbound)
18050 
18051  // If the element is associated to any boundary then package all the
18052  // relevant info
18053  const unsigned nassociated_boundaries = associated_boundaries.size();
18054  if (nassociated_boundaries > 0)
18055  {
18056  Flat_packed_unsigneds.push_back(1);
18057 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18058  Flat_packed_unsigneds_string.push_back(
18059  "The element is a boundary element");
18060 #endif
18061  Flat_packed_unsigneds.push_back(nassociated_boundaries);
18062 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18063  std::stringstream junk;
18064  junk << "The elements is associated to " << nassociated_boundaries
18065  << " boundaries";
18066  Flat_packed_unsigneds_string.push_back(junk.str());
18067 #endif
18068 
18069  // Package the ids of the associated boundaries and the
18070  // corresponding face index for each boundary (if the element is a
18071  // corner element, it will have two faces associated to the
18072  // boundary)
18073  for (unsigned i = 0; i < nassociated_boundaries; i++)
18074  {
18075  unsigned b = associated_boundaries[i];
18076  Flat_packed_unsigneds.push_back(b);
18077 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18078  std::stringstream junk;
18079  junk << "Element associated to boundary " << b << " of "
18080  << nassociated_boundaries << " total associated boundaries";
18081  Flat_packed_unsigneds_string.push_back(junk.str());
18082 #endif
18083  unsigned f = face_index_on_boundary[i];
18084  Flat_packed_unsigneds.push_back(f);
18085 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18086  std::stringstream junk2;
18087  junk2 << "Face index " << f << " for associated boundary " << b;
18088  Flat_packed_unsigneds_string.push_back(junk2.str());
18089 #endif
18090  }
18091 
18092  // If the element is associated to any boundary then we should
18093  // check if the mesh has regions, if that is the case then we need
18094  // to check to which region the boundary element does belong
18095 
18096  // If the mesh has regions we should look for the element
18097  // associated to a boundary and a specified region
18098  Vector<Vector<unsigned>> associated_boundaries_and_regions;
18099  Vector<unsigned> face_index_on_boundary_and_region;
18100 
18101  // Now check for the case when we have regions in the mesh
18102  const unsigned n_regions = this->nregion();
18103  if (n_regions > 1)
18104  {
18105  // Used to count the number of faces associated with
18106  // boundary-regions
18107  unsigned counter_face_indexes_in_regions = 0;
18108  // Loop over the boundaries
18109  for (unsigned b = 0; b < nbound; b++)
18110  {
18111  // Go through each region by getting the region id
18112  for (unsigned i_reg = 0; i_reg < n_regions; i_reg++)
18113  {
18114  // Get thre region id associated with the (i_reg)-th region
18115  const unsigned region_id =
18116  static_cast<unsigned>(this->Region_attribute[i_reg]);
18117 
18118  // Loop over all elements associated with the current boundary
18119  // and the i_reg-th region and check if the element is part of
18120  // any region
18121  const unsigned nele_in_region =
18122  this->nboundary_element_in_region(b, region_id);
18123  for (unsigned ee = 0; ee < nele_in_region; ee++)
18124  {
18125  // Check if the boundary-region element is the same as the
18126  // element
18127  if (ele_pt ==
18128  this->boundary_element_in_region_pt(b, region_id, ee))
18129  {
18130  // Storage for the boundary and region associated to the
18131  // element
18132  Vector<unsigned> bound_and_region(2);
18133 
18134  // Keep track of the boundaries associated to the element
18135  bound_and_region[0] = b;
18136  // Keep track of the regions associated to the element
18137  bound_and_region[1] = region_id;
18138  // Add the boundaries and regions in the storage to be
18139  // sent to other processors
18140  associated_boundaries_and_regions.push_back(bound_and_region);
18141  // Get the face index and keep track of it
18142  face_index_on_boundary_and_region.push_back(
18143  this->face_index_at_boundary_in_region(b, region_id, ee));
18144 
18145  // Increase the number of faces of the element associated
18146  // to boundary-regions
18147  counter_face_indexes_in_regions++;
18148 
18149 #ifdef PARANOID
18150  if (counter_face_indexes_in_regions > 2)
18151  {
18152  std::stringstream error_message;
18153  error_message << "A triangular element can not have more "
18154  "than two of its\n"
18155  << "faces on a boundary!!!\n\n";
18156  throw OomphLibError(error_message.str(),
18157  OOMPH_CURRENT_FUNCTION,
18158  OOMPH_EXCEPTION_LOCATION);
18159  } // if (counter_face_indexes_in_regions > 2)
18160 #endif
18161 
18162  } // The element is a boundary-region element
18163 
18164  } // for (ee < nele_in_region)
18165 
18166  } // for (i_reg < n_regions)
18167 
18168  } // for (b < nbound)
18169 
18170  } // if (n_regions > 1)
18171 
18172  // Now package the info. to be sent to other processors
18173  const unsigned nassociated_boundaries_and_regions =
18174  associated_boundaries_and_regions.size();
18175  if (nassociated_boundaries_and_regions > 0)
18176  {
18177  Flat_packed_unsigneds.push_back(1);
18178 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18179  Flat_packed_unsigneds_string.push_back(
18180  "The element is associated to boundaries and regions");
18181 #endif
18182 
18183  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
18184 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18185  std::stringstream junk;
18186  junk << "The element is associated to "
18187  << nassociated_boundaries_and_regions << " boundaries-regions";
18188  Flat_packed_unsigneds_string.push_back(junk.str());
18189 #endif
18190 
18191  // Package the ids of the associated boundaries, regions and the
18192  // corresponding face index for each boundary-region (if the
18193  // element is a corner element, it will have two faces
18194  // associated to the boundary-region)
18195  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
18196  {
18197  const unsigned b = associated_boundaries_and_regions[i][0];
18198  Flat_packed_unsigneds.push_back(b);
18199 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18200  std::stringstream junk;
18201  junk << "Element associated to boundary " << b << " of "
18202  << nassociated_boundaries_and_regions
18203  << " total associated boundaries-regions";
18204  Flat_packed_unsigneds_string.push_back(junk.str());
18205 #endif
18206 
18207  const unsigned r = associated_boundaries_and_regions[i][1];
18208  Flat_packed_unsigneds.push_back(r);
18209 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18210  std::stringstream junk2;
18211  junk2 << "Element associated to region " << r << " of "
18212  << nassociated_boundaries_and_regions
18213  << " total associated boundaries-regions";
18214  Flat_packed_unsigneds_string.push_back(junk2.str());
18215 #endif
18216 
18217  const unsigned f = face_index_on_boundary_and_region[i];
18218  Flat_packed_unsigneds.push_back(f);
18219 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18220  std::stringstream junk3;
18221  junk3 << "Face index " << f << " for associated boundary-region ("
18222  << b << "-" << r << ")";
18223  Flat_packed_unsigneds_string.push_back(junk3.str());
18224 #endif
18225  } // for (i < nassociated_boundaries_and_regions)
18226  } // if (nassociated_boundaries_and_regions > 0)
18227  else
18228  {
18229  Flat_packed_unsigneds.push_back(0);
18230 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18231  Flat_packed_unsigneds_string.push_back(
18232  "The element is NOT associated to boundaries and regions");
18233 #endif
18234  } // else if (nassociated_boundaries_and_regions > 0)
18235  }
18236  else
18237  {
18238  Flat_packed_unsigneds.push_back(0);
18239 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18240  Flat_packed_unsigneds_string.push_back(
18241  "The element is not associated to any original boundary");
18242 #endif
18243  }
18244 
18245  // ------------------------------------------------------------
18246  // Now review if the element is associated to a shared boundary
18247 
18248  // Store the shared boundaries, and therefore the face indexes
18249  // associated to the element
18250  Vector<unsigned> associated_shared_boundaries;
18251  Vector<unsigned> face_index_on_shared_boundary;
18252 
18253  // Get the shared boundaries in this processor
18254  Vector<unsigned> my_rank_shared_boundaries_ids;
18255  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18256 
18257  // Get the number of shared boundaries
18258  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18259  // Loop over the shared boundaries
18260  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18261  {
18262  // Get the boundary id
18263  const unsigned sb = my_rank_shared_boundaries_ids[i];
18264 
18265  // Get the number of elements associated to shared boundary sb
18266  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18267  for (unsigned e = 0; e < nboundary_ele; e++)
18268  {
18269  if (ele_pt == this->shared_boundary_element_pt(sb, e))
18270  {
18271  // Keep track of the boundaries associated to the element
18272  associated_shared_boundaries.push_back(sb);
18273  // Get the face index
18274  face_index_on_shared_boundary.push_back(
18275  this->face_index_at_shared_boundary(sb, e));
18276  }
18277  } // (e < nboundary_ele)
18278  } // (i < nmy_rank_shd_bnd)
18279 
18280  // If the element is associated to a shared boundary then package
18281  // all the relevant info
18282  const unsigned nassociated_shared_boundaries =
18283  associated_shared_boundaries.size();
18284  if (nassociated_shared_boundaries > 0)
18285  {
18286  Flat_packed_unsigneds.push_back(3);
18287 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18288  Flat_packed_unsigneds_string.push_back(
18289  "The element is a shared boundary element");
18290 #endif
18291  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18292 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18293  std::stringstream junk;
18294  junk << "The elements is associated to " << nassociated_shared_boundaries
18295  << "shared boundaries";
18296  Flat_packed_unsigneds_string.push_back(junk.str());
18297 #endif
18298 
18299  // Package the ids of the associated boundaries
18300  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18301  {
18302  const unsigned b = associated_shared_boundaries[i];
18303  Flat_packed_unsigneds.push_back(b);
18304 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18305  std::stringstream junk;
18306  junk << "Element associated to shared boundary " << b << " of "
18307  << nassociated_shared_boundaries << " total associated boundaries";
18308  Flat_packed_unsigneds_string.push_back(junk.str());
18309 #endif
18310 
18311  const unsigned f = face_index_on_shared_boundary[i];
18312  Flat_packed_unsigneds.push_back(f);
18313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18314  std::stringstream junk2;
18315  junk2 << "Face index " << f << " for associated shared boundary " << b;
18316  Flat_packed_unsigneds_string.push_back(junk2.str());
18317 #endif
18318  }
18319  }
18320  else
18321  {
18322  Flat_packed_unsigneds.push_back(0);
18323 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18324  Flat_packed_unsigneds_string.push_back(
18325  "The element is not associated to any shared boundary");
18326 #endif
18327  }
18328  }
18329 
18330  //========start of get_required_nodal_information_helper==================
18331  /// Helper function to get the required nodal information from an
18332  /// haloed node so that a fully-functional halo node (and therefore element)
18333  /// can be created on the receiving process
18334  //========================================================================
18335  template<class ELEMENT>
18337  unsigned& iproc, Node* nod_pt)
18338  {
18339  unsigned my_rank = this->communicator_pt()->my_rank();
18340  const unsigned nproc = this->communicator_pt()->nproc();
18341 
18342  // Tell the halo copy of this node how many values there are
18343  // [NB this may be different for nodes within the same element, e.g.
18344  // when using Lagrange multipliers]
18345  unsigned n_val = nod_pt->nvalue();
18346  Flat_packed_unsigneds.push_back(n_val);
18347 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18348  Flat_packed_unsigneds_string.push_back("Number of values");
18349 #endif
18350 
18351  unsigned n_dim = nod_pt->ndim();
18352 
18353  // Default number of previous values to 1
18354  unsigned n_prev = 1;
18355  if (this->Time_stepper_pt != 0)
18356  {
18357  // Add number of history values to n_prev
18358  n_prev = this->Time_stepper_pt->ntstorage();
18359  }
18360 
18361  // -----------------------------------------------------
18362  // Is the node on an original boundary?
18363  // Store the original boundaries where the node may be
18364  Vector<unsigned> original_boundaries;
18365  // Loop over the original boundaries of the mesh and check if live
18366  // on one of them
18367  const unsigned n_bnd = this->initial_shared_boundary_id();
18368  for (unsigned bb = 0; bb < n_bnd; bb++)
18369  {
18370  // Which boundaries (could be more than one) is it on?
18371  if (nod_pt->is_on_boundary(bb))
18372  {
18373  original_boundaries.push_back(bb);
18374  }
18375  }
18376 
18377  const unsigned n_original_boundaries = original_boundaries.size();
18378  // Is the node on any original boundary?
18379  if (n_original_boundaries > 0)
18380  {
18381  // Indicate that the node is on an original boundary
18382  Flat_packed_unsigneds.push_back(2);
18383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18384  Flat_packed_unsigneds_string.push_back(
18385  "Node is on the original boundaries");
18386 #endif
18387 
18388  Flat_packed_unsigneds.push_back(n_original_boundaries);
18389 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18390  std::stringstream junk;
18391  junk << "Node is on " << n_original_boundaries << " original boundaries";
18392  Flat_packed_unsigneds_string.push_back(junk.str());
18393 #endif
18394 
18395  // Loop over the original boundaries the node is on
18396  for (unsigned i = 0; i < n_original_boundaries; i++)
18397  {
18398  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18399 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18400  std::stringstream junk;
18401  junk << "Node is on boundary " << original_boundaries[i] << " of "
18402  << nb;
18403  Flat_packed_unsigneds_string.push_back(junk.str());
18404 #endif
18405  // Get the boundary coordinate of the node
18406  Vector<double> zeta(1);
18407  nod_pt->get_coordinates_on_boundary(original_boundaries[i], zeta);
18408  Flat_packed_doubles.push_back(zeta[0]);
18409  }
18410  }
18411  else
18412  {
18413  // Indicate that the node is NOT on an original boundary
18414  Flat_packed_unsigneds.push_back(0);
18415 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18416  Flat_packed_unsigneds_string.push_back(
18417  "Node is on any original boundary");
18418 #endif
18419  }
18420 
18421  // -------------------------------------------------------
18422  // Is the node on shared boundaries?
18423  bool node_on_shared_boundary = false;
18424  // Loop over the shared boundaries with the iproc processors and
18425  // check if live on one of them
18426  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18427  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18428  {
18429  // Get the boundary id
18430  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18431  // Which boundaries (could be more than one) is it on?
18432  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18433  {
18434  node_on_shared_boundary = true;
18435  break;
18436  }
18437  }
18438 
18439  // If the node live on any of the shared boundaries with the iproc
18440  // processor then just get the node number according to the
18441  // sorted_shared_boundary_node_pt() scheme and send it accross
18442  if (node_on_shared_boundary)
18443  {
18444  Flat_packed_unsigneds.push_back(1);
18445 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18446  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18447 #endif
18448 
18449  // Store the shared boundaries where the node is on
18450  Vector<unsigned> shd_boundaries;
18451  // Loop over the shared boundaries with the iproc processor
18452  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18453  {
18454  // Get the boundary id
18455  const unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18456  // Which boundaries (could be more than one) is it on?
18457  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18458  {
18459  shd_boundaries.push_back(i_bnd);
18460  }
18461  }
18462 
18463  // Get the number of shared boundaries the node is on
18464  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18465  // Send the number of shared boundaries the node is on
18466  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18467 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18468  std::stringstream junk;
18469  junk << "Node is on " << n_shd_bnd_is_on << " shared boundaries";
18470  Flat_packed_unsigneds_string.push_back(junk.str());
18471 #endif
18472 
18473  // Loop over the shared boundaries to send their ids
18474  for (unsigned i = 0; i < n_shd_bnd_is_on; i++)
18475  {
18476  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18477 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18478  std::stringstream junk;
18479  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18480  Flat_packed_unsigneds_string.push_back(junk.str());
18481 #endif
18482  }
18483 
18484  // Given that the node is on at least one boundary get the index
18485  // of the node in one of the boundaries and send this index
18486  unsigned shared_boundary_id = shd_boundaries[0];
18487  // Get the number of nodes on the given shared boundary
18488  const unsigned n_nodes_on_shared_boundary =
18489  nsorted_shared_boundary_node(shared_boundary_id);
18490  // Store the index of the node on the shared boundary
18491  unsigned index_node_on_shared_boundary;
18492 #ifdef PARANOID
18493  // Flag to know if the node has been found
18494  bool found_index_node_on_shared_boundary = false;
18495 #endif
18496  // Loop over the nodes on the shared boundary to find the node
18497  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18498  {
18499  // Get the i-th node on the shared boundary
18500  Node* shared_node_pt =
18501  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18502  // Is the node we are looking for
18503  if (shared_node_pt == nod_pt)
18504  {
18505  // Store the index
18506  index_node_on_shared_boundary = i;
18507 #ifdef PARANOID
18508  // Mark as found
18509  found_index_node_on_shared_boundary = true;
18510 #endif
18511  break; // break
18512  }
18513 
18514  } // for (i < nnodes_on_shared_boundary)
18515 
18516 #ifdef PARANOID
18517  if (!found_index_node_on_shared_boundary)
18518  {
18519  std::ostringstream error_message;
18520  error_message << "The index of the node on boundary ("
18521  << shared_boundary_id << ") was not found.\n"
18522  << "The node coordinates are (" << nod_pt->x(0) << ","
18523  << nod_pt->x(1) << ").\n";
18524  throw OomphLibError(
18525  error_message.str(),
18526  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18527  OOMPH_EXCEPTION_LOCATION);
18528  }
18529 #endif
18530  // Send the index of the node on the shared boundary
18531  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18532 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18533  std::stringstream junk2;
18534  junk2 << "Node index on boundary " << boundaries[0] << " is "
18535  << index_node_on_shared_boundary;
18536  Flat_packed_unsigneds_string.push_back(junk2.str());
18537 #endif
18538 
18539  } // if (node_on_shared_boundary)
18540  else
18541  {
18542  // The node is not on a shared boundary
18543  Flat_packed_unsigneds.push_back(0);
18544 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18545  Flat_packed_unsigneds_string.push_back(
18546  "Node is not on a shared boundary");
18547 #endif
18548  }
18549 
18550  // ----------------------------------------------------------------
18551  // Is the node on any shared boundary where the receiver processor
18552  // is not involved?
18553 
18554  // Now check if the node is on a shared boundary created by the
18555  // current processor (my_rank) and other processor different that
18556  // the iproc processor. This info. will help to complete the sending
18557  // of halo(ed) information between processors
18558 
18559  // Flag to know if the node is on a shared boundary with other
18560  // processor
18561  bool node_on_shared_boundary_with_other_processors = false;
18562  // Count the number of other shared boundaries it could be on
18563  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18564 
18565  // Loop over the shared boundaries of the sent processor (my_rank)
18566  // and other processors (jproc)
18567  for (unsigned jproc = 0; jproc < nproc; jproc++)
18568  {
18569  // Do not search with the iproc processor , that was done before
18570  // above because we are sending info to that processor
18571  if (jproc != iproc)
18572  {
18573  // Get the number of shared boundaries with the jproc processor
18574  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
18575  // Loop over the shared boundaries
18576  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18577  {
18578  // Get the boundary id
18579  const unsigned j_shd_bnd =
18580  this->shared_boundaries_ids(my_rank, jproc, bb);
18581  // Is the node part of this boundary?
18582  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18583  {
18584  // DEBP("Sending to");
18585  // DEBP(iproc);
18586  // DEBP("Pair of procs where other shared");
18587  // DEBP(my_rank);
18588  // DEBP(jproc);
18589  // DEBP(i_bnd);
18590  node_on_shared_boundary_with_other_processors = true;
18591  // Increase the counter for the number of shared boundaries
18592  // with other processors the node is on
18593  nshared_boundaries_with_other_processors_have_node++;
18594  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18595 
18596  } // for (bb<n_jshd_bnd)
18597 
18598  } // if (jproc != iproc)
18599 
18600  } // for (jproc < nproc)
18601 
18602  // If the node is on a shared boundary with another processor
18603  // (my_rank, jproc), then send the flag and look for the info.
18604  if (node_on_shared_boundary_with_other_processors)
18605  {
18606  Flat_packed_unsigneds.push_back(4);
18607 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18608  Flat_packed_unsigneds_string.push_back(
18609  "Node is on shared boundary no related with the received processor: 4");
18610 #endif
18611 
18612  // The number of packages of information that will be sent to the
18613  // "iproc" processor. This helps to know how many packages of data
18614  // read from the received processor
18615  Flat_packed_unsigneds.push_back(
18616  nshared_boundaries_with_other_processors_have_node);
18617 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18618  std::stringstream junk;
18619  junk << "Number of other shared boundaries that the node is on: "
18620  << nshared_boundaries_with_other_processors_have_node;
18621  Flat_packed_unsigneds_string.push_back(junk.str());
18622 #endif
18623 
18624  // Counter to ensure that the correct number of data has been sent
18625  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18626  // Loop over the shared boundaries with other processors and get:
18627  // 1) The processors defining the shared boundary
18628  // 2) The shared boundary id
18629  // 3) The index of the node on the shared boundary
18630  Vector<unsigned> other_processor_1;
18631  Vector<unsigned> other_processor_2;
18632  Vector<unsigned> shd_bnd_ids;
18633  Vector<unsigned> indexes;
18634  // Loop over the processors again
18635  for (unsigned jproc = 0; jproc < nproc; jproc++)
18636  {
18637  // Do not search with the iproc processor, that was done before
18638  // above
18639  if (jproc != iproc)
18640  {
18641  // Get the number of shared boundaries with the jproc
18642  // processor
18643  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
18644  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18645  {
18646  // Get the boundary id
18647  const unsigned j_shd_bnd =
18648  this->shared_boundaries_ids(my_rank, jproc, bb);
18649  // Is the node part of this boundary?
18650  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18651  {
18652  // Include the first processor
18653  other_processor_1.push_back(my_rank);
18654  // Include the second processor
18655  other_processor_2.push_back(jproc);
18656  // Include the shared boundary id
18657  shd_bnd_ids.push_back(j_shd_bnd);
18658  // Increase the counter for found shared boundaries with
18659  // other processors
18660  counter_shd_bnd_with_other_procs_have_node++;
18661  }
18662 
18663  } // for (bb < nshared_bnd)
18664 
18665  } // if (jproc != iproc)
18666 
18667  } // for (jproc < nproc)
18668 
18669  // Get the indexes of the node on all the shared boundaries where
18670  // it was found
18671  const unsigned n_other_processors = other_processor_1.size();
18672  // Loop over the processors where the node was found
18673  for (unsigned i = 0; i < n_other_processors; i++)
18674  {
18675  // Get the shared boundary id
18676  unsigned shd_bnd_id = shd_bnd_ids[i];
18677  // Get the number of nodes on that shared boundary
18678  const unsigned n_nodes_on_shd_bnd =
18679  nsorted_shared_boundary_node(shd_bnd_id);
18680 
18681 #ifdef PARANOID
18682  bool found_index_node_on_shared_boundary = false;
18683 #endif
18684  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18685  {
18686  // Get the i-th shared boundary node
18687  Node* shared_node_pt = sorted_shared_boundary_node_pt(shd_bnd_id, i);
18688  // Is the same node?
18689  if (shared_node_pt == nod_pt)
18690  {
18691  // DEBP(i_node);
18692  // DEBP(nod_pt->x(0));
18693  // DEBP(nod_pt->x(1));
18694  // Include the index of the node
18695  indexes.push_back(i);
18696 #ifdef PARANOID
18697  // Mark as found the node
18698  found_index_node_on_shared_boundary = true;
18699 #endif
18700  break;
18701  } // if (shared_node_pt == nod_pt)
18702 
18703  } // for (i < n_nodes_on_shd_bnd)
18704 
18705 #ifdef PARANOID
18706  if (!found_index_node_on_shared_boundary)
18707  {
18708  std::ostringstream error_message;
18709  error_message << "The index of the node on boundary (" << shd_bnd_id
18710  << "), shared by other processors\nwas not found.\n"
18711  << "The node coordinates are (" << nod_pt->x(0) << ","
18712  << nod_pt->x(1) << ").\n";
18713  throw OomphLibError(
18714  error_message.str(),
18715  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18716  OOMPH_EXCEPTION_LOCATION);
18717  }
18718 #endif
18719  } // for (i < n_other_processors)
18720 
18721  // Now send the info. but first check that the number of found
18722  // nodes be the same that the previously found shared boundaries
18723  // with the node
18724 #ifdef PARANOID
18725  if (counter_shd_bnd_with_other_procs_have_node !=
18726  nshared_boundaries_with_other_processors_have_node)
18727  {
18728  std::ostringstream error_message;
18729  error_message << "The number of shared boundaries where the node is on "
18730  << "is different:\n"
18731  << "nshared_boundaries_with_other_processors_have_node: ("
18732  << nshared_boundaries_with_other_processors_have_node
18733  << ")\n"
18734  << "counter_shd_bnd_with_other_procs_have_node: ("
18735  << counter_shd_bnd_with_other_procs_have_node << ")\n";
18736  throw OomphLibError(
18737  error_message.str(),
18738  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18739  OOMPH_EXCEPTION_LOCATION);
18740  } // if (counter_shd_bnd_with_other_procs_have_node !=
18741  // nshared_boundaries_with_other_processors_have_node)
18742 #endif
18743 
18744  // Loop over the info. to send it
18745  for (unsigned i = 0; i < n_other_processors; i++)
18746  {
18747  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18748 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18749  std::stringstream junk1;
18750  junk1 << "Processor where the other shared boundary "
18751  << "has the node: " << other_processor_1[i];
18752  Flat_packed_unsigneds_string.push_back(junk1.str());
18753 #endif
18754 
18755  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18756 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18757  std::stringstream junk2;
18758  junk2 << "Processor where the other shared boundary "
18759  << "has the node: " << other_processor_2[i];
18760  Flat_packed_unsigneds_string.push_back(junk2.str());
18761 #endif
18762 
18763  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18764 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18765  std::stringstream junk3;
18766  junk3 << "Other shared boundary id where the node is on"
18767  << boundaries[i];
18768  Flat_packed_unsigneds_string.push_back(junk3.str());
18769 #endif
18770 
18771  Flat_packed_unsigneds.push_back(indexes[i]);
18772 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18773  std::stringstream junk4;
18774  junk4 << "Node index on other shared boundary " << boundaries[i]
18775  << " is " << indexes[i];
18776  Flat_packed_unsigneds_string.push_back(junk4.str());
18777 #endif
18778 
18779  } // for (i < n_other_processors)
18780 
18781  } // if (node_on_shared_boundary_with_other_processors)
18782  else
18783  {
18784  Flat_packed_unsigneds.push_back(0);
18785 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18786  Flat_packed_unsigneds_string.push_back(
18787  "Node is on any shared boundary with other processors");
18788 #endif
18789  } // else if (node_on_shared_boundary_with_other_processors)
18790 
18791  // Now check if it is required to send the info. of the node. If the
18792  // node is not on a shared boundary with the iproc processor then we
18793  // need to send the info.
18794 
18795  if (!node_on_shared_boundary)
18796  {
18797  // Send all the info. to create it
18798 
18799  // Is the Node algebraic? If so, send its ref values and
18800  // an indication of its geometric objects if they are stored
18801  // in the algebraic mesh
18802  AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
18803  if (alg_nod_pt != 0)
18804  {
18805  // The external mesh should be algebraic
18806  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
18807 
18808  // Get default node update function ID
18809  unsigned update_id = alg_nod_pt->node_update_fct_id();
18810  Flat_packed_unsigneds.push_back(update_id);
18811 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18812  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18813 #endif
18814 
18815  // Get reference values at default...
18816  unsigned n_ref_val = alg_nod_pt->nref_value();
18817  Flat_packed_unsigneds.push_back(n_ref_val);
18818 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18819  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18820 #endif
18821  for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
18822  {
18823  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18824  }
18825 
18826  // Access geometric objects at default...
18827  unsigned n_geom_obj = alg_nod_pt->ngeom_object();
18828  Flat_packed_unsigneds.push_back(n_geom_obj);
18829 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18830  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18831 #endif
18832  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
18833  {
18834  GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
18835 
18836  // Check this against the stored geometric objects in mesh
18837  unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
18838 
18839  // Default found index to zero
18840  unsigned found_geom_object = 0;
18841  for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
18842  {
18843  if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
18844  {
18845  found_geom_object = i_list;
18846  }
18847  }
18848  Flat_packed_unsigneds.push_back(found_geom_object);
18849 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18850  Flat_packed_unsigneds_string.push_back("Found geom object");
18851 #endif
18852  }
18853  } // (if alg_nod_pt!=0)
18854 
18855  // Is it a SolidNode?
18856  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
18857  if (solid_nod_pt != 0)
18858  {
18859  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
18860  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
18861  {
18862  for (unsigned t = 0; t < n_prev; t++)
18863  {
18864  Flat_packed_doubles.push_back(
18865  solid_nod_pt->variable_position_pt()->value(t, i_val));
18866  }
18867  }
18868 
18869  Vector<double> values_solid_node;
18870  solid_nod_pt->add_values_to_vector(values_solid_node);
18871  const unsigned nvalues_solid_node = values_solid_node.size();
18872  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18873 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18874  std::stringstream junk;
18875  junk << "Number of values solid node: " << nvalues_solid_node;
18876  Flat_packed_unsigneds_string.push_back(junk.str());
18877 #endif
18878  for (unsigned i = 0; i < nvalues_solid_node; i++)
18879  {
18880  Flat_packed_doubles.push_back(values_solid_node[i]);
18881  }
18882  }
18883 
18884  // Finally copy info required for all node types
18885  for (unsigned i_val = 0; i_val < n_val; i_val++)
18886  {
18887  for (unsigned t = 0; t < n_prev; t++)
18888  {
18889  Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
18890  }
18891  }
18892 
18893  // Now do positions
18894  for (unsigned idim = 0; idim < n_dim; idim++)
18895  {
18896  for (unsigned t = 0; t < n_prev; t++)
18897  {
18898  Flat_packed_doubles.push_back(nod_pt->x(t, idim));
18899  }
18900  }
18901 
18902  } // if (!node_on_shared_boundary)
18903  }
18904 
18905  //==========start of add_haloed_node_helper===============================
18906  /// Helper to add external haloed node that is not a master
18907  //========================================================================
18908  template<class ELEMENT>
18910  Node* nod_pt)
18911  {
18912  // Attempt to add this node as a haloed node
18913  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18914  const unsigned haloed_node_index =
18915  this->try_to_add_haloed_node_pt(iproc, nod_pt);
18916 
18917  // If it was added then the new index should match the size of the storage
18918  if (haloed_node_index == n_haloed_nod)
18919  {
18920  Flat_packed_unsigneds.push_back(1);
18921 
18922 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18923  std::stringstream junk;
18924  junk << "Node needs to be constructed [size="
18925  << Flat_packed_unsigneds.size() << "]; last entry: "
18926  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
18927  Flat_packed_unsigneds_string.push_back(junk.str());
18928 #endif
18929 
18930  // This helper function gets all the required information for the
18931  // specified node and stores it into MPI-sendable information
18932  // so that a halo copy can be made on the receiving process
18933  get_required_nodal_information_helper(iproc, nod_pt);
18934  }
18935  else // It was already added
18936  {
18937  Flat_packed_unsigneds.push_back(0);
18938 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18939  std::stringstream junk;
18940  junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
18941  << "]; last entry: "
18942  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
18943 
18944  Flat_packed_unsigneds_string.push_back(junk.str());
18945 #endif
18946 
18947  // This node is already a haloed node, so tell
18948  // the other process its index in the equivalent halo storage
18949  Flat_packed_unsigneds.push_back(haloed_node_index);
18950 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18951  Flat_packed_unsigneds_string.push_back("haloed node index");
18952 #endif
18953  }
18954  }
18955 
18956  //================= send_and_receive_haloed_info =======================
18957  /// Send the information of the elements that will be created on the other
18958  /// processor
18959  //======================================================================
18960  template<class ELEMENT>
18962  int& send_proc, int& recv_proc)
18963  {
18964  // Get the communicator of the mesh
18965  OomphCommunicator* comm_pt = this->communicator_pt();
18966 
18967  // Set MPI info
18968  MPI_Status status;
18969  MPI_Request request;
18970 
18971  // Prepare vectors to receive information
18972  Vector<double> received_double_values;
18973  Vector<unsigned> received_unsigned_values;
18974 
18975  // Send the double values associated with halo(ed) elements and nodes
18976  //-------------------------------------------------------------------
18977  unsigned send_count_double_values = Flat_packed_doubles.size();
18978  MPI_Isend(&send_count_double_values,
18979  1,
18980  MPI_UNSIGNED,
18981  send_proc,
18982  1,
18983  comm_pt->mpi_comm(),
18984  &request);
18985 
18986  int receive_count_double_values = 0;
18987  MPI_Recv(&receive_count_double_values,
18988  1,
18989  MPI_INT,
18990  recv_proc,
18991  1,
18992  comm_pt->mpi_comm(),
18993  &status);
18994  MPI_Wait(&request, MPI_STATUS_IGNORE);
18995 
18996  if (send_count_double_values != 0)
18997  {
18998  MPI_Isend(&Flat_packed_doubles[0],
18999  send_count_double_values,
19000  MPI_DOUBLE,
19001  send_proc,
19002  2,
19003  comm_pt->mpi_comm(),
19004  &request);
19005  }
19006  if (receive_count_double_values != 0)
19007  {
19008  received_double_values.resize(receive_count_double_values);
19009  MPI_Recv(&received_double_values[0],
19010  receive_count_double_values,
19011  MPI_DOUBLE,
19012  recv_proc,
19013  2,
19014  comm_pt->mpi_comm(),
19015  &status);
19016  }
19017  if (send_count_double_values != 0)
19018  {
19019  MPI_Wait(&request, MPI_STATUS_IGNORE);
19020  }
19021 
19022  // Now send unsigned values associated with halo(ed) elements and nodes
19023  //---------------------------------------------------------------------
19024  unsigned send_count_unsigned_values = Flat_packed_unsigneds.size();
19025 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19026  unsigned send_count_unsigned_string = Flat_packed_unsigneds_string.size();
19027 #ifdef PARANOID
19028  if (send_count_unsigned_string != send_count_unsigned_values)
19029  {
19030  std::ostringstream error_message;
19031  error_message << "The number of unsigned values to send to processor ("
19032  << send_proc
19033  << ") is different from the\nnumber of annotated strings "
19034  << "for the communication\n\n";
19035  throw OomphLibError(
19036  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
19037  }
19038 #endif // #ifdef PARANOID
19039 #endif
19040  MPI_Isend(&send_count_unsigned_values,
19041  1,
19042  MPI_UNSIGNED,
19043  send_proc,
19044  14,
19045  comm_pt->mpi_comm(),
19046  &request);
19047 
19048  int receive_count_unsigned_values = 0;
19049  MPI_Recv(&receive_count_unsigned_values,
19050  1,
19051  MPI_INT,
19052  recv_proc,
19053  14,
19054  comm_pt->mpi_comm(),
19055  &status);
19056 
19057  MPI_Wait(&request, MPI_STATUS_IGNORE);
19058 
19059  if (send_count_unsigned_values != 0)
19060  {
19061  MPI_Isend(&Flat_packed_unsigneds[0],
19062  send_count_unsigned_values,
19063  MPI_UNSIGNED,
19064  send_proc,
19065  15,
19066  comm_pt->mpi_comm(),
19067  &request);
19068 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19069  for (unsigned i = 0; i < send_count_unsigned_values; i++)
19070  {
19071  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc << " "
19072  << Flat_packed_unsigneds_string[i] << ": "
19073  << Flat_packed_unsigneds[i] << std::endl;
19074  }
19075 #endif
19076  }
19077  if (receive_count_unsigned_values != 0)
19078  {
19079  received_unsigned_values.resize(receive_count_unsigned_values);
19080  MPI_Recv(&received_unsigned_values[0],
19081  receive_count_unsigned_values,
19082  MPI_UNSIGNED,
19083  recv_proc,
19084  15,
19085  comm_pt->mpi_comm(),
19086  &status);
19087  }
19088 
19089  if (send_count_unsigned_values != 0)
19090  {
19091  MPI_Wait(&request, MPI_STATUS_IGNORE);
19092  }
19093 
19094  // Copy across into original containers -- these can now
19095  //------------------------------------------------------
19096  // be processed by create_external_halo_elements() to generate
19097  //------------------------------------------------------------
19098  // external halo elements
19099  //------------------------
19100  Flat_packed_doubles.resize(receive_count_double_values);
19101  for (int ii = 0; ii < receive_count_double_values; ii++)
19102  {
19103  Flat_packed_doubles[ii] = received_double_values[ii];
19104  }
19105  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
19106  for (int ii = 0; ii < receive_count_unsigned_values; ii++)
19107  {
19108  Flat_packed_unsigneds[ii] = received_unsigned_values[ii];
19109  }
19110  }
19111 
19112  //=====================================================================
19113  /// Creates (halo) element on the loop process based on the
19114  /// information received from each processor
19115  //=====================================================================
19116  template<class ELEMENT>
19118  unsigned& iproc,
19119  Vector<Node*>& new_nodes_on_domain,
19120  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19121  other_proc_shd_bnd_node_pt,
19122  Vector<Vector<Vector<unsigned>>>& global_node_names,
19123  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19124  Vector<Node*>& global_shared_node_pt)
19125  {
19126 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19127  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19128  << " Bool: New element needs to be constructed "
19129  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19130  << std::endl;
19131 #endif
19132 
19133  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19134  {
19135  // Create a new element from the communicated values
19136  // and coords from the process that located zeta
19137  GeneralisedElement* new_el_pt = new ELEMENT;
19138 
19139  // Add the element, it is a new element in the mesh
19140  this->add_element_pt(new_el_pt);
19141 
19142  // Add halo element to this mesh
19143  this->add_root_halo_element_pt(iproc, new_el_pt);
19144 
19145  // Cast to the FE pointer
19146  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(new_el_pt);
19147 
19148  // Check if new element is associated to any boundary
19149  this->add_halo_element_helper(iproc, f_el_pt);
19150 
19151  // Now we add nodes to the new element
19152  unsigned n_node = f_el_pt->nnode();
19153 
19154  for (unsigned j = 0; j < n_node; j++)
19155  {
19156  Node* new_nod_pt = 0;
19157 
19158  // Call the add halo node helper function
19159  add_halo_node_helper(new_nod_pt,
19160  new_nodes_on_domain,
19161  other_proc_shd_bnd_node_pt,
19162  iproc,
19163  j,
19164  f_el_pt,
19165  global_node_names,
19166  node_name_to_global_index,
19167  global_shared_node_pt);
19168 
19169  } // for (j<n_nod)
19170  }
19171  else // the element already exists as halo
19172  {
19173 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19174  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19175  << " Index of existing halo element "
19176  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19177  << std::endl;
19178 #endif
19179  // The index itself is in Flat_packed_unsigneds[...]
19180  unsigned halo_ele_index =
19181  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19182 
19183  // Use this index to get the element
19184  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(
19185  this->root_halo_element_pt(iproc, halo_ele_index));
19186 
19187  // If it's not a finite element die
19188  if (f_el_pt == 0)
19189  {
19190  throw OomphLibError("Halo element is not a FiniteElement\n",
19191  OOMPH_CURRENT_FUNCTION,
19192  OOMPH_EXCEPTION_LOCATION);
19193  }
19194 
19195  } // else the element already exists as halo
19196  }
19197 
19198  //========start of add_halo_element_helper==============================
19199  /// Helper function to create (halo) elements on the loop
19200  /// process based on the info received in send_and_received_located_info
19201  /// This function is in charge of verify if the element is associated to
19202  /// a boundary
19203  //======================================================================
19204  template<class ELEMENT>
19206  unsigned& iproc, FiniteElement* ele_pt)
19207  {
19208 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19209  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19210  << " Bool: Element is associated to an original boundary "
19211  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19212  << std::endl;
19213 #endif
19214 
19215  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19216  {
19217 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19218  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19219  << " How many boundaries are associated with the element "
19220  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19221  << std::endl;
19222 #endif
19223  const unsigned nassociated_boundaries =
19224  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19225 
19226  for (unsigned b = 0; b < nassociated_boundaries; b++)
19227  {
19228 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19229  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19230  << " Boundary associated to the element "
19231  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19232  << std::endl;
19233 #endif
19234  const unsigned bnd =
19235  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19236 
19237 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19238  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19239  << " Face index of the element "
19240  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19241  << std::endl;
19242 #endif
19243  const unsigned face_index =
19244  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19245 
19246  // Associate the element with the boundary and establish as many
19247  // face indexes it has
19248  this->Boundary_element_pt[bnd].push_back(ele_pt);
19249  this->Face_index_at_boundary[bnd].push_back(face_index);
19250 
19251  } // (b < nassociated_boundaries)
19252 
19253  // Here read the info. regarding the boundary-region of the element
19254 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19255  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19256  << " Bool: Element is associated to a boundary-region "
19257  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19258  << std::endl;
19259 #endif
19260 
19261  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19262  {
19263 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19264  oomph_info
19265  << "Rec:" << Counter_for_flat_packed_unsigneds
19266  << " How many boundaries-regions are associated with the element "
19267  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19268  << std::endl;
19269 #endif
19270  const unsigned nassociated_boundaries_and_regions =
19271  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19272 
19273  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19274  {
19275 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19276  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19277  << " Boundary associated to the element "
19278  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19279  << std::endl;
19280 #endif
19281  const unsigned bnd =
19282  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19283 
19284 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19285  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19286  << " Region associated to the element "
19287  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19288  << std::endl;
19289 #endif
19290  const unsigned region =
19291  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19292 
19293 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19294  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19295  << " Face index of the element in boundary-region "
19296  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19297  << std::endl;
19298 #endif
19299  const unsigned face_index =
19300  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19301 
19302  // Associate the element with the boundary-regions and establish
19303  // as many face indexes it has
19304  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19305  this->Face_index_region_at_boundary[bnd][region].push_back(
19306  face_index);
19307 
19308  } // for (br < nassociated_boundaries_and_regions)
19309 
19310  } // Is the element associated with a boundary-region?
19311  }
19312 
19313  // Now check if the element is associated to a shared boundary
19314 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19315  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19316  << " Bool: Element is associated to a shared boundary "
19317  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19318  << std::endl;
19319 #endif
19320  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 3)
19321  {
19322 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19323  oomph_info
19324  << "Rec:" << Counter_for_flat_packed_unsigneds
19325  << " How many shared boundaries are associated with the element "
19326  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19327  << std::endl;
19328 #endif
19329  const unsigned nassociated_shared_boundaries =
19330  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19331 
19332  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19333  {
19334 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19335  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19336  << " Shared boundary associated to the element "
19337  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19338  << std::endl;
19339 #endif
19340  const unsigned bnd =
19341  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19342 
19343 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19344  oomph_info
19345  << "Rec:" << Counter_for_flat_packed_unsigneds
19346  << " Face index of the element associated to the shared boundary "
19347  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19348  << std::endl;
19349 #endif
19350 
19351  const unsigned face_index =
19352  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19353 
19354  this->add_shared_boundary_element(bnd, ele_pt);
19355  this->add_face_index_at_shared_boundary(bnd, face_index);
19356 
19357  } // (b < nassociated_shared_boundaries)
19358 
19359  } // The element is associted with a shared boundary
19360  }
19361 
19362  //========start of add_halo_node_helper==========================
19363  /// Helper function to add halo node
19364  //===============================================================
19365  template<class ELEMENT>
19367  Node*& new_nod_pt,
19368  Vector<Node*>& new_nodes_on_domain,
19369  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19370  other_proc_shd_bnd_node_pt,
19371  unsigned& iproc,
19372  unsigned& node_index,
19373  FiniteElement* const& new_el_pt,
19374  Vector<Vector<Vector<unsigned>>>& global_node_names,
19375  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19376  Vector<Node*>& global_shared_node_pt)
19377  {
19378  // Given the node, received information about them from process
19379  // iproc, construct them on the current process
19380 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19381  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19382  << " Bool: New node needs to be constructed "
19383  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19384  << std::endl;
19385 #endif
19386  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
19387  {
19388  // Construct a new node based upon sent information, or copy a node
19389  // from one of the shared boundaries
19390  construct_new_halo_node_helper(new_nod_pt,
19391  new_nodes_on_domain,
19392  other_proc_shd_bnd_node_pt,
19393  iproc,
19394  node_index,
19395  new_el_pt,
19396  global_node_names,
19397  node_name_to_global_index,
19398  global_shared_node_pt);
19399  }
19400  else
19401  {
19402 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19403  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19404  << " Index of existing halo node "
19405  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19406  << std::endl;
19407 #endif
19408 
19409  // Copy node from received location
19410  new_nod_pt = new_nodes_on_domain
19411  [Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
19412 
19413  new_el_pt->node_pt(node_index) = new_nod_pt;
19414  }
19415  }
19416 
19417  //========start of construct_new_halo_node_helper=================
19418  // Helper function which constructs a new external halo node (on new element)
19419  // with the required information sent from the haloed process
19420  //========================================================================
19421  template<class ELEMENT>
19423  Node*& new_nod_pt,
19424  Vector<Node*>& new_nodes_on_domain,
19425  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
19426  other_proc_shd_bnd_node_pt,
19427  unsigned& iproc,
19428  unsigned& node_index,
19429  FiniteElement* const& new_el_pt,
19430  Vector<Vector<Vector<unsigned>>>& global_node_names,
19431  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
19432  Vector<Node*>& global_shared_node_pt)
19433  {
19434  // The first entry indicates the number of values at this new Node
19435  //(which may be different across the same element e.g. Lagrange multipliers)
19436 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19437  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19438  << " Number of values of external halo node "
19439  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19440  << std::endl;
19441 #endif
19442  unsigned n_val = Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19443 
19444  // Null TimeStepper for now
19445  TimeStepper* time_stepper_pt = this->Time_stepper_pt;
19446  // Default number of previous values to 1
19447  unsigned n_prev = time_stepper_pt->ntstorage();
19448 
19449  // ------------------------------------------------------
19450  // Check if the node is on an original boundary
19451 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19452  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19453  << " Is the node on an original boundary "
19454  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19455  << std::endl;
19456 #endif
19457 
19458  // Flag to indicate if the node is on original boundaries
19459  const unsigned node_on_original_boundaries =
19460  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19461 
19462  // Store the original boundaries where the node is on
19463  Vector<unsigned> original_boundaries_node_is_on;
19464  // Store the zeta coordinates of the node on the original boundaries
19465  Vector<double> zeta_coordinates;
19466  // Store the number of original boundaries the node is on
19467  unsigned n_original_boundaries_node_is_on = 0;
19468 
19469  if (node_on_original_boundaries == 2)
19470  {
19471  // How many original boundaries does the node live on?
19472 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19473  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19474  << " Number of boundaries the node is on: "
19475  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19476  << std::endl;
19477 #endif
19478  n_original_boundaries_node_is_on =
19479  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19480 
19481  // Resize the containers
19482  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19483  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19484 
19485  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19486  {
19487  // Boundary number
19488 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19489  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19490  << " Node is on boundary "
19491  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19492  << std::endl;
19493 #endif
19494  original_boundaries_node_is_on[i] =
19495  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19496  zeta_coordinates[i] =
19497  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19498  }
19499 
19500  } // if (node_on_original_boundaries==2)
19501 #ifdef PARANOID
19502  else
19503  {
19504  if (node_on_original_boundaries != 0)
19505  {
19506  std::ostringstream error_message;
19507  error_message
19508  << "The current node is not on an original boundary, this should\n"
19509  << "be indicated by a zero flag. However, the read value for\n"
19510  << "that flag is (" << node_on_original_boundaries << ").\n\n";
19511  throw OomphLibError(
19512  error_message.str(),
19513  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19514  OOMPH_EXCEPTION_LOCATION);
19515  } // if (node_on_original_boundaries != 0)
19516  }
19517 #endif
19518 
19519  // --------------------------------------------------------------
19520  // Check if the node was on a shared boundary with the iproc
19521  // processor
19522 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19523  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19524  << " Is node on shared boundary? "
19525  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19526  << std::endl;
19527 #endif
19528  const unsigned is_node_on_shared_boundary =
19529  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19530  if (is_node_on_shared_boundary == 1)
19531  {
19532  // How many shared boundaries does the node live on?
19533 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19534  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19535  << " Number of boundaries the node is on: "
19536  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19537  << std::endl;
19538 #endif
19539  const unsigned n_shd_bnd_node_is_on =
19540  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19541  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19542  for (unsigned i = 0; i < n_shd_bnd_node_is_on; i++)
19543  {
19544  // Shared boundary number
19545 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19546  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19547  << " Node is on boundary "
19548  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19549  << std::endl;
19550 #endif
19551  shd_bnds_node_is_on[i] =
19552  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19553  }
19554 
19555  // Get the index of the node on the shared boundary
19556 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19557  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19558  << " Index of node on boundary "
19559  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19560  << std::endl;
19561 #endif
19562  // Get the node index of the node on the shared boundary
19563  unsigned node_index_on_shared_boundary =
19564  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19565 
19566  // Get the pointer to the node with the received info.
19567  new_nod_pt = this->sorted_shared_boundary_node_pt(
19568  shd_bnds_node_is_on[0], node_index_on_shared_boundary);
19569 
19570  } // if (is_node_on_shared_boundary == 1)
19571 #ifdef PARANOID
19572  else
19573  {
19574  if (is_node_on_shared_boundary != 0)
19575  {
19576  std::ostringstream error_message;
19577  error_message
19578  << "The current node is not on a shared boundary, this should\n"
19579  << "be indicated by a zero flag. However, the read value for\n"
19580  << "that flag is (" << is_node_on_shared_boundary << ").\n\n";
19581  throw OomphLibError(
19582  error_message.str(),
19583  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19584  OOMPH_EXCEPTION_LOCATION);
19585  } // if (node_on_shared_boundary != 0)
19586  }
19587 #endif
19588 
19589  // ------------------------------------------------------------
19590  // Is the node on a shared boundary with other processor?
19591 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19592  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19593  << " Is the node on shared boundaries with other processors "
19594  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19595  << std::endl;
19596 #endif
19597 
19598  // Is the node in shared boundaries no associated with the
19599  // receiver processor
19600  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19601  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19602 
19603  // The containers where to store the info.
19604  Vector<unsigned> other_processor_1;
19605  Vector<unsigned> other_processor_2;
19606  Vector<unsigned> other_shared_boundaries;
19607  Vector<unsigned> other_indexes;
19608 
19609  // How many shared bounaries with other processors the node lives on
19610  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19611 
19612  // Is the node on shared boundaries with other processors
19613  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19614  {
19615 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19616  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19617  << " In how many shared boundaries with other "
19618  << "processors is the node "
19619  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19620  << std::endl;
19621 #endif
19622 
19623  // How many nodes on other shared boundaries were found
19624  n_shd_bnd_with_other_procs_have_node =
19625  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19626 
19627  // Resize the containers
19628  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19629  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19630  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19631  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19632 
19633  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19634  {
19635 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19636  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19637  << " Processor where the other shared boundary"
19638  << "has the node"
19639  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19640  << std::endl;
19641 #endif
19642  // Read the other processor 1
19643  other_processor_1[i] =
19644  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19645 
19646 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19647  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19648  << " Processor where the other shared boundary"
19649  << "has the node"
19650  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19651  << std::endl;
19652 #endif
19653  // Read the other processor 2
19654  other_processor_2[i] =
19655  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19656 
19657 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19658  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19659  << " Other shared boundary id where the node is on: "
19660  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19661  << std::endl;
19662 #endif
19663 
19664  // Read the other shared boundary id
19665  other_shared_boundaries[i] =
19666  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19667 
19668 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19669  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19670  << " Node index on the other shared boundary "
19671  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19672  << std::endl;
19673 #endif
19674 
19675  // Read the node index on the other shared boundary
19676  other_indexes[i] =
19677  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19678 
19679  } // for (i < n_shd_bnd_with_other_procs_have_node)
19680 
19681  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19682 #ifdef PARANOID
19683  else
19684  {
19685  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19686  {
19687  std::ostringstream error_message;
19688  error_message
19689  << "The current node is not on a shared boundary with\n"
19690  << "other processors, this should be indicated by a zero flag.\n"
19691  << "However, the read value for that flag is ("
19692  << is_the_node_in_shared_boundaries_with_other_processors << ").\n\n";
19693  throw OomphLibError(
19694  error_message.str(),
19695  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19696  OOMPH_EXCEPTION_LOCATION);
19697  }
19698  }
19699 #endif
19700 
19701  // Now we have all the info. to decide whether the node should be
19702  // created or not
19703 
19704  // First check if the node is a shared boundary node
19705  if (is_node_on_shared_boundary == 1)
19706  {
19707  // We already have the node, we do not need to create it
19708 
19709  // Only check if we need to add boundary info. to the node
19710  if (node_on_original_boundaries == 2)
19711  {
19712  // The node is a boundary node, add the boundary info. before
19713  // adding it to the domain
19714 
19715  // Associate the node to the given boundaries
19716  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19717  {
19718  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19719  // Establish the boundary coordinates for the node
19720  Vector<double> zeta(1);
19721  zeta[0] = zeta_coordinates[i];
19722  new_nod_pt->set_coordinates_on_boundary(
19723  original_boundaries_node_is_on[i], zeta);
19724  }
19725 
19726  } // if (node_on_original_boundaries==2)
19727 
19728  // Add the node to the domain
19729  new_nodes_on_domain.push_back(new_nod_pt);
19730 
19731  // Add the node to the element
19732  new_el_pt->node_pt(node_index) = new_nod_pt;
19733 
19734  } // if (is_node_on_shared_boundary == 1)
19735 
19736  // Now check if the node is on a shared boundary with another
19737  // processor, if that is the case try to find the node that may have
19738  // been already sent by the other processors
19739 
19740  // This flags indicates if the node was found, and then decide if it
19741  // is required to create the node
19742  bool found_node_in_other_shared_boundaries = false;
19743  // Flag to indicate whether the node should be created as a boundary
19744  // node or not. If the node lies on a shared boundary with other
19745  // processor the we create it as a boundary node. The processor from
19746  // which we are receiving info. (iproc) may not know that the node
19747  // lies on an original boundary. If the node lies on an original
19748  // boundary then its info. will be sent by another processor, then
19749  // we can set its boundary info. since the node was constructed as a
19750  // boundary node
19751  bool build_node_as_boundary_node = false;
19752 
19753  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19754  {
19755  // Build the node as a boundary node
19756  build_node_as_boundary_node = true;
19757 
19758  // Try to get the node pointer in case that the node has been
19759  // already sent by the other processors
19760 
19761  // Get the number of initial shared boundaries to correct the
19762  // index of the shared boundary
19763  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19764 
19765  // Add the found nodes in the container
19766  Vector<Node*> found_node_pt;
19767 
19768  // Now try to find the node in any of the other shared boundaries
19769  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19770  {
19771  // We always check with the lower processor number. The
19772  // info. is only stored in one direction. More importantly,
19773  // this is done with the hope that the info. has been already
19774  // received from the other processor given that its info. was
19775  // processed before the current processor (iproc). NOTE that
19776  // it is not always the case that this info. has been received
19777  // from the other processors since it may have not require to
19778  // send the elements (and nodes) on the shared boundary with
19779  // the current processor (iproc).
19780  unsigned oproc1 = other_processor_1[i];
19781  unsigned oproc2 = other_processor_2[i];
19782  if (other_processor_1[i] > other_processor_2[i])
19783  {
19784  oproc1 = other_processor_2[i];
19785  oproc2 = other_processor_1[i];
19786  } // if (other_processor_1[i] > other_processor_2[i])
19787 
19788  // Re-compute the shared boundary id between the other
19789  // processors
19790  const unsigned shd_bnd_id =
19791  other_shared_boundaries[i] - initial_shd_bnd_id;
19792 
19793  // Read the index
19794  const unsigned index = other_indexes[i];
19795 
19796  // Check if there are nodes received from the other processor
19797  // and with the given shared boundary
19798  const unsigned n_nodes_on_other_processor =
19799  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19800 
19801  if (n_nodes_on_other_processor > 0)
19802  {
19803  // Check if we can find the index of the node in that
19804  // other processor and shared boundary id
19805  std::map<unsigned, Node*>::iterator it =
19806  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].find(index);
19807 
19808  // If the index exist then get the node pointer
19809  if (it !=
19810  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19811  {
19812  // Mark the node as found
19813  found_node_in_other_shared_boundaries = true;
19814  // Get the node pointer
19815  Node* tmp_node_pt = (*it).second;
19816 
19817  // Push back the node pointer
19818  found_node_pt.push_back(tmp_node_pt);
19819 
19820  } // if (it!=
19821  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19822 
19823  } // if (n_nodes_on_other_processor > 0)
19824 
19825  } // for (i < n_shd_bnd_with_other_procs_have_node)
19826 
19827  // If the node was found, then all their instances should be the
19828  // same but better check
19829  if (found_node_in_other_shared_boundaries)
19830  {
19831 #ifdef PARANOID
19832  const unsigned n_times_node_found = found_node_pt.size();
19833  for (unsigned j = 1; j < n_times_node_found; j++)
19834  {
19835  if (found_node_pt[j - 1] != found_node_pt[j])
19836  {
19837  std::ostringstream error_message;
19838  error_message
19839  << "The instances of the node that was found on\n"
19840  << "shared boundaries with other processors (but not\n"
19841  << "on shared boundaries with this processor) are not\n"
19842  << "the same.\n"
19843  << "These are the coordinates of the instances of the\n"
19844  << "nodes:\n"
19845  << "(" << found_node_pt[j - 1]->x(0) << ", "
19846  << found_node_pt[j - 1]->x(1) << ")\n"
19847  << "(" << found_node_pt[j]->x(0) << ", " << found_node_pt[j]->x(1)
19848  << ")\n"
19849  << "Dont be surprised if they are the same since the "
19850  << "node is\nrepeated.\n";
19851  throw OomphLibError(error_message.str(),
19852  OOMPH_CURRENT_FUNCTION,
19853  OOMPH_EXCEPTION_LOCATION);
19854 
19855  } // if (found_node_pt[j-1] != found_node_pt[j])
19856 
19857  } // for (j < ntimes_node_found)
19858 #endif // #ifdef PARANOID
19859 
19860  // Check if the node is a shared boundary node from the
19861  // current processor and the iproc processor, if that is the
19862  // case, and the node is also on a shared boundary with other
19863  // processor, then the pointer should be the same!!!
19864  if (is_node_on_shared_boundary == 1)
19865  {
19866  // const unsigned n_times_node_found = found_node_pt.size();
19867  // The pointer to the node is already assigned, it was
19868  // assigned when the node was found to be on a shared
19869  // boundary with the sending processor (iproc). Check that
19870  // any previous instances of the node have been copied
19871  // from the shared boundary, if that is not the case then
19872  // there is a problem
19873  if (found_node_pt[0] != new_nod_pt)
19874  {
19875  std::ostringstream error_message;
19876  error_message
19877  << "The pointer of the node that was found to be on a\n"
19878  << "shared boundary with other processor(s) and the pointer\n"
19879  << "of the node on shared boundary with the receiver\n"
19880  << "processor (iproc) are not the same. This means we have a\n"
19881  << "repeated node)\n"
19882  << "The coordinates for the nodes are:\n"
19883  << "(" << found_node_pt[0]->x(0) << ", " << found_node_pt[0]->x(1)
19884  << ")\n"
19885  << "(" << new_nod_pt->x(0) << ", " << new_nod_pt->x(1) << ")\n"
19886  << "Dont be surprised if they are the same since the "
19887  << "node is\nrepeated.\n";
19888  throw OomphLibError(error_message.str(),
19889  OOMPH_CURRENT_FUNCTION,
19890  OOMPH_EXCEPTION_LOCATION);
19891 
19892  } // if (found_node_pt[i] != new_nod_pt)
19893 
19894  } // if (is_node_on_shared_boundary == 1)
19895  else
19896  {
19897  // Take the first instance of the node in case that it was
19898  // found and is not on a shared boundary with the iproc
19899  // processor (the processor from which we are receiving
19900  // the info.)
19901  new_nod_pt = found_node_pt[0];
19902  }
19903 
19904  } // if (found_node_in_other_shared_boundaries)
19905 
19906  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19907 
19908  // -----------------------------------------------------------------
19909  // Create the node or read the received info if the node is not on a
19910  // shared boundary with the iproc processor
19911  if (is_node_on_shared_boundary != 1)
19912  {
19913  // If the node is on a shared boundary with other processor we
19914  // need to read all the info. since the processor that sent the
19915  // info. did not know that the node is part of another shared
19916  // boundary
19917 
19918  // If the node is not on a shared boundary (with any processor),
19919  // or if this is the first time that the info. of the node is
19920  // received from any of the processors with which it has a shared
19921  // boundary, then we create the node
19922 
19923  // Is the node a boundary node or should it be build as a boundary
19924  // node because it is on a shared boundary with other processors
19925  if (node_on_original_boundaries == 2 || build_node_as_boundary_node)
19926  {
19927  // Check if necessary to create the node, or if it has been
19928  // already found in shared boundaries with other processors
19929  if (!found_node_in_other_shared_boundaries)
19930  {
19931  // Construct a boundary node
19932  if (time_stepper_pt != 0)
19933  {
19934  new_nod_pt =
19935  new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
19936  }
19937  else
19938  {
19939  new_nod_pt = new_el_pt->construct_boundary_node(node_index);
19940  }
19941 
19942  } // if (!found_node_in_other_shared_boundaries)
19943  else
19944  {
19945  // If the node was found then assign the node to the element
19946  new_el_pt->node_pt(node_index) = new_nod_pt;
19947 
19948  } // else if (!found_node_in_other_shared_boundaries)
19949 
19950  // Associate the node to the given boundaries
19951  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19952  {
19953  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19954  // Establish the boundary coordinates for the node
19955  Vector<double> zeta(1);
19956  zeta[0] = zeta_coordinates[i];
19957  new_nod_pt->set_coordinates_on_boundary(
19958  original_boundaries_node_is_on[i], zeta);
19959  }
19960 
19961  } // if (node is on an original boundary)
19962  else
19963  {
19964  // Check if necessary to create the node, or if it has been
19965  // already found in shared boundaries with other processors
19966  if (!found_node_in_other_shared_boundaries)
19967  {
19968  // Construct an ordinary (non-boundary) node
19969  if (time_stepper_pt != 0)
19970  {
19971  new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
19972  }
19973  else
19974  {
19975  new_nod_pt = new_el_pt->construct_node(node_index);
19976  }
19977  } // if (!found_node_in_other_shared_boundaries)
19978  else
19979  {
19980  // If the node was found then assign the node to the element
19981  new_el_pt->node_pt(node_index) = new_nod_pt;
19982  } // else if (!found_node_in_other_shared_boundaries)
19983 
19984  } // else (the node is not a boundary node)
19985 
19986  // ... and gather all its information
19987 
19988  // If the node was found or not in other shared boundaries, this
19989  // is the first time the node is received from this processor
19990  // (iproc), therefore it is added to the vector of nodes received
19991  // from this processor (iproc)
19992  new_nodes_on_domain.push_back(new_nod_pt);
19993 
19994  // Check if necessary to state all the info. to the node if it has
19995  // been already found in shared boundaries with other processors
19996  if (!found_node_in_other_shared_boundaries)
19997  {
19998  // Add the node to the general node storage
19999  this->add_node_pt(new_nod_pt);
20000  } // if (!found_node_in_other_shared_boundaries)
20001 
20002  // Is the new constructed node Algebraic?
20003  AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
20004 
20005  // If it is algebraic, its node update functions will
20006  // not yet have been set up properly
20007  if (new_alg_nod_pt != 0)
20008  {
20009  // The AlgebraicMesh is the external mesh
20010  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
20011 
20012  /// The first entry of All_alg_nodal_info contains
20013  /// the default node update id
20014  /// e.g. for the quarter circle there are
20015  /// "Upper_left_box", "Lower right box" etc...
20016 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20017  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20018  << " Alg node update id "
20019  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20020  << std::endl;
20021 #endif
20022 
20023  unsigned update_id =
20024  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20025 
20026  Vector<double> ref_value;
20027 
20028  // The size of this vector is in the next entry
20029  // of All_alg_nodal_info
20030 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20031  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20032  << " Alg node # of ref values "
20033  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20034  << std::endl;
20035 #endif
20036  unsigned n_ref_val =
20037  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20038 
20039  // The reference values themselves are in
20040  // All_alg_ref_value
20041  ref_value.resize(n_ref_val);
20042  for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
20043  {
20044  ref_value[i_ref] =
20045  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20046  }
20047 
20048  Vector<GeomObject*> geom_object_pt;
20049  /// again we need the size of this vector as it varies
20050  /// between meshes; we also need some indication
20051  /// as to which geometric object should be used...
20052 
20053  // The size of this vector is in the next entry
20054  // of All_alg_nodal_info
20055 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20056  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20057  << " Alg node # of geom objects "
20058  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20059  << std::endl;
20060 #endif
20061  unsigned n_geom_obj =
20062  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20063 
20064  // The remaining indices are in the rest of
20065  // All_alg_nodal_info
20066  geom_object_pt.resize(n_geom_obj);
20067  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
20068  {
20069 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20070  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20071  << " Alg node: geom object index "
20072  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20073  << std::endl;
20074 #endif
20075  unsigned geom_index =
20076  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20077  // This index indicates which of the AlgebraicMesh's
20078  // stored geometric objects should be used
20079  // (0 is a null pointer; everything else should have
20080  // been filled in by the specific Mesh). If it
20081  // hasn't been filled in then the update_node_update
20082  // call should fix it
20083  geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
20084  }
20085 
20086  // Check if necessary to state all the info. to the node if it has
20087  // been already found in shared boundaries with other processors
20088  if (!found_node_in_other_shared_boundaries)
20089  {
20090  /// For the received update_id, ref_value, geom_object
20091  /// call add_node_update_info
20092  new_alg_nod_pt->add_node_update_info(
20093  update_id, alg_mesh_pt, geom_object_pt, ref_value);
20094 
20095  /// Now call update_node_update
20096  alg_mesh_pt->update_node_update(new_alg_nod_pt);
20097 
20098  } // if (!found_node_in_other_shared_boundaries)
20099 
20100  } // if (new_alg_nod_pt!=0)
20101 
20102  // Check if necessary to state all the info. to the node if it has
20103  // been already found in shared boundaries with other processors
20104  if (!found_node_in_other_shared_boundaries)
20105  {
20106  // Is the node a MacroElementNodeUpdateNode?
20107  MacroElementNodeUpdateNode* macro_nod_pt =
20108  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
20109 
20110  if (macro_nod_pt != 0)
20111  {
20112  // Need to call set_node_update_info; this requires
20113  // a Vector<GeomObject*> (taken from the mesh)
20114  Vector<GeomObject*> geom_object_vector_pt;
20115 
20116  // Access the required geom objects from the
20117  // MacroElementNodeUpdateMesh
20118  MacroElementNodeUpdateMesh* macro_mesh_pt =
20119  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
20120  geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
20121 
20122  // Get local coordinate of node in new element
20123  Vector<double> s_in_macro_node_update_element;
20124  new_el_pt->local_coordinate_of_node(node_index,
20125  s_in_macro_node_update_element);
20126 
20127  // Set node update info for this node
20128  macro_nod_pt->set_node_update_info(
20129  new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
20130  }
20131 
20132  } // if (!found_node_in_other_shared_boundaries)
20133 
20134  // If there are additional values, resize the node
20135  unsigned n_new_val = new_nod_pt->nvalue();
20136 
20137  // Check if necessary to state all the info. to the node if it has
20138  // been already found in shared boundaries with other processors
20139  if (!found_node_in_other_shared_boundaries)
20140  {
20141  if (n_val > n_new_val)
20142  {
20143  // If it has been necessary to resize then it may be becuse
20144  // the node is on a FSI boundary, if that is the case we need
20145  // to set a map for these external values
20146 
20147  // Cast to a boundary node
20148  BoundaryNodeBase* bnod_pt =
20149  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
20150 
20151  // Create storage, if it doesn't already exist, for the map
20152  // that will contain the position of the first entry of
20153  // this face element's additional values,
20154  if (bnod_pt->index_of_first_value_assigned_by_face_element_pt() == 0)
20155  {
20156  bnod_pt->index_of_first_value_assigned_by_face_element_pt() =
20157  new std::map<unsigned, unsigned>;
20158  }
20159 
20160  // Get pointer to the map
20161  std::map<unsigned, unsigned>* map_pt =
20162  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
20163 
20164  // The id of the face to which this node belong in the bulk
20165  // element
20166  const unsigned id_face = 0;
20167  // We only resize the node values Vector if we haven't done it yet
20168  std::map<unsigned, unsigned>::const_iterator p =
20169  map_pt->find(id_face);
20170 
20171  // If this node hasn't been resized for current id
20172  if (p == map_pt->end())
20173  {
20174  // assign the face element id and the position of the
20175  // first entry to the boundary node
20176  (*map_pt)[id_face] = n_new_val;
20177 
20178  // resize the node vector of values
20179  new_nod_pt->resize(n_val);
20180  }
20181 
20182  } // if (n_val>n_new_val)
20183 
20184  } // if (!found_node_in_other_shared_boundaries)
20185 
20186  // Is the new node a SolidNode?
20187  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
20188  if (solid_nod_pt != 0)
20189  {
20190  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
20191  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
20192  {
20193  for (unsigned t = 0; t < n_prev; t++)
20194  {
20195  double read_data =
20196  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20197 
20198  // Check if necessary to state all the info. to the node if it has
20199  // been already found in shared boundaries with other processors
20200  if (!found_node_in_other_shared_boundaries)
20201  {
20202  solid_nod_pt->variable_position_pt()->set_value(
20203  t, i_val, read_data);
20204  } // if (!found_node_in_other_shared_boundaries)
20205  }
20206  }
20207 
20208 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
20209  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
20210  << " Number of values solid node: "
20211  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
20212  << std::endl;
20213 #endif
20214  const unsigned nvalues_solid_node =
20215  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
20216  Vector<double> values_solid_node(nvalues_solid_node);
20217  for (unsigned i = 0; i < nvalues_solid_node; i++)
20218  {
20219  values_solid_node[i] =
20220  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20221  }
20222 
20223  // Check if necessary to state all the info. to the node if it has
20224  // been already found in shared boundaries with other processors
20225  if (!found_node_in_other_shared_boundaries)
20226  {
20227  unsigned index = 0;
20228  solid_nod_pt->read_values_from_vector(values_solid_node, index);
20229  }
20230  }
20231 
20232  // Get copied history values
20233  // unsigned n_val=new_nod_pt->nvalue();
20234  for (unsigned i_val = 0; i_val < n_val; i_val++)
20235  {
20236  for (unsigned t = 0; t < n_prev; t++)
20237  {
20238  double read_data =
20239  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20240 
20241  // Check if necessary to state all the info. to the node if it
20242  // has been already found in shared boundaries with other
20243  // processors
20244  if (!found_node_in_other_shared_boundaries)
20245  {
20246  new_nod_pt->set_value(t, i_val, read_data);
20247  } // if (!found_node_in_other_shared_boundaries)
20248  }
20249  }
20250 
20251  // Get copied history values for positions
20252  unsigned n_dim = new_nod_pt->ndim();
20253  for (unsigned idim = 0; idim < n_dim; idim++)
20254  {
20255  for (unsigned t = 0; t < n_prev; t++)
20256  {
20257  double read_data =
20258  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20259 
20260  // Check if necessary to state all the info. to the node if it
20261  // has been already found in shared boundaries with other
20262  // processors
20263  if (!found_node_in_other_shared_boundaries)
20264  {
20265  // Copy to coordinate
20266  new_nod_pt->x(t, idim) = read_data;
20267 
20268  } // if (!found_node_in_other_shared_boundaries)
20269  }
20270  }
20271 
20272  } // if (is_node_on_shared_boundary != 1)
20273 
20274  // If the node was not found in other shared boundaries (possibly
20275  // because it is the first time the node has been sent) then copy
20276  // the node to the shared boundaries where it should be, use the
20277  // special container for this cases
20278  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20279  // shared
20280  // boundaries with
20281  // other processors
20282  !found_node_in_other_shared_boundaries) // The node has not
20283  // been previously
20284  // set as
20285  // shared with
20286  // other processors
20287  // (first time)
20288  {
20289  // Update the node pointer in all the (references) of the node
20290  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20291  other_proc_shd_bnd_node_pt,
20292  other_processor_1,
20293  other_processor_2,
20294  other_shared_boundaries,
20295  other_indexes,
20296  global_node_names,
20297  node_name_to_global_index,
20298  global_shared_node_pt);
20299 
20300  } // if (!found_node_in_other_shared_boundaries)
20301  }
20302 
20303  //========start of update_other_proc_shd_bnd_node_helper=================
20304  // Helper function that assigns/updates the references to the node so
20305  // that it can be found with any other reference
20306  //========================================================================
20307  template<class ELEMENT>
20309  Node*& new_node_pt,
20310  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
20311  other_proc_shd_bnd_node_pt,
20312  Vector<unsigned>& other_processor_1,
20313  Vector<unsigned>& other_processor_2,
20314  Vector<unsigned>& other_shared_boundaries,
20315  Vector<unsigned>& other_indexes,
20316  Vector<Vector<Vector<unsigned>>>& global_node_names,
20317  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
20318  Vector<Node*>& global_shared_node_pt)
20319  {
20320  // Get the number of initial shared boundaries to correct the index
20321  // of the shared boundary
20322  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20323 
20324 #ifdef PARANOID
20325  // Get the number of instances of the node on other shared
20326  // boundaries with other processors
20327  const unsigned n_data = other_processor_1.size();
20328 #endif // #ifdef PARANOID
20329 
20330  // Create the first node name
20331  Vector<unsigned> node_name(4);
20332  node_name[0] = other_processor_1[0];
20333  node_name[1] = other_processor_2[0];
20334  node_name[2] = other_shared_boundaries[0];
20335  node_name[3] = other_indexes[0];
20336 
20337 #ifdef PARANOID
20338  // Get the global node index, and all the names of the node
20339  std::map<Vector<unsigned>, unsigned>::iterator it =
20340  node_name_to_global_index.find(node_name);
20341  if (it == node_name_to_global_index.end())
20342  {
20343  std::ostringstream error_stream;
20344  error_stream << "The node name does not exist in the global node names\n"
20345  << "This is the name of the node\n"
20346  << "Name: iproc, jproc, ishd_bnd, idx\n"
20347  << "Name: " << node_name[0] << ", " << node_name[1] << ", "
20348  << node_name[2] << ", " << node_name[3] << "\n";
20349  throw OomphLibError(
20350  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20351  } // if (it!=node_name_to_global_index.end())
20352 #endif // #ifdef PARANOID
20353 
20354  // Get the global node index
20355  const unsigned iglobal_node = node_name_to_global_index[node_name];
20356  // Add the node to the global shared node container
20357  global_shared_node_pt[iglobal_node] = new_node_pt;
20358  // Get the names
20359  Vector<Vector<unsigned>> inode_names = global_node_names[iglobal_node];
20360  // Get the number of names of the node
20361  const unsigned n_names = inode_names.size();
20362 
20363 #ifdef PARANOID
20364  // Check that the received names of the node are part of the global
20365  // node names
20366  unsigned n_found_node_names_on_global_node_name = 0;
20367  // loop over the input node names
20368  for (unsigned j = 0; j < n_data; j++)
20369  {
20370  // loop over the inode_names
20371  for (unsigned k = 0; k < n_names; k++)
20372  {
20373  // Is this input name part of the global node names?
20374  if (inode_names[k][0] == other_processor_1[j] &&
20375  inode_names[k][1] == other_processor_2[j] &&
20376  inode_names[k][2] == other_shared_boundaries[j] &&
20377  inode_names[k][3] == other_indexes[j])
20378  {
20379  // Increase the number of found input node names in the
20380  // global node names
20381  n_found_node_names_on_global_node_name++;
20382  }
20383 
20384  } // for (k < n_names)
20385 
20386  } // for (j < n_data)
20387 
20388  // Were all the input node names found on the global node names?
20389  if (n_found_node_names_on_global_node_name != n_data)
20390  {
20391  std::ostringstream error_stream;
20392  error_stream
20393  << "Not all the node names of the current node were found on the\n"
20394  << "global node names. This happened when adding the node pointer\n"
20395  << "to the data structure that keeps tracks of nodes on shared\n"
20396  << "boundaries with other processors\n\n"
20397  << "These are the names of the current node\n"
20398  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20399  for (unsigned j = 0; j < n_data; j++)
20400  {
20401  error_stream << "Name(" << j << "): " << other_processor_1[j] << ", "
20402  << other_processor_2[j] << ", "
20403  << other_shared_boundaries[j] << ", " << other_indexes[j]
20404  << "\n";
20405  }
20406 
20407  error_stream << "\n\nThese are the names of the global node\n"
20408  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20409  for (unsigned k = 0; k < n_names; k++)
20410  {
20411  error_stream << "Name(" << k << "): " << inode_names[k][0] << ", "
20412  << inode_names[k][1] << ", " << inode_names[k][2] << ", "
20413  << inode_names[k][3] << "\n";
20414  }
20415 
20416  throw OomphLibError(
20417  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20418  }
20419 #endif // #ifdef PARANOID
20420 
20421  // Set the node pointer in all of its names
20422  for (unsigned j = 0; j < n_names; j++)
20423  {
20424  // Get the j-th node name
20425  const unsigned iproc = inode_names[j][0];
20426  const unsigned jproc = inode_names[j][1];
20427  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20428  const unsigned index = inode_names[j][3];
20429 
20430  // The info. is stored only in one direction
20431  // Get the smallest processor number
20432  if (iproc < jproc)
20433  {
20434  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index] = new_node_pt;
20435  }
20436  else
20437  {
20438  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index] = new_node_pt;
20439  }
20440 
20441  } // for (j < n_names)
20442  }
20443 
20444  // *********************************************************************
20445  // End communication functions
20446  // *********************************************************************
20447 
20448  // *********************************************************************
20449  // BEGIN: Methods to perform load balance
20450  // *********************************************************************
20451 
20452  //======================================================================
20453  /// Performs the load balancing for unstructured meshes, the
20454  /// load balancing strategy is based on mesh migration
20455  //======================================================================
20456  template<class ELEMENT>
20458  const Vector<unsigned>& target_domain_for_local_non_halo_element)
20459  {
20460  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20461 
20462  // This method can only be called when the mesh has been already
20463  // distributed
20464  if (!this->is_mesh_distributed())
20465  {
20466  std::ostringstream warning_message;
20467  warning_message
20468  << "\n===============================================================\n"
20469  << "The load balancing can only be performed in distributed meshes,\n"
20470  << "your mesh has not been distributed.\n"
20471  << "==============================================================="
20472  "\n\n";
20473  OomphLibWarning(warning_message.str(),
20474  OOMPH_CURRENT_FUNCTION,
20475  OOMPH_EXCEPTION_LOCATION);
20476  // Return
20477  return;
20478  }
20479 
20480  // Get the number of processors
20481  const unsigned nproc = this->communicator_pt()->nproc();
20482  // Get the rank of the current processors
20483  const unsigned my_rank = this->communicator_pt()->my_rank();
20484 
20485  // Check that there are at least two processors
20486  if (nproc == 1)
20487  {
20488  std::ostringstream warning_message;
20489  warning_message
20490  << "\n===============================================================\n"
20491  << "The load balancing can only be performed when there are at least\n"
20492  << "two procesors, the current number of processors is one.\n"
20493  << "==============================================================="
20494  "\n\n";
20495  OomphLibWarning(warning_message.str(),
20496  OOMPH_CURRENT_FUNCTION,
20497  OOMPH_EXCEPTION_LOCATION);
20498  // Return
20499  return;
20500  }
20501 
20502  // Get the time before load balance
20503  double t_start_overall_load_balance = 0.0;
20504  if (Print_timings_level_load_balance > 1)
20505  {
20506  t_start_overall_load_balance = TimingHelpers::timer();
20507  }
20508 
20509  // Get the number of elements in the mesh before load balance
20510  const unsigned nelement_before_load_balance = this->nelement();
20511 
20512 #ifdef PARANOID
20513  // The number of elements in the mesh and the number of target
20514  // domains for the local non halo elements in the mesh should match
20515  if (nnon_halo_element() != target_domain_for_local_non_halo_element.size())
20516  {
20517  std::ostringstream error_message;
20518  error_message << "The number of non halo elements in the current mesh ("
20519  << nnon_halo_element() << ") and the number\n"
20520  << "of target areas for the local non halo elements ("
20521  << target_domain_for_local_non_halo_element.size()
20522  << ") is different\n\n";
20523  throw OomphLibError(
20524  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
20525  }
20526 #endif
20527 
20528  // Backup pointers to elements in this mesh
20529  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20530  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20531  {
20532  backed_up_ele_pt[e] = this->finite_element_pt(e);
20533  }
20534 
20535  // =====================================================================
20536  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20537  // =====================================================================
20538 
20539  // Get the time to get the domains of halo elements
20540  double tt_start_get_domains_halo_elements = 0.0;
20541  if (Print_timings_level_load_balance > 1)
20542  {
20543  tt_start_get_domains_halo_elements = TimingHelpers::timer();
20544  }
20545 
20546  // Get the new domains for the halo elements
20547 
20548  // Send the new domains for the current haloed elements, and receive
20549  // the new domains for the current halo elements
20550  // -- 1) On the current processor get the new domains for the
20551  // haloed elements
20552  // -- 2) Then send this info. to all the processor that have a
20553  // halo copy of the element
20554 
20555  // The storing for the new domains of the haloed elements (sent to
20556  // other processors)
20557  Vector<Vector<unsigned>> new_domains_haloed_elements(nproc);
20558  // The storing for the new domains of the halo elements (received
20559  // from other processors)
20560  Vector<Vector<unsigned>> new_domains_halo_elements(nproc);
20561 
20562  // First resize the containers by getting the current number of
20563  // halo/haloed elements within each processor
20564  for (unsigned iproc = 0; iproc < nproc; iproc++)
20565  {
20566  // There are no halo/haloed elements with myself (my_rank
20567  // processor)
20568  if (iproc != my_rank)
20569  {
20570  // Get the number of halo elements with iproc processor
20571  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20572  // Resize the container
20573  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20574 
20575  // Get the number of haloed elements with iproc processor
20576  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20577  // Resize the container
20578  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20579  } // if (iproc != my_rank)
20580  } // for (iproc < nproc)
20581 
20582 #ifdef PARANOID
20583  // Count the number of found haloed elements
20584  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20585 #endif
20586 
20587  // Go through all the haloed elements and find their new domain
20588 
20589  // Get the haloed elements with in each processor and check if the
20590  // element is haloed with the processor
20591  for (unsigned iproc = 0; iproc < nproc; iproc++)
20592  {
20593  // There are no halo/haloed elements with myself (my_rank
20594  // processor)
20595  if (iproc != my_rank)
20596  {
20597  // Get the number of haloed elements with iproc processor
20598  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20599 
20600  // Loop over the haloed elements
20601  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20602  {
20603  // Get the ihd-th haloed element with "iproc" processor
20604  GeneralisedElement* haloed_ele_pt =
20605  this->root_haloed_element_pt(iproc, ihd);
20606 
20607  // The counter for the nonhalo elements
20608  unsigned nh_count4 = 0;
20609  // Find the element in the general elements container
20610  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20611  {
20612  // Get the e-th element
20613  GeneralisedElement* ele_pt = this->element_pt(e);
20614  // Check if the element is a nonhalo element
20615  if (!ele_pt->is_halo())
20616  {
20617  // Increase the counter for nonhalo elements, in case the
20618  // haloed element is found get the (nh_count4-1) position
20619  // in the target domains vector
20620  nh_count4++;
20621 
20622  if (ele_pt == haloed_ele_pt)
20623  {
20624  // Get the new domain for this element
20625  const unsigned element_domain =
20626  target_domain_for_local_non_halo_element[nh_count4 - 1];
20627  // Here decrease the counter ---------------------^
20628 
20629  // Set the new domain for the haloed element in the
20630  // special container
20631  new_domains_haloed_elements[iproc][ihd] = element_domain;
20632 #ifdef PARANOID
20633  // Increase the counter
20634  counter_for_found_haloed_elements[iproc]++;
20635 #endif
20636  // ... and break the "for" with the general
20637  // elements. Continue with the next haloed element
20638  break;
20639 
20640  } // if (ele_pt == haloed_ele_pt))
20641 
20642  } // if (!ele_pt->is_halo())
20643 
20644  } // for (e < nelement_before_load_balance)
20645 
20646  } // for (ihd < n_haloed_iproc)
20647 
20648  } // if (iproc != my_rank)
20649 
20650  } // for (iproc < nproc)
20651 
20652 #ifdef PARANOID
20653  // Check that all the haloed elements with all processors have been
20654  // found
20655  for (unsigned iproc = 0; iproc < nproc; iproc++)
20656  {
20657  // There are no halo/haloed elements with myself (my_rank
20658  // processor)
20659  if (iproc != my_rank)
20660  {
20661  // Get the number of haloed elements with "iproc" processor
20662  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20663 
20664  // Compare the number of found haloed elements with the current
20665  // number of haloed elements
20666  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20667  {
20668  std::ostringstream error_message;
20669  error_message << "The independent counting of found haloed elements ("
20670  << counter_for_found_haloed_elements[iproc]
20671  << ") with processor (" << iproc
20672  << ") is not equal to the number of haloed elements ("
20673  << n_haloed_iproc << ") with processor (" << iproc
20674  << ")\n";
20675  throw OomphLibError(error_message.str(),
20676  OOMPH_CURRENT_FUNCTION,
20677  OOMPH_EXCEPTION_LOCATION);
20678  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20679 
20680  } // if (iproc != my_rank)
20681 
20682  } // for (iproc < nproc)
20683 #endif
20684 
20685  // Now we have the new domains for the haloed elements
20686 
20687  // Send this info. to the processor with a halo copy of the haloed
20688  // elements and set the new domains in the halo copies
20689 
20690  // First put all the info. in a flat package array
20691  Vector<unsigned> new_domains_haloed_flat_unsigned;
20692  // Put in a vector the number of haloed elements within each
20693  // processor
20694  Vector<int> nhaloed_elements_with_iproc(nproc);
20695  for (unsigned iproc = 0; iproc < nproc; iproc++)
20696  {
20697  // There are no halo/haloed elements with myself (my_rank
20698  // processor)
20699  if (iproc != my_rank)
20700  {
20701  // Get the number of haloed elements with "iproc" processor
20702  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20703  // Copy the number of haloed elements with "iproc" processor
20704  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20705  // Copy the new domains of the haloed elements in the flat
20706  // package
20707  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20708  {
20709  new_domains_haloed_flat_unsigned.push_back(
20710  new_domains_haloed_elements[iproc][i]);
20711  } // for (i < n_haloed_ele_iproc)
20712 
20713  } // if (iproc != my_rank)
20714 
20715  } // for (iproc < nproc)
20716 
20717  // The offsets of the flat package within each processor
20718  Vector<int> offset_haloed_elements_with_iproc(nproc);
20719  offset_haloed_elements_with_iproc[0] = 0;
20720  for (unsigned ip = 1; ip < nproc; ip++)
20721  {
20722  // Compute the offset to send the values to each processor
20723  offset_haloed_elements_with_iproc[ip] =
20724  offset_haloed_elements_with_iproc[ip - 1] +
20725  nhaloed_elements_with_iproc[ip - 1];
20726  } // for (ip < nproc)
20727 
20728  // Prepare to receive the data
20729 
20730  // Compute the number of data (halo elements) to receive from each
20731  // processor and the displacements within each processor
20732 
20733  // Counter for the total number of halo elements within all processors
20734  unsigned counter_halo_ele_with_all_procs = 0;
20735 
20736  // Put in a vector the number of halo elements expected to receive
20737  // from each processor
20738  Vector<int> nhalo_elements_with_iproc(nproc);
20739  // Compute the number of total halo elements of (my_rank) this
20740  // processor with all other processors
20741  for (unsigned iproc = 0; iproc < nproc; iproc++)
20742  {
20743  // There are no halo/haloed elements with myself (my_rank
20744  // processor)
20745  if (iproc != my_rank)
20746  {
20747  // Get the number of halo elements with "iproc" processor
20748  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20749  // Copy the number of halo elements with "iproc" processor
20750  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20751  // Add the number of elements with this processor
20752  counter_halo_ele_with_all_procs += n_halo_ele_iproc;
20753  } // if (iproc != my_rank)
20754 
20755  } // for (iproc < nproc)
20756 
20757  // The offsets of the flat package within each processor
20758  Vector<int> offset_halo_elements_with_iproc(nproc);
20759  offset_halo_elements_with_iproc[0] = 0;
20760  for (unsigned ip = 1; ip < nproc; ip++)
20761  {
20762  // Compute the offset to receive the values from each processor
20763  offset_halo_elements_with_iproc[ip] =
20764  offset_halo_elements_with_iproc[ip - 1] +
20765  nhalo_elements_with_iproc[ip - 1];
20766  } // for (ip < nproc)
20767 
20768  // The flat container to receive the new domains of the halo
20769  // elements in the current processor
20770 
20771  // The flat package where all the info. will be gather from the
20772  // other processors (the halo flat package)
20773  Vector<unsigned> new_domains_halo_flat_unsigned(
20774  counter_halo_ele_with_all_procs);
20775 
20776  // Perform the sending and receiving of information to and from all
20777  // processors
20778  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20779  &nhaloed_elements_with_iproc[0], // int *sendcnts
20780  &offset_haloed_elements_with_iproc[0], // int *sdispls
20781  MPI_UNSIGNED, // MPI_Datatype sendtype
20782  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20783  &nhalo_elements_with_iproc[0], // int *recvcnts
20784  &offset_halo_elements_with_iproc[0], // int *rdispls
20785  MPI_UNSIGNED, // MPI_Datatype recvtype
20786  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20787 
20788  // Once received the new domains for the halo elements, copy the
20789  // domains back to an easier to handle container (from the flat
20790  // package to the one with the different halo elements domains
20791  // within each processor)
20792  unsigned counter_new_domains_halo_ele = 0;
20793  for (unsigned iproc = 0; iproc < nproc; iproc++)
20794  {
20795  // There are no halo/haloed elements with myself (my_rank
20796  // processor)
20797  if (iproc != my_rank)
20798  {
20799  // Get the number of halo elements with "iproc"
20800  const unsigned ntmp_halo_elements_with_iproc =
20801  nhalo_elements_with_iproc[iproc];
20802  // Loop over the number of halo elements within "iproc" and copy
20803  // the elements from the flat package
20804  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20805  {
20806  // Copy the new domain of the halo elements from the flat
20807  // package to an easier to use container
20808  new_domains_halo_elements[iproc][i] =
20809  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20810  }
20811  } // if (iproc != my_rank)
20812  } // for (iproc < nproc)
20813 
20814  // The time to get domains of halo elements
20815  if (Print_timings_level_load_balance > 1)
20816  {
20817  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20818  << TimingHelpers::timer() - tt_start_get_domains_halo_elements
20819  << std::endl;
20820  }
20821 
20822  // =====================================================================
20823  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20824  // =====================================================================
20825 
20826  // =====================================================================
20827  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20828  // ELEMENTS
20829  // =====================================================================
20830 
20831  // Get the time to get FiniteElement versions from Generalised
20832  // halo(ed) elements
20833  double tt_start_get_fe_version_from_ge_halo_ed = 0.0;
20834  if (Print_timings_level_load_balance > 1)
20835  {
20836  tt_start_get_fe_version_from_ge_halo_ed = TimingHelpers::timer();
20837  }
20838 
20839  // The finite element storage for the halo elements
20840  Vector<Vector<FiniteElement*>> f_halo_element_pt(nproc);
20841  // The finite element storage for the haloed elements
20842  Vector<Vector<FiniteElement*>> f_haloed_element_pt(nproc);
20843  // Loop over the processors
20844  for (unsigned iproc = 0; iproc < nproc; iproc++)
20845  {
20846  // There are no halo(ed) elements with myself
20847  if (iproc != my_rank)
20848  {
20849  // Get the number of halo elements with the "iproc" processor
20850  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20851  // Get the halo elements with the "iproc" processor
20852  Vector<GeneralisedElement*> halo_element_pt_iproc =
20853  this->root_halo_element_pt(iproc);
20854  // Resize the finite element container
20855  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20856  // Loop over the halo elements
20857  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20858  {
20859  // Get the finite element
20860  FiniteElement* ele_pt =
20861  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20862  // Store the finite element version of the element
20863  f_halo_element_pt[iproc][ih] = ele_pt;
20864  } // for (ih < nhalo_ele_iproc)
20865 
20866  // Get the number of haloed elements with the "iproc" processor
20867  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20868  // Get the haloed elements with the "iproc" processor
20869  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20870  this->root_haloed_element_pt(iproc);
20871  // Resize the finite element container
20872  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20873  // Loop over the haloed elements
20874  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20875  {
20876  // Get the finite element
20877  FiniteElement* ele_pt =
20878  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20879  // Store the finite element version of the element
20880  f_haloed_element_pt[iproc][ihd] = ele_pt;
20881  } // for (ih < nhaloed_ele_iproc)
20882 
20883  } // if (iproc != my_rank)
20884 
20885  } // for (iproc < nproc)
20886 
20887  // The time to get FiniteElement versions from Generalised halo(ed)
20888  // elements
20889  if (Print_timings_level_load_balance > 1)
20890  {
20891  oomph_info << "CPU for getting finite element versions from generalised "
20892  "halo(ed) elements (load balance) [2]: "
20893  << TimingHelpers::timer() -
20894  tt_start_get_fe_version_from_ge_halo_ed
20895  << std::endl;
20896  }
20897 
20898  // =====================================================================
20899  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20900  // ELEMENTS
20901  // =====================================================================
20902 
20903  // =====================================================================
20904  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20905  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20906  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20907  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20908  // =====================================================================
20909 
20910  // Get the time to prepare elements to send to other processors
20911  double tt_start_prepare_element_to_send = 0.0;
20912  if (Print_timings_level_load_balance > 1)
20913  {
20914  tt_start_prepare_element_to_send = TimingHelpers::timer();
20915  }
20916 
20917  // Store the elements that will be sent to other processors
20918  Vector<Vector<FiniteElement*>> elements_to_send_pt(nproc);
20919 
20920  // Associate the nodes of each element with the processor the
20921  // element will live on
20922  std::map<Data*, std::set<unsigned>>
20923  processors_associated_with_data_before_load_balance;
20924 
20925  // Compute the elements that will be sent to other processor and
20926  // associate the nodes with the processor the element will live on
20927  unsigned nh_count3 = 0;
20928  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20929  {
20930  // Get the element
20931  FiniteElement* ele_pt = this->finite_element_pt(e);
20932  // Only work with nonhalo elements
20933  if (!(ele_pt->is_halo()))
20934  {
20935  // Get the new domain for the elment
20936  const unsigned element_domain =
20937  target_domain_for_local_non_halo_element[nh_count3++];
20938 
20939  // Include the element in the corresponding vector
20940  elements_to_send_pt[element_domain].push_back(ele_pt);
20941 
20942  // Get the number of nodes on the element
20943  const unsigned n_nodes = ele_pt->nnode();
20944  // Loop over the nodes
20945  for (unsigned j = 0; j < n_nodes; j++)
20946  {
20947  // Get each node of the element
20948  Node* node_pt = ele_pt->node_pt(j);
20949  // ... and associate it with element domains
20950  processors_associated_with_data_before_load_balance[node_pt].insert(
20951  element_domain);
20952 
20953  } // for (j < n_nodes)
20954 
20955  } // if (!(ele_pt->is_halo()))
20956 
20957  } // for (e < nelement_before_load_balance)
20958 
20959  // ... do the same for the halo elements (but do not add them to the
20960  // sending container since only the processor with the haloed
20961  // counterparts is in charge of that). Associate the nodes of the
20962  // halo elements with the processor they will live on
20963  for (unsigned iproc = 0; iproc < nproc; iproc++)
20964  {
20965  // There is no halo elements with myself
20966  if (iproc != my_rank)
20967  {
20968  // Get the number of halo elements with the "iproc" processor
20969  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20970  // Get the halo elements with the "iproc" processor
20971  Vector<GeneralisedElement*> halo_element_pt_iproc =
20972  this->root_halo_element_pt(iproc);
20973  // Loop over the halo elements with iproc
20974  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20975  {
20976  // Get the new domain for the halo element
20977  const unsigned element_domain = new_domains_halo_elements[iproc][ih];
20978 
20979  // Get the finite element
20980  FiniteElement* ele_pt =
20981  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20982 
20983  // Get the number of nodes on the halo element
20984  const unsigned n_nodes = ele_pt->nnode();
20985  // Loop over the nodes
20986  for (unsigned j = 0; j < n_nodes; j++)
20987  {
20988  // Get each node of the halo element
20989  Node* node_pt = ele_pt->node_pt(j);
20990 
20991  // ... and associate it with element domains
20992  processors_associated_with_data_before_load_balance[node_pt].insert(
20993  element_domain);
20994 
20995  } // for (j < n_nodes)
20996 
20997  } // for (ih < nhalo_ele_iproc)
20998 
20999  } // if (iproc != my_rank)
21000 
21001  } // for (iproc < nproc)
21002 
21003  // The time to prepare elements to send to other processors
21004  if (Print_timings_level_load_balance > 1)
21005  {
21006  oomph_info << "CPU for preparing elements to send to other processors "
21007  "(load balance) [3]: "
21008  << TimingHelpers::timer() - tt_start_prepare_element_to_send
21009  << std::endl;
21010  }
21011 
21012  // Now all the nodes are associated with the processor where the
21013  // element will live on. This is performed for the nonhalo and halo
21014  // elements
21015 
21016  // =====================================================================
21017  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
21018  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
21019  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
21020  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
21021  // =====================================================================
21022 
21023  // =====================================================================
21024  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21025  // CURRENT PROCESSOR
21026  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21027  // =====================================================================
21028 
21029  // Get the time to compute new local halo elements within all
21030  // processors
21031  double tt_start_compute_new_local_halo_elements = 0.0;
21032  if (Print_timings_level_load_balance > 1)
21033  {
21034  tt_start_compute_new_local_halo_elements = TimingHelpers::timer();
21035  }
21036 
21037  // Before sending the elements across compute the new local
21038  // halo/haloed elements of each processor. Each processor could have
21039  // elements that will be part of the new halo/haloed elements of
21040  // another processors, then these processors need to compute the
21041  // relations that may happen among these other processors
21042 
21043  // Example:
21044  // Processor 1 may have elements that will be sent to processor 3
21045  // and 4. These processors need to know about the new halo elements
21046  // betweeen them but at this moment only processor 1 can compute that
21047  // info., since it is the only one that currently has that info.
21048 
21049  // Store the new local-halo elements of each processor, the HALOED
21050  // elements are also stored in the container, only needs to INVERT
21051  // the indexes. For example, the HALO elements of processor 2 with
21052  // processor 3 are stored in new_local_halo_element_pt[2][3], and
21053  // the HALOED elements of processor 2 with processor 3 are stored in
21054  // new_local_halo_element_pt[3][2]. Notice that these are also the
21055  // halo elements of processor 3 with 2
21056 
21057  // How to identify the new local halo/haloed element: 1) Loop over
21058  // the element; 2) Only work with nonhalo elements; 3) If the
21059  // element is not assigned to the current processor (iproc) then
21060  // check; 4) Is one of its nodes assiociated to the iproc processor?
21061  // 5) If yes the element is a halo in the iproc processor whose
21062  // nonhalo counter part (haloed) lives in the domain assigned to the
21063  // element
21064  Vector<Vector<Vector<FiniteElement*>>> new_local_halo_element_pt(nproc);
21065 
21066  // Loop over the processors
21067  for (unsigned iproc = 0; iproc < nproc; iproc++)
21068  {
21069  // Resize the container
21070  new_local_halo_element_pt[iproc].resize(nproc);
21071 
21072  // Boolean to know which elements have been already added to the
21073  // new local halo scheme in "iproc"
21074  Vector<std::map<FiniteElement*, bool>> new_local_halo_already_added(
21075  nproc);
21076 
21077  // Go through all the elements and identify the new local halo
21078  // elements of "iproc"
21079  unsigned nh_count5 = 0;
21080  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21081  {
21082  // Get the element
21083  FiniteElement* ele_pt = this->finite_element_pt(e);
21084  // Only work with nonhalo elements
21085  if (!(ele_pt->is_halo()))
21086  {
21087  // Get the domain to which the current element is associated
21088  const unsigned ele_domain =
21089  target_domain_for_local_non_halo_element[nh_count5++];
21090  // If the current element is not associated to the "iproc"
21091  // processor then it could be a halo element
21092  if (ele_domain != iproc)
21093  {
21094  // Get the number of nodes
21095  const unsigned nnodes = ele_pt->nnode();
21096  // Loop over the nodes
21097  for (unsigned j = 0; j < nnodes; j++)
21098  {
21099  Node* node_pt = ele_pt->node_pt(j);
21100  // Check if the node is associated with the current
21101  // "iproc" processor
21102  std::set<unsigned>::iterator it =
21103  processors_associated_with_data_before_load_balance[node_pt]
21104  .find(iproc);
21105  // If it is found then the element is a halo-element
21106  if (it !=
21107  processors_associated_with_data_before_load_balance[node_pt]
21108  .end())
21109  {
21110  // Add the element as new local-halo element with the
21111  // "ele_domain" processor. The non-halo counterpart will
21112  // be located on "ele_domain" processor after sending
21113  // elements across
21114  if (!new_local_halo_already_added[ele_domain][ele_pt])
21115  {
21116  // The element is a halo element on "iproc" with
21117  // "ele_domain"
21118  new_local_halo_element_pt[iproc][ele_domain].push_back(
21119  ele_pt);
21120  // Mark as done
21121  new_local_halo_already_added[ele_domain][ele_pt] = true;
21122  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21123  } // One of the nodes lies on an element on the current
21124  // "iproc" processor
21125  } // for (j < nnodes)
21126  } // if (ele_domain != iproc)
21127  } // if (!(ele_pt->is_halo()))
21128  } // for (e < nelement_before_load_balance)
21129 
21130  // Now do the same with the halo elements, we need to find those
21131  // halo elements that continue being halo elements but possibly
21132  // with/on another processor. The pair of processors where a
21133  // possible shared boundary is created needs to be notified.
21134 
21135  // Example
21136  //
21137  // ---------------* *---------------
21138  // | |* *| |
21139  // | |* *| |
21140  // | New domain |* *| New domain | * Mark the position
21141  // | proc 1 |* *| proc 3 | of halo elements
21142  // | |* *| |
21143  // | |* *| |
21144  // ---------------* *---------------
21145  // Proc 1 Proc 2
21146 
21147  // Processor 1: The halo elements on processor 1 continue being halo ON
21148  // PROCESSOR 1, but now WITH PROCESSOR 3
21149 
21150  // Processor 2: The halo elements on processor 2 continue being
21151  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
21152 
21153  // The current processor (my_rank) also needs to consider the halo
21154  // elements that will be halo elements of other processor with
21155  // another processor. The case of processor 2
21156 
21157  // Loop over all the halo elements in the current processor and
21158  // check if they will be halo with the "iproc" processor
21159  for (unsigned jproc = 0; jproc < nproc; jproc++)
21160  {
21161  // There are no halo elements with myself (the old halo elements
21162  // were halo in the "my_rank" processor)
21163  if (jproc != my_rank)
21164  {
21165  // Get the number of halo elements with the "jproc" processor
21166  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
21167  // Get the halo elements with the "jproc" processor
21168  Vector<GeneralisedElement*> halo_element_pt_jproc =
21169  this->root_halo_element_pt(jproc);
21170  // ... and check if any of those elements is a new halo
21171  // element with the "iproc" processor
21172  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
21173  {
21174  // Get the new domain for the halo element
21175  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
21176 
21177  // If the current element is not associated to the "iproc"
21178  // processor then it could be a halo element on "iproc" with
21179  // "ele_domain".
21180 
21181  // NOTE OUTDATE: Check if the halo element is going to be
21182  // sent to this processor (my_rank), if that is the case
21183  // then we don't need to add it to the set of new halo
21184  // elements with any other processor since any possible
21185  // shared boundary will be created when checking for the
21186  // intersection of the sent and received elements
21187 
21188  // if (ele_domain != iproc && ele_domain != my_rank)
21189 
21190  // NOTE UPDATE: Only check if the halo element is not going
21191  // to be part of the iproc processor, not required to avoid
21192  // those halo elements whose domain is the current rank
21193  // (my_rank). When the shared boundaries are computed, these
21194  // last elements can not create a shared boundary since no
21195  // haloed elements (that shared an edge) are found for
21196  // them. By considering also those halo elements whose new
21197  // domain is the current one (commenting "ele_domain !=
21198  // my_rank") the current processor can compute shared
21199  // boundaries with the iproc processor with help of its old
21200  // halo elements but that will become nonhalo elements, in
21201  // fact they will become haloed elements The halo element is
21202  // not sent to the "element_domain" processor and is not
21203  // passed to the array used to create the new shared
21204  // boundaries "new_shared_boundary_element_pt" because of
21205  // its halo condition
21206  if (ele_domain != iproc)
21207  {
21208  // Get the finite element
21209  FiniteElement* ele_pt =
21210  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
21211  // Get the number of nodes on the halo element
21212  const unsigned nnodes = ele_pt->nnode();
21213  // Loop over the nodes
21214  for (unsigned j = 0; j < nnodes; j++)
21215  {
21216  // Get each node of the halo element
21217  Node* node_pt = ele_pt->node_pt(j);
21218 
21219  // Check if the node is associated with the "iproc"
21220  // processor
21221  std::set<unsigned>::iterator it =
21222  processors_associated_with_data_before_load_balance[node_pt]
21223  .find(iproc);
21224  // If it is found then the element is a halo-element
21225  if (it !=
21226  processors_associated_with_data_before_load_balance[node_pt]
21227  .end())
21228  {
21229  // Add the element as new local-halo element with
21230  // the "ele_domain" processor. The non-halo
21231  // counterpart will be located on "ele_domain"
21232  // processor. Because this is a old-halo element it
21233  // will not be sent to the "element_domain" processor
21234  if (!new_local_halo_already_added[ele_domain][ele_pt])
21235  {
21236  // The element is a halo element on "iproc" with
21237  // "ele_domain"
21238  new_local_halo_element_pt[iproc][ele_domain].push_back(
21239  ele_pt);
21240  new_local_halo_already_added[ele_domain][ele_pt] = true;
21241 
21242  // Break the for of the nodes, the element has been
21243  // already added to the new_local_halo_element_pt
21244  // structure
21245  break;
21246 
21247  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21248 
21249  } // One of the nodes lies on an element belonging to
21250  // "iproc" processor
21251 
21252  } // for (j < nnodes)
21253 
21254  } // if (ele_domain != iproc)
21255 
21256  } // for (jh < n_halo_ele_jproc)
21257 
21258  } // if (jproc != my_rank) // The old halo elements are halo
21259  // with other processors except with "my_rank"
21260 
21261  } // for (jproc < nproc): This is the one that goes for the halo
21262  // elements in the current processor to find the new halo
21263  // elements
21264 
21265  } // for (iproc < nproc)
21266 
21267  // Get the time to compute new local halo elements within all
21268  // processors
21269  if (Print_timings_level_load_balance > 1)
21270  {
21271  oomph_info
21272  << "CPU for computing new local halo elements (load balance) [4]: "
21273  << TimingHelpers::timer() - tt_start_compute_new_local_halo_elements
21274  << std::endl;
21275  }
21276 
21277  // =====================================================================
21278  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21279  // CURRENT PROCESSOR
21280  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21281  // =====================================================================
21282 
21283  // =====================================================================
21284  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21285  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21286  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21287  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21288  // ELEMENTS IN THE RECEIVED PROCESSOR
21289  // =====================================================================
21290 
21291  // Get the time to compute new local shared boundary elements
21292  double tt_start_compute_new_local_shd_bnd_ele = 0.0;
21293  if (Print_timings_level_load_balance > 1)
21294  {
21295  tt_start_compute_new_local_shd_bnd_ele = TimingHelpers::timer();
21296  }
21297 
21298  // Store the new local-shared boundary elements and the face indexes
21299  // The halo elements and halo face indexes
21300  Vector<Vector<Vector<FiniteElement*>>>
21301  new_local_halo_shared_boundary_element_pt(nproc);
21302  Vector<Vector<Vector<unsigned>>>
21303  new_local_halo_shared_boundary_element_face_index(nproc);
21304 
21305  // Allocate enough memory for the containers
21306  for (unsigned iproc = 0; iproc < nproc; iproc++)
21307  {
21308  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21309  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21310  } // for (iproc < nproc)
21311 
21312  // Get the elements that create the new local-halo-shared
21313  // boundaries, mark them and identify the face that lies on the
21314  // shared boundary. The new local-halo-shared boundary elements are
21315  // actually a sub-set of the halo elements of each processor with in
21316  // each processor
21317  for (unsigned iproc = 0; iproc < nproc; iproc++)
21318  {
21319  // Star from jproc = iproc + 1 to avoid double creation of shared
21320  // boundary elements, any shared boundary element identified
21321  // between processor "iproc" and "jproc" is also established as
21322  // shared boundary element between processor "jproc" and "iproc"
21323  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21324  {
21325  this->get_shared_boundary_elements_and_face_indexes(
21326  new_local_halo_element_pt[iproc][jproc],
21327  new_local_halo_element_pt[jproc][iproc],
21328  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21329  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21330  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21331  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21332  } // for (jproc < nproc)
21333  } // for (iproc < nproc)
21334 
21335  // The time to compute new local shared boundary elements
21336  if (Print_timings_level_load_balance > 1)
21337  {
21338  oomph_info << "CPU for computing new local shared boundary elements "
21339  "(load balance) [5]: "
21340  << TimingHelpers::timer() -
21341  tt_start_compute_new_local_shd_bnd_ele
21342  << std::endl;
21343  }
21344 
21345  // =====================================================================
21346  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21347  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21348  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21349  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21350  // THE RECEIVED PROCESSOR
21351  // =====================================================================
21352 
21353  // =====================================================================
21354  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21355  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21356  // =====================================================================
21357 
21358  // Get the time to send the elements to their new processor in
21359  // charge
21360  double tt_start_send_elements_to_other_processors = 0.0;
21361  if (Print_timings_level_load_balance > 1)
21362  {
21363  tt_start_send_elements_to_other_processors = TimingHelpers::timer();
21364  }
21365 
21366  // Sort the nodes on shared boundaries so that they have the same
21367  // order on all the shared boundaries, this is required to know the
21368  // possible shared nodes among processors
21369  this->sort_nodes_on_shared_boundaries();
21370 
21371  // Store the received elements from each processor
21372  Vector<Vector<FiniteElement*>> received_elements_pt(nproc);
21373 
21374  // The haloed elements and haloed face indexes, these store the
21375  // haloed elements received from "iproc" but that are haloed with
21376  // "jproc". The elements are received from "iproc" which was the
21377  // processor that computed the haloed relation of the "my_rank"
21378  // processor with "jproc"
21379  Vector<Vector<Vector<FiniteElement*>>>
21380  new_received_haloed_shared_boundary_element_pt(nproc);
21381  Vector<Vector<Vector<unsigned>>>
21382  new_received_haloed_shared_boundary_element_face_index(nproc);
21383 
21384  // Container where to store the nodes on shared boundaries not
21385  // associated with the processor that receives the elements/nodes
21386  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21387  Vector<Vector<Vector<std::map<unsigned, Node*>>>>
21388  other_proc_shd_bnd_node_pt(nproc);
21389  // Resize the container
21390  for (unsigned iproc = 0; iproc < nproc; iproc++)
21391  {
21392  // Resize the container
21393  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21394  for (unsigned jproc = 0; jproc < nproc; jproc++)
21395  {
21396  // Get the number of shared boundaries (OLD shared boundaries)
21397  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21398  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21399  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21400  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21401  } // for (jproc < nproc)
21402 
21403  } // for (iproc < nproc)
21404 
21405  // Store the global node names
21406  // global_node_name[x][ ][ ] Global node number
21407  // global_node_name[ ][x][ ] Global node names
21408  // global_node_name[ ][ ][x] Global node info.
21409  Vector<Vector<Vector<unsigned>>> global_node_names;
21410 
21411  // Creates a map between the node name and the index of the global
21412  // node so we can access all its node names
21413  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21414 
21415  // Store the global shared nodes pointers
21416  Vector<Node*> global_shared_node_pt;
21417 
21418  // Compute all the names of the nodes and fill in the
21419  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21420  // on this processor (my_rank) by looking over all their names
21421  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21422  global_node_names,
21423  node_name_to_global_index,
21424  global_shared_node_pt);
21425 
21426  // From the elements received from each processor, store the haloed
21427  // information of the element, it means, the processor with which it
21428  // is haloed and the haloed index with that processor
21429  Vector<Vector<std::map<unsigned, FiniteElement*>>>
21430  received_old_haloed_element_pt(nproc);
21431  // [x][][] : The receiver processor (the original processor)
21432  // [][x][] : The processor with which the receiver processor has
21433  // haloed elements
21434  // [][][x]: The haloed element number
21435 
21436  // Resize the container
21437  for (unsigned iproc = 0; iproc < nproc; iproc++)
21438  {
21439  received_old_haloed_element_pt[iproc].resize(nproc);
21440  } // for (iproc < nproc)
21441 
21442  // Go through all processors and send the corresponding elements to
21443  // each one
21444  for (unsigned iproc = 0; iproc < nproc; iproc++)
21445  {
21446  if (iproc != my_rank)
21447  {
21448  // -----------------------------------------------------------
21449  // Send (package) information of the elements
21450  // -----------------------------------------------------------
21451 
21452  // Keep track of the currently sent elements
21453  Vector<FiniteElement*> currently_sent_elements;
21454  // Keep track of the currently sent nodes to the iproc processor
21455  Vector<Node*> currently_sent_nodes;
21456 
21457  // Clear send and receive buffers
21458  Flat_packed_unsigneds.clear();
21459  Flat_packed_doubles.clear();
21460 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21461  Flat_packed_unsigneds_string.clear();
21462 #endif
21463 
21464  // Get the number of elements to send to iproc processor
21465  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21466 
21467  // The very first data of the flat package sent to processor
21468  // iproc is the number of elements that will be sent, this data
21469  // is used by the receiver processor to loop over the number of
21470  // expected elements to receive
21471  Flat_packed_unsigneds.push_back(nelements_to_send);
21472 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21473  std::stringstream junk;
21474  junk << "Number of elements to send from processor " << my_rank
21475  << " to processor " << iproc << ": (" << nelements_to_send << ")";
21476  Flat_packed_unsigneds_string.push_back(junk.str());
21477 #endif
21478 
21479  // Loop over the elements to sent
21480  for (unsigned e = 0; e < nelements_to_send; e++)
21481  {
21482  // Get the element to send
21483  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21484 
21485  // Get the current number of sent elements
21486  const unsigned ncurrently_sent_elements =
21487  currently_sent_elements.size();
21488 
21489  // Try to add the element
21490  const unsigned index_ele = try_to_add_element_pt_load_balance(
21491  currently_sent_elements, send_ele_pt);
21492 
21493  // Element needs to be added
21494  if (index_ele == ncurrently_sent_elements)
21495  {
21496  Flat_packed_unsigneds.push_back(1);
21497 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21498  Flat_packed_unsigneds_string.push_back(
21499  "Element needs to be constructed");
21500 #endif
21501 
21502  // Get required info. related with the element
21503  get_required_elemental_information_load_balance_helper(
21504  iproc, f_haloed_element_pt, send_ele_pt);
21505 
21506  // Get the number of nodes in the element
21507  const unsigned nnodes = send_ele_pt->nnode();
21508 
21509  // Loop over the nodes in the element
21510  for (unsigned j = 0; j < nnodes; j++)
21511  {
21512  Node* node_pt = send_ele_pt->node_pt(j);
21513 
21514  // Package the info. of the nodes
21515  add_node_load_balance_helper(iproc, // The destination process
21516  f_halo_element_pt,
21517  currently_sent_nodes,
21518  node_pt);
21519 
21520  } // for (j < nnodes)
21521 
21522  } // if (index_ele == ncurrently_sent_elements)
21523  else
21524  {
21525  Flat_packed_unsigneds.push_back(0);
21526 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21527  Flat_packed_unsigneds_string.push_back("Element already exists");
21528 #endif
21529  Flat_packed_unsigneds.push_back(index_ele);
21530 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21531  Flat_packed_unsigneds_string.push_back("Index of existing element");
21532 #endif
21533  } // else if (index_ele == ncurrently_sent_elements)
21534 
21535  } // for (e < nelements_to_send)
21536 
21537  // After storing the info. of the elements identify the indexes
21538  // of the "new_local_halo_shared_boundary_elements" in the
21539  // "currently_send_elements" vector, these elements will be
21540  // identified as "new_received_haloed_shared_boundary_elements"
21541  // on the "receiver" processor
21542 
21543  // Each processor has information of every other processor so we
21544  // need to send all the corresponding info. to the other
21545  // processors. Processor 1 may have information of the relation
21546  // (halo elements) between processor 3 and 4 say, so processor 1
21547  // needs to let know processor 3 and 4 what this relation is
21548  // (which are the shared-elements among these processors)
21549 
21550  for (unsigned jproc = 0; jproc < nproc; jproc++)
21551  {
21552  // Get the number of new local-halo shared boundary elements
21553  // between processor "jproc" and "iproc" (we invert the index
21554  // since we really want the haloed elements, those elements
21555  // that we have just sent)
21556  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21557  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21558 
21559  // The vector with the info. of the indexes
21560  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21561 
21562  // The number of found shared boundary elements in the sent
21563  // container (only consider the nonhalo elements)
21564  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21565  // The number of nonhalo elements in the new local halo shared
21566  // boundary elements
21567  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21568 
21569  // Loop over the local halo shared boundary elements between
21570  // processor jproc and iproc
21571  for (unsigned e = 0;
21572  e < njproc_iproc_new_local_halo_shared_boundary_ele;
21573  e++)
21574  {
21575  // Get the shared boundary element
21576  FiniteElement* shared_ele_pt =
21577  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21578 
21579  // Only consider the nonhalo elements since the halo
21580  // elements were no considered for sending
21581  if (!shared_ele_pt->is_halo())
21582  {
21583  nnon_halo_new_local_halo_shared_bound_ele++;
21584 
21585  // Now find the index on the currently sent elements
21586 
21587  // Get the current number of sent elements
21588  const unsigned ncurrently_sent_elements =
21589  currently_sent_elements.size();
21590  // Loop over the sent elements
21591  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21592  {
21593  FiniteElement* currently_sent_ele_pt =
21594  currently_sent_elements[ics];
21595 
21596  // Is this the element?
21597  if (currently_sent_ele_pt == shared_ele_pt)
21598  {
21599  // Store the index on the sent elements of the local
21600  // halo shared boundary element
21601  new_local_halo_shared_boundary_ele_index.push_back(ics);
21602  // Increase the number of found new local halo shared
21603  // bound element index
21604  nfound_new_local_halo_shared_bound_ele_index++;
21605  // We have found it, no need to further search
21606  break;
21607  } // if (currently_sent_ele_pt == shared_ele_pt)
21608 
21609  } // for (ics < ncurrently_sent_elements)
21610 
21611  } // if (!shared_ele_pt->is_halo())
21612 
21613  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21614 
21615 #ifdef PARANOID
21616  if (nfound_new_local_halo_shared_bound_ele_index !=
21617  nnon_halo_new_local_halo_shared_bound_ele)
21618  {
21619  std::ostringstream error_message;
21620  error_message << "Was only possible to identify ("
21621  << nfound_new_local_halo_shared_bound_ele_index
21622  << ") of ("
21623  << nnon_halo_new_local_halo_shared_bound_ele
21624  << ") shared "
21625  << "elements between\nprocessor (" << iproc
21626  << ") and (" << jproc << ") "
21627  << "when sending elements to processor (" << iproc
21628  << ")\n\n";
21629  throw OomphLibError(error_message.str(),
21630  OOMPH_CURRENT_FUNCTION,
21631  OOMPH_EXCEPTION_LOCATION);
21632  }
21633 #endif
21634 
21635  // Send a flag for synchronisation issues
21636  Flat_packed_unsigneds.push_back(9999);
21637 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21638  std::stringstream junk;
21639  junk << "Flag for synchronisation 9999";
21640  Flat_packed_unsigneds_string.push_back(junk.str());
21641 #endif
21642 
21643  // Send the number of nonhalo new local-shared boundary
21644  // elements of processor "iproc" with processor "jproc"
21645  Flat_packed_unsigneds.push_back(
21646  nnon_halo_new_local_halo_shared_bound_ele);
21647 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21648  std::stringstream junk2;
21649  junk2 << "Number of new local halo shared boundary elements "
21650  << nnon_halo_new_local_halo_shared_bound_ele;
21651  Flat_packed_unsigneds_string.push_back(junk2.str());
21652 #endif
21653 
21654  // Send the indexes and the face indexes of the shared
21655  // boundary elements
21656  unsigned counter_nonhalo_sent = 0;
21657  // Loop over the local halo shared boundary elements between
21658  // processor jproc and iproc
21659  for (unsigned e = 0;
21660  e < njproc_iproc_new_local_halo_shared_boundary_ele;
21661  e++)
21662  {
21663  // Get the shared boundary element
21664  FiniteElement* shared_ele_pt =
21665  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21666 
21667  // Only consider the nonhalo elements since the halo
21668  // elements were no considered for sending
21669  if (!shared_ele_pt->is_halo())
21670  {
21671  // Get the index on the sent elements of the current
21672  // nonhalo shared boundary element
21673  const unsigned ele_index =
21674  new_local_halo_shared_boundary_ele_index
21675  [counter_nonhalo_sent++];
21676  // ... and get the face index
21677  const unsigned face_index =
21678  new_local_halo_shared_boundary_element_face_index[jproc][iproc]
21679  [e];
21680 
21681  // Send the index on the sent elements of the new local
21682  // halo shared boundary element
21683  Flat_packed_unsigneds.push_back(ele_index);
21684 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21685  std::stringstream junk;
21686  junk << "The index of the halo shared boundary element "
21687  << ele_index;
21688  Flat_packed_unsigneds_string.push_back(junk.str());
21689 #endif
21690 
21691  // Send the face index of the new local halo shared boundary
21692  // element
21693  Flat_packed_unsigneds.push_back(face_index);
21694 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21695  std::stringstream junk2;
21696  junk2 << "The face index of the halo shared boundary element "
21697  << face_index;
21698  Flat_packed_unsigneds_string.push_back(junk2.str());
21699 #endif
21700 
21701  } // if (!shared_ele_pt->is_halo())
21702 
21703  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21704 
21705  } // for (jproc < nproc)
21706 
21707  // ----------------------------------------------------------
21708  // Send the info. perform the communications
21709  // ----------------------------------------------------------
21710  // Processor to which send the info.
21711  int send_proc = static_cast<int>(iproc);
21712  // Processor from which receive the info.
21713  int recv_proc = static_cast<int>(iproc);
21714  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21715 
21716  // ----------------------------------------------------------
21717  // Receive (unpackage) the info of the elements
21718  // ----------------------------------------------------------
21719 
21720  // Keep track of the currently created elements
21721  Vector<FiniteElement*> currently_created_elements;
21722  // Keep track of the currently created nodes
21723  Vector<Node*> currently_created_nodes;
21724 
21725  // Reset the counters
21726  Counter_for_flat_packed_doubles = 0;
21727  Counter_for_flat_packed_unsigneds = 0;
21728 
21729 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21730  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
21731  << " Number of elements need to be constructed "
21732  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
21733  << std::endl;
21734 #endif
21735 
21736  // Read the number of elements that need to be created
21737  const unsigned nelements_to_create =
21738  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21739 
21740  for (unsigned e = 0; e < nelements_to_create; e++)
21741  {
21742  // Create the element from received info. of "iproc"
21743  // processor on the current processor
21744  create_element_load_balance_helper(iproc,
21745  f_haloed_element_pt,
21746  received_old_haloed_element_pt,
21747  currently_created_elements,
21748  currently_created_nodes,
21749  other_proc_shd_bnd_node_pt,
21750  global_node_names,
21751  node_name_to_global_index,
21752  global_shared_node_pt);
21753  }
21754 
21755  // Copy the received elements from "iproc" processor
21756 
21757  // Number of received elements
21758  const unsigned nreceived_elements = currently_created_elements.size();
21759  received_elements_pt[iproc].resize(nreceived_elements);
21760  for (unsigned e = 0; e < nreceived_elements; e++)
21761  {
21762  received_elements_pt[iproc][e] = currently_created_elements[e];
21763  }
21764 
21765  // Go for the haloed elements received from processor "iproc"
21766  // but haloed with "jproc"
21767 
21768  // Allocate memory for the containers
21769  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21770  new_received_haloed_shared_boundary_element_face_index[iproc].resize(
21771  nproc);
21772 
21773  // Loop over the processors
21774  for (unsigned jproc = 0; jproc < nproc; jproc++)
21775  {
21776  // Read the synchronisation flag
21777  const unsigned synchronisation_flag =
21778  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21779 
21780  if (synchronisation_flag != 9999)
21781  {
21782  std::ostringstream error_message;
21783  error_message << "The synchronisation flag was not read, the\n"
21784  << "information sent between processor (" << my_rank
21785  << ") "
21786  << "and (" << iproc
21787  << ")\nis no longer synchronised\n\n";
21788  throw OomphLibError(error_message.str(),
21789  OOMPH_CURRENT_FUNCTION,
21790  OOMPH_EXCEPTION_LOCATION);
21791  }
21792 
21793  // Read the number of elements that will be part of the new
21794  // received haloed shared boundary elements received from "iproc"
21795  // and haloed with "jproc"
21796  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21797  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21798 
21799  // Loop over the new received haloed shared boundary elements
21800  for (unsigned e = 0;
21801  e < niproc_jproc_new_received_haloed_shared_boundary_ele;
21802  e++)
21803  {
21804  // Read the index of the new received haloed shared boundary
21805  // ele with "jproc"
21806  const unsigned ele_index =
21807  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21808  // Read the face index for the new received haloed shared
21809  // boundary element
21810  const unsigned face_index =
21811  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21812 
21813  // Get the element
21814  FiniteElement* shared_ele_pt =
21815  currently_created_elements[ele_index];
21816 
21817  // Add the element to the new received-haloed shared
21818  // boundary elements. Received from "iproc" but haloed with
21819  // "jproc" processor
21820  new_received_haloed_shared_boundary_element_pt[iproc][jproc]
21821  .push_back(shared_ele_pt);
21822  // Store the face index
21823  new_received_haloed_shared_boundary_element_face_index[iproc][jproc]
21824  .push_back(face_index);
21825 
21826  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21827 
21828  } // for (jproc < nproc)
21829 
21830  } // if (iproc != my_rank)
21831 
21832  } // for (iproc < nproc)
21833 
21834  // The time to send the elements to their new processor in charge
21835  if (Print_timings_level_load_balance > 1)
21836  {
21837  oomph_info << "CPU for sending elements to their new processors (load "
21838  "balance) [6]: "
21839  << TimingHelpers::timer() -
21840  tt_start_send_elements_to_other_processors
21841  << std::endl;
21842  }
21843 
21844  // =====================================================================
21845  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21846  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21847  // =====================================================================
21848 
21849  // =====================================================================
21850  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21851  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21852  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21853  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21854  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21855  // ELEMENTS)
21856  // =====================================================================
21857 
21858  // Get the time to compute any additional shared boundary
21859  double tt_start_compute_additional_shared_boundaries = 0.0;
21860  if (Print_timings_level_load_balance > 1)
21861  {
21862  tt_start_compute_additional_shared_boundaries = TimingHelpers::timer();
21863  }
21864 
21865  // Store any additional elements that may create a shared boundary,
21866  // after sending elements from one to other processor check for any
21867  // new possible shared boundaries
21868  Vector<Vector<FiniteElement*>> tmp_group1_shared_boundary_element_pt(nproc);
21869  Vector<Vector<unsigned>> tmp_group1_shared_boundary_element_face_index(
21870  nproc);
21871  Vector<Vector<FiniteElement*>> tmp_group2_shared_boundary_element_pt(nproc);
21872  Vector<Vector<unsigned>> tmp_group2_shared_boundary_element_face_index(
21873  nproc);
21874 
21875  // Compute any additional shared boundaries by checking the
21876  // intersection between the received elements from each processor
21877  // and the elements just sent to that processor, the lowest
21878  // processors number loops over its received elements and the
21879  // highest loops over its sent elements (halo elements that have
21880  // become part of the domain now can create shared boundaries with
21881  // other processor)
21882 
21883  // Note: These additional shared boundaries may be created by the
21884  // elements that previously were halo but now have become part of
21885  // the processor (the received elements), and the elements that were
21886  // previously part of the processor but now have become halo (a
21887  // subset of the sent-elements)
21888 
21889  // Then these new shared boundaries come from the intersection of
21890  // the new-haloed elements (received elements) and the new-halo
21891  // elements (sent elements). These could be computed previously (in
21892  // the computing of the local new-halo and local new-haloed elements
21893  // usign the info. of the new domains for the old halo elements),
21894  // however, it was decided to perform the computation here in order to
21895  // avoid the identification of the old halo element that was part of a
21896  // shared boundary in the set of just received elements
21897  for (unsigned iproc = 0; iproc < nproc; iproc++)
21898  {
21899  if (my_rank < iproc)
21900  {
21901  // Lowest processor loops over the received elements
21902  this->get_shared_boundary_elements_and_face_indexes(
21903  received_elements_pt[iproc],
21904  elements_to_send_pt[iproc],
21905  tmp_group1_shared_boundary_element_pt[iproc],
21906  tmp_group1_shared_boundary_element_face_index[iproc],
21907  tmp_group2_shared_boundary_element_pt[iproc],
21908  tmp_group2_shared_boundary_element_face_index[iproc]);
21909 
21910  } // if (my_rank < iproc)
21911  else if (my_rank > iproc)
21912  {
21913  // Highest processor loops over the sent elements
21914  this->get_shared_boundary_elements_and_face_indexes(
21915  elements_to_send_pt[iproc],
21916  received_elements_pt[iproc],
21917  tmp_group1_shared_boundary_element_pt[iproc],
21918  tmp_group1_shared_boundary_element_face_index[iproc],
21919  tmp_group2_shared_boundary_element_pt[iproc],
21920  tmp_group2_shared_boundary_element_face_index[iproc]);
21921 
21922  } // else if (my_rank > iproc)
21923 
21924  } // for (iproc < nproc)
21925 
21926  // The time to compute any additional shared boundary
21927  if (Print_timings_level_load_balance > 1)
21928  {
21929  oomph_info
21930  << "CPU for computing additional shared boundaries (load balance) [7]: "
21931  << TimingHelpers::timer() -
21932  tt_start_compute_additional_shared_boundaries
21933  << std::endl;
21934  }
21935 
21936  // =====================================================================
21937  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21938  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21939  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21940  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21941  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21942  // ELEMENTS)
21943  // =====================================================================
21944 
21945  // =====================================================================
21946  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21947  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21948  // =====================================================================
21949 
21950  // Get the time to sort shared boundaries
21951  double tt_start_sort_shared_boundaries = 0.0;
21952  if (Print_timings_level_load_balance > 1)
21953  {
21954  tt_start_sort_shared_boundaries = TimingHelpers::timer();
21955  }
21956 
21957  // Once computed the elements that create the shared boundaries,
21958  // sort them so that the shared boundaries are created at the same
21959  // order in both processors that define the shared boundary
21960 
21961  // The order is like this
21962 
21963  // Lowest processors
21964  // 1) Shared boundary elements received from processors (local in
21965  // other processors)
21966  // 2) Local shared boundary elements (do not include halo elements)
21967  // 3) Shared boundary elements by intersection (already sorted)
21968 
21969  // Highest processors
21970  // 1) Local shared boundary elements (do not include halo elements)
21971  // 2) Shared boundary elements received from processors (local in
21972  // other processors)
21973  // 3) Shared boundary elements by intersection (already sorted)
21974 
21975  Vector<Vector<FiniteElement*>> new_shared_boundary_element_pt(nproc);
21976  Vector<Vector<unsigned>> new_shared_boundary_element_face_index(nproc);
21977  for (unsigned iproc = 0; iproc < nproc; iproc++)
21978  {
21979  // Lower processor
21980  if (my_rank < iproc)
21981  {
21982  // Copy the elements received from processor "jproc" but that
21983  // are haloed with "iproc" processor
21984  for (unsigned jproc = 0; jproc < nproc; jproc++)
21985  {
21986  // Can not receive elements from itself
21987  if (jproc != my_rank)
21988  {
21989  // Get the number of elements to copy from received processors
21990  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21991  new_received_haloed_shared_boundary_element_pt[jproc][iproc]
21992  .size();
21993  for (unsigned e = 0; e < nrecvd_haloed_shared_bound_ele_jproc_iproc;
21994  e++)
21995  {
21996  // Get the element
21997  FiniteElement* ele_pt =
21998  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21999  // Get the face index
22000  const unsigned face_index =
22001  new_received_haloed_shared_boundary_element_face_index[jproc]
22002  [iproc]
22003  [e];
22004 
22005  // Add the elements to the containers
22006  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22007  new_shared_boundary_element_face_index[iproc].push_back(
22008  face_index);
22009 
22010  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
22011 
22012  } // if (jproc != my_rank)
22013 
22014  } // for (jproc < nproc)
22015 
22016  // Then the local shared haloed (invert the indexes to get the
22017  // haloed elements)
22018  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
22019  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
22020  for (unsigned e = 0; e < nlocal_haloed_shared_bound_ele_iproc_my_rank;
22021  e++)
22022  {
22023  // Get the element
22024  FiniteElement* ele_pt =
22025  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
22026  // Get the face index
22027  const unsigned face_index =
22028  new_local_halo_shared_boundary_element_face_index[iproc][my_rank]
22029  [e];
22030 
22031  // Only include the element if it is nonhalo (this may be an
22032  // old halo element that helped to indentify a shared boundary
22033  // with iproc)
22034  if (!ele_pt->is_halo())
22035  {
22036  // Add the elements to the containers
22037  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22038  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22039  } // if (!ele_pt->is_halo())
22040 
22041  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
22042 
22043  // ... and finally any additional shared boundary elements from
22044  // tmp_group1
22045  const unsigned ntmp_group1_shared_bound_ele_iproc =
22046  tmp_group1_shared_boundary_element_pt[iproc].size();
22047  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
22048  {
22049  // Get the element
22050  FiniteElement* ele_pt =
22051  tmp_group1_shared_boundary_element_pt[iproc][e];
22052  // Get the face index
22053  const unsigned face_index =
22054  tmp_group1_shared_boundary_element_face_index[iproc][e];
22055 
22056  // Add the elements to the containers
22057  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22058  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22059 
22060  } // for (e < ntmp_group1_shared_bound_ele_iproc)
22061 
22062  } // if (my_rank < iproc)
22063  // Highest processor
22064  else if (my_rank > iproc)
22065  {
22066  // Get the haloed elements first and then the elements received
22067  // from processor "jproc" but that are haloed with "iproc"
22068  // processor
22069 
22070  // Get the number of elements to copy from local elements
22071  // (invert the indexes to get the haloed elements)
22072  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
22073  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
22074  for (unsigned e = 0; e < nlocal_haloed_shared_bound_ele_iproc_my_rank;
22075  e++)
22076  {
22077  // Get the element
22078  FiniteElement* ele_pt =
22079  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
22080  // Get the face index
22081  const unsigned face_index =
22082  new_local_halo_shared_boundary_element_face_index[iproc][my_rank]
22083  [e];
22084 
22085  // Only include the element if it is nonhalo (this may be an
22086  // old halo element that helped to indentify a shared boundary
22087  // with iproc)
22088  if (!ele_pt->is_halo())
22089  {
22090  // Add the elements to the containers
22091  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22092  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22093  } // if (!ele_pt->is_halo())
22094 
22095  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
22096 
22097  for (unsigned jproc = 0; jproc < nproc; jproc++)
22098  {
22099  // Can not receive elements from itself
22100  if (jproc != my_rank)
22101  {
22102  // Then the received shared elements from "jproc" but haloed
22103  // with "iproc"
22104  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
22105  new_received_haloed_shared_boundary_element_pt[jproc][iproc]
22106  .size();
22107  for (unsigned e = 0; e < nrecvd_haloed_shared_bound_ele_jproc_iproc;
22108  e++)
22109  {
22110  // Get the element
22111  FiniteElement* ele_pt =
22112  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
22113  // Get the face index
22114  const unsigned face_index =
22115  new_received_haloed_shared_boundary_element_face_index[jproc]
22116  [iproc]
22117  [e];
22118 
22119  // Add the elements to the containers
22120  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22121  new_shared_boundary_element_face_index[iproc].push_back(
22122  face_index);
22123 
22124  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
22125 
22126  } // if (jproc != my_rank)
22127 
22128  } // for (jproc < nproc)
22129 
22130  // ... and finally any additional shared boundary elements from
22131  // tmp_group2
22132  const unsigned ntmp_group2_shared_bound_ele_iproc =
22133  tmp_group2_shared_boundary_element_pt[iproc].size();
22134  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
22135  {
22136  // Get the element
22137  FiniteElement* ele_pt =
22138  tmp_group2_shared_boundary_element_pt[iproc][e];
22139  // Get the face index
22140  const unsigned face_index =
22141  tmp_group2_shared_boundary_element_face_index[iproc][e];
22142 
22143  // Add the elements to the containers
22144  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
22145  new_shared_boundary_element_face_index[iproc].push_back(face_index);
22146 
22147  } // for (e < ntmp_group2_shared_bound_ele_iproc)
22148 
22149  } // else if (my_rank > iproc)
22150 
22151  } // for (iproc < nproc)
22152 
22153  // The time to sort shared boundaries
22154  if (Print_timings_level_load_balance > 1)
22155  {
22156  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
22157  << TimingHelpers::timer() - tt_start_sort_shared_boundaries
22158  << std::endl;
22159  }
22160 
22161  // =====================================================================
22162  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
22163  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
22164  // =====================================================================
22165 
22166  // =====================================================================
22167  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22168  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22169  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22170  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22171  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22172  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22173  // THE ORIGINAL BOUNDARIES
22174  // =====================================================================
22175  // Finally, create the new shared boundaries
22176 
22177  // Get the time to create the new shared boundaries
22178  double tt_start_create_new_shared_boundaries = 0.0;
22179  if (Print_timings_level_load_balance > 1)
22180  {
22181  tt_start_create_new_shared_boundaries = TimingHelpers::timer();
22182  }
22183 
22184  // Compute the elements that will remain after deletion in the
22185  // curent processor. This is required to check if the new shared
22186  // boundaries crete a connection with any node of the elements in
22187  // the boundaries
22188 
22189  // Try to use as much information as possible
22190 
22191  // Storage for the elements in the processor
22192  std::set<FiniteElement*> element_in_processor_pt;
22193 
22194  // Loop over the old elements, those before sending/received
22195  // elements to/from other processors
22196  unsigned nh_count6 = 0;
22197  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22198  {
22199  // Get the element
22200  FiniteElement* ele_pt = backed_up_ele_pt[e];
22201  // Only work with nonhalo elements
22202  if (!(ele_pt->is_halo()))
22203  {
22204  // Is the element part of the new domain
22205  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
22206  {
22207  // Add the element to the set of elements in the processor
22208  element_in_processor_pt.insert(ele_pt);
22209  }
22210 
22211  } // if (!(ele_pt->is_halo()))
22212 
22213  } // for (e < nelement_before_load_balance)
22214 
22215  // Now include the received elements from the other processors
22216  // Loop over the processors
22217  for (unsigned iproc = 0; iproc < nproc; iproc++)
22218  {
22219  // No elements received from myself
22220  if (iproc != my_rank)
22221  {
22222  // Get the number of received elements with the "iproc"
22223  // processor
22224  const unsigned n_received_ele = received_elements_pt[iproc].size();
22225  for (unsigned ie = 0; ie < n_received_ele; ie++)
22226  {
22227  // Get the ie-th received element from processor iproc
22228  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22229 
22230  // Include it in the set of elements in the processor
22231  element_in_processor_pt.insert(ele_pt);
22232 
22233  } // for (ie < nreceived_ele)
22234 
22235  } // if (iproc != my_rank)
22236 
22237  } // for (iproc < nproc)
22238 
22239  // Now create the shared boundaries
22240  create_new_shared_boundaries(element_in_processor_pt,
22241  new_shared_boundary_element_pt,
22242  new_shared_boundary_element_face_index);
22243 
22244  // The time to create the new shared boundaries
22245  if (Print_timings_level_load_balance > 1)
22246  {
22247  oomph_info
22248  << "CPU for creating new shared boundaries (load balance) [9]: "
22249  << TimingHelpers::timer() - tt_start_create_new_shared_boundaries
22250  << std::endl;
22251  }
22252 
22253  // =====================================================================
22254  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22255  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22256  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22257  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22258  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22259  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22260  // THE ORIGINAL BOUNDARIES
22261  // =====================================================================
22262 
22263  // =====================================================================
22264  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22265  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22266  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22267  // =====================================================================
22268 
22269  // Get the time to delete elements no longer belonging to the
22270  // processor
22271  double tt_start_delete_elements = 0.0;
22272  if (Print_timings_level_load_balance > 1)
22273  {
22274  tt_start_delete_elements = TimingHelpers::timer();
22275  }
22276 
22277  // Once computed the new shared boundaries delete the elements that
22278  // no longer belong to the processor (including the old halo
22279  // elements)
22280 
22281  // The procedure is similar to the one performed at the distribution
22282  // stage (src/generic/mesh.cc -- distribute() method)
22283 
22284  // Clean the storage for halo(ed) elements/nodes
22285  this->Halo_node_pt.clear();
22286  this->Root_halo_element_pt.clear();
22287 
22288  this->Haloed_node_pt.clear();
22289  this->Root_haloed_element_pt.clear();
22290 
22291  // Mark all the nodes as obsolete
22292  const unsigned nnodes = this->nnode();
22293  for (unsigned j = 0; j < nnodes; j++)
22294  {
22295  this->node_pt(j)->set_obsolete();
22296  }
22297 
22298  // Flush the mesh storage
22299  this->flush_element_storage();
22300 
22301  // Delete any storage of external elements and nodes
22302  this->delete_all_external_storage();
22303 
22304  // Clear external storage
22305  this->External_halo_node_pt.clear();
22306  this->External_halo_element_pt.clear();
22307 
22308  this->External_haloed_node_pt.clear();
22309  this->External_haloed_element_pt.clear();
22310 
22311  // Keep track of the deleted elements
22312  Vector<FiniteElement*> deleted_elements;
22313 
22314  // Delete the elements that no longer belong to the processor
22315  unsigned nh_count7 = 0;
22316  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22317  {
22318  FiniteElement* ele_pt = backed_up_ele_pt[e];
22319  // Only work with nonhalo elements
22320  if (!(ele_pt->is_halo()))
22321  {
22322  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22323  {
22324  // Add the element to the mesh
22325  this->add_element_pt(ele_pt);
22326  // Get the number of nodes on the element
22327  const unsigned nele_nodes = ele_pt->nnode();
22328  // Loop over the nodes of the element
22329  for (unsigned j = 0; j < nele_nodes; j++)
22330  {
22331  // Mark the node as non-obsolete
22332  ele_pt->node_pt(j)->set_non_obsolete();
22333  } // for (j < nele_nodes)
22334 
22335  } // The element belongs to the domain
22336  else
22337  {
22338  // Delete the element, but keep track of it
22339  deleted_elements.push_back(ele_pt);
22340  // Delete and point to null
22341  delete ele_pt;
22342  ele_pt = 0;
22343  }
22344 
22345  } // if (!(ele_pt->is_halo()))
22346  else
22347  {
22348  // If the element is halo, delete if but keep track of it
22349  deleted_elements.push_back(ele_pt);
22350  // Delete and point to null
22351  delete ele_pt;
22352  ele_pt = 0;
22353  }
22354 
22355  } // for (e < nelement_before_load_balance)
22356 
22357  // Now add the received elements from each processor
22358  for (unsigned iproc = 0; iproc < nproc; iproc++)
22359  {
22360  if (iproc != my_rank)
22361  {
22362  // Get the number of received elements with the "iproc"
22363  // processor
22364  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22365  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22366  {
22367  // Get the element and add it to the mesh
22368  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22369  // Add the element to the mesh
22370  this->add_element_pt(ele_pt);
22371  // Get the number of nodes on the element
22372  const unsigned nele_nodes = ele_pt->nnode();
22373  // Loop over the nodes of the element
22374  for (unsigned j = 0; j < nele_nodes; j++)
22375  {
22376  // Mark the node as non-obsolete
22377  ele_pt->node_pt(j)->set_non_obsolete();
22378  } // for (j < nele_nodes)
22379 
22380  } // for (ie < nreceived_ele)
22381 
22382  } // if (iproc != my_rank)
22383 
22384  } // for (iproc < nproc)
22385 
22386  // Now remove the obsolete nodes
22387  this->prune_dead_nodes();
22388 
22389  // The time to delete elements no longer belonging to the processor
22390  if (Print_timings_level_load_balance > 1)
22391  {
22392  oomph_info << "CPU for deleting elements no longer belonging to this "
22393  "processor (load balance) [10]: "
22394  << TimingHelpers::timer() - tt_start_delete_elements
22395  << std::endl;
22396  }
22397 
22398  // =====================================================================
22399  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22400  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22401  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22402  // =====================================================================
22403 
22404  // =====================================================================
22405  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22406  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22407  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22408  // ON EACH BOUNDARY
22409  // =====================================================================
22410 
22411  // Get the time to re-establish the halo(ed) information
22412  double tt_start_re_etablish_halo_ed_info = 0.0;
22413  if (Print_timings_level_load_balance > 1)
22414  {
22415  tt_start_re_etablish_halo_ed_info = TimingHelpers::timer();
22416  }
22417 
22418  // Prepare the data to re-establish the halo(ed) scheme
22419 
22420  // Sort the nodes on the new shared boundaries so that they have the
22421  // same order on all processors
22422  this->sort_nodes_on_shared_boundaries();
22423 
22424  // Before re-establish the halo and haloed elements save the number
22425  // of current elements in the boundaries, this will be useful to
22426  // re-establish the boundary elements. Notice that there may be
22427  // boundary elements with null pointers, since the element may no
22428  // longer belong to the current processor
22429  const unsigned tmp_nboundary = this->nboundary();
22430  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22431 
22432  // If there are regions, save the number of boundary-region elements
22433  Vector<Vector<unsigned>> ntmp_boundary_elements_in_region(tmp_nboundary);
22434  // Are there regions?
22435  const unsigned n_regions = this->nregion();
22436 
22437  // Loop over the boundaries
22438  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22439  {
22440  // Get the number of boundary elements
22441  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22442 
22443  // Resize the container
22444  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22445 
22446  // Loop over the regions
22447  for (unsigned rr = 0; rr < n_regions; rr++)
22448  {
22449  // Get the region id
22450  const unsigned region_id =
22451  static_cast<unsigned>(this->region_attribute(rr));
22452 
22453  // Store the number of element in the region (notice we are
22454  // using the region index not the region id to refer to the
22455  // region)
22456  ntmp_boundary_elements_in_region[ib][rr] =
22457  this->nboundary_element_in_region(ib, region_id);
22458 
22459  } // for (rr < n_regions)
22460 
22461  } // for (ib < tmp_nboundary)
22462 
22463  // Re-establish the halo(ed) scheme
22464  this->reset_halo_haloed_scheme();
22465 
22466  // Get the number of elements in the mesh after load balance
22467  const unsigned nelement_after_load_balance = this->nelement();
22468 
22469  // We need to reset boundary elements because we need to get rid of
22470  // the old boundary elements and stay only with the new ones
22471  this->reset_boundary_element_info(ntmp_boundary_elements,
22472  ntmp_boundary_elements_in_region,
22473  deleted_elements);
22474 
22475  // There is no need to re-set boundary coordinates since the
22476  // load-balanced mesh already has the correct information (the
22477  // boundary coordinate for each node was sent with the node
22478  // information)
22479 
22480  // We need to re-compute the number of segments on each boundary
22481  // after load balance. It may be possible that the boundary is now
22482  // split in more segments, or that previous gaps between the
22483  // segments have now dissapeared because the received elements
22484  // filled those gaps
22485 
22486  // In order to re-set the number of segments it is required to get
22487  // the face elements, attach them to create a contiguous
22488  // representation of the boundary (in segments possibly) and then
22489  // counter the number of segments. This can only be done after
22490  // restoring the boundary elements scheme (which has been done
22491  // above)
22492 
22493  // Set the number of segments for the boundaries with geom objects
22494  // associated. The correct value is not on the original mesh since
22495  // it is computed only when calling then
22496  // setup_boundary_coordinates() method (called only for those
22497  // boundaries with no geom object associated)
22498  for (unsigned b = 0; b < tmp_nboundary; b++)
22499  {
22500  if (this->boundary_geom_object_pt(b) != 0)
22501  {
22502  // Clear the boundary segment nodes storage
22503  this->flush_boundary_segment_node(b);
22504 
22505  // Dummy vector of nodes on segments
22506  Vector<Vector<Node*>> dummy_segment_node_pt;
22507 
22508  // Compute the new number of segments in the boundary
22509  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22510 
22511  // Get the number of segments from the vector of nodes
22512  const unsigned nsegments = dummy_segment_node_pt.size();
22513 
22514  // Set the number of segments for the storing of the nodes
22515  // associated to the segments
22516  this->set_nboundary_segment_node(b, nsegments);
22517  } // if (this->boundary_geom_object_pt(b)!=0)
22518 
22519  } // for (b < n_boundary)
22520 
22521  // The time to re-establish the halo(ed) information
22522  if (Print_timings_level_load_balance > 1)
22523  {
22524  oomph_info
22525  << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22526  << TimingHelpers::timer() - tt_start_re_etablish_halo_ed_info
22527  << std::endl;
22528  }
22529 
22530  // =====================================================================
22531  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22532  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22533  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22534  // BOUNDARY
22535  // =====================================================================
22536 
22537  if (Print_timings_level_load_balance > 1)
22538  {
22539  oomph_info << "CPU for load balance [n_ele_before="
22540  << nelement_before_load_balance
22541  << ", n_ele_after=" << nelement_after_load_balance << "]: "
22542  << TimingHelpers::timer() - t_start_overall_load_balance
22543  << std::endl;
22544  }
22545 
22546  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22547  }
22548 
22549  //======================================================================
22550  /// Use the first and second group of elements to find the
22551  /// intersection between them to get the shared boundary
22552  /// elements from the first and second group
22553  //======================================================================
22554  template<class ELEMENT>
22557  const Vector<FiniteElement*>& first_element_pt,
22558  const Vector<FiniteElement*>& second_element_pt,
22559  Vector<FiniteElement*>& first_shared_boundary_element_pt,
22560  Vector<unsigned>& first_shared_boundary_element_face_index,
22561  Vector<FiniteElement*>& second_shared_boundary_element_pt,
22562  Vector<unsigned>& second_shared_boundary_element_face_index)
22563  {
22564  // 1) Compare their faces (nodes) and if they match then they are
22565  // part of a shared boundary
22566  // 2) Save the first and second group of elements that give rise to
22567  // the shared boundary, also include the face index
22568 
22569  // Get the number of elements on the first group
22570  const unsigned nfirst_element = first_element_pt.size();
22571  // Loop over the elements in the first group
22572  for (unsigned ef = 0; ef < nfirst_element; ef++)
22573  {
22574  // Get the element
22575  FiniteElement* fele_pt = first_element_pt[ef];
22576  // Check if the element is halo
22577  bool first_ele_is_halo = false;
22578  if (fele_pt->is_halo())
22579  {
22580  first_ele_is_halo = true;
22581  }
22582  // Get each of the faces
22583  for (unsigned ifface = 0; ifface < 3; ifface++)
22584  {
22585  Vector<Node*> first_face(2);
22586  if (ifface == 0)
22587  {
22588  first_face[0] = fele_pt->node_pt(1);
22589  first_face[1] = fele_pt->node_pt(2);
22590  }
22591  else if (ifface == 1)
22592  {
22593  first_face[0] = fele_pt->node_pt(2);
22594  first_face[1] = fele_pt->node_pt(0);
22595  }
22596  else if (ifface == 2)
22597  {
22598  first_face[0] = fele_pt->node_pt(0);
22599  first_face[1] = fele_pt->node_pt(1);
22600  }
22601 
22602  // Now check each of the faces with the faces on the second
22603  // elements
22604 
22605  // Get the number of elements on the second group
22606  const unsigned nsecond_element = second_element_pt.size();
22607  // Loop over the elements in the second group
22608  for (unsigned es = 0; es < nsecond_element; es++)
22609  {
22610  // Get the element
22611  FiniteElement* sele_pt = second_element_pt[es];
22612  // Check if the element is halo
22613  bool second_ele_is_halo = false;
22614  if (sele_pt->is_halo())
22615  {
22616  second_ele_is_halo = true;
22617  }
22618  // Now check whether both elements are halo, if that is the
22619  // case then we go for the next elements. We can not look for
22620  // shared boundaries between halo elements since other
22621  // processors, those with the nonhalo counterpart of the
22622  // elements, are in charge of creating those shared boundaries
22623  if (!(first_ele_is_halo && second_ele_is_halo))
22624  {
22625  // Get each of the faces
22626  for (unsigned isface = 0; isface < 3; isface++)
22627  {
22628  Vector<Node*> second_face(2);
22629  if (isface == 0)
22630  {
22631  second_face[0] = sele_pt->node_pt(1);
22632  second_face[1] = sele_pt->node_pt(2);
22633  }
22634  else if (isface == 1)
22635  {
22636  second_face[0] = sele_pt->node_pt(2);
22637  second_face[1] = sele_pt->node_pt(0);
22638  }
22639  else if (isface == 2)
22640  {
22641  second_face[0] = sele_pt->node_pt(0);
22642  second_face[1] = sele_pt->node_pt(1);
22643  }
22644 
22645  // Now check for any intersection among first and second
22646  // faces
22647  if (first_face[0] == second_face[0] &&
22648  first_face[1] == second_face[1])
22649  {
22650  // Save the elements on the corresponding containers
22651  first_shared_boundary_element_pt.push_back(fele_pt);
22652  // .. and the face index
22653  first_shared_boundary_element_face_index.push_back(ifface);
22654 
22655  // Save the elements on the corresponding containers
22656  second_shared_boundary_element_pt.push_back(sele_pt);
22657  // .. and the face index
22658  second_shared_boundary_element_face_index.push_back(isface);
22659 
22660  // Break the loop over the faces of the first elements
22661  // and the first elements, we need to continue looking
22662  // on the next face of the first elements
22663 
22664  // Increase the indexes to force breaking the loop
22665  isface = 3;
22666  es = nsecond_element;
22667  }
22668  // Check for intersection with the reversed case too
22669  else if (first_face[0] == second_face[1] &&
22670  first_face[1] == second_face[0])
22671  {
22672  // Save the elements on the corresponding containers
22673  first_shared_boundary_element_pt.push_back(fele_pt);
22674  // .. and the face index
22675  first_shared_boundary_element_face_index.push_back(ifface);
22676 
22677  // Save the elements on the corresponding containers
22678  second_shared_boundary_element_pt.push_back(sele_pt);
22679  // .. and the face index
22680  second_shared_boundary_element_face_index.push_back(isface);
22681 
22682  // Break the loop over the faces of the first elements
22683  // and the first elements, we need to continue looking
22684  // on the next face of the first elements
22685 
22686  // Increase the indexes to force breaking the loop
22687  isface = 3;
22688  es = nsecond_element;
22689  }
22690 
22691  } // for (isface < 3)
22692 
22693  } // if (!(first_ele_is_halo && second_ele_is_halo))
22694 
22695  } // for (es < nsecond_element)
22696 
22697  } // for (ifface < 3)
22698 
22699  } // for (ef < nfirst_element)
22700  }
22701 
22702  //======================================================================
22703  /// Creates the new shared boundaries, this method is also in
22704  /// charge of computing the shared boundaries ids of each processor
22705  /// and send that info. to all the processors
22706  //======================================================================
22707  template<class ELEMENT>
22709  std::set<FiniteElement*>& element_in_processor_pt,
22710  Vector<Vector<FiniteElement*>>& new_shared_boundary_element_pt,
22711  Vector<Vector<unsigned>>& new_shared_boundary_element_face_index)
22712  {
22713  // Get the number of processors
22714  const unsigned nproc = this->communicator_pt()->nproc();
22715  // Get the rank of the current processor
22716  const unsigned my_rank = this->communicator_pt()->my_rank();
22717 
22718  // ================================================================
22719  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22720  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22721  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22722  // SAME EDGE (INTERNAL BOUNDARIES)
22723  // ================================================================
22724 
22725  // Get the time to get edges from shared boundary face elements
22726  double tt_start_get_edges_from_shd_bnd_face_ele = 0.0;
22727  if (Print_timings_level_load_balance > 2)
22728  {
22729  tt_start_get_edges_from_shd_bnd_face_ele = TimingHelpers::timer();
22730  }
22731 
22732  // Face elements that create the shared boundaries (unsorted)
22733  Vector<Vector<FiniteElement*>> tmp_unsorted_face_ele_pt(nproc);
22734  // The elements from where the face element was created
22735  Vector<Vector<FiniteElement*>> tmp_unsorted_ele_pt(nproc);
22736  // The face index of the bulk element from where was created the
22737  // face element
22738  Vector<Vector<int>> tmp_unsorted_face_index_ele(nproc);
22739 
22740  // Store the current edges lying on boundaries (this will help for
22741  // any edge of a shared boundary lying on an internal boundary)
22742  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22743 
22744  // Compute the edges on the other boundaries
22745  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22746 
22747  // Mark those edges (pair of nodes overlapped by a shared boundary)
22748  std::map<std::pair<Node*, Node*>, bool> overlapped_edge;
22749 
22750  // Associate every found edge (face element) on the shared boundary
22751  // with an original boundary only if the edge (face element) lies
22752  // (overlaps) on an original boundary, it may happen only for
22753  // internal boundaries
22754  Vector<Vector<int>> tmp_edge_boundary(nproc);
22755 
22756  // Get the face elements from the shared boundary elements with in
22757  // each processor
22758  for (unsigned iproc = 0; iproc < nproc; iproc++)
22759  {
22760  // There are no shared boundary elements with myself
22761  if (iproc != my_rank)
22762  {
22763  // Get the number of shared boundary elements with in "iproc"
22764  // processor
22765  const unsigned n_shared_bound_ele =
22766  new_shared_boundary_element_pt[iproc].size();
22767 
22768  // Avoid to create repeated face elements, compare the nodes on
22769  // the edges of the face elements
22770  Vector<std::pair<Node*, Node*>> done_faces;
22771 
22772  // Count the number of repeated faces
22773  unsigned nrepeated_faces = 0;
22774 
22775  // Loop over the shared boundary elements with the iproc
22776  // processor
22777  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22778  {
22779  // Get the bulk element
22780  FiniteElement* bulk_ele_pt =
22781  new_shared_boundary_element_pt[iproc][iele];
22782 
22783  // Get the face index
22784  int face_index = static_cast<int>(
22785  new_shared_boundary_element_face_index[iproc][iele]);
22786 
22787  // Create the face element
22788  FiniteElement* tmp_ele_pt =
22789  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
22790 
22791  // Before adding the face element to the vector check that is
22792  // not has been previously created
22793  bool done_face = false;
22794 
22795  // Get the number of nodes on the face element and get the first
22796  // and last node
22797  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22798  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22799  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22800 
22801  // Get the number of already done face elements
22802  const unsigned ndone_faces = done_faces.size();
22803  // Loop over the already visited face elements
22804  for (unsigned n = 0; n < ndone_faces; n++)
22805  {
22806  Node* first_done_face_node_pt = done_faces[n].first;
22807  Node* second_done_face_node_pt = done_faces[n].second;
22808  if (first_face_node_pt == first_done_face_node_pt &&
22809  last_face_node_pt == second_done_face_node_pt)
22810  {
22811  done_face = true;
22812  nrepeated_faces++;
22813  break;
22814  }
22815  // Check for the reversed case
22816  else if (first_face_node_pt == second_done_face_node_pt &&
22817  last_face_node_pt == first_done_face_node_pt)
22818  {
22819  done_face = true;
22820  nrepeated_faces++;
22821  break;
22822  }
22823 
22824  } // for (n < ndone_faces)
22825 
22826  // Only include the faces that are not repeated
22827  if (!done_face)
22828  {
22829  // Add the face element in the vector
22830  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22831  // Add the bulk element to the vector
22832  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22833  // Add the face index to the vector
22834  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22835  // Include the nodes in the done nodes vector
22836  std::pair<Node*, Node*> tmp_edge =
22837  std::make_pair(first_face_node_pt, last_face_node_pt);
22838  // Push the edge
22839  done_faces.push_back(tmp_edge);
22840 
22841  // Associate the face element with a boundary (if that is
22842  // the case)
22843  int edge_boundary_id = -1;
22844  std::map<std::pair<Node*, Node*>, unsigned>::iterator it;
22845  it = elements_edges_on_boundary.find(tmp_edge);
22846  // If the edges lie on a boundary then get the boundary id
22847  // on which the edges lie
22848  if (it != elements_edges_on_boundary.end())
22849  {
22850  // Assign the internal boundary id associated with the
22851  // edge
22852  edge_boundary_id = (*it).second;
22853  // Mark the edge as overlapped
22854  overlapped_edge[tmp_edge] = true;
22855  // Also include the reversed version of the edge
22856  std::pair<Node*, Node*> rev_tmp_edge =
22857  std::make_pair(last_face_node_pt, first_face_node_pt);
22858  // Mark the reversed version of the edge as overlapped
22859  overlapped_edge[rev_tmp_edge] = true;
22860  }
22861  else
22862  {
22863  // Look for the reversed version
22864  std::pair<Node*, Node*> rtmp_edge =
22865  std::make_pair(last_face_node_pt, first_face_node_pt);
22866  it = elements_edges_on_boundary.find(rtmp_edge);
22867  if (it != elements_edges_on_boundary.end())
22868  {
22869  // Assign the internal boundary id associated with the
22870  // edge
22871  edge_boundary_id = (*it).second;
22872  // Mark the edge as overlapped
22873  overlapped_edge[rtmp_edge] = true;
22874  // Mark the reversed version (normal) of the edge as
22875  // overlapped
22876  overlapped_edge[tmp_edge] = true;
22877  }
22878  }
22879  // Associate the edge with a boundary
22880  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22881  } // if (!done_face)
22882  else
22883  {
22884  // Delete the repeated face elements
22885  delete tmp_ele_pt;
22886  tmp_ele_pt = 0;
22887  }
22888 
22889  } // for (iele < n_shared_bound_ele)
22890 
22891  } // if (iproc != my_rank)
22892 
22893  } // for (iproc < nproc)
22894 
22895  // The time to get edges from shared boundary face elements
22896  if (Print_timings_level_load_balance > 2)
22897  {
22898  oomph_info << "CPU for getting edges from shared boundary face elements "
22899  "(load balance) [9.1]: "
22900  << TimingHelpers::timer() -
22901  tt_start_get_edges_from_shd_bnd_face_ele
22902  << std::endl;
22903  }
22904 
22905  // ================================================================
22906  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22907  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22908  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22909  // SAME EDGE (INTERNAL BOUNDARIES)
22910  // ================================================================
22911 
22912  // ================================================================
22913  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22914  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22915  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22916  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22917  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22918  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22919  // ================================================================
22920 
22921  // Get the time to sort shared face elements
22922  double tt_start_sort_shared_face_elements = 0.0;
22923  if (Print_timings_level_load_balance > 2)
22924  {
22925  tt_start_sort_shared_face_elements = TimingHelpers::timer();
22926  }
22927 
22928  // -----------------------------------------------------------------
22929  // Before continuing we need to ensured that the face elements are
22930  // stored in the same order in all processors. Sort them starting
22931  // from the face element with the bottom-left node coordinate
22932 
22933  // Face elements that create the shared boundaries (unsorted)
22934  Vector<Vector<FiniteElement*>> unsorted_face_ele_pt(nproc);
22935  // The elements from where the face element was created
22936  Vector<Vector<FiniteElement*>> unsorted_ele_pt(nproc);
22937  // The face index of the bulk element from where was created the
22938  // face element
22939  Vector<Vector<int>> unsorted_face_index_ele(nproc);
22940  // Associate every found edge on the shared boundary with an
22941  // original boundary only if the edge lies on an original boundary,
22942  // it may happen only for internal boundaries
22943  Vector<Vector<int>> edge_boundary(nproc);
22944 
22945  // For each face element, mark if the element should be considered
22946  // in its inverted way to fullfill with the bottom-left node to be
22947  // the first (left) node. First get the status of each element and
22948  // when they get sorted copy the values across
22949  std::vector<std::vector<bool>> tmp_treat_as_inverted(nproc);
22950  // Vector to store the status of the sorted face elements based on
22951  // the bottom-left condition
22952  std::vector<std::vector<bool>> treat_as_inverted(nproc);
22953 
22954  // Get the bottom-left node of each face element and sort them
22955  // starting from the face element with the bottom-left node
22956 
22957  // Loop over the processors
22958  for (unsigned iproc = 0; iproc < nproc; iproc++)
22959  {
22960  // There are no shared face elements with myself
22961  if (iproc != my_rank)
22962  {
22963  // Get the number of unsorted face elements
22964  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22965  // Store the centroid of the face element. Perform the sorting
22966  // based on the bottom-left centroid of each face element
22967  Vector<Vector<double>> centroid_vertices(n_face_ele);
22968 
22969  // Resize the storage for the treating as inverted face element
22970  // storage
22971  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22972 
22973  // Loop over the face elements associated with the iproc
22974  // processor
22975  for (unsigned e = 0; e < n_face_ele; e++)
22976  {
22977  // Get the face element
22978  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22979  // Get the number of nodes of the face element
22980  const unsigned n_node = face_ele_pt->nnode();
22981  Vector<double> bottom_left(2);
22982  // Assign as the bottom-left node the first node
22983  // Get the node
22984  Node* node_pt = face_ele_pt->node_pt(0);
22985  bottom_left[0] = node_pt->x(0);
22986  bottom_left[1] = node_pt->x(1);
22987  // Set as not treat as inverted element
22988  tmp_treat_as_inverted[iproc][e] = false;
22989  // Loop over the nodes to get the bottom-left vertex of all
22990  // the nodes
22991  for (unsigned n = 1; n < n_node; n++)
22992  {
22993  // Get the node
22994  Node* node_pt = face_ele_pt->node_pt(n);
22995  if (node_pt->x(1) < bottom_left[1])
22996  {
22997  bottom_left[0] = node_pt->x(0);
22998  bottom_left[1] = node_pt->x(1);
22999  // The first node is no longer the bottom-left node, we
23000  // need to treat the element as inverted
23001  tmp_treat_as_inverted[iproc][e] = true;
23002  } // if (node_pt->x(1) < bottom_left[1])
23003  else if (node_pt->x(1) == bottom_left[1])
23004  {
23005  if (node_pt->x(0) < bottom_left[0])
23006  {
23007  bottom_left[0] = node_pt->x(0);
23008  bottom_left[1] = node_pt->x(1);
23009  // The first node is no longer the bottom-left node, we
23010  // need to treat the element as inverted
23011  tmp_treat_as_inverted[iproc][e] = true;
23012  } // if (node_pt->x(0) < bottom_left[0])
23013  } // else if (node_pt->x(1) == bottom_left[1])
23014 
23015  } // for (n < n_node
23016 
23017  // Resize the container
23018  centroid_vertices[e].resize(2);
23019  // Add the centroid of the face element
23020  centroid_vertices[e][0] = (face_ele_pt->node_pt(0)->x(0) +
23021  face_ele_pt->node_pt(n_node - 1)->x(0)) *
23022  0.5;
23023  centroid_vertices[e][1] = (face_ele_pt->node_pt(0)->x(1) +
23024  face_ele_pt->node_pt(n_node - 1)->x(1)) *
23025  0.5;
23026 
23027  } // for (e < n_face_ele)
23028 
23029  // Sort the face elements based on their bottom-left node
23030  unsigned n_sorted_bottom_left = 0;
23031  // Keep track of the already sorted face elements
23032  std::vector<bool> done_face(n_face_ele, false);
23033 
23034  // Loop until all face elements have been sorted
23035  while (n_sorted_bottom_left < n_face_ele)
23036  {
23037  // The index of the next bottom-left face element
23038  unsigned index = 0;
23039  Vector<double> current_bottom_left(2);
23040  for (unsigned e = 0; e < n_face_ele; e++)
23041  {
23042  // Get the first not done face element
23043  if (!done_face[e])
23044  {
23045  // Store the first not done
23046  current_bottom_left[0] = centroid_vertices[e][0];
23047  current_bottom_left[1] = centroid_vertices[e][1];
23048  // Set the index
23049  index = e;
23050  // Break
23051  break;
23052  } // if (!done_face[e])
23053 
23054  } // for (e < n_face_ele)
23055 
23056  // Loop over all the other nondone face elements
23057  for (unsigned e = index + 1; e < n_face_ele; e++)
23058  {
23059  // Get the first not done face element
23060  if (!done_face[e])
23061  {
23062  if (centroid_vertices[e][1] < current_bottom_left[1])
23063  {
23064  // Re-set the current bottom left vertex
23065  current_bottom_left[0] = centroid_vertices[e][0];
23066  current_bottom_left[1] = centroid_vertices[e][1];
23067  // Re-assign the index
23068  index = e;
23069  } // if (centroid_vertices[e][1] < current_bottom_left[1])
23070  else if (centroid_vertices[e][1] == current_bottom_left[1])
23071  {
23072  if (centroid_vertices[e][0] < current_bottom_left[0])
23073  {
23074  // Re-set the current bottom left vertex
23075  current_bottom_left[0] = centroid_vertices[e][0];
23076  current_bottom_left[1] = centroid_vertices[e][1];
23077  // Re-assign the index
23078  index = e;
23079  } // if (centroid_vertices[e][0] < current_bottom_left[0])
23080 
23081  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
23082 
23083  } // if (!done_face[e])
23084 
23085  } // for (e < n_face_ele)
23086 
23087  // The face element
23088  unsorted_face_ele_pt[iproc].push_back(
23089  tmp_unsorted_face_ele_pt[iproc][index]);
23090  // The boundary element
23091  unsorted_ele_pt[iproc].push_back(tmp_unsorted_ele_pt[iproc][index]);
23092  // The face index
23093  unsorted_face_index_ele[iproc].push_back(
23094  tmp_unsorted_face_index_ele[iproc][index]);
23095  // The edge boundary associated to the face element
23096  edge_boundary[iproc].push_back(tmp_edge_boundary[iproc][index]);
23097  // The treat as inverted condition
23098  treat_as_inverted[iproc].push_back(
23099  tmp_treat_as_inverted[iproc][index]);
23100 
23101  // Mark the face element as sorted (done or visited)
23102  done_face[index] = true;
23103 
23104  // Increase the number of sorted bottom-left face elements
23105  n_sorted_bottom_left++;
23106 
23107  } // while (n_sorted_bottom_left < n_face_ele)
23108 
23109 #ifdef PARANOID
23110  // Get the number of face elements sorted with the bottom-left
23111  // condition
23112  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
23113 
23114  if (tmp_n_face_ele != n_face_ele)
23115  {
23116  std::ostringstream error_stream;
23117  error_stream
23118  << "The number of face elements before sorting them starting\n"
23119  << "from their bottom-left vertex is different from the number\n"
23120  << "of face elements after the sorting\n"
23121  << "N. ele before sorting: (" << n_face_ele << ")\n"
23122  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
23123  throw OomphLibError(
23124  error_stream.str(),
23125  "RefineableTriangleMesh::create_new_shared_boundaries()",
23126  OOMPH_EXCEPTION_LOCATION);
23127  }
23128 #endif
23129 
23130  } // if (iproc != my_rank)
23131 
23132  } // for (iproc < nproc)
23133 
23134  // The time to sort shared face elements
23135  if (Print_timings_level_load_balance > 2)
23136  {
23137  oomph_info << "CPU for sorting shared boundary face elements (load "
23138  "balance) [9.2]: "
23139  << TimingHelpers::timer() - tt_start_sort_shared_face_elements
23140  << std::endl;
23141  }
23142 
23143  // ================================================================
23144  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
23145  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
23146  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
23147  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
23148  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
23149  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
23150  // ================================================================
23151 
23152  // ================================================================
23153  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
23154  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
23155  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
23156  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
23157  // IS THE CASE)
23158  // ================================================================
23159 
23160  // Get the time to compute the valency of each node
23161  double tt_start_compute_valency_of_nodes = 0.0;
23162  if (Print_timings_level_load_balance > 2)
23163  {
23164  tt_start_compute_valency_of_nodes = TimingHelpers::timer();
23165  }
23166 
23167  // Stores the global-degree of each node
23168  std::map<Node*, unsigned> global_node_degree;
23169 
23170  // Get the global degree (valency) of each node
23171  compute_shared_node_degree_helper(unsorted_face_ele_pt, global_node_degree);
23172 
23173  // The time to compute the valency of each node
23174  if (Print_timings_level_load_balance > 2)
23175  {
23176  oomph_info
23177  << "CPU for computing the valency of nodes (load balance) [9.3]: "
23178  << TimingHelpers::timer() - tt_start_compute_valency_of_nodes
23179  << std::endl;
23180  }
23181 
23182  // ================================================================
23183  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
23184  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
23185  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
23186  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
23187  // IS THE CASE)
23188  // ================================================================
23189 
23190  // ================================================================
23191  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23192  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23193  // ================================================================
23194 
23195  // Get the time to compute nodes on non overlapped shared boundaries
23196  double tt_start_nodes_on_non_overlapped_shd_bnd = 0.0;
23197  if (Print_timings_level_load_balance > 2)
23198  {
23199  tt_start_nodes_on_non_overlapped_shd_bnd = TimingHelpers::timer();
23200  }
23201 
23202  // Mark the nodes on original boundaries not overlapped by shared
23203  // boundaries
23204  std::map<unsigned, std::map<Node*, bool>>
23205  node_on_bnd_not_overlapped_by_shd_bnd;
23206 
23207  // Loop over the edges of the original boundaries
23208  for (std::map<std::pair<Node*, Node*>, unsigned>::iterator it_map =
23209  elements_edges_on_boundary.begin();
23210  it_map != elements_edges_on_boundary.end();
23211  it_map++)
23212  {
23213  // Get the edge
23214  std::pair<Node*, Node*> edge_pair = (*it_map).first;
23215  // Is the edge overlaped by a shared boundary
23216  if (!overlapped_edge[edge_pair])
23217  {
23218  // Mark the nodes of the edge as being on an edge not overlaped
23219  // by a shared boundary on the boundary the edge is
23220  unsigned b = (*it_map).second;
23221 
23222  // Get the left node
23223  Node* left_node_pt = edge_pair.first;
23224  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
23225 
23226  // Get the right node
23227  Node* right_node_pt = edge_pair.second;
23228  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
23229 
23230  } // if (!overlapped_edge[edge_pair])
23231 
23232  } // Loop over edges to mark those nodes on overlaped edge by
23233  // shared boundaries
23234 
23235  // The time to compute nodes on non overlapped shared boundaries
23236  if (Print_timings_level_load_balance > 2)
23237  {
23238  oomph_info << "CPU for computing nodes on non overlapped shared "
23239  "boundaries (load balance) [9.4]: "
23240  << TimingHelpers::timer() -
23241  tt_start_nodes_on_non_overlapped_shd_bnd
23242  << std::endl;
23243  }
23244 
23245  // ================================================================
23246  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23247  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23248  // ================================================================
23249 
23250  // ==================================================================
23251  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23252  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23253  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23254  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23255  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23256  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23257  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23258  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23259  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23260  // ==================================================================
23261 
23262  // Get the time to sort shared boundaries face elements to create a
23263  // continuous representation of the boundary
23264  double tt_start_join_shd_bnd_face_ele = 0.0;
23265  if (Print_timings_level_load_balance > 2)
23266  {
23267  tt_start_join_shd_bnd_face_ele = TimingHelpers::timer();
23268  }
23269 
23270  // Face elements that create the shared boundaries (sorted)
23271  Vector<Vector<Vector<FiniteElement*>>> sorted_face_ele_pt(nproc);
23272 
23273  // Bulk elements that create the shared boundaries (sorted)
23274  Vector<Vector<Vector<FiniteElement*>>> sorted_ele_pt(nproc);
23275 
23276  // Face indexes of the bulk elements that create the shared
23277  // boundaries (sorted)
23278  Vector<Vector<Vector<int>>> sorted_face_index_ele(nproc);
23279 
23280  // Store the edge boundary id associated with a shared boundary (if
23281  // any, this apply for shared boundaries lying on internal
23282  // boundaries, then the shared boundary is marked as overlaping an
23283  // internal boundary)
23284  Vector<Vector<int>> edge_boundary_id(nproc);
23285 
23286  // Store the connection information obtained when joining the face
23287  // elements (used for connection purposes only)
23288  Vector<Vector<Vector<int>>> sorted_connection_info(nproc);
23289 
23290  // Store the local shared boundary id associated to the elements
23291  // that will give rise to the shared boundaries (used to compute the
23292  // global shared boundary id from the local shared boundary id)
23293  Vector<Vector<unsigned>> proc_local_shared_boundary_id(nproc);
23294 
23295  // Map that associates the local shared boundary id with the list of
23296  // nodes that create it
23297  std::map<unsigned, std::list<Node*>>
23298  local_shd_bnd_id_to_sorted_list_node_pt;
23299 
23300  // Local shared bouonday id (used to locally identify the lists of
23301  // nodes that create shared boundaries, it is also useful to
23302  // identify connections with shared boundaries)
23303  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23304 
23305  // Sort the face elements, using the nodes at its ends
23306 
23307  // Mark the done elements
23308  std::map<FiniteElement*, bool> done_ele;
23309 
23310  // Mark the inverted elements
23311  std::map<FiniteElement*, bool> is_inverted;
23312 
23313  // Sort the face elements to get the number of shared boundaries
23314  // with in each processor
23315  for (unsigned iproc = 0; iproc < nproc; iproc++)
23316  {
23317  // No face elements with myself
23318  if (iproc != my_rank)
23319  {
23320  // Get the number of unsorted face elements with the iproc
23321  // processor
23322  const unsigned nunsorted_face_ele = unsorted_face_ele_pt[iproc].size();
23323  // Count the number of sorted face elements
23324  unsigned nsorted_face_ele = 0;
23325 
23326  // Iterate until all the face elements have been sorted
23327  while (nsorted_face_ele < nunsorted_face_ele)
23328  {
23329  // Take the first nonsorted element an use it as root element,
23330  // add elements to the left and right until no more elements
23331  // left or until a stop condition is reached (connection,
23332  // boundary node)
23333 
23334 #ifdef PARANOID
23335  // Flag to indicate if a root element was found
23336  bool found_root_element = false;
23337 #endif
23338 
23339  // Index of the found root element
23340  unsigned root_index = 0;
23341 
23342  // List that contains the sorted face elements
23343  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23344 
23345  // List that contains the sorted elements
23346  std::list<FiniteElement*> tmp_sorted_ele_pt;
23347 
23348  // List that contains the sorted face indexes of the bulk
23349  // elements
23350  std::list<int> tmp_sorted_face_index_ele;
23351 
23352  // Storing for the sorting nodes extracted from the face
23353  // elements. The sorted nodes are used to identify connections
23354  // among new shared boundaries or original boundaries
23355  std::list<Node*> tmp_sorted_nodes_pt;
23356  // Clear the storage (just in case)
23357  tmp_sorted_nodes_pt.clear();
23358 
23359  // The initial and final nodes
23360  Node* initial_node_pt = 0;
23361  Node* final_node_pt = 0;
23362 
23363  // Store the original boundary id related with the root face
23364  // element (if there is one)
23365  int root_edge_bound_id = -1;
23366 
23367  // Loop over the unsorted face elements until a root element
23368  // is found
23369  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23370  {
23371  // Get a root element
23372  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23373  // Is the element already done?
23374  if (!done_ele[root_ele_pt])
23375  {
23376  // Get the edge boundary id associated with the edge (if
23377  // there is one)
23378  root_edge_bound_id = edge_boundary[iproc][e];
23379  // Add the face element to the list of sorted face
23380  // elements
23381  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23382  // Add the bulk element to the list of sorted elements
23383  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23384  // Add the face index to the list of sorted face index
23385  // elements
23386  tmp_sorted_face_index_ele.push_back(
23387  unsorted_face_index_ele[iproc][e]);
23388 
23389  // Get the nodes and state them as initial and final
23390  const unsigned nnodes = root_ele_pt->nnode();
23391  // Check if the face element should be treated as inverted
23392  if (!treat_as_inverted[iproc][e])
23393  {
23394  initial_node_pt = root_ele_pt->node_pt(0);
23395  final_node_pt = root_ele_pt->node_pt(nnodes - 1);
23396  }
23397  else
23398  {
23399  initial_node_pt = root_ele_pt->node_pt(nnodes - 1);
23400  final_node_pt = root_ele_pt->node_pt(0);
23401  }
23402  // Add both nodes to the list of sorted nodes
23403  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23404  tmp_sorted_nodes_pt.push_back(final_node_pt);
23405 
23406  // Mark the element as done
23407  done_ele[root_ele_pt] = true;
23408  // Check if the face element should be treated as inverted
23409  if (!treat_as_inverted[iproc][e])
23410  {
23411  // Mark the element as not inverted
23412  is_inverted[root_ele_pt] = false;
23413  }
23414  else
23415  {
23416  // Mark the element as inverted
23417  is_inverted[root_ele_pt] = true;
23418  }
23419  // Increase the counter for sorted face elements
23420  nsorted_face_ele++;
23421  // Set the root index
23422  root_index = e;
23423 #ifdef PARANOID
23424  // Set the flag of found root element
23425  found_root_element = true;
23426 #endif
23427  // Break the loop
23428  break;
23429 
23430  } // if (!done_ele[root_ele_pt])
23431 
23432  } // for (e < nunsorted_face_ele)
23433 
23434 #ifdef PARANOID
23435  if (!found_root_element)
23436  {
23437  std::ostringstream error_stream;
23438  error_stream
23439  << "It was not possible the found the root element\n\n";
23440  throw OomphLibError(error_stream.str(),
23441  OOMPH_CURRENT_FUNCTION,
23442  OOMPH_EXCEPTION_LOCATION);
23443  }
23444 #endif
23445 
23446  // New element added. Continue adding elements -- or nodes --
23447  // to the list of shared boundary elements while a new element
23448  // has been added to the list (we have just added the root
23449  // element)
23450  bool new_element_added = true;
23451 
23452  // Similarly that in the
23453  // "create_polylines_from_halo_elements_helper() method, we
23454  // extract the nodes (in order) that will create the shared
23455  // polyline, and also check for connections with the just
23456  // added face elements (nodes)
23457 
23458  // Flags to indicate at which end (of the sorted list of
23459  // boundary elements) the element was added (left or right)
23460  bool element_added_to_the_left = false;
23461  bool element_added_to_the_right = false;
23462 
23463  // Flag to indicate that the "left" node of the element added
23464  // to the left was found to be shared with another boundary
23465  bool connection_to_the_left = false;
23466 
23467  // Flag to indicate that the "right" node of the element added
23468  // to the right was found to be shared with another boundary
23469  bool connection_to_the_right = false;
23470 
23471  // Flag to stop the adding of elements (and nodes) to the
23472  // current shared boundary (because there are connections at
23473  // both ends)
23474  bool current_polyline_has_connections_at_both_ends = false;
23475 
23476  // Store the boundary ids of the polylines to connect (only
23477  // used when the polyline was found to have a connection)
23478  // -1: Indicates no connection
23479  // -2: Indicates connection with itself
23480  // -3: Indicates no connection BUT STOP adding elements
23481  // -because the node is a boundary node whose boundary is no
23482  // -currently part of the domain. Think in one of the corner
23483  // -nodes of a triangle touchin a boundary that does no longer
23484  // -exist
23485  // Any other value: Boundary id to connect
23486  int bound_id_connection_to_the_left = -1;
23487  int bound_id_connection_to_the_right = -1;
23488 
23489  // Get the global degree of the node (notice the local degree
23490  // has been updated to global degree)
23491  const unsigned initial_node_degree =
23492  global_node_degree[initial_node_pt];
23493 
23494  // Flag to indicate we are calling the method from a load
23495  // balance sub-rutine
23496  const bool called_for_load_balance = true;
23497 
23498  // Check if the nodes of the root element have connections
23499  // ... to the left
23500  bound_id_connection_to_the_left =
23501  this->check_connections_of_polyline_nodes(
23502  element_in_processor_pt,
23503  root_edge_bound_id,
23504  overlapped_edge,
23505  node_on_bnd_not_overlapped_by_shd_bnd,
23506  tmp_sorted_nodes_pt,
23507  local_shd_bnd_id_to_sorted_list_node_pt,
23508  initial_node_degree,
23509  initial_node_pt,
23510  called_for_load_balance);
23511 
23512  // If there is a stop condition then set the corresponding
23513  // flag
23514  if (bound_id_connection_to_the_left != -1)
23515  {
23516  connection_to_the_left = true;
23517  } // if (bound_id_connection_to_the_left != -1)
23518 
23519  // Get the global degree of the node (notice the local degree
23520  // has been updated to global degree)
23521  const unsigned final_node_degree = global_node_degree[final_node_pt];
23522 
23523  // ... and to the right
23524  bound_id_connection_to_the_right =
23525  this->check_connections_of_polyline_nodes(
23526  element_in_processor_pt,
23527  root_edge_bound_id,
23528  overlapped_edge,
23529  node_on_bnd_not_overlapped_by_shd_bnd,
23530  tmp_sorted_nodes_pt,
23531  local_shd_bnd_id_to_sorted_list_node_pt,
23532  final_node_degree,
23533  final_node_pt,
23534  called_for_load_balance);
23535 
23536  // If there is a stop condition then set the corresponding
23537  // flag
23538  if (bound_id_connection_to_the_right != -1)
23539  {
23540  connection_to_the_right = true;
23541  } // if (bound_id_connection_to_the_right != -1)
23542 
23543  // If the current shared boundary has connections at both ends
23544  // then stop the adding of elements (and nodes)
23545  if (connection_to_the_left && connection_to_the_right)
23546  {
23547  current_polyline_has_connections_at_both_ends = true;
23548  }
23549 
23550  // Continue searching for more elements to add if
23551  // 1) A new element was added at the left or right of the list
23552  // 2) There are more possible elements to add
23553  // 3) The nodes at the edges of the added element (left or
23554  // right) are not part of any other previous shared
23555  // boundary
23556  while (new_element_added && (nsorted_face_ele < nunsorted_face_ele) &&
23557  !current_polyline_has_connections_at_both_ends)
23558  {
23559  // Loop over the remaining elements and try to create a
23560  // contiguous set of face elements, start looking from the
23561  // root index. Any previous element should have been already
23562  // visited
23563  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23564  {
23565  // Reset the flags for added elements, to the left and right
23566  new_element_added = false;
23567  element_added_to_the_left = false;
23568  element_added_to_the_right = false;
23569 
23570  // Get the "e"-th element on the vector
23571  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23572  // Get the boundary id associated with the edge (if any)
23573  const int edge_bound_id = edge_boundary[iproc][e];
23574  // Check if the element has been already sorted and the
23575  // related edge bound id is the same as the root edge (if
23576  // any)
23577  if (!done_ele[tmp_ele_pt] &&
23578  (edge_bound_id == root_edge_bound_id))
23579  {
23580  // Get the number of nodes on the current element
23581  const unsigned nnodes = tmp_ele_pt->nnode();
23582  // Get the first and last node of the element
23583  // Check if the face element should be treated as inverted
23584  Node* first_node_pt = 0;
23585  Node* last_node_pt = 0;
23586  if (!treat_as_inverted[iproc][e])
23587  {
23588  first_node_pt = tmp_ele_pt->node_pt(0);
23589  last_node_pt = tmp_ele_pt->node_pt(nnodes - 1);
23590  }
23591  else
23592  {
23593  first_node_pt = tmp_ele_pt->node_pt(nnodes - 1);
23594  last_node_pt = tmp_ele_pt->node_pt(0);
23595  }
23596 
23597  // A pointer to the node at the left or right of the
23598  // just added element, the most left or the most right
23599  // node
23600  Node* new_added_node_pt = 0;
23601 
23602  // Check if the element goes to the left
23603  if (initial_node_pt == last_node_pt && !connection_to_the_left)
23604  {
23605  // Update the initial node and the just added node
23606  new_added_node_pt = initial_node_pt = first_node_pt;
23607  // Add the most left node
23608  tmp_sorted_nodes_pt.push_front(first_node_pt);
23609  // Add the face element to the list of sorted face
23610  // elements
23611  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23612  // Add the bulk element to the list of sorted elements
23613  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23614  // Add the face index to the list of sorted face index
23615  // elements
23616  tmp_sorted_face_index_ele.push_front(
23617  unsorted_face_index_ele[iproc][e]);
23618  if (!treat_as_inverted[iproc][e])
23619  {
23620  // Mark the element as not inverted
23621  is_inverted[tmp_ele_pt] = false;
23622  }
23623  else
23624  {
23625  // Mark the element as inverted
23626  is_inverted[tmp_ele_pt] = true;
23627  }
23628  // Set the flag to indicate a new element was added
23629  new_element_added = true;
23630  // Set the flag to indicate the element was added to
23631  // the left
23632  element_added_to_the_left = true;
23633  }
23634  // Check if the element goes to the left (but inverted)
23635  else if (initial_node_pt == first_node_pt &&
23636  !connection_to_the_left)
23637  {
23638  // Update the initial node and the just added node
23639  new_added_node_pt = initial_node_pt = last_node_pt;
23640  // Add the most left node
23641  tmp_sorted_nodes_pt.push_front(last_node_pt);
23642  // Add the face element to the list of sorted face
23643  // elements
23644  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23645  // Add the bulk element to the list of sorted elements
23646  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23647  // Add the face index to the list of sorted face index
23648  // elements
23649  tmp_sorted_face_index_ele.push_front(
23650  unsorted_face_index_ele[iproc][e]);
23651  if (!treat_as_inverted[iproc][e])
23652  {
23653  // Mark the element as inverted
23654  is_inverted[tmp_ele_pt] = true;
23655  }
23656  else
23657  {
23658  // Mark the element as not inverted
23659  is_inverted[tmp_ele_pt] = false;
23660  }
23661  // Set the flag to indicate a new element was added
23662  new_element_added = true;
23663  // Set the flag to indicate the element was added to
23664  // the left
23665  element_added_to_the_left = true;
23666  }
23667  // Check if the elements goes to the right
23668  else if (final_node_pt == first_node_pt &&
23669  !connection_to_the_right)
23670  {
23671  // Update the final node and the just added node
23672  new_added_node_pt = final_node_pt = last_node_pt;
23673  // Add the most right node
23674  tmp_sorted_nodes_pt.push_back(last_node_pt);
23675  // Add the face element to the list of sorted face
23676  // elements
23677  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23678  // Add the bulk element to the list of sorted elements
23679  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23680  // Add the face index to the list of sorted face index
23681  // elements
23682  tmp_sorted_face_index_ele.push_back(
23683  unsorted_face_index_ele[iproc][e]);
23684  if (!treat_as_inverted[iproc][e])
23685  {
23686  // Mark the element as not inverted
23687  is_inverted[tmp_ele_pt] = false;
23688  }
23689  else
23690  {
23691  // Mark the element as inverted
23692  is_inverted[tmp_ele_pt] = true;
23693  }
23694  // Set the flag to indicate a new element was added
23695  new_element_added = true;
23696  // Set the flag to indicate the element was added to
23697  // the right
23698  element_added_to_the_right = true;
23699  }
23700  // Check if the elements goes to the right (but inverted)
23701  else if (final_node_pt == last_node_pt &&
23702  !connection_to_the_right)
23703  {
23704  // Update the final node and the just added node
23705  new_added_node_pt = final_node_pt = first_node_pt;
23706  // Add the most right node
23707  tmp_sorted_nodes_pt.push_back(first_node_pt);
23708  // Add the face element to the list of sorted face
23709  // elements
23710  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23711  // Add the bulk element to the list of sorted elements
23712  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23713  // Add the face index to the list of sorted face index
23714  // elements
23715  tmp_sorted_face_index_ele.push_back(
23716  unsorted_face_index_ele[iproc][e]);
23717  if (!treat_as_inverted[iproc][e])
23718  {
23719  // Mark the element as inverted
23720  is_inverted[tmp_ele_pt] = true;
23721  }
23722  else
23723  {
23724  // Mark the element as not inverted
23725  is_inverted[tmp_ele_pt] = false;
23726  }
23727  // Set the flag to indicate a new elements was added
23728  new_element_added = true;
23729  // Set the flag to indicate the element was added to
23730  // the right
23731  element_added_to_the_right = true;
23732  }
23733 
23734  // Do additional stuff if the element was added
23735  if (new_element_added)
23736  {
23737  // Mark the element as done
23738  done_ele[tmp_ele_pt] = true;
23739  // Increase the counter for sorted face elements
23740  nsorted_face_ele++;
23741 
23742  // Get the global degree of the node (notice the
23743  // local degree has been updated to global degree)
23744  const unsigned new_added_node_degree =
23745  global_node_degree[new_added_node_pt];
23746 
23747  // Based on which side the element was added, look for
23748  // connections on that side
23749 
23750  // Verify for connections to the left (we need to
23751  // check for the connection variable too, since
23752  // after a connection has been done we no longer
23753  // need to verify for this condition)
23754  if (element_added_to_the_left && !connection_to_the_left)
23755  {
23756  // Check for connection
23757  bound_id_connection_to_the_left =
23758  this->check_connections_of_polyline_nodes(
23759  element_in_processor_pt,
23760  root_edge_bound_id,
23761  overlapped_edge,
23762  node_on_bnd_not_overlapped_by_shd_bnd,
23763  tmp_sorted_nodes_pt,
23764  local_shd_bnd_id_to_sorted_list_node_pt,
23765  new_added_node_degree,
23766  new_added_node_pt,
23767  called_for_load_balance);
23768 
23769  // If there is a stop condition then set the
23770  // corresponding flag
23771  if (bound_id_connection_to_the_left != -1)
23772  {
23773  connection_to_the_left = true;
23774  } // if (bound_id_connection_to_the_left != -1)
23775 
23776  } // if (node_added_to_the_left &&
23777  // !connection_to_the_left)
23778 
23779  // Verify for connections to the right (we need to
23780  // check for the connection variable too, since
23781  // after a connection has been done we no longer
23782  // need to verify for this condition)
23783  if (element_added_to_the_right && !connection_to_the_right)
23784  {
23785  // Check for connection
23786  bound_id_connection_to_the_right =
23787  this->check_connections_of_polyline_nodes(
23788  element_in_processor_pt,
23789  root_edge_bound_id,
23790  overlapped_edge,
23791  node_on_bnd_not_overlapped_by_shd_bnd,
23792  tmp_sorted_nodes_pt,
23793  local_shd_bnd_id_to_sorted_list_node_pt,
23794  new_added_node_degree,
23795  new_added_node_pt,
23796  called_for_load_balance);
23797 
23798  // If there is a stop condition then set the
23799  // corresponding flag
23800  if (bound_id_connection_to_the_right != -1)
23801  {
23802  connection_to_the_right = true;
23803  } // if (bound_id_connection_to_the_right != -1)
23804 
23805  } // if (node_added_to_the_right &&
23806  // !connection_to_the_right)
23807 
23808  // If the current shared boundary has connections at
23809  // both ends then stop the adding of elements (and
23810  // nodes)
23811  if (connection_to_the_left && connection_to_the_right)
23812  {
23813  current_polyline_has_connections_at_both_ends = true;
23814  }
23815 
23816  // Break the for (looping over unsorted face
23817  // elements) and re-start looking for more elements
23818  // that fit to the left or right
23819  break;
23820 
23821  } // if (new_element_added)
23822 
23823  } // if (!done_ele[tmp_ele_pt])
23824 
23825  } // for (e < nunsorted_face_ele)
23826 
23827  } // while(new_element_added &&
23828  // (nsorted_face_ele < nunsorted_face_ele)
23829  // && !current_polyline_has_connections_at_both_ends)
23830 
23831  // ------------------------------------------------------------
23832  // Before assigning a local shared boundary id to the list of
23833  // nodes and boundary elements, check for any loop that the
23834  // shared boundary may be creating
23835 
23836  // The vector of the elements
23837  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23838  // Store the list of elements on a vector of elements
23839  for (std::list<FiniteElement*>::iterator it =
23840  tmp_sorted_ele_pt.begin();
23841  it != tmp_sorted_ele_pt.end();
23842  it++)
23843  {
23844  tmp_vector_sorted_ele_pt.push_back((*it));
23845  }
23846 
23847  // The vector of the face elements
23848  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23849  // Store the list of face elements on a vector of face
23850  // elements
23851  for (std::list<FiniteElement*>::iterator it =
23852  tmp_sorted_face_ele_pt.begin();
23853  it != tmp_sorted_face_ele_pt.end();
23854  it++)
23855  {
23856  tmp_vector_sorted_face_ele_pt.push_back((*it));
23857  }
23858 
23859  // The vector of the face indexes
23860  Vector<int> tmp_vector_sorted_face_index_ele;
23861  // Store the list of elements on a vector of elements
23862  for (std::list<int>::iterator it = tmp_sorted_face_index_ele.begin();
23863  it != tmp_sorted_face_index_ele.end();
23864  it++)
23865  {
23866  tmp_vector_sorted_face_index_ele.push_back((*it));
23867  }
23868 
23869  // Store the nodes for the new shared polylines without loops
23870  Vector<std::list<Node*>> final_sorted_nodes_pt;
23871  // Store the boundary elements of the shared polyline without
23872  // loops
23873  Vector<Vector<FiniteElement*>> final_boundary_element_pt;
23874  // Store the boundary face elements of the shared polyline
23875  // without loops
23876  Vector<Vector<FiniteElement*>> final_boundary_face_element_pt;
23877  // Face indexes of the boundary elements without loops
23878  Vector<Vector<int>> final_face_index_element;
23879  // Connection flags (to the left) of the shared boundaries
23880  // without loops
23881  Vector<int> final_bound_id_connection_to_the_left;
23882  // Connection flags (to the right) of the shared boundaries
23883  // without loops
23884  Vector<int> final_bound_id_connection_to_the_right;
23885 
23886  // Break any possible loop created by the shared polyline
23887  this->break_loops_on_shared_polyline_load_balance_helper(
23888  local_shd_bnd_id,
23889  tmp_sorted_nodes_pt,
23890  tmp_vector_sorted_ele_pt,
23891  tmp_vector_sorted_face_ele_pt,
23892  tmp_vector_sorted_face_index_ele,
23893  bound_id_connection_to_the_left,
23894  bound_id_connection_to_the_right,
23895  final_sorted_nodes_pt,
23896  final_boundary_element_pt,
23897  final_boundary_face_element_pt,
23898  final_face_index_element,
23899  final_bound_id_connection_to_the_left,
23900  final_bound_id_connection_to_the_right);
23901 
23902  // Get the number of final sorted nodes
23903  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23904 
23905  // Loop over the list of final sorted nodes
23906  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23907  {
23908  // Store the list of nodes that gave rise to the shared
23909  // boundary
23910  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23911  final_sorted_nodes_pt[i];
23912 
23913  // Store the local shared boundary id assigned to the
23914  // elements that will create the shared boundary
23915  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23916 
23917  // Increase the shared boundary id (note that this is only
23918  // used to keep track of the list of nodes that create the
23919  // shared boundaries in the current processor)
23920  local_shd_bnd_id++;
23921 
23922  // Include the vector of elements to the sorted vector
23923  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23924 
23925  // Include the vector of face elements to the sorted vector
23926  sorted_face_ele_pt[iproc].push_back(
23927  final_boundary_face_element_pt[i]);
23928 
23929  // Include the vector of elements to the sorted vector
23930  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23931 
23932  // Include the possible associated boundary id to the vector
23933  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23934 
23935  // Include the connection information associated with the
23936  // current set of face elements (that will give rise to a
23937  // shared polyline
23938  // The temporal storage for the boundary connections ids
23939  Vector<int> bnd_connections_ids(2);
23940  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23941  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23942  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23943 
23944  } // for (i < n_final_sorted_nodes)
23945 
23946  } // while (nsorted_face_ele < nunsorted_face_ele)
23947 
23948  } // if (iproc != my_rank)
23949 
23950  } // for (iproc < nproc)
23951 
23952  // The time to sort shared boundaries face elements to create a
23953  // continuous representation of the boundary
23954  if (Print_timings_level_load_balance > 2)
23955  {
23956  oomph_info << "CPU for joining shared boundary face elements (load "
23957  "balance) [9.5]: "
23958  << TimingHelpers::timer() - tt_start_join_shd_bnd_face_ele
23959  << std::endl;
23960  }
23961 
23962  // ==================================================================
23963  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23964  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23965  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23966  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23967  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23968  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23969  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23970  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23971  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23972  // ==================================================================
23973 
23974  // ==================================================================
23975  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23976  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23977  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23978  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23979  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23980  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23981  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23982  // ALSO COMPUTED
23983  // ==================================================================
23984 
23985  // Get the time to compute new shared boundaries ids
23986  double tt_start_get_new_shared_boundaries_ids = 0.0;
23987  if (Print_timings_level_load_balance > 2)
23988  {
23989  tt_start_get_new_shared_boundaries_ids = TimingHelpers::timer();
23990  }
23991 
23992  // Get the number of shared boundaries with in each processor
23993  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23994  // Loop over the processors
23995  for (unsigned iproc = 0; iproc < nproc; iproc++)
23996  {
23997  // No shared boundaries with myself
23998  if (iproc != my_rank)
23999  {
24000  // Store the number of shared boundaries of the current
24001  // processor (my_rank) with the iproc processor
24002  nshared_boundaries_with_processor[iproc] =
24003  sorted_face_ele_pt[iproc].size();
24004 
24005  } // if (iproc != my_rank)
24006 
24007  } // for (iproc < nproc)
24008 
24009  // Each processor sends the number of shared boundaries that it has
24010  // with in each other processor to the "root_processor" which will
24011  // be in charge of checking and computing the global shared
24012  // boundaries ids
24013  const unsigned root_processor = 0;
24014 
24015  // Get the communicator of the mesh
24016  OomphCommunicator* comm_pt = this->communicator_pt();
24017 
24018  // Container where to store the info. received from other processor
24019  // in root. It receives from all processors the number of shared
24020  // boundaries that each one has with any other processor
24021  Vector<unsigned> flat_unsigned_root_received_data(nproc * nproc);
24022 
24023  // Gather the info. in the "root_processor"
24024  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
24025  // each processor
24026  nproc, // Total number of data to send from each
24027  // processor
24028  MPI_UNSIGNED,
24029  &flat_unsigned_root_received_data[0], // Container where
24030  // to receive the
24031  // info. from all
24032  // the processors
24033  nproc, // Number of data to receive from each processor
24034  MPI_UNSIGNED,
24035  root_processor, // The processor that receives all the
24036  // info.
24037  comm_pt->mpi_comm());
24038 
24039  // Container where root store the info. that will be sent back to
24040  // all processor, because root performs a Broadcast operation then
24041  // the info. is received in the same container
24042  Vector<unsigned> flat_unsigned_root_send_receive_data;
24043 
24044  // Compute the new initial and final shared boundary id (they are
24045  // based on the global number of shared boundaries)
24046  unsigned new_initial_shared_boundary_id = 0;
24047  unsigned new_final_shared_boundary_id = 0;
24048 
24049  // Compute the boundaries ids for the shared boundaries
24050  if (my_rank == root_processor)
24051  {
24052  // Change the representation of the data received from all
24053  // processors to a matrix representation for ease access
24054  Vector<Vector<unsigned>> root_nshared_bound_proc_with_proc(nproc);
24055  // Loop over the processors and get the number of shared
24056  // boundaries of processor iproc with jproc
24057  for (unsigned iproc = 0; iproc < nproc; iproc++)
24058  {
24059  // Resize the vector to store the data
24060  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
24061  // Loop over the processors and get the number of shared
24062  // boundaries of processor iproc with jproc
24063  for (unsigned jproc = 0; jproc < nproc; jproc++)
24064  {
24065  root_nshared_bound_proc_with_proc[iproc][jproc] =
24066  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
24067 
24068  } // for (jproc < nproc)
24069 
24070  } // for (iproc < nproc)
24071 
24072 #ifdef PARANOID
24073  // Check that the same number of boundaries are shared by two
24074  // specific processors
24075  for (unsigned iproc = 0; iproc < nproc; iproc++)
24076  {
24077  for (unsigned jproc = 0; jproc < iproc; jproc++)
24078  {
24079  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
24080  root_nshared_bound_proc_with_proc[jproc][iproc])
24081  {
24082  std::ostringstream error_stream;
24083  error_stream
24084  << "ROOT PROCESSOR ERROR\n\n"
24085  << "The number of shared boundaries between processor (" << iproc
24086  << ") and (" << jproc << ") is not the same:\n"
24087  << "Shared boundaries of processor (" << iproc
24088  << ") with processor (" << jproc << "): ("
24089  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
24090  << "Shared boundaries of processor (" << jproc
24091  << ") with processor (" << iproc << "): ("
24092  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
24093  throw OomphLibError(error_stream.str(),
24094  OOMPH_CURRENT_FUNCTION,
24095  OOMPH_EXCEPTION_LOCATION);
24096 
24097  } // The number of shared boundaries between processors
24098  // "iproc" and "jproc" is not the same
24099 
24100  } // for (jproc < iproc)
24101 
24102  } // for (iproc < nproc)
24103 #endif
24104 
24105  // The enumeration of the shared boundaries starts from the lowest
24106  // processor number to the highest processor number
24107 
24108  // Two processors share the same boundaries ids, the lowest
24109  // processor number is the one in charge of computing the shared
24110  // boundaries ids
24111  Vector<Vector<unsigned>> start_shared_bound_id_proc_with_proc(nproc);
24112  // Resize the vector, we can not do it when storing the
24113  // info. because of the strategy to save the info.
24114  for (unsigned iproc = 0; iproc < nproc; iproc++)
24115  {
24116  start_shared_bound_id_proc_with_proc[iproc].resize(nproc);
24117  }
24118 
24119  // The shared boundaries ids start from the current number of
24120  // original boundaries
24121  unsigned shared_bound_id = this->nboundary();
24122 
24123  // Set the new initial shared boundary id
24124  new_initial_shared_boundary_id = shared_bound_id;
24125 
24126  // Assign the global shared boundary id for the shared boundaries
24127  for (unsigned iproc = 0; iproc < nproc; iproc++)
24128  {
24129  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24130  {
24131  // Are there shared boundaries between the pair of processors
24132  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
24133  {
24134  // Set the start boundary id of processor "iproc" with
24135  // processor "jproc" and viceversa
24136  start_shared_bound_id_proc_with_proc[iproc][jproc] =
24137  shared_bound_id;
24138  start_shared_bound_id_proc_with_proc[jproc][iproc] =
24139  shared_bound_id;
24140  // Increase the shared boundary id counter with as many
24141  // shared boundaries there are between the iproc and jproc
24142  // processor
24143  shared_bound_id += root_nshared_bound_proc_with_proc[iproc][jproc];
24144  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
24145 
24146  } // for (jproc < iproc)
24147 
24148  } // for (iproc < nproc)
24149 
24150  // Set the new final shared boundary id
24151  new_final_shared_boundary_id = shared_bound_id;
24152 
24153  // Prepare the info. to send back to each processor
24154  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc * nproc);
24155 
24156  // Copy the info. to the storage to send the info. back to other
24157  // processors
24158  for (unsigned iproc = 0; iproc < nproc; iproc++)
24159  {
24160  for (unsigned jproc = 0; jproc < nproc; jproc++)
24161  {
24162  // Get the initial shared boundary id between each pair of
24163  // processors (iproc, jproc)
24164  const unsigned initial_shd_bnd_id =
24165  start_shared_bound_id_proc_with_proc[iproc][jproc];
24166  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
24167 
24168  // .. then copy the number of shared boundaries that there are
24169  // between processor iproc and jproc
24170  const unsigned nshared_bnd_iproc_jproc =
24171  root_nshared_bound_proc_with_proc[iproc][jproc];
24172  flat_unsigned_root_send_receive_data.push_back(
24173  nshared_bnd_iproc_jproc);
24174 
24175  } // for (jproc < nproc)
24176 
24177  } // for (iproc < nproc)
24178 
24179  // .. at the end of the data to send include the global initial
24180  // shared boundary id
24181  flat_unsigned_root_send_receive_data.push_back(
24182  new_initial_shared_boundary_id);
24183 
24184  // ... and the global final shared boundary id
24185  flat_unsigned_root_send_receive_data.push_back(
24186  new_final_shared_boundary_id);
24187 
24188  } // if (my_rank == root_processor)
24189 
24190  // Send the initial shared boundaries ids and the number of shared
24191  // boundaries between all procesors to all processors. All
24192  // processors need to know this info.
24193 
24194  // The number of data that will be sent by root to other processors
24195  // and the number of data that other processors receive from root,
24196  // it is the same because it is performed via a Broadcast
24197  unsigned root_ndata_sent_to_all_proc =
24198  flat_unsigned_root_send_receive_data.size();
24199 
24200  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
24201  1,
24202  MPI_UNSIGNED,
24203  root_processor,
24204  comm_pt->mpi_comm());
24205 
24206  // Resize the container if this is a processor that receives data
24207  if (my_rank != root_processor)
24208  {
24209  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
24210  }
24211 
24212  // Send back the start boundaries ids for the shared boundaries
24213  // Scatter the info. from the "root_processor"
24214  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
24215  // each
24216  // processor
24217  root_ndata_sent_to_all_proc, // Total number of data to
24218  // send to each processor
24219  MPI_UNSIGNED,
24220  root_processor, // The processor that sends all the info.
24221  comm_pt->mpi_comm());
24222 
24223  // The container to store the initial shared boundaries ids between
24224  // each pair of processors
24225  Vector<Vector<unsigned>> initial_shared_bound_id_proc_with_proc(nproc);
24226 
24227  // All processors need to know how many shared boundaries there are
24228  // between each pair of processors
24229 
24230  // The number of shared boundaries between each pair of processors
24231  Vector<Vector<unsigned>> nshared_bound_proc_with_proc(nproc);
24232 
24233  unsigned iflat_counter = 0;
24234  // Fill the containers with the received info. from root processor
24235  for (unsigned iproc = 0; iproc < nproc; iproc++)
24236  {
24237  // Resize the containers
24238  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
24239  nshared_bound_proc_with_proc[iproc].resize(nproc);
24240 
24241  // Loop over the processors
24242  for (unsigned jproc = 0; jproc < nproc; jproc++)
24243  {
24244  // Get the initial shared boundary id between each pair of
24245  // processors (iproc, jproc)
24246  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
24247  flat_unsigned_root_send_receive_data[iflat_counter++];
24248 
24249  // .. and copy the number of shared boundaries that there are
24250  // between processor iproc and jproc
24251  nshared_bound_proc_with_proc[iproc][jproc] =
24252  flat_unsigned_root_send_receive_data[iflat_counter++];
24253 
24254  } // for (jproc < nproc)
24255 
24256  } // for (iproc < nproc)
24257 
24258  // Read the new initial shared boundary id
24259  new_initial_shared_boundary_id =
24260  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc - 2];
24261 
24262  // Read the new final shared boundary id
24263  new_final_shared_boundary_id =
24264  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc - 1];
24265 
24266  // The time to compute new shared boundaries ids
24267  if (Print_timings_level_load_balance > 2)
24268  {
24269  oomph_info
24270  << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24271  << TimingHelpers::timer() - tt_start_get_new_shared_boundaries_ids
24272  << std::endl;
24273  }
24274 
24275  // ==================================================================
24276  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24277  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24278  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24279  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24280  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24281  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24282  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24283  // ==================================================================
24284 
24285  // ==================================================================
24286  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24287  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24288  // SHARED BOUNDARIES INFO.
24289  // ==================================================================
24290 
24291  // Get the time to create new shared boundaries representations
24292  double tt_start_create_new_shared_boundaries_polylines = 0.0;
24293  if (Print_timings_level_load_balance > 2)
24294  {
24295  tt_start_create_new_shared_boundaries_polylines = TimingHelpers::timer();
24296  }
24297 
24298  // Create the shared boundaries and establish all the related info.
24299  // - Create Polylines
24300  // - Store shared boundary elements
24301  // - Fill data structures to know which shared boundaries belong to
24302  // which processor
24303 
24304  // Resize the shared polylines container
24305  this->flush_shared_boundary_polyline_pt();
24306  this->Shared_boundary_polyline_pt.resize(nproc);
24307 
24308  // Resize for the boundaries ids shared with all processors
24309  this->Shared_boundaries_ids.clear();
24310  this->Shared_boundaries_ids.resize(nproc);
24311  for (unsigned iproc = 0; iproc < nproc; iproc++)
24312  {
24313  this->Shared_boundaries_ids[iproc].clear();
24314  this->Shared_boundaries_ids[iproc].resize(nproc);
24315  } // for (iproc < nproc)
24316 
24317  // Clear data
24318  this->Shared_boundary_from_processors.clear();
24319  this->Shared_boundary_overlaps_internal_boundary.clear();
24320  this->Boundary_was_splitted.clear();
24321  this->Boundary_subpolylines.clear();
24322  this->Boundary_marked_as_shared_boundary.clear();
24323 
24324  // Flush data
24325  this->flush_shared_boundary_element();
24326  this->flush_face_index_at_shared_boundary();
24327  this->flush_shared_boundary_node();
24328  this->flush_sorted_shared_boundary_node();
24329 
24330  // Store the old local inital shared boundary id (used to map from
24331  // local shared boundary id to global shared boundary id)
24332  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24333 
24334  // Update the initial and final shared boundary id
24335  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24336  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24337 
24338  // Storage for the new created polylines between the current
24339  // processor (my_rank) and the other processors, unsorted polylines
24340  Vector<TriangleMeshPolyLine*> unsorted_polylines_pt;
24341 
24342  // Map to get the global shared boundary id from the local shared
24343  // boundary id. Note that this is only used to get the global shared
24344  // boundary id when the shared boundary that is being created has
24345  // connections
24346  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24347 
24348  // Each processor knows the boundaries ids for each of the shared
24349  // boundaries it has, establish that info. in the proper containers
24350  // Additionally, store the shared boundaries of ALL processors with
24351  // ALL processors, but only create the shared boundaries (and their
24352  // respective polylines) of the current processor (my_rank)
24353  for (unsigned iproc = 0; iproc < nproc; iproc++)
24354  {
24355  // Avoid creating double shared boundaries, the shared boundaries
24356  // created between processor "iproc" and processor "jproc" are the
24357  // same than those created between processor "jproc" and processor
24358  // "iproc"
24359  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24360  {
24361  // If we are working with the current processor (my_rank) then
24362  // create the shared boundaries, if that is not the case then
24363  // only fill the info. on the proper containers
24364  if (iproc == my_rank || jproc == my_rank)
24365  {
24366  // Check the condition that made it get here
24367  unsigned ref_proc = 0;
24368  if (iproc == my_rank)
24369  {
24370  ref_proc = jproc;
24371  }
24372  else if (jproc == my_rank)
24373  {
24374  ref_proc = iproc;
24375  }
24376 
24377  // Get the number of shared boundaries between processor iproc
24378  // and processor jproc
24379  const unsigned nshared_bound_iproc_jproc =
24380  nshared_bound_proc_with_proc[iproc][jproc];
24381 
24382  // Loop over the number of shared boundaries
24383  for (unsigned counter = 0; counter < nshared_bound_iproc_jproc;
24384  counter++)
24385  {
24386  // Compute the shared boundary id for the shared boundary
24387  const unsigned shd_bnd_id =
24388  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24389  // Set up the shared boundaries between "iproc" (my_rank)
24390  // and "jproc"
24391  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24392  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24393 
24394  // Specify the processors involved for the creation of the
24395  // shared boundary
24396  Vector<unsigned> processors(2);
24397  processors[0] = iproc;
24398  processors[1] = jproc;
24399  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24400 
24401  // Get the possible root edge id associated to the shared
24402  // boundary (useful when the shared boundary overlaps an
24403  // original boundary)
24404  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24405  // Check if the shared boundary is overlapping (or is part)
24406  // of an internal boundary
24407  if (root_edge_bound_id != -1)
24408  {
24409  // If the shared boundary is part of an internal boundary then
24410  // mark the shared boundary
24411  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24412  static_cast<unsigned>(root_edge_bound_id);
24413  } // if (root_edge_bound_id != -1)
24414 
24415  // Storing for the nodes of the polyline (these are different
24416  // from the nodes on the face elements -- it is actually a
24417  // sub-set -- since the polyline is created from the first and
24418  // last nodes on the face elements)
24419  Vector<Node*> node_pt_to_create_shared_polyline;
24420 
24421  // Add the first node for the very first face element. In
24422  // the loop we will only add the last node of the face
24423  // element
24424  FiniteElement* first_face_ele_pt =
24425  sorted_face_ele_pt[ref_proc][counter][0];
24426 
24427  // Get the number of nodes on the first face element
24428  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24429  if (!is_inverted[first_face_ele_pt])
24430  {
24431  // Get the first node
24432  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24433  // Add the node to create the polyline
24434  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24435  // Add the first node to the shared boundary
24436  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24437  }
24438  else
24439  {
24440  // Get the first node in the inverted face element
24441  Node* first_node_pt =
24442  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24443  // Add the node to create the polyline
24444  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24445  // Add the first node to the shared boundary
24446  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24447  }
24448 
24449  // ... and extract only the last nodes of the face elements
24450  // in the next loop and add them in the vector of nodes to
24451  // create polylines (node_pt_to_create_shared_polyline)
24452 
24453  // Get the number of elements
24454  const unsigned nshared_boundary_elements =
24455  sorted_face_ele_pt[ref_proc][counter].size();
24456 
24457  // Store the shared boundary elements, nodes and get the
24458  // sorted nodes to create the polyline
24459  for (unsigned ie = 0; ie < nshared_boundary_elements; ie++)
24460  {
24461  // Get the bulk element version of the face element
24462  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24463 
24464  // Add the shared boundary element and associate it to the
24465  // "shd_bnd_id"
24466  this->add_shared_boundary_element(shd_bnd_id, bulk_ele_pt);
24467 
24468  // Get the face index from which the face element was
24469  // created from the bulk element
24470  const int face_index =
24471  sorted_face_index_ele[ref_proc][counter][ie];
24472 
24473  // Add the face index to the face indexes of the shared
24474  // boundary
24475  this->add_face_index_at_shared_boundary(shd_bnd_id, face_index);
24476 
24477  // Get the face element to obtain the last node
24478  FiniteElement* face_ele_pt =
24479  sorted_face_ele_pt[ref_proc][counter][ie];
24480 
24481  // Get the number of nodes
24482  const unsigned nnodes = face_ele_pt->nnode();
24483  if (!is_inverted[face_ele_pt])
24484  {
24485  // We have already added the first node, then start from
24486  // the second one
24487  for (unsigned n = 1; n < nnodes; n++)
24488  {
24489  // Get the node to be added
24490  Node* node_pt = face_ele_pt->node_pt(n);
24491  // Add the node and associate it to the shared boundary
24492  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24493  } // for (n < nnodes)
24494 
24495  // Add the last node of the face element to the vector of
24496  // nodes to create the polyline
24497  // Get the last node
24498  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24499  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24500  } // if (!is_inverted[face_ele_pt])
24501  else
24502  {
24503  // We have already added the first node, then start from
24504  // the second one (in reverse order)
24505  for (int n = nnodes - 2; n >= 0; n--)
24506  {
24507  // Get the node to be added
24508  Node* node_pt = face_ele_pt->node_pt(n);
24509  // Add the node and associate it to the shared boundary
24510  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24511  } // for (n < nnodes)
24512 
24513  // Add the last node of the face element to the vector of
24514  // nodes to create the polyline
24515  // Get the last node
24516  Node* last_node_pt = face_ele_pt->node_pt(0);
24517  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24518 
24519  } // else if (!is_inverted[face_ele_pt])
24520 
24521  } // for (ie < nshared_boundary_elements)
24522 
24523  // The number of nodes for the shared boundary polyline
24524  const unsigned nnodes_to_create_shared_boundary =
24525  node_pt_to_create_shared_polyline.size();
24526 
24527  // Get the vertices that create the shared boundary polyline
24528  Vector<Vector<double>> vertices(nnodes_to_create_shared_boundary);
24529  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24530  {
24531  vertices[n].resize(2);
24532  // Get the node
24533  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24534  // Get the vertices
24535  vertices[n][0] = tmp_node_pt->x(0);
24536  vertices[n][1] = tmp_node_pt->x(1);
24537  } // for (n < nnodes_to_create_shared_boundary)
24538 
24539  // Create the polyline
24540  TriangleMeshPolyLine* polyline_pt =
24541  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24542 
24543  // Updates bnd_id<--->curve section map
24544  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24545 
24546  // Add the new created polyline to the list of unsorted
24547  // polylines
24548  unsorted_polylines_pt.push_back(polyline_pt);
24549 
24550  // Mark the polyline for deletion (when calling destructor)
24551  this->Free_curve_section_pt.insert(polyline_pt);
24552 
24553  // Now assign the connection information
24554  // ---------------------------------------------------------
24555  // Get the local shared boundary id associated to the
24556  // elements that gave rise to this shared boundary
24557  const unsigned local_shd_bnd_id =
24558  proc_local_shared_boundary_id[ref_proc][counter];
24559 
24560  // Associate the local shared boundary to the global shared
24561  // boundary
24562  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24563 
24564  // Get the correct shared boundaries ids, from the local
24565  // shared boundaries ids established at the identification
24566  // of the conections
24567 
24568  // Get the local bnd id for the connection to the left
24569  int tmp_bnd_id_connection_to_the_left =
24570  sorted_connection_info[ref_proc][counter][0];
24571  // Get the local bnd id for the connection to the right
24572  int tmp_bnd_id_connection_to_the_right =
24573  sorted_connection_info[ref_proc][counter][1];
24574 
24575  // The global shared boundaries ids for connections to the
24576  // left or right
24577  int bnd_id_connection_to_the_left = -1;
24578  int bnd_id_connection_to_the_right = -1;
24579 
24580  // To the left
24581  // --------------
24582 
24583  // If the connection is with the same shared boundary then
24584  // set the current boundary id
24585  if (tmp_bnd_id_connection_to_the_left == -2)
24586  {
24587  // Set the current shared boundary id
24588  bnd_id_connection_to_the_left = shd_bnd_id;
24589  } // if (tmp_bnd_id_connection_to_the_left == -2)
24590 
24591  // Check if the connection was a stop adding nodes condition
24592  if (tmp_bnd_id_connection_to_the_left == -3)
24593  {
24594  // Set as no connected
24595  bnd_id_connection_to_the_left = -1;
24596  } // if (tmp_bnd_id_connection_to_the_left == -3)
24597 
24598  // There is a connection with another boundary, check if it
24599  // is a shared boundary or an original boundary
24600  if (tmp_bnd_id_connection_to_the_left >=
24601  static_cast<int>(old_local_shd_bnd_id))
24602  {
24603  // The connection is with a shared boundary, get the
24604  // global shared boundary id and set the connection
24605 #ifdef PARANOID
24606  std::map<unsigned, unsigned>::iterator it =
24607  local_to_global_shd_bnd_id.find(
24608  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24609  // If the global shared boundary id was not found we
24610  // are in trouble
24611  if (it == local_to_global_shd_bnd_id.end())
24612  {
24613  std::stringstream error_message;
24614  error_message
24615  << "The global shared boundary id was not found for\n"
24616  << "the local shared boundary shared with processor ("
24617  << ref_proc << ").\n"
24618  << "This processor: (" << my_rank << ")\n"
24619  << "Boundary shared with processor: (" << ref_proc << ")\n"
24620  << "Local shared boundary: ("
24621  << tmp_bnd_id_connection_to_the_left << ")\n";
24622  throw OomphLibError(error_message.str(),
24623  OOMPH_CURRENT_FUNCTION,
24624  OOMPH_EXCEPTION_LOCATION);
24625  } // if (it==local_to_global_shd_bnd_id.end())
24626 #endif
24627 
24628  // Get the global shared boundary id
24629  bnd_id_connection_to_the_left =
24630  local_to_global_shd_bnd_id[static_cast<unsigned>(
24631  tmp_bnd_id_connection_to_the_left)];
24632  }
24633  else
24634  {
24635  // The connection is with an original boundary, copy
24636  // the boundary id
24637  bnd_id_connection_to_the_left = tmp_bnd_id_connection_to_the_left;
24638 
24639  } // else (connection with a shared boundary)
24640 
24641  // To the right
24642  // --------------
24643 
24644  // If the connection is with the same shared boundary then
24645  // set the current boundary id
24646  if (tmp_bnd_id_connection_to_the_right == -2)
24647  {
24648  // Set the current shared boundary id
24649  bnd_id_connection_to_the_right = shd_bnd_id;
24650  } // if (tmp_bnd_id_connection_to_the_right == -2)
24651 
24652  // Check if the connection was a stop adding nodes condition
24653  if (tmp_bnd_id_connection_to_the_right == -3)
24654  {
24655  // Set as no connected
24656  bnd_id_connection_to_the_right = -1;
24657  } // if (tmp_bnd_id_connection_to_the_right == -3)
24658 
24659  // There is a connection with another boundary, check if it
24660  // is a shared boundary or an original boundary
24661  if (tmp_bnd_id_connection_to_the_right >=
24662  static_cast<int>(old_local_shd_bnd_id))
24663  {
24664  // The connection is with a shared boundary, get the
24665  // global shared boundary id and set the connection
24666 #ifdef PARANOID
24667  std::map<unsigned, unsigned>::iterator it =
24668  local_to_global_shd_bnd_id.find(
24669  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24670  // If the global shared boundary id was not found we
24671  // are in trouble
24672  if (it == local_to_global_shd_bnd_id.end())
24673  {
24674  std::stringstream error_message;
24675  error_message
24676  << "The global shared boundary id was not found for\n"
24677  << "the local shared boundary shared with processor ("
24678  << ref_proc << ").\n"
24679  << "This processor: (" << my_rank << ")\n"
24680  << "Boundary shared with processor: (" << ref_proc << ")\n"
24681  << "Local shared boundary: ("
24682  << tmp_bnd_id_connection_to_the_right << ")\n";
24683  throw OomphLibError(error_message.str(),
24684  OOMPH_CURRENT_FUNCTION,
24685  OOMPH_EXCEPTION_LOCATION);
24686  } // if (it==local_to_global_shd_bnd_id.end())
24687 #endif
24688  // Get the global shared boundary id
24689  bnd_id_connection_to_the_right =
24690  local_to_global_shd_bnd_id[static_cast<unsigned>(
24691  tmp_bnd_id_connection_to_the_right)];
24692  }
24693  else
24694  {
24695  // The connection is with an original boundary, copy the
24696  // boundary id
24697  bnd_id_connection_to_the_right =
24698  tmp_bnd_id_connection_to_the_right;
24699 
24700  } // else (connection with a shared boundary)
24701 
24702  // --------------------------------
24703  // Set the connection to the left
24704  if (bnd_id_connection_to_the_left != -1)
24705  {
24706  // Get the unsigned version of the boundary id to the left
24707  const unsigned ubnd_id_connection_to_the_left =
24708  static_cast<unsigned>(bnd_id_connection_to_the_left);
24709  // Set the initial vertex as connected
24710  polyline_pt->set_initial_vertex_connected();
24711  // Set the initial vertex connected boundary id
24712  polyline_pt->initial_vertex_connected_bnd_id() =
24713  ubnd_id_connection_to_the_left;
24714  // Set the chunk number to zero
24715  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24716 
24717  } // if (bnd_id_connection_to_the_left != -1)
24718 
24719  // ---------------------------------
24720  // Set the connection to the right
24721  if (bnd_id_connection_to_the_right != -1)
24722  {
24723  // Get the unsigned version of the boundary id to the
24724  // right
24725  const unsigned ubnd_id_connection_to_the_right =
24726  static_cast<unsigned>(bnd_id_connection_to_the_right);
24727  // Set the final vertex as connected
24728  polyline_pt->set_final_vertex_connected();
24729  // Set the final vertex connected boundary id
24730  polyline_pt->final_vertex_connected_bnd_id() =
24731  ubnd_id_connection_to_the_right;
24732  // Set the chunk number to zero
24733  polyline_pt->final_vertex_connected_n_chunk() = 0;
24734 
24735  } // if (bnd_id_connection_to_the_right != -1)
24736 
24737  } // for (counter < nshared_bound_iproc_jproc)
24738 
24739  } // if (iproc == my_rank || jproc == my_rank)
24740  else
24741  {
24742  // We are not working with the current processor, then we only
24743  // need to fill the containers
24744 
24745  // Get the number of shared boundaries between processor iproc
24746  // and processor jproc
24747  const unsigned nshared_bound_iproc_jproc =
24748  nshared_bound_proc_with_proc[iproc][jproc];
24749  // Loop over the number of shared boundaries
24750  for (unsigned counter = 0; counter < nshared_bound_iproc_jproc;
24751  counter++)
24752  {
24753  // Compute the shared boundary id for the shared boundary
24754  const unsigned shd_bnd_id =
24755  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24756 
24757  // Set up the shared boundaries between "iproc" and "jproc"
24758  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24759  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24760 
24761  // Specify the processors involved for the creation of the
24762  // shared boundary
24763  Vector<unsigned> processors(2);
24764  processors[0] = iproc;
24765  processors[1] = jproc;
24766  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24767 
24768  } // for (counter < nshared_bound_iproc_jproc)
24769 
24770  } // else if (iproc == my_rank || jproc == my_rank)
24771 
24772  } // for (jproc < nproc)
24773 
24774  } // for (iproc < nproc)
24775 
24776  // Get the time to create new shared boundaries representations
24777  if (Print_timings_level_load_balance > 2)
24778  {
24779  oomph_info << "CPU for creating new shared boundaries representations "
24780  "(load balance) [9.7]: "
24781  << TimingHelpers::timer() -
24782  tt_start_create_new_shared_boundaries_polylines
24783  << std::endl;
24784  }
24785 
24786  // ==================================================================
24787  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24788  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24789  // SHARED BOUNDARIES INFO.
24790  // ==================================================================
24791 
24792  // ==================================================================
24793  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24794  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24795  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24796  // ELEMENTS
24797  // ==================================================================
24798 
24799  // Get the time to create the new shared curves
24800  double tt_start_create_new_shared_curves = 0.0;
24801  if (Print_timings_level_load_balance > 2)
24802  {
24803  tt_start_create_new_shared_curves = TimingHelpers::timer();
24804  }
24805 
24806  // Sort the polylines and find if they create a contiguous open
24807  // curve
24808  if (unsorted_polylines_pt.size() > 0)
24809  {
24810  // Now that we have all the new unsorted polylines on "my_rank"x
24811  // processor it is time to sort them so they be all contiguous
24812  this->sort_polylines_helper(unsorted_polylines_pt,
24813  this->Shared_boundary_polyline_pt[my_rank]);
24814  }
24815 
24816  // Free the memory allocated for the face elements
24817  for (unsigned iproc = 0; iproc < nproc; iproc++)
24818  {
24819  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24820  for (unsigned e = 0; e < nface_ele; e++)
24821  {
24822  delete unsorted_face_ele_pt[iproc][e];
24823  unsorted_face_ele_pt[iproc][e] = 0;
24824  } // for (e < nface_ele)
24825 
24826  } // for (iproc < nproc)
24827 
24828  // The time to create the new shared curves
24829  if (Print_timings_level_load_balance > 2)
24830  {
24831  oomph_info
24832  << "CPU for creating the new shared curves (load balance) [9.8]: "
24833  << TimingHelpers::timer() - tt_start_create_new_shared_curves
24834  << std::endl;
24835  }
24836 
24837  // ==================================================================
24838  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24839  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24840  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24841  // ELEMENTS
24842  // ==================================================================
24843  }
24844 
24845  //======================================================================
24846  // Computes the degree of the nodes on the shared boundaries, the
24847  // degree of the node is computed from the global graph created by the
24848  // shared boundaries of all processors
24849  //======================================================================
24850  template<class ELEMENT>
24852  Vector<Vector<FiniteElement*>>& unsorted_face_ele_pt,
24853  std::map<Node*, unsigned>& global_node_degree)
24854  {
24855  // Get the rank and number of processors
24856  const unsigned nproc = this->communicator_pt()->nproc();
24857  const unsigned my_rank = this->communicator_pt()->my_rank();
24858 
24859  // Store a temporary sorting of the nodes, starting from the
24860  // lower-left position
24861  Vector<Vector<Node*>> tmp_sorted_shared_node_pt(nproc);
24862 
24863  // Store the alias of the node, it may be shared by more than two
24864  // processors, they should know that the node is the same
24865  // [0] iproc, processor with which the current processor shared the node
24866  // [1] node #, number of node in the number of nodes shared with iproc
24867  // processor
24868  std::map<Node*, Vector<Vector<unsigned>>> node_alias;
24869 
24870  // Stores the local adjacency matrix
24871  // (nproc*n_shared_nodes*n_shared_nodes)
24872  Vector<Vector<Vector<unsigned>>> local_adjacency_matrix(nproc);
24873 
24874  // Sort the nodes and create the adjacency matrix of each sub-graph
24875  // created by the shared edges
24876  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24877  tmp_sorted_shared_node_pt,
24878  node_alias,
24879  local_adjacency_matrix);
24880 
24881  // Prepare the info. to be sent to the root processor, which will be
24882  // in charge of updating the nodes degree by combining the info. of
24883  // all the processors
24884 
24885  // The flat package with the info. to send to root
24886  Vector<unsigned> package_unsigned_send_data_to_root;
24887 
24888  // Encode the info. that will be sent to the root processor
24889 
24890  // Loop over the temporary sorted nodes between each pair of
24891  // processors
24892  for (unsigned iproc = 0; iproc < nproc; iproc++)
24893  {
24894  // Send the processor index
24895  package_unsigned_send_data_to_root.push_back(iproc);
24896 
24897  // Get the number of nodes shared between the processors
24898  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24899 
24900  // Send the number of nodes shared with the iproc processor
24901  package_unsigned_send_data_to_root.push_back(n_nodes);
24902 
24903  // Loop over the nodes
24904  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24905  {
24906  // Get the node
24907  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24908 
24909  // Get the alias info.
24910  Vector<Vector<unsigned>> alias_node_info = node_alias[shd_node_pt];
24911 
24912  // Get the number of alias for the node
24913  const unsigned n_alias = alias_node_info.size();
24914 
24915  // Send the number of alias assigned to the node
24916  package_unsigned_send_data_to_root.push_back(n_alias);
24917 
24918  // Loop over the alias to include them in the package
24919  for (unsigned i = 0; i < n_alias; i++)
24920  {
24921  // Send the alias info.
24922  // The current processor
24923  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24924  // The prociesso with which is shared
24925  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24926  // The index of the node
24927  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24928  } // for (i < n_alias)
24929 
24930  } // for (ishd < n_nodes)
24931 
24932  // Now send the adjacency matrix
24933  for (unsigned i = 0; i < n_nodes; i++)
24934  {
24935  for (unsigned j = 0; j < n_nodes; j++)
24936  {
24937  // Package the adjacency matrix
24938  package_unsigned_send_data_to_root.push_back(
24939  local_adjacency_matrix[iproc][i][j]);
24940 
24941  } // for (j < n_nodes)
24942 
24943  } // for (i < n_nodes)
24944 
24945  } // for (iproc < nproc)
24946 
24947  // Define the root processor
24948  const unsigned root_processor = 0;
24949 
24950  // Get the communicator of the mesh
24951  OomphCommunicator* comm_pt = this->communicator_pt();
24952 
24953  // Number of data send. from this processor to root processor
24954  unsigned n_unsigned_data_send_to_root =
24955  package_unsigned_send_data_to_root.size();
24956 
24957  // Store the number of data to receive from each processor in root
24958  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24959 
24960  // Send the number of data that each processor will send to root
24961  // Gather the info. in the "root_processor"
24962  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24963  // each processor
24964  1, // Total number of data to send from each processor
24965  MPI_UNSIGNED,
24966  &n_unsigned_data_received_in_root[0], // Container where
24967  // to receive the
24968  // info. from all
24969  // the processors
24970  1, // Number of data to receive from each processor
24971  MPI_UNSIGNED,
24972  root_processor, // The processor that receives all the
24973  // info.
24974  comm_pt->mpi_comm());
24975 
24976  // Compute the total number of data to receive from all processors
24977  unsigned n_unsigned_total_data_receive_in_root = 0;
24978  for (unsigned iproc = 0; iproc < nproc; iproc++)
24979  {
24980  // Add the number of data to receive from each processor
24981  n_unsigned_total_data_receive_in_root +=
24982  n_unsigned_data_received_in_root[iproc];
24983  }
24984 
24985  // Compute the offsets from each processor
24986  Vector<int> root_unsigned_offsets_receive(nproc, 0);
24987  root_unsigned_offsets_receive[0] = 0;
24988  for (unsigned iproc = 1; iproc < nproc; iproc++)
24989  {
24990  // Compute the offset to store the values received from each
24991  // processor
24992  root_unsigned_offsets_receive[iproc] =
24993  root_unsigned_offsets_receive[iproc - 1] +
24994  n_unsigned_data_received_in_root[iproc - 1];
24995  }
24996 
24997  // Create at least one entry so we don't get a seg fault below
24998  if (package_unsigned_send_data_to_root.size() == 0)
24999  {
25000  package_unsigned_send_data_to_root.resize(1);
25001  }
25002 
25003  // Vector where to receive the data sent from each processor
25004  Vector<unsigned> package_unsigned_data_received_root(
25005  n_unsigned_total_data_receive_in_root);
25006  if (my_rank != root_processor)
25007  {
25008  // Create at least one entry so we don't get a seg fault below
25009  if (package_unsigned_data_received_root.size() == 0)
25010  {
25011  package_unsigned_data_received_root.resize(1);
25012  }
25013  } // if (my_rank!=root_processor)
25014 
25015  // Gather the info. from all processors
25016  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
25017  // to send
25018  // info. from
25019  // each
25020  // processor
25021  n_unsigned_data_send_to_root, // Total number of data to
25022  // send from each
25023  // processor
25024  MPI_UNSIGNED,
25025  &package_unsigned_data_received_root[0], // Container
25026  // where to
25027  // receive the
25028  // info. from
25029  // all the
25030  // processors
25031  &n_unsigned_data_received_in_root[0], // Number of data
25032  // to receive from
25033  // each processor
25034  &root_unsigned_offsets_receive[0], // The offset to
25035  // store the
25036  // info. from each
25037  // processor
25038  MPI_UNSIGNED,
25039  root_processor, // The processor that receives all the
25040  // info.
25041  comm_pt->mpi_comm());
25042 
25043  // Store the info. to be sent by root to other processors
25044  Vector<unsigned> package_unsigned_data_sent_from_root;
25045  // Total data sent to each processor from root
25046  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
25047 
25048  // The root processor now has all the info. regarding the shared
25049  // nodes and the adjacency matrix of each pair of processors
25050  if (my_rank == root_processor)
25051  {
25052  // Decode the info. received from all processors
25053  // Counter to decode the info.
25054  unsigned decode_counter = 0;
25055 
25056  // Store the local alias of the nodes in each processor
25057  // [x][][][][] iproc
25058  // [][x][][][] jproc
25059  // [][][x][][] inode
25060  // [][][][x][] ialias
25061  // [][][][][x] alias_data
25062  Vector<Vector<Vector<Vector<Vector<unsigned>>>>> local_node_alias(nproc);
25063  // Store the local adjacency matrix of each processor
25064  Vector<Vector<Vector<Vector<unsigned>>>> local_adjacency_matrix(nproc);
25065 
25066  // Loop over all the processors
25067  for (unsigned iproc = 0; iproc < nproc; iproc++)
25068  {
25069  local_node_alias[iproc].resize(nproc);
25070 
25071  // Resize the local adjacency matrix to store the info. sent
25072  // from all processors
25073  local_adjacency_matrix[iproc].resize(nproc);
25074 
25075  if (n_unsigned_data_received_in_root[iproc] > 0)
25076  {
25077  // Loop over all the processors to decode the info. received
25078  // from each one
25079  for (unsigned jproc = 0; jproc < nproc; jproc++)
25080  {
25081  // Read the processor number to which the info. correspond
25082  const unsigned read_jproc =
25083  package_unsigned_data_received_root[decode_counter++];
25084 
25085  // The read processor must be the same as the jproc, if that
25086  // is not the case then there is a synchronisation issue
25087  if (read_jproc != jproc)
25088  {
25089  std::ostringstream error_stream;
25090  error_stream
25091  << "The read processor is different from the jproc, this is\n"
25092  << "a synchronisation issue. The data are not read in the\n"
25093  << "sameorder as the were packaged\n"
25094  << "Read processor: (" << read_jproc << ")\n"
25095  << "Current jproc: (" << jproc << ")\n\n";
25096  throw OomphLibError(
25097  error_stream.str(),
25098  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25099  OOMPH_EXCEPTION_LOCATION);
25100  }
25101 
25102  // Read the number of nodes in the shared boundaries between
25103  // iproc and jproc
25104  const unsigned read_n_shd_nodes_iproc_jproc =
25105  package_unsigned_data_received_root[decode_counter++];
25106 
25107  // Resize the container
25108  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
25109 
25110  // Loop over the number of nodes shared between iproc and
25111  // jproc
25112  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
25113  {
25114  // Read the number of alias of the current ishd node
25115  const unsigned read_n_alias_node_iproc_jproc =
25116  package_unsigned_data_received_root[decode_counter++];
25117 
25118  // Resize the container
25119  local_node_alias[iproc][jproc][ishd].resize(
25120  read_n_alias_node_iproc_jproc);
25121 
25122  for (unsigned ialias = 0; ialias < read_n_alias_node_iproc_jproc;
25123  ialias++)
25124  {
25125  // Resize the container, we know there are three data to
25126  // define the alias of a node
25127  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
25128 
25129  // The 1st processor with which is shared
25130  local_node_alias[iproc][jproc][ishd][ialias][0] =
25131  package_unsigned_data_received_root[decode_counter++];
25132 
25133  // The 2nd processor with which is shared
25134  local_node_alias[iproc][jproc][ishd][ialias][1] =
25135  package_unsigned_data_received_root[decode_counter++];
25136 
25137  // The index of the node in the interaction iproc-jproc
25138  local_node_alias[iproc][jproc][ishd][ialias][2] =
25139  package_unsigned_data_received_root[decode_counter++];
25140 
25141  } // for (ialias < read_n_alias_node_iproc_jproc)
25142 
25143  } // for (ishd < read_n_shd_nodes_iproc_jproc)
25144 
25145  // Resize the local adjacency matrix
25146  local_adjacency_matrix[iproc][jproc].resize(
25147  read_n_shd_nodes_iproc_jproc);
25148  // Read the adjacency matrix sent to root processor
25149  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
25150  {
25151  // Resize the local adjacency matrix
25152  local_adjacency_matrix[iproc][jproc][i].resize(
25153  read_n_shd_nodes_iproc_jproc);
25154  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
25155  {
25156  // Read the adjacency matrix entry
25157  local_adjacency_matrix[iproc][jproc][i][j] =
25158  package_unsigned_data_received_root[decode_counter++];
25159  } // for (j < read_n_shd_nodes_iproc_jproc)
25160 
25161  } // for (i < read_n_shd_nodes_iproc_jproc)
25162 
25163  } // for (jproc < nproc)
25164 
25165  } // for (iproc < nproc)
25166 
25167  } // for (iproc < nproc)
25168 
25169 #ifdef PARANOID
25170  if (decode_counter != n_unsigned_total_data_receive_in_root)
25171  {
25172  std::ostringstream error_stream;
25173  error_stream
25174  << "The number of data decoded in root received from others\n"
25175  << "processors is different from the total number of data received\n"
25176  << "Data decoded: (" << decode_counter << ")\n"
25177  << "Data received: (" << n_unsigned_total_data_receive_in_root
25178  << ")\n\n"
25179  << "This is a synchronisation issue so you are probably sending\n"
25180  << "more or less info. than the one that is being decoded\n\n";
25181  throw OomphLibError(
25182  error_stream.str(),
25183  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25184  OOMPH_EXCEPTION_LOCATION);
25185  }
25186 #endif
25187 
25188  // Assign a unique id to the nodes (uses the alias information to
25189  // identify the repetition of a node in other processors). The
25190  // global node id is given by the position (index) in the global
25191  // node alias
25192 
25193  // Keep track of those alias already assigned a unique id
25194  std::map<Vector<unsigned>, bool> alias_done;
25195 
25196  // Store all the alias associated to each node
25197  Vector<Vector<Vector<unsigned>>> global_node_alias;
25198 
25199  // Loop over all the processors
25200  for (unsigned iproc = 0; iproc < nproc; iproc++)
25201  {
25202  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25203  {
25204  // Read the number of nodes shared between the processors
25205  const unsigned n_shd_nodes_iproc_jproc =
25206  local_node_alias[iproc][jproc].size();
25207 #ifdef PARANOID
25208  // Read the number of nodes shared in the other direction
25209  const unsigned n_shd_nodes_jproc_iproc =
25210  local_node_alias[jproc][iproc].size();
25211 
25212  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
25213  {
25214  std::ostringstream error_stream;
25215  error_stream
25216  << "The number of nodes shared between iproc and jproc is\n"
25217  << "different from the number of nodes shared between jproc\n"
25218  << "and iproc\n"
25219  << "Nodes shared between processor (" << iproc << ") and "
25220  << "processor (" << jproc << "): (" << n_shd_nodes_iproc_jproc
25221  << ")\n"
25222  << "Nodes shared between processor (" << jproc << ") and "
25223  << "processor (" << iproc << "): (" << n_shd_nodes_jproc_iproc
25224  << ")\n\n";
25225  throw OomphLibError(
25226  error_stream.str(),
25227  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25228  OOMPH_EXCEPTION_LOCATION);
25229  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
25230 #endif
25231 
25232  // Loop over the nodes shared between the processors
25233  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
25234  {
25235  // Get the number of alias associated to the node on each
25236  // processor
25237  const unsigned n_alias_iproc_jproc =
25238  local_node_alias[iproc][jproc][ishd].size();
25239  const unsigned n_alias_jproc_iproc =
25240  local_node_alias[jproc][iproc][ishd].size();
25241 
25242  // Store all the found alias to the node
25243  Vector<Vector<unsigned>> node_alias;
25244 
25245  // Flag to indicate if a new alias has been added
25246  bool new_alias_added = false;
25247 
25248  // Start by adding the "direct" alias of the node
25249  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
25250  {
25251  // Get the alias of the node
25252  Vector<unsigned> current_alias =
25253  local_node_alias[iproc][jproc][ishd][ialias];
25254  // Check if already done
25255  if (!alias_done[current_alias])
25256  {
25257  // Add the alias of the node
25258  node_alias.push_back(current_alias);
25259  // Set the flag to indicate a new alias has been added
25260  new_alias_added = true;
25261  // Mark the alias as done
25262  alias_done[current_alias] = true;
25263  } // if (!alias_done[i_alias])
25264 
25265  } // for (ialias < n_alias_iproc_jproc)
25266 
25267  // Start by adding the "direct" alias of the node
25268  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25269  {
25270  // Get the alias of the node
25271  Vector<unsigned> current_alias =
25272  local_node_alias[jproc][iproc][ishd][ialias];
25273 
25274  // Check if already done
25275  if (!alias_done[current_alias])
25276  {
25277  // Add the alias of the node
25278  node_alias.push_back(current_alias);
25279  // Set the flag to indicate a new alias has been added
25280  new_alias_added = true;
25281  // Mark the alias as done
25282  alias_done[current_alias] = true;
25283  } // if (!alias_done[i_alias])
25284 
25285  } // for (ialias < n_alias_jproc_iproc)
25286 
25287  unsigned counter_alias = 0;
25288  // Visit the alias of the node and add any new found
25289  // alias, end until all its alias have been included
25290 
25291  unsigned n_current_alias = node_alias.size();
25292  while (new_alias_added || counter_alias < n_current_alias)
25293  // while(new_alias_added) // we need to check all the alias,
25294  // including those added during the process
25295  {
25296  new_alias_added = false;
25297  // Store the current visited alias
25298  Vector<unsigned> current_alias = node_alias[counter_alias];
25299 
25300  // Get the alias associated with the current alias
25301  Vector<Vector<unsigned>> alias_of_current_alias =
25302  local_node_alias[current_alias[0]][current_alias[1]]
25303  [current_alias[2]];
25304 
25305  // Get all the alias associated with the alias of the
25306  // current alias
25307  const unsigned n_alias = alias_of_current_alias.size();
25308 
25309  // Loop over the new alias and check if require to add
25310  // them
25311  for (unsigned k = 0; k < n_alias; k++)
25312  {
25313  // Get the alias of the node
25314  Vector<unsigned> add_alias = alias_of_current_alias[k];
25315 
25316  // Check if already done
25317  if (!alias_done[add_alias])
25318  {
25319  // Add the alias of the node
25320  node_alias.push_back(add_alias);
25321  // Set the flag to indicate a new alias has been
25322  // added
25323  new_alias_added = true;
25324  // Mark the alias ad done
25325  alias_done[add_alias] = true;
25326  } // if (!alias_done[i_alias])
25327 
25328  } // for (k < n_alias)
25329 
25330  // Get the alias associated with the current alias (in the
25331  // other direction)
25332  Vector<Vector<unsigned>> alias_of_current_alias2 =
25333  local_node_alias[current_alias[1]][current_alias[0]]
25334  [current_alias[2]];
25335 
25336  // Get all the alias associated with the current alias
25337  // (in the other direction)
25338  const unsigned n_alias2 = alias_of_current_alias2.size();
25339 
25340  // Loop over the new alias and check if require to add
25341  // them
25342  for (unsigned k = 0; k < n_alias2; k++)
25343  {
25344  // Get the alias of the node
25345  Vector<unsigned> add_alias = alias_of_current_alias2[k];
25346 
25347  // Check if already done
25348  if (!alias_done[add_alias])
25349  {
25350  // Add the alias of the node
25351  node_alias.push_back(add_alias);
25352  // Set the flag to indicate a new alias has been
25353  // added
25354  new_alias_added = true;
25355  // Mark the alias ad done
25356  alias_done[add_alias] = true;
25357  } // if (!alias_done[i_alias])
25358 
25359  } // for (k < n_alias)
25360 
25361  // Go for the next alias
25362  counter_alias++;
25363 
25364  // Update the number of alias so that the while stops when
25365  // all the alias have been visited and no new alias was
25366  // added
25367  n_current_alias = node_alias.size();
25368 
25369  } // while(new_alias_added || counter_alias < n_current_alias)
25370 
25371  // If the node has not been previously added, then include
25372  // all its alias
25373  if (node_alias.size() > 0)
25374  {
25375  // Add all the found alias of the node to the global alias
25376  // storage
25377  global_node_alias.push_back(node_alias);
25378  }
25379 
25380  } // for (ishd < n_shd_nodes_iproc_jproc)
25381 
25382  } // for (jproc < nproc)
25383 
25384  } // for (iproc < nproc)
25385 
25386  // We now have the global number of nodes, each with its own id
25387  // (the index in the global_node_alias vector)
25388 
25389  // Get the number of global shared nodes
25390  const unsigned n_global_shared_nodes = global_node_alias.size();
25391 
25392  // Create matrix from local to global shared node id
25393  Vector<Vector<Vector<int>>> local_to_global_shared_node(nproc);
25394 
25395  // Loop over all the processors to resize
25396  for (unsigned iproc = 0; iproc < nproc; iproc++)
25397  {
25398  // Resize the map matrix
25399  local_to_global_shared_node[iproc].resize(nproc);
25400  } // for (iproc < nproc)
25401 
25402  // Loop over all the processors to resize (the third direction,
25403  // required if we want to loop over the half of the matrix only)
25404  for (unsigned iproc = 0; iproc < nproc; iproc++)
25405  {
25406  // Loop over the half of the matrix to resize
25407  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25408  {
25409  // Read the number of nodes shared between the processors
25410  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25411 
25412  // Resize the map matrix
25413  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes, -1);
25414 
25415  // ... and resize the other half map matrix
25416  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes, -1);
25417 
25418  } // for (jproc < nproc)
25419 
25420  } // for (iproc < nproc)
25421 
25422  // Fill the matrix for mapping from local to global node id
25423 
25424  // Loop over the global nodes, and for each alias assign the
25425  // corresponding global node id
25426  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25427  {
25428  // Get the number of alias associated to the current global node
25429  const unsigned n_alias_global_node = global_node_alias[k].size();
25430  // Loop over the alias and assign the global node id
25431  for (unsigned l = 0; l < n_alias_global_node; l++)
25432  {
25433  // Get the 1st processor
25434  const unsigned iproc = global_node_alias[k][l][0];
25435  // Get the 2nd processor
25436  const unsigned jproc = global_node_alias[k][l][1];
25437  // Get the node number
25438  const unsigned ishd = global_node_alias[k][l][2];
25439  // Assign the global node id
25440  local_to_global_shared_node[iproc][jproc][ishd] = k;
25441 
25442  } // for (l < n_alias_global_node)
25443 
25444  } // for (k < n_global_shared_nodes)
25445 
25446  // Create the global adjacency matrix
25447  Vector<Vector<unsigned>> global_adjacency_matrix(n_global_shared_nodes);
25448  // Resize the global adjacency matrix
25449  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25450  {
25451  // Resize
25452  global_adjacency_matrix[k].resize(n_global_shared_nodes, 0);
25453  } // for (k < n_global_shared_nodes)
25454 
25455  // Add the entries to the global adjacency matrix and compute the
25456  // degree of each node
25457 
25458  // Store the degree of the global nodes
25459  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25460 
25461  // Loop over the processors
25462  for (unsigned iproc = 0; iproc < nproc; iproc++)
25463  {
25464  // Loop over the half of the matrix to resize
25465  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25466  {
25467  // Get the number of nodes shared between the processors
25468  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25469 
25470  // Search for entries in the local adjacency matrix that set a
25471  // connection among the nodes
25472 
25473  // Loop over the shared nodes in the current pair of
25474  // processors
25475  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25476  {
25477  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25478  {
25479  // Are the nodes associated
25480  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25481  {
25482  // Get the global nodes id
25483 
25484  // Get the "left-node" global id
25485  const int global_shd_node_left =
25486  local_to_global_shared_node[iproc][jproc][ishd];
25487 
25488  // Get the "right-node" global id
25489  const int global_shd_node_right =
25490  local_to_global_shared_node[iproc][jproc][jshd];
25491 
25492 #ifdef PARANOID
25493  // Check if the local nodes have a global node
25494  // associated
25495  if (global_shd_node_left == -1)
25496  {
25497  std::ostringstream error_stream;
25498  error_stream
25499  << "The local node in processors iproc and jproc has no\n"
25500  << "global node assigned\n"
25501  << "iproc processor: (" << iproc << ")\n"
25502  << "jproc processor: (" << jproc << ")\n"
25503  << "Local node: (" << ishd << ")\n\n";
25504  throw OomphLibError(error_stream.str(),
25505  "RefineableTriangleMesh::compute_shared_"
25506  "node_degree_helper()",
25507  OOMPH_EXCEPTION_LOCATION);
25508  }
25509 
25510  // Check if the local nodes have a global node
25511  // associated
25512  if (global_shd_node_right == -1)
25513  {
25514  std::ostringstream error_stream;
25515  error_stream
25516  << "The local node in processors iproc and jproc has no\n"
25517  << "global node assigned\n"
25518  << "iproc processor: (" << iproc << ")\n"
25519  << "jproc processor: (" << jproc << ")\n"
25520  << "Local node: (" << jshd << ")\n\n";
25521  throw OomphLibError(error_stream.str(),
25522  "RefineableTriangleMesh::compute_shared_"
25523  "node_degree_helper()",
25524  OOMPH_EXCEPTION_LOCATION);
25525  }
25526 #endif
25527  // Get the unsigned version of the indexes
25528  const unsigned uleft =
25529  static_cast<unsigned>(global_shd_node_left);
25530  const unsigned uright =
25531  static_cast<unsigned>(global_shd_node_right);
25532 
25533  // Add the entry in the global adjacency matrix
25534  global_adjacency_matrix[uleft][uright]++;
25535 
25536  // ... and in the other direction too
25537  global_adjacency_matrix[uright][uleft]++;
25538 
25539  // Add on to the degree of the left node
25540  global_node_degree[uleft]++;
25541 
25542  // Add on to the degree of the right node
25543  global_node_degree[uright]++;
25544 
25545  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25546 
25547  } // // for (jshd < n_shd_nodes)
25548 
25549  } // for (ishd < n_shd_nodes)
25550 
25551  } // for (jproc < nproc)
25552 
25553  } // for (iproc < nproc)
25554 
25555  // Assign the global degree to the shared nodes between each pair
25556  // of processors
25557  Vector<Vector<Vector<unsigned>>> root_local_node_degree(nproc);
25558  // Resize the container
25559  for (unsigned iproc = 0; iproc < nproc; iproc++)
25560  {
25561  root_local_node_degree[iproc].resize(nproc);
25562  }
25563 
25564  // Loop over the processors and visited their shared nodes
25565  for (unsigned iproc = 0; iproc < nproc; iproc++)
25566  {
25567  // Only visit the half of the data
25568  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25569  {
25570  // Get the number of shared nodes between this pair of
25571  // processors (iproc, jproc)
25572  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25573 
25574  // Resize the container to store the local degree of the nodes
25575  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25576  // ... and in the other way too
25577  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25578 
25579  // Loop over the number of nodes shared between the pair of
25580  // processors
25581  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25582  {
25583  // Get the global node id for the current shared node
25584  const int global_shd_node_id =
25585  local_to_global_shared_node[iproc][jproc][ishd];
25586 
25587 #ifdef PARANOID
25588  // Check if the local nodes have a global node associated
25589  if (global_shd_node_id == -1)
25590  {
25591  std::ostringstream error_stream;
25592  error_stream
25593  << "The local node in processors iproc and jproc has no\n"
25594  << "global node assigned\n"
25595  << "iproc processor: (" << iproc << ")\n"
25596  << "jproc processor: (" << jproc << ")\n"
25597  << "Local node: (" << ishd << ")\n\n";
25598  throw OomphLibError(
25599  error_stream.str(),
25600  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25601  OOMPH_EXCEPTION_LOCATION);
25602  }
25603 #endif
25604 
25605  // Get the unsigned version of the global index
25606  const unsigned uglobal_shd_node_id =
25607  static_cast<unsigned>(global_shd_node_id);
25608 
25609  // Get the degree of the node
25610  const unsigned node_degree =
25611  global_node_degree[uglobal_shd_node_id];
25612 
25613  // Set the degree in the container for the degree of the
25614  // nodes in the local interaction between processors
25615  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25616  // ... and in the other way too
25617  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25618 
25619  } // for (ishd < n_shd_nodes)
25620 
25621  } // for (jproc < nproc)
25622 
25623  } // for (iproc < nproc)
25624 
25625  // Clear the container where the info. will be sent back to each
25626  // processor
25627  package_unsigned_data_sent_from_root.clear();
25628 
25629  // Prepare the data to sent it back to each processor (encode the
25630  // info. to sent to all processors)
25631  for (unsigned iproc = 0; iproc < nproc; iproc++)
25632  {
25633  // Count the number of data sent to iproc processor
25634  unsigned count_n_data_sent_to_iproc = 0;
25635  for (unsigned jproc = 0; jproc < nproc; jproc++)
25636  {
25637  // No shared nodes between the same processor
25638  if (iproc != jproc)
25639  {
25640  // Get the number of nodes shared between the processors
25641  const unsigned n_shd_nodes =
25642  root_local_node_degree[iproc][jproc].size();
25643 
25644  // Add the number of data sent to iproc processor
25645  count_n_data_sent_to_iproc += n_shd_nodes;
25646 
25647  // Loop over the nodes shared between the pair of processors
25648  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25649  {
25650  package_unsigned_data_sent_from_root.push_back(
25651  root_local_node_degree[iproc][jproc][ishd]);
25652  } // for (ishd < n_shd_nodes)
25653 
25654  } // if (iproc != jproc)
25655 
25656  } // for (jproc < nproc)
25657 
25658  // Set the number of data sent to iproc processor
25659  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25660 
25661  } // for (iproc < nproc)
25662 
25663  } // if (my_rank == root_processor)
25664 
25665  // Total data received from root to this processor
25666  int n_unsigned_data_received_from_root = 0;
25667 
25668  // Get the number of data that each processor receives from root
25669  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25670  // root to each
25671  // processor
25672  1, // The number of data sent from root to each
25673  // processor
25674  MPI_UNSIGNED,
25675  &n_unsigned_data_received_from_root, // Store the
25676  // info. received
25677  // from root
25678  1, // The number of data received from root
25679  MPI_UNSIGNED,
25680  root_processor, // The processor that sends the
25681  // info.
25682  comm_pt->mpi_comm());
25683 
25684  // Receive the info. sent by root
25685  Vector<unsigned> package_unsigned_data_received_from_root(
25686  n_unsigned_data_received_from_root);
25687 
25688  // Compute the offsets to each processor
25689  Vector<int> root_unsigned_offsets_sent(nproc, 0);
25690  root_unsigned_offsets_sent[0] = 0;
25691  for (unsigned iproc = 1; iproc < nproc; iproc++)
25692  {
25693  // Compute the offset to send the values to each processor
25694  root_unsigned_offsets_sent[iproc] =
25695  root_unsigned_offsets_sent[iproc - 1] +
25696  n_unsigned_data_sent_from_root[iproc - 1];
25697  }
25698 
25699  if (my_rank != root_processor)
25700  {
25701  // Create at least one entry so we don't get a seg fault below
25702  if (package_unsigned_data_sent_from_root.size() == 0)
25703  {
25704  package_unsigned_data_sent_from_root.resize(1);
25705  }
25706  } // if (my_rank!=root_processor)
25707 
25708  // Create at least one entry so we don't get a seg fault below
25709  if (package_unsigned_data_received_from_root.size() == 0)
25710  {
25711  package_unsigned_data_received_from_root.resize(1);
25712  }
25713 
25714  // Get the data from root
25715  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25716  // info. sent
25717  // from root
25718  // to others
25719  // processors
25720  &n_unsigned_data_sent_from_root[0], // The number of
25721  // data sent from
25722  // root to others
25723  // processors
25724  &root_unsigned_offsets_sent[0], // The offsets to each
25725  // processors
25726  MPI_UNSIGNED,
25727  &package_unsigned_data_received_from_root[0], // The
25728  // storage
25729  // in the
25730  // processor
25731  // that
25732  // receives
25733  // the
25734  // info.
25735  n_unsigned_data_received_from_root, // The number of
25736  // data that the
25737  // current
25738  // processor
25739  // receives from
25740  // root
25741  MPI_UNSIGNED,
25742  root_processor, // The root processors
25743  comm_pt->mpi_comm());
25744 
25745  // Decode the info.
25746 
25747  // Keep track of the already nodes done
25748  std::map<Node*, bool> node_done;
25749 
25750  // Read the global degree assigned to the shared nodes between the
25751  // current processors and the other processors
25752  int decode_counter = 0;
25753  // Store the global degree of the local nodes
25754  Vector<Vector<unsigned>> local_node_degree(nproc);
25755  // Loop over the processors
25756  for (unsigned iproc = 0; iproc < nproc; iproc++)
25757  {
25758  // There are no shared nodes with the current processor itself
25759  if (iproc != my_rank)
25760  {
25761  // Get the number of nodes shared with the iproc processor
25762  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25763 
25764  // Read the global degree of the node
25765  package_unsigned_send_data_to_root.push_back(n_nodes);
25766 
25767  // Loop over the nodes
25768  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25769  {
25770  // Get the node degree assigned to the ishd node in between
25771  // the interaction of the iproc and the current processor
25772  const unsigned node_degree =
25773  package_unsigned_data_received_from_root[decode_counter++];
25774 
25775  // Get the node
25776  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
25777 
25778  // Has the node been assigned a global degree
25779  if (!node_done[shd_node_pt])
25780  {
25781  // Assign the global degree to the node
25782  global_node_degree[shd_node_pt] = node_degree;
25783  // Mark the node as done
25784  node_done[shd_node_pt] = true;
25785  }
25786 #ifdef PARANOID
25787  else
25788  {
25789  // The node has been already done, check that the node
25790  // degree is the same as the already assigned
25791  if (global_node_degree[shd_node_pt] != node_degree)
25792  {
25793  std::ostringstream error_stream;
25794  error_stream
25795  << "The local node has already assigned a global degree,\n"
25796  << "however, a different degree for the same node has been\n"
25797  << "read from the data sent from root processor\n"
25798  << "iproc processor: (" << iproc << ")\n"
25799  << "Local node: (" << ishd << ")\n"
25800  << "---------------------------------------------------------\n"
25801  << "Already assigned degree: ("
25802  << global_node_degree[shd_node_pt] << ")\n"
25803  << "New found degree: (" << node_degree << ")\n"
25804  << "---------------------------------------------------------\n"
25805  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25806  << shd_node_pt->x(1) << ")\n\n";
25807  throw OomphLibError(
25808  error_stream.str(),
25809  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25810  OOMPH_EXCEPTION_LOCATION);
25811  }
25812 
25813  } // else if (!node_done[shd_node_pt])
25814 #endif // #ifdef PARANOID
25815 
25816  } // for (ishd < n_nodes)
25817 
25818  } // if (iproc != my_rank)
25819 
25820  } // for (iproc < nproc)
25821 
25822 #ifdef PARANOID
25823  // Ensure that all the info. sent from root processor has been read
25824  if (decode_counter != n_unsigned_data_received_from_root)
25825  {
25826  std::ostringstream error_stream;
25827  error_stream
25828  << "The number of data decoded received from root processor is\n"
25829  << "different from the total number of data received from the root\n"
25830  << "processor\n"
25831  << "Data decoded: (" << decode_counter << ")\n"
25832  << "Data received: (" << n_unsigned_data_received_from_root << ")\n\n"
25833  << "This is a synchronisation issue so you are probably sending\n"
25834  << "more or less info. than the one that is being decoded\n\n";
25835  throw OomphLibError(
25836  error_stream.str(),
25837  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25838  OOMPH_EXCEPTION_LOCATION);
25839  }
25840 #endif
25841  }
25842 
25843  //======================================================================
25844  // Sort the nodes on the new shared boundaries (after load balancing),
25845  // computes the alias of the nodes and creates the adjacency matrix
25846  // that represent the graph created by the shared edges between each
25847  // pair of processors
25848  // ======================================================================
25849  template<class ELEMENT>
25852  Vector<Vector<FiniteElement*>>& unsorted_face_ele_pt,
25853  Vector<Vector<Node*>>& tmp_sorted_shared_node_pt,
25854  std::map<Node*, Vector<Vector<unsigned>>>& node_alias,
25855  Vector<Vector<Vector<unsigned>>>& adjacency_matrix)
25856  {
25857  // Get the number of processors and the rank
25858  const unsigned nproc = this->communicator_pt()->nproc();
25859  const unsigned my_rank = this->communicator_pt()->my_rank();
25860 
25861  // Assign a unique id to each node shared between each pair of
25862  // processors, in this case the current processor and the iproc
25863 
25864  // ... also compute the alias of each node (processor and index of
25865  // the node in all processors where it appears)
25866 
25867  // Clear the alias info
25868  node_alias.clear();
25869 
25870  // Temporary storage for the index of the nodes
25871  Vector<std::map<Node*, unsigned>> tmp_node_index(nproc);
25872 
25873  // Loop over the processors
25874  for (unsigned iproc = 0; iproc < nproc; iproc++)
25875  {
25876  // There is no shared elements between the same processor
25877  if (iproc != my_rank)
25878  {
25879  // Map to mark those nodes already visited
25880  std::map<Node*, bool> done_node;
25881 
25882  // A map is used to sort the nodes using their coordinates as
25883  // the key of the map
25884  // std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25885  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25886 
25887  // Get the number of unsorted face elements
25888  const unsigned n_unsorted_face_ele = unsorted_face_ele_pt[iproc].size();
25889 
25890  // Loop over the unsorted elements
25891  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25892  {
25893  // Get a root element
25894  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25895  // Get the left node of the face element
25896  Node* left_node_pt = face_ele_pt->node_pt(0);
25897 
25898  // Check if the node has been already sorted in the
25899  // interaction between the current processor and iproc
25900  // processor
25901  if (!done_node[left_node_pt])
25902  {
25903  std::pair<double, double> vertex =
25904  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25905  sorted_nodes_pt[vertex] = left_node_pt;
25906  // Mark the node as done
25907  done_node[left_node_pt] = true;
25908  }
25909 
25910  // Get the number of nodes of the face element
25911  const unsigned n_nodes = face_ele_pt->nnode();
25912  // Get the right node of the face element
25913  Node* right_node_pt = face_ele_pt->node_pt(n_nodes - 1);
25914 
25915  // Check if the node has been already sorted in the
25916  // interaction between the current processor and iproc
25917  // processor
25918  if (!done_node[right_node_pt])
25919  {
25920  std::pair<double, double> vertex =
25921  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25922  sorted_nodes_pt[vertex] = right_node_pt;
25923  // Mark the node as done
25924  done_node[right_node_pt] = true;
25925  }
25926 
25927  } // for (e < nunsorted_face_ele)
25928 
25929  // The nodes are already sorted, we need to return them in the
25930  // proper container
25931 
25932  // The counter to enumerate the nodes
25933  unsigned counter = 0;
25934 
25935  // Go through the map container which already have the nodes
25936  // sorted they have the same sorting on all processors
25937  for (std::map<std::pair<double, double>, Node*>::iterator it =
25938  sorted_nodes_pt.begin();
25939  it != sorted_nodes_pt.end();
25940  it++)
25941  {
25942  // Get the node
25943  Node* node_pt = (*it).second;
25944  // Store the node at the corresponding index
25945  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25946 
25947  // Create the temporary access to the node index
25948  tmp_node_index[iproc][node_pt] = counter;
25949 
25950  // Fill the info. for the node alias
25951  Vector<unsigned> alias(3);
25952  // The current processor
25953  alias[0] = my_rank;
25954  // The processor with which is shared
25955  alias[1] = iproc;
25956  // The index with that processor
25957  alias[2] = counter++;
25958 
25959  // Store the info. of the alias
25960  node_alias[node_pt].push_back(alias);
25961 
25962  } // Loop map
25963 
25964  } // if (iproc != my_rank)
25965 
25966  } // for (iproc < nproc)
25967 
25968  // Loop over the processors to resize and initialize the adjacency
25969  // matrix
25970  for (unsigned iproc = 0; iproc < nproc; iproc++)
25971  {
25972  // Get the number of nodes shared with iproc
25973  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25974  // Resize the adjacency matrix
25975  adjacency_matrix[iproc].resize(n_shd_nodes);
25976  for (unsigned i = 0; i < n_shd_nodes; i++)
25977  {
25978  // Resize the adjacency matrix
25979  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25980 
25981  // Initialize the
25982  for (unsigned j = 0; j < n_shd_nodes; j++)
25983  {
25984  adjacency_matrix[iproc][i][j] = 0;
25985  } // for (j < n_shd_nodes)
25986 
25987  } // for (i < n_shd_nodes)
25988 
25989  } // for (iproc < nproc)
25990 
25991  // Loop over the processors to fill the adjacency matrix
25992  for (unsigned iproc = 0; iproc < nproc; iproc++)
25993  {
25994  // There is no shared elements between the same processor
25995  if (iproc != my_rank)
25996  {
25997  // Get the number of unsorted face elements
25998  const unsigned n_unsorted_face_ele = unsorted_face_ele_pt[iproc].size();
25999 
26000  // Loop over the unsorted elements
26001  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
26002  {
26003  // Get a root element
26004  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
26005  // Get the left node of the face element
26006  Node* left_node_pt = face_ele_pt->node_pt(0);
26007 
26008  // Get the number of nodes of the face element
26009  const unsigned n_nodes = face_ele_pt->nnode();
26010  // Get the right node of the face element
26011  Node* right_node_pt = face_ele_pt->node_pt(n_nodes - 1);
26012 
26013  // Get the index of each of the nodes
26014  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
26015  const unsigned right_node_index =
26016  tmp_node_index[iproc][right_node_pt];
26017 
26018  // Add an entry to the adjacency matrix to indicate the
26019  // association of left and right node
26020  adjacency_matrix[iproc][left_node_index][right_node_index]++;
26021  // ... both directions
26022  adjacency_matrix[iproc][right_node_index][left_node_index]++;
26023 
26024  } // for (e < n_unsorted_face_ele)
26025 
26026  } // if (iproc != my_rank)
26027 
26028  } // for (iproc < nproc)
26029  }
26030 
26031  //======================================================================
26032  /// Get the nodes on the shared boundary (b), these are stored
26033  /// in the segment they belong
26034  //======================================================================
26035  template<class ELEMENT>
26038  const unsigned& shd_bnd_id, Vector<Vector<Node*>>& tmp_segment_nodes)
26039  {
26040  // Clear the data structure were to return the nodes
26041  tmp_segment_nodes.clear();
26042 
26043  // Get the face elements that created the shared boundary from the
26044  // bulk shared boundary elements
26045 
26046 #ifdef PARANOID
26047  // The temporary storage for the halo face elements
26048  Vector<FiniteElement*> halo_shared_face_ele_pt;
26049 #endif
26050  // The temporary storage for the nonhalo face elements
26051  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
26052 
26053  // Get the number of shared boundary elements associated with the
26054  // current shared boundary
26055  const unsigned nshared_bound_ele =
26056  this->nshared_boundary_element(shd_bnd_id);
26057 
26058  // Loop over the elements in the shared boundary to create the face
26059  // elements
26060  for (unsigned e = 0; e < nshared_bound_ele; e++)
26061  {
26062  // Get the shared boundary element
26063  FiniteElement* bulk_ele_pt =
26064  this->shared_boundary_element_pt(shd_bnd_id, e);
26065 
26066  // Get the face index
26067  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
26068 
26069  // Before adding the new element we need to ensure that the edge
26070  // that this element represents has not been already added
26071  FiniteElement* face_ele_pt =
26072  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
26073 
26074  // Nonhalo element
26075  if (!bulk_ele_pt->is_halo())
26076  {
26077  // Add nonhalo shared face element to the container
26078  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
26079  }
26080 #ifdef PARANOID
26081  else // halo element
26082  {
26083  // Add halo shared face element to the container
26084  halo_shared_face_ele_pt.push_back(face_ele_pt);
26085  }
26086 #endif
26087 
26088  } // for (e < nshared_bound_ele)
26089 
26090  // Mark the face elements already used
26091  std::map<FiniteElement*, bool> shared_face_done;
26092 
26093  // Get the number of nonhalo face elements
26094  const unsigned nnonhalo_face_shared_ele = nonhalo_shared_face_ele_pt.size();
26095 
26096  // If we are in PARANOID mode check that there is one halo element
26097  // for each nonhalo element
26098 #ifdef PARANOID
26099  // Get the number of halo face elements
26100  const unsigned nhalo_face_shared_ele = halo_shared_face_ele_pt.size();
26101 
26102  // The number of nonhalo shared face boundary elements must be the
26103  // half of the total number of shared boundary elements
26104  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
26105  {
26106  std::ostringstream error_message;
26107  error_message
26108  << "The number of shared boundary elements (" << nshared_bound_ele
26109  << ") is not the double\nof the number of unsorted nonhalo shared "
26110  << "face boundary elements (" << nnonhalo_face_shared_ele
26111  << ")\n for the current boundary (" << shd_bnd_id << ")\n\n";
26112  throw OomphLibError(
26113  error_message.str(),
26114  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26115  OOMPH_EXCEPTION_LOCATION);
26116  }
26117 
26118  // The number of halo shared face boundary elements must be the
26119  // half of the total number of shared boundary elements
26120  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
26121  {
26122  std::ostringstream error_message;
26123  error_message
26124  << "The number of shared boundary elements (" << nshared_bound_ele
26125  << ") is not the double\nof the number of unsorted halo shared "
26126  << "face boundary elements (" << nhalo_face_shared_ele
26127  << ")\n for the current boundary (" << shd_bnd_id << ")\n\n";
26128  throw OomphLibError(
26129  error_message.str(),
26130  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26131  OOMPH_EXCEPTION_LOCATION);
26132  }
26133 
26134  // ------------------------------------------------------------------
26135  // Loop over the nonhalo face elements and look for the halo face
26136  // element at the other side of the shared boundary
26137  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26138  {
26139  // Get the inh-th face element
26140  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
26141 
26142  // Get the number of nodes on the face element
26143  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
26144  // Get the first and last node on the element
26145  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
26146  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh - 1);
26147 
26148  // Now find the (halo) face element at the other side of the
26149  // shared boundary
26150  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26151  {
26152  // Get the ih-th face element
26153  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
26154 
26155  // Check that the face element has not been done
26156  if (!shared_face_done[halo_face_ele_pt])
26157  {
26158  // Get the number of nodes on the face element
26159  const unsigned nnodes_h = halo_face_ele_pt->nnode();
26160  // Get the first and last node on the element
26161  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
26162  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h - 1);
26163 
26164  // If the nodes are the same then we have found the (halo)
26165  // face element at the other side of the shared boundary
26166  if (nh_first_node_pt == h_first_node_pt &&
26167  nh_last_node_pt == h_last_node_pt)
26168  {
26169  // Mark the face elements as done
26170  shared_face_done[nonhalo_face_ele_pt] = true;
26171  shared_face_done[halo_face_ele_pt] = true;
26172 
26173  // Break the loop for (ih < nhalo_face_shared_ele)
26174  break;
26175  } // if (nh_first_node_pt == h_first_node_pt &&
26176  // nh_last_node_pt == h_last_node_pt)
26177  else if (nh_first_node_pt == h_last_node_pt &&
26178  nh_last_node_pt == h_first_node_pt)
26179  {
26180  // Mark the face elements as done
26181  shared_face_done[nonhalo_face_ele_pt] = true;
26182  shared_face_done[halo_face_ele_pt] = true;
26183 
26184  // Break the loop for (ih < nhalo_face_shared_ele)
26185  break;
26186  } // else if (nh_first_node_pt == h_last_node_pt &&
26187  // nh_last_node_pt == h_first_node_pt)
26188 
26189  } // if (face_done[halo_face_ele_pt])
26190 
26191  } // for (ih < nhalo_face_shared_ele)
26192 
26193  } // for (inh < nnonhalo_face_shared_ele)
26194 
26195  // The number of done shared face elements MUST be the same as the
26196  // sum of the nonhalo and halo shared boundary face elements
26197  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
26198  shared_face_done.size())
26199  {
26200  std::ostringstream error_message;
26201  error_message << "The number of DONE shared boundary face elements ("
26202  << shared_face_done.size()
26203  << ") is not the same\n as the sum of"
26204  << "the nonhalo face shared boundary elements ("
26205  << nnonhalo_face_shared_ele
26206  << ")\nand the halo face shared "
26207  << "boundary elements (" << nhalo_face_shared_ele
26208  << ") for the\n/"
26209  << "current boundary (" << shd_bnd_id << ")\n\n";
26210  throw OomphLibError(
26211  error_message.str(),
26212  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
26213  OOMPH_EXCEPTION_LOCATION);
26214  }
26215 #endif // #ifdef PARANOID
26216 
26217  // -------------------------------------------------------------
26218  // Now sort the face elements
26219  // -------------------------------------------------------------
26220 
26221  // We already have the shared face elements that make the shared
26222  // boundary now sort them to create a contiguous boundary
26223 
26224  // Clear the already done face elements
26225  shared_face_done.clear();
26226 
26227  unsigned nsorted_face_ele = 0;
26228 
26229  // Storing for the sorting nodes extracted from the face elements
26230  std::list<Node*> sorted_nodes;
26231 
26232  // Get the root face element
26233  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
26234  nsorted_face_ele++;
26235 
26236  // Mark face as done
26237  shared_face_done[root_face_ele_pt] = true;
26238 
26239  // The initial and final node on the list
26240  const unsigned nnodes_root = root_face_ele_pt->nnode();
26241  Node* first_node_pt = root_face_ele_pt->node_pt(0);
26242  Node* last_node_pt = root_face_ele_pt->node_pt(nnodes_root - 1);
26243 
26244  // Push back on the list the new nodes
26245  sorted_nodes.push_back(first_node_pt);
26246  sorted_nodes.push_back(last_node_pt);
26247 
26248  // Sort the face elements
26249  while (nsorted_face_ele < nnonhalo_face_shared_ele)
26250  {
26251  // Flag to indicate when a node was added
26252  bool node_added = false;
26253 
26254  // Start from the next edge since we have already added the
26255  // previous one as the initial face element
26256  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
26257  {
26258  FiniteElement* tmp_shared_face_ele_pt =
26259  nonhalo_shared_face_ele_pt[iface];
26260 
26261  // If face has not been sorted
26262  if (!shared_face_done[tmp_shared_face_ele_pt])
26263  {
26264  // Get the number of nodes for the current face element
26265  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
26266 
26267  // Get each individual node
26268  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26269  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes - 1);
26270 
26271  if (left_node_pt == first_node_pt)
26272  {
26273  // Push front the new node
26274  sorted_nodes.push_front(right_node_pt);
26275  first_node_pt = right_node_pt;
26276  node_added = true;
26277  }
26278  else if (left_node_pt == last_node_pt)
26279  {
26280  // Push back the new node
26281  sorted_nodes.push_back(right_node_pt);
26282  last_node_pt = right_node_pt;
26283  node_added = true;
26284  }
26285  else if (right_node_pt == first_node_pt)
26286  {
26287  // Push front the new node
26288  sorted_nodes.push_front(left_node_pt);
26289  first_node_pt = left_node_pt;
26290  node_added = true;
26291  }
26292  else if (right_node_pt == last_node_pt)
26293  {
26294  // Push back the new node
26295  sorted_nodes.push_back(left_node_pt);
26296  last_node_pt = left_node_pt;
26297  node_added = true;
26298  }
26299 
26300  if (node_added)
26301  {
26302  // Mark as done only if one of its nodes has been added to
26303  // the list
26304  shared_face_done[tmp_shared_face_ele_pt] = true;
26305  nsorted_face_ele++;
26306 
26307  // Break the for
26308  break;
26309  }
26310 
26311  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26312 
26313  } // for (iface < nnonhalo_face_shared_ele)
26314 
26315  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26316 
26317  // Here we can safely delete the face elements, they are no longer
26318  // required
26319 
26320  // First the nonhalo face elements
26321  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26322  {
26323  delete nonhalo_shared_face_ele_pt[inh];
26324  nonhalo_shared_face_ele_pt[inh] = 0;
26325  } // for (inh < nnonhalo_face_shared_ele)
26326 
26327 #ifdef PARANOID
26328  // ... then the halo face elements
26329  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26330  {
26331  delete halo_shared_face_ele_pt[ih];
26332  halo_shared_face_ele_pt[ih] = 0;
26333  } // for (inh < nhalo_face_shared_ele)
26334 #endif
26335 
26336  // ------------------------------------------------
26337  // Now copy the nodes to the output container
26338  // ------------------------------------------------
26339  // Get the number of nodes in the container
26340  const unsigned n_nodes = sorted_nodes.size();
26341 
26342  // First resize the container
26343  tmp_segment_nodes.resize(1);
26344  tmp_segment_nodes[0].resize(n_nodes);
26345 
26346  // Counter
26347  unsigned counter = 0;
26348 
26349  // Loop over the list of nodes and copy them in the output container
26350  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26351  it != sorted_nodes.end();
26352  it++)
26353  {
26354  tmp_segment_nodes[0][counter] = (*it);
26355  counter++;
26356  } // Loop over sorted nodes
26357  }
26358 
26359  //=====start of get_required_elemental_information_load_balance_helper====
26360  /// Helper function to get the required elemental information from
26361  /// the element that will be sent to iproc processor.
26362  /// This info. involves the association of the element to a boundary or
26363  /// region.
26364  //========================================================================
26365  template<class ELEMENT>
26368  unsigned& iproc,
26369  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
26370  FiniteElement* ele_pt)
26371  {
26372  // Check if the element is associated with the original boundaries
26373  const unsigned nbound = this->initial_shared_boundary_id();
26374 
26375  // Get the number of processors
26376  const unsigned nproc = this->communicator_pt()->nproc();
26377 
26378  // ------------------------------------------------------------------
26379  // Stores the information regarding the boundaries associated to the
26380  // element (it that is the case)
26381  Vector<unsigned> associated_boundaries;
26382  Vector<unsigned> face_index_on_boundary;
26383 
26384  unsigned counter_face_indexes = 0;
26385 
26386  for (unsigned b = 0; b < nbound; b++)
26387  {
26388  // Get the number of elements associated to boundary i
26389  const unsigned nboundary_ele = nboundary_element(b);
26390  for (unsigned e = 0; e < nboundary_ele; e++)
26391  {
26392  if (ele_pt == this->boundary_element_pt(b, e))
26393  {
26394  // Keep track of the boundaries associated to the element
26395  associated_boundaries.push_back(b);
26396  // Get the face index
26397  face_index_on_boundary.push_back(face_index_at_boundary(b, e));
26398  counter_face_indexes++;
26399 #ifdef PARANOID
26400  if (counter_face_indexes > 2)
26401  {
26402  std::stringstream error_message;
26403  error_message
26404  << "A triangular element can not have more than two of its faces "
26405  << "on a boundary!!!\n\n";
26406  throw OomphLibError(error_message.str(),
26407  "RefineableTriangleMesh::get_required_"
26408  "elemental_information_helper()",
26409  OOMPH_EXCEPTION_LOCATION);
26410  }
26411 #else
26412  // Already found 2 face indexes on the same boundary?
26413  if (counter_face_indexes == 2)
26414  {
26415  break;
26416  }
26417 #endif // #ifdef PARANOID
26418 
26419  } // if (ele_pt == this->boundary_element_pt(b,e))
26420 
26421  } // (e < nboundary_ele)
26422 
26423  } // (b < nbound)
26424 
26425  // If the element is associated to any boundary then package all the
26426  // relevant info
26427  const unsigned nassociated_boundaries = associated_boundaries.size();
26428  if (nassociated_boundaries > 0)
26429  {
26430  Flat_packed_unsigneds.push_back(1);
26431 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26432  Flat_packed_unsigneds_string.push_back(
26433  "The element is a boundary element");
26434 #endif
26435  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26436 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26437  std::stringstream junk;
26438  junk << "The elements is associated to " << nassociated_boundaries
26439  << " boundaries";
26440  Flat_packed_unsigneds_string.push_back(junk.str());
26441 #endif
26442 
26443  // Package the ids of the associated boundaries and the
26444  // corresponding face index for each boundary (if the element is a
26445  // corner element, it will have two faces associated to the
26446  // boundary)
26447  for (unsigned i = 0; i < nassociated_boundaries; i++)
26448  {
26449  unsigned b = associated_boundaries[i];
26450  Flat_packed_unsigneds.push_back(b);
26451 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26452  std::stringstream junk;
26453  junk << "Element associated to boundary " << b << " of "
26454  << nassociated_boundaries << " total associated boundaries";
26455  Flat_packed_unsigneds_string.push_back(junk.str());
26456 #endif
26457  unsigned f = face_index_on_boundary[i];
26458  Flat_packed_unsigneds.push_back(f);
26459 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26460  std::stringstream junk2;
26461  junk2 << "Face index " << f << " for associated boundary " << b;
26462  Flat_packed_unsigneds_string.push_back(junk2.str());
26463 #endif
26464  }
26465 
26466  // If the element is associated to any boundary then we should
26467  // check if the mesh has regions, if that is the case then we need
26468  // to check to which region the boundary element does belong
26469 
26470  // If the mesh has regions we should look for the element
26471  // associated to a boundary and a specified region
26472  Vector<Vector<unsigned>> associated_boundaries_and_regions;
26473  Vector<unsigned> face_index_on_boundary_and_region;
26474 
26475  // Now check for the case when we have regions in the mesh
26476  const unsigned n_regions = this->nregion();
26477  if (n_regions > 1)
26478  {
26479  // Used to count the number of faces associated with
26480  // boundary-regions
26481  unsigned counter_face_indexes_in_regions = 0;
26482  // Loop over the boundaries
26483  for (unsigned b = 0; b < nbound; b++)
26484  {
26485  // Go through each region by getting the region id
26486  for (unsigned i_reg = 0; i_reg < n_regions; i_reg++)
26487  {
26488  // Get thre region id associated with the (i_reg)-th region
26489  const unsigned region_id =
26490  static_cast<unsigned>(this->Region_attribute[i_reg]);
26491 
26492  // Loop over all elements associated with the current boundary
26493  // and the i_reg-th region and check if the element is part of
26494  // any region
26495  const unsigned nele_in_region =
26496  this->nboundary_element_in_region(b, region_id);
26497  for (unsigned ee = 0; ee < nele_in_region; ee++)
26498  {
26499  // Check if the boundary-region element is the same as the
26500  // element
26501  if (ele_pt ==
26502  this->boundary_element_in_region_pt(b, region_id, ee))
26503  {
26504  // Storage for the boundary and region associated to the
26505  // element
26506  Vector<unsigned> bound_and_region(2);
26507 
26508  // Keep track of the boundaries associated to the element
26509  bound_and_region[0] = b;
26510  // Keep track of the regions associated to the element
26511  bound_and_region[1] = region_id;
26512  // Add the boundaries and regions in the storage to be
26513  // sent to other processors
26514  associated_boundaries_and_regions.push_back(bound_and_region);
26515  // Get the face index and keep track of it
26516  face_index_on_boundary_and_region.push_back(
26517  this->face_index_at_boundary_in_region(b, region_id, ee));
26518 
26519  // Increase the number of faces of the element associated
26520  // to boundary-regions
26521  counter_face_indexes_in_regions++;
26522 
26523 #ifdef PARANOID
26524  if (counter_face_indexes_in_regions > 2)
26525  {
26526  std::stringstream error_message;
26527  error_message << "A triangular element can not have more "
26528  "than two of its\n"
26529  << "faces on a boundary!!!\n\n";
26530  throw OomphLibError(error_message.str(),
26531  "RefineableTriangleMesh::get_required_"
26532  "elemental_information_helper()",
26533  OOMPH_EXCEPTION_LOCATION);
26534  } // if (counter_face_indexes_in_regions > 2)
26535 #endif
26536 
26537  } // The element is a boundary-region element
26538 
26539  } // for (ee < nele_in_region)
26540 
26541  } // for (i_reg < n_regions)
26542 
26543  } // for (b < nbound)
26544 
26545  } // if (n_regions > 1)
26546 
26547  // Now package the info. to be sent to other processors
26548  const unsigned nassociated_boundaries_and_regions =
26549  associated_boundaries_and_regions.size();
26550  if (nassociated_boundaries_and_regions > 0)
26551  {
26552  Flat_packed_unsigneds.push_back(1);
26553 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26554  Flat_packed_unsigneds_string.push_back(
26555  "The element is associated to boundaries and regions");
26556 #endif
26557 
26558  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26559 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26560  std::stringstream junk;
26561  junk << "The element is associated to "
26562  << nassociated_boundaries_and_regions << " boundaries-regions";
26563  Flat_packed_unsigneds_string.push_back(junk.str());
26564 #endif
26565 
26566  // Package the ids of the associated boundaries, regions and the
26567  // corresponding face index for each boundary-region (if the
26568  // element is a corner element, it will have two faces
26569  // associated to the boundary-region)
26570  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26571  {
26572  const unsigned b = associated_boundaries_and_regions[i][0];
26573  Flat_packed_unsigneds.push_back(b);
26574 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26575  std::stringstream junk;
26576  junk << "Element associated to boundary " << b << " of "
26577  << nassociated_boundaries_and_regions
26578  << " total associated boundaries-regions";
26579  Flat_packed_unsigneds_string.push_back(junk.str());
26580 #endif
26581 
26582  const unsigned r = associated_boundaries_and_regions[i][1];
26583  Flat_packed_unsigneds.push_back(r);
26584 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26585  std::stringstream junk2;
26586  junk2 << "Element associated to region " << r << " of "
26587  << nassociated_boundaries_and_regions
26588  << " total associated boundaries-regions";
26589  Flat_packed_unsigneds_string.push_back(junk2.str());
26590 #endif
26591 
26592  const unsigned f = face_index_on_boundary_and_region[i];
26593  Flat_packed_unsigneds.push_back(f);
26594 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26595  std::stringstream junk3;
26596  junk3 << "Face index " << f << " for associated boundary-region ("
26597  << b << "-" << r << ")";
26598  Flat_packed_unsigneds_string.push_back(junk3.str());
26599 #endif
26600  } // for (i < nassociated_boundaries_and_regions)
26601  } // if (nassociated_boundaries_and_regions > 0)
26602  else
26603  {
26604  Flat_packed_unsigneds.push_back(0);
26605 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26606  Flat_packed_unsigneds_string.push_back(
26607  "The element is NOT associated to boundaries and regions");
26608 #endif
26609  } // else if (nassociated_boundaries_and_regions > 0)
26610  }
26611  else
26612  {
26613  Flat_packed_unsigneds.push_back(0);
26614 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26615  Flat_packed_unsigneds_string.push_back(
26616  "The element is not associated to any original boundary");
26617 #endif
26618  }
26619 
26620  // ------------------------------------------------------------
26621  // Now review if the element is associated to a shared boundary
26622 
26623  // Store the shared boundaries, and therefore the face indexes
26624  // associated to the element
26625  Vector<unsigned> associated_shared_boundaries;
26626  Vector<unsigned> face_index_on_shared_boundary;
26627 
26628  // Get the shared boundaries in this processor
26629  Vector<unsigned> my_rank_shared_boundaries_ids;
26630  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26631 
26632  // Get the number of shared boundaries
26633  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26634  // Loop over the shared boundaries
26635  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26636  {
26637  // Get the boundary id
26638  const unsigned sb = my_rank_shared_boundaries_ids[i];
26639 
26640  // Get the number of elements associated to shared boundary sb
26641  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26642  for (unsigned e = 0; e < nboundary_ele; e++)
26643  {
26644  if (ele_pt == this->shared_boundary_element_pt(sb, e))
26645  {
26646  // Keep track of the boundaries associated to the element
26647  associated_shared_boundaries.push_back(sb);
26648  // Get the face index
26649  face_index_on_shared_boundary.push_back(
26650  this->face_index_at_shared_boundary(sb, e));
26651  }
26652  } // (e < nboundary_ele)
26653  } // (i < nmy_rank_shd_bnd)
26654 
26655  // If the element is associated to a shared boundary then package
26656  // all the relevant info
26657  const unsigned nassociated_shared_boundaries =
26658  associated_shared_boundaries.size();
26659  if (nassociated_shared_boundaries > 0)
26660  {
26661  Flat_packed_unsigneds.push_back(3);
26662 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26663  Flat_packed_unsigneds_string.push_back(
26664  "The element is a shared boundary element");
26665 #endif
26666  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26667 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26668  std::stringstream junk;
26669  junk << "The elements is associated to " << nassociated_shared_boundaries
26670  << "shared boundaries";
26671  Flat_packed_unsigneds_string.push_back(junk.str());
26672 #endif
26673 
26674  // Package the ids of the associated boundaries
26675  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26676  {
26677  const unsigned b = associated_shared_boundaries[i];
26678  Flat_packed_unsigneds.push_back(b);
26679 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26680  std::stringstream junk;
26681  junk << "Element associated to shared boundary " << b << " of "
26682  << nassociated_shared_boundaries << " total associated boundaries";
26683  Flat_packed_unsigneds_string.push_back(junk.str());
26684 #endif
26685 
26686  const unsigned f = face_index_on_shared_boundary[i];
26687  Flat_packed_unsigneds.push_back(f);
26688 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26689  std::stringstream junk2;
26690  junk2 << "Face index " << f << " for associated shared boundary " << b;
26691  Flat_packed_unsigneds_string.push_back(junk2.str());
26692 #endif
26693  }
26694  }
26695  else
26696  {
26697  Flat_packed_unsigneds.push_back(0);
26698 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26699  Flat_packed_unsigneds_string.push_back(
26700  "The element is not associated to any shared boundary");
26701 #endif
26702  }
26703 
26704  // Now check if the element is haloed with any processor
26705 
26706  // Store the index of the haloed element with the jproc
26707  Vector<Vector<unsigned>> index_haloed(nproc);
26708 
26709  // Loop over the processors
26710  for (unsigned jproc = 0; jproc < nproc; jproc++)
26711  {
26712  // Get the number of haloed elements with jproc
26713  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26714  // Loop over the haloed elements with jproc
26715  for (unsigned ihd = 0; ihd < n_haloed_jproc; ihd++)
26716  {
26717  // Is a haloed element?
26718  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26719  {
26720  // Store the haloed index with the jproc processor
26721  index_haloed[jproc].push_back(ihd);
26722  // Break the searching with the jproc processor
26723  break;
26724  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26725 
26726  } // for (ihd < n_haloed_jproc)
26727 
26728  } // for (jproc < nproc)
26729 
26730  // Send the haloed info.
26731  // Loop over the processors
26732  for (unsigned jproc = 0; jproc < nproc; jproc++)
26733  {
26734  // Is the element haloed with the jproc processor
26735  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26736  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26737 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26738  Flat_packed_unsigneds_string.push_back(
26739  "The number of haloed indexes the element is with processor jproc");
26740 #endif
26741  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26742  {
26743  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26744 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26745  Flat_packed_unsigneds_string.push_back(
26746  "The haloed index of the element with jproc");
26747 #endif
26748  } // for (ihd < n_index_haloed_jproc)
26749 
26750  } // for (jproc < nproc)
26751  }
26752 
26753  //======================================================================
26754  /// Helper function to add nodes on a new domain as a result of
26755  /// load balance
26756  //======================================================================
26757  template<class ELEMENT>
26759  unsigned& iproc,
26760  Vector<Vector<FiniteElement*>>& f_halo_ele_pt,
26761  Vector<Node*>& new_nodes_on_domain,
26762  Node* nod_pt)
26763  {
26764  // Attempt to add this node to the new domain
26765  const unsigned nnew_nodes_on_domain = new_nodes_on_domain.size();
26766  const unsigned new_added_node_index =
26767  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26768 
26769  // If it was added then the new index should match the size of the storage
26770  if (new_added_node_index == nnew_nodes_on_domain)
26771  {
26772  Flat_packed_unsigneds.push_back(1);
26773 
26774 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26775  std::stringstream junk;
26776  junk << "Node needs to be constructed [size="
26777  << Flat_packed_unsigneds.size() << "]; last entry: "
26778  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
26779  Flat_packed_unsigneds_string.push_back(junk.str());
26780 #endif
26781 
26782  // This helper function gets all the required information for the
26783  // specified node and stores it into MPI-sendable information
26784  // so that a new copy can be made on the receiving process
26785  get_required_nodal_information_load_balance_helper(
26786  f_halo_ele_pt, iproc, nod_pt);
26787  }
26788  else // It was already added
26789  {
26790  Flat_packed_unsigneds.push_back(0);
26791 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26792  std::stringstream junk;
26793  junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
26794  << "]; last entry: "
26795  << Flat_packed_unsigneds[Flat_packed_unsigneds.size() - 1];
26796 
26797  Flat_packed_unsigneds_string.push_back(junk.str());
26798 #endif
26799 
26800  // This node has been already added, so tell the other process
26801  // its index in the equivalent storage
26802  Flat_packed_unsigneds.push_back(new_added_node_index);
26803 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26804  Flat_packed_unsigneds_string.push_back("new added node index");
26805 #endif
26806  }
26807  }
26808 
26809  //======start of get_required_nodal_information_load_balance_helper=======
26810  /// Helper function to get the required nodal information from an
26811  /// haloed node so that a fully-functional halo node (and therefore element)
26812  /// can be created on the receiving process
26813  //========================================================================
26814  template<class ELEMENT>
26817  Vector<Vector<FiniteElement*>>& f_halo_ele_pt,
26818  unsigned& iproc,
26819  Node* nod_pt)
26820  {
26821  unsigned my_rank = this->communicator_pt()->my_rank();
26822  const unsigned nproc = this->communicator_pt()->nproc();
26823 
26824  // Tell the halo copy of this node how many values there are
26825  // [NB this may be different for nodes within the same element, e.g.
26826  // when using Lagrange multipliers]
26827  unsigned n_val = nod_pt->nvalue();
26828  Flat_packed_unsigneds.push_back(n_val);
26829 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26830  Flat_packed_unsigneds_string.push_back("Number of values");
26831 #endif
26832 
26833  unsigned n_dim = nod_pt->ndim();
26834 
26835  // Default number of previous values to 1
26836  unsigned n_prev = 1;
26837  if (this->Time_stepper_pt != 0)
26838  {
26839  // Add number of history values to n_prev
26840  n_prev = this->Time_stepper_pt->ntstorage();
26841  }
26842 
26843  // -----------------------------------------------------
26844  // Is the node on an original boundary?
26845  // Store the original boundaries where the node may be
26846  Vector<unsigned> original_boundaries;
26847  // Loop over the original boundaries of the mesh and check if live
26848  // on one of them
26849  const unsigned n_bnd = this->initial_shared_boundary_id();
26850  for (unsigned bb = 0; bb < n_bnd; bb++)
26851  {
26852  // Which boundaries (could be more than one) is it on?
26853  if (nod_pt->is_on_boundary(bb))
26854  {
26855  original_boundaries.push_back(bb);
26856  }
26857  }
26858 
26859  const unsigned n_original_boundaries = original_boundaries.size();
26860  // Is the node on any original boundary?
26861  if (n_original_boundaries > 0)
26862  {
26863  // Indicate that the node is on an original boundary
26864  Flat_packed_unsigneds.push_back(2);
26865 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26866  Flat_packed_unsigneds_string.push_back(
26867  "Node is on the original boundaries");
26868 #endif
26869 
26870  Flat_packed_unsigneds.push_back(n_original_boundaries);
26871 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26872  std::stringstream junk;
26873  junk << "Node is on " << n_original_boundaries << " original boundaries";
26874  Flat_packed_unsigneds_string.push_back(junk.str());
26875 #endif
26876 
26877  // Loop over the original boundaries the node is on
26878  for (unsigned i = 0; i < n_original_boundaries; i++)
26879  {
26880  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26881 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26882  std::stringstream junk;
26883  junk << "Node is on boundary " << original_boundaries[i] << " of "
26884  << nb;
26885  Flat_packed_unsigneds_string.push_back(junk.str());
26886 #endif
26887  // Get the boundary coordinate of the node
26888  Vector<double> zeta(1);
26889  nod_pt->get_coordinates_on_boundary(original_boundaries[i], zeta);
26890  Flat_packed_doubles.push_back(zeta[0]);
26891  }
26892  }
26893  else
26894  {
26895  // Indicate that the node is NOT on an original boundary
26896  Flat_packed_unsigneds.push_back(0);
26897 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26898  Flat_packed_unsigneds_string.push_back(
26899  "Node is on any original boundary");
26900 #endif
26901  }
26902 
26903  // -------------------------------------------------------
26904  // Is the node on shared boundaries?
26905  bool node_on_shared_boundary = false;
26906  // Loop over the shared boundaries with the iproc processors and
26907  // check if live on one of them
26908  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26909  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26910  {
26911  // Get the boundary id
26912  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26913  // Which boundaries (could be more than one) is it on?
26914  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26915  {
26916  node_on_shared_boundary = true;
26917  break;
26918  }
26919  }
26920 
26921  // If the node live on any of the shared boundaries with the iproc
26922  // processor then just get the node number according to the
26923  // sorted_shared_boundary_node_pt() scheme and send it accross
26924  if (node_on_shared_boundary)
26925  {
26926  Flat_packed_unsigneds.push_back(1);
26927 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26928  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26929 #endif
26930 
26931  // Store the shared boundaries where the node is on
26932  Vector<unsigned> shd_boundaries;
26933  // Loop over the shared boundaries with the iproc processor
26934  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26935  {
26936  // Get the boundary id
26937  const unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26938  // Which boundaries (could be more than one) is it on?
26939  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26940  {
26941  shd_boundaries.push_back(i_bnd);
26942  }
26943  }
26944 
26945  // Get the number of shared boundaries the node is on
26946  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26947  // Send the number of shared boundaries the node is on
26948  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26949 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26950  std::stringstream junk;
26951  junk << "Node is on " << n_shd_bnd_is_on << " shared boundaries";
26952  Flat_packed_unsigneds_string.push_back(junk.str());
26953 #endif
26954 
26955  // Loop over the shared boundaries to send their ids
26956  for (unsigned i = 0; i < n_shd_bnd_is_on; i++)
26957  {
26958  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26959 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26960  std::stringstream junk;
26961  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26962  Flat_packed_unsigneds_string.push_back(junk.str());
26963 #endif
26964  }
26965 
26966  // Given that the node is on at least one boundary get the index
26967  // of the node in one of the boundaries and send this index
26968  unsigned shared_boundary_id = shd_boundaries[0];
26969  // Get the number of nodes on the given shared boundary
26970  const unsigned n_nodes_on_shared_boundary =
26971  nsorted_shared_boundary_node(shared_boundary_id);
26972  // Store the index of the node on the shared boundary
26973  unsigned index_node_on_shared_boundary;
26974 #ifdef PARANOID
26975  // Flag to know if the node has been found
26976  bool found_index_node_on_shared_boundary = false;
26977 #endif
26978  // Loop over the nodes on the shared boundary to find the node
26979  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26980  {
26981  // Get the i-th node on the shared boundary
26982  Node* shared_node_pt =
26983  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26984  // Is the node we are looking for
26985  if (shared_node_pt == nod_pt)
26986  {
26987  // Store the index
26988  index_node_on_shared_boundary = i;
26989 #ifdef PARANOID
26990  // Mark as found
26991  found_index_node_on_shared_boundary = true;
26992 #endif
26993  break; // break
26994  }
26995 
26996  } // for (i < nnodes_on_shared_boundary)
26997 
26998 #ifdef PARANOID
26999  if (!found_index_node_on_shared_boundary)
27000  {
27001  std::ostringstream error_message;
27002  error_message << "The index of the node on boundary ("
27003  << shared_boundary_id << ") was not found.\n"
27004  << "The node coordinates are (" << nod_pt->x(0) << ","
27005  << nod_pt->x(1) << ").\n";
27006  throw OomphLibError(
27007  error_message.str(),
27008  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27009  OOMPH_EXCEPTION_LOCATION);
27010  }
27011 #endif
27012  // Send the index of the node on the shared boundary
27013  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
27014 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27015  std::stringstream junk2;
27016  junk2 << "Node index on boundary " << boundaries[0] << " is "
27017  << index_node_on_shared_boundary;
27018  Flat_packed_unsigneds_string.push_back(junk2.str());
27019 #endif
27020 
27021  } // if (node_on_shared_boundary)
27022  else
27023  {
27024  // The node is not on a shared boundary
27025  Flat_packed_unsigneds.push_back(0);
27026 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27027  Flat_packed_unsigneds_string.push_back(
27028  "Node is not on a shared boundary");
27029 #endif
27030  }
27031 
27032  // ----------------------------------------------------------------
27033  // Is the node on any shared boundary where the receiver processor
27034  // is not involved?
27035 
27036  // Now check if the node is on a shared boundary created by the
27037  // current processor (my_rank) and other processor different that
27038  // the iproc processor. This info. will help to complete the sending
27039  // of halo(ed) information between processors
27040 
27041  // Flag to know if the node is on a shared boundary with other
27042  // processor
27043  bool node_on_shared_boundary_with_other_processors = false;
27044  // Count the number of other shared boundaries it could be on
27045  unsigned nshared_boundaries_with_other_processors_have_node = 0;
27046 
27047  // Loop over the shared boundaries of the sent processor (my_rank)
27048  // and other processors (jproc)
27049  for (unsigned jproc = 0; jproc < nproc; jproc++)
27050  {
27051  // Do not search with the iproc processor, that was done before
27052  // above
27053  if (jproc != iproc)
27054  {
27055  // Get the number of shared boundaries with the jproc processor
27056  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
27057  // Loop over the shared boundaries
27058  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
27059  {
27060  // Get the boundary id
27061  const unsigned j_shd_bnd =
27062  this->shared_boundaries_ids(my_rank, jproc, bb);
27063  // Is the node part of this boundary?
27064  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
27065  {
27066  // DEBP("Sending to");
27067  // DEBP(iproc);
27068  // DEBP("Pair of procs where other shared");
27069  // DEBP(my_rank);
27070  // DEBP(jproc);
27071  // DEBP(i_bnd);
27072  node_on_shared_boundary_with_other_processors = true;
27073  // Increase the counter for the number of shared boundaries
27074  // with other processors the node is on
27075  nshared_boundaries_with_other_processors_have_node++;
27076  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
27077 
27078  } // for (bb<n_jshd_bnd)
27079 
27080  } // if (jproc != iproc)
27081 
27082  } // for (jproc < nproc)
27083 
27084  // If the node is on a shared boundary with another processor
27085  // (my_rank, jproc), then send the flag and look for the info.
27086  if (node_on_shared_boundary_with_other_processors)
27087  {
27088  Flat_packed_unsigneds.push_back(4);
27089 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27090  Flat_packed_unsigneds_string.push_back(
27091  "Node is on shared boundary no related with the received processor: 4");
27092 #endif
27093 
27094  // The number of packages of information that will be sent to the
27095  // "iproc" processor. This helps to know how many packages of data
27096  // read from the received processor
27097  Flat_packed_unsigneds.push_back(
27098  nshared_boundaries_with_other_processors_have_node);
27099 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27100  std::stringstream junk;
27101  junk << "Number of other shared boundaries that the node is on: "
27102  << nshared_boundaries_with_other_processors_have_node;
27103  Flat_packed_unsigneds_string.push_back(junk.str());
27104 #endif
27105 
27106  // Counter to ensure that the correct number of data has been sent
27107  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
27108  // Loop over the shared boundaries with other processors and get:
27109  // 1) The processors defining the shared boundary
27110  // 2) The shared boundary id
27111  // 3) The index of the node on the shared boundary
27112  Vector<unsigned> other_processor_1;
27113  Vector<unsigned> other_processor_2;
27114  Vector<unsigned> shd_bnd_ids;
27115  Vector<unsigned> indexes;
27116  // Loop over the processors again
27117  for (unsigned jproc = 0; jproc < nproc; jproc++)
27118  {
27119  // Do not search with the iproc processor, that was done before
27120  // above
27121  if (jproc != iproc)
27122  {
27123  // Get the number of shared boundaries with the jproc
27124  // processor
27125  const unsigned n_jshd_bnd = this->nshared_boundaries(my_rank, jproc);
27126  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
27127  {
27128  // Get the boundary id
27129  const unsigned j_shd_bnd =
27130  this->shared_boundaries_ids(my_rank, jproc, bb);
27131  // Is the node part of this boundary?
27132  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
27133  {
27134  // Include the first processor
27135  other_processor_1.push_back(my_rank);
27136  // Include the second processor
27137  other_processor_2.push_back(jproc);
27138  // Include the shared boundary id
27139  shd_bnd_ids.push_back(j_shd_bnd);
27140  // Increase the counter for found shared boundaries with
27141  // other processors
27142  counter_shd_bnd_with_other_procs_have_node++;
27143  }
27144 
27145  } // for (bb < nshared_bnd)
27146 
27147  } // if (jproc != iproc)
27148 
27149  } // for (jproc < nproc)
27150 
27151  // Get the indexes of the node on all the shared boundaries where
27152  // it was found
27153  const unsigned n_other_processors = other_processor_1.size();
27154  // Loop over the processors where the node was found
27155  for (unsigned i = 0; i < n_other_processors; i++)
27156  {
27157  // Get the shared boundary id
27158  unsigned shd_bnd_id = shd_bnd_ids[i];
27159  // Get the number of nodes on that shared boundary
27160  const unsigned n_nodes_on_shd_bnd =
27161  nsorted_shared_boundary_node(shd_bnd_id);
27162 
27163 #ifdef PARANOID
27164  bool found_index_node_on_shared_boundary = false;
27165 #endif
27166  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
27167  {
27168  // Get the i-th shared boundary node
27169  Node* shared_node_pt = sorted_shared_boundary_node_pt(shd_bnd_id, i);
27170  // Is the same node?
27171  if (shared_node_pt == nod_pt)
27172  {
27173  // DEBP(i_node);
27174  // DEBP(nod_pt->x(0));
27175  // DEBP(nod_pt->x(1));
27176  // Include the index of the node
27177  indexes.push_back(i);
27178 #ifdef PARANOID
27179  // Mark as found the node
27180  found_index_node_on_shared_boundary = true;
27181 #endif
27182  break;
27183  } // if (shared_node_pt == nod_pt)
27184 
27185  } // for (i < n_nodes_on_shd_bnd)
27186 
27187 #ifdef PARANOID
27188  if (!found_index_node_on_shared_boundary)
27189  {
27190  std::ostringstream error_message;
27191  error_message << "The index of the node on boundary (" << shd_bnd_id
27192  << "), shared by other processors\nwas not found.\n"
27193  << "The node coordinates are (" << nod_pt->x(0) << ","
27194  << nod_pt->x(1) << ").\n";
27195  throw OomphLibError(
27196  error_message.str(),
27197  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27198  OOMPH_EXCEPTION_LOCATION);
27199  }
27200 #endif
27201  } // for (i < n_other_processors)
27202 
27203  // Now send the info. but first check that the number of found
27204  // nodes be the same that the previously found shared boundaries
27205  // with the node
27206 #ifdef PARANOID
27207  if (counter_shd_bnd_with_other_procs_have_node !=
27208  nshared_boundaries_with_other_processors_have_node)
27209  {
27210  std::ostringstream error_message;
27211  error_message << "The number of shared boundaries where the node is on "
27212  << "is different:\n"
27213  << "nshared_boundaries_with_other_processors_have_node: ("
27214  << nshared_boundaries_with_other_processors_have_node
27215  << ")\n"
27216  << "counter_shd_bnd_with_other_procs_have_node: ("
27217  << counter_shd_bnd_with_other_procs_have_node << ")\n";
27218  throw OomphLibError(
27219  error_message.str(),
27220  "RefineableTriangleMesh::get_required_nodal_information_helper()",
27221  OOMPH_EXCEPTION_LOCATION);
27222  } // if (counter_shd_bnd_with_other_procs_have_node !=
27223  // nshared_boundaries_with_other_processors_have_node)
27224 #endif
27225 
27226  // Loop over the info. to send it
27227  for (unsigned i = 0; i < n_other_processors; i++)
27228  {
27229  Flat_packed_unsigneds.push_back(other_processor_1[i]);
27230 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27231  std::stringstream junk1;
27232  junk1 << "Processor where the other shared boundary "
27233  << "has the node: " << other_processor_1[i];
27234  Flat_packed_unsigneds_string.push_back(junk1.str());
27235 #endif
27236 
27237  Flat_packed_unsigneds.push_back(other_processor_2[i]);
27238 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27239  std::stringstream junk2;
27240  junk2 << "Processor where the other shared boundary "
27241  << "has the node: " << other_processor_2[i];
27242  Flat_packed_unsigneds_string.push_back(junk2.str());
27243 #endif
27244 
27245  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
27246 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27247  std::stringstream junk3;
27248  junk3 << "Other shared boundary id where the node is on"
27249  << boundaries[i];
27250  Flat_packed_unsigneds_string.push_back(junk3.str());
27251 #endif
27252 
27253  Flat_packed_unsigneds.push_back(indexes[i]);
27254 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27255  std::stringstream junk4;
27256  junk4 << "Node index on other shared boundary " << boundaries[i]
27257  << " is " << indexes[i];
27258  Flat_packed_unsigneds_string.push_back(junk4.str());
27259 #endif
27260 
27261  } // for (i < n_other_processors)
27262 
27263  } // if (node_on_shared_boundary_with_other_processors)
27264  else
27265  {
27266  Flat_packed_unsigneds.push_back(0);
27267 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27268  Flat_packed_unsigneds_string.push_back(
27269  "Node is on any shared boundary with other processors");
27270 #endif
27271  } // else if (node_on_shared_boundary_with_other_processors)
27272 
27273  // It may still be possible that the node be shared with the
27274  // processor that receives the info. but it is neither on shared
27275  // boundary with the receiver processor nor on a shared boundary
27276  // with others processors. Think in the next case:
27277 
27278  // |-----|-----| - The elements in processor 3 need to be sent to
27279  // | 4 | 3 | processor 1, and that is all
27280  // |-----*-----| - When processor 1 receives the data from node (*)
27281  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
27282  // |-----|-----| that the node is also on the shared boundary that
27283  // processor 1 and 2 or processor 1 and 4 share.
27284 
27285  // This problem become even worse if there would be more processors
27286  // between processor 3 and 2, or/and processor 3 and 4. Think in
27287  // triangles sharing the node (*)
27288 
27289  // To solve this check if the node that we are trying to send is
27290  // part of the halo elements of the curreent processor (my_rank)
27291  // with any other processor (we need to check with all the
27292  // processors and not just with the processors to which we will send
27293  // to cover more cases)
27294 
27295  // Store the halo element number with jproc where the node was found
27296  Vector<Vector<unsigned>> halo_element_number(nproc);
27297  // Store the node number on the halo element where the node was found
27298  Vector<Vector<unsigned>> halo_node_number_in_halo_element(nproc);
27299 
27300  // Loop over the processor
27301  for (unsigned jproc = 0; jproc < nproc; jproc++)
27302  {
27303  // Get the number of halo elements with the jproc processor
27304  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27305  // Loop over the halo elements
27306  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27307  {
27308  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27309  // Get the number of nodes of the halo element
27310  const unsigned n_node = halo_ele_pt->nnode();
27311  // Loop over the nodes
27312  for (unsigned n = 0; n < n_node; n++)
27313  {
27314  // Is the node part of the ih-th halo element with jproc
27315  if (nod_pt == halo_ele_pt->node_pt(n))
27316  {
27317  halo_element_number[jproc].push_back(jh);
27318  halo_node_number_in_halo_element[jproc].push_back(n);
27319  // break with the nodes, no need to look for more nodes in
27320  // the element
27321  break;
27322  } // if (nod_pt == halo_ele_pt->node_pt(n))
27323 
27324  } // for (n < n_node)
27325 
27326  } // for (jh < n_halo_jproc)
27327 
27328  } // for (jproc < nproc)
27329 
27330  // Send the info. related with if the node is on halo elements with
27331  // any processor
27332 
27333  // Loop over the processors
27334  for (unsigned jproc = 0; jproc < nproc; jproc++)
27335  {
27336  // Get the number of halo elements with jproc processor where the
27337  // node is
27338  const unsigned n_jproc_halo_ele_node_is_on =
27339  halo_element_number[jproc].size();
27340  // Send the number of halo elements with jproc where the node is
27341  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27342 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27343  std::stringstream junk5;
27344  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27345  << "elements with " << jproc << "-th processor";
27346  Flat_packed_unsigneds_string.push_back(junk5.str());
27347 #endif
27348  // Send the halo elements indexes (which will be haloed elements
27349  // indexes in the receiver processor), and the indexes of the
27350  // nodes in each halo element
27351  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27352  {
27353  // The halo element index
27354  const unsigned halo_element_index = halo_element_number[jproc][i];
27355  Flat_packed_unsigneds.push_back(halo_element_index);
27356 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27357  std::stringstream junk6;
27358  junk6 << "Halo element index is (" << halo_element_index
27359  << ") with processor (" << jproc << ")";
27360  Flat_packed_unsigneds_string.push_back(junk6.str());
27361 #endif
27362  // The node index on the halo element
27363  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27364  Flat_packed_unsigneds.push_back(node_index);
27365 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27366  std::stringstream junk7;
27367  junk7 << "The node index on the halo element index is (" << node_index;
27368  Flat_packed_unsigneds_string.push_back(junk7.str());
27369 #endif
27370 
27371  } // for (i < n_jproc_halo_ele_node_is_on)
27372 
27373  } // for (jproc < nproc)
27374 
27375  // Now check if it is required to send the info. of the node. If the
27376  // node is not on a shared boundary with the iproc processor then we
27377  // need to send the info.
27378 
27379  // Flag to indicate if it is on a halo element with the iproc
27380  // processor. If this flag is true then there is no need to send the
27381  // info. to create the node, in the receiver processor the info is
27382  // copied from the indicated haloed element-node
27383  bool on_halo_element_with_iproc_processor = false;
27384  if (halo_element_number[iproc].size() > 0)
27385  {
27386  on_halo_element_with_iproc_processor = true;
27387  } // if (halo_element_number[iproc].size() > 0)
27388 
27389  // if (!node_on_shared_boundary)
27390  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27391  {
27392  // Send all the info. to create it
27393 
27394  // Is the Node algebraic? If so, send its ref values and
27395  // an indication of its geometric objects if they are stored
27396  // in the algebraic mesh
27397  AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
27398  if (alg_nod_pt != 0)
27399  {
27400  // The external mesh should be algebraic
27401  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
27402 
27403  // Get default node update function ID
27404  unsigned update_id = alg_nod_pt->node_update_fct_id();
27405  Flat_packed_unsigneds.push_back(update_id);
27406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27407  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27408 #endif
27409 
27410  // Get reference values at default...
27411  unsigned n_ref_val = alg_nod_pt->nref_value();
27412  Flat_packed_unsigneds.push_back(n_ref_val);
27413 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27414  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27415 #endif
27416  for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
27417  {
27418  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27419  }
27420 
27421  // Access geometric objects at default...
27422  unsigned n_geom_obj = alg_nod_pt->ngeom_object();
27423  Flat_packed_unsigneds.push_back(n_geom_obj);
27424 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27425  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27426 #endif
27427  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
27428  {
27429  GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
27430 
27431  // Check this against the stored geometric objects in mesh
27432  unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
27433 
27434  // Default found index to zero
27435  unsigned found_geom_object = 0;
27436  for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
27437  {
27438  if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
27439  {
27440  found_geom_object = i_list;
27441  }
27442  }
27443  Flat_packed_unsigneds.push_back(found_geom_object);
27444 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27445  Flat_packed_unsigneds_string.push_back("Found geom object");
27446 #endif
27447  }
27448  } // (if alg_nod_pt!=0)
27449 
27450  // Is it a SolidNode?
27451  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
27452  if (solid_nod_pt != 0)
27453  {
27454  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
27455  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
27456  {
27457  for (unsigned t = 0; t < n_prev; t++)
27458  {
27459  Flat_packed_doubles.push_back(
27460  solid_nod_pt->variable_position_pt()->value(t, i_val));
27461  }
27462  }
27463 
27464  Vector<double> values_solid_node;
27465  solid_nod_pt->add_values_to_vector(values_solid_node);
27466  const unsigned nvalues_solid_node = values_solid_node.size();
27467  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27468 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27469  std::stringstream junk;
27470  junk << "Number of values solid node: " << nvalues_solid_node;
27471  Flat_packed_unsigneds_string.push_back(junk.str());
27472 #endif
27473  for (unsigned i = 0; i < nvalues_solid_node; i++)
27474  {
27475  Flat_packed_doubles.push_back(values_solid_node[i]);
27476  }
27477  }
27478 
27479  // Finally copy info required for all node types
27480  for (unsigned i_val = 0; i_val < n_val; i_val++)
27481  {
27482  for (unsigned t = 0; t < n_prev; t++)
27483  {
27484  Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
27485  }
27486  }
27487 
27488  // Now do positions
27489  for (unsigned idim = 0; idim < n_dim; idim++)
27490  {
27491  for (unsigned t = 0; t < n_prev; t++)
27492  {
27493  Flat_packed_doubles.push_back(nod_pt->x(t, idim));
27494  // DEBP(nod_pt->x(t,idim));
27495  }
27496  }
27497 
27498  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27499  }
27500 
27501  //======================================================================
27502  /// Helper function to create elements on the loop
27503  /// process based on the info received in
27504  /// send_and_received_elements_nodes_info
27505  //======================================================================
27506  template<class ELEMENT>
27508  unsigned& iproc,
27509  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27510  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27511  received_old_haloed_element_pt,
27512  Vector<FiniteElement*>& new_elements_on_domain,
27513  Vector<Node*>& new_nodes_on_domain,
27514  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27515  other_proc_shd_bnd_node_pt,
27516  Vector<Vector<Vector<unsigned>>>& global_node_names,
27517  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27518  Vector<Node*>& global_shared_node_pt)
27519  {
27520 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27521  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27522  << " Bool: New element needs to be constructed "
27523  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27524  << std::endl;
27525 #endif
27526 
27527  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27528  {
27529  // Create a new element from the communicated values
27530  // and coords from the process that located zeta
27531  GeneralisedElement* new_el_pt = new ELEMENT;
27532 
27533  // Add the new element to the mesh - Do not add the element yet
27534  // since no retained elements still need to be deleted
27535  // this->add_element_pt(new_el_pt);
27536 
27537  // Cast to the FE pointer
27538  FiniteElement* f_el_pt = dynamic_cast<FiniteElement*>(new_el_pt);
27539 
27540  // Add the element to the new elements in the domain container
27541  new_elements_on_domain.push_back(f_el_pt);
27542 
27543  // Set any additional information for the element
27544  this->add_element_load_balance_helper(
27545  iproc, received_old_haloed_element_pt, f_el_pt);
27546 
27547  // Add nodes to the new element
27548  unsigned n_node = f_el_pt->nnode();
27549  for (unsigned j = 0; j < n_node; j++)
27550  {
27551  Node* new_nod_pt = 0;
27552 
27553  // Call the add halo node helper function
27554  add_received_node_load_balance_helper(new_nod_pt,
27555  f_haloed_ele_pt,
27556  received_old_haloed_element_pt,
27557  new_nodes_on_domain,
27558  other_proc_shd_bnd_node_pt,
27559  iproc,
27560  j,
27561  f_el_pt,
27562  global_node_names,
27563  node_name_to_global_index,
27564  global_shared_node_pt);
27565  }
27566  }
27567  else // the element already exists
27568  {
27569 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27570  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27571  << " Index of existing element "
27572  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27573  << std::endl;
27574 #endif
27575 
27576  // Incrase the index, we do anything else with the element
27577  Counter_for_flat_packed_unsigneds++;
27578 
27579  } // else the element already exists
27580  }
27581 
27582  //========start of add_element_load_balance_helper=====================
27583  /// Helper function to create elements on the loop
27584  /// process based on the info received in
27585  /// send_and_received_elements_nodes_info
27586  /// This function is in charge of verify if the element is associated
27587  /// to a boundary and associate to it if that is the case
27588  //======================================================================
27589  template<class ELEMENT>
27591  const unsigned& iproc,
27592  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27593  received_old_haloed_element_pt,
27594  FiniteElement* ele_pt)
27595  {
27596  // Get the number of processors
27597  const unsigned nproc = this->communicator_pt()->nproc();
27598 
27599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27600  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27601  << " Bool: Element is associated to a boundary "
27602  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27603  << std::endl;
27604 #endif
27605 
27606  // Is on an original boundary?
27607  const unsigned is_on_original_boundary =
27608  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27609  if (is_on_original_boundary == 1)
27610  {
27611 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27612  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27613  << " How many boundaries are associated with the element "
27614  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27615  << std::endl;
27616 #endif
27617  // Number of boundaries the element is associated with
27618  const unsigned nassociated_boundaries =
27619  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27620 
27621  // Loop over the associated boundaries
27622  for (unsigned b = 0; b < nassociated_boundaries; b++)
27623  {
27624 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27625  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27626  << " Boundary associated to the element "
27627  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27628  << std::endl;
27629 #endif
27630 
27631  // The boundary id
27632  const unsigned bnd =
27633  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27634 
27635 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27636  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27637  << " Face index of the element "
27638  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27639  << std::endl;
27640 #endif
27641 
27642  // The face index
27643  const unsigned face_index =
27644  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27645 
27646  // Associate the element with the boundary and establish as many
27647  // face indexes it has
27648  this->Boundary_element_pt[bnd].push_back(ele_pt);
27649  this->Face_index_at_boundary[bnd].push_back(face_index);
27650 
27651  } // (b < nassociated_boundaries)
27652 
27653  // Here read the info. regarding the boundary-region of the element
27654 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27655  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27656  << " Bool: Element is associated to a boundary-region "
27657  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27658  << std::endl;
27659 #endif
27660 
27661  // Is the element associated to a boundary-region?
27662  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27663  {
27664 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27665  oomph_info
27666  << "Rec:" << Counter_for_flat_packed_unsigneds
27667  << " How many boundaries-regions are associated with the element "
27668  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27669  << std::endl;
27670 #endif
27671  // Number of boundary-regions the element is associated
27672  const unsigned nassociated_boundaries_and_regions =
27673  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27674 
27675  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27676  {
27677 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27678  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27679  << " Boundary associated to the element "
27680  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27681  << std::endl;
27682 #endif
27683  // The boundary id
27684  const unsigned bnd =
27685  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27686 
27687 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27688  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27689  << " Region associated to the element "
27690  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27691  << std::endl;
27692 #endif
27693  // The region id
27694  const unsigned region =
27695  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27696 
27697 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27698  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27699  << " Face index of the element in boundary-region "
27700  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27701  << std::endl;
27702 #endif
27703  const unsigned face_index =
27704  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27705 
27706  // Associate the element with the boundary-regions and establish
27707  // as many face indexes it has
27708  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27709  this->Face_index_region_at_boundary[bnd][region].push_back(
27710  face_index);
27711 
27712  } // for (br < nassociated_boundaries_and_regions)
27713 
27714  } // Is the element associated with a boundary-region?
27715 
27716  } // The element is associated with an original boundary
27717 #ifdef PARANOID
27718  else
27719  {
27720  if (is_on_original_boundary != 0)
27721  {
27722  std::ostringstream error_message;
27723  error_message
27724  << "The current element is not on an original boundary, this should\n"
27725  << "be indicated by a zero flag. However, the read value for\n"
27726  << "that flag is (" << is_on_original_boundary << ").\n\n";
27727  throw OomphLibError(
27728  error_message.str(),
27729  "RefineableTriangleMesh::add_element_load_balance_helper()",
27730  OOMPH_EXCEPTION_LOCATION);
27731  } // if (is_on_shared_boundary != 0)
27732  }
27733 #endif
27734 
27735 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27736  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27737  << " Bool: Element is associated to a shared boundary "
27738  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27739  << std::endl;
27740 #endif
27741 
27742  // Is the element a shared boundary element?
27743  const unsigned is_on_shared_boundary =
27744  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27745  if (is_on_shared_boundary == 3)
27746  {
27747 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27748  oomph_info
27749  << "Rec:" << Counter_for_flat_packed_unsigneds
27750  << " How many shared boundaries are associated with the element "
27751  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27752  << std::endl;
27753 #endif
27754 
27755  // The number of shared boundaries the element is associated
27756  const unsigned nassociated_shared_boundaries =
27757  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27758 
27759  // Loop over the associated shared boundaries
27760  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27761  {
27762 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27763  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27764  << " Shared boundary associated to the element "
27765  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27766  << std::endl;
27767 #endif
27768  const unsigned bnd =
27769  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27770 
27771 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27772  oomph_info
27773  << "Rec:" << Counter_for_flat_packed_unsigneds
27774  << " Face index of the element associated to the shared boundary "
27775  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27776  << std::endl;
27777 #endif
27778 
27779  const unsigned face_index =
27780  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27781 
27782  this->add_shared_boundary_element(bnd, ele_pt);
27783  this->add_face_index_at_shared_boundary(bnd, face_index);
27784 
27785  } // (b < nassociated_shared_boundaries)
27786 
27787  } // The element is associted with a shared boundary
27788 #ifdef PARANOID
27789  else
27790  {
27791  if (is_on_shared_boundary != 0)
27792  {
27793  std::ostringstream error_message;
27794  error_message
27795  << "The current element is not on a shared boundary, this should\n"
27796  << "be indicated by a zero flag. However, the read value for\n"
27797  << "that flag is (" << is_on_shared_boundary << ").\n\n";
27798  throw OomphLibError(
27799  error_message.str(),
27800  "RefineableTriangleMesh::add_element_load_balance_helper()",
27801  OOMPH_EXCEPTION_LOCATION);
27802  } // if (is_on_shared_boundary != 0)
27803  }
27804 #endif
27805 
27806  // Now check if the element is a haloed element in the sender
27807  // processor with any other processor
27808 
27809  // Loop over the processors
27810  for (unsigned jproc = 0; jproc < nproc; jproc++)
27811  {
27812 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27813  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27814  << " Bool: Number of haloed indexes of the element with the "
27815  << jproc << " processor: "
27816  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27817  << std::endl;
27818 #endif
27819  // Is the element haloed with the jproc processor
27820  const unsigned n_index_haloed_jproc =
27821  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27822  // Loop over the number of haloed indexes
27823  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27824  {
27825 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27826  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27827  << " Bool: The haloed element index with the " << jproc
27828  << " processor: "
27829  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27830  << std::endl;
27831 #endif
27832  const unsigned haloed_index =
27833  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27834 
27835  // Set the halod element in the proper storage
27836  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27837 
27838  } // for (ihd < n_index_haloed_jproc)
27839 
27840  } // for (jproc < nproc)
27841  }
27842 
27843  //======================================================================
27844  /// Helper function to add a new node from load balance
27845  //======================================================================
27846  template<class ELEMENT>
27848  Node*& new_nod_pt,
27849  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27850  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27851  received_old_haloed_element_pt,
27852  Vector<Node*>& new_nodes_on_domain,
27853  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27854  other_proc_shd_bnd_node_pt,
27855  unsigned& iproc,
27856  unsigned& node_index,
27857  FiniteElement* const& new_el_pt,
27858  Vector<Vector<Vector<unsigned>>>& global_node_names,
27859  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27860  Vector<Node*>& global_shared_node_pt)
27861  {
27862  // Given the node, received information about it from processor
27863  // iproc, construct it on the current process
27864 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27865  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27866  << " Bool: New node needs to be constructed "
27867  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27868  << std::endl;
27869 #endif
27870  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++] == 1)
27871  {
27872  // Construct a new node based upon sent information, or copy a node
27873  // from one of the shared boundaries
27874  construct_new_node_load_balance_helper(new_nod_pt,
27875  f_haloed_ele_pt,
27876  received_old_haloed_element_pt,
27877  new_nodes_on_domain,
27878  other_proc_shd_bnd_node_pt,
27879  iproc,
27880  node_index,
27881  new_el_pt,
27882  global_node_names,
27883  node_name_to_global_index,
27884  global_shared_node_pt);
27885  }
27886  else
27887  {
27888 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27889  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27890  << " Index of existing halo node "
27891  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27892  << std::endl;
27893 #endif
27894  // The node already exist, copy it from the indicated position
27895 
27896  // Get the node's index, and copy it
27897  new_nod_pt = new_nodes_on_domain
27898  [Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
27899 
27900  // Set the node in the current element
27901  new_el_pt->node_pt(node_index) = new_nod_pt;
27902  }
27903  }
27904 
27905  //============start_of_construct_new_node_load_balance_helper()=========
27906  /// Helper function which constructs a new node (on an
27907  /// element) with the information sent from the load balance
27908  /// process
27909  //======================================================================
27910  template<class ELEMENT>
27912  Node*& new_nod_pt,
27913  Vector<Vector<FiniteElement*>>& f_haloed_ele_pt,
27914  Vector<Vector<std::map<unsigned, FiniteElement*>>>&
27915  received_old_haloed_element_pt,
27916  Vector<Node*>& new_nodes_on_domain,
27917  Vector<Vector<Vector<std::map<unsigned, Node*>>>>&
27918  other_proc_shd_bnd_node_pt,
27919  unsigned& iproc,
27920  unsigned& node_index,
27921  FiniteElement* const& new_el_pt,
27922  Vector<Vector<Vector<unsigned>>>& global_node_names,
27923  std::map<Vector<unsigned>, unsigned>& node_name_to_global_index,
27924  Vector<Node*>& global_shared_node_pt)
27925  {
27926  // Get the number of processors
27927  const unsigned nproc = this->communicator_pt()->nproc();
27928  // Get the rank of the current processor
27929  const unsigned my_rank = this->communicator_pt()->my_rank();
27930 
27931  // The first entry indicates the number of values at this new Node
27932  //(which may be different across the same element e.g. Lagrange multipliers)
27933 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27934  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27935  << " Number of values of external halo node "
27936  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27937  << std::endl;
27938 #endif
27939  unsigned n_val = Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27940 
27941  // Null TimeStepper for now
27942  TimeStepper* time_stepper_pt = this->Time_stepper_pt;
27943  // Default number of previous values to 1
27944  unsigned n_prev = time_stepper_pt->ntstorage();
27945 
27946  // ------------------------------------------------------
27947  // Check if the node is on an original boundary
27948 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27949  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27950  << " Is the node on an original boundary "
27951  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27952  << std::endl;
27953 #endif
27954 
27955  // Flag to indicate if the node is on original boundaries
27956  const unsigned node_on_original_boundaries =
27957  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27958 
27959  // Store the original boundaries where the node is on
27960  Vector<unsigned> original_boundaries_node_is_on;
27961  // Store the zeta coordinates of the node on the original boundaries
27962  Vector<double> zeta_coordinates;
27963  // Store the number of original boundaries the node is on
27964  unsigned n_original_boundaries_node_is_on = 0;
27965 
27966  if (node_on_original_boundaries == 2)
27967  {
27968  // How many original boundaries does the node live on?
27969 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27970  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27971  << " Number of boundaries the node is on: "
27972  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27973  << std::endl;
27974 #endif
27975  n_original_boundaries_node_is_on =
27976  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27977 
27978  // Resize the containers
27979  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27980  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27981 
27982  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
27983  {
27984  // Boundary number
27985 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27986  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27987  << " Node is on boundary "
27988  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27989  << std::endl;
27990 #endif
27991  original_boundaries_node_is_on[i] =
27992  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27993  zeta_coordinates[i] =
27994  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
27995  }
27996 
27997  } // if (node_on_original_boundaries==2)
27998 #ifdef PARANOID
27999  else
28000  {
28001  if (node_on_original_boundaries != 0)
28002  {
28003  std::ostringstream error_message;
28004  error_message
28005  << "The current node is not on an original boundary, this should\n"
28006  << "be indicated by a zero flag. However, the read value for\n"
28007  << "that flag is (" << node_on_original_boundaries << ").\n\n";
28008  throw OomphLibError(
28009  error_message.str(),
28010  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28011  OOMPH_EXCEPTION_LOCATION);
28012  } // if (node_on_original_boundaries != 0)
28013  }
28014 #endif
28015 
28016  // --------------------------------------------------------------
28017  // Check if the node was on a shared boundary with the iproc
28018  // processor
28019 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28020  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28021  << " Is node on shared boundary? "
28022  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28023  << std::endl;
28024 #endif
28025  const unsigned is_node_on_shared_boundary =
28026  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28027  if (is_node_on_shared_boundary == 1)
28028  {
28029  // How many shared boundaries does the node live on?
28030 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28031  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28032  << " Number of boundaries the node is on: "
28033  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28034  << std::endl;
28035 #endif
28036  const unsigned n_shd_bnd_node_is_on =
28037  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28038  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
28039  for (unsigned i = 0; i < n_shd_bnd_node_is_on; i++)
28040  {
28041  // Shared boundary number
28042 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28043  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28044  << " Node is on boundary "
28045  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28046  << std::endl;
28047 #endif
28048  shd_bnds_node_is_on[i] =
28049  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28050  }
28051 
28052  // Get the index of the node on the shared boundary
28053 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28054  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28055  << " Index of node on boundary "
28056  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28057  << std::endl;
28058 #endif
28059  // Get the node index of the node on the shared boundary
28060  unsigned node_index_on_shared_boundary =
28061  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28062 
28063  // Get the pointer to the node with the received info.
28064  new_nod_pt = this->sorted_shared_boundary_node_pt(
28065  shd_bnds_node_is_on[0], node_index_on_shared_boundary);
28066 
28067  } // if (is_node_on_shared_boundary == 1)
28068 #ifdef PARANOID
28069  else
28070  {
28071  if (is_node_on_shared_boundary != 0)
28072  {
28073  std::ostringstream error_message;
28074  error_message
28075  << "The current node is not on a shared boundary, this should\n"
28076  << "be indicated by a zero flag. However, the read value for\n"
28077  << "that flag is (" << is_node_on_shared_boundary << ").\n\n";
28078  throw OomphLibError(
28079  error_message.str(),
28080  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28081  OOMPH_EXCEPTION_LOCATION);
28082  } // if (node_on_shared_boundary != 0)
28083  }
28084 #endif
28085 
28086  // ------------------------------------------------------------
28087  // Is the node on a shared boundary with other processor?
28088 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28089  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28090  << " Is the node on shared boundaries with other processors "
28091  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28092  << std::endl;
28093 #endif
28094 
28095  // Is the node in shared boundaries no associated with the
28096  // receiver processor
28097  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
28098  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28099 
28100  // The containers where to store the info.
28101  Vector<unsigned> other_processor_1;
28102  Vector<unsigned> other_processor_2;
28103  Vector<unsigned> other_shared_boundaries;
28104  Vector<unsigned> other_indexes;
28105 
28106  // How many shared bounaries with other processors the node lives on
28107  unsigned n_shd_bnd_with_other_procs_have_node = 0;
28108 
28109  // Is the node on shared boundaries with other processors
28110  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28111  {
28112 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28113  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28114  << " In how many shared boundaries with other "
28115  << "processors is the node "
28116  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28117  << std::endl;
28118 #endif
28119 
28120  // How many nodes on other shared boundaries were found
28121  n_shd_bnd_with_other_procs_have_node =
28122  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28123 
28124  // Resize the containers
28125  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
28126  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
28127  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
28128  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
28129 
28130  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28131  {
28132 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28133  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28134  << " Processor where the other shared boundary"
28135  << "has the node"
28136  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28137  << std::endl;
28138 #endif
28139  // Read the other processor 1
28140  other_processor_1[i] =
28141  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28142 
28143 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28144  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28145  << " Processor where the other shared boundary"
28146  << "has the node"
28147  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28148  << std::endl;
28149 #endif
28150  // Read the other processor 2
28151  other_processor_2[i] =
28152  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28153 
28154 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28155  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28156  << " Other shared boundary id where the node is on: "
28157  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28158  << std::endl;
28159 #endif
28160 
28161  // Read the other shared boundary id
28162  other_shared_boundaries[i] =
28163  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28164 
28165 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28166  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28167  << " Node index on the other shared boundary "
28168  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28169  << std::endl;
28170 #endif
28171 
28172  // Read the node index on the other shared boundary
28173  other_indexes[i] =
28174  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28175 
28176  } // for (i < n_shd_bnd_with_other_procs_have_node)
28177 
28178  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28179 #ifdef PARANOID
28180  else
28181  {
28182  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
28183  {
28184  std::ostringstream error_message;
28185  error_message
28186  << "The current node is not on a shared boundary with\n"
28187  << "other processors, this should be indicated by a zero flag.\n"
28188  << "However, the read value for that flag is ("
28189  << is_the_node_in_shared_boundaries_with_other_processors << ").\n\n";
28190  throw OomphLibError(
28191  error_message.str(),
28192  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28193  OOMPH_EXCEPTION_LOCATION);
28194  }
28195  }
28196 #endif
28197 
28198  // ------------------------------------------------------------
28199  // Receive the info. to check if the node is on a haloed element
28200  // with any processor
28201 
28202  // Store the halo element number with jproc where the node was found
28203  Vector<Vector<unsigned>> halo_element_number(nproc);
28204  // Store the node number on the halo element where the node was found
28205  Vector<Vector<unsigned>> halo_node_number_in_halo_element(nproc);
28206 
28207  // Loop over the processors
28208  for (unsigned jproc = 0; jproc < nproc; jproc++)
28209  {
28210 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28211  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28212  << " The node is on "
28213  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28214  << " halo elements with " << jproc << " processor"
28215  << std::endl;
28216 #endif
28217  // Get the number of halo elements with jproc processor where the
28218  // node was found
28219  const unsigned n_jproc_halo_ele_node_is_on =
28220  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28221 
28222  // Resize the containers
28223  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
28224  halo_node_number_in_halo_element[jproc].resize(
28225  n_jproc_halo_ele_node_is_on);
28226 
28227  // Read halo elements indexes (which are indexes of the halo
28228  // elements of the sender processor (iproc) with other processors
28229  // (included my_rank)
28230  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
28231  {
28232  // Get the halo element index in the jproc processor
28233 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28234  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28235  << " The halo element index where the node is on "
28236  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28237  << std::endl;
28238 #endif
28239  // Get the node index on the halo element
28240  const unsigned halo_ele_index =
28241  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28242 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28243  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28244  << " The node index on the halo element where the node "
28245  << "is on "
28246  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28247  << std::endl;
28248 #endif
28249  const unsigned node_index_on_halo_ele =
28250  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28251 
28252  // Store the halo element number
28253  halo_element_number[jproc][i] = halo_ele_index;
28254  // Store the index of on the haloed element
28255  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
28256 
28257  } // for (i < n_jproc_halo_ele_node_is_on)
28258 
28259  } // for (jproc < nproc)
28260 
28261  // Store the node pointers obtained from the indicated halo elements
28262  // (use a set to check for the case when the node pointer is
28263  // different)
28264  std::set<Node*> set_haloed_node_pt;
28265 
28266  // Store the node pointer obtained from the haloed elements
28267  Node* haloed_node_pt = 0;
28268 
28269  // Flag to indicate if it is on a haloed element of the current
28270  // processor with the iproc processor. If this flag is true then
28271  // there is no need to read the info. to create the node, only copy
28272  // the node from the indicated haloed element-node
28273  bool on_haloed_element_with_iproc_processor = false;
28274  if (halo_element_number[my_rank].size() > 0)
28275  {
28276  // The node is part of the haloed element in the current processor
28277  // (my_rank) with the receiver processor
28278  on_haloed_element_with_iproc_processor = true;
28279 
28280  // Get the number of haloed elements in the current processor
28281  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28282  // Loop over the different haloed indexes, and get the nodes
28283  // instances from all the indicated haloed elements (all of them
28284  // should be the same)
28285  for (unsigned i = 0; i < n_haloed_indexes; i++)
28286  {
28287  // Get the haloed element numbers where the node is on
28288  const unsigned haloed_index = halo_element_number[my_rank][i];
28289  // Get the node index on the haloed element
28290  const unsigned haloed_node_index =
28291  halo_node_number_in_halo_element[my_rank][i];
28292 
28293  // Get the haloed element (with iproc)
28294  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28295  // Get the node on the indicated node number
28296  Node* tmp_haloed_node_pt =
28297  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28298 
28299  // Set the pointer for the obtained haloed node
28300  haloed_node_pt = tmp_haloed_node_pt;
28301 
28302  // Add the node to the set of node pointers
28303  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28304 
28305 #ifdef PARANOID
28306  if (set_haloed_node_pt.size() > 1)
28307  {
28308  std::ostringstream error_message;
28309  error_message
28310  << "When adding the " << haloed_node_index << " node of the "
28311  << haloed_index << "-th haloed element\n"
28312  << "in the currrent processor with the " << iproc << " processor"
28313  << "it was found that\nthe node pointer is different from the other"
28314  << "instances of the node.\nIt means we have a repeated node."
28315  << "This are the node coordinates of the previous node instances\n"
28316  << "The last entry is for the just added node with a different "
28317  "node\n"
28318  << "pointer\n";
28319  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28320  it != set_haloed_node_pt.end();
28321  it++)
28322  {
28323  error_message << "Node: (" << (*it)->x(0) << ", " << (*it)->x(1)
28324  << ")\n";
28325  }
28326  error_message << "\n";
28327  throw OomphLibError(
28328  error_message.str(),
28329  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28330  OOMPH_EXCEPTION_LOCATION);
28331  }
28332 #endif
28333 
28334  } // for (i < n_haloed_indexes)
28335 
28336  } // if (halo_element_number[iproc].size() > 0)
28337 
28338  // Flag to indicate if the node has been found on a haloed element
28339  // of other processor with the iproc processor
28340  bool found_on_haloed_element_with_other_processor = false;
28341  // Loop over the processors (only until the iproc since no info. of
28342  // higher processors has been received)
28343  for (unsigned jproc = 0; jproc < iproc; jproc++)
28344  {
28345  // Is the node on a halo element with the jproc processor
28346  if (halo_element_number[jproc].size() > 0)
28347  {
28348  // Get the number of halo elements with the jproc processor
28349  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28350  // Loop over the different halo indexes, and get the nodes
28351  // instances from all the indicated halo elements (all of them
28352  // should be the same)
28353  for (unsigned i = 0; i < n_halo_indexes; i++)
28354  {
28355  // Get the haloed element numbers where the node is on
28356  const unsigned haloed_index = halo_element_number[jproc][i];
28357  // Get the node index on the haloed element
28358  const unsigned haloed_node_index =
28359  halo_node_number_in_halo_element[jproc][i];
28360 
28361  // Have we received the indicated element? (Get the haloed
28362  // element on jproc with the iproc processor)
28363  std::map<unsigned, FiniteElement*>::iterator it_map =
28364  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28365  // Have we received the indicated element?
28366  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28367  {
28368  // Set the flag of found element in other processors haloed
28369  // element, in this case in haloed elements of processor
28370  // jproc wiht iproc processor
28371  found_on_haloed_element_with_other_processor = true;
28372 
28373  // Get the element
28374  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28375  // Get the node on the indicated node number
28376  Node* tmp_haloed_node_pt =
28377  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28378 
28379  // Set the pointer for the obtained haloed node
28380  haloed_node_pt = tmp_haloed_node_pt;
28381 
28382  // Add the node to the set of node pointers
28383  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28384 
28385 #ifdef PARANOID
28386  if (set_haloed_node_pt.size() > 1)
28387  {
28388  std::ostringstream error_message;
28389  error_message
28390  << "When adding the " << haloed_node_index << " node of the "
28391  << haloed_index << "-th haloed element "
28392  << "of the " << jproc << " processor\nwith the " << iproc
28393  << " processor, it was found that\n"
28394  << "the node pointer is different from the other\n"
28395  << "instances of the node.\nThis means we have a repeated "
28396  "node.\n"
28397  << "These are the node coordinates of the previous node "
28398  << "instances\n"
28399  << "The last entry is for the just added node with a "
28400  "different\n"
28401  << "node pointer\n";
28402  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28403  it != set_haloed_node_pt.end();
28404  it++)
28405  {
28406  error_message << "Node: (" << (*it)->x(0) << ", " << (*it)->x(1)
28407  << ")\n";
28408  }
28409  error_message << "\n";
28410  throw OomphLibError(error_message.str(),
28411  "RefineableTriangleMesh::construct_new_node_"
28412  "load_balance_helper()",
28413  OOMPH_EXCEPTION_LOCATION);
28414  }
28415 #endif
28416 
28417  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28418  // Have we received the element?
28419 
28420  } // for (i < n_haloed_indexes)
28421 
28422  } // if (halo_element_number[iproc].size() > 0)
28423 
28424  } // for (jproc < nproc)
28425 
28426  // If the node was found in the haloed elements of the current
28427  // processor with the iproc processor, or in the haloed elements of
28428  // any other processor with the iproc processor then copy the node
28429  // pointer (no problem if we overwrite the node info. it should be
28430  // the same node pointer)
28431  if (on_haloed_element_with_iproc_processor ||
28432  found_on_haloed_element_with_other_processor)
28433  {
28434  // Set the node pointer
28435  new_nod_pt = haloed_node_pt;
28436  }
28437 
28438  // Now we have all the info. to decide if the node should be created
28439  // or not
28440 
28441  // First check if the node is a shared boundary node, or if it has
28442  // been found on haloed elements
28443  if (is_node_on_shared_boundary == 1 ||
28444  (on_haloed_element_with_iproc_processor))
28445  {
28446  // We already have the node, we do not need to create it
28447 
28448  // Only check if we need to add boundary info. to the node
28449  if (node_on_original_boundaries == 2)
28450  {
28451  // The node is a boundary node, add the boundary info. before
28452  // adding it to the domain
28453 
28454  // Associate the node to the given boundaries
28455  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28456  {
28457  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28458  // Establish the boundary coordinates for the node
28459  Vector<double> zeta(1);
28460  zeta[0] = zeta_coordinates[i];
28461  new_nod_pt->set_coordinates_on_boundary(
28462  original_boundaries_node_is_on[i], zeta);
28463  }
28464 
28465  } // if (node_on_original_boundaries==2)
28466 
28467  // Add the node to the domain
28468  new_nodes_on_domain.push_back(new_nod_pt);
28469 
28470  // Add the node to the element
28471  new_el_pt->node_pt(node_index) = new_nod_pt;
28472 
28473  } // if (is_node_on_shared_boundary == 1)
28474 
28475  // Now check if the node is on a shared boundary with another
28476  // processor, if that is the case try to find the node that may have
28477  // been already sent by the other processors
28478 
28479  // This flags indicates if the node was found, and then decide if it
28480  // is required to create the node
28481  bool found_node_in_other_shared_boundaries = false;
28482  // Flag to indicate whether the node should be created as a boundary
28483  // node or not. If the node lies on a shared boundary with other
28484  // processor the we create it as a boundary node. The processor from
28485  // which we are receiving info. (iproc) may not know that the node
28486  // lies on an original boundary. If the node lies on an original
28487  // boundary then its info. will be sent by another processor, then
28488  // we can set its boundary info. since the node was constructed as a
28489  // boundary node
28490  bool build_node_as_boundary_node = false;
28491 
28492  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28493  {
28494  // Build the node as a boundary node
28495  build_node_as_boundary_node = true;
28496 
28497  // Try to get the node pointer in case that the node has been
28498  // already sent by the other processors
28499 
28500  // Get the number of initial shared boundaries to correct the
28501  // index of the shared boundary
28502  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28503 
28504  // Add the found nodes in the container, should be the same but
28505  // better check
28506  Vector<Node*> found_node_pt;
28507 
28508  // Now try to find the node in any of the other shared boundaries
28509  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28510  {
28511  unsigned oproc1 = other_processor_1[i];
28512  unsigned oproc2 = other_processor_2[i];
28513 
28514  // Check that we always check with the lower processors number
28515  // first
28516  if (oproc1 > oproc2)
28517  {
28518  oproc2 = oproc1;
28519  oproc1 = other_processor_2[i];
28520  } // if (oproc1 > oproc2)
28521 
28522  // Re-compute the shared boundary id between the other
28523  // processors
28524  const unsigned shd_bnd_id =
28525  other_shared_boundaries[i] - initial_shd_bnd_id;
28526  // Read the index
28527  const unsigned index = other_indexes[i];
28528 
28529  // Check if there are nodes received from the other processor
28530  // and with the given shared boundary
28531  const unsigned n_nodes_on_other_processor =
28532  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28533 
28534  if (n_nodes_on_other_processor > 0)
28535  {
28536  // Check if we can find the index of the node in that other
28537  // processor and shared boundary id
28538  std::map<unsigned, Node*>::iterator it =
28539  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].find(index);
28540 
28541  // If the index exist then get the node pointer
28542  if (it !=
28543  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28544  {
28545  // Mark the node as found
28546  found_node_in_other_shared_boundaries = true;
28547  // Get the node pointer
28548  Node* tmp_node_pt =
28549  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28550  found_node_pt.push_back(tmp_node_pt);
28551  } // if (it!=
28552  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28553 
28554  } // if (n_nodes_on_other_processor > 0)
28555 
28556  } // for (i < n_shd_bnd_with_other_procs_have_node)
28557 
28558  // If the node was found, then all their instances should be the
28559  // same but better check
28560  if (found_node_in_other_shared_boundaries)
28561  {
28562 #ifdef PARANOID
28563  const unsigned ntimes_node_found = found_node_pt.size();
28564  for (unsigned j = 1; j < ntimes_node_found; j++)
28565  {
28566  if (found_node_pt[j - 1] != found_node_pt[j])
28567  {
28568  std::ostringstream error_message;
28569  error_message
28570  << "The instances of the node that was found to be on a\n"
28571  << "shared boundary with other processors are not the same,\n"
28572  << "the coordinates for the nodes are these:\n"
28573  << "(" << found_node_pt[j - 1]->x(0) << ", "
28574  << found_node_pt[j - 1]->x(1) << ")\n"
28575  << "(" << found_node_pt[j]->x(0) << ", " << found_node_pt[j]->x(1)
28576  << ")\n"
28577  << "Not be surprised if they are the same since the node is\n"
28578  << "repeated!!!\n";
28579  throw OomphLibError(
28580  error_message.str(),
28581  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28582  OOMPH_EXCEPTION_LOCATION);
28583 
28584  } // if (found_node_pt[j-1] != found_node_pt[j])
28585 
28586  } // for (j < ntimes_node_found)
28587 #endif
28588 
28589  // Check if the node is a shared boundary node from the current
28590  // processor and the iproc processor, if that is the case, and
28591  // the node is also on a shared boundary with other processor,
28592  // then the pointer should be the same!!!
28593  if (is_node_on_shared_boundary == 1)
28594  {
28595  // The pointer to the node is already assigned, it was
28596  // assigned when thenode was found to be on a shared boundary
28597  // with the iproc processor
28598  if (found_node_pt[0] != new_nod_pt)
28599  {
28600  std::ostringstream error_message;
28601  error_message
28602  << "The pointer of the node that was found to be on a\n"
28603  << "shared boundary with other processor(s) and the pointer\n"
28604  << "of the node on shared boundary with the receiver\n"
28605  << "processor (iproc) are not the same. This means we have a\n"
28606  << "repeated node)\n"
28607  << "The coordinates for the nodes are:\n"
28608  << "(" << found_node_pt[0]->x(0) << ", " << found_node_pt[0]->x(1)
28609  << ")\n"
28610  << "(" << new_nod_pt->x(0) << ", " << new_nod_pt->x(1) << ")\n"
28611  << "Not to be surprised if they are the same since the node is\n"
28612  << "repeated!!!\n";
28613  throw OomphLibError(
28614  error_message.str(),
28615  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28616  OOMPH_EXCEPTION_LOCATION);
28617  } // if (found_node_pt[0] != new_nod_pt)
28618 
28619  } // if (is_node_on_shared_boundary == 1)
28620  else
28621  {
28622  // Take the first instance of the node in case that it was
28623  // found and is not on a shared boundary with the iproc
28624  // processor
28625  new_nod_pt = found_node_pt[0];
28626  }
28627 
28628  } // if (found_node_in_other_shared_boundaries)
28629 
28630  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28631 
28632  // -----------------------------------------------------------------
28633  // Create the node or read the received info if the node is not on a
28634  // shared boundary with the iproc processor and if the node is not
28635  // part of the haloed elements with the iproc processor in the
28636  // current processors
28637  if (is_node_on_shared_boundary != 1 &&
28638  !on_haloed_element_with_iproc_processor)
28639  {
28640  // If the node is on a shared boundary with other processor we
28641  // need to read all the info. since the processor that sent the
28642  // info. did not know that the node is part of another shared
28643  // boundary
28644 
28645  // If the node is not a shared boundary (with any processor), or
28646  // if this is the first time that the info. of the node is
28647  // received from any of the processors with which is has a shared
28648  // boundary, then we create the node
28649 
28650  // Is the node a boundary node or should it be build as a boundary
28651  // node because it is on a shared boundary with other processors
28652  if (node_on_original_boundaries == 2 || build_node_as_boundary_node)
28653  {
28654  // Check if necessary to create the node, or if it has been
28655  // already found in shared boundaries with other processors or
28656  // in the haloed elements with of other processors with the
28657  // iproc processor
28658  if (!found_node_in_other_shared_boundaries ||
28659  !found_on_haloed_element_with_other_processor)
28660  {
28661  // Construct a boundary node
28662  if (time_stepper_pt != 0)
28663  {
28664  new_nod_pt =
28665  new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
28666  }
28667  else
28668  {
28669  new_nod_pt = new_el_pt->construct_boundary_node(node_index);
28670  }
28671 
28672  } // if (!found_node_in_other_shared_boundaries ||
28673  // !found_on_haloed_element_with_other_processor)
28674  else
28675  {
28676  // If the node was found then assign the node to the element
28677  new_el_pt->node_pt(node_index) = new_nod_pt;
28678  } // else if (!found_node_in_other_shared_boundaries ||
28679  // !found_on_haloed_element_with_other_processor)
28680 
28681  // Associate the node to the given boundaries
28682  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28683  {
28684  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28685  // Establish the boundary coordinates for the node
28686  Vector<double> zeta(1);
28687  zeta[0] = zeta_coordinates[i];
28688  new_nod_pt->set_coordinates_on_boundary(
28689  original_boundaries_node_is_on[i], zeta);
28690  }
28691 
28692  } // if (node is on an original boundary)
28693  else
28694  {
28695  // Check if necessary to create the node, or if it has been
28696  // already found in shared boundaries with other processors or
28697  // in the haloed elements with of other processors with the
28698  // iproc processor
28699  if (!found_node_in_other_shared_boundaries ||
28700  !found_on_haloed_element_with_other_processor)
28701  {
28702  // Construct an ordinary (non-boundary) node
28703  if (time_stepper_pt != 0)
28704  {
28705  new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
28706  }
28707  else
28708  {
28709  new_nod_pt = new_el_pt->construct_node(node_index);
28710  }
28711  } // if (!found_node_in_other_shared_boundaries ||
28712  // !found_on_haloed_element_with_other_processor)
28713  else
28714  {
28715  // If the node was found then assign the node to the element
28716  new_el_pt->node_pt(node_index) = new_nod_pt;
28717  } // else // if (!found_node_in_other_shared_boundaries ||
28718  // !found_on_haloed_element_with_other_processor)
28719 
28720  } // else (the node is not a boundary node)
28721 
28722  // ... and gather all its information
28723 
28724  // If the node was found or not in other shared boundaries, this
28725  // is the first time the node is received from this processor
28726  // (iproc), therefore it is added to the vector of nodes received
28727  // from this processor (iproc)
28728  new_nodes_on_domain.push_back(new_nod_pt);
28729 
28730  // Check if necessary to state all the info. to the node if it has
28731  // been already found in shared boundaries with other processors
28732  // or in the haloed elements with of other processors with the
28733  // iproc processor
28734  if (!found_node_in_other_shared_boundaries ||
28735  !found_on_haloed_element_with_other_processor)
28736  {
28737  // Add the node to the general node storage
28738  this->add_node_pt(new_nod_pt);
28739  } // if (!found_node_in_other_shared_boundaries ||
28740  // !found_on_haloed_element_with_other_processor)
28741 
28742  // Is the new constructed node Algebraic?
28743  AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
28744 
28745  // If it is algebraic, its node update functions will
28746  // not yet have been set up properly
28747  if (new_alg_nod_pt != 0)
28748  {
28749  // The AlgebraicMesh is the external mesh
28750  AlgebraicMesh* alg_mesh_pt = dynamic_cast<AlgebraicMesh*>(this);
28751 
28752  /// The first entry of All_alg_nodal_info contains
28753  /// the default node update id
28754  /// e.g. for the quarter circle there are
28755  /// "Upper_left_box", "Lower right box" etc...
28756 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28757  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28758  << " Alg node update id "
28759  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28760  << std::endl;
28761 #endif
28762 
28763  unsigned update_id =
28764  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28765 
28766  Vector<double> ref_value;
28767 
28768  // The size of this vector is in the next entry
28769  // of All_alg_nodal_info
28770 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28771  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28772  << " Alg node # of ref values "
28773  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28774  << std::endl;
28775 #endif
28776  unsigned n_ref_val =
28777  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28778 
28779  // The reference values themselves are in
28780  // All_alg_ref_value
28781  ref_value.resize(n_ref_val);
28782  for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
28783  {
28784  ref_value[i_ref] =
28785  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28786  }
28787 
28788  Vector<GeomObject*> geom_object_pt;
28789  /// again we need the size of this vector as it varies
28790  /// between meshes; we also need some indication
28791  /// as to which geometric object should be used...
28792 
28793  // The size of this vector is in the next entry
28794  // of All_alg_nodal_info
28795 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28796  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28797  << " Alg node # of geom objects "
28798  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28799  << std::endl;
28800 #endif
28801  unsigned n_geom_obj =
28802  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28803 
28804  // The remaining indices are in the rest of
28805  // All_alg_nodal_info
28806  geom_object_pt.resize(n_geom_obj);
28807  for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
28808  {
28809 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28810  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28811  << " Alg node: geom object index "
28812  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28813  << std::endl;
28814 #endif
28815  unsigned geom_index =
28816  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28817  // This index indicates which of the AlgebraicMesh's
28818  // stored geometric objects should be used
28819  // (0 is a null pointer; everything else should have
28820  // been filled in by the specific Mesh). If it
28821  // hasn't been filled in then the update_node_update
28822  // call should fix it
28823  geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
28824  }
28825 
28826  // Check if necessary to state all the info. to the node if it
28827  // has been already found in shared boundaries with other
28828  // processors or in the haloed elements with of other processors
28829  // with the iproc processor
28830  if (!found_node_in_other_shared_boundaries ||
28831  !found_on_haloed_element_with_other_processor)
28832  {
28833  /// For the received update_id, ref_value, geom_object
28834  /// call add_node_update_info
28835  new_alg_nod_pt->add_node_update_info(
28836  update_id, alg_mesh_pt, geom_object_pt, ref_value);
28837 
28838  /// Now call update_node_update
28839  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28840 
28841  } // if (!found_node_in_other_shared_boundaries ||
28842  // !found_on_haloed_element_with_other_processor)
28843 
28844  } // if (new_alg_nod_pt!=0)
28845 
28846  // Check if necessary to state all the info. to the node if it has
28847  // been already found in shared boundaries with other processors
28848  // or in the haloed elements with of other processors with the
28849  // iproc processor
28850  if (!found_node_in_other_shared_boundaries ||
28851  !found_on_haloed_element_with_other_processor)
28852  {
28853  // Is the node a MacroElementNodeUpdateNode?
28854  MacroElementNodeUpdateNode* macro_nod_pt =
28855  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28856 
28857  if (macro_nod_pt != 0)
28858  {
28859  // Need to call set_node_update_info; this requires
28860  // a Vector<GeomObject*> (taken from the mesh)
28861  Vector<GeomObject*> geom_object_vector_pt;
28862 
28863  // Access the required geom objects from the
28864  // MacroElementNodeUpdateMesh
28865  MacroElementNodeUpdateMesh* macro_mesh_pt =
28866  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28867  geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
28868 
28869  // Get local coordinate of node in new element
28870  Vector<double> s_in_macro_node_update_element;
28871  new_el_pt->local_coordinate_of_node(node_index,
28872  s_in_macro_node_update_element);
28873 
28874  // Set node update info for this node
28875  macro_nod_pt->set_node_update_info(
28876  new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
28877  }
28878 
28879  } // if (!found_node_in_other_shared_boundaries ||
28880  // !found_on_haloed_element_with_other_processor)
28881 
28882  // If there are additional values, resize the node
28883  unsigned n_new_val = new_nod_pt->nvalue();
28884 
28885  // Check if necessary to state all the info. to the node if it has
28886  // been already found in shared boundaries with other processors
28887  // or in the haloed elements with of other processors with the
28888  // iproc processor
28889  if (!found_node_in_other_shared_boundaries ||
28890  !found_on_haloed_element_with_other_processor)
28891  {
28892  if (n_val > n_new_val)
28893  {
28894  // If it has been necessary to resize then it may be becuse
28895  // the node is on a FSI boundary, if that is the case we need
28896  // to set a map for these external values
28897 
28898  // Cast to a boundary node
28899  BoundaryNodeBase* bnod_pt =
28900  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28901 
28902  // Create storage, if it doesn't already exist, for the map
28903  // that will contain the position of the first entry of
28904  // this face element's additional values,
28905  if (bnod_pt->index_of_first_value_assigned_by_face_element_pt() == 0)
28906  {
28907  bnod_pt->index_of_first_value_assigned_by_face_element_pt() =
28908  new std::map<unsigned, unsigned>;
28909  }
28910 
28911  // Get pointer to the map
28912  std::map<unsigned, unsigned>* map_pt =
28913  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
28914 
28915  // The id of the face to which this node belong in the bulk
28916  // element
28917  const unsigned id_face = 0;
28918  // We only resize the node values Vector if we haven't done it yet
28919  std::map<unsigned, unsigned>::const_iterator p =
28920  map_pt->find(id_face);
28921 
28922  // If this node hasn't been resized for current id
28923  if (p == map_pt->end())
28924  {
28925  // assign the face element id and the position of the
28926  // first entry to the boundary node
28927  (*map_pt)[id_face] = n_new_val;
28928 
28929  // resize the node vector of values
28930  new_nod_pt->resize(n_val);
28931  }
28932 
28933  } // if (n_val>n_new_val)
28934 
28935  } // if (!found_node_in_other_shared_boundaries ||
28936  // !found_on_haloed_element_with_other_processor)
28937 
28938  // Is the new node a SolidNode?
28939  SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
28940  if (solid_nod_pt != 0)
28941  {
28942  unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
28943  for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
28944  {
28945  for (unsigned t = 0; t < n_prev; t++)
28946  {
28947  double read_data =
28948  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28949 
28950  // Check if necessary to state all the info. to the node if
28951  // it has been already found in shared boundaries with other
28952  // processors or in the haloed elements with of other
28953  // processors with the iproc processor
28954  if (!found_node_in_other_shared_boundaries ||
28955  !found_on_haloed_element_with_other_processor)
28956  {
28957  solid_nod_pt->variable_position_pt()->set_value(
28958  t, i_val, read_data);
28959  } // if (!found_node_in_other_shared_boundaries ||
28960  // !found_on_haloed_element_with_other_processor)
28961  }
28962  }
28963 
28964 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28965  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28966  << " Number of values solid node: "
28967  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28968  << std::endl;
28969 #endif
28970  const unsigned nvalues_solid_node =
28971  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28972  Vector<double> values_solid_node(nvalues_solid_node);
28973  for (unsigned i = 0; i < nvalues_solid_node; i++)
28974  {
28975  values_solid_node[i] =
28976  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28977  }
28978 
28979  // Check if necessary to state all the info. to the node if it
28980  // has been already found in shared boundaries with other
28981  // processors or in the haloed elements with of other processors
28982  // with the iproc processor
28983  if (!found_node_in_other_shared_boundaries ||
28984  !found_on_haloed_element_with_other_processor)
28985  {
28986  unsigned index = 0;
28987  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28988  } // if (!found_node_in_other_shared_boundaries ||
28989  // !found_on_haloed_element_with_other_processor)
28990  }
28991 
28992  // Get copied history values
28993  // unsigned n_val=new_nod_pt->nvalue();
28994  for (unsigned i_val = 0; i_val < n_val; i_val++)
28995  {
28996  for (unsigned t = 0; t < n_prev; t++)
28997  {
28998  double read_data =
28999  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
29000 
29001  // Check if necessary to state all the info. to the node if it
29002  // has been already found in shared boundaries with other
29003  // processors or in the haloed elements with of other
29004  // processors with the iproc processor
29005  if (!found_node_in_other_shared_boundaries ||
29006  !found_on_haloed_element_with_other_processor)
29007  {
29008  new_nod_pt->set_value(t, i_val, read_data);
29009  } // if (!found_node_in_other_shared_boundaries ||
29010  // !found_on_haloed_element_with_other_processor)
29011  }
29012  }
29013 
29014  // Get copied history values for positions
29015  unsigned n_dim = new_nod_pt->ndim();
29016  for (unsigned idim = 0; idim < n_dim; idim++)
29017  {
29018  for (unsigned t = 0; t < n_prev; t++)
29019  {
29020  double read_data =
29021  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
29022 
29023  // Check if necessary to state all the info. to the node if it
29024  // has been already found in shared boundaries with other
29025  // processors or in the haloed elements with of other
29026  // processors with the iproc processor
29027  if (!found_node_in_other_shared_boundaries ||
29028  !found_on_haloed_element_with_other_processor)
29029  {
29030  // Copy to coordinate
29031  new_nod_pt->x(t, idim) = read_data;
29032  // DEBP(new_nod_pt->x(t,idim));
29033  } // if (!found_node_in_other_shared_boundaries ||
29034  // !found_on_haloed_element_with_other_processor)
29035  }
29036  }
29037 
29038  } // if (is_node_on_shared_boundary != 1)
29039 
29040  // If the node was not found in other shared boundaries (possibly
29041  // because it is the first time the node has been sent) then copy
29042  // the node to the shared boundaries where it should be, use the
29043  // special container for this cases
29044  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
29045  // shared
29046  // boundaries with
29047  // other processors
29048  !found_node_in_other_shared_boundaries) // The node has not
29049  // been previously
29050  // set as with
29051  // shared with
29052  // other processors
29053  // (first time)
29054  {
29055  // Update the node pointer in all the references of the node
29056  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
29057  other_proc_shd_bnd_node_pt,
29058  other_processor_1,
29059  other_processor_2,
29060  other_shared_boundaries,
29061  other_indexes,
29062  global_node_names,
29063  node_name_to_global_index,
29064  global_shared_node_pt);
29065 
29066  } // if (!found_node_in_other_shared_boundaries)
29067  }
29068 
29069 #endif // #ifdef OOMPH_HAS_MPI
29070 
29071  //======================================================================
29072  /// Get the nodes on the boundary (b), these are stored in the
29073  /// segment they belong (also used by the load balance method to
29074  /// re-set the number of segments per boundary after load balance has
29075  /// taken place)
29076  //======================================================================
29077  template<class ELEMENT>
29079  const unsigned& b, Vector<Vector<Node*>>& tmp_segment_nodes)
29080  {
29081  // Clear the data structure were to return the nodes
29082  tmp_segment_nodes.clear();
29083 
29084  // Temporary storage for face elements
29085  Vector<FiniteElement*> face_el_pt;
29086 
29087  // Temporary storage for number of elements adjacent to the boundary
29088  unsigned nel = 0;
29089 
29090  // Temporary storage for elements adjacent to the boundary that have
29091  // a common edge (related with internal boundaries)
29092  unsigned n_repeated_ele = 0;
29093 
29094  // Get the number of regions
29095  const unsigned n_regions = this->nregion();
29096 
29097  // Temporary storage for already visited pair of nodes (edges)
29098  Vector<std::pair<Node*, Node*>> done_nodes_pt;
29099 
29100  // Are there more than one region?
29101  if (n_regions > 1)
29102  {
29103  for (unsigned rr = 0; rr < n_regions; rr++)
29104  {
29105  const unsigned region_id =
29106  static_cast<unsigned>(this->Region_attribute[rr]);
29107 
29108  // Loop over all elements on boundaries in region rr
29109  const unsigned nel_in_region =
29110  this->nboundary_element_in_region(b, region_id);
29111 
29112  // Number of repeated element in region
29113  unsigned nel_repeated_in_region = 0;
29114 
29115  // Only bother to do anything else, if there are elements
29116  // associated with the boundary and the current region
29117  if (nel_in_region > 0)
29118  {
29119  // Flag that activates when a repeated face element is found,
29120  // possibly because we are dealing with an internal boundary
29121  bool repeated = false;
29122 
29123  // Loop over the bulk elements adjacent to boundary b
29124  for (unsigned e = 0; e < nel_in_region; e++)
29125  {
29126  // Get pointer to the bulk element that is adjacent to boundary b
29127  FiniteElement* bulk_elem_pt =
29128  this->boundary_element_in_region_pt(b, region_id, e);
29129 
29130 #ifdef OOMPH_HAS_MPI
29131  // In a distributed mesh only work with nonhalo elements
29132  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
29133  {
29134  // Increase the number of repeated elements
29135  n_repeated_ele++;
29136  // Go for the next element
29137  continue;
29138  }
29139 #endif
29140 
29141  // Find the index of the face of element e along boundary b
29142  int face_index =
29143  this->face_index_at_boundary_in_region(b, region_id, e);
29144 
29145  // Before adding the new element we need to be sure that the
29146  // edge that this element represents has not been already
29147  // added
29148  FiniteElement* tmp_ele_pt =
29149  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
29150 
29151  // Number of nodes in the face element
29152  const unsigned n_nodes = tmp_ele_pt->nnode();
29153 
29154  std::pair<Node*, Node*> tmp_pair = std::make_pair(
29155  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
29156 
29157  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
29158  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
29159 
29160  // Search for repeated nodes
29161  unsigned n_done_nodes = done_nodes_pt.size();
29162  for (unsigned l = 0; l < n_done_nodes; l++)
29163  {
29164  if (tmp_pair == done_nodes_pt[l] ||
29165  tmp_pair_inverse == done_nodes_pt[l])
29166  {
29167  nel_repeated_in_region++;
29168  repeated = true;
29169  break;
29170  }
29171 
29172  } // for (l < n_done_nodes)
29173 
29174  // Create new face element?
29175  if (!repeated)
29176  {
29177  // Add the pair of nodes (edge) to the node dones
29178  done_nodes_pt.push_back(tmp_pair);
29179  // Add the face element to the storage
29180  face_el_pt.push_back(tmp_ele_pt);
29181  }
29182  else
29183  {
29184  // Clean up
29185  delete tmp_ele_pt;
29186  tmp_ele_pt = 0;
29187  }
29188 
29189  // Re-start
29190  repeated = false;
29191 
29192  } // for (e < nel_in_region)
29193 
29194  // Add on the number of elements in the boundary with the
29195  // current region
29196  nel += nel_in_region;
29197 
29198  // Add on the number of repeated elements
29199  n_repeated_ele += nel_repeated_in_region;
29200 
29201  } // if (nel_in_region > 0)
29202 
29203  } // for (rr < n_regions)
29204 
29205  } // if (n_regions > 1)
29206  // Otherwise it's just the normal boundary functions
29207  else
29208  {
29209  // Assign the number of boundary elements
29210  nel = this->nboundary_element(b);
29211 
29212  // Only bother to do anything else, if there are elements
29213  if (nel > 0)
29214  {
29215  // Flag that activates when a repeated face element is found,
29216  // possibly because we are dealing with an internal boundary
29217  bool repeated = false;
29218 
29219  // Loop over the bulk elements adjacent to boundary b
29220  for (unsigned e = 0; e < nel; e++)
29221  {
29222  // Get pointer to the bulk element that is adjacent to boundary b
29223  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
29224 
29225 #ifdef OOMPH_HAS_MPI
29226  // In a distributed mesh only work with nonhalo elements
29227  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
29228  {
29229  // Increase the number of repeated elements
29230  n_repeated_ele++;
29231  // Go for the next element
29232  continue;
29233  }
29234 #endif
29235 
29236  // Find the index of the face of element e along boundary b
29237  int face_index = this->face_index_at_boundary(b, e);
29238 
29239  // Before adding the new element we need to be sure that the
29240  // edge that this element represent has not been already added
29241  FiniteElement* tmp_ele_pt =
29242  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
29243 
29244  // Number of nodes in the face element
29245  const unsigned n_nodes = tmp_ele_pt->nnode();
29246 
29247  std::pair<Node*, Node*> tmp_pair = std::make_pair(
29248  tmp_ele_pt->node_pt(0), tmp_ele_pt->node_pt(n_nodes - 1));
29249 
29250  std::pair<Node*, Node*> tmp_pair_inverse = std::make_pair(
29251  tmp_ele_pt->node_pt(n_nodes - 1), tmp_ele_pt->node_pt(0));
29252 
29253  // Search for repeated nodes
29254  unsigned n_done_nodes = done_nodes_pt.size();
29255  for (unsigned l = 0; l < n_done_nodes; l++)
29256  {
29257  if (tmp_pair == done_nodes_pt[l] ||
29258  tmp_pair_inverse == done_nodes_pt[l])
29259  {
29260  n_repeated_ele++;
29261  repeated = true;
29262  break;
29263  }
29264 
29265  } // for (l < n_done_nodes)
29266 
29267  // Create new face element
29268  if (!repeated)
29269  {
29270  // Add the pair of nodes (edge) to the node dones
29271  done_nodes_pt.push_back(tmp_pair);
29272  // Add the face element to the storage
29273  face_el_pt.push_back(tmp_ele_pt);
29274  }
29275  else
29276  {
29277  // Free the repeated bulk element!!
29278  delete tmp_ele_pt;
29279  tmp_ele_pt = 0;
29280  }
29281 
29282  // Re-start
29283  repeated = false;
29284 
29285  } // for (e < nel)
29286 
29287  } // if (nel > 0)
29288 
29289  } // else if (n_regions > 1)
29290 
29291  // Substract the repeated elements
29292  nel -= n_repeated_ele;
29293 
29294 #ifdef PARANOID
29295  if (nel != face_el_pt.size())
29296  {
29297  std::ostringstream error_message;
29298  error_message
29299  << "The independet counting of face elements (" << nel << ") for "
29300  << "boundary (" << b << ") is different\n"
29301  << "from the real number of face elements in the container ("
29302  << face_el_pt.size() << ")\n";
29303  throw OomphLibError(
29304  error_message.str(),
29305  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29306  OOMPH_EXCEPTION_LOCATION);
29307  }
29308 #endif
29309 
29310  // Only bother to do anything else, if there are elements
29311  if (nel > 0)
29312  {
29313  // Assign the number of nonhalo face elements
29314  const unsigned nnon_halo_face_elements = nel;
29315 
29316  // The vector of list to store the "segments" that compound the
29317  // boundary (segments may appear only in a distributed mesh)
29318  Vector<std::list<FiniteElement*>> segment_sorted_ele_pt;
29319 
29320  // Number of already sorted face elements (only nonhalo face
29321  // elements for a distributed mesh)
29322  unsigned nsorted_face_elements = 0;
29323 
29324  // Keep track of who's done (in a distributed mesh this apply to
29325  // nonhalo only)
29326  std::map<FiniteElement*, bool> done_ele;
29327 
29328  // Keep track of which element is inverted (in distributed mesh
29329  // the elements may be inverted with respect to the segment they
29330  // belong)
29331  std::map<FiniteElement*, bool> is_inverted;
29332 
29333  // Iterate until all possible segments have been created. In a non
29334  // distributed mesh there is only one segment which defines the
29335  // complete boundary
29336  while (nsorted_face_elements < nnon_halo_face_elements)
29337  {
29338  // The ordered list of face elements (in a distributed mesh a
29339  // collection of continuous face elements define a segment)
29340  std::list<FiniteElement*> sorted_el_pt;
29341 
29342 #ifdef PARANOID
29343  // Select an initial element for the segment
29344  bool found_initial_face_element = false;
29345 #endif
29346 
29347  FiniteElement* ele_face_pt = 0;
29348 
29349  unsigned iface = 0;
29350 #ifdef OOMPH_HAS_MPI
29351  if (this->is_mesh_distributed())
29352  {
29353  for (iface = 0; iface < nel; iface++)
29354  {
29355  ele_face_pt = face_el_pt[iface];
29356  // If not done then take it as initial face element
29357  if (!done_ele[ele_face_pt])
29358  {
29359 #ifdef PARANOID
29360  // Set the flag to indicate the initial element was
29361  // found
29362  found_initial_face_element = true;
29363 #endif
29364  // Increase the number of sorted face elements
29365  nsorted_face_elements++;
29366  // Set the index to the next face element
29367  iface++;
29368  // Add the face element in the container
29369  sorted_el_pt.push_back(ele_face_pt);
29370  // Mark as done
29371  done_ele[ele_face_pt] = true;
29372  break;
29373  } // if (!done_el[ele_face_pt])
29374  } // for (iface < nel)
29375  } // if (this->is_mesh_distributed())
29376  else
29377  {
29378 #endif // #ifdef OOMPH_HAS_MPI
29379 
29380  // When the mesh is not distributed just take the first
29381  // element and put it in the ordered list
29382  ele_face_pt = face_el_pt[0];
29383 #ifdef PARANOID
29384  // Set the flag to indicate the initial element was found
29385  found_initial_face_element = true;
29386 #endif
29387  // Increase the number of sorted face elements
29388  nsorted_face_elements++;
29389  // Set the index to the next face element
29390  iface = 1;
29391  // Add the face element in the container
29392  sorted_el_pt.push_back(ele_face_pt);
29393  // Mark as done
29394  done_ele[ele_face_pt] = true;
29395 #ifdef OOMPH_HAS_MPI
29396  } // else if (this->is_mesh_distributed())
29397 #endif
29398 
29399 #ifdef PARANOID
29400  if (!found_initial_face_element)
29401  {
29402  std::ostringstream error_message;
29403  error_message << "Could not find an initial face element for the "
29404  "current segment\n";
29405  throw OomphLibError(
29406  error_message.str(),
29407  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29408  OOMPH_EXCEPTION_LOCATION);
29409  }
29410 #endif
29411 
29412  // Number of nodes in the face element
29413  const unsigned nnod = ele_face_pt->nnode();
29414 
29415  // Left and rightmost nodes (the left and right nodes of the
29416  // current face element)
29417  Node* left_node_pt = ele_face_pt->node_pt(0);
29418  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29419 
29420  // Continue iterating if a new face element has been added to
29421  // the list
29422  bool face_element_added = false;
29423 
29424  // While a new face element has been added to the set of sorted
29425  // face elements continue iterating
29426  do
29427  {
29428  // Start from the next face element since we have already
29429  // added the previous one as the initial face element (any
29430  // previous face element had to be added on previous
29431  // iterations)
29432  for (unsigned iiface = iface; iiface < nel; iiface++)
29433  {
29434  // Re-start flag
29435  face_element_added = false;
29436 
29437  // Get the candidate element
29438  ele_face_pt = face_el_pt[iiface];
29439 
29440  // Check that the candidate element has not been done and is
29441  // not a halo element
29442  if (!done_ele[ele_face_pt])
29443  {
29444  // Get the left and right nodes of the current element
29445  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29446  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29447 
29448  // New element fits at the left of segment and is not inverted
29449  if (left_node_pt == local_right_node_pt)
29450  {
29451  left_node_pt = local_left_node_pt;
29452  sorted_el_pt.push_front(ele_face_pt);
29453  is_inverted[ele_face_pt] = false;
29454  face_element_added = true;
29455  }
29456  // New element fits at the left of segment and is inverted
29457  else if (left_node_pt == local_left_node_pt)
29458  {
29459  left_node_pt = local_right_node_pt;
29460  sorted_el_pt.push_front(ele_face_pt);
29461  is_inverted[ele_face_pt] = true;
29462  face_element_added = true;
29463  }
29464  // New element fits on the right of segment and is not inverted
29465  else if (right_node_pt == local_left_node_pt)
29466  {
29467  right_node_pt = local_right_node_pt;
29468  sorted_el_pt.push_back(ele_face_pt);
29469  is_inverted[ele_face_pt] = false;
29470  face_element_added = true;
29471  }
29472  // New element fits on the right of segment and is inverted
29473  else if (right_node_pt == local_right_node_pt)
29474  {
29475  right_node_pt = local_left_node_pt;
29476  sorted_el_pt.push_back(ele_face_pt);
29477  is_inverted[ele_face_pt] = true;
29478  face_element_added = true;
29479  }
29480 
29481  if (face_element_added)
29482  {
29483  // Mark the face element as done
29484  done_ele[ele_face_pt] = true;
29485  nsorted_face_elements++;
29486  break;
29487  }
29488 
29489  } // if (!done_el[ele_face_pt])
29490 
29491  } // for (iiface<nnon_halo_face_element)
29492 
29493  } while (face_element_added &&
29494  (nsorted_face_elements < nnon_halo_face_elements));
29495 
29496  // Store the created segment in the vector of segments
29497  segment_sorted_ele_pt.push_back(sorted_el_pt);
29498 
29499  } // while(nsorted_face_elements < nnon_halo_face_elements);
29500 
29501  // The number of boundary segments in this processor
29502  const unsigned nsegments = segment_sorted_ele_pt.size();
29503 
29504 #ifdef PARANOID
29505  if (nnon_halo_face_elements > 0 && nsegments == 0)
29506  {
29507  std::ostringstream error_message;
29508  error_message
29509  << "The number of segments is zero, but the number of nonhalo\n"
29510  << "elements is: (" << nnon_halo_face_elements << ")\n";
29511  throw OomphLibError(
29512  error_message.str(),
29513  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29514  OOMPH_EXCEPTION_LOCATION);
29515  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29516 #endif
29517 
29518  // Go through all the segments, visit each face element in order
29519  // and get the nodes based that represent the boundary segment
29520 
29521  // Resize the container to store the nodes with the required
29522  // number of segments
29523  tmp_segment_nodes.resize(nsegments);
29524 
29525  for (unsigned is = 0; is < nsegments; is++)
29526  {
29527 #ifdef PARANOID
29528  if (segment_sorted_ele_pt[is].size() == 0)
29529  {
29530  std::ostringstream error_message;
29531  error_message << "The (" << is << ")-th segment has no elements\n";
29532  throw OomphLibError(
29533  error_message.str(),
29534  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29535  OOMPH_EXCEPTION_LOCATION);
29536  } // if (segment_sorted_ele_pt[is].size() == 0)
29537 #endif
29538 
29539  // Get access to the first element on the segment
29540  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29541 
29542  // Number of nodes
29543  const unsigned nnod = first_ele_pt->nnode();
29544 
29545  // Get the first node of the current segment
29546  Node* first_node_pt = first_ele_pt->node_pt(0);
29547  if (is_inverted[first_ele_pt])
29548  {
29549  first_node_pt = first_ele_pt->node_pt(nnod - 1);
29550  }
29551 
29552  // Add the node to the corresponding segment
29553  tmp_segment_nodes[is].push_back(first_node_pt);
29554 
29555  // Now loop over face elements in order to get the nodes
29556  for (std::list<FiniteElement*>::iterator it =
29557  segment_sorted_ele_pt[is].begin();
29558  it != segment_sorted_ele_pt[is].end();
29559  it++)
29560  {
29561  // Get element
29562  FiniteElement* ele_pt = *it;
29563 
29564  // The last node pointer
29565  Node* last_node_pt = 0;
29566 
29567  // Get the last node
29568  if (!is_inverted[ele_pt])
29569  {
29570  last_node_pt = ele_pt->node_pt(nnod - 1);
29571  }
29572  else
29573  {
29574  last_node_pt = ele_pt->node_pt(0);
29575  }
29576 
29577  // Add the node to the corresponding segment
29578  tmp_segment_nodes[is].push_back(last_node_pt);
29579 
29580  } // iterator over the elements in the segment
29581 
29582  } // for (is < nsegments)
29583 
29584  } // for (if (nel > 0))
29585 
29586  // Free memory allocation
29587  for (unsigned e = 0; e < nel; e++)
29588  {
29589  delete face_el_pt[e];
29590  face_el_pt[e] = 0;
29591  } // for (e < nel)
29592  }
29593 
29594  //======================================================================
29595  /// Adapt problem based on specified elemental error estimates
29596  /// This function implement serial and parallel mesh adaptation, the
29597  /// sections for parallel mesh adaptation are clearly identified by
29598  /// checking whether the mesh is distributed or not
29599  //======================================================================
29600  template<class ELEMENT>
29601  void RefineableTriangleMesh<ELEMENT>::adapt(const Vector<double>& elem_error)
29602  {
29603  double t_start_overall = TimingHelpers::timer();
29604 
29605  // ==============================================================
29606  // BEGIN: Compute target areas
29607  // ==============================================================
29608 
29609  // Get refinement targets
29610  Vector<double> target_area(elem_error.size());
29611  double min_angle = compute_area_target(elem_error, target_area);
29612 
29613  // Post-process to allow only quantised target areas
29614  // in an attempt to more closely mimick the structured
29615  // case and limit the diffusion of small elements.
29616  bool quantised_areas = true;
29617  if (quantised_areas)
29618  {
29619  unsigned n = target_area.size();
29620  double total_area = 0;
29621  // If the mesh is distributed then we need to get the contribution
29622  // of all processors to compute the total areas
29623  // ------------------------------------------
29624  // DISTRIBUTED MESH: BEGIN
29625  // ------------------------------------------
29626 #ifdef OOMPH_HAS_MPI
29627  if (this->is_mesh_distributed())
29628  {
29629  // When working in parallel we get the total area from the sum
29630  // of the the sub-areas of all the meshes
29631  double sub_area = 0.0;
29632 
29633  // Only add the area of nonhalo elements
29634  for (unsigned e = 0; e < n; e++)
29635  {
29636  // Get the pointer to the element
29637  FiniteElement* ele_pt = this->finite_element_pt(e);
29638  if (!ele_pt->is_halo())
29639  {
29640  sub_area += ele_pt->size();
29641  }
29642  } // for (e<n)
29643 
29644  // Get the communicator of the mesh
29645  OomphCommunicator* comm_pt = this->communicator_pt();
29646 
29647  // Get the total area
29648  MPI_Allreduce(
29649  &sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM, comm_pt->mpi_comm());
29650  }
29651  else
29652  {
29653  for (unsigned e = 0; e < n; e++)
29654  {
29655  total_area += this->finite_element_pt(e)->size();
29656  }
29657  }
29658  // ------------------------------------------
29659  // DISTRIBUTED MESH: END
29660  // ------------------------------------------
29661 #else // #ifdef OOMPH_HAS_MPI
29662  for (unsigned e = 0; e < n; e++)
29663  {
29664  total_area += this->finite_element_pt(e)->size();
29665  }
29666 #endif // #ifdef OOMPH_HAS_MPI
29667 
29668  for (unsigned e = 0; e < n; e++)
29669  {
29670  unsigned level =
29671  unsigned(ceil(log(target_area[e] / total_area) / log(1.0 / 3.0))) - 1;
29672  double new_target_area = total_area * pow(1.0 / 3.0, int(level));
29673  target_area[e] = new_target_area;
29674  }
29675  }
29676 
29677  // std::ofstream tmp;
29678  // tmp.open((Global_string_for_annotation::
29679  // String[0]+"overall_target_areas"+
29680  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29681 
29682  // Get maximum target area
29683  unsigned n = target_area.size();
29684  double max_area = 0.0;
29685  double min_area = DBL_MAX;
29686  for (unsigned e = 0; e < n; e++)
29687  {
29688  if (target_area[e] > max_area) max_area = target_area[e];
29689  if (target_area[e] < min_area) min_area = target_area[e];
29690 
29691  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29692  // finite_element_pt(e)->node_pt(1)->x(0)+
29693  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29694  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29695  // finite_element_pt(e)->node_pt(1)->x(1)+
29696  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29697  // << target_area[e] << " "
29698  // << finite_element_pt(e)->size() << " "
29699  // << elem_error[e] << " " << std::endl;
29700  }
29701 
29702  // tmp.close();
29703 
29704  oomph_info << "Maximum target area: " << max_area << std::endl;
29705  oomph_info << "Minimum target area: " << min_area << std::endl;
29706  oomph_info << "Number of elements to be refined: " << this->Nrefined
29707  << std::endl;
29708  oomph_info << "Number of elements to be unrefined: " << this->Nunrefined
29709  << std::endl;
29710  oomph_info << "Min. angle: " << min_angle << std::endl;
29711 
29712  double orig_max_area, orig_min_area;
29713  this->max_and_min_element_size(orig_max_area, orig_min_area);
29714  oomph_info << "Max./min. element size in original mesh: " << orig_max_area
29715  << " " << orig_min_area << std::endl;
29716 
29717  // ==============================================================
29718  // END: Compute target areas
29719  // ==============================================================
29720 
29721  // Check if boundaries need to be updated (regardless of
29722  // requirements of bulk error estimator) but don't do anything!
29723  bool check_only = true;
29724  bool outer_boundary_update_necessary = false;
29725  bool inner_boundary_update_necessary = false;
29726  bool inner_open_boundary_update_necessary = false;
29727 
29728  // Get the number of outer boundaries and check if they require
29729  // update
29730  const unsigned nouter = this->Outer_boundary_pt.size();
29731 
29732  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29733  {
29734  // loop over the outer boundaries
29735  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29736  {
29737  outer_boundary_update_necessary = this->update_polygon_using_face_mesh(
29738  this->Outer_boundary_pt[i_outer], check_only);
29739  // Break the loop if at least one needs updating
29740  if (outer_boundary_update_necessary) break;
29741  }
29742 
29743  // Do not waste time if we already know that it is necessary an update
29744  // on the boundary representation
29745  if (!outer_boundary_update_necessary)
29746  {
29747  // Check if we need to generate a new 1D mesh representation of
29748  // the inner hole boundaries
29749  const unsigned nhole = this->Internal_polygon_pt.size();
29750  Vector<Vector<double>> internal_point_coord(nhole);
29751  inner_boundary_update_necessary =
29752  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29753  check_only);
29754 
29755  // If there was not necessary a change even on the internal closed
29756  // curve then finally check for the open curves as well
29757  if (!inner_boundary_update_necessary)
29758  {
29759  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29760  // loop over the open polylines
29761  for (unsigned i = 0; i < n_open_polyline; i++)
29762  {
29763  inner_open_boundary_update_necessary =
29764  this->update_open_curve_using_face_mesh(
29765  this->Internal_open_curve_pt[i], check_only);
29766  // If at least one needs modification then break the for loop
29767  if (inner_open_boundary_update_necessary) break;
29768  }
29769  }
29770  }
29771  }
29772 
29773  // Flag to indicate whether we need to adapt or not (for parallel
29774  // mesh adaptation only)
29775  int adapt_all = 0;
29776  // ------------------------------------------
29777  // DISTRIBUTED MESH: BEGIN
29778  // ------------------------------------------
29779 #ifdef OOMPH_HAS_MPI
29780  // When working in distributed meshes we need to ensure that all the
29781  // processors take part on the adaptation process. If at least one
29782  // of the processors requires adaptation then all processor take
29783  // part on the adaptation process.
29784  int adapt_this_processor = 0;
29785  if (this->is_mesh_distributed())
29786  {
29787  // Do this processor requires adaptation?
29788  if ((Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29789  (min_angle < min_permitted_angle()) ||
29790  (outer_boundary_update_necessary) ||
29791  (inner_boundary_update_necessary) ||
29792  (inner_open_boundary_update_necessary))
29793  {
29794  adapt_this_processor = 1;
29795  }
29796 
29797  // Get the communicator of the mesh
29798  OomphCommunicator* comm_pt = this->communicator_pt();
29799 
29800  // Verify if at least one processor needs mesh adaptation
29801  MPI_Allreduce(&adapt_this_processor,
29802  &adapt_all,
29803  1,
29804  MPI_INT,
29805  MPI_SUM,
29806  comm_pt->mpi_comm());
29807  }
29808 #endif
29809  // ------------------------------------------
29810  // DISTRIBUTED MESH: END
29811  // ------------------------------------------
29812 
29813  // Should we bother to adapt?
29814  if ((Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29815  (min_angle < min_permitted_angle()) ||
29816  (outer_boundary_update_necessary) ||
29817  (inner_boundary_update_necessary) ||
29818  (inner_open_boundary_update_necessary) || (adapt_all))
29819  {
29820  if (!((Nrefined > 0) || (Nunrefined > max_keep_unrefined())))
29821  {
29822  if ((outer_boundary_update_necessary) ||
29823  (inner_boundary_update_necessary) ||
29824  (inner_open_boundary_update_necessary))
29825  {
29826  oomph_info
29827  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29828  << "representation; setting Nrefined to number of elements.\n"
29829  << "outer_boundary_update_necessary : "
29830  << outer_boundary_update_necessary << "\n"
29831  << "inner_boundary_update_necessary : "
29832  << inner_boundary_update_necessary << "\n"
29833  << "inner_open_boundary_update_necessary: "
29834  << inner_open_boundary_update_necessary << "\n";
29835  Nrefined = nelement();
29836  }
29837  else
29838  {
29839  oomph_info << "Mesh regeneration triggered by min angle criterion;\n"
29840  << "setting Nrefined to number of elements.\n";
29841  Nrefined = nelement();
29842  }
29843  }
29844 
29845  // ------------------------------------------
29846  // DISTRIBUTED MESH: BEGIN
29847  // ------------------------------------------
29848 #ifdef OOMPH_HAS_MPI
29849  else if (this->is_mesh_distributed() && adapt_this_processor == 0 &&
29850  adapt_all > 0)
29851  {
29852  oomph_info << "Mesh regeneration triggered by (" << adapt_all
29853  << ") processor(s) "
29854  << "that require(s)\n adaptation\n";
29855  }
29856 #endif
29857  // ------------------------------------------
29858  // DISTRIBUTED MESH: END
29859  // ------------------------------------------
29860 
29861  // ==============================================================
29862  // BEGIN: Updating of boundaries representation (unrefinement and
29863  // refinement of polylines)
29864  // ==============================================================
29865 
29866  // Add the initial and final vertices of the polylines that
29867  // present connections to a list of non-delete-able vertices. The
29868  // vertices where the connections are performed cannot be deleted
29869  add_vertices_for_non_deletion();
29870 
29871  // ------------------------------------------
29872  // DISTRIBUTED MESH: BEGIN
29873  // ------------------------------------------
29874 #ifdef OOMPH_HAS_MPI
29875  // Synchronise connections for shared boundaries among
29876  // processors. This is required since one of the processor may noy
29877  // know that some of its shared boundaries have connections, thus
29878  // the vertices receiving the connections cannot be deleted
29879  if (this->is_mesh_distributed())
29880  {
29881  synchronize_shared_boundary_connections();
29882  }
29883 #endif // #ifdef OOMPH_HAS_MPI
29884  // ------------------------------------------
29885  // DISTRIBUTED MESH: END
29886  // ------------------------------------------
29887 
29888  // Are we allowing automatic insertion of vertices on boundaries?
29889  // If YES then Triangle automatically insert points along
29890  // boundaries, if NOT, then points are inserted along the
29891  // boundaries based on the target areas of boundary elements. When
29892  // the mesh is distributed the automatic insertion of vertices by
29893  // Triangle along the boundaries is not allowed
29894  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29895  {
29896  // Generate a new 1D mesh representation of the inner hole boundaries
29897  unsigned nhole = this->Internal_polygon_pt.size();
29898  Vector<Vector<double>> internal_point_coord(nhole);
29899  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29900 
29901  // Update the representation of the outer boundary
29902  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29903  {
29904  this->update_polygon_using_face_mesh(
29905  this->Outer_boundary_pt[i_outer]);
29906  }
29907 
29908  // After updating outer and internal closed boundaries it is also
29909  // necessary to update internal boundaries.
29910  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29911  for (unsigned i = 0; i < n_open_polyline; i++)
29912  {
29913  this->update_open_curve_using_face_mesh(
29914  this->Internal_open_curve_pt[i]);
29915  }
29916  }
29917  else
29918  {
29919  // Update the representation of the internal boundaries using
29920  // the element's target area
29921 
29922  // Get the number of interal polygons
29923  const unsigned ninternal = this->Internal_polygon_pt.size();
29924  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29925  {
29926  this->update_polygon_using_elements_area(
29927  this->Internal_polygon_pt[i_internal], target_area);
29928  }
29929 
29930  // Update the representation of the outer boundaries using the
29931  // element's target area
29932  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29933  {
29934  this->update_polygon_using_elements_area(
29935  this->Outer_boundary_pt[i_outer], target_area);
29936  }
29937 
29938  // Update the representation of the internal open boundaries
29939  // using the element's target areas
29940  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29941  for (unsigned i = 0; i < n_open_polyline; i++)
29942  {
29943  this->update_open_curve_using_elements_area(
29944  this->Internal_open_curve_pt[i], target_area);
29945  }
29946 
29947  // ------------------------------------------
29948  // DISTRIBUTED MESH: BEGIN
29949  // ------------------------------------------
29950 
29951  // When working with a distributed mesh we require to update the
29952  // boundary representation of the shared boundaries, this is
29953  // based on the target areas of the elements adjaced to the
29954  // shared boundaries
29955 #ifdef OOMPH_HAS_MPI
29956  // Update shared boundaries if the mesh is distributed
29957  if (this->is_mesh_distributed())
29958  {
29959  // Get the rank of the current processor
29960  const unsigned my_rank = this->communicator_pt()->my_rank();
29961 
29962  // Get the number of shared curves
29963  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29964  // Loop over the shared curves in the current processor
29965  for (unsigned nc = 0; nc < n_curves; nc++)
29966  {
29967  // Update the shared polyline
29968  this->update_shared_curve_using_elements_area(
29969  this->Shared_boundary_polyline_pt[my_rank][nc], // shared_curve,
29970  target_area);
29971  }
29972 
29973  } // if (this->is_mesh_distributed())
29974 #endif
29975 
29976  // ------------------------------------------
29977  // DISTRIBUTED MESH: END
29978  // ------------------------------------------
29979 
29980  } // else if
29981  // (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29982 
29983  // ==============================================================
29984  // END: Updating of boundaries representation (unrefinement and
29985  // refinement of polylines)
29986  // ==============================================================
29987 
29988  // ==============================================================
29989  // BEGIN: Reset boundary coordinates for boundaries with no
29990  // associated GeomObject
29991  // ==============================================================
29992 
29993  // If there is not a geometric object associated with the boundary
29994  // then reset the boundary coordinates so that the lengths are
29995  // consistent in the new mesh and the old mesh.
29996  const unsigned n_boundary = this->nboundary();
29997 
29998  const double t_start_first_stage_segments_connectivity =
29999  TimingHelpers::timer();
30000 
30001  // ------------------------------------------
30002  // DISTRIBUTED MESH: BEGIN
30003  // ------------------------------------------
30004 #ifdef OOMPH_HAS_MPI
30005  // Clear storage for assignment of initial zeta values for
30006  // boundaries
30007  if (this->is_mesh_distributed())
30008  {
30009  this->Assigned_segments_initial_zeta_values.clear();
30010  }
30011 #endif // #ifdef OOMPH_HAS_MPI
30012  // ------------------------------------------
30013  // DISTRIBUTED MESH: END
30014  // ------------------------------------------
30015 
30016  // Loop over the boundaries to assign boundary coordinates
30017  for (unsigned b = 0; b < n_boundary; ++b)
30018  {
30019  // ------------------------------------------
30020  // DISTRIBUTED MESH: BEGIN
30021  // ------------------------------------------
30022 #ifdef OOMPH_HAS_MPI
30023  if (this->is_mesh_distributed())
30024  {
30025  // In a distributed mesh, the boundaries may have been split
30026  // across processors during the distribution process, thus we
30027  // need to compute the connectivity among the segments of the
30028  // boundary to correctly assign its boundary coordinates
30029  this->compute_boundary_segments_connectivity_and_initial_zeta_values(
30030  b);
30031  }
30032 #endif
30033  // ------------------------------------------
30034  // DISTRIBUTED MESH: END
30035  // ------------------------------------------
30036 
30037  // Does the boundary has an associated GeomObject
30038  if (this->boundary_geom_object_pt(b) == 0)
30039  {
30040  this->template setup_boundary_coordinates<ELEMENT>(b);
30041  }
30042 
30043  // ------------------------------------------
30044  // DISTRIBUTED MESH: BEGIN
30045  // ------------------------------------------
30046 #ifdef OOMPH_HAS_MPI
30047  if (this->is_mesh_distributed())
30048  {
30049  // Synchronise boundary coordinates for internal open curves,
30050  // also establish the boundary coordinates for the nodes on
30051  // the corners of elements not on the boundary
30052  this->synchronize_boundary_coordinates(b);
30053  }
30054 #endif
30055  // ------------------------------------------
30056  // DISTRIBUTED MESH: END
30057  // ------------------------------------------
30058 
30059  } // for (b<n_boundary)
30060 
30061  const double t_total_first_stage_segments_connectivity =
30062  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
30063 
30064  // ==============================================================
30065  // END: Reset boundary coordinates for boundaries with no
30066  // associated GeomObject
30067  // ==============================================================
30068 
30069  // ------------------------------------------
30070  // DISTRIBUTED MESH: BEGIN
30071  // ------------------------------------------
30072 #ifdef OOMPH_HAS_MPI
30073  // ==============================================================
30074  // BEGIN: Create the new representation of the domain by joining
30075  // the original boundaries and the shared boundaries.
30076  // ==============================================================
30077 
30078  // Storage for the new temporary polygons "closed" by the shared
30079  // boundaries
30080  Vector<TriangleMeshPolygon*> tmp_outer_polygons_pt;
30081 
30082  // Storage for the new temporary open curves, could be the
30083  // original open curves or "chunks" of the original open curves
30084  // not overlapped by shared boundaries
30085  Vector<TriangleMeshOpenCurve*> tmp_open_curves_pt;
30086 
30087  if (this->is_mesh_distributed())
30088  {
30089  // Create the new polygons and open curves with help of the
30090  // original polylines and shared polylines
30091  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
30092  tmp_open_curves_pt);
30093 
30094  // Create the connections of the temporary domain representations
30095  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
30096  tmp_open_curves_pt);
30097  }
30098  // ==============================================================
30099  // END: Create the new representation of the domain by joining
30100  // the original boundaries and the shared boundaries.
30101  // ==============================================================
30102 #endif
30103  // ------------------------------------------
30104  // DISTRIBUTED MESH: END
30105  // ------------------------------------------
30106 
30107  // Re-establish polylines' connections. The boundary
30108  // representation has changed (new polylines), therefore we need
30109  // to update the connection information
30110  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
30111  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
30112  restore_boundary_connections(resume_initial_connection_polyline_pt,
30113  resume_final_connection_polyline_pt);
30114 
30115  // Update the region information by setting the coordinates from the
30116  // centroid of the first element in each region (which should allow
30117  // automatic updates when the regions deform)
30118  {
30119  unsigned n_region = this->nregion();
30120  if (n_region > 1)
30121  {
30122  for (std::map<unsigned, Vector<double>>::iterator it =
30123  this->Regions_coordinates.begin();
30124  it != this->Regions_coordinates.end();
30125  ++it)
30126  {
30127  // Storage for the approximate centroid
30128  Vector<double> centroid(2, 0.0);
30129 
30130  // Get the region id
30131  unsigned region_id = it->first;
30132 
30133  // Report information
30134  oomph_info << "Region " << region_id << ": " << it->second[0] << " "
30135  << it->second[1] << " ";
30136 
30137  // Check that there is at least one element in the region
30138  unsigned n_region_element = this->nregion_element(region_id);
30139  if (n_region_element > 0)
30140  {
30141  // Cache pointer to the first element
30142  FiniteElement* const elem_pt =
30143  this->region_element_pt(region_id, 0);
30144 
30145  // Loop over the corners of the triangle and average
30146  for (unsigned n = 0; n < 3; n++)
30147  {
30148  Node* const nod_pt = elem_pt->node_pt(n);
30149  for (unsigned i = 0; i < 2; i++)
30150  {
30151  centroid[i] += nod_pt->x(i);
30152  }
30153  }
30154  for (unsigned i = 0; i < 2; i++)
30155  {
30156  centroid[i] /= 3;
30157  }
30158  // Now we have the centroid set it
30159  it->second = centroid;
30160 
30161  oomph_info << " , " << it->second[0] << " " << it->second[1]
30162  << std::endl;
30163  } // end of case when there is at least one element
30164 
30165  } // loop over regions coordinates
30166 
30167  } // if(n_region > 1)
30168 
30169  } // Updating region info.
30170 
30171  // ==============================================================
30172  // BEGIN: Create background mesh
30173  // ==============================================================
30174 
30175  // Are we dealing with a solid mesh?
30176  SolidMesh* solid_mesh_pt = dynamic_cast<SolidMesh*>(this);
30177 
30178  // Build temporary uniform background mesh
30179  //----------------------------------------
30180  // with area set by maximum required area
30181  //---------------------------------------
30182  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt = 0;
30183 
30184  // The storage for the new temporary boundaries representation to
30185  // create the background mesh
30186  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
30187  Vector<TriangleMeshClosedCurve*> hole_pt;
30188  Vector<TriangleMeshOpenCurve*> open_curves_pt;
30189 
30190 #ifdef OOMPH_HAS_MPI
30191  if (!this->is_mesh_distributed())
30192 #endif
30193  {
30194  // Copy the outer boundaries
30195  closed_curve_pt.resize(nouter);
30196  for (unsigned i = 0; i < nouter; i++)
30197  {
30198  closed_curve_pt[i] = this->Outer_boundary_pt[i];
30199  }
30200 
30201  // Copy the internal closed boundaries (may be holes)
30202  const unsigned n_holes = this->Internal_polygon_pt.size();
30203  hole_pt.resize(n_holes);
30204  for (unsigned i = 0; i < n_holes; i++)
30205  {
30206  hole_pt[i] = this->Internal_polygon_pt[i];
30207  }
30208 
30209  // Copy the internal open curves
30210  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
30211  open_curves_pt.resize(n_open_curves);
30212  for (unsigned i = 0; i < n_open_curves; i++)
30213  {
30214  open_curves_pt[i] = this->Internal_open_curve_pt[i];
30215  }
30216  }
30217  // ------------------------------------------
30218  // DISTRIBUTED MESH: BEGIN
30219  // ------------------------------------------
30220 #ifdef OOMPH_HAS_MPI
30221  else
30222  {
30223  // Copy the new representation of the outer/internal closed
30224  // boundaries
30225  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
30226  closed_curve_pt.resize(n_tmp_outer);
30227  for (unsigned i = 0; i < n_tmp_outer; i++)
30228  {
30229  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
30230  }
30231 
30232  // Copy the new representation of the internal open curves
30233  const unsigned n_open_curves = tmp_open_curves_pt.size();
30234  open_curves_pt.resize(n_open_curves);
30235  for (unsigned i = 0; i < n_open_curves; i++)
30236  {
30237  open_curves_pt[i] = tmp_open_curves_pt[i];
30238  }
30239  }
30240 #endif
30241  // ------------------------------------------
30242  // DISTRIBUTED MESH: END
30243  // ------------------------------------------
30244 
30245  // ----------------------------------------------------------------
30246  // Gather all the information and use the TriangleMeshParameters
30247  // object which help us on the manage of all TriangleMesh object's
30248  // information
30249 
30250  // Create the TriangleMeshParameters objects with the outer boundary
30251  // as the only one parameter
30252  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
30253 
30254  // Pass information about the holes
30255  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
30256 
30257  // Pass information about the internal open boundaries
30258  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
30259 
30260  // Set the element area
30261  triangle_mesh_parameters.element_area() = max_area;
30262 
30263  // Pass information about the extra holes (not defined with closed
30264  // boundaries)
30265  triangle_mesh_parameters.extra_holes_coordinates() =
30266  this->Extra_holes_coordinates;
30267 
30268  // Pass information about regions
30269  triangle_mesh_parameters.regions_coordinates() =
30270  this->Regions_coordinates;
30271 
30272  // Pass information about the using of regions
30273  if (this->Use_attributes)
30274  {
30275  triangle_mesh_parameters.enable_use_attributes();
30276  }
30277 
30278  // Pass information about allowing the creation of new points
30279  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30280  {
30281  triangle_mesh_parameters
30283  }
30284 
30285  // When the mesh is distributed we need to create a distributed
30286  // background mesh
30287 #ifdef OOMPH_HAS_MPI
30288  if (this->is_mesh_distributed())
30289  {
30290  // Mark the mesh to be created as distributed by passing a
30291  // pointer to the communicator
30292  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30293  }
30294 #endif
30295 
30296  // ----------------------------------------------------------
30297  // Build the background mesh using Triangle
30298  // ----------------------------------------------------------
30299  const double t_start_building_background_mesh = TimingHelpers::timer();
30300 
30301  if (solid_mesh_pt != 0)
30302  {
30303  tmp_new_mesh_pt = new RefineableSolidTriangleMesh<ELEMENT>(
30304  triangle_mesh_parameters, this->Time_stepper_pt);
30305  }
30306  else
30307  {
30308  tmp_new_mesh_pt = new RefineableTriangleMesh<ELEMENT>(
30309  triangle_mesh_parameters, this->Time_stepper_pt);
30310  }
30311 
30312  if (Print_timings_level_adaptation > 2)
30313  {
30314  oomph_info << "CPU for building background mesh: "
30315  << TimingHelpers::timer() - t_start_building_background_mesh
30316  << std::endl;
30317  }
30318 
30319  // Pass the info. regarding the maximum and minimum element size
30320  // from the old mesh to the background mesh
30321  const double this_max_element_size = this->max_element_size();
30322  const double this_min_element_size = this->min_element_size();
30323  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30324  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30325 
30326  // ... also copy the minimum permitted angle
30327  const double this_min_permitted_angle = this->min_permitted_angle();
30328  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30329 
30330  // ------------------------------------------
30331  // DISTRIBUTED MESH: BEGIN
30332  // ------------------------------------------
30333 #ifdef OOMPH_HAS_MPI
30334  // If the mesh is distributed we need to pass and set the
30335  // information of internal boundaries overlaped by shared
30336  // boundaries
30337  if (this->is_mesh_distributed())
30338  {
30339  // Check if necessary to fill boundary elements for those
30340  // internal boundaries that overlap shared boundaries
30341  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30342  {
30343  // Copy the data structures that indicates which shared
30344  // boundaries are part of an internal boundary
30345  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30346  this->shared_boundary_overlaps_internal_boundary();
30347 
30348  // Copy the data structure that indicates which are the shared
30349  // boundaries in each processor
30350  tmp_new_mesh_pt->shared_boundaries_ids() =
30351  this->shared_boundaries_ids();
30352 
30353  // Fill the structures for the boundary elements and face indexes
30354  // of the boundary elements
30355  tmp_new_mesh_pt
30357 
30358  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30359 
30360  } // if (this->is_mesh_distributed())
30361 #endif // #ifdef OOMPH_HAS_MPI
30362  // ------------------------------------------
30363  // DISTRIBUTED MESH: END
30364  // ------------------------------------------
30365 
30366  // Snap to curvilinear boundaries (some code duplication as this
30367  // is repeated below but helper function would take so many
30368  // arguments that it's nearly as messy...
30369 
30370  // Pass the boundary geometric objects to the new mesh
30371  tmp_new_mesh_pt->boundary_geom_object_pt() =
30372  this->boundary_geom_object_pt();
30373 
30374  // Reset the boundary coordinates if there is
30375  // a geometric object associated with the boundary
30376  tmp_new_mesh_pt->boundary_coordinate_limits() =
30377  this->boundary_coordinate_limits();
30378 
30379  const double t_start_second_stage_segments_connectivity =
30380  TimingHelpers::timer();
30381 
30382  for (unsigned b = 0; b < n_boundary; b++)
30383  {
30384  // ------------------------------------------
30385  // DISTRIBUTED MESH: BEGIN
30386  // ------------------------------------------
30387 #ifdef OOMPH_HAS_MPI
30388  if (this->is_mesh_distributed())
30389  {
30390  // Identify the segments of the new mesh with the ones of the
30391  // original mesh
30392  tmp_new_mesh_pt
30394  this);
30395  }
30396 #endif
30397  // ------------------------------------------
30398  // DISTRIBUTED MESH: END
30399  // ------------------------------------------
30400 
30401  // Setup boundary coordinates for boundaries with GeomObject
30402  // associated
30403  if (tmp_new_mesh_pt->boundary_geom_object_pt(b) != 0)
30404  {
30405  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30406  }
30407  }
30408 
30409  const double t_total_second_stage_segments_connectivity =
30410  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30411 
30412  const double t_start_snap_nodes_bg_mesh = TimingHelpers::timer();
30413  // Move the nodes on the new boundary onto the old curvilinear
30414  // boundary. If the boundary is straight this will do precisely
30415  // nothing but will be somewhat inefficient
30416  for (unsigned b = 0; b < n_boundary; b++)
30417  {
30418  this->snap_nodes_onto_boundary(tmp_new_mesh_pt, b);
30419  }
30420 
30421  const double t_total_snap_nodes_bg_mesh =
30422  TimingHelpers::timer() - t_start_snap_nodes_bg_mesh;
30423 
30424  if (Print_timings_level_adaptation > 2)
30425  {
30426  oomph_info << "CPU for snapping nodes onto boundaries "
30427  << "(background mesh): " << t_total_snap_nodes_bg_mesh
30428  << std::endl;
30429  }
30430 
30431  // Update mesh further?
30432  if (Mesh_update_fct_pt != 0)
30433  {
30434  Mesh_update_fct_pt(tmp_new_mesh_pt);
30435  }
30436 
30437  // If we have a continuation problem
30438  // any problem in which the timestepper is a "generalisedtimestepper",
30439  // which will have been set by the problem, then ensure
30440  // all data in the new mesh has the appropriate timestepper
30441  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30442  {
30443  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30444  this->Time_stepper_pt);
30445  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30446  }*/
30447 
30448 
30449  // tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30450  // this->output("existing_mesh.dat");
30451 
30452  // ==============================================================
30453  // END: Create background mesh
30454  // ==============================================================
30455 
30456  // ==============================================================
30457  // BEGIN: Transferring of target areas and creation of new mesh
30458  // ==============================================================
30459 
30460  // Get the TriangulateIO object associated with that mesh
30461  TriangulateIO tmp_new_triangulateio =
30462  tmp_new_mesh_pt->triangulateio_representation();
30463  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30464 
30465  // If the mesh is a solid mesh then do the mapping based on the
30466  // Eulerian coordinates
30467  bool use_eulerian_coords = false;
30468  if (solid_mesh_pt != 0)
30469  {
30470  use_eulerian_coords = true;
30471  }
30472 
30473 
30474 #ifdef OOMPH_HAS_CGAL
30475 
30476  // Make cgal-based bin
30477  CGALSamplePointContainerParameters cgal_params(this);
30478  if (use_eulerian_coords)
30479  {
30480  cgal_params.enable_use_eulerian_coordinates_during_setup();
30481  }
30482  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(&cgal_params);
30483 
30484 #else
30485 
30486  // Make nonrefineable bin
30487  NonRefineableBinArrayParameters params(this);
30488  if (use_eulerian_coords)
30489  {
30490  params.enable_use_eulerian_coordinates_during_setup();
30491  }
30492  Vector<unsigned> bin_dim(2);
30493  bin_dim[0] = Nbin_x_for_area_transfer;
30494  bin_dim[1] = Nbin_y_for_area_transfer;
30495  params.dimensions_of_bin_array() = bin_dim;
30496  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(&params);
30497 
30498 #endif
30499 
30500  // Set up a map from pointer to element to its number
30501  // in the mesh
30502  std::map<GeneralisedElement*, unsigned> element_number;
30503  unsigned nelem = this->nelement();
30504  for (unsigned e = 0; e < nelem; e++)
30505  {
30506  element_number[this->element_pt(e)] = e;
30507  }
30508 
30509 #ifndef OOMPH_HAS_CGAL
30510 
30511  // Create a vector to store the min target area of each bin (at
30512  // this stage the number of bins should not be that large, so it
30513  // should be safe to build a vector for the total number of bins)
30514  Vector<double> bin_min_target_area;
30515 
30516  // Get pointer to sample point container
30517  NonRefineableBinArray* bin_array_pt =
30518  dynamic_cast<NonRefineableBinArray*>(
30519  mesh_geom_obj_pt->sample_point_container_pt());
30520  if (bin_array_pt == 0)
30521  {
30522  throw OomphLibError(
30523  "Sample point container has to be NonRefineableBinArray",
30524  OOMPH_CURRENT_FUNCTION,
30525  OOMPH_EXCEPTION_LOCATION);
30526  }
30527 
30528  {
30529  unsigned n_bin = 0;
30530  unsigned max_n_entry = 0;
30531  unsigned min_n_entry = UINT_MAX;
30532  unsigned tot_n_entry = 0;
30533  unsigned n_empty = 0;
30534  bin_array_pt->get_fill_stats(
30535  n_bin, max_n_entry, min_n_entry, tot_n_entry, n_empty);
30536 
30537  oomph_info << "Before bin diffusion:"
30538  << " nbin:(" << n_bin << ")"
30539  << " nempty:(" << n_empty << ")"
30540  << " min:(" << min_n_entry << ")"
30541  << " max:(" << max_n_entry << ")"
30542  << " average entries:("
30543  << double(tot_n_entry) / double(n_bin) << ")" << std::endl;
30544  }
30545 
30546  // Fill bin by diffusion
30547  double t0_bin_diff = TimingHelpers::timer();
30548  oomph_info << "Going into diffusion bit...\n";
30549  bin_array_pt->fill_bin_by_diffusion();
30550  oomph_info << "Back from diffusion bit...\n";
30551  oomph_info << "Time for bin diffusion: "
30552  << TimingHelpers::timer() - t0_bin_diff << std::endl;
30553 
30554  // Do some stats
30555  {
30556  unsigned n_bin = 0;
30557  unsigned max_n_entry = 0;
30558  unsigned min_n_entry = UINT_MAX;
30559  unsigned tot_n_entry = 0;
30560  unsigned n_empty = 0;
30561  bin_array_pt->get_fill_stats(
30562  n_bin, max_n_entry, min_n_entry, tot_n_entry, n_empty);
30563 
30564  oomph_info << "After bin diffusion:"
30565  << " nbin:(" << n_bin << ")"
30566  << " nempty:(" << n_empty << ")"
30567  << " min:(" << min_n_entry << ")"
30568  << " max:(" << max_n_entry << ")"
30569  << " average entries:("
30570  << double(tot_n_entry) / double(n_bin) << ")" << std::endl;
30571  }
30572 
30573 
30574  // For each bin, compute the minimum of the target areas in the bin
30575 
30576  // Timing for map
30577  double t_total_map = 0.0;
30578 
30579  // Counter for map
30580  unsigned counter_map = 0;
30581 
30582  // Get access to the bins (we need access to the content of the
30583  // bins to compute the minimum of the target areas of the elements
30584  // in each bin)
30585  const std::map<unsigned,
30586  Vector<std::pair<FiniteElement*, Vector<double>>>>*
30587  bins_pt = bin_array_pt->get_all_bins_content();
30588 
30589  // Get the number of bins
30590  const unsigned n_bin = bins_pt->size();
30591 
30592  // Create a vector to store the min target area of each bin (at
30593  // this stage the number of bins should not be that large, so it
30594  // should be safe to build a vector for the total number of bins)
30595  bin_min_target_area.resize(n_bin);
30596  for (unsigned u = 0; u < n_bin; u++)
30597  {
30598  bin_min_target_area[u] = 0.0;
30599  }
30600  // loop over the bins, get their elements and compute the minimum
30601  // target area of all of them
30602  typedef std::map<
30603  unsigned,
30604  Vector<std::pair<FiniteElement*, Vector<double>>>>::const_iterator IT;
30605  for (IT it = bins_pt->begin(); it != bins_pt->end(); it++)
30606  {
30607  // The bin number
30608  unsigned ib = (*it).first;
30609 
30610  // Get the number of elements in the bin
30611  const unsigned n_ele_bin = (*it).second.size();
30612 
30613  // loop over the elements in the bin
30614  for (unsigned ee = 0; ee < n_ele_bin; ee++)
30615  {
30616  // Get ee-th element (in currrent mesh) in ib-th bin
30617  GeneralisedElement* ele_pt = (*it).second[ee].first;
30618  double t_map = TimingHelpers::timer();
30619  const unsigned ele_number = element_number[ele_pt];
30620  t_total_map += TimingHelpers::timer() - t_map;
30621 
30622  // Increase the number of calls to map
30623  counter_map++;
30624 
30625  // Go for smallest target area of any element in this bin to
30626  // force "one level" of refinement (the one-level-ness is
30627  // enforced below by limiting the actual reduction in area
30628  if (bin_min_target_area[ib] != 0)
30629  {
30630  bin_min_target_area[ib] =
30631  std::min(bin_min_target_area[ib], target_area[ele_number]);
30632  }
30633  else
30634  {
30635  bin_min_target_area[ib] = target_area[ele_number];
30636  }
30637 
30638  } // for (ee<n_ele_bin)
30639 
30640  } // for (it!=bins.end())
30641 
30642  oomph_info << "CPU for map[counter=" << counter_map
30643  << "]: " << t_total_map << std::endl;
30644 
30645 
30646  // Optional output for debugging (keep it around!)
30647  const bool output_bins = false;
30648  if (output_bins)
30649  {
30650  unsigned length = bin_min_target_area.size();
30651  for (unsigned u = 0; u < length; u++)
30652  {
30653  oomph_info << "Bin n" << u
30654  << ",target area: " << bin_min_target_area[u] << std::endl;
30655  }
30656  }
30657 
30658 #endif
30659 
30660 
30661  // Now start iterating to refine mesh recursively
30662  //-----------------------------------------------
30663  bool done = false;
30664  unsigned iter = 0;
30665 #ifdef OOMPH_HAS_MPI
30666  // The number of elements that require (un)refinement
30667  unsigned n_ele_need_refinement = 0;
30668 #endif
30669 
30670  // The timing for the third stage of segments connectivity
30671  double t_total_third_stage_segments_connectivity = 0.0;
30672 
30673  // The timing for the transfering target areas
30674  double t_total_transfer_target_areas = 0.0;
30675 
30676  // The timing for the copying of target areas
30677  double t_total_limit_target_areas = 0.0;
30678 
30679  // The timing to create the new mesh
30680  double t_total_create_new_adapted_mesh = 0.0;
30681 
30682  // The timing for the snapping of the nodes on the new meshes
30683  double t_total_snap_nodes = 0.0;
30684 
30685  // The timing to check whether other processors need to adapt
30686  double t_total_wait_other_processors = 0.0;
30687  double t_iter = TimingHelpers::timer();
30688  while (!done)
30689  {
30690  // Accept by default but overwrite if things go wrong below
30691  done = true;
30692 
30693  double t_start_transfer_target_areas = TimingHelpers::timer();
30694  double t0_loop_int_pts = TimingHelpers::timer();
30695 
30696  // Loop over elements in new (tmp) mesh and visit all
30697  // its integration points. Check where it's located in the bin
30698  // structure of the current mesh and pass the target area
30699  // to the new element
30700  nelem = tmp_new_mesh_pt->nelement();
30701 
30702  // Store the target areas for elements in the temporary
30703  // TriangulateIO mesh
30704  Vector<double> new_transferred_target_area(nelem, 0.0);
30705  for (unsigned e = 0; e < nelem; e++)
30706  { // start loop el
30707  ELEMENT* el_pt =
30708  dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30709  unsigned nint = el_pt->integral_pt()->nweight();
30710  for (unsigned ipt = 0; ipt < nint; ipt++)
30711  {
30712  // Get the coordinate of current point
30713  Vector<double> s(2);
30714  for (unsigned i = 0; i < 2; i++)
30715  {
30716  s[i] = el_pt->integral_pt()->knot(ipt, i);
30717  }
30718 
30719  Vector<double> x(2);
30720  el_pt->interpolated_x(s, x);
30721 
30722 #if OOMPH_HAS_CGAL
30723 
30724  // Try the five nearest sample points for Newton search
30725  // then just settle on the nearest one
30726  GeomObject* geom_obj_pt = 0;
30727  unsigned max_sample_points =
30728  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30729  dynamic_cast<CGALSamplePointContainer*>(
30730  mesh_geom_obj_pt->sample_point_container_pt())
30731  ->limited_locate_zeta(x, max_sample_points, geom_obj_pt, s);
30732 #ifdef PARANOID
30733  if (geom_obj_pt == 0)
30734  {
30735  std::stringstream error_message;
30736  error_message << "Limited locate zeta failed for zeta = [ "
30737  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30738  throw OomphLibError(error_message.str(),
30739  OOMPH_CURRENT_FUNCTION,
30740  OOMPH_EXCEPTION_LOCATION);
30741  }
30742  else
30743  {
30744 #endif
30745  FiniteElement* fe_pt = dynamic_cast<FiniteElement*>(geom_obj_pt);
30746 #ifdef PARANOID
30747  if (fe_pt == 0)
30748  {
30749  std::stringstream error_message;
30750  error_message << "Cast to FE for GeomObject returned by "
30751  "limited locate zeta failed for zeta = [ "
30752  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30753  throw OomphLibError(error_message.str(),
30754  OOMPH_CURRENT_FUNCTION,
30755  OOMPH_EXCEPTION_LOCATION);
30756  }
30757  else
30758  {
30759 #endif
30760  // What's the target area of the element that contains this
30761  // point
30762  double tg_area = target_area[element_number[fe_pt]];
30763 
30764  // Go for smallest target area over all integration
30765  // points in new element
30766  // to force "one level" of refinement (the one-level-ness
30767  // is enforced below by limiting the actual reduction in
30768  // area
30769  if (new_transferred_target_area[e] != 0)
30770  {
30771  new_transferred_target_area[e] =
30772  std::min(new_transferred_target_area[e], tg_area);
30773  }
30774  else
30775  {
30776  new_transferred_target_area[e] = tg_area;
30777  }
30778 #ifdef PARANOID
30779  }
30780  }
30781 #endif
30782 
30783 #else
30784 
30785  // Find the bin that contains that point and its contents
30786  int bin_number = 0;
30787  bin_array_pt->get_bin(x, bin_number);
30788 
30789  // Did we find it?
30790  if (bin_number < 0)
30791  {
30792  // Not even within bin boundaries... odd
30793  std::stringstream error_message;
30794  error_message << "Very odd -- we're looking for a point[ " << x[0]
30795  << " " << x[1] << " ] that's not even \n"
30796  << "located within the bin boundaries.\n";
30797  throw OomphLibError(error_message.str(),
30798  "RefineableTriangleMesh::adapt()",
30799  OOMPH_EXCEPTION_LOCATION);
30800  } // if (bin_number<0)
30801  else
30802  {
30803  // Go for smallest target area of any element in this bin
30804  // to force "one level" of refinement (the one-level-ness
30805  // is enforced below by limiting the actual reduction in
30806  // area
30807  if (new_transferred_target_area[e] != 0)
30808  {
30809  new_transferred_target_area[e] =
30810  std::min(new_transferred_target_area[e],
30811  bin_min_target_area[bin_number]);
30812  }
30813  else
30814  {
30815  new_transferred_target_area[e] =
30816  bin_min_target_area[bin_number];
30817  }
30818  }
30819 
30820 #endif
30821 
30822  } // for (ipt<nint)
30823 
30824  } // for (e<nelem)
30825 
30826 
30827  // do some output (keep it alive!)
30828  const bool output_target_areas = false;
30829  if (output_target_areas)
30830  {
30831  unsigned length = new_transferred_target_area.size();
30832  for (unsigned u = 0; u < length; u++)
30833  {
30834  oomph_info << "Element" << u
30835  << ",target area: " << new_transferred_target_area[u]
30836  << std::endl;
30837  }
30838  }
30839  oomph_info << "Time for loop over integration points in new mesh: "
30840  << TimingHelpers::timer() - t0_loop_int_pts << std::endl;
30841 
30842 
30843  // {
30844  // tmp.open((Global_string_for_annotation::
30845  // String[0]+"binned_target_areas"+
30846  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30847 
30848  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > >
30849  // bin_content=
30850  // mesh_geom_obj_pt->bin_content();
30851  // unsigned nbin=bin_content.size();
30852  // for (unsigned b=0;b<nbin;b++)
30853  // {
30854  // unsigned nentry=bin_content[b].size();
30855  // for (unsigned entry=0;entry<nentry;entry++)
30856  // {
30857  // FiniteElement* el_pt=bin_content[b][entry].first;
30858  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30859  // Vector<double> s=bin_content[b][entry].second;
30860  // Vector<double> x(2);
30861  // el_pt->interpolated_x(s,x);
30862  // unsigned e_current=element_number[gen_el_pt];
30863  // tmp << x[0] << " " << x[1] << " "
30864  // << target_area[e_current] << " "
30865  // << el_pt->size() << " "
30866  // << std::endl;
30867  // }
30868  // }
30869  // tmp.close();
30870  // }
30871 
30872  const double t_sub_total_transfer_target_areas =
30873  TimingHelpers::timer() - t_start_transfer_target_areas;
30874 
30875  if (Print_timings_level_adaptation > 2)
30876  {
30877  // Get the number of elements in the old mesh (this)
30878  const unsigned n_element = this->nelement();
30879  // Get the number of elements in the background mesh
30880  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30881 
30882  oomph_info << "CPU for transfer of target areas "
30883  << "[n_ele_old_mesh=" << n_element
30884  << ", n_ele_background_mesh=" << n_element_background
30885  << "] (iter " << iter
30886  << "): " << t_sub_total_transfer_target_areas << std::endl;
30887  }
30888 
30889  // Add the timing for tranfer of target areas
30890  t_total_transfer_target_areas += t_sub_total_transfer_target_areas;
30891 
30892  // // Output mesh
30893  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30894  // StringConversion::to_string(iter)+".dat").c_str());
30895 
30896  // tmp.open((Global_string_for_annotation::
30897  // String[0]+"target_areas_intermediate_mesh_iter"+
30898  // StringConversion::to_string(iter)+"_"+
30899  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30900 
30901  const double t_start_limit_target_areas = TimingHelpers::timer();
30902 
30903  // Now copy into target area for temporary mesh but limit to
30904  // the equivalent of one sub-division per iteration
30905 #ifdef OOMPH_HAS_MPI
30906  unsigned n_ele_need_refinement_iter = 0;
30907 #endif
30908 
30909 
30910  // Don't delete! Keep these around for debugging
30911  // ofstream tmp_mesh_file;
30912  // tmp_mesh_file.open("tmp_mesh_file.dat");
30913  // tmp_new_mesh_pt->output(tmp_mesh_file);
30914  // tmp_mesh_file.close();
30915  // ofstream target_areas_file;
30916  // target_areas_file.open("target_areas_file.dat");
30917 
30918  const unsigned nel_new = tmp_new_mesh_pt->nelement();
30919  Vector<double> new_target_area(nel_new);
30920  for (unsigned e = 0; e < nel_new; e++)
30921  {
30922  // The finite element
30923  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30924 
30925  // Transferred target area
30926  const double new_area = new_transferred_target_area[e];
30927  if (new_area <= 0.0)
30928  {
30929  std::ostringstream error_stream;
30930  error_stream
30931  << "This shouldn't happen! Element whose centroid is at "
30932  << (f_ele_pt->node_pt(0)->x(0) + f_ele_pt->node_pt(1)->x(0) +
30933  f_ele_pt->node_pt(2)->x(0)) /
30934  3.0
30935  << " "
30936  << (f_ele_pt->node_pt(0)->x(1) + f_ele_pt->node_pt(1)->x(1) +
30937  f_ele_pt->node_pt(2)->x(1)) /
30938  3.0
30939  << " "
30940  << " has no target area assigned\n";
30941  throw OomphLibError(error_stream.str(),
30942  OOMPH_CURRENT_FUNCTION,
30943  OOMPH_EXCEPTION_LOCATION);
30944  }
30945  else
30946  {
30947  // Limit target area to the equivalent of uniform refinement
30948  // during this stage of the iteration
30949  new_target_area[e] = new_area;
30950  if (new_target_area[e] < f_ele_pt->size() / 3.0)
30951  {
30952  new_target_area[e] = f_ele_pt->size() / 3.0;
30953 
30954  // We'll need to give it another go later
30955  done = false;
30956  }
30957 
30958  // Don't delete! Keep around for debugging
30959  // target_areas_file
30960  // << (f_ele_pt->node_pt(0)->x(0)+
30961  // f_ele_pt->node_pt(1)->x(0)+
30962  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30963  // << (f_ele_pt->node_pt(0)->x(1)+
30964  // f_ele_pt->node_pt(1)->x(1)+
30965  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30966  // << new_area << " "
30967  // << new_target_area[e] << std::endl;
30968 
30969 
30970 #ifdef OOMPH_HAS_MPI
30971  // Keep track of the elements that require (un)refinement
30972  n_ele_need_refinement_iter++;
30973 #endif
30974 
30975  } // else if (new_area <= 0.0)
30976 
30977  } // for (e < nel_new)
30978 
30979 
30980  // Don't delete! Keep around for debugging
30981  // target_areas_file.close();
30982 
30983  const double t_sub_total_limit_target_areas =
30984  TimingHelpers::timer() - t_start_limit_target_areas;
30985 
30986  // Add the timing for copying target areas
30987  t_total_limit_target_areas += t_sub_total_limit_target_areas;
30988 
30989  if (Print_timings_level_adaptation > 2)
30990  {
30991  // Get the number of elements in the old mesh (this)
30992  const unsigned n_element = this->nelement();
30993  // Get the number of elements in the background mesh
30994  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30995 
30996  oomph_info << "CPU for limiting target areas "
30997  << "[n_ele_old_mesh=" << n_element
30998  << ", n_ele_background_mesh=" << n_element_background
30999  << "] (iter " << iter
31000  << "): " << t_sub_total_limit_target_areas << std::endl;
31001  }
31002 
31003  if (done)
31004  {
31005  oomph_info
31006  << "All area adjustments accommodated by max. permitted area"
31007  << " reduction \n";
31008  }
31009  else
31010  {
31011  oomph_info << "NOT all area adjustments accommodated by max. "
31012  << "permitted area reduction \n";
31013  }
31014 
31015  // tmp.close();
31016  // pause("doced binned_target_areas.dat and intermediate mesh targets");
31017 
31018  // Now create the new mesh from TriangulateIO structure
31019  //-----------------------------------------------------
31020  // associated with uniform background mesh and the
31021  //------------------------------------------------
31022  // associated target element sizes.
31023  //---------------------------------
31024 
31025  const double t_start_create_new_adapted_mesh = TimingHelpers::timer();
31026 
31027  // Solid mesh?
31028  if (solid_mesh_pt != 0)
31029  {
31030  new_mesh_pt = new RefineableSolidTriangleMesh<ELEMENT>(
31031  new_target_area,
31032  tmp_new_triangulateio,
31033  this->Time_stepper_pt,
31034  this->Use_attributes,
31035  this->Allow_automatic_creation_of_vertices_on_boundaries,
31036  this->communicator_pt());
31037  }
31038  // No solid mesh
31039  else
31040  {
31041  new_mesh_pt = new RefineableTriangleMesh<ELEMENT>(
31042  new_target_area,
31043  tmp_new_triangulateio,
31044  this->Time_stepper_pt,
31045  this->Use_attributes,
31046  this->Allow_automatic_creation_of_vertices_on_boundaries,
31047  this->communicator_pt());
31048  }
31049 
31050  // Sub-total to create new adapted mesh
31051  const double t_sub_total_create_new_adapted_mesh =
31052  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
31053 
31054  // Add the time to the total snap nodes time
31055  t_total_create_new_adapted_mesh += t_sub_total_create_new_adapted_mesh;
31056 
31057  if (Print_timings_level_adaptation > 2)
31058  {
31059  // Get the number of elements of the new adapted mesh
31060  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
31061 
31062  oomph_info << "CPU for creation of new adapted mesh "
31063  << t_sub_total_create_new_adapted_mesh
31064  << "[nele=" << n_element_new_adapted_mesh << "] (iter "
31065  << iter << "): " << t_sub_total_create_new_adapted_mesh
31066  << std::endl;
31067  }
31068 
31069 #ifdef OOMPH_HAS_MPI
31070  // ------------------------------------------
31071  // DISTRIBUTED MESH: BEGIN
31072  // ------------------------------------------
31073 
31074  // This section is only required if we are dealing with
31075  // distributed meshes, otherwise there are not shared boundaries
31076  // overlapping internal boundaries
31077 
31078  // Check if necessary to fill boundary elements for those internal
31079  // boundaries that overlap shared boundaries
31080  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
31081  {
31082  // Copy the data structures that indicate which shared
31083  // boundaries are part of an internal boundary
31085  this->shared_boundary_overlaps_internal_boundary();
31086 
31087  // Copy the data structure that indicates which are the shared
31088  // boundaries in each processor
31089  new_mesh_pt->shared_boundaries_ids() = this->shared_boundaries_ids();
31090 
31091  // Fill the structures for the boundary elements and face indexes
31092  // of the boundary elements
31093  new_mesh_pt
31095  }
31096  // ------------------------------------------
31097  // DISTRIBUTED MESH: END
31098  // ------------------------------------------
31099 #endif // #ifdef OOMPH_HAS_MPI
31100 
31101  // Snap to curvilinear boundaries (some code duplication as this
31102  // is repeated below but helper function would take so many
31103  // arguments that it's nearly as messy...
31104 
31105  // Pass the boundary geometric objects to the new mesh
31106  new_mesh_pt->boundary_geom_object_pt() =
31107  this->boundary_geom_object_pt();
31108 
31109  // Reset the boundary coordinates if there is
31110  // a geometric object associated with the boundary
31111  new_mesh_pt->boundary_coordinate_limits() =
31112  this->boundary_coordinate_limits();
31113 
31114  const double t_start_third_stage_segments_connectivity =
31115  TimingHelpers::timer();
31116 
31117  for (unsigned b = 0; b < n_boundary; b++)
31118  {
31119  // ------------------------------------------
31120  // DISTRIBUTED MESH: BEGIN
31121  // ------------------------------------------
31122 
31123  // Before setting up boundary coordinates for the new mesh we
31124  // require to identify the segments with the old mesh to
31125  // assign initial zeta values
31126 #ifdef OOMPH_HAS_MPI
31127  if (this->is_mesh_distributed())
31128  {
31129  // Identify the segments of the new mesh with the ones of
31130  // the original mesh
31131  new_mesh_pt
31133  this);
31134  }
31135 #endif
31136  // ------------------------------------------
31137  // DISTRIBUTED MESH: END
31138  // ------------------------------------------
31139 
31140  // Setup boundary coordinates for boundaries with GeomObject
31141  // associated
31142  if (new_mesh_pt->boundary_geom_object_pt(b) != 0)
31143  {
31144  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
31145  }
31146  }
31147 
31148  t_total_third_stage_segments_connectivity +=
31149  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
31150 
31151  const double t_start_snap_nodes_new_mesh = TimingHelpers::timer();
31152  // Move the nodes on the new boundary onto the old curvilinear
31153  // boundary. If the boundary is straight this will do precisely
31154  // nothing but will be somewhat inefficient
31155  for (unsigned b = 0; b < n_boundary; b++)
31156  {
31157  this->snap_nodes_onto_boundary(new_mesh_pt, b);
31158  }
31159 
31160  const double t_sub_total_snap_nodes_new_mesh =
31161  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
31162 
31163  // Add the time to the total snap nodes time
31164  t_total_snap_nodes += t_sub_total_snap_nodes_new_mesh;
31165 
31166  if (Print_timings_level_adaptation > 2)
31167  {
31168  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
31169  << "(iter " << iter
31170  << "): " << t_sub_total_snap_nodes_new_mesh << std::endl;
31171  }
31172 
31173  // Update mesh further?
31174  if (Mesh_update_fct_pt != 0)
31175  {
31176  Mesh_update_fct_pt(new_mesh_pt);
31177  }
31178 
31179  // If we have a continuation problem
31180  // any problem in which the timestepper is a "generalisedtimestepper",
31181  // which will have been set by the problem, then ensure
31182  // all data in the new mesh has the appropriate timestepper
31183  if (dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
31184  {
31185  new_mesh_pt->set_nodal_and_elemental_time_stepper(
31186  this->Time_stepper_pt, false);
31187  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,
31188  false);
31189  }
31190 
31191  // Not done: get ready for another iteration
31192  iter++;
31193  delete tmp_new_mesh_pt;
31194 
31195 #ifdef OOMPH_HAS_MPI
31196  // Check whether the number of elements that need (un)refinement
31197  // from the previous iteration is the same, if that is the case
31198  // then we mark this processor as done
31199  if (n_ele_need_refinement_iter == n_ele_need_refinement)
31200  {
31201  done = true;
31202  }
31203  // Update the number of elements that require further
31204  // (un)refinement
31205  n_ele_need_refinement = n_ele_need_refinement_iter;
31206 #endif // #ifdef OOMPH_HAS_MPI
31207 
31208  // ------------------------------------------
31209  // DISTRIBUTED MESH: BEGIN
31210  // ------------------------------------------
31211 
31212  // We can only finish the iteration adaptation process if ALL
31213  // the involved processor are marked as done, otherwise, ALL
31214  // processor need to go for another iteration
31215 #ifdef OOMPH_HAS_MPI
31216  if (this->is_mesh_distributed())
31217  {
31218  // Time to check whether other processors have finish to adapt
31219  const double t_start_wait_other_processors = TimingHelpers::timer();
31220 
31221  // In case that the mesh is distributed it is necessary to
31222  // verify that no processor requires further refinement. If at
31223  // least one processor needs more refinement then all
31224  // processors need to go for another iteration to participate
31225  // in the communications
31226  unsigned this_processor_requires_another_iteration = 1;
31227 
31228  // Is this processor done?
31229  if (done)
31230  {
31231  this_processor_requires_another_iteration = 0;
31232  }
31233  int nproc_not_done = this_processor_requires_another_iteration;
31234  // Get the communicator of the mesh
31235  OomphCommunicator* comm_pt = this->communicator_pt();
31236  // Communicate with all procesoors to check whether we need to
31237  // re-iterate
31238  MPI_Allreduce(&this_processor_requires_another_iteration,
31239  &nproc_not_done,
31240  1,
31241  MPI_UNSIGNED,
31242  MPI_SUM,
31243  comm_pt->mpi_comm());
31244  // Are all processors done?
31245  if (nproc_not_done > 0)
31246  {
31247  oomph_info
31248  << "At least one processors requires further refinement. "
31249  << "Go for another iteration." << std::endl;
31250  done = false;
31251  }
31252 
31253  // Total to check whether other processors have finish to
31254  // adapt
31255  const double t_sub_total_wait_other_processors =
31256  TimingHelpers::timer() - t_start_wait_other_processors;
31257 
31258  // Add to the total timings to check whether other processors
31259  // need to adapt
31260  t_total_wait_other_processors += t_sub_total_wait_other_processors;
31261 
31262  if (Print_timings_level_adaptation > 2)
31263  {
31264  oomph_info << "CPU for waiting other processors "
31265  << "(iter " << iter
31266  << "): " << t_sub_total_wait_other_processors
31267  << std::endl;
31268  }
31269 
31270  } // if (this->is_mesh_distributed())
31271 #endif
31272  // ------------------------------------------
31273  // DISTRIBUTED MESH: END
31274  // ------------------------------------------
31275 
31276  if (!done)
31277  {
31278  oomph_info << "Going for another iteration. Current iteration ("
31279  << iter << ")" << std::endl;
31280 
31281  // Use the new mesh as the tmp mesh
31282  tmp_new_mesh_pt = new_mesh_pt;
31283  tmp_new_triangulateio = new_mesh_pt->triangulateio_representation();
31284  }
31285 
31286  } // end of iteration (while (!done))
31287 
31288  // Delete the temporary geometric object representation of the
31289  // current mesh
31290  delete mesh_geom_obj_pt;
31291 
31292  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31293  << TimingHelpers::timer() - t_iter << std::endl;
31294 
31295  if (Print_timings_level_adaptation > 1)
31296  {
31297  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31298  << t_total_create_new_adapted_mesh << std::endl;
31299 
31300  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31301  << t_total_limit_target_areas << std::endl;
31302 
31303  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31304  << t_total_transfer_target_areas << std::endl;
31305 
31306  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31307  << t_total_wait_other_processors << std::endl;
31308  }
31309 
31310  // ==============================================================
31311  // END: Transferring of target areas and creation of new mesh
31312  // ==============================================================
31313 
31314  // ==============================================================
31315  // BEGIN: Project solution from the old to the new mesh
31316  // ==============================================================
31317 
31318  // Check that the projection step is not disabled
31319  if (!Disable_projection)
31320  {
31321  // Take the time for the projection step
31322  double tt_start_projection = TimingHelpers::timer();
31323 
31324  // Print info. for tranfering target areas
31325  if (Print_timings_projection)
31326  {
31327  // Switch timings and stats on
31328  Multi_domain_functions::Doc_timings = true;
31329  Multi_domain_functions::Doc_stats = true;
31330  Multi_domain_functions::Doc_full_stats = true;
31331  }
31332 
31333  double t_proj = TimingHelpers::timer();
31334  oomph_info << "About to begin projection.\n";
31335 
31336  // Project current solution onto new mesh
31337  //---------------------------------------
31338  ProjectionProblem<ELEMENT>* project_problem_pt =
31339  new ProjectionProblem<ELEMENT>;
31340 
31341  // Projection requires to be enabled as distributed if working
31342  // with a distributed mesh
31343 #ifdef OOMPH_HAS_MPI
31344  if (this->is_mesh_distributed())
31345  {
31346  // ------------------------------------------
31347  // DISTRIBUTED MESH: BEGIN
31348  // ------------------------------------------
31349 
31350  // We need to back up the time stepper object since the
31351  // projection class creates a new one
31352  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31353 
31354  // Set the projection problem as distributed
31355  project_problem_pt->enable_problem_distributed();
31356 
31357  // Pass the time stepper to the projection problem (used when
31358  // setting multi_domain_interation)
31359  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31360 
31361  // Set the mesh used for the projection object
31362  project_problem_pt->mesh_pt() = new_mesh_pt;
31363  // project_problem_pt->disable_suppress_output_during_projection();
31364 
31365  // Use iterative solver for projection? By default, an iterative
31366  // solver is used for the projection stage
31367  if (!this->use_iterative_solver_for_projection())
31368  {
31369  project_problem_pt->disable_use_iterative_solver_for_projection();
31370  }
31371 
31372  // Do the projection
31373  project_problem_pt->project(this);
31374 
31375  // Reset the time stepper object (only affects distributed meshes)
31376  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31377 
31378  // ------------------------------------------
31379  // DISTRIBUTED MESH: END
31380  // ------------------------------------------
31381 
31382  } // if (this->is_mesh_distributed())
31383  else
31384 #endif // #ifdef OOMPH_HAS_MPI
31385  {
31386  // Set the mesh used for the projection object
31387  project_problem_pt->mesh_pt() = new_mesh_pt;
31388 
31389  // project_problem_pt->disable_suppress_output_during_projection();
31390 
31391  // Use iterative solver for projection? By default, an iterative
31392  // solver is used for the projection stage
31393  if (!this->use_iterative_solver_for_projection())
31394  {
31395  project_problem_pt->disable_use_iterative_solver_for_projection();
31396  }
31397 
31398  // Do the projection
31399  project_problem_pt->project(this);
31400  }
31401 
31402  // Reset printing info. for projection
31403  if (Print_timings_projection)
31404  {
31405  // Switch timings and stats off
31406  Multi_domain_functions::Doc_timings = false;
31407  Multi_domain_functions::Doc_stats = false;
31408  Multi_domain_functions::Doc_full_stats = false;
31409  }
31410 
31411  // Get the total time for projection
31412  const double tt_projection =
31413  TimingHelpers::timer() - tt_start_projection;
31414 
31415  if (Print_timings_level_adaptation > 1)
31416  {
31417  // Get the number of elements in the old mesh (this)
31418  const unsigned n_element = this->nelement();
31419  // Get the number of elements in the new mesh
31420  const unsigned n_element_new = new_mesh_pt->nelement();
31421  oomph_info << "CPU for projection (in mesh adaptation) "
31422  << "[n_ele_old_mesh=" << n_element
31423  << ", n_ele_new_mesh=" << n_element_new
31424  << "]: " << tt_projection << std::endl;
31425 
31426  // ------------------------------------------
31427  // DISTRIBUTED MESH: BEGIN
31428  // ------------------------------------------
31429 #ifdef OOMPH_HAS_MPI
31430  if (this->is_mesh_distributed())
31431  {
31432  // The maximum number of elements in the mesh (over all
31433  // processors)
31434  unsigned n_this_element_new = n_element_new;
31435  unsigned n_max_element_new_global = 0;
31436  // Get the maximum number of elements over all processors
31437  MPI_Reduce(&n_this_element_new,
31438  &n_max_element_new_global,
31439  1,
31440  MPI_UNSIGNED,
31441  MPI_MAX,
31442  0,
31443  this->communicator_pt()->mpi_comm());
31444 
31445  // The time for projection for this processor
31446  double tt_this_projection = tt_projection;
31447  double tt_global_min_projection = 0.0;
31448  double tt_global_max_projection = 0.0;
31449 
31450  // Get the minimum and maximum time for projection
31451  MPI_Reduce(&tt_this_projection,
31452  &tt_global_min_projection,
31453  1,
31454  MPI_DOUBLE,
31455  MPI_MIN,
31456  0,
31457  this->communicator_pt()->mpi_comm());
31458  MPI_Reduce(&tt_this_projection,
31459  &tt_global_max_projection,
31460  1,
31461  MPI_DOUBLE,
31462  MPI_MAX,
31463  0,
31464  this->communicator_pt()->mpi_comm());
31465 
31466  if (this->communicator_pt()->my_rank() == 0)
31467  {
31468  oomph_info << "CPU for projection global (MIN): "
31469  << tt_global_min_projection << std::endl;
31470  oomph_info << "CPU for projection global (MAX) "
31471  << "[n_max_ele_new_global=" << n_max_element_new_global
31472  << "]: " << tt_global_max_projection << std::endl;
31473 
31474  std::cerr << "CPU for projection global (MIN): "
31475  << tt_global_min_projection << std::endl;
31476  std::cerr << "CPU for projection global (MAX): "
31477  << "[n_max_ele_new_global=" << n_max_element_new_global
31478  << "]: " << tt_global_max_projection << std::endl;
31479  }
31480  }
31481 #endif // #ifdef OOMPH_HAS_MPI
31482  // ------------------------------------------
31483  // DISTRIBUTED MESH: END
31484  // ------------------------------------------
31485 
31486  } // if (Print_timings_level_adaptation>1)
31487 
31488  oomph_info << "CPU for projection of solution onto new mesh: "
31489  << TimingHelpers::timer() - t_proj << std::endl;
31490 
31491  // Delete the projection problem
31492  delete project_problem_pt;
31493 
31494  } // if (!Disable_projection)
31495  else
31496  {
31497  oomph_info << "Projection disabled! The new mesh will contain zeros"
31498  << std::endl;
31499  }
31500 
31501  // ==============================================================
31502  // END: Project solution from the old to the new mesh
31503  // ==============================================================
31504 
31505  double t_rest = TimingHelpers::timer();
31506 
31507  // Flush the old mesh
31508  unsigned nnod = nnode();
31509  for (unsigned j = nnod; j > 0; j--)
31510  {
31511  delete Node_pt[j - 1];
31512  Node_pt[j - 1] = 0;
31513  }
31514  unsigned nel = nelement();
31515  for (unsigned e = nel; e > 0; e--)
31516  {
31517  delete Element_pt[e - 1];
31518  Element_pt[e - 1] = 0;
31519  }
31520 
31521  // Now copy back to current mesh
31522  //------------------------------
31523  nnod = new_mesh_pt->nnode();
31524  Node_pt.resize(nnod);
31525  nel = new_mesh_pt->nelement();
31526  Element_pt.resize(nel);
31527  for (unsigned j = 0; j < nnod; j++)
31528  {
31529  Node_pt[j] = new_mesh_pt->node_pt(j);
31530  }
31531  for (unsigned e = 0; e < nel; e++)
31532  {
31533  Element_pt[e] = new_mesh_pt->element_pt(e);
31534  }
31535 
31536  // Copy the boundary elements information from the new mesh to the
31537  // original mesh
31538  unsigned nbound = 0;
31539 
31540 #ifdef OOMPH_HAS_MPI
31541  // If working with a distributed mesh we need to change the number
31542  // of boundaries so that shared boundaries information is also
31543  // copied from the old to the new mesh
31544  if (this->is_mesh_distributed())
31545  {
31546  // The boundaries to be copied include those new ones in the new
31547  // mesh (shared boundaries). This info. is required to
31548  // re-establish the halo/haloed scheme
31549  nbound = new_mesh_pt->nboundary();
31550  // After halo and haloed scheme has been re-established the
31551  // number of boundaries is changed to the original number of
31552  // boundaries
31553  }
31554  else
31555 #endif
31556  {
31557  // The original number of boundaries
31558  nbound = n_boundary;
31559  }
31560 
31561  Boundary_element_pt.resize(nbound);
31562  Face_index_at_boundary.resize(nbound);
31563  Boundary_node_pt.resize(nbound);
31564  for (unsigned b = 0; b < nbound; b++)
31565  {
31566  unsigned nel = new_mesh_pt->nboundary_element(b);
31567  Boundary_element_pt[b].resize(nel);
31568  Face_index_at_boundary[b].resize(nel);
31569  for (unsigned e = 0; e < nel; e++)
31570  {
31571  Boundary_element_pt[b][e] = new_mesh_pt->boundary_element_pt(b, e);
31572  Face_index_at_boundary[b][e] =
31573  new_mesh_pt->face_index_at_boundary(b, e);
31574  }
31575  unsigned nnod = new_mesh_pt->nboundary_node(b);
31576  Boundary_node_pt[b].resize(nnod);
31577  for (unsigned j = 0; j < nnod; j++)
31578  {
31579  Boundary_node_pt[b][j] = new_mesh_pt->boundary_node_pt(b, j);
31580  }
31581  }
31582 
31583  // Also copy over the new boundary and region information
31584  unsigned n_region = new_mesh_pt->nregion();
31585  // Only bother if we have regions
31586  if (n_region > 1)
31587  {
31588  // Deal with the region information first
31589  this->Region_attribute.resize(n_region);
31590  for (unsigned r = 0; r < n_region; r++)
31591  {
31592  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31593  // Get the region id
31594  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31595  // Find the number of elements in the region
31596  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31597  this->Region_element_pt[r_id].resize(n_region_element);
31598  for (unsigned e = 0; e < n_region_element; e++)
31599  {
31600  this->Region_element_pt[r_id][e] =
31601  new_mesh_pt->region_element_pt(r_id, e);
31602  }
31603  }
31604 
31605  // Now the boundary region information
31606  this->Boundary_region_element_pt.resize(nbound);
31607  this->Face_index_region_at_boundary.resize(nbound);
31608 
31609  // Now loop over the boundaries
31610  for (unsigned b = 0; b < nbound; ++b)
31611  {
31612  for (unsigned rr = 0; rr < n_region; rr++)
31613  {
31614  // The region id
31615  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31616 
31617  unsigned n_boundary_el_in_region =
31618  new_mesh_pt->nboundary_element_in_region(b, r);
31619 
31620  if (n_boundary_el_in_region > 0)
31621  {
31622  // Allocate storage in the map
31623  this->Boundary_region_element_pt[b][r].resize(
31624  n_boundary_el_in_region);
31625  this->Face_index_region_at_boundary[b][r].resize(
31626  n_boundary_el_in_region);
31627 
31628  // Copy over the information
31629  for (unsigned e = 0; e < n_boundary_el_in_region; ++e)
31630  {
31631  this->Boundary_region_element_pt[b][r][e] =
31632  new_mesh_pt->boundary_element_in_region_pt(b, r, e);
31633  this->Face_index_region_at_boundary[b][r][e] =
31634  new_mesh_pt->face_index_at_boundary_in_region(b, r, e);
31635  }
31636  }
31637  }
31638  } // End of loop over boundaries
31639 
31640  } // End of case when more than one region
31641 
31642  // ------------------------------------------
31643  // DISTRIBUTED MESH: BEGIN
31644  // ------------------------------------------
31645 
31646  // Re-generate halo(ed) information (only for distributed meshes)
31647 #ifdef OOMPH_HAS_MPI
31648  if (this->is_mesh_distributed())
31649  {
31650  // Delete halo(ed) information in the original mesh, the new
31651  // halo(ed) information is generated usign the info. of the new
31652  // mesh
31653  if (this->is_mesh_distributed())
31654  {
31655  this->Halo_node_pt.clear();
31656  this->Root_halo_element_pt.clear();
31657 
31658  this->Haloed_node_pt.clear();
31659  this->Root_haloed_element_pt.clear();
31660 
31661  this->External_halo_node_pt.clear();
31662  this->External_halo_element_pt.clear();
31663 
31664  this->External_haloed_node_pt.clear();
31665  this->External_haloed_element_pt.clear();
31666  }
31667 
31668  // Re-establish the shared boundary elements and nodes scheme
31669  // before re-establish halo(ed) information
31670  this->reset_shared_boundary_elements_and_nodes();
31671 
31672  // -------------------------------------------------------------
31673  // Remove shared boundary elements and nodes from original
31674  // boundary elements and boundary nodes containers. Shared
31675  // boundary elements and nodes are stored in a special
31676  // container.
31677 
31678  // Get the shared boundaries in this processor with any other
31679  // processor
31680  Vector<unsigned> my_rank_shared_boundaries_ids;
31681  this->shared_boundaries_in_this_processor(
31682  my_rank_shared_boundaries_ids);
31683 
31684  // Get the number of shared boundaries
31685  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31686  // Loop over the shared boundaries marked as original boundaries
31687  // in tmp_new_mesh
31688  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31689  {
31690  // Get the boundary id
31691  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31692  // Flush any previous relation of shared boundary elements
31693  // marked as original boundary elements in tmp_new_mesh
31694  this->Boundary_element_pt[shd_bnd_id].clear();
31695 
31696  // Get the number of nodes associated with the original
31697  // boundary in tmp_new_mesh that is a shared boundary
31698  const unsigned tmp_nnodes = this->nshared_boundary_node(shd_bnd_id);
31699  for (unsigned n = 0; n < tmp_nnodes; n++)
31700  {
31701  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31702  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31703  } // for (n < nnodes)
31704 
31705  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31706 
31707  // Re-set the number of boundaries to the original one
31708  this->set_nboundary(n_boundary);
31709 
31710  // Sort the nodes on the boundaries so that they have the same
31711  // order on all the boundaries
31712  this->sort_nodes_on_shared_boundaries();
31713 
31714  // Re-set the halo(ed) scheme
31715  this->reset_halo_haloed_scheme();
31716 
31717  // Set the correct number of segments for the boundaries with
31718  // geom objects associated
31719  for (unsigned b = 0; b < n_boundary; b++)
31720  {
31721  if (this->boundary_geom_object_pt(b) != 0)
31722  {
31723  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31724  this->set_nboundary_segment_node(b, nsegments);
31725  }
31726  }
31727 
31728  // Resume the connections in boundaries were it was suspended
31729  resume_boundary_connections(resume_initial_connection_polyline_pt,
31730  resume_final_connection_polyline_pt);
31731 
31732  } // if (this->is_mesh_distributed())
31733 
31734 #endif // #ifdef OOMPH_HAS_MPI
31735 
31736  // ------------------------------------------
31737  // DISTRIBUTED MESH: END
31738  // ------------------------------------------
31739 
31740  // Snap the newly created nodes onto any geometric objects
31741  this->snap_nodes_onto_geometric_objects();
31742 
31743  // Copy the IDs of the vertex nodes
31744  this->Oomph_vertex_nodes_id = new_mesh_pt->oomph_vertex_nodes_id();
31745 
31746  // Copy TriangulateIO representation
31747  TriangleHelper::clear_triangulateio(this->Triangulateio);
31748  bool quiet = true;
31749  this->Triangulateio =
31750  TriangleHelper::deep_copy_of_triangulateio_representation(
31751  new_mesh_pt->triangulateio_representation(), quiet);
31752 
31753  // Flush the mesh
31754  new_mesh_pt->flush_element_and_node_storage();
31755 
31756  // Delete the mesh
31757  delete new_mesh_pt;
31758 
31759  // Resume of timings
31760  if (Print_timings_level_adaptation > 2)
31761  {
31762  // Report timings related with setting boundary coordinates of
31763  // nodes on segments
31764  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31765  << t_total_first_stage_segments_connectivity << std::endl;
31766  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31767  << t_total_second_stage_segments_connectivity << std::endl;
31768  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31769  << t_total_third_stage_segments_connectivity << std::endl;
31770  }
31771 
31772  if (Print_timings_level_adaptation > 1)
31773  {
31774  const double t_total_segments_connectivity =
31775  t_total_first_stage_segments_connectivity +
31776  t_total_second_stage_segments_connectivity +
31777  t_total_third_stage_segments_connectivity;
31778 
31779  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31780  << t_total_segments_connectivity << std::endl;
31781 
31782  if (Print_timings_level_adaptation > 2)
31783  {
31784  // Report timings for snapping of nodes onto boundaries
31785  oomph_info << "CPU for snapping nodes onto boundaries "
31786  << "(new mesh): " << t_total_snap_nodes << std::endl;
31787  }
31788 
31789  t_total_snap_nodes += t_total_snap_nodes_bg_mesh;
31790  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31791  << t_total_snap_nodes << std::endl;
31792  }
31793 
31794  double max_area = 0.0;
31795  double min_area = 0.0;
31796 
31797  this->max_and_min_element_size(max_area, min_area);
31798  oomph_info << "Max/min element size in adapted mesh: " << max_area << " "
31799  << min_area << std::endl;
31800 
31801  oomph_info << "CPU time for final bits [sec]: "
31802  << TimingHelpers::timer() - t_rest << std::endl;
31803  }
31804  else
31805  {
31806  oomph_info << "Not enough benefit in adaptation.\n";
31807  Nrefined = 0;
31808  Nunrefined = 0;
31809  }
31810 
31811  double CPU_for_adaptation = TimingHelpers::timer() - t_start_overall;
31812  oomph_info << "CPU time for adaptation [sec]: " << CPU_for_adaptation
31813  << std::endl;
31814 
31815  // ------------------------------------------
31816  // DISTRIBUTED MESH: BEGIN
31817  // ------------------------------------------
31818 #ifdef OOMPH_HAS_MPI
31819  if (this->is_mesh_distributed())
31820  {
31821  // Get the communicator
31822  OomphCommunicator* comm_pt = this->communicator_pt();
31823  // Get the total number of processors to compute the average
31824  const unsigned n_proc = comm_pt->nproc();
31825  if (Print_timings_level_adaptation > 1 && n_proc > 1)
31826  {
31827  double global_min_CPU_for_adaptation = 0.0;
31828  double global_max_CPU_for_adaptation = 0.0;
31829  double global_average_CPU_for_adaptation = 0.0;
31830 
31831  // Get the maximum and minimum of the adaptation times
31832  MPI_Reduce(&CPU_for_adaptation,
31833  &global_min_CPU_for_adaptation,
31834  1,
31835  MPI_DOUBLE,
31836  MPI_MIN,
31837  0,
31838  comm_pt->mpi_comm());
31839  MPI_Reduce(&CPU_for_adaptation,
31840  &global_max_CPU_for_adaptation,
31841  1,
31842  MPI_DOUBLE,
31843  MPI_MAX,
31844  0,
31845  comm_pt->mpi_comm());
31846  MPI_Reduce(&CPU_for_adaptation,
31847  &global_average_CPU_for_adaptation,
31848  1,
31849  MPI_DOUBLE,
31850  MPI_SUM,
31851  0,
31852  comm_pt->mpi_comm());
31853 
31854  // Get the rank of the processor
31855  const unsigned my_rank = comm_pt->my_rank();
31856  if (my_rank == 0)
31857  {
31858  oomph_info << "CPU for adaptation (MIN): "
31859  << global_min_CPU_for_adaptation << std::endl;
31860  oomph_info << "CPU for adaptation (MAX): "
31861  << global_max_CPU_for_adaptation << std::endl;
31862  oomph_info << "CPU for adaptation (AVERAGE): "
31863  << global_average_CPU_for_adaptation / n_proc << std::endl;
31864  } // if (my_rank==0)
31865 
31866  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31867 
31868  } // if (this->is_mesh_distributed())
31869 
31870  // ------------------------------------------
31871  // DISTRIBUTED MESH: END
31872  // ------------------------------------------
31873 
31874 #endif // #ifdef OOMPH_HAS_MPI
31875  }
31876 
31877  //=========================================================================
31878  /// Mark the vertices that are not allowed for deletion by
31879  /// the unrefienment/refinement polyline methods. In charge of
31880  /// filling the Boundary_connections_pt structure
31881  //=========================================================================
31882  template<class ELEMENT>
31884  {
31885  // Clear any previous information
31886  // Boundary_chunk_connections_pt.clear();
31887  Boundary_connections_pt.clear();
31888 
31889  // Loop over the boundaries in the domain (outer, internal -- closed
31890  // and open ---, and shared) and get the boundaries ids with
31891  // connections (have or receive)
31892 
31893  // Store the boundaries ids that have or receive connection
31894  std::set<unsigned> boundary_id_with_connections;
31895 
31896  // ------------------------------------------------------------------
31897  // Outer boundaries
31898  // ------------------------------------------------------------------
31899 
31900  // Get the number of outer boundaries (closed boundaries)
31901  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31902 
31903  // Loop over the outer boundaries
31904  for (unsigned i = 0; i < n_outer_boundaries; i++)
31905  {
31906  // Get a temporary polygon representation
31907  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31908  // Get the number of polylines associated to the current outer
31909  // boundary
31910  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31911  // Loop over the polylines
31912  for (unsigned p = 0; p < n_polyline; p++)
31913  {
31914  // Get a temporary representation of the polyline
31915  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
31916 
31917  // Is the initial vertex connected?
31918  if (tmp_polyline_pt->is_initial_vertex_connected())
31919  {
31920  // Get the boundary id of the current polyline
31921  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31922 
31923  // Include the boundary id to the set of boundaries with
31924  // connections
31925  boundary_id_with_connections.insert(bnd_id);
31926 
31927  // Boundary id to which the curve is connecte
31928  const unsigned dst_bnd_id =
31929  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31930 
31931  // Include the destination boundary id to the set of
31932  // boundaries with connections
31933  boundary_id_with_connections.insert(dst_bnd_id);
31934 
31935  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31936 
31937  // Is the final vertex connected?
31938  if (tmp_polyline_pt->is_final_vertex_connected())
31939  {
31940  // Get the boundary id of the current polyline
31941  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31942 
31943  // Include the boundary id to the set of boundaries with
31944  // connections
31945  boundary_id_with_connections.insert(bnd_id);
31946 
31947  // Boundary id to which the curve is connected
31948  const unsigned dst_bnd_id =
31949  tmp_polyline_pt->final_vertex_connected_bnd_id();
31950 
31951  // Include the destination boundary id to the set of
31952  // boundaries with connections
31953  boundary_id_with_connections.insert(dst_bnd_id);
31954 
31955  } // if (tmp_polyline_pt->is_final_vertex_connected())
31956 
31957  } // for (p < n_polyline)
31958 
31959  } // for (i < n_outer_boundaries)
31960 
31961  // ------------------------------------------------------------------
31962  // Internal boundaries
31963  // ------------------------------------------------------------------
31964 
31965  // Get the number of internal boundaries (closed boundaries)
31966  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31967 
31968  // Loop over the internal boundaries
31969  for (unsigned i = 0; i < n_internal_boundaries; i++)
31970  {
31971  // Get a temporary polygon representation
31972  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31973  // Get the number of polylines associated to the current internal
31974  // boundary
31975  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31976  // Loop over the polylines
31977  for (unsigned p = 0; p < n_polyline; p++)
31978  {
31979  // Get a temporary representation of the polyline
31980  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
31981 
31982  // Is the initial vertex connected?
31983  if (tmp_polyline_pt->is_initial_vertex_connected())
31984  {
31985  // Get the boundary id of the current polyline
31986  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31987 
31988  // Include the boundary id to the set of boundaries with
31989  // connections
31990  boundary_id_with_connections.insert(bnd_id);
31991 
31992  // Boundary id to which the curve is connecte
31993  const unsigned dst_bnd_id =
31994  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31995 
31996  // Include the destination boundary id to the set of
31997  // boundaries with connections
31998  boundary_id_with_connections.insert(dst_bnd_id);
31999 
32000  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32001 
32002  // Is the final vertex connected?
32003  if (tmp_polyline_pt->is_final_vertex_connected())
32004  {
32005  // Get the boundary id of the current polyline
32006  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32007 
32008  // Include the boundary id to the set of boundaries with
32009  // connections
32010  boundary_id_with_connections.insert(bnd_id);
32011 
32012  // Boundary id to which the curve is connected
32013  const unsigned dst_bnd_id =
32014  tmp_polyline_pt->final_vertex_connected_bnd_id();
32015 
32016  // Include the destination boundary id to the set of
32017  // boundaries with connections
32018  boundary_id_with_connections.insert(dst_bnd_id);
32019 
32020  } // if (tmp_polyline_pt->is_final_vertex_connected())
32021 
32022  } // for (p < n_polyline)
32023 
32024  } // for (i < n_internal_boundaries)
32025 
32026  // ------------------------------------------------------------------
32027  // Open boundaries (nonclosed internal boundaries)
32028  // ------------------------------------------------------------------
32029 
32030  // Get the number of internal boundaries (open boundaries)
32031  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32032 
32033  // Loop over the internal open boundaries
32034  for (unsigned i = 0; i < n_open_boundaries; i++)
32035  {
32036  // Get a temporary representation for the open curve
32037  TriangleMeshOpenCurve* tmp_open_curve_pt =
32038  this->Internal_open_curve_pt[i];
32039 
32040  // Get the number of curve sections associated to the current
32041  // internal open boundary
32042  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32043 
32044  // Loop over the curve section
32045  for (unsigned p = 0; p < n_curve_section; p++)
32046  {
32047  // Get a temporary representation of the curve section
32048  // (polyline)
32049  TriangleMeshPolyLine* tmp_polyline_pt =
32050  tmp_open_curve_pt->polyline_pt(p);
32051 
32052  // Is the initial vertex connected?
32053  if (tmp_polyline_pt->is_initial_vertex_connected())
32054  {
32055  // Get the boundary id of the current polyline
32056  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32057 
32058  // Include the boundary id to the set of boundaries with
32059  // connections
32060  boundary_id_with_connections.insert(bnd_id);
32061 
32062  // Boundary id to which the curve is connecte
32063  const unsigned dst_bnd_id =
32064  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32065 
32066  // Include the destination boundary id to the set of
32067  // boundaries with connections
32068  boundary_id_with_connections.insert(dst_bnd_id);
32069 
32070  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32071 
32072  // Is the final vertex connected?
32073  if (tmp_polyline_pt->is_final_vertex_connected())
32074  {
32075  // Get the boundary id of the current polyline
32076  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32077 
32078  // Include the boundary id to the set of boundaries with
32079  // connections
32080  boundary_id_with_connections.insert(bnd_id);
32081 
32082  // Boundary id to which the curve is connected
32083  const unsigned dst_bnd_id =
32084  tmp_polyline_pt->final_vertex_connected_bnd_id();
32085 
32086  // Include the destination boundary id to the set of
32087  // boundaries with connections
32088  boundary_id_with_connections.insert(dst_bnd_id);
32089 
32090  } // if (tmp_polyline_pt->is_final_vertex_connected())
32091 
32092  } // for (p < n_curve_section)
32093 
32094  } // for (i < n_open_boundaries)
32095 
32096 #ifdef OOMPH_HAS_MPI
32097  // ------------------------------------------------------------------
32098  // Shared boundaries (only for distributed meshes)
32099  // ------------------------------------------------------------------
32100 
32101  // Check if we need to include any information associated with
32102  // shared boundaries
32103  if (this->is_mesh_distributed())
32104  {
32105  // Get the rank of the current processor
32106  const unsigned my_rank = this->communicator_pt()->my_rank();
32107 
32108  // Get the number of shared curves in the current processor
32109  const unsigned n_shared_curves = this->nshared_boundary_curves(my_rank);
32110 
32111  // Loop over the shared curves
32112  for (unsigned i = 0; i < n_shared_curves; i++)
32113  {
32114  // Get the number of polylines associated to the current shared
32115  // curve
32116  const unsigned n_polyline = this->nshared_boundary_polyline(my_rank, i);
32117 
32118  // Loop over the polylines associated to the current shared
32119  // curve
32120  for (unsigned p = 0; p < n_polyline; p++)
32121  {
32122  // Get a temporary representation of the shared polyline
32123  TriangleMeshPolyLine* tmp_polyline_pt =
32124  this->shared_boundary_polyline_pt(my_rank, i, p);
32125 
32126  // Is the initial vertex connected?
32127  if (tmp_polyline_pt->is_initial_vertex_connected())
32128  {
32129  // Get the boundary id of the current polyline
32130  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32131 
32132  // Include the boundary id to the set of boundaries with
32133  // connections
32134  boundary_id_with_connections.insert(bnd_id);
32135 
32136  // Boundary id to which the curve is connecte
32137  const unsigned dst_bnd_id =
32138  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32139 
32140  // Include the destination boundary id to the set of
32141  // boundaries with connections
32142  boundary_id_with_connections.insert(dst_bnd_id);
32143 
32144  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32145 
32146  // Is the final vertex connected?
32147  if (tmp_polyline_pt->is_final_vertex_connected())
32148  {
32149  // Get the boundary id of the current polyline
32150  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32151 
32152  // Include the boundary id to the set of boundaries with
32153  // connections
32154  boundary_id_with_connections.insert(bnd_id);
32155 
32156  // Boundary id to which the curve is connected
32157  const unsigned dst_bnd_id =
32158  tmp_polyline_pt->final_vertex_connected_bnd_id();
32159 
32160  // Include the destination boundary id to the set of
32161  // boundaries with connections
32162  boundary_id_with_connections.insert(dst_bnd_id);
32163 
32164  } // if (tmp_polyline_pt->is_final_vertex_connected())
32165 
32166  } // for (p < n_polyline)
32167 
32168  } // for (i < n_shared_curves)
32169 
32170  } // if (this->is_mesh_distributed())
32171 
32172 #endif // #ifdef OOMPH_HAS_MPI
32173 
32174  // ---------------------------------------------------------------
32175  // Get the nodes sorted by segments of the boundaries with
32176  // connections
32177 
32178  // Store the sorted nodes by segments of the boundaries with
32179  // connections
32180  std::map<unsigned, Vector<Vector<Node*>>> bnd_sorted_segment_node_pt;
32181 
32182  // Loop over the boundaries with connections
32183  for (std::set<unsigned>::iterator it = boundary_id_with_connections.begin();
32184  it != boundary_id_with_connections.end();
32185  it++)
32186  {
32187  // Get the boundary id
32188  const unsigned bnd_id = (*it);
32189 #ifdef OOMPH_HAS_MPI
32190  // Working with a distributed mesh
32191  if (this->is_mesh_distributed())
32192  {
32193  // Get the initial shared boundary id
32194  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32195  // Is an original or shared boundary
32196  if (bnd_id >= init_shd_bnd_id)
32197  {
32198  // Is a shared boundary
32199 
32200  // Temporary storage for the nodes on the shared boundary
32201  Vector<Vector<Node*>> tmp_shared_nodes_pt;
32202 
32203  // Get the nodes associated to the shared boundary
32204  get_shared_boundary_segment_nodes_helper(bnd_id, tmp_shared_nodes_pt);
32205 
32206  // Store the nodes associated to the shared boundary
32207  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
32208 
32209  } // if (bnd_id >= init_shd_bnd_id)
32210  else
32211  {
32212  // Is an original boundary
32213 
32214  // Temporary storage for the nodes on the original boundary
32215  Vector<Vector<Node*>> tmp_boundary_nodes_pt;
32216 
32217  // Get the nodes associated to the shared boundary
32218  get_boundary_segment_nodes_helper(bnd_id, tmp_boundary_nodes_pt);
32219 
32220  // Store the nodes associated to the shared boundary
32221  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
32222 
32223  } // if (bnd_id >= init_shd_bnd_id)
32224 
32225  } // if (this->is_mesh_distributed())
32226  else
32227 #endif // #ifdef OOMPH_HAS_MPI
32228  {
32229  // Is an original boundary
32230 
32231  // Temporary storage for the nodes on the original boundary
32232  Vector<Vector<Node*>> tmp_boundary_nodes_pt;
32233 
32234  // Get the nodes associated to the shared boundary
32235  get_boundary_segment_nodes_helper(bnd_id, tmp_boundary_nodes_pt);
32236 
32237  // Store the nodes associated to the shared boundary
32238  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
32239 
32240  } // if (this->is_mesh_distributed())
32241 
32242  } // Loop over boundaries with connections
32243 
32244  // -----------------------------------------------------------------
32245  // Loop again over the boundaries (original and shared) and search
32246  // for the repeated nodes in those boundaries with connections
32247 
32248  // ------------------------------------------------------------------
32249  // Outer boundaries
32250  // ------------------------------------------------------------------
32251  // Loop over the outer boundaries
32252  for (unsigned i = 0; i < n_outer_boundaries; i++)
32253  {
32254  // Get a temporary polygon representation
32255  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32256  // Get the number of polylines associated to the current outer
32257  // boundary
32258  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32259  // Loop over the polylines
32260  for (unsigned p = 0; p < n_polyline; p++)
32261  {
32262  // Get a temporary representation of the polyline
32263  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
32264 
32265  // Is the initial vertex connected?
32266  if (tmp_polyline_pt->is_initial_vertex_connected())
32267  {
32268  // Get the boundary id of the current polyline
32269  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32270 
32271  // Boundary id to which the curve is connected
32272  const unsigned dst_bnd_id =
32273  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32274 
32275  // Boundary chunk to which the curve is connected
32276  const unsigned dst_chunk =
32277  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32278 
32279  // Get the nodes representation of the current boundary
32280  Vector<Vector<Node*>> src_bnd_node_pt =
32281  bnd_sorted_segment_node_pt[bnd_id];
32282 
32283  // Get the nodes representation of the boundary to connect
32284  Vector<Vector<Node*>> dst_bnd_node_pt =
32285  bnd_sorted_segment_node_pt[dst_bnd_id];
32286 
32287  // Add the repeated node to the list of non delete-able
32288  // vertices
32289  add_non_delete_vertices_from_boundary_helper(
32290  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32291 
32292  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32293 
32294  // Is the final vertex connected?
32295  if (tmp_polyline_pt->is_final_vertex_connected())
32296  {
32297  // Get the boundary id of the current polyline
32298  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32299 
32300  // Boundary id to which the curve is connected
32301  const unsigned dst_bnd_id =
32302  tmp_polyline_pt->final_vertex_connected_bnd_id();
32303 
32304  // Boundary chunk to which the curve is connected
32305  const unsigned dst_chunk =
32306  tmp_polyline_pt->final_vertex_connected_n_chunk();
32307 
32308  // Get the nodes representation of the current boundary
32309  Vector<Vector<Node*>> src_bnd_node_pt =
32310  bnd_sorted_segment_node_pt[bnd_id];
32311 
32312  // Get the nodes representation of the boundary to connect
32313  Vector<Vector<Node*>> dst_bnd_node_pt =
32314  bnd_sorted_segment_node_pt[dst_bnd_id];
32315 
32316  // Add the repeated node to the list of non delete-able
32317  // vertices
32318  add_non_delete_vertices_from_boundary_helper(
32319  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32320 
32321  } // if (tmp_polyline_pt->is_final_vertex_connected())
32322 
32323  } // for (p < n_polyline)
32324 
32325  } // for (i < n_outer_boundaries)
32326 
32327  // ------------------------------------------------------------------
32328  // Internal boundaries
32329  // ------------------------------------------------------------------
32330  // Loop over the internal boundaries
32331  for (unsigned i = 0; i < n_internal_boundaries; i++)
32332  {
32333  // Get a temporary polygon representation
32334  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32335  // Get the number of polylines associated to the current internal
32336  // boundary
32337  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32338  // Loop over the polylines
32339  for (unsigned p = 0; p < n_polyline; p++)
32340  {
32341  // Get a temporary representation of the polyline
32342  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
32343 
32344  // Is the initial vertex connected?
32345  if (tmp_polyline_pt->is_initial_vertex_connected())
32346  {
32347  // Get the boundary id of the current polyline
32348  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32349 
32350  // Boundary id to which the curve is connected
32351  const unsigned dst_bnd_id =
32352  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32353 
32354  // Boundary chunk to which the curve is connected
32355  const unsigned dst_chunk =
32356  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32357 
32358  // Get the nodes representation of the current boundary
32359  Vector<Vector<Node*>> src_bnd_node_pt =
32360  bnd_sorted_segment_node_pt[bnd_id];
32361 
32362  // Get the nodes representation of the boundary to connect
32363  Vector<Vector<Node*>> dst_bnd_node_pt =
32364  bnd_sorted_segment_node_pt[dst_bnd_id];
32365 
32366  // Add the repeated node to the list of non delete-able
32367  // vertices
32368  add_non_delete_vertices_from_boundary_helper(
32369  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32370 
32371  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32372 
32373  // Is the final vertex connected?
32374  if (tmp_polyline_pt->is_final_vertex_connected())
32375  {
32376  // Get the boundary id of the current polyline
32377  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32378 
32379  // Boundary id to which the curve is connected
32380  const unsigned dst_bnd_id =
32381  tmp_polyline_pt->final_vertex_connected_bnd_id();
32382 
32383  // Boundary chunk to which the curve is connected
32384  const unsigned dst_chunk =
32385  tmp_polyline_pt->final_vertex_connected_n_chunk();
32386 
32387  // Get the nodes representation of the current boundary
32388  Vector<Vector<Node*>> src_bnd_node_pt =
32389  bnd_sorted_segment_node_pt[bnd_id];
32390 
32391  // Get the nodes representation of the boundary to connect
32392  Vector<Vector<Node*>> dst_bnd_node_pt =
32393  bnd_sorted_segment_node_pt[dst_bnd_id];
32394 
32395  // Add the repeated node to the list of non delete-able
32396  // vertices
32397  add_non_delete_vertices_from_boundary_helper(
32398  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32399 
32400  } // if (tmp_polyline_pt->is_final_vertex_connected())
32401 
32402  } // for (p < n_polyline)
32403 
32404  } // for (i < n_internal_boundaries)
32405 
32406  // ------------------------------------------------------------------
32407  // Open boundaries (nonclosed internal boundaries)
32408  // ------------------------------------------------------------------
32409  // Loop over the internal open boundaries
32410  for (unsigned i = 0; i < n_open_boundaries; i++)
32411  {
32412  // Get a temporary representation for the open curve
32413  TriangleMeshOpenCurve* tmp_open_curve_pt =
32414  this->Internal_open_curve_pt[i];
32415 
32416  // Get the number of curve sections associated to the current
32417  // internal open boundary
32418  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32419 
32420  // Loop over the curve section
32421  for (unsigned p = 0; p < n_curve_section; p++)
32422  {
32423  // Get a temporary representation of the curve section
32424  // (polyline)
32425  TriangleMeshPolyLine* tmp_polyline_pt =
32426  tmp_open_curve_pt->polyline_pt(p);
32427 
32428  // Is the initial vertex connected?
32429  if (tmp_polyline_pt->is_initial_vertex_connected())
32430  {
32431  // Get the boundary id of the current polyline
32432  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32433 
32434  // Boundary id to which the curve is connected
32435  const unsigned dst_bnd_id =
32436  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32437 
32438  // Boundary chunk to which the curve is connected
32439  const unsigned dst_chunk =
32440  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32441 
32442  // Get the nodes representation of the current boundary
32443  Vector<Vector<Node*>> src_bnd_node_pt =
32444  bnd_sorted_segment_node_pt[bnd_id];
32445 
32446  // Get the nodes representation of the boundary to connect
32447  Vector<Vector<Node*>> dst_bnd_node_pt =
32448  bnd_sorted_segment_node_pt[dst_bnd_id];
32449 
32450  // Add the repeated node to the list of non delete-able
32451  // vertices
32452  add_non_delete_vertices_from_boundary_helper(
32453  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32454 
32455  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32456 
32457  // Is the final vertex connected?
32458  if (tmp_polyline_pt->is_final_vertex_connected())
32459  {
32460  // Get the boundary id of the current polyline
32461  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32462 
32463  // Boundary id to which the curve is connected
32464  const unsigned dst_bnd_id =
32465  tmp_polyline_pt->final_vertex_connected_bnd_id();
32466 
32467  // Boundary chunk to which the curve is connected
32468  const unsigned dst_chunk =
32469  tmp_polyline_pt->final_vertex_connected_n_chunk();
32470 
32471  // Get the nodes representation of the current boundary
32472  Vector<Vector<Node*>> src_bnd_node_pt =
32473  bnd_sorted_segment_node_pt[bnd_id];
32474 
32475  // Get the nodes representation of the boundary to connect
32476  Vector<Vector<Node*>> dst_bnd_node_pt =
32477  bnd_sorted_segment_node_pt[dst_bnd_id];
32478 
32479  // Add the repeated node to the list of non delete-able
32480  // vertices
32481  add_non_delete_vertices_from_boundary_helper(
32482  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32483 
32484  } // if (tmp_polyline_pt->is_final_vertex_connected())
32485 
32486  } // for (p < n_curve_section)
32487 
32488  } // for (i < n_open_boundaries)
32489 
32490 #ifdef OOMPH_HAS_MPI
32491  // ------------------------------------------------------------------
32492  // Shared boundaries (only for distributed meshes)
32493  // ------------------------------------------------------------------
32494 
32495  // Check if we need to include any information associated with
32496  // shared boundaries
32497  if (this->is_mesh_distributed())
32498  {
32499  // Get the rank of the current processor
32500  const unsigned my_rank = this->communicator_pt()->my_rank();
32501 
32502  // Get the number of shared curves in the current processor
32503  const unsigned n_shared_curves = this->nshared_boundary_curves(my_rank);
32504 
32505  // Loop over the shared curves
32506  for (unsigned i = 0; i < n_shared_curves; i++)
32507  {
32508  // Get the number of polylines associated to the current shared
32509  // curve
32510  const unsigned n_polyline = this->nshared_boundary_polyline(my_rank, i);
32511 
32512  // Loop over the polylines associated to the current shared
32513  // curve
32514  for (unsigned p = 0; p < n_polyline; p++)
32515  {
32516  // Get a temporary representation of the shared polyline
32517  TriangleMeshPolyLine* tmp_polyline_pt =
32518  this->shared_boundary_polyline_pt(my_rank, i, p);
32519 
32520  // Is the initial vertex connected?
32521  if (tmp_polyline_pt->is_initial_vertex_connected())
32522  {
32523  // Get the boundary id of the current polyline
32524  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32525 
32526  // Boundary id to which the curve is connected
32527  const unsigned dst_bnd_id =
32528  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32529 
32530  // Boundary chunk to which the curve is connected
32531  const unsigned dst_chunk =
32532  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32533 
32534  // Get the nodes representation of the current boundary
32535  Vector<Vector<Node*>> src_bnd_node_pt =
32536  bnd_sorted_segment_node_pt[bnd_id];
32537 
32538  // Get the nodes representation of the boundary to connect
32539  Vector<Vector<Node*>> dst_bnd_node_pt =
32540  bnd_sorted_segment_node_pt[dst_bnd_id];
32541 
32542  // Add the repeated node to the list of non delete-able
32543  // vertices
32544  add_non_delete_vertices_from_boundary_helper(
32545  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32546 
32547  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32548 
32549  // Is the final vertex connected?
32550  if (tmp_polyline_pt->is_final_vertex_connected())
32551  {
32552  // Get the boundary id of the current polyline
32553  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32554 
32555  // Boundary id to which the curve is connected
32556  const unsigned dst_bnd_id =
32557  tmp_polyline_pt->final_vertex_connected_bnd_id();
32558 
32559  // Boundary chunk to which the curve is connected
32560  const unsigned dst_chunk =
32561  tmp_polyline_pt->final_vertex_connected_n_chunk();
32562 
32563  // Get the nodes representation of the current boundary
32564  Vector<Vector<Node*>> src_bnd_node_pt =
32565  bnd_sorted_segment_node_pt[bnd_id];
32566 
32567  // Get the nodes representation of the boundary to connect
32568  Vector<Vector<Node*>> dst_bnd_node_pt =
32569  bnd_sorted_segment_node_pt[dst_bnd_id];
32570 
32571  // Add the repeated node to the list of non delete-able
32572  // vertices
32573  add_non_delete_vertices_from_boundary_helper(
32574  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32575 
32576  } // if (tmp_polyline_pt->is_final_vertex_connected())
32577 
32578  } // for (p < n_polyline)
32579 
32580  } // for (i < n_shared_curves)
32581 
32582  } // if (this->is_mesh_distributed())
32583 
32584 #endif // #ifdef OOMPH_HAS_MPI
32585  }
32586 
32587  //=========================================================================
32588  /// Adds the vertices from the sources boundary that are
32589  /// repeated in the destination boundary to the list of non
32590  /// delete-able vertices in the destination boundary
32591  //=========================================================================
32592  template<class ELEMENT>
32595  Vector<Vector<Node*>> src_bound_segment_node_pt,
32596  Vector<Vector<Node*>> dst_bound_segment_node_pt,
32597  const unsigned& dst_bnd_id,
32598  const unsigned& dst_bnd_chunk)
32599  {
32600  // Get the number of segments in the source boundary
32601  const unsigned n_seg = src_bound_segment_node_pt.size();
32602  // Loop over the segments in the source boundary
32603  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32604  {
32605  // Get the number of nodes in the current segment
32606  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32607  // Get the left and right node of the current segment
32608  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32609  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode - 1];
32610 
32611  // Get the number of segments in the destination boundary
32612  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32613  // Loop over the segments in the destination boundary
32614  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32615  {
32616  // Get the number of nodes on the current destination segment
32617  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32618  // Loop over the nodes until the node has been found or we have
32619  // visited all the nodes
32620  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32621  {
32622  // Get a pointer to the jnode in the destination segment
32623  // boundary
32624  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32625  // Is the node the same as the left or right node if
32626  // the source segment boundary
32627  if (tmp_node_pt == left_node_pt)
32628  {
32629  // We have foud the node to connect, get the vertex of the node
32630  Vector<double> vertex(2);
32631  vertex[0] = tmp_node_pt->x(0);
32632  vertex[1] = tmp_node_pt->x(1);
32633 
32634  // Establish the vertex coordinate as untouchable in the
32635  // destination boundary during the adaptation process. It
32636  // means that unrefinement can not take off the vertices
32637  // that receive connections in the destination boundary
32638  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32639  // Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32640  // insert(vertex);
32641 
32642  // return
32643  return;
32644 
32645  } // if (tmp_node_pt == left_node_pt)
32646  else if (tmp_node_pt == right_node_pt)
32647  {
32648  // We have foud the node to connect, get the vertex of the node
32649  Vector<double> vertex(2);
32650  vertex[0] = tmp_node_pt->x(0);
32651  vertex[1] = tmp_node_pt->x(1);
32652 
32653  // Establish the vertex coordinate as untouchable in the
32654  // destination boundary during the adaptation process. It
32655  // means that unrefinement can not take off the vertices
32656  // that receive connections in the destination boundary
32657  // Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32658  // insert(vertex);
32659  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32660 
32661  // return
32662  return;
32663 
32664  } // else if (tmp_node_pt == right_node_pt)
32665 
32666  } // for (jnode < n_dst_node)
32667 
32668  } // for (jseg < n_dst_seg)
32669 
32670  } // for (iseg < n_seg)
32671  }
32672 
32673 #ifdef OOMPH_HAS_MPI
32674  //=========================================================================
32675  /// Synchronise the vertices that are marked for non deletion
32676  // on the shared boundaries. Unrefinement of shared boundaries is
32677  // performed only if the candidate node is not marked for non deletion
32678  //=========================================================================
32679  template<class ELEMENT>
32680  const void RefineableTriangleMesh<
32681  ELEMENT>::synchronize_shared_boundary_connections()
32682  {
32683  // Get the number of processors
32684  const unsigned nproc = this->communicator_pt()->nproc();
32685  // Get my rank
32686  const unsigned my_rank = this->communicator_pt()->my_rank();
32687 
32688  // loop over the processors
32689  for (unsigned jproc = 0; jproc < nproc; jproc++)
32690  {
32691  // The number of boundaries shared with the current processor
32692  // (if jproc==my_rank then there are no shared boundaries
32693  // between them)
32694  const unsigned n_shd_bnd_jproc = this->nshared_boundaries(my_rank, jproc);
32695 
32696  // Are there shared boundaries with the jproc processor?
32697  // There are no info. with myself
32698  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32699  {
32700  // Storage for the boundaries ids with vertices for non
32701  // deletion
32702  Vector<unsigned> shd_bnd_id_for_non_deletion;
32703 
32704  // Storage for chunk numbers of boundaries with vertices
32705  // for non deletion
32706  Vector<unsigned> chunk_for_non_deletion;
32707 
32708  // The number of vertices for nondeletion in the shared
32709  // boundaries
32710  Vector<unsigned> number_vertices_non_deletion;
32711 
32712  // Vertices marked for nondeletion in shared boundaries
32713  Vector<Vector<Vector<double>>> vertices_for_non_deletion;
32714 
32715  // Get the boundary ids of the shared boundaries with jproc
32716  // processor
32717  Vector<unsigned> shd_bnd_ids =
32718  this->shared_boundaries_ids(my_rank, jproc);
32719 
32720  // Get the number of shared boundaries with jproc
32721  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32722  // loop over the shared boundaries with jproc
32723  for (unsigned ishd_bnd = 0; ishd_bnd < n_shd_bnd_jproc; ishd_bnd++)
32724  {
32725  // Get the shared boudary id
32726  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32727  // Get the associated polyline
32728  TriangleMeshPolyLine* shd_polyline_pt =
32729  this->boundary_polyline_pt(shd_bnd_id);
32730  // Get the chunk number
32731  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32732 
32733  // Store the vertices not allowed for deletion
32734  std::set<Vector<double>> no_delete_vertex;
32735 
32736  // Does the boundary has vertives for nondeleteion?
32737  const bool boundary_receive_connections =
32738  this->boundary_connections(shd_bnd_id, chunk, no_delete_vertex);
32739 
32740  // Get the number of vertices for nondeletion
32741  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32742 
32743  // Are there vertices for nondeletion?
32744  if (boundary_receive_connections && n_non_delete_vertex > 0)
32745  {
32746  // Add the shared boundary id
32747  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32748  // Add the chunk number
32749  chunk_for_non_deletion.push_back(chunk);
32750  // Add the number of vertices for non deletion
32751  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32752 
32753  // The list of vertices to add
32754  Vector<Vector<double>> tmp_vertices;
32755 
32756  // Add the vertices for non deletion
32757  for (std::set<Vector<double>>::iterator it =
32758  no_delete_vertex.begin();
32759  it != no_delete_vertex.end();
32760  it++)
32761  {
32762  // Get the vertex coordinate
32763  Vector<double> vertex = (*it);
32764  tmp_vertices.push_back(vertex);
32765  }
32766 
32767  // Add the vertices coordinates to a vector storage
32768  vertices_for_non_deletion.push_back(tmp_vertices);
32769 
32770  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32771 
32772  } // for (ishd_bnd<n_shd_bnd_jproc)
32773 
32774  // ----------------------------------------------------------
32775  // ----------------------------------------------------------
32776  // ----------------------------------------------------------
32777  // Now send the info. to the other processor (jproc)
32778  // ----------------------------------------------------------
32779  // ----------------------------------------------------------
32780  // ----------------------------------------------------------
32781  // Get the communicator of the mesh
32782  OomphCommunicator* comm_pt = this->communicator_pt();
32783 
32784  // Set MPI info
32785  MPI_Status status;
32786  MPI_Request request;
32787 
32788  // -----------------------------------------------------------
32789  // Prepare the data
32790  // Get the number of shared boundaires with vertices marked
32791  // for non deletion
32792  const unsigned n_shd_bnd_with_non_delete_vertices =
32793  shd_bnd_id_for_non_deletion.size();
32794 
32795  // Size of the package
32796  const unsigned size_package = 3;
32797  // Ndata to send
32798  const unsigned n_unsigned_data_to_send =
32799  n_shd_bnd_with_non_delete_vertices * size_package;
32800  // The flat package to send the info.
32801  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32802  Vector<double> flat_package_double_send;
32803 
32804  Vector<unsigned> flat_package_unsigned_recv;
32805  Vector<double> flat_package_double_recv;
32806 
32807  // Prepare the data to be sent
32808  unsigned j = 0;
32809  for (unsigned i = 0; i < n_shd_bnd_with_non_delete_vertices; i++)
32810  {
32811  // The shared boundary id
32812  flat_package_unsigned_send[j++] = shd_bnd_id_for_non_deletion[i];
32813  // The chunk number
32814  flat_package_unsigned_send[j++] = chunk_for_non_deletion[i];
32815  // The number of vertices for nondeletion
32816  flat_package_unsigned_send[j++] = number_vertices_non_deletion[i];
32817  // Also package the vertices
32818  const unsigned n_vertices_non_deletion =
32819  number_vertices_non_deletion[i];
32820  // Loop over the vertices and store them in the flat
32821  // package to be sent
32822  for (unsigned h = 0; h < n_vertices_non_deletion; h++)
32823  {
32824  flat_package_double_send.push_back(
32825  vertices_for_non_deletion[i][h][0]);
32826  flat_package_double_send.push_back(
32827  vertices_for_non_deletion[i][h][1]);
32828  } // for (h<n_vertices_non_deletion)
32829 
32830  } // for (i<n_shd_bnd_with_non_delete_vertices)
32831 
32832  // ----------------------------------------------------------
32833  int send_proc = jproc;
32834  int recv_proc = jproc;
32835  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32836  unsigned send_count_double_values = flat_package_double_send.size();
32837  //-----------------------------------------------------------
32838  // Do the transfering of info.
32839  //-----------------------------------------------------------
32840  // Start with UNSIGNED info.
32841  MPI_Isend(&send_count_unsigned_values,
32842  1,
32843  MPI_UNSIGNED,
32844  send_proc,
32845  1,
32846  comm_pt->mpi_comm(),
32847  &request);
32848 
32849  unsigned receive_count_unsigned_values = 0;
32850  MPI_Recv(&receive_count_unsigned_values,
32851  1,
32852  MPI_UNSIGNED,
32853  recv_proc,
32854  1,
32855  comm_pt->mpi_comm(),
32856  &status);
32857 
32858  MPI_Wait(&request, MPI_STATUS_IGNORE);
32859 
32860  // Send the actual data
32861  if (send_count_unsigned_values != 0)
32862  {
32863  MPI_Isend(&flat_package_unsigned_send[0],
32864  send_count_unsigned_values,
32865  MPI_UNSIGNED,
32866  send_proc,
32867  2,
32868  comm_pt->mpi_comm(),
32869  &request);
32870  }
32871 
32872  // Receive the actual data
32873  if (receive_count_unsigned_values != 0)
32874  {
32875  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32876  MPI_Recv(&flat_package_unsigned_recv[0],
32877  receive_count_unsigned_values,
32878  MPI_UNSIGNED,
32879  recv_proc,
32880  2,
32881  comm_pt->mpi_comm(),
32882  &status);
32883  }
32884 
32885  // Wait for sending the data and the other processor
32886  // receives
32887  if (send_count_unsigned_values != 0)
32888  {
32889  MPI_Wait(&request, MPI_STATUS_IGNORE);
32890  }
32891 
32892  //-----------------------------------------------------------
32893  // Then continue with DOUBLE info.
32894  MPI_Isend(&send_count_double_values,
32895  1,
32896  MPI_UNSIGNED,
32897  send_proc,
32898  1,
32899  comm_pt->mpi_comm(),
32900  &request);
32901 
32902  unsigned receive_count_double_values = 0;
32903  MPI_Recv(&receive_count_double_values,
32904  1,
32905  MPI_UNSIGNED,
32906  recv_proc,
32907  1,
32908  comm_pt->mpi_comm(),
32909  &status);
32910 
32911  MPI_Wait(&request, MPI_STATUS_IGNORE);
32912 
32913  // Send the actual data
32914  if (send_count_double_values != 0)
32915  {
32916  MPI_Isend(&flat_package_double_send[0],
32917  send_count_double_values,
32918  MPI_DOUBLE,
32919  send_proc,
32920  2,
32921  comm_pt->mpi_comm(),
32922  &request);
32923  }
32924 
32925  // Receive the actual data
32926  if (receive_count_double_values != 0)
32927  {
32928  flat_package_double_recv.resize(receive_count_double_values);
32929  MPI_Recv(&flat_package_double_recv[0],
32930  receive_count_double_values,
32931  MPI_DOUBLE,
32932  recv_proc,
32933  2,
32934  comm_pt->mpi_comm(),
32935  &status);
32936  }
32937 
32938  // Wait for sending the data and the other processor
32939  // receives
32940  if (send_count_double_values != 0)
32941  {
32942  MPI_Wait(&request, MPI_STATUS_IGNORE);
32943  }
32944 
32945  // ------------------------------------------------------------
32946  // ------------------------------------------------------------
32947  // ------------------------------------------------------------
32948  // Now unpackage the data
32949  // ------------------------------------------------------------
32950  // ------------------------------------------------------------
32951  // ------------------------------------------------------------
32952 
32953  // Storage for the boundaries ids with vertices for non
32954  // deletion
32955  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32956 
32957  // Storage for chunk numbers of boundaries with vertices
32958  // for non deletion
32959  Vector<unsigned> recv_chunk_for_non_deletion;
32960 
32961  // The number of vertices for nondeletion in the shared
32962  // boundaries
32963  Vector<unsigned> recv_number_vertices_non_deletion;
32964 
32965  // Vertices marked for nondeletion in shared boundaries
32966  Vector<Vector<Vector<double>>> recv_vertices_for_non_deletion;
32967 
32968  // Counter
32969  j = 0;
32970  for (unsigned i = 0; i < receive_count_unsigned_values; i += 3)
32971  {
32972  // Get the shared boundary id
32973  const unsigned recv_shd_bnd_id = flat_package_unsigned_recv[i];
32974  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32975  // Get the chunk number
32976  const unsigned recv_chunk = flat_package_unsigned_recv[i + 1];
32977  recv_chunk_for_non_deletion.push_back(recv_chunk);
32978  // Get the number of vertices for non deletion
32979  const unsigned recv_num_vertices = flat_package_unsigned_recv[i + 2];
32980  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32981 
32982  // Create a temporal storage
32983  Vector<Vector<double>> temp_recv_vertices;
32984  // Now get the vertices
32985  for (unsigned h = 0; h < recv_num_vertices; h++)
32986  {
32987  Vector<double> tmp_vertex(2);
32988  tmp_vertex[0] = flat_package_double_recv[j++];
32989  tmp_vertex[1] = flat_package_double_recv[j++];
32990  // Add the vertex to the vector of vertices
32991  temp_recv_vertices.push_back(tmp_vertex);
32992  } // for (h<recv_num_vertices)
32993 
32994  // Add the vertices to the vector of vertices
32995  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32996 
32997  } // for(i<receive_count_unsigned_values)
32998 
32999  // ---------------------------------------------------------
33000  // ---------------------------------------------------------
33001  // ---------------------------------------------------------
33002  // Now add the vertices to the data structures to mark them
33003  // as non delete-able
33004  // ---------------------------------------------------------
33005  // ---------------------------------------------------------
33006  // ---------------------------------------------------------
33007 
33008  // Get the number of shd boundaries that have vertices
33009  // marked for non deletion
33010  const unsigned n_recv_shd_bnd_id_for_non_deletion =
33011  recv_shd_bnd_id_for_non_deletion.size();
33012  // loop over the shared boundaries and add the data for non
33013  // deletion
33014  for (unsigned i = 0; i < n_recv_shd_bnd_id_for_non_deletion; i++)
33015  {
33016  // Get the shared boundary id.
33017  const unsigned shd_bnd_id = recv_shd_bnd_id_for_non_deletion[i];
33018  // Get the chunk number
33019  unsigned chunk = recv_chunk_for_non_deletion[i];
33020  // Increase and decrease the chunk number to avoid the
33021  // warning when compiling without PARANOID
33022  chunk++;
33023  chunk--;
33024 
33025  // Get the number of vertices marked for non deletion
33026  const unsigned n_vertices = recv_number_vertices_non_deletion[i];
33027  // Add all the vertices
33028  for (unsigned h = 0; h < n_vertices; h++)
33029  {
33030  // Get the vertex
33031  Vector<double> vertex(2);
33032  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
33033  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
33034  // Add the vertex to the data structure for non
33035  // deletion
33036  // Boundary_chunk_connections_pt[shd_bnd_id][chunk].
33037  // insert(vertex);
33038  Boundary_connections_pt[shd_bnd_id].insert(vertex);
33039 
33040  } // for (h<n_vertices)
33041 
33042  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
33043 
33044  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
33045 
33046  } // for (jproc < nproc)
33047  }
33048 #endif // #ifdef OOMPH_HAS_MPI
33049 
33050  //=========================================================================
33051  /// After unrefinement and refinement has taken place compute
33052  /// the new vertices numbers of the temporary representation of the
33053  // boundaries to connect.
33054  //=========================================================================
33055  template<class ELEMENT>
33057  Vector<TriangleMeshPolygon*>& tmp_outer_polygons_pt,
33058  Vector<TriangleMeshOpenCurve*>& tmp_open_curves_pt)
33059  {
33060  // Dummy storages
33061  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
33062  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
33063 
33064  // Clear the storage
33065  dummy_resume_initial_connection_polyline_pt.clear();
33066  dummy_resume_final_connection_polyline_pt.clear();
33067 
33068  // Get the initial shared boundary id (to check whether the
33069  // polylines represent original or shared boundaries)
33070  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33071 
33072  // ------------------------------------------------------------------
33073  // This seems unnecesary since the outer polygons does not create
33074  // connections with other boundaries (the original ones)
33075  // ------------------------------------------------------------------
33076  // Unnecessary?
33077  // ------------------------------------------------------------------
33078 
33079  // Loop over the temporary outer polygons create the connection
33080  // information of those boundaries marked to be connected at their
33081  // ends
33082 
33083  // ------------------------------------------------------------------
33084  // Temporary outer polygons
33085  // ------------------------------------------------------------------
33086 
33087  // Get the number of outer boundaries (closed boundaries)
33088  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
33089 
33090  // Loop over the outer boundaries
33091  for (unsigned i = 0; i < n_outer_boundaries; i++)
33092  {
33093  // Get a temporary polygon representation
33094  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
33095  // Get the number of polylines associated to the current outer
33096  // boundary
33097  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33098  // Loop over the polylines
33099  for (unsigned p = 0; p < n_polyline; p++)
33100  {
33101  // Get a temporary representation of the polyline
33102  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33103 
33104  // Get the boundary id
33105  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
33106 
33107  // Is the boundary to connect a shared boundary
33108  if (bnd_id < init_shd_bnd_id)
33109  {
33110  // Restore the connections of the current polyline
33111  restore_polyline_connections_helper(
33112  tmp_polyline_pt,
33113  dummy_resume_initial_connection_polyline_pt,
33114  dummy_resume_final_connection_polyline_pt);
33115 
33116  } // if (bnd_id < init_shd_bnd_id)
33117 
33118  } // for (p < n_polyline)
33119 
33120  } // for (i < n_outer_boundaries)
33121 
33122  // ------------------------------------------------------------------
33123  // Unnecessary?
33124  // ------------------------------------------------------------------
33125 
33126  // ------------------------------------------------------------------
33127  // Temporary open boundaries (nonclosed internal boundaries)
33128  // ------------------------------------------------------------------
33129 
33130  // Get the number of internal boundaries (open boundaries)
33131  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
33132 
33133  // Loop over the internal open boundaries
33134  for (unsigned i = 0; i < n_open_boundaries; i++)
33135  {
33136  // Get a temporary representation for the open curve
33137  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
33138 
33139  // Get the number of curve sections associated to the current
33140  // internal open boundary
33141  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
33142 
33143  // Loop over the curve section
33144  for (unsigned p = 0; p < n_curve_section; p++)
33145  {
33146  // Get a temporary representation of the curve section
33147  // (polyline)
33148  TriangleMeshPolyLine* tmp_polyline_pt =
33149  tmp_open_curve_pt->polyline_pt(p);
33150 
33151  // Get the boundary id
33152  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
33153 
33154  // Is the boundary to connect a shared boundary
33155  if (bnd_id < init_shd_bnd_id)
33156  {
33157  // Restore the connections of the current polyline
33158  restore_polyline_connections_helper(
33159  tmp_polyline_pt,
33160  dummy_resume_initial_connection_polyline_pt,
33161  dummy_resume_final_connection_polyline_pt);
33162 
33163  } // if (bnd_id < init_shd_bnd_id)
33164 
33165  } // for (p < n_curve_section)
33166 
33167  } // for (i < n_open_boundaries)
33168  }
33169 
33170  //=========================================================================
33171  /// After unrefinement and refinement has taken place compute
33172  /// the new vertices numbers of the boundaries to connect (in a
33173  /// distributed scheme it may be possible that the destination
33174  /// boundary does no longer exist, therefore the connection is
33175  /// suspended. It is not permanently deleted because if load balance
33176  /// takes place it may be possible that the boundary to connect be
33177  /// part of the new domain representation, so the connection would
33178  /// exist)
33179  //=========================================================================
33180  template<class ELEMENT>
33182  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
33183  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
33184  {
33185  // Clear the storage
33186  resume_initial_connection_polyline_pt.clear();
33187  resume_final_connection_polyline_pt.clear();
33188 
33189  // Loop over the boundaries in the domain (outer, internal -- closed
33190  // and open) and restore the connection information of those
33191  // boundaries marked to be connected at their ends
33192 
33193  // ------------------------------------------------------------------
33194  // Outer boundaries
33195  // ------------------------------------------------------------------
33196 
33197  // Get the number of outer boundaries (closed boundaries)
33198  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
33199 
33200  // Loop over the outer boundaries
33201  for (unsigned i = 0; i < n_outer_boundaries; i++)
33202  {
33203  // Get a temporary polygon representation
33204  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
33205  // Get the number of polylines associated to the current outer
33206  // boundary
33207  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33208  // Loop over the polylines
33209  for (unsigned p = 0; p < n_polyline; p++)
33210  {
33211  // Get a temporary representation of the polyline
33212  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33213 
33214  // Restore the connections of the current polyline
33215  restore_polyline_connections_helper(
33216  tmp_polyline_pt,
33217  resume_initial_connection_polyline_pt,
33218  resume_final_connection_polyline_pt);
33219 
33220  } // for (p < n_polyline)
33221 
33222  } // for (i < n_outer_boundaries)
33223 
33224  // ------------------------------------------------------------------
33225  // Internal boundaries
33226  // ------------------------------------------------------------------
33227 
33228  // Get the number of internal boundaries (closed boundaries)
33229  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
33230 
33231  // Loop over the internal boundaries
33232  for (unsigned i = 0; i < n_internal_boundaries; i++)
33233  {
33234  // Get a temporary polygon representation
33235  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
33236  // Get the number of polylines associated to the current internal
33237  // boundary
33238  const unsigned n_polyline = tmp_polygon_pt->npolyline();
33239  // Loop over the polylines
33240  for (unsigned p = 0; p < n_polyline; p++)
33241  {
33242  // Get a temporary representation of the polyline
33243  TriangleMeshPolyLine* tmp_polyline_pt = tmp_polygon_pt->polyline_pt(p);
33244 
33245  // Restore the connections of the current polyline
33246  restore_polyline_connections_helper(
33247  tmp_polyline_pt,
33248  resume_initial_connection_polyline_pt,
33249  resume_final_connection_polyline_pt);
33250 
33251  } // for (p < n_polyline)
33252 
33253  } // for (i < n_internal_boundaries)
33254 
33255  // ------------------------------------------------------------------
33256  // Open boundaries (nonclosed internal boundaries)
33257  // ------------------------------------------------------------------
33258 
33259  // Get the number of internal boundaries (open boundaries)
33260  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
33261 
33262  // Loop over the internal open boundaries
33263  for (unsigned i = 0; i < n_open_boundaries; i++)
33264  {
33265  // Get a temporary representation for the open curve
33266  TriangleMeshOpenCurve* tmp_open_curve_pt =
33267  this->Internal_open_curve_pt[i];
33268 
33269  // Get the number of curve sections associated to the current
33270  // internal open boundary
33271  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
33272 
33273  // Loop over the curve section
33274  for (unsigned p = 0; p < n_curve_section; p++)
33275  {
33276  // Get a temporary representation of the curve section
33277  // (polyline)
33278  TriangleMeshPolyLine* tmp_polyline_pt =
33279  tmp_open_curve_pt->polyline_pt(p);
33280 
33281  // Restore the connections of the current polyline
33282  restore_polyline_connections_helper(
33283  tmp_polyline_pt,
33284  resume_initial_connection_polyline_pt,
33285  resume_final_connection_polyline_pt);
33286 
33287  } // for (p < n_curve_section)
33288 
33289  } // for (i < n_open_boundaries)
33290  }
33291 
33292  //=========================================================================
33293  /// Restore the connections of the specific polyline
33294  /// The vertices numbering on the destination boundaries may have
33295  /// change because of (un)refinement in the destination boundaries.
33296  /// Also deals with connection that do not longer exist because the
33297  /// destination boundary does no longer exist because of the distribution
33298  /// process
33299  //=========================================================================
33300  template<class ELEMENT>
33302  TriangleMeshPolyLine* polyline_pt,
33303  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
33304  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
33305  {
33306  // If the polyline is connected at any of its ends compute the new
33307  // vertex number on the destination boundary
33308 
33309  // ------------------------------------------------------------------
33310  // Is the initial vertex connected?
33311  if (polyline_pt->is_initial_vertex_connected())
33312  {
33313  // The pointer to the boundary to connect
33314  TriangleMeshPolyLine* poly_to_connect_pt = 0;
33315 
33316  // Get the boundary id of the destination/connected boundary
33317  const unsigned dst_bnd_id_initial =
33318  polyline_pt->initial_vertex_connected_bnd_id();
33319 
33320  // Get the initial vertex on the current boundary
33321  Vector<double> src_vertex_coordinates_initial =
33322  polyline_pt->vertex_coordinate(0);
33323 
33324 #ifdef PARANOID
33325  // Is the mesh distributed?
33326 #ifdef OOMPH_HAS_MPI
33327  if (this->is_mesh_distributed())
33328  {
33329  // Get the initial shared boundary id
33330  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33331  // Is the boundary to connect a shared boundary
33332  if (dst_bnd_id_initial >= init_shd_bnd_id)
33333  {
33334  // Get the current polyline original boundary id
33335  const unsigned bnd_id = polyline_pt->boundary_id();
33336  std::ostringstream error_message;
33337  error_message
33338  << "INITIAL VERTEX CONNECTION\n"
33339  << "The current original boundary is trying to connect to a\n"
33340  << "shared boundary, this is not allowed. In this case the\n"
33341  << "shared boundary should be the one that connects with the\n"
33342  << "original boundary\n"
33343  << "The current original boundary (" << bnd_id << ") is marked\n"
33344  << "to have a connection at the\nINITIAL vertex ("
33345  << src_vertex_coordinates_initial[0] << ","
33346  << src_vertex_coordinates_initial[1] << ")\n"
33347  << "with the shared boundary (" << dst_bnd_id_initial << ")\n"
33348  << "This is the list of vertices on the shared destination "
33349  "boundary\n";
33350  // Get the pointer to the associated polyline by using the
33351  // boundary id
33352  TriangleMeshPolyLine* dst_polyline =
33353  this->boundary_polyline_pt(dst_bnd_id_initial);
33354  // The number of vertices on the destination boundary
33355  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33356  // Loop over the vertices print them
33357  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33358  {
33359  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33360  error_message << "Vertex#(i): (" << current_vertex[0] << ", "
33361  << current_vertex[1] << ")\n";
33362  }
33363  throw OomphLibError(
33364  error_message.str(),
33365  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33366  OOMPH_EXCEPTION_LOCATION);
33367  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33368 
33369  } // if (this->is_mesh_distributed())
33370 #endif // #ifdef OOMPH_HAS_MPI
33371 
33372 #endif // #ifdef PARANOID
33373 
33374  // Flag to indicate if the vertex was found on the destination
33375  // boundary
33376  bool found_vertex_on_dst_boundary_initial = false;
33377 
33378  // Flag that stores the chunk number to connect (only used in
33379  // distributed meshes)
33380  unsigned sub_poly_to_connect = 0;
33381 
33382  // Store the vertex number on the destination boundary
33383  unsigned n_vertex_connection_initial = 0;
33384 
33385  // Flags only used in a distributed mesh
33386  // ----------------------------------------
33387  // Flag to indicate we are trying to connect to an split boundary
33388  bool connecting_to_an_split_boundary = false;
33389 
33390  // Flag to indicate we are trying to connecto to an internal
33391  // boundary that is overlaped by a shared boundary)
33392  bool connecting_to_an_overlaped_boundary = false;
33393 
33394 #ifdef OOMPH_HAS_MPI
33395  if (this->is_mesh_distributed())
33396  {
33397  // We can only connect to an original boundary, check if the
33398  // boundary was splitted during the distribution process to
33399  // consider all the chunks (sub-polylines) of the boundary
33400  if (this->boundary_was_splitted(dst_bnd_id_initial))
33401  {
33402  connecting_to_an_split_boundary = true;
33403  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33404 
33405  // Check if the destination boundary, or any of its chunks is
33406  // marked to be overlapped by a shared boundary, if that is the
33407  // case we can only connect to the chunks that are not
33408  // overlapped by shared boundaries (the shared boundaries are in
33409  // charge of generating the connections with original boundaries
33410  // and with themselves)
33411  if (connecting_to_an_split_boundary)
33412  {
33413  // Get the number of chucks that represent the destination
33414  // boundary
33415  const unsigned n_sub_poly =
33416  this->nboundary_subpolylines(dst_bnd_id_initial);
33417  // Now loop over the chunks of the destination boundary and if
33418  // any of them is marked to be overlaped by a shared boundary
33419  // then set the flag and break the loop
33420  for (unsigned ii = 0; ii < n_sub_poly; ii++)
33421  {
33422  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_initial,
33423  ii))
33424  {
33425  // Mark the boundary as being overlaped by a shared
33426  // boundary
33427  connecting_to_an_overlaped_boundary = true;
33428  // Break, no need to look for more overlapings
33429  break;
33430  } // if (boundary_marked_as_shared_boundary(...))
33431  } // for (ii < n_sub_poly)
33432  } // if (connecting_to_an_split_boundary)
33433  else
33434  {
33435  // If not connecting to an split boundary then check if the
33436  // whole destination boundary is overlaped by an internal
33437  // boundary
33438  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33439  {
33440  // Mark the boundary as being overlaped by a shared boundary
33441  connecting_to_an_overlaped_boundary = true;
33442  } // if (boundary_marked_as_shared_boundary(...))
33443  } // else if (connecting_to_an_split_boundary)
33444 
33445  } // if (this->is_mesh_distributed())
33446 
33447 #endif // #ifdef OOMPH_HAS_MPI
33448 
33449  // If we are connecting neither to an split boundary nor an
33450  // overlaped boundary then get the pointer to the original
33451  // boundary
33452  if (!(connecting_to_an_split_boundary ||
33453  connecting_to_an_overlaped_boundary))
33454  {
33455  // Get the polyline pointer representing the destination
33456  // boundary
33457  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33458  } // else if (NOT split, NOT overlaped)
33459 
33460  // Now look for the vertex number on the destination boundary(ies)
33461  // -- in case that the boundary was split ---
33462 
33463  // Do not check for same orientation, that was previously worked
33464  // by interchanging the connections boundaries (if necessary)
33465 
33466  // If the boundary was not split then ...
33467  if (!connecting_to_an_split_boundary)
33468  {
33469  // ... check if the boundary is marked to be overlaped by
33470  // a shared boundary
33471  if (!connecting_to_an_overlaped_boundary)
33472  {
33473  // If that is not the case then we can safely look for the
33474  // vertex number on the destination boundary
33475  found_vertex_on_dst_boundary_initial =
33476  this->get_connected_vertex_number_on_destination_polyline(
33477  poly_to_connect_pt,
33478  src_vertex_coordinates_initial,
33479  n_vertex_connection_initial);
33480 
33481  } // if (!connecting_to_an_overlaped_boundary)
33482  else
33483  {
33484  // If the whole boundary is marked to be overlaped by a shared
33485  // boundary then do nothing, the shared boundaries are already
33486  // in charge of performing the connection (it will be required
33487  // to disabled the connection) with the original boundary
33488 
33489  } // else if (!connecting_to_an_overlaped_boundary)
33490 
33491  } // if (!connecting_to_an_split_boundary)
33492 #ifdef OOMPH_HAS_MPI
33493  else
33494  {
33495  // If the boundary was split then we need to look for the vertex
33496  // in the sub-polylines
33497 
33498  // Get the sub-polylines vector
33499  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33500  this->boundary_subpolylines(dst_bnd_id_initial);
33501 
33502  // Get the number of sub-polylines
33503  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33504 #ifdef PARANOID
33505  if (nsub_poly <= 1)
33506  {
33507  std::ostringstream error_message;
33508  error_message << "The boundary (" << dst_bnd_id_initial << ") was "
33509  << "marked to be splitted but\n"
33510  << "there are only (" << nsub_poly << ") polylines to "
33511  << "represent it.\n";
33512  throw OomphLibError(
33513  error_message.str(),
33514  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33515  OOMPH_EXCEPTION_LOCATION);
33516  } // if (nsub_poly <= 1)
33517 #endif
33518  // We need to check if the boundary is marked to be overlaped by
33519  // a shared boundary, if that is the case we need to check for
33520  // each indivual subpolyline, and for those overlaped by a
33521  // shared polyline do nothing, the shared polylines have already
33522  // deal with these connections
33523 
33524  // ... check if the boundary is marked to be overlaped by
33525  // a shared boundary
33526  if (!connecting_to_an_overlaped_boundary)
33527  {
33528  // The boundary is not overlapped by shared boundaries, we can
33529  // work without checking the subpolylines individually (non of
33530  // them are overlapped by a shared boundary)
33531 
33532  // Look for the vertex number to connect on each of the
33533  // subpolyines
33534  for (unsigned isub = 0; isub < nsub_poly; isub++)
33535  {
33536  // Assign the pointer to the sub-polyline
33537  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33538  // Search for the vertex in the current sub-polyline
33539  found_vertex_on_dst_boundary_initial =
33540  this->get_connected_vertex_number_on_destination_polyline(
33541  poly_to_connect_pt,
33542  src_vertex_coordinates_initial,
33543  n_vertex_connection_initial);
33544 
33545  // If we have found the vertex to connect then break the
33546  // loop
33547  if (found_vertex_on_dst_boundary_initial)
33548  {
33549  // But first save the subpoly number (chunk), that will be
33550  // used to perform the connection
33551  sub_poly_to_connect = isub;
33552  break;
33553  } // if (found_vertex_on_dst_boundary_initial)
33554 
33555  } // for (isub < nsub_poly)
33556 
33557  } // if (!connecting_to_an_overlaped_boundary)
33558  else
33559  {
33560  // If connecting to an overlapped boundary then we ignore the
33561  // subpolylines overlapped by shared boundaries and only look
33562  // on the sub-polylines that are not marked as being overlaped
33563  // by shared boundaries
33564 
33565  // Look for the vertex number to connect on each of the
33566  // subpolyines
33567  for (unsigned isub = 0; isub < nsub_poly; isub++)
33568  {
33569  // Only work with those sub-polylines that are not overlaped
33570  // by shared boundaries
33571  if (!this->boundary_marked_as_shared_boundary(dst_bnd_id_initial,
33572  isub))
33573  {
33574  // Assign the pointer to the sub-polyline
33575  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33576 
33577  // Search for the vertex in the current sub-polyline
33578  found_vertex_on_dst_boundary_initial =
33579  this->get_connected_vertex_number_on_destination_polyline(
33580  poly_to_connect_pt,
33581  src_vertex_coordinates_initial,
33582  n_vertex_connection_initial);
33583 
33584  // Was the vertex found?
33585  if (found_vertex_on_dst_boundary_initial)
33586  {
33587  // But first save the subpoly number (chunk), that will
33588  // be used to perform the connection
33589  sub_poly_to_connect = isub;
33590  break;
33591  } // if (found_vertex_on_dst_boundary_initial)
33592 
33593  } // if (not overlaped by shared boundary)
33594 
33595  } // for (isub < nsub_poly)
33596 
33597  } // else if (!connecting_to_an_overlaped_boundary)
33598 
33599  } // else if (!connecting_to_an_split_boundary)
33600 #endif // #ifdef OOMPH_HAS_MPI
33601 
33602  // If not found it may be that the connection information is
33603  // inverted
33604  if (!found_vertex_on_dst_boundary_initial)
33605  {
33606  // Is the mesh distributed?
33607 #ifdef OOMPH_HAS_MPI
33608  if (this->is_mesh_distributed())
33609  {
33610  // If the mesh is distributed and the vertex number was not
33611  // found, that means that the boundary (or vertex) to connect
33612  // in the destination boundary is not in the current
33613  // processor. In that case suspend the connection
33614  polyline_pt->suspend_initial_vertex_connected();
33615  // Add the polyline to the vector of polylines whose
33616  // connection will be resumed at the end of the adaptation
33617  // process
33618  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33619  // The shared boundaries are marked to connect to the initial
33620  // vertex of the polyline (remember that a shared boundary
33621  // stops adding nodes when it finds a node on an original
33622  // boundary) -- The initial vertex is now a base node
33623  }
33624  else
33625 #endif // #ifdef OOMPH_HAS_MPI
33626  {
33627 #ifdef PARANOID
33628  // If not found then there is a problem with the vertices
33629  // Get the associated boundary id of the current polyline
33630  const unsigned bnd_id = polyline_pt->boundary_id();
33631  std::ostringstream error_message;
33632  error_message
33633  << "INITIAL VERTEX CONNECTION\n"
33634  << "It was not possible to find the associated "
33635  << "vertex number on the destination boundary\n"
33636  << "The current boundary (" << bnd_id << ") is marked to have"
33637  << "a connection at the\nINITIAL vertex ("
33638  << src_vertex_coordinates_initial[0] << ","
33639  << src_vertex_coordinates_initial[1] << ")\n"
33640  << "with boundary (" << dst_bnd_id_initial << ")\n"
33641  << "This is the list of vertices on the destination boundary\n";
33642  // Get the pointer to the associated polyline by using the
33643  // boundary id
33644  TriangleMeshPolyLine* dst_polyline =
33645  this->boundary_polyline_pt(dst_bnd_id_initial);
33646  // The number of vertices on the destination boundary
33647  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33648  // Loop over the vertices print them
33649  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33650  {
33651  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33652  error_message << "Vertex#(i): (" << current_vertex[0] << ", "
33653  << current_vertex[1] << ")\n";
33654  }
33655  throw OomphLibError(
33656  error_message.str(),
33657  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33658  OOMPH_EXCEPTION_LOCATION);
33659 #endif
33660 
33661  } // else if (this->is_mesh_distributed())
33662 
33663  } // if (!found_vertex_on_dst_boundary_initial)
33664  else
33665  {
33666  // Set the vertex number on the destination boundary
33667  polyline_pt->initial_vertex_connected_n_vertex() =
33668  n_vertex_connection_initial;
33669 
33670  // Set the chunk number on the destination boundary
33671  polyline_pt->initial_vertex_connected_n_chunk() = sub_poly_to_connect;
33672 
33673  } // else if (!found_vertex_on_dst_boundary_initial)
33674 
33675  } // if (polyline_pt->is_initial_vertex_connected())
33676 
33677  // ------------------------------------------------------------------
33678  // Is the final vertex connected?
33679  if (polyline_pt->is_final_vertex_connected())
33680  {
33681  // The pointer to the boundary to connect
33682  TriangleMeshPolyLine* poly_to_connect_pt = 0;
33683 
33684  // Get the boundary id of the destination/connected boundary
33685  const unsigned dst_bnd_id_final =
33686  polyline_pt->final_vertex_connected_bnd_id();
33687 
33688  // Get the final vertex on the current boundary
33689  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33690  Vector<double> src_vertex_coordinates_final =
33691  polyline_pt->vertex_coordinate(tmp_n_vertices - 1);
33692 
33693 
33694 #ifdef PARANOID
33695  // Is the mesh distributed?
33696 #ifdef OOMPH_HAS_MPI
33697  if (this->is_mesh_distributed())
33698  {
33699  // Get the initial shared boundary id
33700  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
33701  // Is the boundary to connect a shared boundary
33702  if (dst_bnd_id_final >= init_shd_bnd_id)
33703  {
33704  // Get the current polyline original boundary id
33705  const unsigned bnd_id = polyline_pt->boundary_id();
33706  std::ostringstream error_message;
33707  error_message
33708  << "FINAL VERTEX CONNECTION\n"
33709  << "The current original boundary is trying to connect to a\n"
33710  << "shared boundary, this is not allowed. In this case the\n"
33711  << "shared boundary should be the one that connects with the\n"
33712  << "original boundary\n"
33713  << "The current boundary (" << bnd_id << ") is marked to have "
33714  << "a connection at the\nFINAL vertex ("
33715  << src_vertex_coordinates_final[0] << ","
33716  << src_vertex_coordinates_final[1] << ")\n"
33717  << "with boundary (" << dst_bnd_id_final << ")\n"
33718  << "This is the list of vertices on the destination boundary\n";
33719  // Get the pointer to the associated polyline by using the
33720  // boundary id
33721  TriangleMeshPolyLine* dst_polyline =
33722  this->boundary_polyline_pt(dst_bnd_id_final);
33723  // The number of vertices on the destination boundary
33724  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33725  // Loop over the vertices print them
33726  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33727  {
33728  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33729  error_message << "Vertex#(" << i << "): (" << current_vertex[0]
33730  << ", " << current_vertex[1] << ")\n";
33731  }
33732  throw OomphLibError(
33733  error_message.str(),
33734  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33735  OOMPH_EXCEPTION_LOCATION);
33736  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33737 
33738  } // if (this->is_mesh_distributed())
33739 #endif // #ifdef OOMPH_HAS_MPI
33740 
33741 #endif // #ifdef PARANOID
33742 
33743  // Flag to indicate if the vertex was found on the destination
33744  // boundary
33745  bool found_vertex_on_dst_boundary_final = false;
33746 
33747  // Flag that stores the chunk number to connect (only used in
33748  // distributed meshes)
33749  unsigned sub_poly_to_connect = 0;
33750 
33751  // Store the vertex number on the destination boundary
33752  unsigned n_vertex_connection_final = 0;
33753 
33754  // Flags only used in a distributed mesh
33755  // ----------------------------------------
33756  // Flag to indicate we are trying to connect to an split boundary
33757  bool connecting_to_an_split_boundary = false;
33758 
33759  // Flag to indicate we are trying to connecto to an internal
33760  // boundary that is overlaped by a shared boundary)
33761  bool connecting_to_an_overlaped_boundary = false;
33762 
33763 #ifdef OOMPH_HAS_MPI
33764  if (this->is_mesh_distributed())
33765  {
33766  // We can only connect to an original boundary, check if the
33767  // boundary was splitted during the distribution process to
33768  // consider all the chunks (sub-polylines) of the boundary
33769  if (this->boundary_was_splitted(dst_bnd_id_final))
33770  {
33771  connecting_to_an_split_boundary = true;
33772  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33773 
33774  // Check if the destination boundary, or any of its chunks is
33775  // marked to be overlapped by a shared boundary, if that is the
33776  // case we can only connect to the chunks that are not
33777  // overlapped by shared boundaries (the shared boundaries are in
33778  // charge of generating the connections with original boundaries
33779  // and with themselves)
33780  if (connecting_to_an_split_boundary)
33781  {
33782  // Get the number of chucks that represent the destination
33783  // boundary
33784  const unsigned n_sub_poly =
33785  this->nboundary_subpolylines(dst_bnd_id_final);
33786  // Now loop over the chunks of the destination boundary and if
33787  // any of them is marked to be overlaped by a shared boundary
33788  // then set the flag and break the loop
33789  for (unsigned ii = 0; ii < n_sub_poly; ii++)
33790  {
33791  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33792  {
33793  // Mark the boundary as being overlaped by a shared
33794  // boundary
33795  connecting_to_an_overlaped_boundary = true;
33796  // Break, no need to look for more overlapings
33797  break;
33798  } // if (boundary_marked_as_shared_boundary(...))
33799  } // for (ii < n_sub_poly)
33800  } // if (connecting_to_an_split_boundary)
33801  else
33802  {
33803  // If not connecting to an split boundary then check if the
33804  // whole destination boundary is overlaped by an internal
33805  // boundary
33806  if (this->boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33807  {
33808  // Mark the boundary as being overlaped by a shared boundary
33809  connecting_to_an_overlaped_boundary = true;
33810  } // if (boundary_marked_as_shared_boundary(...))
33811  } // else if (connecting_to_an_split_boundary)
33812 
33813  } // if (this->is_mesh_distributed())
33814 
33815 #endif // #ifdef OOMPH_HAS_MPI
33816 
33817  // If we are connecting neither to an split boundary nor an
33818  // overlaped boundary then get the pointer to the original
33819  // boundary
33820  if (!(connecting_to_an_split_boundary ||
33821  connecting_to_an_overlaped_boundary))
33822  {
33823  // Get the polyline pointer representing the destination
33824  // boundary
33825  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33826  } // else if (NOT split, NOT overlaped)
33827 
33828  // Now look for the vertex number on the destination boundary(ies)
33829  // -- in case that the boundary was split ---
33830 
33831  // Do not check for same orientation, that was previously worked
33832  // by interchanging the connections boundaries (if necessary)
33833 
33834  // If the boundary was not split then ...
33835  if (!connecting_to_an_split_boundary)
33836  {
33837  // ... check if the boundary is marked to be overlaped by
33838  // a shared boundary
33839  if (!connecting_to_an_overlaped_boundary)
33840  {
33841  // If that is not the case then we can safely look for the
33842  // vertex number on the destination boundary
33843  found_vertex_on_dst_boundary_final =
33844  this->get_connected_vertex_number_on_destination_polyline(
33845  poly_to_connect_pt,
33846  src_vertex_coordinates_final,
33847  n_vertex_connection_final);
33848 
33849  } // if (!connecting_to_an_overlaped_boundary)
33850  else
33851  {
33852  // If the whole boundary is marked to be overlaped by a shared
33853  // boundary then do nothing, the shared boundaries are already
33854  // in charge of performing the connection (it will be required
33855  // to disabled the connection) with the original boundary
33856 
33857  } // else if (!connecting_to_an_overlaped_boundary)
33858 
33859  } // if (!connecting_to_an_split_boundary)
33860 #ifdef OOMPH_HAS_MPI
33861  else
33862  {
33863  // If the boundary was split then we need to look for the vertex
33864  // in the sub-polylines
33865 
33866  // Get the sub-polylines vector
33867  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33868  this->boundary_subpolylines(dst_bnd_id_final);
33869 
33870  // Get the number of sub-polylines
33871  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33872 #ifdef PARANOID
33873  if (nsub_poly <= 1)
33874  {
33875  std::ostringstream error_message;
33876  error_message << "The boundary (" << dst_bnd_id_final << ") was "
33877  << "marked to be splitted but\n"
33878  << "there are only (" << nsub_poly << ") polylines to "
33879  << "represent it.\n";
33880  throw OomphLibError(
33881  error_message.str(),
33882  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33883  OOMPH_EXCEPTION_LOCATION);
33884  } // if (nsub_poly <= 1)
33885 #endif
33886  // We need to check if the boundary is marked to be overlaped by
33887  // a shared boundary, if that is the case we need to check for
33888  // each indivual subpolyline, and for those overlaped by a
33889  // shared polyline do nothing, the shared polylines have already
33890  // deal with these connections
33891 
33892  // ... check if the boundary is marked to be overlaped by
33893  // a shared boundary
33894  if (!connecting_to_an_overlaped_boundary)
33895  {
33896  // The boundary is not overlapped by shared boundaries, we can
33897  // work without checking the subpolylines individually (non of
33898  // them are overlapped by a shared boundary)
33899 
33900  // Look for the vertex number to connect on each of the
33901  // subpolyines
33902  for (unsigned isub = 0; isub < nsub_poly; isub++)
33903  {
33904  // Assign the pointer to the sub-polyline
33905  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33906  // Search for the vertex in the current sub-polyline
33907  found_vertex_on_dst_boundary_final =
33908  this->get_connected_vertex_number_on_destination_polyline(
33909  poly_to_connect_pt,
33910  src_vertex_coordinates_final,
33911  n_vertex_connection_final);
33912 
33913  // If we have found the vertex to connect then break the
33914  // loop
33915  if (found_vertex_on_dst_boundary_final)
33916  {
33917  // But first save the subpoly number (chunk), that will be
33918  // used to perform the connection
33919  sub_poly_to_connect = isub;
33920  break;
33921  } // if (found_vertex_on_dst_boundary_initial)
33922 
33923  } // for (isub < nsub_poly)
33924 
33925  } // if (!connecting_to_an_overlaped_boundary)
33926  else
33927  {
33928  // If connecting to an overlapped boundary then we ignore the
33929  // subpolylines overlapped by shared boundaries and only look
33930  // on the sub-polylines that are not marked as being overlaped
33931  // by shared boundaries
33932 
33933  // Look for the vertex number to connect on each of the
33934  // subpolyines
33935  for (unsigned isub = 0; isub < nsub_poly; isub++)
33936  {
33937  // Only work with those sub-polylines that are not overlaped
33938  // by shared boundaries
33939  if (!this->boundary_marked_as_shared_boundary(dst_bnd_id_final,
33940  isub))
33941  {
33942  // Assign the pointer to the sub-polyline
33943  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33944 
33945  // Search for the vertex in the current sub-polyline
33946  found_vertex_on_dst_boundary_final =
33947  this->get_connected_vertex_number_on_destination_polyline(
33948  poly_to_connect_pt,
33949  src_vertex_coordinates_final,
33950  n_vertex_connection_final);
33951 
33952  // Was the vertex found?
33953  if (found_vertex_on_dst_boundary_final)
33954  {
33955  // But first save the subpoly number (chunk), that will
33956  // be used to perform the connection
33957  sub_poly_to_connect = isub;
33958  break;
33959  } // if (found_vertex_on_dst_boundary_final)
33960 
33961  } // if (not overlaped by shared boundary)
33962 
33963  } // for (isub < nsub_poly)
33964 
33965  } // else if (!connecting_to_an_overlaped_boundary)
33966 
33967  } // else if (!connecting_to_an_split_boundary)
33968 #endif // #ifdef OOMPH_HAS_MPI
33969 
33970  // If not found it may be that the connection information is
33971  // inverted
33972  if (!found_vertex_on_dst_boundary_final)
33973  {
33974  // Is the mesh distributed?
33975 #ifdef OOMPH_HAS_MPI
33976  if (this->is_mesh_distributed())
33977  {
33978  // If the mesh is distributed and the vertex number was not
33979  // found, that means that the boundary (or vertex) to connect
33980  // in the destination boundary is not in the current
33981  // processor. In that suspend the connection
33982  polyline_pt->suspend_final_vertex_connected();
33983  // Add the polyline to the vector of polylines whose
33984  // connection will be resumed at the end of the adaptation
33985  // process
33986  resume_final_connection_polyline_pt.push_back(polyline_pt);
33987  // The shared boundaries are marked to connect to the final
33988  // vertex of the polyline (remember that a shared boundary
33989  // stops adding nodes when it finds a node on an original
33990  // boundary) -- The final vertex is now a base node
33991  } // if (this->is_mesh_distributed())
33992  else
33993 #endif // #ifdef OOMPH_HAS_MPI
33994  {
33995 #ifdef PARANOID
33996  // If not found then there is a problem with the vertices
33997  // Get the associated boundary id of the current polyline
33998  const unsigned bnd_id = polyline_pt->boundary_id();
33999  std::ostringstream error_message;
34000  error_message
34001  << "FINAL VERTEX CONNECTION\n"
34002  << "It was not possible to find the associated "
34003  << "vertex number on the destination boundary\n"
34004  << "The current boundary (" << bnd_id << ") is marked to have "
34005  << "a connection at the\nFINAL vertex ("
34006  << src_vertex_coordinates_final[0] << ","
34007  << src_vertex_coordinates_final[1] << ")\n"
34008  << "with boundary (" << dst_bnd_id_final << ")\n"
34009  << "This is the list of vertices on the destination boundary\n";
34010  // Get the pointer to the associated polyline by using the
34011  // boundary id
34012  TriangleMeshPolyLine* dst_polyline =
34013  this->boundary_polyline_pt(dst_bnd_id_final);
34014  // The number of vertices on the destination boundary
34015  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
34016  // Loop over the vertices print them
34017  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
34018  {
34019  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
34020  error_message << "Vertex#(" << i << "): (" << current_vertex[0]
34021  << ", " << current_vertex[1] << ")\n";
34022  }
34023  throw OomphLibError(
34024  error_message.str(),
34025  "RefineableTriangleMesh::restore_polyline_connections_helper()",
34026  OOMPH_EXCEPTION_LOCATION);
34027 #endif
34028  } // else if (this->is_mesh_distributed())
34029 
34030  } // if (!found_vertex_on_dst_boundary_final)
34031  else
34032  {
34033  // Set the vertex number on the destination boundary
34034  polyline_pt->final_vertex_connected_n_vertex() =
34035  n_vertex_connection_final;
34036 
34037  // Set the chunk number on the destination boundary
34038  polyline_pt->final_vertex_connected_n_chunk() = sub_poly_to_connect;
34039 
34040  } // else if (!found_vertex_on_dst_boundary_final)
34041 
34042  } // if (polyline_pt->is_final_vertex_connected())
34043  }
34044 
34045  //=========================================================================
34046  /// Resume the boundary connections that may have been
34047  /// suspended because the destination boundary is no part of the
34048  /// domain. The connections are no permanently suspended because if
34049  /// load balance takes place the destination boundary may be part of
34050  /// the new domain representation therefore the connection would
34051  /// exist
34052  //=========================================================================
34053  template<class ELEMENT>
34055  Vector<TriangleMeshPolyLine*>& resume_initial_connection_polyline_pt,
34056  Vector<TriangleMeshPolyLine*>& resume_final_connection_polyline_pt)
34057  {
34058  // Get the number of polylines that require to resume the connection
34059  // at the initial vertex
34060  const unsigned n_initial_poly =
34061  resume_initial_connection_polyline_pt.size();
34062  // Loop over the polylines that require to resume the connection
34063  // at the initial vertex
34064  for (unsigned p = 0; p < n_initial_poly; p++)
34065  {
34066  // Get the polyline
34067  TriangleMeshPolyLine* tmp_poly_pt =
34068  resume_initial_connection_polyline_pt[p];
34069  // Resume the connection with the initial vertex
34070  tmp_poly_pt->resume_initial_vertex_connected();
34071  } // for (p < n_initial_poly)
34072 
34073  // Get the number of polylines that require to resume the connection
34074  // at the final vertex
34075  const unsigned n_final_poly = resume_final_connection_polyline_pt.size();
34076  // Loop over the polylines that require to resume the connection at
34077  // the final vertex
34078  for (unsigned p = 0; p < n_final_poly; p++)
34079  {
34080  // Get the polyline
34081  TriangleMeshPolyLine* tmp_poly_pt =
34082  resume_final_connection_polyline_pt[p];
34083  // Resume the connection with the final vertex
34084  tmp_poly_pt->resume_final_vertex_connected();
34085  } // for (p < n_final_poly)
34086 
34087  // Clear the storage
34088  resume_initial_connection_polyline_pt.clear();
34089  resume_final_connection_polyline_pt.clear();
34090  }
34091 
34092  //=========================================================================
34093  /// Gets the associated vertex number according to the vertex
34094  /// coordinates on the destination boundary
34095  //=========================================================================
34096  template<class ELEMENT>
34099  Vector<double>& vertex_coordinates,
34100  const unsigned& dst_bnd_id,
34101  unsigned& vertex_number)
34102  {
34103  bool found_associated_vertex_number = false;
34104 
34105  // Get the pointer to the associated polyline by using the boundary id
34106  TriangleMeshPolyLine* dst_polyline = this->boundary_polyline_pt(dst_bnd_id);
34107 
34108  const unsigned n_vertices = dst_polyline->nvertex();
34109 
34110  // Loop over the vertices and return the closest vertex
34111  // to the given vertex coordinates
34112  for (unsigned i = 0; i < n_vertices; i++)
34113  {
34114  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
34115 
34116  double error = (vertex_coordinates[0] - current_vertex[0]) *
34117  (vertex_coordinates[0] - current_vertex[0]) +
34118  (vertex_coordinates[1] - current_vertex[1]) *
34119  (vertex_coordinates[1] - current_vertex[1]);
34120 
34121  error = sqrt(error);
34122 
34123  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
34124  {
34125  vertex_number = i;
34126  found_associated_vertex_number = true;
34127  break;
34128  }
34129  }
34130 
34131  return found_associated_vertex_number;
34132  }
34133 
34134  //=========================================================================
34135  /// Helper function that updates the input polygon's PSLG
34136  /// by using the end-points of elements from FaceMesh(es) that are
34137  /// constructed for the boundaries associated with the segments of the
34138  /// polygon. Optional boolean is used to run it as test only (if
34139  /// true is specified as input) in which case polygon isn't actually
34140  /// modified. Returned boolean indicates if polygon was (or would have
34141  /// been -- if called with check_only=false) changed.
34142  //=========================================================================
34143  template<class ELEMENT>
34145  TriangleMeshPolygon* polygon_pt, const bool& check_only)
34146  {
34147 #ifdef PARANOID
34148  // If the mesh is marked as distributed this method can not be
34149  // called since there is no guarantee of creating (distributed)
34150  // meshes that match in the number and position of nodes at their
34151  // shared boundaries. The only exececption is when called with
34152  // check_only=true, since no boundary updating is performed
34153  if (this->is_mesh_distributed() && !check_only)
34154  {
34155  std::stringstream error_message;
34156  error_message
34157  << "The updating of polygons of a distributed mesh can ONLY be\n"
34158  << "performed using the element's area associated to the halo(ed)\n"
34159  << "elements.\n"
34160  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34161  << "option if you are working with a distributed mesh, OR\n"
34162  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34163  << "if the mesh is marked as distributed\n\n";
34164  throw OomphLibError(
34165  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
34166  } // if (this->is_mesh_distributed())
34167 #endif
34168 
34169  // Boolean that indicates whether an actual update of the polygon
34170  // was performed or not
34171  bool unrefinement_was_performed = false;
34172  bool refinement_was_performed = false;
34173  bool max_length_applied = false;
34174 
34175  // Loop over the number of polylines
34176  const unsigned n_polyline = polygon_pt->npolyline();
34177 
34178  // Get face mesh representation of all polylines, possibly
34179  // with segments re-distributed to maintain an approximately
34180  // even sub-division of the polygon
34181  Vector<Mesh*> face_mesh_pt;
34182  get_face_mesh_representation(polygon_pt, face_mesh_pt);
34183 
34184  // Create vertices for the polylines by using the vertices
34185  // of the FaceElements
34186  Vector<double> vertex_coord(3); // zeta,x,y
34187  Vector<double> bound_left(1);
34188  Vector<double> bound_right(1);
34189 
34190  for (unsigned p = 0; p < n_polyline; p++)
34191  {
34192  // Set of coordinates that will be placed on the boundary
34193  // Set entries are ordered on first entry in vector which stores
34194  // the boundary coordinate so the vertices come out in order!
34195  std::set<Vector<double>> vertex_nodes;
34196 
34197  // Get the boundary id
34198  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
34199 
34200  // Get the chunk number
34201  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
34202 
34203  // Loop over the face elements (ordered) and add their vertices
34204  unsigned n_face_element = face_mesh_pt[p]->nelement();
34205  for (unsigned e = 0; e < n_face_element; ++e)
34206  {
34207  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34208 
34209 #ifdef OOMPH_HAS_MPI
34210  // Only work with non-halo elements if the mesh is distributed
34211  if (this->is_mesh_distributed() && el_pt->is_halo())
34212  {
34213  continue;
34214  }
34215 #endif
34216 
34217  unsigned n_node = el_pt->nnode();
34218 
34219  // Add the left-hand node to the set:
34220 
34221  // Boundary coordinate
34222  el_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
34223  vertex_coord[0] = bound_left[0];
34224 
34225  // Actual coordinates
34226  for (unsigned i = 0; i < 2; i++)
34227  {
34228  vertex_coord[i + 1] = el_pt->node_pt(0)->x(i);
34229  }
34230  vertex_nodes.insert(vertex_coord);
34231 
34232  // Add the right-hand nodes to the set:
34233 
34234  // Boundary coordinate
34235  el_pt->node_pt(n_node - 1)
34236  ->get_coordinates_on_boundary(bound, bound_right);
34237  vertex_coord[0] = bound_right[0];
34238 
34239  // Actual coordinates
34240  for (unsigned i = 0; i < 2; i++)
34241  {
34242  vertex_coord[i + 1] = el_pt->node_pt(n_node - 1)->x(i);
34243  }
34244  vertex_nodes.insert(vertex_coord);
34245  }
34246 
34247  // Now turn into vector for ease of handling...
34248  unsigned n_poly_vertex = vertex_nodes.size();
34249  Vector<Vector<double>> tmp_vector_vertex_node(n_poly_vertex);
34250  unsigned count = 0;
34251  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
34252  it != vertex_nodes.end();
34253  ++it)
34254  {
34255  tmp_vector_vertex_node[count].resize(3);
34256  tmp_vector_vertex_node[count][0] = (*it)[0];
34257  tmp_vector_vertex_node[count][1] = (*it)[1];
34258  tmp_vector_vertex_node[count][2] = (*it)[2];
34259  ++count;
34260  }
34261 
34262  // Size of the vector
34263  unsigned n_vertex = tmp_vector_vertex_node.size();
34264 
34265  // Tolerance below which the middle point can be deleted
34266  // (ratio of deflection to element length)
34267  double unrefinement_tolerance =
34268  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
34269 
34270  //------------------------------------------------------
34271  // Unrefinement
34272  //------------------------------------------------------
34273  if (unrefinement_tolerance > 0.0 && n_vertex >= 3)
34274  {
34275  unrefinement_was_performed = unrefine_boundary(bound,
34276  chunk,
34277  tmp_vector_vertex_node,
34278  unrefinement_tolerance,
34279  check_only);
34280 
34281  // In this case the "unrefinement_was_performed" variable
34282  // tell us if the update had been performed when calling
34283  // with check_oly=false
34284  if (check_only && unrefinement_was_performed)
34285  {
34286  // Cleanup (but only the elements -- the nodes still exist in
34287  // the bulk mesh!
34288  for (unsigned p = 0; p < n_polyline; p++)
34289  {
34290  face_mesh_pt[p]->flush_node_storage();
34291  delete face_mesh_pt[p];
34292  }
34293  return true;
34294  }
34295 
34296  } // end of unrefinement
34297 
34298  // Do not perform refinement if there are no more than two vertices
34299  // New size of the vector
34300  n_vertex = tmp_vector_vertex_node.size();
34301 
34302  //------------------------------------------------
34303  // Refinement
34304  //------------------------------------------------
34305  double refinement_tolerance =
34306  polygon_pt->polyline_pt(p)->refinement_tolerance();
34307  if (refinement_tolerance > 0.0 && n_vertex >= 2)
34308  {
34309  refinement_was_performed = refine_boundary(face_mesh_pt[p],
34310  tmp_vector_vertex_node,
34311  refinement_tolerance,
34312  check_only);
34313 
34314  // In this case the "refinement_was_performed" variable
34315  // tell us if the update had been performed when calling
34316  // with check_only=false
34317  if (check_only && refinement_was_performed)
34318  {
34319  // Cleanup (but only the elements -- the nodes still exist in
34320  // the bulk mesh!
34321  for (unsigned p = 0; p < n_polyline; p++)
34322  {
34323  face_mesh_pt[p]->flush_node_storage();
34324  delete face_mesh_pt[p];
34325  }
34326  return true;
34327  }
34328 
34329  } // end refinement
34330 
34331  // Do not perform maximum length constraint if there are no more than
34332  // two vertices
34333  // New size of the vector
34334  n_vertex = tmp_vector_vertex_node.size();
34335 
34336  //------------------------------------------------
34337  // Maximum length constrait
34338  //-----------------------------------------------
34339  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34340  if (maximum_length > 0.0 && n_vertex >= 2)
34341  {
34342  max_length_applied = apply_max_length_constraint(
34343  face_mesh_pt[p], tmp_vector_vertex_node, maximum_length);
34344 
34345  // In this case the max length criteria was applied, check if
34346  // check_only=false
34347  if (check_only && max_length_applied)
34348  {
34349  // Cleanup (but only the elements -- the nodes still exist in
34350  // the bulk mesh!
34351  for (unsigned p = 0; p < n_polyline; p++)
34352  {
34353  face_mesh_pt[p]->flush_node_storage();
34354  delete face_mesh_pt[p];
34355  }
34356  return true;
34357  }
34358  }
34359 
34360  // For further processing the three-dimensional vector
34361  // has to be reduced to a two-dimensional vector
34362  n_vertex = tmp_vector_vertex_node.size();
34363  Vector<Vector<double>> vector_vertex_node(n_vertex);
34364 
34365  for (unsigned i = 0; i < n_vertex; i++)
34366  {
34367  vector_vertex_node[i].resize(2);
34368  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
34369  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
34370  }
34371 
34372 #ifdef OOMPH_HAS_MPI
34373  // Only perform this checking if the mesh is not distributed. When
34374  // the mesh is distributed the polylines continuity is addressed in
34375  // the sort_polylines_helper() method
34376  if (!this->is_mesh_distributed())
34377 #endif
34378  {
34379  if ((p > 0) && !check_only)
34380  {
34381  // Final end point of previous line
34382  Vector<double> final_vertex_of_previous_segment;
34383  unsigned n_prev_vertex =
34384  polygon_pt->curve_section_pt(p - 1)->nvertex();
34385  final_vertex_of_previous_segment =
34386  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
34387  1);
34388 
34389  unsigned prev_seg_boundary_id =
34390  polygon_pt->curve_section_pt(p - 1)->boundary_id();
34391 
34392  // Find the error between the final vertex of the previous
34393  // line and the first vertex of the current line
34394  double error = 0.0;
34395  for (unsigned i = 0; i < 2; i++)
34396  {
34397  const double dist = final_vertex_of_previous_segment[i] -
34398  (*vector_vertex_node.begin())[i];
34399  error += dist * dist;
34400  }
34401  error = sqrt(error);
34402 
34403  // If the error is bigger than the tolerance then
34404  // we probably need to reverse, but better check
34405  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34406  {
34407  // Find the error between the final vertex of the previous
34408  // line and the last vertex of the current line
34409  double rev_error = 0.0;
34410  for (unsigned i = 0; i < 2; i++)
34411  {
34412  const double dist = final_vertex_of_previous_segment[i] -
34413  (*--vector_vertex_node.end())[i];
34414  rev_error += dist * dist;
34415  }
34416  rev_error = sqrt(rev_error);
34417 
34418  if (rev_error >
34419  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34420  {
34421  // It could be possible that the first segment be reversed and we
34422  // did not notice it because this check does not apply for the
34423  // first segment. We can verify if the first segment is reversed
34424  // by using the vertex number 1
34425  if (p == 1)
34426  {
34427  // Initial end point of previous line
34428  Vector<double> initial_vertex_of_previous_segment;
34429 
34430  initial_vertex_of_previous_segment =
34431  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
34432 
34433  unsigned prev_seg_boundary_id =
34434  polygon_pt->curve_section_pt(p - 1)->boundary_id();
34435 
34436  // Find the error between the initial vertex of the previous
34437  // line and the first vertex of the current line
34438  double error = 0.0;
34439  for (unsigned i = 0; i < 2; i++)
34440  {
34441  const double dist = initial_vertex_of_previous_segment[i] -
34442  (*vector_vertex_node.begin())[i];
34443  error += dist * dist;
34444  }
34445  error = sqrt(error); // Reversed only the previous one
34446 
34447  // If the error is bigger than the tolerance then
34448  // we probably need to reverse, but better check
34449  if (error >
34450  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34451  {
34452  // Find the error between the final vertex of the previous
34453  // line and the last vertex of the current line
34454  double rev_error = 0.0;
34455  for (unsigned i = 0; i < 2; i++)
34456  {
34457  const double dist = initial_vertex_of_previous_segment[i] -
34458  (*--vector_vertex_node.end())[i];
34459  rev_error += dist * dist;
34460  }
34461  rev_error =
34462  sqrt(rev_error); // Reversed both the current one and
34463  // the previous one
34464 
34465  if (rev_error >
34466  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34467  {
34468  std::ostringstream error_stream;
34469  error_stream
34470  << "The distance between the first node of the current\n"
34471  << "line segment (boundary " << bound
34472  << ") and either end of "
34473  << "the previous line segment\n"
34474  << "(boundary " << prev_seg_boundary_id
34475  << ") is bigger than "
34476  << "the desired tolerance "
34477  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34478  << ".\n"
34479  << "This suggests that the polylines defining the "
34480  "polygonal\n"
34481  << "representation are not properly ordered.\n"
34482  << "Fail on last vertex of polyline: ("
34483  << prev_seg_boundary_id
34484  << ") and\nfirst vertex of polyline (" << bound
34485  << ").\nThis should have failed when first trying to "
34486  << "construct the\npolygon.\n";
34487  throw OomphLibError(error_stream.str(),
34488  OOMPH_CURRENT_FUNCTION,
34489  OOMPH_EXCEPTION_LOCATION);
34490  }
34491  else
34492  {
34493  // Reverse both
34494  // Reverse the current vector to line up with the previous
34495  // one
34496  std::reverse(vector_vertex_node.begin(),
34497  vector_vertex_node.end());
34498 
34499  polygon_pt->polyline_pt(p - 1)->reverse();
34500  }
34501  }
34502  else
34503  {
34504  // Reverse the previous one
34505  polygon_pt->polyline_pt(p - 1)->reverse();
34506  }
34507 
34508  } // if p == 1
34509  else
34510  {
34511  std::ostringstream error_stream;
34512  error_stream
34513  << "The distance between the first node of the current\n"
34514  << "line segment (boundary " << bound
34515  << ") and either end of "
34516  << "the previous line segment\n"
34517  << "(boundary " << prev_seg_boundary_id
34518  << ") is bigger than the "
34519  << "desired tolerance "
34520  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34521  << ".\n"
34522  << "This suggests that the polylines defining the polygonal\n"
34523  << "representation are not properly ordered.\n"
34524  << "Fail on last vertex of polyline: ("
34525  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
34526  << bound << ").\n"
34527  << "This should have failed when first trying to construct "
34528  "the\n"
34529  << "polygon.\n";
34530  throw OomphLibError(error_stream.str(),
34531  OOMPH_CURRENT_FUNCTION,
34532  OOMPH_EXCEPTION_LOCATION);
34533  }
34534  }
34535  else
34536  {
34537  // Reverse the current vector to line up with the previous one
34538  std::reverse(vector_vertex_node.begin(),
34539  vector_vertex_node.end());
34540  }
34541 
34542  } // first error
34543  } // p > 0
34544  } // is mesh not distributed?
34545 
34546  if (!check_only)
34547  {
34548  // Now update the polyline according to the new vertices
34549  // The new one representation
34550  TriangleMeshPolyLine* tmp_polyline_pt =
34551  new TriangleMeshPolyLine(vector_vertex_node, bound);
34552 
34553  // Create a temporal "curve section" version of the recently created
34554  // polyline
34555  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
34556 
34557  // Establish refinement and unrefinement tolerance
34558  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
34559  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
34560 
34561  // Establish the maximum length constraint
34562  tmp_polyline_pt->set_maximum_length(maximum_length);
34563 
34564  // We pass the connection information from the old polyline to
34565  // the new one
34566  this->copy_connection_information(polygon_pt->polyline_pt(p),
34567  tmp_curve_section_pt);
34568 
34569 
34570  std::set<TriangleMeshCurveSection*>::iterator it =
34571  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34572 
34573  if (it != this->Free_curve_section_pt.end())
34574  {
34575  this->Free_curve_section_pt.erase(it);
34576  delete polygon_pt->curve_section_pt(p);
34577  }
34578 
34579  // ------------------------------------------------------------
34580  // Copying the new representation
34581  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34582 
34583  // Update the Boundary - Polyline map
34584  this->Boundary_curve_section_pt[bound] =
34585  polygon_pt->curve_section_pt(p);
34586 
34587  // The new curve always needs to be added to the free section
34588  // because we created it internally
34589  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34590 
34591  } // if(!check_only)
34592 
34593  } // for (p < n_polyline)
34594 
34595  // Cleanup (but only the elements -- the nodes still exist in
34596  // the bulk mesh!
34597  for (unsigned p = 0; p < n_polyline; p++)
34598  {
34599  face_mesh_pt[p]->flush_node_storage();
34600  delete face_mesh_pt[p];
34601  }
34602 
34603  if (check_only)
34604  {
34605  // if we end up all the way down here, no update of the internal
34606  // boundaries is necessary (in case we only check)
34607  return false;
34608  }
34609  else
34610  {
34611  // if we not only check, but actually perform the update and end up
34612  // all the way down here then we indicate whether an update was performed
34613  // or not
34614  return (unrefinement_was_performed || refinement_was_performed ||
34615  max_length_applied);
34616  }
34617  }
34618 
34619  //=========================================================================
34620  /// Helper function that updates the input open curve by using
34621  /// end-points of elements from FaceMesh(es) that are constructed for the
34622  /// boundaries associated with the polylines. Optional boolean is used to
34623  /// run it as test only (if true is specified as input) in which case the
34624  /// polylines are not actually modified. Returned boolean indicates if
34625  /// polylines were (or would have been -- if called with check_only=false)
34626  /// changed.
34627  //=========================================================================
34628  template<class ELEMENT>
34630  TriangleMeshOpenCurve* open_polyline_pt, const bool& check_only)
34631  {
34632 #ifdef PARANOID
34633  // If the mesh is marked as distributed this method can not be
34634  // called since there is no guarantee of creating (distributed)
34635  // meshes that match in the number and position of nodes at their
34636  // shared boundaries. The only exececption is when called with
34637  // check_only=true, since no boundary updating is performed
34638  if (this->is_mesh_distributed() && !check_only)
34639  {
34640  std::stringstream error_message;
34641  error_message
34642  << "The updating of open curves of a distributed mesh can ONLY be\n"
34643  << "performed using the element's area associated to the halo(ed)\n"
34644  << "elements.\n"
34645  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34646  << "option if you are working with a distributed mesh, OR\n"
34647  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34648  << "if the mesh is marked as distributed\n\n";
34649  throw OomphLibError(
34650  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
34651  } // if (this->is_mesh_distributed())
34652 #endif
34653 
34654  // Boolean that indicates whether an actual update of the polylines
34655  // were performed or not
34656  bool unrefinement_was_performed = false;
34657  bool refinement_was_performed = false;
34658  bool max_length_applied = false;
34659 
34660  // Loop over the number of polylines
34661  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34662 
34663  // Get face mesh representation of all polylines, possibly
34664  // with segments re-distributed to maintain an approximately
34665  // even sub-division of the polygon
34666  Vector<Mesh*> face_mesh_pt;
34667  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34668 
34669  // Create vertices for the polylines by using the vertices
34670  // of the FaceElements
34671  Vector<double> vertex_coord(3); // zeta,x,y
34672  Vector<double> bound_left(1);
34673  Vector<double> bound_right(1);
34674 
34675  for (unsigned p = 0; p < n_polyline; p++)
34676  {
34677  // Set of coordinates that will be placed on the boundary
34678  // Set entries are ordered on first entry in vector which stores
34679  // the boundary coordinate so the vertices come out in order!
34680  std::set<Vector<double>> vertex_nodes;
34681 
34682  // Get the boundary id
34683  const unsigned bound =
34684  open_polyline_pt->curve_section_pt(p)->boundary_id();
34685 
34686  // Get the chunk number
34687  const unsigned chunk =
34688  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34689 
34690  // Loop over the face elements (ordered) and add their vertices
34691  unsigned n_face_element = face_mesh_pt[p]->nelement();
34692 
34693  // n_count = 0;
34694  for (unsigned e = 0; e < n_face_element; ++e)
34695  {
34696  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34697  unsigned n_node = el_pt->nnode();
34698 
34699  // Add the left-hand node to the set:
34700 
34701  // Boundary coordinate
34702  el_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
34703  vertex_coord[0] = bound_left[0];
34704 
34705  // Actual coordinates
34706  for (unsigned i = 0; i < 2; i++)
34707  {
34708  vertex_coord[i + 1] = el_pt->node_pt(0)->x(i);
34709  }
34710  vertex_nodes.insert(vertex_coord);
34711 
34712  // Add the right-hand nodes to the set:
34713 
34714  // Boundary coordinate
34715  el_pt->node_pt(n_node - 1)
34716  ->get_coordinates_on_boundary(bound, bound_right);
34717  vertex_coord[0] = bound_right[0];
34718 
34719  // Actual coordinates
34720  for (unsigned i = 0; i < 2; i++)
34721  {
34722  vertex_coord[i + 1] = el_pt->node_pt(n_node - 1)->x(i);
34723  }
34724  vertex_nodes.insert(vertex_coord);
34725  }
34726 
34727  // Now turn into vector for ease of handling...
34728  unsigned n_poly_vertex = vertex_nodes.size();
34729  Vector<Vector<double>> tmp_vector_vertex_node(n_poly_vertex);
34730  unsigned count = 0;
34731  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
34732  it != vertex_nodes.end();
34733  ++it)
34734  {
34735  tmp_vector_vertex_node[count].resize(3);
34736  tmp_vector_vertex_node[count][0] = (*it)[0];
34737  tmp_vector_vertex_node[count][1] = (*it)[1];
34738  tmp_vector_vertex_node[count][2] = (*it)[2];
34739  ++count;
34740  }
34741 
34742  // Size of the vector
34743  unsigned n_vertex = tmp_vector_vertex_node.size();
34744 
34745  // Tolerance below which the middle point can be deleted
34746  // (ratio of deflection to element length)
34747  double unrefinement_tolerance =
34748  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34749 
34750  //------------------------------------------------------
34751  // Unrefinement
34752  //------------------------------------------------------
34753  if (unrefinement_tolerance > 0.0 && n_vertex >= 3)
34754  {
34755  unrefinement_was_performed = unrefine_boundary(bound,
34756  chunk,
34757  tmp_vector_vertex_node,
34758  unrefinement_tolerance,
34759  check_only);
34760 
34761  // In this case the unrefinement_was_performed variable actually
34762  // tell us if the update had been performed when calling
34763  // with check_only=false
34764  if (check_only && unrefinement_was_performed)
34765  {
34766  // Cleanup (but only the elements -- the nodes still exist in
34767  // the bulk mesh!
34768  for (unsigned p = 0; p < n_polyline; p++)
34769  {
34770  face_mesh_pt[p]->flush_node_storage();
34771  delete face_mesh_pt[p];
34772  }
34773  return true;
34774  }
34775 
34776  } // end of unrefinement
34777 
34778  // Do not perform refinement if there are no more than two vertices
34779  // (open curve version)
34780  // New size of the vector
34781  n_vertex = tmp_vector_vertex_node.size();
34782 
34783  //------------------------------------------------
34784  /// Refinement
34785  //------------------------------------------------
34786  double refinement_tolerance =
34787  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34788  if (refinement_tolerance > 0.0 && n_vertex >= 2)
34789  {
34790  refinement_was_performed = refine_boundary(face_mesh_pt[p],
34791  tmp_vector_vertex_node,
34792  refinement_tolerance,
34793  check_only);
34794 
34795  // In this case the unrefinement_was_performed variable actually
34796  // tell us if the update had been performed when calling
34797  // with check_only=false
34798  if (check_only && refinement_was_performed)
34799  {
34800  // Cleanup (but only the elements -- the nodes still exist in
34801  // the bulk mesh!
34802  for (unsigned p = 0; p < n_polyline; p++)
34803  {
34804  face_mesh_pt[p]->flush_node_storage();
34805  delete face_mesh_pt[p];
34806  }
34807  return true;
34808  }
34809 
34810  } // end refinement
34811 
34812  // Do not perform maximum length constraint if there are no more than
34813  // two vertices
34814  // New size of the vector
34815  n_vertex = tmp_vector_vertex_node.size();
34816 
34817  //------------------------------------------------
34818  // Maximum length constraint
34819  //-----------------------------------------------
34820  double maximum_length =
34821  open_polyline_pt->polyline_pt(p)->maximum_length();
34822  if (maximum_length > 0.0 && n_vertex >= 2)
34823  {
34824  bool max_length_applied = false;
34825  max_length_applied = apply_max_length_constraint(
34826  face_mesh_pt[p], tmp_vector_vertex_node, maximum_length);
34827 
34828  // In this case the max length criteria was applied, check if
34829  // check_only=false
34830  if (check_only && max_length_applied)
34831  {
34832  // Cleanup (but only the elements -- the nodes still exist in
34833  // the bulk mesh!
34834  for (unsigned p = 0; p < n_polyline; p++)
34835  {
34836  face_mesh_pt[p]->flush_node_storage();
34837  delete face_mesh_pt[p];
34838  }
34839  return true;
34840  }
34841  }
34842 
34843  // For further processing the three-dimensional vector
34844  // has to be reduced to a two-dimensional vector
34845  n_vertex = tmp_vector_vertex_node.size();
34846  Vector<Vector<double>> vector_vertex_node(n_vertex);
34847 
34848  for (unsigned i = 0; i < n_vertex; i++)
34849  {
34850  vector_vertex_node[i].resize(2);
34851  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
34852  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
34853  }
34854 
34855 #ifdef OOMPH_HAS_MPI
34856  // Only perform this checking if the mesh is not distributed. When
34857  // the mesh is distributed the polylines continuity is addressed
34858  // in the sort_polylines_helper() method
34859  if (!this->is_mesh_distributed())
34860 #endif
34861  {
34862  // Check whether the segments are continguous (first vertex of this
34863  // segment is equal to last vertex of previous segment).
34864  // If not, we should reverse the order of the current segment.
34865  // This check only applies for segments other than the first.
34866  // We only bother with this check, if we actually perform an update
34867  // of the polyline, i.e. if it's not only a check
34868  if ((p > 0) && !check_only)
34869  {
34870  // Final end point of previous line
34871  Vector<double> final_vertex_of_previous_segment;
34872  open_polyline_pt->polyline_pt(p - 1)->final_vertex_coordinate(
34873  final_vertex_of_previous_segment);
34874 
34875  unsigned prev_seg_boundary_id =
34876  open_polyline_pt->curve_section_pt(p - 1)->boundary_id();
34877 
34878  // Find the error between the final vertex of the previous
34879  // line and the first vertex of the current line
34880  double error = 0.0;
34881  for (unsigned i = 0; i < 2; i++)
34882  {
34883  const double dist = final_vertex_of_previous_segment[i] -
34884  (*vector_vertex_node.begin())[i];
34885  error += dist * dist;
34886  }
34887  error = sqrt(error);
34888 
34889  // If the error is bigger than the tolerance then
34890  // we probably need to reverse, but better check
34891  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34892  {
34893  // Find the error between the final vertex of the previous
34894  // line and the first vertex of the current line
34895  error = 0.0;
34896  for (unsigned i = 0; i < 2; i++)
34897  {
34898  const double dist = final_vertex_of_previous_segment[i] -
34899  (*--vector_vertex_node.end())[i];
34900  error += dist * dist;
34901  }
34902  error = sqrt(error);
34903 
34904  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34905  {
34906  // It could be possible that the first segment be reversed
34907  // and we did not notice it because this check does not
34908  // apply for the first segment. We can verify if the first
34909  // segment is reversed by using the vertex number 1
34910  if (p == 1)
34911  {
34912  // If no found it is possible that the previous polyline
34913  // be reversed Check for that case Initial point of
34914  // previous line
34915  Vector<double> initial_vertex_of_previous_segment;
34916  open_polyline_pt->polyline_pt(p - 1)->initial_vertex_coordinate(
34917  initial_vertex_of_previous_segment);
34918 
34919  // Find the error between the initial vertex of the previous
34920  // line and the first vertex of the current line
34921  error = 0.0;
34922  for (unsigned i = 0; i < 2; i++)
34923  {
34924  const double dist = initial_vertex_of_previous_segment[i] -
34925  (*vector_vertex_node.begin())[i];
34926  error += dist * dist;
34927  }
34928  error = sqrt(error);
34929 
34930  // If the error is bigger than the tolerance then
34931  // we probably need to reverse, but better check
34932  if (error >
34933  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34934  {
34935  // Find the error between the final vertex of the previous
34936  // line and the first vertex of the current line
34937  error = 0.0;
34938  for (unsigned i = 0; i < 2; i++)
34939  {
34940  const double dist = initial_vertex_of_previous_segment[i] -
34941  (*--vector_vertex_node.end())[i];
34942  error += dist * dist;
34943  }
34944  error = sqrt(error);
34945 
34946  if (error >
34947  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34948  {
34949  std::ostringstream error_stream;
34950  error_stream
34951  << "The distance between the first node of the current\n"
34952  << "line segment (boundary " << bound
34953  << ") and either end of the previous line segment\n"
34954  << "(boundary " << prev_seg_boundary_id
34955  << ") is bigger than "
34956  << "the desired tolerance "
34957  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34958  << ".\n"
34959  << "This suggests that the polylines defining the open "
34960  << "curve\n"
34961  << "representation are not properly ordered.\n"
34962  << "Fail on last vertex of polyline: ("
34963  << prev_seg_boundary_id
34964  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34965  << "This should have failed when first trying to "
34966  "construct\n"
34967  << "the open curve.\n";
34968  throw OomphLibError(error_stream.str(),
34969  OOMPH_CURRENT_FUNCTION,
34970  OOMPH_EXCEPTION_LOCATION);
34971  }
34972  else // We have to reverse both
34973  {
34974  // First reverse the previous polyline
34975  open_polyline_pt->polyline_pt(p - 1)->reverse();
34976  // Then reverse the current polyline
34977  std::reverse(vector_vertex_node.begin(),
34978  vector_vertex_node.end());
34979  }
34980  }
34981  else
34982  {
34983  // Reverse the previous polyline only
34984  open_polyline_pt->polyline_pt(p - 1)->reverse();
34985  }
34986  } // if (p == 1)
34987  else
34988  {
34989  std::ostringstream error_stream;
34990  error_stream
34991  << "The distance between the first node of the current\n"
34992  << "line segment (boundary " << bound
34993  << ") and either end of "
34994  << "the previous line segment\n"
34995  << "(boundary " << prev_seg_boundary_id
34996  << ") is bigger than the "
34997  << "desired tolerance "
34998  << ToleranceForVertexMismatchInPolygons::Tolerable_error
34999  << ".\n"
35000  << "This suggests that the polylines defining the polygonal\n"
35001  << "representation are not properly ordered.\n"
35002  << "Fail on last vertex of polyline: ("
35003  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
35004  << bound << ").\n"
35005  << "This should have failed when first trying to construct "
35006  "the\n"
35007  << "polygon.\n";
35008  throw OomphLibError(error_stream.str(),
35009  OOMPH_CURRENT_FUNCTION,
35010  OOMPH_EXCEPTION_LOCATION);
35011  }
35012  }
35013  else
35014  {
35015  // Reverse the current vector to line up with the previous one
35016  std::reverse(vector_vertex_node.begin(),
35017  vector_vertex_node.end());
35018  }
35019  }
35020 
35021  } // if p > 0
35022 
35023  } // is mesh not distributed?
35024 
35025  if (!check_only)
35026  {
35027  // Now update the polyline according to the new vertices The new
35028  // one representation
35029  TriangleMeshPolyLine* tmp_polyline =
35030  new TriangleMeshPolyLine(vector_vertex_node, bound);
35031 
35032  // Create a temporal "curve section" version of the recently
35033  // created polyline
35034  TriangleMeshCurveSection* tmp_curve_section = tmp_polyline;
35035 
35036  // Copy the unrefinement and refinement information
35037  tmp_polyline->set_unrefinement_tolerance(unrefinement_tolerance);
35038  tmp_polyline->set_refinement_tolerance(refinement_tolerance);
35039 
35040  // Establish the maximum length constraint
35041  tmp_polyline->set_maximum_length(maximum_length);
35042 
35043  // Pass the connection information from the old polyline to the
35044  // new one
35045  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
35046  tmp_curve_section);
35047 
35048  std::set<TriangleMeshCurveSection*>::iterator it =
35049  this->Free_curve_section_pt.find(
35050  open_polyline_pt->curve_section_pt(p));
35051 
35052  bool delete_it_on_destructor = false;
35053 
35054  if (it != this->Free_curve_section_pt.end())
35055  {
35056  // Free previous representation only if you created
35057  this->Free_curve_section_pt.erase(it);
35058  delete open_polyline_pt->curve_section_pt(p);
35059  delete_it_on_destructor = true;
35060  }
35061 
35062  // *****************************************************************
35063  // Copying the new representation
35064  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
35065 
35066  // Update the Boundary <--> PolyLine map
35067  this->Boundary_curve_section_pt[bound] =
35068  open_polyline_pt->curve_section_pt(p);
35069 
35070  if (delete_it_on_destructor)
35071  {
35072  this->Free_curve_section_pt.insert(
35073  open_polyline_pt->curve_section_pt(p));
35074  }
35075 
35076  } // if(!check_only)
35077 
35078  } // n_polylines
35079 
35080  // Cleanup (but only the elements -- the nodes still exist in
35081  // the bulk mesh!
35082  for (unsigned p = 0; p < n_polyline; p++)
35083  {
35084  face_mesh_pt[p]->flush_node_storage();
35085  delete face_mesh_pt[p];
35086  }
35087 
35088  if (check_only)
35089  {
35090  // if we end up all the way down here, no update of the internal
35091  // boundaries is necessary (in case we only check)
35092  return false;
35093  }
35094  else
35095  {
35096  // if we not only check, but actually perform the update and end
35097  // up all the way down here then we indicate whether an update was
35098  // performed or not
35099  return (unrefinement_was_performed || refinement_was_performed ||
35100  max_length_applied);
35101  }
35102  }
35103 
35104  //=========================================================================
35105  /// Helper function that performs the unrefinement process
35106  /// on the specified boundary by using the provided vertices
35107  /// representation. Optional boolean is used to run it as test only (if
35108  /// true is specified as input) in which case vertex coordinates aren't
35109  /// actually modified. Returned boolean indicates if polyline was (or
35110  /// would have been -- if called with check_only=false) changed.
35111  //=========================================================================
35112  template<class ELEMENT>
35114  const unsigned& b,
35115  const unsigned& c,
35116  Vector<Vector<double>>& vector_bnd_vertices,
35117  double& unrefinement_tolerance,
35118  const bool& check_only)
35119  {
35120  // Store the vertices not allowed for deletion
35121  std::set<Vector<double>> no_delete_vertex;
35122 
35123  // Does the boundary receives connections?
35124  const bool boundary_receive_connections =
35125  this->boundary_connections(b, c, no_delete_vertex);
35126 
35127  // Boolean that indicates whether an actual update of the vertex
35128  // coordinates was performed or not
35129  bool unrefinement_was_performed = false;
35130 
35131  unsigned n_vertex = vector_bnd_vertices.size();
35132 
35133  // Initialise counter that indicates at which vertex we're currently
35134  // considering for deletion
35135  unsigned counter = 1;
35136 
35137  // Loop over the nodes; start with the second one and increment by two
35138  // this way a "pack" of three nodes will be considered for calculation:
35139  // the middle-node (which is to be deleted or not) and the adjacent
35140  // nodes
35141  for (unsigned i = 1; i <= n_vertex - 2; i += 2)
35142  {
35143  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35144  double a_x = vector_bnd_vertices[i - 1][1];
35145  double a_y = vector_bnd_vertices[i - 1][2];
35146  double b_x = vector_bnd_vertices[i][1];
35147  double b_y = vector_bnd_vertices[i][2];
35148  double c_x = vector_bnd_vertices[i + 1][1];
35149  double c_y = vector_bnd_vertices[i + 1][2];
35150 
35151  double a = b_x - a_x;
35152  double b = b_y - a_y;
35153  double c = c_x - a_x;
35154  double d = c_y - a_y;
35155 
35156  double e = a * (a_x + b_x) + b * (a_y + b_y);
35157  double f = c * (a_x + c_x) + d * (a_y + c_y);
35158 
35159  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
35160 
35161  bool do_it = false;
35162  if (std::fabs(g) < 1.0e-14)
35163  {
35164  do_it = true;
35165  if (check_only)
35166  {
35167  return true;
35168  }
35169  }
35170  else
35171  {
35172  double p_x = (d * e - b * f) / g;
35173  double p_y = (a * f - c * e) / g;
35174 
35175  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
35176 
35177  double rhalfca_x = 0.5 * (a_x - c_x);
35178  double rhalfca_y = 0.5 * (a_y - c_y);
35179 
35180  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
35181 
35182  double sticky_out_bit = r - sqrt(std::fabs((r * r) - halfca_squared));
35183 
35184  // If sticky out bit divided by distance between end nodes
35185  // is less than tolerance the boundary is so flat that we
35186  // can safely kill the node
35187  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
35188  unrefinement_tolerance)
35189  {
35190  do_it = true;
35191  if (check_only)
35192  {
35193  return true;
35194  }
35195  }
35196  }
35197 
35198  // If the vertex was proposed for deletion check that it is
35199  // allowed for being deleted
35200  if (do_it && boundary_receive_connections)
35201  {
35202  // Is the vertex one of the non deletable vertices
35203  for (std::set<Vector<double>>::iterator it = no_delete_vertex.begin();
35204  it != no_delete_vertex.end();
35205  it++)
35206  {
35207  // Compute the distance between the proposed node to delete
35208  // and the ones that should not be deleted
35209  const double x = (*it)[0];
35210  const double y = (*it)[1];
35211  double error = (b_x - x) * (b_x - x) + (b_y - y) * (b_y - y);
35212  error = sqrt(error);
35213 
35214  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35215  {
35216  // Do not delete the vertex
35217  do_it = false;
35218  break;
35219  }
35220  }
35221 
35222  } // if (do_it && boundary_receive_connections)
35223 
35224  // Remove node?
35225  if (do_it)
35226  {
35227  vector_bnd_vertices[i].resize(0);
35228  }
35229 
35230  // Increase the counter, that indicates the number of the
35231  // next middle node
35232  counter += 2;
35233  }
35234 
35235  // coming out of here the value of counter is the index of the
35236  // last node on the polyline counter=n_vertex-1 (in case of an
35237  // even number of nodes) or counter has the value of the number
35238  // of nodes on the polyline counter=n_vertex (in case of an odd
35239  // number of nodes
35240 
35241  // Special treatment for the end of the polyline:
35242  // If the number of nodes is even, then the previous loop stopped
35243  // at the last but second node, i.e. the current value of counter
35244  // is the index of the last node. If that's the case, the last but
35245  // one node needs to be treated separately
35246  if ((counter) == (n_vertex - 1))
35247  {
35248  // Set the last but one node as middle node
35249  unsigned i = vector_bnd_vertices.size() - 2;
35250 
35251  // Index of the current! last but second node (considering any
35252  // previous deletion)
35253  unsigned n = 0;
35254 
35255  if (vector_bnd_vertices[counter - 2].size() != 0)
35256  {
35257  // if the initial last but second node does still exist then
35258  // this one is obviously also the current last but second one
35259  n = counter - 2;
35260  }
35261  else
35262  {
35263  // if the initial last but second node was deleted then the
35264  // initial last but third node is the current last but second
35265  // node
35266  n = counter - 3;
35267  }
35268 
35269  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
35270  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
35271  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
35272 
35273  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35274  double a_x = vector_bnd_vertices[n][1];
35275  double a_y = vector_bnd_vertices[n][2];
35276  double b_x = vector_bnd_vertices[i][1];
35277  double b_y = vector_bnd_vertices[i][2];
35278  double c_x = vector_bnd_vertices[i + 1][1];
35279  double c_y = vector_bnd_vertices[i + 1][2];
35280 
35281  double a = b_x - a_x;
35282  double b = b_y - a_y;
35283  double c = c_x - a_x;
35284  double d = c_y - a_y;
35285 
35286  double e = a * (a_x + b_x) + b * (a_y + b_y);
35287  double f = c * (a_x + c_x) + d * (a_y + c_y);
35288 
35289  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
35290 
35291  bool do_it = false;
35292  if (std::fabs(g) < 1.0e-14)
35293  {
35294  do_it = true;
35295  if (check_only)
35296  {
35297  return true;
35298  }
35299  }
35300  else
35301  {
35302  double p_x = (d * e - b * f) / g;
35303  double p_y = (a * f - c * e) / g;
35304 
35305  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
35306 
35307  double rhalfca_x = 0.5 * (a_x - c_x);
35308  double rhalfca_y = 0.5 * (a_y - c_y);
35309 
35310  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
35311 
35312  double sticky_out_bit = r - sqrt(std::fabs((r * r) - halfca_squared));
35313 
35314  // If sticky out bit divided by distance between end nodes
35315  // is less than tolerance the boundary is so flat that we
35316  // can safely kill the node
35317  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
35318  unrefinement_tolerance)
35319  {
35320  do_it = true;
35321  if (check_only)
35322  {
35323  return true;
35324  }
35325  }
35326  }
35327 
35328  // If the vertex was proposed for deletion check that it is
35329  // allowed for being deleted
35330  if (do_it && boundary_receive_connections)
35331  {
35332  // Is the vertex one of the non deletable vertices
35333  for (std::set<Vector<double>>::iterator it = no_delete_vertex.begin();
35334  it != no_delete_vertex.end();
35335  it++)
35336  {
35337  // Compute the distance between the proposed node to delete
35338  // and the ones that should not be deleted
35339  const double x = (*it)[0];
35340  const double y = (*it)[1];
35341  double error = (b_x - x) * (b_x - x) + (b_y - y) * (b_y - y);
35342  error = sqrt(error);
35343 
35344  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35345  {
35346  // Do not delete the vertex
35347  do_it = false;
35348  break;
35349  }
35350  }
35351 
35352  } // if (do_it && boundary_receive_connections)
35353 
35354  // Remove node?
35355  if (do_it)
35356  {
35357  vector_bnd_vertices[i].resize(0);
35358  }
35359  }
35360 
35361  // Create another vector, which will only contain entries of
35362  // nodes that still exist
35363  Vector<Vector<double>> compact_vector;
35364  compact_vector.reserve(n_vertex);
35365  for (unsigned i = 0; i < n_vertex; i++)
35366  {
35367  // If the entry was not deleted include it in the new vector
35368  if (vector_bnd_vertices[i].size() != 0)
35369  {
35370  compact_vector.push_back(vector_bnd_vertices[i]);
35371  }
35372  }
35373 
35374  /// Get the size of the vector that now includes all remaining nodes
35375  n_vertex = compact_vector.size();
35376 
35377  // If the size of the vector containing the remaining nodes is
35378  // different from the size of the vector before the unrefinement
35379  // routine (with the original nodes)
35380  // then the polyline was obviously updated
35381  if (n_vertex != vector_bnd_vertices.size())
35382  {
35383  unrefinement_was_performed = true;
35384  }
35385 
35386  /// Copy back
35387  vector_bnd_vertices.resize(n_vertex);
35388  for (unsigned i = 0; i < n_vertex; i++)
35389  {
35390  vector_bnd_vertices[i].resize(3);
35391  vector_bnd_vertices[i][0] = compact_vector[i][0];
35392  vector_bnd_vertices[i][1] = compact_vector[i][1];
35393  vector_bnd_vertices[i][2] = compact_vector[i][2];
35394  }
35395 
35396  return unrefinement_was_performed;
35397  }
35398 
35399  //=========================================================================
35400  /// Helper function that performs the refinement process
35401  /// on the specified boundary by using the provided vertices
35402  /// representation. Optional boolean is used to run it as test only (if
35403  /// true is specified as input) in which case vertex coordinates aren't
35404  /// actually modified. Returned boolean indicates if polyline was (or
35405  /// would have been -- if called with check_only=false) changed.
35406  //=========================================================================
35407  template<class ELEMENT>
35409  Mesh* face_mesh_pt,
35410  Vector<Vector<double>>& vector_bnd_vertices,
35411  double& refinement_tolerance,
35412  const bool& check_only)
35413  {
35414  // Boolean that indicates whether an actual update of the vertex
35415  // coordinates was performed or not
35416  bool refinement_was_performed = false;
35417 
35418  // Create a geometric object from the mesh to represent
35419  // the curvilinear boundary
35420  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
35421 
35422  // Get the total number of current vertices
35423  unsigned n_vertex = vector_bnd_vertices.size();
35424 
35425  // Create a new (temporary) vector for the nodes, so
35426  // that new nodes can be stored
35427  Vector<Vector<double>> extended_vector;
35428 
35429  // Reserve memory space for twice the number of already
35430  // existing nodes (worst case)
35431  extended_vector.reserve(2 * n_vertex);
35432 
35433  // Loop over the nodes until the last but one node
35434  for (unsigned inod = 0; inod < n_vertex - 1; inod++)
35435  {
35436  // Get local coordinate of "left" node
35437  double zeta_left = vector_bnd_vertices[inod][0];
35438 
35439  // Get position vector of "left" node
35440  Vector<double> R_left(2);
35441  for (unsigned i = 0; i < 2; i++)
35442  {
35443  R_left[i] = vector_bnd_vertices[inod][i + 1];
35444  }
35445 
35446  // Get local coordinate of "right" node
35447  double zeta_right = vector_bnd_vertices[inod + 1][0];
35448 
35449  // Get position vector of "right" node
35450  Vector<double> R_right(2);
35451  for (unsigned i = 0; i < 2; i++)
35452  {
35453  R_right[i] = vector_bnd_vertices[inod + 1][i + 1];
35454  }
35455 
35456  // Get the boundary coordinate of the midpoint
35457  Vector<double> zeta_mid(1);
35458  zeta_mid[0] = 0.5 * (zeta_left + zeta_right);
35459 
35460  // Get the position vector of the midpoint on the
35461  // curvilinear boundary
35462  Vector<double> R_mid(2);
35463  mesh_geom_obj_pt->position(zeta_mid, R_mid);
35464 
35465  // Get the position vector of the midpoint on the straight
35466  // line connecting "left" and "right" node
35467  Vector<double> R_mid_polygon(2);
35468  for (unsigned i = 0; i < 2; i++)
35469  {
35470  R_mid_polygon[i] = 0.5 * (R_right[i] + R_left[i]);
35471  }
35472 
35473  // Calculate the distance between the midpoint on the curvilinear
35474  // boundary and the midpoint on the straight line
35475  double distance =
35476  sqrt((R_mid[0] - R_mid_polygon[0]) * (R_mid[0] - R_mid_polygon[0]) +
35477  (R_mid[1] - R_mid_polygon[1]) * (R_mid[1] - R_mid_polygon[1]));
35478 
35479  // Calculating the length of the straight line
35480  double length = sqrt((R_right[0] - R_left[0]) * (R_right[0] - R_left[0]) +
35481  (R_right[1] - R_left[1]) * (R_right[1] - R_left[1]));
35482 
35483  // If the ratio of distance between the midpoints to the length
35484  // of the straight line is larger than the tolerance
35485  // specified for the criterion when points can be deleted,
35486  // create a new node and add it to the (temporary) vector
35487  if ((distance / length) > refinement_tolerance)
35488  {
35489  if (check_only)
35490  {
35491  // Delete the allocated memory for the geometric object
35492  // that represents the curvilinear boundary
35493  delete mesh_geom_obj_pt;
35494  return true;
35495  }
35496 
35497  Vector<double> new_node(3);
35498  new_node[0] = zeta_mid[0];
35499  new_node[1] = R_mid[0];
35500  new_node[2] = R_mid[1];
35501 
35502  // Include the "left" node in the new "temporary" vector
35503  extended_vector.push_back(vector_bnd_vertices[inod]);
35504 
35505  // Include the new node as well
35506  extended_vector.push_back(new_node);
35507  }
35508  else
35509  {
35510  // Include the "left" node in the new "temporary" vector
35511  // and move on to the next node
35512  extended_vector.push_back(vector_bnd_vertices[inod]);
35513  }
35514  } // end of loop over nodes
35515 
35516  // Add the last node to the vector
35517  extended_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
35518 
35519  /// Get the size of the vector that now includes all added nodes
35520  n_vertex = extended_vector.size();
35521 
35522  // If the size of the vector including the added nodes is
35523  // different from the size of the vector before the refinement
35524  // routine then the polyline was obviously updated
35525  if (n_vertex != vector_bnd_vertices.size())
35526  {
35527  refinement_was_performed = true;
35528  }
35529 
35530  // Copy across
35531  vector_bnd_vertices.resize(n_vertex);
35532  for (unsigned i = 0; i < n_vertex; i++)
35533  {
35534  vector_bnd_vertices[i].resize(3);
35535  vector_bnd_vertices[i][0] = extended_vector[i][0];
35536  vector_bnd_vertices[i][1] = extended_vector[i][1];
35537  vector_bnd_vertices[i][2] = extended_vector[i][2];
35538  }
35539 
35540  // Delete the allocated memory for the geometric object
35541  // that represents the curvilinear boundary
35542  delete mesh_geom_obj_pt;
35543 
35544  return refinement_was_performed;
35545  }
35546 
35547  //=========================================================================
35548  // Helper function that applies the maximum length constraint
35549  // when it was specified. This will increase the number of points in
35550  // the current curve section in case that any segment on it does not
35551  // fulfils the requirement
35552  //=========================================================================
35553  template<class ELEMENT>
35555  Mesh* face_mesh_pt,
35556  Vector<Vector<double>>& vector_bnd_vertices,
35557  double& max_length_constraint)
35558  {
35559  // Boolean that indicates whether an actual update of the vertex
35560  // coordinates was performed or not
35561  bool max_length_applied = false;
35562 
35563  // Create a geometric object from the mesh to represent
35564  // the curvilinear boundary
35565  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
35566 
35567  // Get the total number of current vertices
35568  unsigned n_vertex = vector_bnd_vertices.size();
35569 
35570  // Create a new (temporary) vector for the nodes, so
35571  // that new nodes can be stored
35572  Vector<Vector<double>> extended_vector;
35573 
35574  // Loop over the nodes until the last but one node
35575  for (unsigned inod = 0; inod < n_vertex - 1; inod++)
35576  {
35577  // Get local coordinate of "left" node
35578  double zeta_left = vector_bnd_vertices[inod][0];
35579 
35580  // Get position vector of "left" node
35581  Vector<double> R_left(2);
35582  for (unsigned i = 0; i < 2; i++)
35583  {
35584  R_left[i] = vector_bnd_vertices[inod][i + 1];
35585  }
35586 
35587  // Get local coordinate of "right" node
35588  double zeta_right = vector_bnd_vertices[inod + 1][0];
35589 
35590  // Get position vector of "right" node
35591  Vector<double> R_right(2);
35592  for (unsigned i = 0; i < 2; i++)
35593  {
35594  R_right[i] = vector_bnd_vertices[inod + 1][i + 1];
35595  }
35596 
35597  // Include the "left" node in the new "temporary" vector
35598  extended_vector.push_back(vector_bnd_vertices[inod]);
35599 
35600  // Check whether the current distance between the left and right node
35601  // is longer than the specified constraint or not
35602  double length = std::fabs(zeta_right - zeta_left);
35603 
35604  // Do we need to introduce new nodes?
35605  if (length > max_length_constraint)
35606  {
35607  double n_pts = length / max_length_constraint;
35608  // We only want the integer part
35609  unsigned n_points = static_cast<unsigned>(n_pts);
35610  double zeta_increment =
35611  (zeta_right - zeta_left) / ((double)n_points + 1);
35612 
35613  Vector<double> zeta(1);
35614  // Create the n_points+1 points inside the segment
35615  for (unsigned s = 1; s < n_points + 1; s++)
35616  {
35617  // Get the coordinates
35618  zeta[0] = zeta_left + zeta_increment * double(s);
35619  Vector<double> vertex(2);
35620  mesh_geom_obj_pt->position(zeta, vertex);
35621 
35622  // Create the new node
35623  Vector<double> new_node(3);
35624  new_node[0] = zeta[0];
35625  new_node[1] = vertex[0];
35626  new_node[2] = vertex[1];
35627 
35628  // Include the new node
35629  extended_vector.push_back(new_node);
35630  }
35631  }
35632  }
35633 
35634  // Add the last node to the vector
35635  extended_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
35636 
35637  /// Get the size of the vector that now includes all added nodes
35638  n_vertex = extended_vector.size();
35639 
35640  // If the size of the vector including the added nodes is
35641  // different from the size of the vector before applying the maximum length
35642  // constraint then the polyline was obviously updated
35643  if (n_vertex != vector_bnd_vertices.size())
35644  {
35645  max_length_applied = true;
35646  }
35647 
35648  // Copy across
35649  vector_bnd_vertices.resize(n_vertex);
35650  for (unsigned i = 0; i < n_vertex; i++)
35651  {
35652  vector_bnd_vertices[i].resize(3);
35653  vector_bnd_vertices[i][0] = extended_vector[i][0];
35654  vector_bnd_vertices[i][1] = extended_vector[i][1];
35655  vector_bnd_vertices[i][2] = extended_vector[i][2];
35656  }
35657 
35658  // Delete the allocated memory for the geometric object
35659  // that represents the curvilinear boundary
35660  delete mesh_geom_obj_pt;
35661 
35662  return max_length_applied;
35663  }
35664 
35665  //=========================================================================
35666  /// Helper function
35667  /// Creates an unsorted face mesh representation from the specified
35668  /// boundary id. It means that the elements are not sorted along the
35669  /// boundary
35670  //=========================================================================
35671  template<class ELEMENT>
35673  create_unsorted_face_mesh_representation(const unsigned& boundary_id,
35674  Mesh* face_mesh_pt)
35675  {
35676  // Create a face mesh adjacent to specified boundary.
35677  // The face mesh consists of FaceElements that may also be
35678  // interpreted as GeomObjects
35679 
35680  // Build the face mesh
35681  this->template build_face_mesh<ELEMENT, FaceElementAsGeomObject>(
35682  boundary_id, face_mesh_pt);
35683 
35684  // Find the total number of added elements
35685  unsigned n_element = face_mesh_pt->nelement();
35686  // Loop over the elements
35687  for (unsigned e = 0; e < n_element; e++)
35688  {
35689  // Cast the element pointer to the correct thing!
35690  FaceElementAsGeomObject<ELEMENT>* el_pt =
35691  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>(
35692  face_mesh_pt->element_pt(e));
35693 
35694  // Set bulk boundary number
35695  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35696  }
35697  }
35698 
35699  //=========================================================================
35700  /// Helper function
35701  /// Creates a sorted face mesh representation of the specified PolyLine
35702  /// It means that the elements are sorted along the boundary
35703  //=========================================================================
35704  template<class ELEMENT>
35706  const unsigned& boundary_id,
35707  Mesh* face_mesh_pt,
35708  std::map<FiniteElement*, bool>& is_inverted,
35709  bool& inverted_face_mesh)
35710  {
35711  Mesh* tmp_unsorted_face_mesh_pt = new Mesh();
35712 
35713  // First step we get the unsorted version of the face mesh
35714  create_unsorted_face_mesh_representation(boundary_id,
35715  tmp_unsorted_face_mesh_pt);
35716 
35717  // Once with the unsorted version of the face mesh
35718  // only left to sort it out!!!
35719 
35720  // Put all face elements in order
35721  //-------------------------------
35722 
35723  // Put first element into ordered list
35724  // Temporal list for sorting the elements
35725  std::list<FiniteElement*> sorted_el_pt;
35726  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35727  sorted_el_pt.push_back(el_pt);
35728 
35729  // Number of nodes
35730  unsigned nnod = el_pt->nnode();
35731 
35732  // Count elements that have been done
35733  unsigned count_done = 0;
35734 
35735  // How many face elements are there?
35736  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35737 
35738  // Keep track of who's done
35739  std::map<FiniteElement*, bool> done_el;
35740 
35741  is_inverted.clear();
35742 
35743  // Fit in the other elements in at most nel^2 loops
35744  for (unsigned ee = 1; ee < n_face_element; ee++)
35745  {
35746  // Loop over all elements to check if they fit to the right
35747  // or the left of the current one
35748  for (unsigned e = 1; e < n_face_element; e++)
35749  {
35750  // Candidate element
35751  el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35752 
35753  // Is it done yet?
35754  if (!done_el[el_pt])
35755  {
35756  // Left and rightmost elements
35757  FiniteElement* first_el_pt = (*sorted_el_pt.begin());
35758  std::list<FiniteElement*>::iterator it = sorted_el_pt.end();
35759  it--;
35760  FiniteElement* last_el_pt = *it;
35761 
35762  // Left and rightmost nodes
35763  Node* left_node_pt = first_el_pt->node_pt(0);
35764  if (is_inverted[first_el_pt])
35765  {
35766  left_node_pt = first_el_pt->node_pt(nnod - 1);
35767  }
35768  Node* right_node_pt = last_el_pt->node_pt(nnod - 1);
35769  if (is_inverted[last_el_pt])
35770  {
35771  right_node_pt = last_el_pt->node_pt(0);
35772  }
35773 
35774  // New element fits at the left of first element and is not inverted
35775  if (left_node_pt == el_pt->node_pt(nnod - 1))
35776  {
35777  sorted_el_pt.push_front(el_pt);
35778  done_el[el_pt] = true;
35779  count_done++;
35780  is_inverted[el_pt] = false;
35781  }
35782  // New element fits at the left of first element and is inverted
35783 
35784  else if (left_node_pt == el_pt->node_pt(0))
35785  {
35786  sorted_el_pt.push_front(el_pt);
35787  done_el[el_pt] = true;
35788  count_done++;
35789  is_inverted[el_pt] = true;
35790  }
35791  // New element fits on the right of last element and is not inverted
35792 
35793  else if (right_node_pt == el_pt->node_pt(0))
35794  {
35795  sorted_el_pt.push_back(el_pt);
35796  done_el[el_pt] = true;
35797  count_done++;
35798  is_inverted[el_pt] = false;
35799  }
35800  // New element fits on the right of last element and is inverted
35801 
35802  else if (right_node_pt == el_pt->node_pt(nnod - 1))
35803  {
35804  sorted_el_pt.push_back(el_pt);
35805  done_el[el_pt] = true;
35806  count_done++;
35807  is_inverted[el_pt] = true;
35808  }
35809 
35810  if (done_el[el_pt])
35811  {
35812  break;
35813  }
35814  }
35815  }
35816  }
35817 
35818  // Are we done?
35819  if (count_done != (n_face_element - 1))
35820  {
35821  std::ostringstream error_message;
35822  error_message << "When ordering FaceElements on "
35823  << "boundary " << boundary_id << " only managed to order \n"
35824  << count_done << " of " << n_face_element
35825  << " face elements.\n"
35826  << std::endl;
35827  throw OomphLibError(
35828  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
35829  }
35830 
35831  // Now make a mesh that contains the FaceElements in order
35832  // Remember that we currently have a list, not a mesh of sorted elements
35833 
35834  // Fill it
35835  for (std::list<FiniteElement*>::iterator it = sorted_el_pt.begin();
35836  it != sorted_el_pt.end();
35837  it++)
35838  {
35839  // Get element
35840  FiniteElement* el_pt = *it;
35841 
35842  // add this face element to the order original mesh
35843  face_mesh_pt->add_element_pt(el_pt);
35844  }
35845 
35846  // Verify if face mesh representation is not inverted according to the
35847  // polyline specified by the user, it means that the initial and the
35848  // final vertex does really correspond to the first and last vertex
35849  // respectively, if not, state that the face mesh representation is
35850  // inverted
35851 
35852  // Get the associated polyline representation to the boundary
35853  TriangleMeshPolyLine* bnd_polyline =
35854  this->Boundary_curve_section_pt[boundary_id];
35855 
35856  // Get the really first vertex
35857  Vector<double> first_vertex = bnd_polyline->vertex_coordinate(0);
35858 
35859  // Now get the first node based on the face mesh representation
35860  // First get access to the first element
35861  FiniteElement* first_el_pt = face_mesh_pt->finite_element_pt(0);
35862 
35863  // Now get access to the first node
35864  unsigned n_node = first_el_pt->nnode();
35865  // Get the very first node (taking into account if it is
35866  // inverted or not!!)
35867  Node* first_node_pt = first_el_pt->node_pt(0);
35868  if (is_inverted[first_el_pt])
35869  {
35870  first_node_pt = first_el_pt->node_pt(n_node - 1);
35871  }
35872 
35873  double error = (first_node_pt->x(0) - first_vertex[0]) *
35874  (first_node_pt->x(0) - first_vertex[0]) +
35875  (first_node_pt->x(1) - first_vertex[1]) *
35876  (first_node_pt->x(1) - first_vertex[1]);
35877 
35878  error = sqrt(error);
35879 
35880  if (error < ToleranceForVertexMismatchInPolygons::Tolerable_error)
35881  {
35882  inverted_face_mesh = false;
35883  }
35884  else
35885  {
35886  inverted_face_mesh = true;
35887  }
35888  }
35889 
35890  //=========================================================================
35891  /// Helper function to construct face mesh representation of all polylines,
35892  /// possibly with segments re-distributed between polylines
35893  /// to maintain an approximately even sub-division of the polygon
35894  //=========================================================================
35895  template<class ELEMENT>
35897  TriangleMeshPolygon* polygon_pt, Vector<Mesh*>& face_mesh_pt)
35898  {
35899  // Number of polylines
35900  unsigned n_polyline = polygon_pt->npolyline();
35901  face_mesh_pt.resize(n_polyline);
35902 
35903  // Are we eligible for re-distributing polyline segments between
35904  // polylines? We're not if any of the boundaries are associated
35905  // with a GeomObject because we're then tied to the start and
35906  // end coordinates along it.
35907  bool eligible_for_segment_redistribution = true;
35908 
35909  // Loop over constituent polylines
35910  for (unsigned p = 0; p < n_polyline; p++)
35911  {
35912  // Get the boundary id of the polyline
35913  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
35914 
35915  // If the boundary has a geometric object representation then
35916  // we can't redistribute
35917  GeomObject* const geom_object_pt = this->boundary_geom_object_pt(bound);
35918  if (geom_object_pt != 0)
35919  {
35920  eligible_for_segment_redistribution = false;
35921  }
35922 
35923  face_mesh_pt[p] = new Mesh();
35924  create_unsorted_face_mesh_representation(bound, face_mesh_pt[p]);
35925  }
35926 
35927  if (!polygon_pt->is_redistribution_of_segments_between_polylines_enabled())
35928  {
35929  return;
35930  }
35931 
35932  // If there is more than one region we have to think... Die for now.
35933  if (this->nregion() > 1)
35934  {
35935  std::ostringstream warn_message;
35936  warn_message
35937  << "Can't currently re-distribute segments between polylines if there\n"
35938  << "are multiple regions; returning..." << std::endl;
35939  OomphLibWarning(warn_message.str(),
35940  "RefineableTriangleMesh::get_face_mesh_representation()",
35941  OOMPH_EXCEPTION_LOCATION);
35942  return;
35943  }
35944 
35945  // Redistribution overruled
35946  if (!eligible_for_segment_redistribution)
35947  {
35948  std::ostringstream warn_message;
35949  warn_message
35950  << "Over-ruling re-distribution of segments between polylines\n"
35951  << "because at least one boundary is associated with a GeomObject."
35952  << "Returning..." << std::endl;
35953  OomphLibWarning(warn_message.str(),
35954  "RefineableTriangleMesh::get_face_mesh_representation()",
35955  OOMPH_EXCEPTION_LOCATION);
35956  return;
35957  }
35958 
35959  // Create a vector for ordered face mesh
35960  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35961 
35962  // Storage for the total arclength of polygon
35963  double s_total = 0.0;
35964 
35965  // Storage for first and last nodes on polylines so we can figure
35966  // out if they are inverted relative to each other
35967  Vector<Node*> first_polyline_node_pt(n_polyline);
35968  Vector<Node*> last_polyline_node_pt(n_polyline);
35969  std::vector<bool> is_reversed(n_polyline, false);
35970 
35971  // Loop over constituent polylines
35972  for (unsigned p = 0; p < n_polyline; p++)
35973  {
35974  // Put all face elements in order
35975  //-------------------------------
35976 
35977  // Put first element into ordered list
35978  std::list<FiniteElement*> ordered_el_pt;
35979  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(0);
35980  ordered_el_pt.push_back(el_pt);
35981 
35982  // Number of nodes
35983  unsigned nnod = el_pt->nnode();
35984 
35985  // Default for first and last node on polyline
35986  first_polyline_node_pt[p] = el_pt->node_pt(0);
35987  last_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
35988 
35989  // Count elements that have been done
35990  unsigned count_done = 0;
35991 
35992  // How many face elements are there?
35993  unsigned n_face_element = face_mesh_pt[p]->nelement();
35994 
35995  // Get the boundary id of the polyline
35996  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
35997 
35998  // Keep track of who's done
35999  std::map<FiniteElement*, bool> done_el;
36000 
36001  // Keep track of which element is inverted
36002  std::map<FiniteElement*, bool> is_inverted;
36003 
36004  // Fit in the other elements in at most nel^2 loops
36005  for (unsigned ee = 1; ee < n_face_element; ee++)
36006  {
36007  // Loop over all elements to check if they fit to the right
36008  // or the left of the current one
36009  for (unsigned e = 1; e < n_face_element; e++)
36010  {
36011  // Candidate element
36012  el_pt = face_mesh_pt[p]->finite_element_pt(e);
36013 
36014  // Is it done yet?
36015  if (!done_el[el_pt])
36016  {
36017  // Left and rightmost elements
36018  FiniteElement* first_el_pt = (*ordered_el_pt.begin());
36019  std::list<FiniteElement*>::iterator it = ordered_el_pt.end();
36020  it--;
36021  FiniteElement* last_el_pt = *it;
36022 
36023  // Left and rightmost nodes
36024  Node* left_node_pt = first_el_pt->node_pt(0);
36025  if (is_inverted[first_el_pt])
36026  {
36027  left_node_pt = first_el_pt->node_pt(nnod - 1);
36028  }
36029  Node* right_node_pt = last_el_pt->node_pt(nnod - 1);
36030  if (is_inverted[last_el_pt])
36031  {
36032  right_node_pt = last_el_pt->node_pt(0);
36033  }
36034 
36035  // New element fits at the left of first element and is not inverted
36036  if (left_node_pt == el_pt->node_pt(nnod - 1))
36037  {
36038  ordered_el_pt.push_front(el_pt);
36039  done_el[el_pt] = true;
36040  count_done++;
36041  is_inverted[el_pt] = false;
36042  first_polyline_node_pt[p] = el_pt->node_pt(0);
36043  }
36044  // New element fits at the left of first element and is inverted
36045 
36046  else if (left_node_pt == el_pt->node_pt(0))
36047  {
36048  ordered_el_pt.push_front(el_pt);
36049  done_el[el_pt] = true;
36050  count_done++;
36051  is_inverted[el_pt] = true;
36052  first_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
36053  }
36054  // New element fits on the right of last element and is not inverted
36055 
36056  else if (right_node_pt == el_pt->node_pt(0))
36057  {
36058  ordered_el_pt.push_back(el_pt);
36059  done_el[el_pt] = true;
36060  count_done++;
36061  is_inverted[el_pt] = false;
36062  last_polyline_node_pt[p] = el_pt->node_pt(nnod - 1);
36063  }
36064  // New element fits on the right of last element and is inverted
36065 
36066  else if (right_node_pt == el_pt->node_pt(nnod - 1))
36067  {
36068  ordered_el_pt.push_back(el_pt);
36069  done_el[el_pt] = true;
36070  count_done++;
36071  is_inverted[el_pt] = true;
36072  last_polyline_node_pt[p] = el_pt->node_pt(0);
36073  }
36074 
36075  if (done_el[el_pt])
36076  {
36077  break;
36078  }
36079  }
36080  }
36081  }
36082 
36083  // Are we done?
36084  if (count_done != (n_face_element - 1))
36085  {
36086  std::ostringstream error_message;
36087  error_message << "When ordering FaceElements on "
36088  << "boundary " << bound << " only managed to order \n"
36089  << count_done << " of " << n_face_element
36090  << " face elements.\n"
36091  << std::endl;
36092  throw OomphLibError(error_message.str(),
36093  OOMPH_CURRENT_FUNCTION,
36094  OOMPH_EXCEPTION_LOCATION);
36095  }
36096 
36097  // Now make a mesh that contains the FaceElements in order
36098  ordered_face_mesh_pt[p] = new Mesh;
36099 
36100  // Fill it
36101  for (std::list<FiniteElement*>::iterator it = ordered_el_pt.begin();
36102  it != ordered_el_pt.end();
36103  it++)
36104  {
36105  // Get element
36106  FiniteElement* el_pt = *it;
36107 
36108  // add this face element to the order original mesh
36109  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
36110  }
36111 
36112  // Get the arclength along the polygon
36113  for (unsigned e = 0; e < n_face_element; ++e)
36114  {
36115  FiniteElement* el_pt = ordered_face_mesh_pt[p]->finite_element_pt(e);
36116  unsigned n_node = el_pt->nnode();
36117  double element_length_squared = 0.0;
36118  for (unsigned i = 0; i < 2; i++)
36119  {
36120  element_length_squared +=
36121  pow(el_pt->node_pt(n_node - 1)->x(i) - el_pt->node_pt(0)->x(i), 2);
36122  }
36123 
36124  // Determine element length
36125  double element_length = sqrt(element_length_squared);
36126 
36127  // Add this length to the total arclength
36128  s_total += element_length;
36129  }
36130 
36131  // Empty the original meshes
36132  face_mesh_pt[p]->flush_element_and_node_storage();
36133  }
36134 
36135  // Is first one reversed?
36136  if ((last_polyline_node_pt[0] == first_polyline_node_pt[1]) ||
36137  (last_polyline_node_pt[0] == last_polyline_node_pt[1]))
36138  {
36139  is_reversed[0] = false;
36140  }
36141  else if ((first_polyline_node_pt[0] == first_polyline_node_pt[1]) ||
36142  (first_polyline_node_pt[0] == last_polyline_node_pt[1]))
36143  {
36144  is_reversed[0] = true;
36145  }
36146 
36147  // Reorder the face meshes so that they are contiguous
36148  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
36149  std::vector<bool> mesh_done(n_polyline, false);
36150  Vector<unsigned> old_polyline_number(n_polyline);
36151 
36152  // Initial entry
36153  tmp_face_mesh_pt[0] = ordered_face_mesh_pt[0];
36154  unsigned current = 0;
36155  old_polyline_number[0] = 0;
36156  unsigned count_found = 0;
36157 
36158  // Fill in the next entries
36159  for (unsigned p = 1; p < n_polyline; p++)
36160  {
36161  Node* end_node_pt = last_polyline_node_pt[current];
36162  if (is_reversed[current])
36163  {
36164  end_node_pt = first_polyline_node_pt[current];
36165  }
36166 
36167  // Loop over all remaining face meshes to see which one fits
36168  for (unsigned pp = 1; pp < n_polyline; pp++)
36169  {
36170  if (!mesh_done[pp])
36171  {
36172  // Current one is not reversed, candidate is not reversed
36173  if ((!is_reversed[current]) &&
36174  (end_node_pt == first_polyline_node_pt[pp]))
36175  {
36176  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36177  mesh_done[pp] = true;
36178  is_reversed[pp] = false;
36179  old_polyline_number[p] = pp;
36180  current = pp;
36181  count_found++;
36182  break;
36183  }
36184  // Current one is not reversed, candidate is reversed
36185 
36186  else if ((!is_reversed[current]) &&
36187  (end_node_pt == last_polyline_node_pt[pp]))
36188  {
36189  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36190  mesh_done[pp] = true;
36191  is_reversed[pp] = true;
36192  old_polyline_number[p] = pp;
36193  current = pp;
36194  count_found++;
36195  break;
36196  }
36197  // Current one is reversed, candidate is not reversed
36198 
36199  else if ((is_reversed[current]) &&
36200  (end_node_pt == first_polyline_node_pt[pp]))
36201  {
36202  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36203  mesh_done[pp] = true;
36204  is_reversed[pp] = false;
36205  old_polyline_number[p] = pp;
36206  current = pp;
36207  count_found++;
36208  break;
36209  }
36210  // Current one is reversed, candidate is reversed
36211 
36212  else if ((is_reversed[current]) &&
36213  (end_node_pt == last_polyline_node_pt[pp]))
36214  {
36215  tmp_face_mesh_pt[p] = ordered_face_mesh_pt[pp];
36216  mesh_done[pp] = true;
36217  is_reversed[pp] = true;
36218  old_polyline_number[p] = pp;
36219  current = pp;
36220  count_found++;
36221  break;
36222  }
36223  }
36224  }
36225  }
36226 
36227 #ifdef PARANOID
36228  if (count_found != n_polyline - 1)
36229  {
36230  std::ostringstream error_message;
36231  error_message << "Only found " << count_found << " out of "
36232  << n_polyline - 1 << " polylines to be fitted in.\n";
36233  throw OomphLibError(
36234  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36235  }
36236 #endif
36237 
36238  // Now overwrite the re-ordered data
36239  for (unsigned i = 0; i < n_polyline; i++)
36240  {
36241  ordered_face_mesh_pt[i] = tmp_face_mesh_pt[i];
36242  }
36243 
36244  // Now do an approximate equidistribution of polylines
36245  //----------------------------------------------------
36246  double s = 0.0;
36247  unsigned new_face_id = 0;
36248 
36249  // Matrix map to indicate if node must not be removed from specified
36250  // boundary (!=0) or not (=0). Initialises itself to zero
36251  std::map<Node*, std::map<unsigned, unsigned>>
36252  node_must_not_be_removed_from_boundary_flag;
36253 
36254  // Loop over the old face mesh
36255  for (unsigned p = 0; p < n_polyline; p++)
36256  {
36257  // Loop over the face elements
36258  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36259  for (unsigned e = 0; e < n_face_element; e++)
36260  {
36261  unsigned el_number = e;
36262  if (is_reversed[p])
36263  {
36264  el_number = n_face_element - e - 1;
36265  }
36266 
36267  FiniteElement* el_pt =
36268  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36269  unsigned n_node = el_pt->nnode();
36270 
36271  // Determine element length
36272  double element_length_squared = 0.0;
36273  for (unsigned i = 0; i < 2; i++)
36274  {
36275  element_length_squared +=
36276  pow(el_pt->node_pt(n_node - 1)->x(i) - el_pt->node_pt(0)->x(i), 2);
36277  }
36278  double element_length = sqrt(element_length_squared);
36279 
36280  // Add this length to the total arclength
36281  s += element_length;
36282 
36283  // Check if the current 'arclength' is less than the
36284  // whole 'arclength' divided by the number of polylines
36285  if (s < s_total / double(n_polyline) + 1e-6)
36286  {
36287  // If so add this face element to the new face mesh
36288  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36289 
36290  unsigned bound_old =
36291  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36292 
36293  unsigned bound_new =
36294  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36295 
36296  // Loop over the nodes in the element
36297  for (unsigned i = 0; i < n_node; i++)
36298  {
36299  // Get the pointer to the node
36300  Node* nod_pt = el_pt->node_pt(i);
36301 
36302  // If the two boundary id's are different, the face element's nodes
36303  // have to be added to the new boundary
36304  if (bound_new != bound_old)
36305  {
36306  // Add it to the new boundary
36307  add_boundary_node(bound_new, nod_pt);
36308 
36309  // We are happy for this node to be removed from the
36310  // old boundary?
36311  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old] +=
36312  0;
36313  }
36314 
36315  // If the face element hasn't moved, its nodes MUST remain
36316  // on that boundary (incl. any nodes that ar shared by
36317  // FaceElements that have moved (see above)
36318 
36319  else
36320  {
36321  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old] +=
36322  1;
36323  }
36324  }
36325  }
36326 
36327  // If not, reset the current 'arclength' to zero,
36328  // increase the new face id by one and go one element
36329  // back by decreasing e by one to make sure the current
36330  // element gets added to the next face mesh
36331 
36332  else
36333  {
36334  if (new_face_id != n_polyline - 1)
36335  {
36336  s = 0.0;
36337  new_face_id++;
36338  --e;
36339  }
36340  else
36341  {
36342  s = 0.0;
36343  --e;
36344  }
36345  }
36346  }
36347  } // end of loop over all polylines -- they are now re-distributed
36348 
36349 
36350  // Loop over all nodes on the boundaries of the polygon to remove
36351  // nodes from boundaries they are no longer on
36352  unsigned move_count = 0;
36353  for (std::map<Node*, std::map<unsigned, unsigned>>::iterator it =
36354  node_must_not_be_removed_from_boundary_flag.begin();
36355  it != node_must_not_be_removed_from_boundary_flag.end();
36356  it++)
36357  {
36358  // Get the node
36359  Node* nod_pt = (*it).first;
36360 
36361  // Now we loop over the boundaries that this node is on
36362  for (std::map<unsigned, unsigned>::iterator it_2 = (*it).second.begin();
36363  it_2 != (*it).second.end();
36364  it_2++)
36365  {
36366  // Get the boundary id
36367  unsigned bound = (*it_2).first;
36368 
36369  // Remove it from that boundary?
36370  if ((*it_2).second == 0)
36371  {
36372  remove_boundary_node(bound, nod_pt);
36373  move_count++;
36374  }
36375  }
36376  }
36377 
36378  // Loop over the new face mesh to assign new boundary IDs
36379  for (unsigned p = 0; p < n_polyline; p++)
36380  {
36381  // Get the boundary id of the polyline
36382  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
36383 
36384  // Loop over the face elements
36385  unsigned n_face_element = face_mesh_pt[p]->nelement();
36386  for (unsigned e = 0; e < n_face_element; e++)
36387  {
36388  // Cast the element pointer to the correct thing!
36389  FaceElementAsGeomObject<ELEMENT>* el_pt =
36390  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>(
36391  face_mesh_pt[p]->element_pt(e));
36392 
36393  // Set bulk boundary number
36394  el_pt->set_boundary_number_in_bulk_mesh(bound);
36395  }
36396  }
36397 
36398  // Update look-up for elements next to boundary
36399  setup_boundary_element_info();
36400 
36401  // Now re-create the boundary coordinates
36402  for (unsigned p = 0; p < n_polyline; p++)
36403  {
36404  // Get the boundary id of the polyline
36405  unsigned bound = polygon_pt->polyline_pt(p)->boundary_id();
36406 
36407  // Do it
36408  this->template setup_boundary_coordinates<ELEMENT>(bound);
36409  }
36410 
36411  // Clean up
36412  for (unsigned p = 0; p < n_polyline; p++)
36413  {
36414  // Flush the nodes from the face mesh to make sure we
36415  // don't delete them (the face mesh that we're returning from here
36416  // still needs them!)
36417  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36418  delete ordered_face_mesh_pt[p];
36419  }
36420  }
36421 
36422  //=========================================================================
36423  /// Helper function to construct face mesh representation of all polylines
36424  //=========================================================================
36425  template<class ELEMENT>
36427  TriangleMeshOpenCurve* open_polyline_pt, Vector<Mesh*>& face_mesh_pt)
36428  {
36429  // Number of polylines
36430  unsigned n_polyline = open_polyline_pt->ncurve_section();
36431  face_mesh_pt.resize(n_polyline);
36432 
36433  // Loop over constituent polylines
36434  for (unsigned p = 0; p < n_polyline; p++)
36435  {
36436  // Get the boundary id of the polyline
36437  unsigned bound = open_polyline_pt->curve_section_pt(p)->boundary_id();
36438 
36439  face_mesh_pt[p] = new Mesh();
36440  create_unsorted_face_mesh_representation(bound, face_mesh_pt[p]);
36441  }
36442  }
36443 
36444  //======================================================================
36445  /// Update the PSLG that define the inner boundaries of the mesh.
36446  /// Optional boolean is used to run it as test only (if
36447  /// true is specified as input) in which case PSLG isn't actually
36448  /// modified. Returned boolean indicates if PSLG was (or would have
36449  /// been -- if called with check_only=false) changed.
36450  //======================================================================
36451  template<class ELEMENT>
36453  ELEMENT>::surface_remesh_for_inner_hole_boundaries(Vector<Vector<double>>&
36454  internal_point_coord,
36455  const bool& check_only)
36456  {
36457  // Boolean to indicate whether an actual update of the internal
36458  // holes was performed
36459  bool update_was_performed = false;
36460  // Loop over the number of internal boundaries
36461  unsigned n_hole = internal_point_coord.size();
36462  for (unsigned ihole = 0; ihole < n_hole; ihole++)
36463  {
36464  // Cache the pointer to the polygon representation
36465  TriangleMeshPolygon* const poly_pt = this->Internal_polygon_pt[ihole];
36466 
36467 
36468  // Can the polygon update its own configuration, in which case this
36469  // is easy
36470  if (poly_pt->can_update_reference_configuration())
36471  {
36472  poly_pt->reset_reference_configuration();
36473 
36474  // Initialize Vector hole_coordinates
36475  internal_point_coord[ihole].resize(2);
36476 
36477  // Get the vector of hole coordinates
36478  internal_point_coord[ihole] = poly_pt->internal_point();
36479  }
36480  // Otherwise we have to work much harder
36481 
36482  else
36483  {
36484  // if we only want to check whether an update of the inner
36485  // hole is necessary
36486  if (check_only)
36487  {
36488  // is it necessary?
36489  bool update_necessary =
36490  this->update_polygon_using_face_mesh(poly_pt, check_only);
36491 
36492  // Yes?
36493  if (update_necessary)
36494  {
36495  // then we have to adaptand return 'true'
36496  return true;
36497  }
36498  }
36499  // if we not only want to check, then we actually perform
36500  // the update
36501  else
36502  {
36503  update_was_performed = this->update_polygon_using_face_mesh(poly_pt);
36504  }
36505 
36506  // Now we need to sort out the hole coordinates
36507  if (!poly_pt->internal_point().empty())
36508  {
36509  // If fixed don't update and simply
36510  // Read out the existing value
36511  if (poly_pt->is_internal_point_fixed())
36512  {
36513  // Get the vector of hole coordinates
36514  internal_point_coord[ihole] = poly_pt->internal_point();
36515  }
36516  // This is where the work starts and this could be made much
36517  // better than the current hack
36518  else
36519  {
36520  // If the user has set their own function then use that
36521  if (this->Internal_hole_point_update_fct_pt != 0)
36522  {
36523  this->Internal_hole_point_update_fct_pt(ihole, poly_pt);
36524  }
36525  // Otherwise use our clunky default
36526  else
36527  {
36528  // Now sort out the hole coordinates
36529  Vector<double> vertex_coord;
36530  unsigned n_polyline = poly_pt->npolyline();
36531 
36532  // Initialize Vector hole_coordinates
36533  vertex_coord.resize(2);
36534  internal_point_coord[ihole].resize(2);
36535 
36536  // Hole centre will be found by averaging the position of
36537  // all vertex nodes
36538  internal_point_coord[ihole][0] = 0.0;
36539  internal_point_coord[ihole][1] = 0.0;
36540 
36541  for (unsigned p = 0; p < n_polyline; p++)
36542  {
36543  Vector<double> poly_ave(2, 0.0);
36544  // How many vertices are there in the segment
36545  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36546  for (unsigned v = 0; v < n_vertex; v++)
36547  {
36548  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36549  for (unsigned i = 0; i < 2; i++)
36550  {
36551  poly_ave[i] += vertex_coord[i];
36552  }
36553  }
36554 
36555  // Add the average polyline coordinate to the hole centre
36556  for (unsigned i = 0; i < 2; i++)
36557  {
36558  internal_point_coord[ihole][i] += poly_ave[i] / n_vertex;
36559  }
36560  }
36561 
36562  // Now average out the hole centre
36563  for (unsigned i = 0; i < 2; i++)
36564  {
36565  internal_point_coord[ihole][i] /= n_polyline;
36566  }
36567 
36568  // We have now found the hole centre stored in
36569  // internal_point_coordinate[ihole][i]
36570 
36571  // Find polylines that intersect at y average value
36572  // Alice's version but this does not work if the end point of a
36573  // segment is the intersection point (i.e. at the y average value)
36574  /*Vector<double> vertex_coord2;
36575  unsigned n_intersect=0;
36576  double x_average=0.0;
36577 
36578  for(unsigned p=0;p<n_polyline;p++)
36579  {
36580  //How many vertices are there in the segment
36581  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36582  for(unsigned v=0;v<n_vertex-1;v++)
36583  {
36584  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36585  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36586  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36587  << " " <<
36588  vertex_coord2[0] << " " <<
36589 
36590  vertex_coord2[1] << "\n";
36591  //Does the line between vertices intersect the vertical position
36592  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36593  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36594  {
36595  ++n_intersect; x_average += 0.5*(vertex_coord[0] +
36596  vertex_coord2[0]);
36597  }
36598  }
36599  }
36600 
36601  //Now just report the value if we have had intersections
36602  if(n_intersect != 0)
36603  {
36604  //Report
36605  std::cout << "I have computed a hole " << x_average << " " <<
36606  n_intersect << " "
36607  << x_average/((double)n_intersect) << std::endl;
36608  internal_point_coord[ihole][0] =
36609  x_average/((double)n_intersect);
36610  }
36611  */
36612 
36613  // Set the new hole centre
36614  poly_pt->internal_point() = internal_point_coord[ihole];
36615  // std::cout << "I've had my centre updated to "
36616  // << internal_point_coord[ihole][0]
36617  // << " " << internal_point_coord[ihole][1] << "\n";
36618  }
36619  }
36620  }
36621  }
36622  } // End of the action (n_hole for)
36623 
36624  if (check_only)
36625  {
36626  // If we make it up to here and we only check then no update is required
36627  return false;
36628  }
36629  else
36630  {
36631  // otherwise indicate whether an actual update was performed
36632  return update_was_performed;
36633  }
36634 
36635  } // End of the loop of internal boundaries
36636 
36637  //======================================================================
36638  /// Create the polylines and fill associate data structures, used when
36639  /// creating from a mesh from polyfiles
36640  //======================================================================
36641  template<class ELEMENT>
36643  const std::string& node_file_name, const std::string& poly_file_name)
36644  {
36645  // Get the nodes coordinates (the index of the nodes to build the
36646  // polylines is the one used in the node_file_name file)
36647  // Process node file
36648  // -----------------
36649  std::ifstream node_file(node_file_name.c_str(), std::ios_base::in);
36650 
36651  // Check that the file actually opened correctly
36652  if (!node_file.is_open())
36653  {
36654  std::string error_msg("Failed to open node file: ");
36655  error_msg += "\"" + node_file_name + "\".";
36656  throw OomphLibError(
36657  error_msg, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36658  }
36659 
36660  // Read number of nodes
36661  unsigned nnodes;
36662  node_file >> nnodes;
36663 
36664  // Spatial dimension of nodes
36665  unsigned dimension;
36666  node_file >> dimension;
36667 
36668 #ifdef PARANOID
36669  if (dimension != 2)
36670  {
36671  throw OomphLibError("The dimension must be 2\n",
36672  OOMPH_CURRENT_FUNCTION,
36673  OOMPH_EXCEPTION_LOCATION);
36674  }
36675 #endif
36676 
36677  // Storage the nodes vertices
36678  Vector<double> x_node(nnodes);
36679  Vector<double> y_node(nnodes);
36680 
36681  // Number of attributes
36682  unsigned npoint_attributes;
36683  node_file >> npoint_attributes;
36684  ;
36685 
36686  // Flag for boundary markers
36687  unsigned boundary_markers_flag = 0;
36688  node_file >> boundary_markers_flag;
36689 
36690  // Dummy for node number
36691  unsigned dummy_node_number;
36692  // Dummy for node attribute
36693  unsigned dummy_node_attribute;
36694  // Dummy for node boundary
36695  unsigned dummy_node_boundary;
36696 
36697  // Load in nodal posititions, point attributes
36698  // and boundary markers
36699  for (unsigned i = 0; i < nnodes; i++)
36700  {
36701  node_file >> dummy_node_number;
36702  node_file >> x_node[i];
36703  node_file >> y_node[i];
36704  for (unsigned j = 0; j < npoint_attributes; ++j)
36705  {
36706  node_file >> dummy_node_attribute;
36707  }
36708  if (boundary_markers_flag)
36709  {
36710  node_file >> dummy_node_boundary;
36711  }
36712  }
36713  node_file.close();
36714 
36715  // Get the segments information and use that info. to create the
36716  // polylines
36717 
36718  // A map to store the segments associated to a boundary, non sorted
36719  std::map<unsigned, Vector<std::pair<unsigned, unsigned>>>
36720  unsorted_boundary_segments;
36721 
36722  // Independent storage for the boundaries ids found in the segments so that
36723  // the polylines, and therefore polygons be created in the order they appear
36724  // in the polyfile
36725  Vector<unsigned> sorted_boundaries_ids;
36726 
36727  // Process poly file to extract edges
36728  //-----------------------------------
36729 
36730  // Open poly file
36731  std::ifstream poly_file(poly_file_name.c_str(), std::ios_base::in);
36732 
36733  // Check that the file actually opened correctly
36734  if (!poly_file.is_open())
36735  {
36736  std::string error_msg("Failed to open poly file: ");
36737  error_msg += "\"" + poly_file_name + "\".";
36738  throw OomphLibError(
36739  error_msg, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36740  }
36741 
36742  // Number of nodes in poly file --- these will be ignore
36743  unsigned n_node_poly;
36744  poly_file >> n_node_poly;
36745 
36746  // Dimension
36747  poly_file >> dimension;
36748 
36749  // Attribute flag
36750  unsigned attribute_flag;
36751  poly_file >> attribute_flag;
36752 
36753  // Flag for boundary markers
36754  poly_file >> boundary_markers_flag;
36755 
36756  // Ignore node information: Note: No, we can't extract the
36757  // actual nodes themselves from here!
36758  unsigned dummy;
36759  for (unsigned i = 0; i < n_node_poly; i++)
36760  {
36761  // Read in (and discard) node number and x and y coordinates
36762  poly_file >> dummy;
36763  poly_file >> dummy;
36764  poly_file >> dummy;
36765  // read in the attributes
36766  for (unsigned j = 0; j < attribute_flag; ++j)
36767  {
36768  poly_file >> dummy;
36769  }
36770  // read in the boundary marker
36771  if (boundary_markers_flag == 1)
36772  {
36773  poly_file >> dummy;
36774  }
36775  }
36776 
36777  // Variable used to read the values from the input file
36778  unsigned read_value;
36779 
36780  // Number of segments
36781  poly_file >> read_value;
36782  const unsigned nglobal_segments = read_value;
36783 
36784  // Boundary marker flag
36785  poly_file >> boundary_markers_flag;
36786 
36787  // Global segment number
36788  unsigned global_segment_number;
36789 
36790  // Node identifier set (used to identify possible internal boundaries)
36791  std::set<unsigned> nodes_ids;
36792 
36793  // Extract information for each segment
36794  for (unsigned i = 0; i < nglobal_segments; i++)
36795  {
36796  // Node id on the edge of the segment
36797  unsigned lnode_id = 0; // left node
36798  unsigned rnode_id = 0; // right node
36799  unsigned bnd_id = 0; // boundary id associated to the current segment
36800  poly_file >> global_segment_number;
36801  poly_file >> lnode_id;
36802  poly_file >> rnode_id;
36803  nodes_ids.insert(lnode_id);
36804  nodes_ids.insert(rnode_id);
36805  if (boundary_markers_flag)
36806  {
36807  poly_file >> bnd_id;
36808  }
36809 
36810  // Store the segments info. (use bnd_id - 1 because the nodes and
36811  // elements associated the bnd_id have been associated by external
36812  // methods to bnd_id - 1)
36813  unsorted_boundary_segments[bnd_id - 1].push_back(
36814  std::make_pair(lnode_id, rnode_id));
36815 
36816  // Add the boundary id to the vector of boundaries ids only if it
36817  // has not been added, the polylines will be created using this
36818  // order
36819 
36820  // Get the number of boundaries ids currently sorted
36821  const unsigned nsorted_boundaries_ids = sorted_boundaries_ids.size();
36822  // Flag to know if the boundary id was found
36823  bool boundary_id_found = false;
36824  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36825  {
36826  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36827  {
36828  boundary_id_found = true;
36829  break;
36830  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36831  } // for (ib < nsorted_boundaries_ids)
36832 
36833  // If th boundary id has not been added, then add it!!!
36834  if (!boundary_id_found)
36835  {
36836  sorted_boundaries_ids.push_back(bnd_id - 1);
36837  } // if (!boundary_id_found)
36838  }
36839 
36840  // Verify if there are internal boundaries defined, if that is the
36841  // case we can not continue since we are not yet supporting internal
36842  // boundaries defined in polyfiles to created a mesh that may be
36843  // adapted
36844 #ifdef PARANOID
36845  if (nglobal_segments != nodes_ids.size())
36846  {
36847  std::ostringstream error_message;
36848  error_message
36849  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36850  << nglobal_segments << ") is different.\nThis may mean that there "
36851  << "are internal non-closed boundaries defined in\nthe polyfile. "
36852  << "If you need this feature please use the TriangleMeshPoyLine\n"
36853  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36854  throw OomphLibError(
36855  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36856  }
36857 #endif
36858 
36859  // Now sort the segments associated to a boundary to create a contiguous
36860  // polyline, but first check that the number of found boundaries be the
36861  // same as the current number of boundaries in the mesh
36862  const unsigned nboundary = unsorted_boundary_segments.size();
36863 
36864 #ifdef PARANOID
36865  if (nboundary != this->nboundary())
36866  {
36867  std::ostringstream error_message;
36868  error_message
36869  << "The number of boundaries on the mesh (" << this->nboundary()
36870  << ") is different from the number of\nboundaries read from the "
36871  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36872  throw OomphLibError(
36873  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36874  }
36875 #endif
36876 
36877  // Get the number of sorted boundaries ids and check that it matches
36878  // with the total number of boundaries
36879  const unsigned nsorted_boundaries_ids = sorted_boundaries_ids.size();
36880 #ifdef PARANOID
36881  if (nsorted_boundaries_ids != this->nboundary())
36882  {
36883  std::ostringstream error_message;
36884  error_message
36885  << "The number of boundaries on the mesh (" << this->nboundary()
36886  << ") is different from the number of\nsorted boundaries ids read "
36887  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36888  throw OomphLibError(
36889  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
36890  }
36891 #endif
36892 
36893  // Sorted segments (to create a polyline -- boundary)
36894  std::map<unsigned, std::list<unsigned>> sorted_boundary_segments;
36895 
36896  // Go through all the found boundaries
36897  std::map<unsigned, Vector<std::pair<unsigned, unsigned>>>::iterator it;
36898 
36899  for (it = unsorted_boundary_segments.begin();
36900  it != unsorted_boundary_segments.end();
36901  it++)
36902  {
36903  // Get the current boundary id, only look for the segments
36904  // associated with this boundary
36905  const unsigned bnd_id = (*it).first;
36906  Vector<std::pair<unsigned, unsigned>> segments_edges = (*it).second;
36907 
36908  // Now sort the segments associated to this boundary
36909  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36910  const unsigned nsegments = segments_edges.size();
36911 
36912  // Sorted nodes for the current segment
36913  std::list<unsigned> sorted_segments;
36914 
36915  // Get the left and right node of the zero segment
36916  unsigned left_node_id = segments_edges[0].first;
36917  unsigned right_node_id = segments_edges[0].second;
36918 
36919  // ... and add it to the sorted segments structure
36920  sorted_segments.push_back(left_node_id);
36921  sorted_segments.push_back(right_node_id);
36922 
36923  // Mark the current segment as done
36924  segment_done[segments_edges[0]] = true;
36925 
36926  // Set the number of sorted segments
36927  unsigned nsorted_segments = 1;
36928 
36929  while (nsorted_segments < nsegments)
36930  {
36931  for (unsigned i = 1; i < nsegments; i++)
36932  {
36933  // Check if the i-th segments has been done
36934  if (!segment_done[segments_edges[i]])
36935  {
36936  // Get the left and right node id
36937  unsigned current_left_node_id = segments_edges[i].first;
36938  unsigned current_right_node_id = segments_edges[i].second;
36939 
36940  // Now check if the current segment can be added to the left
36941  // or right side of the sorted segments
36942  if (current_left_node_id == right_node_id)
36943  {
36944  // Add the current_right_node_id to the right of the sorted
36945  // segments
36946  sorted_segments.push_back(current_right_node_id);
36947  // Increase the number of sorted segments
36948  nsorted_segments++;
36949  // Mark the segment as done
36950  segment_done[segments_edges[i]] = true;
36951  // Update the right most node
36952  right_node_id = current_right_node_id;
36953  // Break the for loop
36954  break;
36955  }
36956  else if (current_right_node_id == left_node_id)
36957  {
36958  // Add the current_left_node_id to the left of the sorted
36959  // segments
36960  sorted_segments.push_front(current_left_node_id);
36961  // Increase the number of sorted segments
36962  nsorted_segments++;
36963  // Mark the segment as done
36964  segment_done[segments_edges[i]] = true;
36965  // Update the left most node
36966  left_node_id = current_left_node_id;
36967  // Break the for loop
36968  break;
36969  }
36970  else if (current_left_node_id == left_node_id)
36971  {
36972  // Add the current_right_node_id to the left of the sorted
36973  // segments
36974  sorted_segments.push_front(current_right_node_id);
36975  // Increase the number of sorted segments
36976  nsorted_segments++;
36977  // Mark the segment as done
36978  segment_done[segments_edges[i]] = true;
36979  // Update the left most node
36980  left_node_id = current_right_node_id;
36981  // Break the for loop
36982  break;
36983  }
36984  else if (current_right_node_id == right_node_id)
36985  {
36986  // Add the current_left_node_id to the right of the sorted
36987  // segments
36988  sorted_segments.push_back(current_left_node_id);
36989  // Increase the number of sorted segments
36990  nsorted_segments++;
36991  // Mark the segment as done
36992  segment_done[segments_edges[i]] = true;
36993  // Update the left most node
36994  right_node_id = current_left_node_id;
36995  // Break the for loop
36996  break;
36997  }
36998  } // if (!segment_done[segments_edges[i]])
36999  } // for (i < nsegments)
37000  } // while(nsorted_segments < nsegments)
37001 
37002  sorted_boundary_segments[bnd_id] = sorted_segments;
37003 
37004  } // for (unsorted_boundary_segments.begin();
37005  // unsorted_boundary_segments.end())
37006 
37007 #ifdef PARANOID
37008  if (sorted_boundary_segments.size() != this->nboundary())
37009  {
37010  std::ostringstream error_message;
37011  error_message
37012  << "The number of boundaries on the mesh (" << this->nboundary()
37013  << ") is different from the number\nof sorted boundaries to create the "
37014  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
37015  throw OomphLibError(
37016  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37017  }
37018 #endif
37019 
37020  // Now we have the sorted nodes, we can create the polylines by
37021  // getting the vertices of the nodes
37022  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
37023  unsigned current_polyline = 0;
37024 
37025  // Go through the sorted boundaries using the sorted boundaries ids
37026  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
37027  {
37028  // Get the boundary id from the vector of sorted boundaries ids
37029  const unsigned bnd_id = sorted_boundaries_ids[ib];
37030 
37031  // Create a vector representation for ease to use
37032  // Get the vertices of the nodes that create the boundary / polyline
37033  Vector<unsigned> nodes_ids;
37034  for (std::list<unsigned>::iterator it_list =
37035  sorted_boundary_segments[bnd_id].begin();
37036  it_list != sorted_boundary_segments[bnd_id].end();
37037  it_list++)
37038  {
37039  nodes_ids.push_back((*it_list));
37040  }
37041 
37042  // Get the number of vertices for the polyline
37043  const unsigned nvertices = nodes_ids.size();
37044 
37045  // The storage for the vertices
37046  Vector<Vector<double>> vertices(nvertices);
37047 
37048  // Now get the vertices of the nodes of the current boundary
37049  for (unsigned i = 0; i < nvertices; i++)
37050  {
37051  // Get the vertices
37052  vertices[i].resize(2);
37053  vertices[i][0] = x_node[nodes_ids[i] - 1];
37054  vertices[i][1] = y_node[nodes_ids[i] - 1];
37055  }
37056 
37057  // Now create the polyline
37058 
37059  // Note: The bnd_id is the real bnd_id (from the input file) - 1
37060  // since nodes and elements of the current boundary have been
37061  // associated to bnd_id - 1)
37062  polylines_pt[current_polyline] =
37063  new TriangleMeshPolyLine(vertices, bnd_id);
37064 
37065  // Updates bnd_id<--->curve section map
37066  this->Boundary_curve_section_pt[bnd_id] =
37067  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
37068 
37069  // Increase the index for the polyline storage
37070  current_polyline++;
37071 
37072  } // for (it_sorted = sorted_boundary_segments.begin();
37073  // it_sorted != sorted_boundary_segments.end())
37074 
37075  // Now create the polygons or closed curves
37076  // Sort the polylines to create polygons
37077  unsigned nsorted_polylines = 0;
37078 
37079  // Number of created polygons
37080  unsigned npolygons = 0;
37081 
37082  // Storage for the polygons
37083  Vector<TriangleMeshPolygon*> polygons_pt;
37084 
37085  // Mark the already done polylines
37086  std::map<unsigned, bool> polyline_done;
37087  while (nsorted_polylines < nboundary)
37088  {
37089  // Storage for the curve sections that create a polygon
37090  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
37091 
37092  unsigned init_poly = 0;
37093 #ifdef PARANOID
37094  bool found_root_polyline = false;
37095 #endif
37096  // Get the left and right node of the current polyline
37097  for (unsigned i = 0; i < nboundary; i++)
37098  {
37099  if (!polyline_done[i])
37100  {
37101  init_poly = i;
37102  // Increase the number of sorted polylines
37103  nsorted_polylines++;
37104 #ifdef PARANOID
37105  // Mark as found the root polyline
37106  found_root_polyline = true;
37107 #endif
37108  // Mark the polyline as done
37109  polyline_done[i] = true;
37110  // Add the polyline to the curve sections storage
37111  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37112  // Break the loop to set we have found a root polyline
37113  break;
37114  }
37115  }
37116 
37117 #ifdef PARANOID
37118  if (!found_root_polyline)
37119  {
37120  std::ostringstream error_message;
37121  error_message << "Was not possible to found the root polyline to "
37122  "create polygons\n\n";
37123  throw OomphLibError(error_message.str(),
37124  OOMPH_CURRENT_FUNCTION,
37125  OOMPH_EXCEPTION_LOCATION);
37126  }
37127 #endif
37128 
37129  // Get the associated boundary to the current polyline
37130  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
37131  // Get the initial and final node id of the current polyline
37132  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
37133  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
37134 
37135  // Flag to know that we already have a closed polygon
37136  bool closed_polygon = false;
37137 
37138  do
37139  {
37140  // Go through all the polylines
37141  for (unsigned i = init_poly; i < nboundary; i++)
37142  {
37143  // Check that the polyline has not been currently done
37144  if (!polyline_done[i])
37145  {
37146  // Get the initial and final nodes id of the current polyline
37147 
37148  // Get the associated boundary to the current polyline
37149  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
37150  // Get the initial and final node id of the current polyline
37151  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
37152  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
37153 
37154  // Check if the polyline goes to the left or right of the
37155  // current sorted polylines
37156  if (cleft_node_id == right_node_id)
37157  {
37158  // Add the polyline to the curve section storage
37159  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37160  // Mark the polyline as done
37161  polyline_done[i] = true;
37162  // Update the right node
37163  right_node_id = cright_node_id;
37164  // Increase the number of done polyines
37165  nsorted_polylines++;
37166  // Break the for loop
37167  break;
37168  }
37169  else if (cright_node_id == left_node_id)
37170  {
37171  // Add the polyline to the curve section storage
37172  sorted_curve_sections_pt.push_front(polylines_pt[i]);
37173  // Mark the polyline as done
37174  polyline_done[i] = true;
37175  // Update the right node
37176  left_node_id = cleft_node_id;
37177  // Increase the number of done polyines
37178  nsorted_polylines++;
37179  // Break the for loop
37180  break;
37181  }
37182  else if (cleft_node_id == left_node_id)
37183  {
37184  // First reverse the polyline
37185  polylines_pt[i]->reverse();
37186  // Add the polyline to the curve section storage
37187  sorted_curve_sections_pt.push_front(polylines_pt[i]);
37188  // Mark the polyline as done
37189  polyline_done[i] = true;
37190  // Update the right node
37191  left_node_id = cright_node_id;
37192  // Increase the number of done polyines
37193  nsorted_polylines++;
37194  // Break the for loop
37195  break;
37196  }
37197  else if (cright_node_id == right_node_id)
37198  {
37199  // First reverse the polyline
37200  polylines_pt[i]->reverse();
37201  // Add the polyline to the curve section storage
37202  sorted_curve_sections_pt.push_back(polylines_pt[i]);
37203  // Mark the polyline as done
37204  polyline_done[i] = true;
37205  // Update the right node
37206  right_node_id = cleft_node_id;
37207  // Increase the number of done polyines
37208  nsorted_polylines++;
37209  // Break the for loop
37210  break;
37211  }
37212  } // if (!polyline_done[i])
37213 
37214  } // for (i < nboundary)
37215 
37216  // We have created a polygon
37217  if (left_node_id == right_node_id)
37218  {
37219  // Set the flag as true
37220  closed_polygon = true;
37221  }
37222 
37223  } while (nsorted_polylines < nboundary && !closed_polygon);
37224 
37225 #ifdef PARANOID
37226  if (!closed_polygon)
37227  {
37228  std::ostringstream error_message;
37229  error_message
37230  << "It was not possible to create a closed curve, these are the "
37231  << "vertices of the already sorted polylines\n\n";
37232  unsigned cpolyline = 0;
37233  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37234  sorted_curve_sections_pt.begin();
37235  it_list != sorted_curve_sections_pt.end();
37236  it_list++)
37237  {
37238  error_message << "Polyline (" << cpolyline << ")\n";
37239  TriangleMeshPolyLine* tmp_poly_pt =
37240  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
37241  const unsigned nvertex = tmp_poly_pt->nvertex();
37242  for (unsigned v = 0; v < nvertex; v++)
37243  {
37244  error_message << "(" << tmp_poly_pt->vertex_coordinate(v)[0] << ", "
37245  << tmp_poly_pt->vertex_coordinate(v)[1] << ")\n";
37246  }
37247  error_message << "\n";
37248  cpolyline++;
37249  }
37250  throw OomphLibError(error_message.str(),
37251  OOMPH_CURRENT_FUNCTION,
37252  OOMPH_EXCEPTION_LOCATION);
37253  }
37254 #endif
37255 
37256  // Create a vector version to create the polygon from the sorted
37257  // polyines
37258  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37259  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37260  sorted_curve_sections_pt.begin();
37261  it_list != sorted_curve_sections_pt.end();
37262  it_list++)
37263  {
37264  tmp_sorted_curve_sections_pt.push_back((*it_list));
37265  }
37266 
37267  // Create a new polygon by using the new created polylines
37268  TriangleMeshPolygon* polygon_pt =
37269  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37270 
37271  // Keep track of new created polygons that need to be deleted!!!
37272  this->Free_polygon_pt.insert(polygon_pt);
37273 
37274  // Store the polygon in the polygons storages
37275  polygons_pt.push_back(polygon_pt);
37276 
37277  npolygons++;
37278 
37279  } // while(nsorted_polylines < nboundary)
37280 
37281  // ------------------------------------------------------------------
37282  // Before filling the data structures we need to identify the outer
37283  // closed boundary and the inner closed boundaries.
37284  // If the nodes are not in order we throw a warning message
37285 
37286  // Index for the polygon that is currently considered as the outer
37287  // boundary
37288  unsigned index_outer = 0;
37289 
37290  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37291  {
37292  // Get the vertices of the outer boundary
37293  Vector<Vector<double>> outer_vertex_coordinates;
37294 
37295  // Flag to know if ALL the inner closed boundaries are inside the
37296  // outer closed boundary
37297  bool all_inner_inside = true;
37298 
37299  // Number of polylines of the outer boundary
37300  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37301  for (unsigned p = 0; p < nouter_polylines; p++)
37302  {
37303  TriangleMeshPolyLine* tmp_poly_pt =
37304  polygons_pt[idx_outer]->polyline_pt(p);
37305  const unsigned nvertex = tmp_poly_pt->nvertex();
37306  for (unsigned v = 0; v < nvertex; v++)
37307  {
37308  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37309  outer_vertex_coordinates.push_back(current_vertex);
37310  } // for (v < nvertex)
37311  } // for (p < nouter_polylines)
37312 
37313  // Now get the vertices for the inner boundaries
37314 
37315  // First get the number of inner closed boundaries (polygons size
37316  // minus one because one of the polygons is considered to be the
37317  // outer closed boundary
37318  const unsigned ninner_polygons = polygons_pt.size() - 1;
37319 
37320  // Store the vertices of the inner closed boundaries
37321  Vector<Vector<Vector<double>>> inner_vertex_coordinates(ninner_polygons);
37322  // Get all the vertices of the inner closed boundaries
37323  for (unsigned i = 0; i <= ninner_polygons; i++)
37324  {
37325  if (i != idx_outer)
37326  {
37327  // Number of polylines of the current internal closed boundary
37328  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37329  for (unsigned p = 0; p < ninner_polylines; p++)
37330  {
37331  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37332  const unsigned nvertex = tmp_poly_pt->nvertex();
37333  for (unsigned v = 0; v < nvertex; v++)
37334  {
37335  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37336  if (i < idx_outer)
37337  {
37338  inner_vertex_coordinates[i].push_back(current_vertex);
37339  }
37340  else if (i > idx_outer)
37341  {
37342  inner_vertex_coordinates[i - 1].push_back(current_vertex);
37343  }
37344  } // for (v < nvertex)
37345 
37346  } // for (p < ninner_polylines)
37347 
37348  } // if (i != index_outer)
37349 
37350  } // for (i <= ninner_polygons)
37351 
37352  // Now check that ALL the vertices of ALL the internal closed
37353  // boundaries are inside the outer closed boundary
37354  for (unsigned i = 0; i < ninner_polygons; i++)
37355  {
37356  // Get the number of vertices in the current internal closed
37357  // boundary
37358  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37359  for (unsigned v = 0; v < nvertex_internal; v++)
37360  {
37361  // Get a vertex in the current internal closed boundary
37362  Vector<double> current_point = inner_vertex_coordinates[i][v];
37363  all_inner_inside &= this->is_point_inside_polygon_helper(
37364  outer_vertex_coordinates, current_point);
37365 
37366  // Check if we should continue checking for more points inside
37367  // the current proposed outer boundary
37368  if (!all_inner_inside)
37369  {
37370  // Break the "for" for the vertices
37371  break;
37372  }
37373 
37374  } // for (v < nvertex_internal)
37375 
37376  // Check if we should continue checking for more inner closed
37377  // boundaries inside the current proposed outer boundary
37378  if (!all_inner_inside)
37379  {
37380  // Break the "for" for the inner boundaries
37381  break;
37382  }
37383 
37384  } // for (i < ninner_polygons)
37385 
37386  // Check if all the vertices of all the polygones are inside the
37387  // current proposed outer boundary
37388  if (all_inner_inside)
37389  {
37390  index_outer = idx_outer;
37391  break;
37392  }
37393 
37394  } // for (idx_outer < npolygons)
37395 
37396 #ifdef PARANOID
37397  // Check if the first nodes listed in the polyfiles correspond to
37398  // the outer boundary, if that is not the case then throw a warning
37399  // message
37400  if (index_outer != 0)
37401  {
37402  std::ostringstream warning_message;
37403  warning_message
37404  << "The first set of nodes listed in the input polyfiles does not\n"
37405  << "correspond to the outer closed boundary. This may lead to\n"
37406  << "problems at the adaptation stage if the holes coordinates\n"
37407  << "are no correctly associated to the inner closed boundaries.\n"
37408  << "You can check the generated mesh by calling the output() method\n"
37409  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37410  OomphLibWarning(warning_message.str(),
37411  OOMPH_CURRENT_FUNCTION,
37412  OOMPH_EXCEPTION_LOCATION);
37413  } // if (index_outer != 0)
37414 #endif
37415 
37416  // ------------------------------------------------------------------
37417  // Now fill the data structures
37418 
37419  // Store outer polygon
37420  // We are assuming there is only one outer polygon
37421  this->Outer_boundary_pt.resize(1);
37422  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37423 
37424  this->Internal_polygon_pt.resize(npolygons - 1);
37425  for (unsigned i = 0; i < npolygons; i++)
37426  {
37427  if (i != index_outer)
37428  {
37429  if (i < index_outer)
37430  {
37431  // Store internal polygons by copy constructor
37432  this->Internal_polygon_pt[i] = polygons_pt[i];
37433  }
37434  else if (i > index_outer)
37435  {
37436  // Store internal polygons by copy constructor
37437  this->Internal_polygon_pt[i - 1] = polygons_pt[i];
37438  }
37439  } // if (i != index_outer)
37440  } // for (i < npolygons)
37441 
37442  // Before assigning the hole vertex coordinate to the inner closed
37443  // boundaries check that the holes are listed in orderm if that is
37444  // not the case the associate each hole vertex coordinate to the
37445  // inner closed boundaries
37446 
37447  // Store the vertices of the inner closed boundaries
37448  Vector<Vector<Vector<double>>> inner_vertex_coordinates(npolygons - 1);
37449  // Get all the vertices of the inner closed boundaries
37450  for (unsigned i = 0; i < npolygons - 1; i++)
37451  {
37452  // Number of polylines of the current internal closed boundary
37453  const unsigned ninner_polylines =
37454  this->Internal_polygon_pt[i]->npolyline();
37455  for (unsigned p = 0; p < ninner_polylines; p++)
37456  {
37457  TriangleMeshPolyLine* tmp_poly_pt =
37458  this->Internal_polygon_pt[i]->polyline_pt(p);
37459  // Number of vertices of the current polyline in the current
37460  // internal closed polygon
37461  const unsigned nvertex = tmp_poly_pt->nvertex();
37462  for (unsigned v = 0; v < nvertex; v++)
37463  {
37464  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37465  inner_vertex_coordinates[i].push_back(current_vertex);
37466  } // for (v < nvertex)
37467 
37468  } // for (p < ninner_polylines)
37469 
37470  } // for (i <= ninner_polygons)
37471 
37472  // Holes information
37473  unsigned nholes;
37474  poly_file >> nholes;
37475 
37476 #ifdef PARANOID
37477  if (npolygons > 1 && (npolygons - 1) != nholes)
37478  {
37479  std::ostringstream error_message;
37480  error_message
37481  << "The number of holes (" << nholes << ") does not correspond "
37482  << "with the number\nof internal polygons (" << npolygons - 1 << ")\n\n"
37483  << "Using polyfiles as input does not currently allows the\n"
37484  << "definition of more than one outer polygon\n\n";
37485  throw OomphLibError(
37486  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37487  }
37488 #endif
37489 
37490  // Storage for the holes
37491  Vector<Vector<double>> hole_coordinates(nholes);
37492 
37493  // Dummy for hole number
37494  unsigned dummy_hole;
37495  // Loop over the holes to get centre coords
37496  for (unsigned ihole = 0; ihole < nholes; ihole++)
37497  {
37498  hole_coordinates[ihole].resize(2);
37499  // Read the centre value
37500  poly_file >> dummy_hole;
37501  poly_file >> hole_coordinates[ihole][0];
37502  poly_file >> hole_coordinates[ihole][1];
37503  }
37504 
37505  // Vector that store the index of the hole coordinate that
37506  // correspond to each internal closed polygon
37507  Vector<unsigned> index_hole_of_internal_polygon(npolygons - 1);
37508  std::map<unsigned, bool> hole_done;
37509 
37510  // Now associate each hole vertex to a corresponding internal closed
37511  // polygon
37512  for (unsigned i = 0; i < npolygons - 1; i++)
37513  {
37514  // Find which hole is associated to each internal closed boundary
37515  for (unsigned h = 0; h < nholes; h++)
37516  {
37517  // If the hole has not been previously associated
37518  if (!hole_done[h])
37519  {
37520  // Get the hole coordinate
37521  Vector<double> current_point = hole_coordinates[h];
37522 
37523  const bool hole_in_polygon = this->is_point_inside_polygon_helper(
37524  inner_vertex_coordinates[i], current_point);
37525 
37526  // If the hole is inside the polygon
37527  if (hole_in_polygon)
37528  {
37529  // Mark the hole as done
37530  hole_done[h] = true;
37531  // Associate the current hole with the current inner closed
37532  // boundary
37533  index_hole_of_internal_polygon[i] = h;
37534  // Break the search
37535  break;
37536  }
37537 
37538  } // if (!hole_done[h])
37539 
37540  } // for (h < nholes)
37541 
37542  } // for (i < npolygons-1)
37543 
37544 #ifdef PARANOID
37545  if (hole_done.size() != npolygons - 1)
37546  {
37547  std::ostringstream error_message;
37548  error_message
37549  << "Not all the holes were associated to an internal closed boundary\n"
37550  << "Only (" << hole_done.size()
37551  << ") holes were assigned for a total of\n"
37552  << "(" << npolygons - 1 << ") internal closed boundaries.\n"
37553  << "You can check the generated mesh by calling the output() method\n"
37554  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37555  throw OomphLibError(
37556  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
37557  } // if (index_hole != ihole)
37558 #endif
37559 
37560  // Assign the holes coordinates to the internal polygons
37561  for (unsigned ihole = 0; ihole < nholes; ihole++)
37562  {
37563  // Get the index hole of the current internal closed polygon
37564  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37565 #ifdef PARANOID
37566  // Check if the hole index is the same as the internal closed
37567  // boundary, it means that the holes were listed in the same order
37568  // as the nodes of the internal closed boundaries
37569  if (index_hole != ihole)
37570  {
37571  std::ostringstream error_message;
37572  error_message
37573  << "The hole vertices coordinates are not listed in the same order\n"
37574  << "as the nodes that define the internal closed boundaries.\n"
37575  << "This may lead to problems in case that the holes coordinates\n"
37576  << "were no properly assigned to the internal closed boundaries.\n"
37577  << "You can check the generated mesh by calling the output() method\n"
37578  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37579  throw OomphLibError(error_message.str(),
37580  OOMPH_CURRENT_FUNCTION,
37581  OOMPH_EXCEPTION_LOCATION);
37582  } // if (index_hole != ihole)
37583 #endif
37584 
37585  // Set the hole coordinate for the internal polygon
37586  this->Internal_polygon_pt[ihole]->internal_point() =
37587  hole_coordinates[index_hole];
37588  }
37589 
37590  // Ignore the first line with structure description
37591  poly_file.ignore(80, '\n');
37592 
37593  // Regions information
37594  unsigned nregions;
37595 
37596  // Extract regions information
37597  // But first check if there are regions or not
37598  std::string regions_info_string;
37599 
37600  // Read line up to termination sign
37601  getline(poly_file, regions_info_string);
37602 
37603  // Check if the read string is a number or a comment wrote by triangle,
37604  // if it is a number then that is the number of regions
37605  if (isdigit(regions_info_string.c_str()[0]))
37606  {
37607  nregions = std::atoi(regions_info_string.c_str());
37608  }
37609  else
37610  {
37611  nregions = 0;
37612  }
37613 
37614  // The regions coordinates
37615  std::map<unsigned, Vector<double>> regions_coordinates;
37616 
37617  // Dummy for regions number
37618  unsigned dummy_region;
37619 
37620  unsigned region_id;
37621 
37622  // Loop over the regions to get their coords
37623  for (unsigned iregion = 0; iregion < nregions; iregion++)
37624  {
37625  Vector<double> tmp_region_coordinates(2);
37626  // Read the regions coordinates
37627  poly_file >> dummy_region;
37628  poly_file >> tmp_region_coordinates[0];
37629  poly_file >> tmp_region_coordinates[1];
37630  poly_file >> region_id;
37631  regions_coordinates[region_id].resize(2);
37632  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37633  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37634 
37635  // Ignore the first line with structure description
37636  poly_file.ignore(80, '\n');
37637 
37638  // Verify if not using the default region number (zero)
37639  if (region_id == 0)
37640  {
37641  std::ostringstream error_message;
37642  error_message
37643  << "Please use another region id different from zero.\n"
37644  << "It is internally used as the default region number.\n";
37645  throw OomphLibError(error_message.str(),
37646  OOMPH_CURRENT_FUNCTION,
37647  OOMPH_EXCEPTION_LOCATION);
37648  }
37649  }
37650 
37651  // Store the extra regions coordinates
37652  this->Regions_coordinates = regions_coordinates;
37653 
37654  poly_file.close();
37655  }
37656 
37657  //======================================================================
37658  /// Updates the polygon but using the elements area instead of
37659  /// the default refinement and unrefinement methods
37660  //======================================================================
37661  template<class ELEMENT>
37663  TriangleMeshPolygon*& polygon_pt, const Vector<double>& target_area)
37664  {
37665  // Verify that there was a change on the polygon representation
37666  unsigned update_was_performed = false;
37667 
37668  const unsigned nele = this->nelement();
37669 
37670  // - Get the vertices along the boundaries and for each element identify
37671  // its associated target error.
37672  // - Get face mesh representation of each polyline.
37673  // - Get the vertices with the help of face elements.
37674  // - Find the global index in the mesh of the face element and use
37675  // it to get its associated target area
37676 
37677  // Get the face mesh representation
37678  Vector<Mesh*> face_mesh_pt;
37679  get_face_mesh_representation(polygon_pt, face_mesh_pt);
37680 
37681  // Create vertices of the polylines by using the vertices of the
37682  // FaceElements
37683  Vector<double> vertex_coord(3); // zeta,x,y
37684  Vector<double> bound_left(1);
37685  Vector<double> bound_right(1);
37686 
37687  unsigned n_polyline = polygon_pt->npolyline();
37688 
37689  // Go for each polyline
37690  for (unsigned p = 0; p < n_polyline; p++)
37691  {
37692  // Get the MeshAsGeomObject representation just once per polyline,
37693  // this object is only used by the
37694  // refine_boundary_constrained_by_target_area() method. We get it
37695  // here to ensure that all processors (in a distributed context)
37696  // get this representation just once, and because an AllToAll MPI
37697  // communication is used in this calling
37698  MeshAsGeomObject* mesh_geom_obj_pt =
37699  new MeshAsGeomObject(face_mesh_pt[p]);
37700 
37701  // Set of coordinates on the boundary
37702  // Set entries are ordered on first entry in vector which stores
37703  // the boundary coordinate so the vertices come out in order!
37704  std::set<Vector<double>> vertex_nodes;
37705 
37706  // Vector to store the vertices, transfer the sorted vertices from the
37707  // set to this vector, --- including the z-value ---
37708  Vector<Vector<double>> tmp_vector_vertex_node;
37709 
37710  // Vector to store the coordinates of the polylines, same as the
37711  // tmp_vector_vertex_node vector (after adding more nodes) but
37712  // --- without the z-value ---, used to re-generate the polylines
37713  Vector<Vector<double>> vector_vertex_node;
37714 
37715 #ifdef OOMPH_HAS_MPI
37716  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37717  // Set of coordinates that are on the boundary (splitted boundary version)
37718  // The first vector is used to allocate the points for each sub-boundary
37719  // Set entries are ordered on first entry in vector which stores
37720  // the boundary coordinate so the vertices come out in order!
37721  Vector<std::set<Vector<double>>> sub_vertex_nodes;
37722 
37723  // Vector to store the vertices, transfer the sorted vertices from the
37724  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37725  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
37726 
37727  // Vector to store the coordinates of the polylines that will represent
37728  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37729  // but --- without the z-value ---, used to generate the sub-polylines
37730  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
37731  // --------- Stuff to deal with splitted boundaries ----------- End ------
37732 #endif
37733 
37734  // Get the boundary id
37735  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37736 
37737  // Get the chunk number
37738  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37739 
37740  /// Use a vector of vector for vertices and target areas to deal
37741  /// with the cases when the boundaries are split by the
37742  /// distribution process
37743 
37744  // Loop over the face elements (ordered) and add their vertices
37745  const unsigned nface_element = face_mesh_pt[p]->nelement();
37746 
37747  // Store the non halo face elements, the ones from which we will
37748  // get the vertices
37749  Vector<FiniteElement*> non_halo_face_element_pt;
37750 
37751  // Map to store the index of the face element on a boundary
37752  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
37753 
37754  for (unsigned ef = 0; ef < nface_element; ++ef)
37755  {
37756  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37757 #ifdef OOMPH_HAS_MPI
37758  // Skip the halo elements if working with a distributed mesh
37759  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37760  {
37761  continue;
37762  }
37763 #endif
37764  // Add the face element to the vector
37765  non_halo_face_element_pt.push_back(ele_face_pt);
37766  face_element_index_on_boundary[ele_face_pt] = ef;
37767  }
37768 
37769  // Get the number of non halo face element
37770  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37771 
37772  // Map to know the already sorted face elements
37773  std::map<FiniteElement*, bool> face_element_done;
37774 
37775  // Number of done face elements
37776  unsigned nsorted_face_elements = 0;
37777 
37778 #ifdef OOMPH_HAS_MPI
37779  // Counter for sub_boundaries
37780  unsigned nsub_boundaries = 0;
37781 #endif // #ifdef OOMPH_HAS_MPI
37782 
37783  // Continue until all the face elements have been sorted
37784  // While to deal with split boundaries cases
37785  while (nsorted_face_elements < nnon_halo_face_element)
37786  {
37787  // Get and initial face element
37788  FiniteElement* ele_face_pt = 0;
37789 #ifdef PARANOID
37790  bool found_initial_face_element = false;
37791 #endif
37792 
37793  unsigned iface = 0;
37794  for (iface = 0; iface < nnon_halo_face_element; iface++)
37795  {
37796  ele_face_pt = non_halo_face_element_pt[iface];
37797  // If not done then take it as initial face element
37798  if (!face_element_done[ele_face_pt])
37799  {
37800 #ifdef PARANOID
37801  found_initial_face_element = true;
37802 #endif
37803  nsorted_face_elements++;
37804  iface++;
37805  break;
37806  }
37807  }
37808 
37809 #ifdef PARANOID
37810  if (!found_initial_face_element)
37811  {
37812  std::ostringstream error_message;
37813  error_message << "Could not find an initial face element for the "
37814  "current segment\n";
37815  // << "----- Possible memory leak -----\n";
37816  throw OomphLibError(
37817  error_message.str(),
37818  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37819  OOMPH_EXCEPTION_LOCATION);
37820  }
37821 #endif
37822 
37823  // Local set of coordinates that are on the boundary
37824  // Set entries are ordered on first entry in vector which stores
37825  // the boundary coordinate so the vertices come out in order!
37826  std::set<Vector<double>> local_vertex_nodes;
37827 
37828  // Vector to store the vertices, transfer the sorted vertices from the
37829  // set (local) to this vector (local), --- including the z-value ---
37830  Vector<Vector<double>> local_tmp_vector_vertex_node;
37831 
37832  // Vector to store the target areas, uses the same approach as the
37833  // set for the local_vertex_nodes, ordered on first entry
37834  std::set<Vector<double>> sorted_target_areas;
37835 
37836  // Vector to store the target areas, used to transfer the sorted target
37837  // areas from "local_sorted_target_areas" set
37838  Vector<double> tmp_sorted_target_areas;
37839 
37840  // -----------------------------------------------------------------
37841  // Add the vertices of the initial face element to the set of
37842  // local sorted vertices
37843  // -----------------------------------------------------------------
37844  unsigned nnode = ele_face_pt->nnode();
37845  // Add the left-hand node to the set:
37846  // Boundary coordinate
37847  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
37848  vertex_coord[0] = bound_left[0];
37849 
37850  // Actual coordinates
37851  for (unsigned i = 0; i < 2; i++)
37852  {
37853  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
37854  }
37855  local_vertex_nodes.insert(vertex_coord);
37856 
37857  // Add the right-hand nodes to the set:
37858  // Boundary coordinate
37859  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
37860  bound, bound_right);
37861  vertex_coord[0] = bound_right[0];
37862 
37863  // Actual coordinates
37864  for (unsigned i = 0; i < 2; i++)
37865  {
37866  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
37867  }
37868  local_vertex_nodes.insert(vertex_coord);
37869 
37870  // The initial and final node on the set
37871  Node* first_node_pt = ele_face_pt->node_pt(0);
37872  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
37873 
37874  // Mark the current face element as done
37875  face_element_done[ele_face_pt] = true;
37876 
37877  // -------------------------------------------------------
37878  // Find the global index in the mesh of the face element
37879  // and use it to get its associated target area
37880  // -------------------------------------------------------
37881  // Container to store the zeta value (used as index) and
37882  // the associated target area of the element
37883  Vector<double> zeta_target_area_values(2);
37884 
37885  // Use the minimum zeta value to sort the target areas
37886  // along the boundary
37887  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
37888 
37889  // Get the index of the face element on the current boundary
37890  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37891  // Get the "ef"-th element on the boundary
37892  FiniteElement* el_pt = this->boundary_element_pt(bound, ef);
37893 
37894 #ifdef PARANOID
37895  bool found_global_element_index = false;
37896 #endif
37897  for (unsigned eg = 0; eg < nele; eg++)
37898  {
37899  // Get the "eg-th" element
37900  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
37901 
37902  // Compare with the element on the boundary, if equal then
37903  // store the target area
37904  if (el_pt == el_compare_pt)
37905  {
37906  zeta_target_area_values[1] = target_area[eg];
37907 #ifdef PARANOID
37908  found_global_element_index = true;
37909 #endif
37910  break; // break the for (e < nele) global element
37911  } // if element_pt == element_compare_pt
37912  } // for nele (on complete mesh)
37913 
37914 #ifdef PARANOID
37915  if (!found_global_element_index)
37916  {
37917  std::ostringstream error_message;
37918  error_message << "The global index for the (" << ef
37919  << ")-th face element "
37920  << "on\nthe (" << bound
37921  << ")-th boundary was not found!!!";
37922  throw OomphLibError(
37923  error_message.str(),
37924  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37925  OOMPH_EXCEPTION_LOCATION);
37926  }
37927 #endif
37928 
37929  // Add the target areas to the sorted set
37930  sorted_target_areas.insert(zeta_target_area_values);
37931  // ------------------------------------------------------------------
37932 
37933  // Continue iterating if a new face element has been added to the
37934  // list
37935  bool face_element_added = false;
37936 
37937  // While a new face element has been added to the set of sorted
37938  // face elements then re-iterate
37939  do
37940  {
37941  // Start from the next face elements since we have already
37942  // added the previous one as the initial face element (any
37943  // previous face element had to be added on previous
37944  // iterations)
37945  for (unsigned iiface = iface; iiface < nnon_halo_face_element;
37946  iiface++)
37947  {
37948  face_element_added = false;
37949  ele_face_pt = non_halo_face_element_pt[iiface];
37950  if (!face_element_done[ele_face_pt])
37951  {
37952  // Get each individual node to check if they are contiguous
37953  nnode = ele_face_pt->nnode();
37954  Node* left_node_pt = ele_face_pt->node_pt(0);
37955  Node* right_node_pt = ele_face_pt->node_pt(nnode - 1);
37956 
37957  if (left_node_pt == first_node_pt)
37958  {
37959  first_node_pt = right_node_pt;
37960  face_element_added = true;
37961  }
37962  else if (left_node_pt == last_node_pt)
37963  {
37964  last_node_pt = right_node_pt;
37965  face_element_added = true;
37966  }
37967  else if (right_node_pt == first_node_pt)
37968  {
37969  first_node_pt = left_node_pt;
37970  face_element_added = true;
37971  }
37972  else if (right_node_pt == last_node_pt)
37973  {
37974  last_node_pt = left_node_pt;
37975  face_element_added = true;
37976  }
37977 
37978  if (face_element_added)
37979  {
37980  // Add the left-hand node to the set:
37981  // Boundary coordinate
37982  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
37983  vertex_coord[0] = bound_left[0];
37984 
37985  // Actual coordinates
37986  for (unsigned i = 0; i < 2; i++)
37987  {
37988  vertex_coord[i + 1] = left_node_pt->x(i);
37989  }
37990  local_vertex_nodes.insert(vertex_coord);
37991 
37992  // Add the right-hand nodes to the set:
37993  // Boundary coordinate
37994  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
37995  vertex_coord[0] = bound_right[0];
37996 
37997  // Actual coordinates
37998  for (unsigned i = 0; i < 2; i++)
37999  {
38000  vertex_coord[i + 1] = right_node_pt->x(i);
38001  }
38002  local_vertex_nodes.insert(vertex_coord);
38003 
38004  // Mark as done only if one of its nodes has been
38005  // added to the list
38006  face_element_done[ele_face_pt] = true;
38007  nsorted_face_elements++;
38008 
38009  // -----------------------------------------------------
38010  // Find the global index in the mesh of the face element
38011  // and use it to get its associated target area
38012  // -----------------------------------------------------
38013  // Use the minimum zeta value to sort the target areas
38014  // along the boundary
38015  zeta_target_area_values[0] =
38016  std::min(bound_left[0], bound_right[0]);
38017 
38018  // Get the "ef"-th element on the boundary
38019  ef = face_element_index_on_boundary[ele_face_pt];
38020  FiniteElement* lel_pt = this->boundary_element_pt(bound, ef);
38021 
38022 #ifdef PARANOID
38023  found_global_element_index = false;
38024 #endif
38025  for (unsigned eg = 0; eg < nele; eg++)
38026  {
38027  // Get the "eg-th" element
38028  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
38029 
38030  // Compare with the element on the boundary, if equal then
38031  // store the target area
38032  if (lel_pt == lel_compare_pt)
38033  {
38034  zeta_target_area_values[1] = target_area[eg];
38035 #ifdef PARANOID
38036  found_global_element_index = true;
38037 #endif
38038  break; // break the for (e < nele) global element
38039  } // if element_pt == element_compare_pt
38040  } // for nele (on complete mesh)
38041 
38042 #ifdef PARANOID
38043  if (!found_global_element_index)
38044  {
38045  std::ostringstream error_message;
38046  error_message << "The global index for the (" << ef
38047  << ")-th face element "
38048  << "on\nthe (" << bound
38049  << ")-th boundary was not found!!!";
38050  throw OomphLibError(error_message.str(),
38051  "RefineableTriangleMesh::update_polygon_"
38052  "using_elements_area()",
38053  OOMPH_EXCEPTION_LOCATION);
38054  }
38055 #endif
38056 
38057  // Add the target areas to the sorted set
38058  sorted_target_areas.insert(zeta_target_area_values);
38059 
38060  break;
38061  }
38062 
38063  } // if (!edge_done[edge])
38064  } // for (iiedge < nedges)
38065  } while (face_element_added &&
38066  (nsorted_face_elements < nnon_halo_face_element));
38067 
38068  // -----------------------------------------------------------------
38069  // At this point we already have a sorted set of nodes and
38070  // can be used to peform the unrefinement and refinement procedures
38071  // -----------------------------------------------------------------
38072 
38073  // Get the number of nodes on the list
38074  const unsigned nlocal_nodes = local_vertex_nodes.size();
38075  // Change representation to vector for easy of handling ...
38076  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38077 
38078  // Copy the vertices of the nodes
38079  unsigned counter = 0;
38080  std::set<Vector<double>>::iterator it_vertex;
38081  for (it_vertex = local_vertex_nodes.begin();
38082  it_vertex != local_vertex_nodes.end();
38083  it_vertex++)
38084  {
38085  local_tmp_vector_vertex_node[counter].resize(3);
38086  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
38087  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
38088  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
38089  counter++;
38090  }
38091 
38092  // ... same for the info. related with the target areas (turn
38093  // into vector)
38094  const unsigned ntarget_areas = sorted_target_areas.size();
38095  tmp_sorted_target_areas.resize(ntarget_areas);
38096  counter = 0;
38097  std::set<Vector<double>>::iterator it_area;
38098  for (it_area = sorted_target_areas.begin();
38099  it_area != sorted_target_areas.end();
38100  ++it_area)
38101  {
38102  tmp_sorted_target_areas[counter] = (*it_area)[1];
38103  ++counter;
38104  }
38105 
38106 #ifdef PARANOID
38107  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1))
38108  {
38109  std::ostringstream error_message;
38110  error_message
38111  << "The boundary (" << bound << ") was split during the "
38112  << "distribution process.\n"
38113  << "The problem is in the association of the target areas with "
38114  "the\n"
38115  << "elements that gave rise to the vertex coordinates.\n"
38116  << "The number of local nodes (" << nlocal_nodes
38117  << "), on the 'sub-polyline', is not\n"
38118  << "according with the number of target "
38119  << "areas (" << ntarget_areas << ")\nfor that number of nodes.\n"
38120  << "The target areas number MUST be equal to the number of\n"
38121  << "local nodes minus one\n\n";
38122  throw OomphLibError(error_message.str(),
38123  OOMPH_CURRENT_FUNCTION,
38124  OOMPH_EXCEPTION_LOCATION);
38125  }
38126 #endif
38127 
38128  // -------------------------------------------------------------------
38129  // Update the vertices along the boundary using the target area
38130  // to define the distance among them
38131  // -------------------------------------------------------------------
38132 
38133  // Tolerance below which the middle point can be deleted
38134  // (ratio of deflection to element length)
38135  double unrefinement_tolerance =
38136  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38137 
38138  // Apply unrefinement
38139  bool unrefinement_applied =
38140  unrefine_boundary_constrained_by_target_area(
38141  bound,
38142  chunk,
38143  local_tmp_vector_vertex_node,
38144  unrefinement_tolerance,
38145  tmp_sorted_target_areas);
38146 
38147  // Tolerance for refinement
38148  double refinement_tolerance =
38149  polygon_pt->polyline_pt(p)->refinement_tolerance();
38150 
38151  // Apply refinement
38152  bool refinement_applied = refine_boundary_constrained_by_target_area(
38153  mesh_geom_obj_pt,
38154  local_tmp_vector_vertex_node,
38155  refinement_tolerance,
38156  tmp_sorted_target_areas);
38157 
38158  // Clear the local containter to recover the nodes ordered using the
38159  // zeta value
38160  local_vertex_nodes.clear();
38161 
38162  // At the end of each unrefinement/refinement step store the new nodes
38163  // on the set that will give rise to the vertices of the new polyline
38164  // representation
38165  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
38166  for (unsigned i = 0; i < nnew_nodes; i++)
38167  {
38168  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
38169  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
38170  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
38171  vertex_nodes.insert(vertex_coord); // Global container
38172  local_vertex_nodes.insert(vertex_coord);
38173  }
38174 
38175  // Update the flag to indicate whether an unrefinement or
38176  // refinement was applied
38177  update_was_performed = (unrefinement_applied || refinement_applied);
38178 
38179 #ifdef OOMPH_HAS_MPI
38180  if (this->is_mesh_distributed())
38181  {
38182  // Add the set of vertices for the boundary, this will help to
38183  // detect if we need to deal with sub-boundaries
38184  sub_vertex_nodes.push_back(local_vertex_nodes);
38185  // Increase the counter for sub-boundaries
38186  nsub_boundaries++;
38187  }
38188 #endif
38189 
38190  } // while(nsorted_face_elements < nnon_halo_face_element)
38191 
38192  // Now turn into vector for ease of handling...
38193  unsigned npoly_vertex = vertex_nodes.size();
38194  // This will store all the vertices whether the boundary was split
38195  // or not
38196  tmp_vector_vertex_node.resize(npoly_vertex);
38197  unsigned count = 0;
38198  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
38199  it != vertex_nodes.end();
38200  ++it)
38201  {
38202  tmp_vector_vertex_node[count].resize(3);
38203  tmp_vector_vertex_node[count][0] = (*it)[0];
38204  tmp_vector_vertex_node[count][1] = (*it)[1];
38205  tmp_vector_vertex_node[count][2] = (*it)[2];
38206  ++count;
38207  }
38208 
38209 #ifdef OOMPH_HAS_MPI
38210  // --------- Stuff for the sub_boundaries ----- Begin section ---------
38211 #ifdef PARANOID
38212  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
38213  if (nsub_boundaries_set != nsub_boundaries)
38214  {
38215  std::ostringstream error_message;
38216  error_message
38217  << "The number of found sub-boundaries and the number of counted\n"
38218  << "sub-boundaries are different:\n"
38219  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
38220  << "Number of counted sub-boundaries: (" << nsub_boundaries << ")\n";
38221  throw OomphLibError(error_message.str(),
38222  OOMPH_CURRENT_FUNCTION,
38223  OOMPH_EXCEPTION_LOCATION);
38224  }
38225 #endif
38226 
38227  // Are there sub-boundaries (only appear in distributed meshes)
38228  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38229  {
38230  // Mark the boundary as been splitted in the partition process
38231  this->Boundary_was_splitted[bound] = true;
38232  // Resize the vector to store the info. of sub-boundaries
38233  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
38234  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38235  {
38236  // Turn info. into vector for ease of handling...
38237  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
38238  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
38239  unsigned subcount = 0;
38240  std::set<Vector<double>>::iterator subit;
38241  for (subit = sub_vertex_nodes[isub].begin();
38242  subit != sub_vertex_nodes[isub].end();
38243  ++subit)
38244  {
38245  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
38246  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
38247  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
38248  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
38249  ++subcount;
38250  }
38251  }
38252  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38253  // --------- Stuff for the sub_boundaries ----- End section ------------
38254 #endif // OOMPH_HAS_MPI
38255 
38256  // For further processing the three-dimensional vector has to be
38257  // reduced to a two-dimensional vector
38258  unsigned n_vertex = tmp_vector_vertex_node.size();
38259 
38260  // Resize the vector for vectices
38261  vector_vertex_node.resize(n_vertex);
38262  for (unsigned i = 0; i < n_vertex; i++)
38263  {
38264  vector_vertex_node[i].resize(2);
38265  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
38266  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
38267  }
38268 
38269 #ifdef OOMPH_HAS_MPI
38270  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38271  // Verify if need to deal with sub_boundaries
38272  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38273  {
38274  // For further processing the three-dimensional vector
38275  // has to be reduced to a two-dimensional vector
38276  // Resize the vector to store the info. of sub-boundaries
38277  sub_vector_vertex_node.resize(nsub_boundaries);
38278  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38279  {
38280  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
38281  // Resize the vector for vectices
38282  sub_vector_vertex_node[isub].resize(subn_vertex);
38283  for (unsigned i = 0; i < subn_vertex; i++)
38284  {
38285  sub_vector_vertex_node[isub][i].resize(2);
38286  sub_vector_vertex_node[isub][i][0] =
38287  sub_tmp_vector_vertex_node[isub][i][1];
38288  sub_vector_vertex_node[isub][i][1] =
38289  sub_tmp_vector_vertex_node[isub][i][2];
38290  }
38291  }
38292  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38293 
38294  // We already have the info. for the sub-boundaries (if necessary)
38295  // and then we can create the sub-boundaries representations to
38296  // ease the generation of the mesh by Triangle
38297 
38298  // --------- Stuff for the sub_boundaries ----- End section ------------
38299 #endif // OOMPH_HAS_MPI
38300 
38301  // --------------------------------------------------------------------
38302  // Check for contiguousness
38303  // --------------------------------------------------------------------
38304 #ifdef OOMPH_HAS_MPI
38305  // Only perform this checking if the mesh is not distributed. When
38306  // the mesh is distributed the polylines continuity is addressed
38307  // by the sort_polylines_helper() method
38308  if (!this->is_mesh_distributed())
38309 #endif
38310  {
38311  if (p > 0)
38312  {
38313  // Final end point of previous line
38314  Vector<double> final_vertex_of_previous_segment;
38315  unsigned n_prev_vertex =
38316  polygon_pt->curve_section_pt(p - 1)->nvertex();
38317  final_vertex_of_previous_segment =
38318  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
38319  1);
38320 
38321  unsigned prev_seg_boundary_id =
38322  polygon_pt->curve_section_pt(p - 1)->boundary_id();
38323 
38324  // Find the error between the final vertex of the previous
38325  // line and the first vertex of the current line
38326  double error = 0.0;
38327  for (unsigned i = 0; i < 2; i++)
38328  {
38329  const double dist = final_vertex_of_previous_segment[i] -
38330  (*vector_vertex_node.begin())[i];
38331  error += dist * dist;
38332  }
38333  error = sqrt(error);
38334 
38335  // If the error is bigger than the tolerance then
38336  // we probably need to reverse, but better check
38337  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38338  {
38339  // Find the error between the final vertex of the previous
38340  // line and the last vertex of the current line
38341  double rev_error = 0.0;
38342  for (unsigned i = 0; i < 2; i++)
38343  {
38344  const double dist = final_vertex_of_previous_segment[i] -
38345  (*--vector_vertex_node.end())[i];
38346  rev_error += dist * dist;
38347  }
38348  rev_error = sqrt(rev_error);
38349 
38350  if (rev_error >
38351  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38352  {
38353  // It could be possible that the first segment be reversed
38354  // and we did not notice it because this check does not
38355  // apply for the first segment. We can verify if the first
38356  // segment is reversed by using the vertex number 1
38357  if (p == 1)
38358  {
38359  // Initial end point of previous line
38360  Vector<double> initial_vertex_of_previous_segment;
38361 
38362  initial_vertex_of_previous_segment =
38363  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
38364 
38365  unsigned prev_seg_boundary_id =
38366  polygon_pt->curve_section_pt(p - 1)->boundary_id();
38367 
38368  // Find the error between the initial vertex of the previous
38369  // line and the first vertex of the current line
38370  double error = 0.0;
38371  for (unsigned i = 0; i < 2; i++)
38372  {
38373  const double dist = initial_vertex_of_previous_segment[i] -
38374  (*vector_vertex_node.begin())[i];
38375  error += dist * dist;
38376  }
38377  error = sqrt(error); // Reversed only the previous one
38378 
38379  // If the error is bigger than the tolerance then
38380  // we probably need to reverse, but better check
38381  if (error >
38382  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38383  {
38384  // Find the error between the final vertex of the previous
38385  // line and the last vertex of the current line
38386  double rev_error = 0.0;
38387  for (unsigned i = 0; i < 2; i++)
38388  {
38389  const double dist = initial_vertex_of_previous_segment[i] -
38390  (*--vector_vertex_node.end())[i];
38391  rev_error += dist * dist;
38392  }
38393  rev_error =
38394  sqrt(rev_error); // Reversed both the current one and
38395  // the previous one
38396 
38397  if (rev_error >
38398  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38399  {
38400  std::ostringstream error_stream;
38401  error_stream
38402  << "The distance between the first node of the current\n"
38403  << "line segment (boundary " << bound
38404  << ") and either end of "
38405  << "the previous line segment\n"
38406  << "(boundary " << prev_seg_boundary_id
38407  << ") is bigger than "
38408  << "the desired tolerance "
38409  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38410  << ".\n"
38411  << "This suggests that the polylines defining the "
38412  << "polygonal\n"
38413  << "representation are not properly ordered.\n"
38414  << "Fail on last vertex of polyline: ("
38415  << prev_seg_boundary_id << ") and\n"
38416  << "first vertex of polyline (" << bound << ").\n"
38417  << "This should have failed when first trying to "
38418  << "construct the\npolygon.\n";
38419  throw OomphLibError(error_stream.str(),
38420  OOMPH_CURRENT_FUNCTION,
38421  OOMPH_EXCEPTION_LOCATION);
38422  }
38423  else
38424  {
38425  // Reverse both
38426  // Reverse the current vector to line up with the
38427  // previous one
38428  std::reverse(vector_vertex_node.begin(),
38429  vector_vertex_node.end());
38430 
38431  polygon_pt->polyline_pt(p - 1)->reverse();
38432  }
38433  }
38434  else
38435  {
38436  // Reverse the previous one
38437  polygon_pt->polyline_pt(p - 1)->reverse();
38438  }
38439 
38440  } // if p == 1
38441  else
38442  {
38443  std::ostringstream error_stream;
38444  error_stream
38445  << "The distance between the first node of the current\n"
38446  << "line segment (boundary " << bound
38447  << ") and either end of "
38448  << "the previous line segment\n"
38449  << "(boundary " << prev_seg_boundary_id
38450  << ") is bigger than the "
38451  << "desired tolerance "
38452  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38453  << ".\n"
38454  << "This suggests that the polylines defining the polygonal\n"
38455  << "representation are not properly ordered.\n"
38456  << "Fail on last vertex of polyline: ("
38457  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
38458  << bound << ").\n"
38459  << "This should have failed when first trying to construct"
38460  << " the polygon.\n";
38461  throw OomphLibError(error_stream.str(),
38462  OOMPH_CURRENT_FUNCTION,
38463  OOMPH_EXCEPTION_LOCATION);
38464  }
38465  }
38466  else
38467  {
38468  // Reverse the current vector to line up with the previous one
38469  std::reverse(vector_vertex_node.begin(),
38470  vector_vertex_node.end());
38471  }
38472  } // error
38473 
38474  } // if ( p > 0 )
38475 
38476  } // if (!this->is_mesh_distributed())
38477 
38478  // --------------------------------------------------------------------
38479  // Update the polylines representation
38480  // --------------------------------------------------------------------
38481 
38482  // Always update the polylines representation, in a distributed
38483  // mesh it is necessary to update the polyline representation since
38484  // it may no longer have vertices (the boundary may not be part of
38485  // the domain in the current processor)
38486 
38487  // The new nunber of vertices
38488  n_vertex = vector_vertex_node.size();
38489 
38490  // Now update the polyline according to the new vertices
38491  TriangleMeshPolyLine* tmp_polyline_pt =
38492  new TriangleMeshPolyLine(vector_vertex_node, bound);
38493 
38494  // Create a temporal "curve section" version of the recently
38495  // created polyline
38496  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
38497 
38498  // Tolerance below which the middle point can be deleted (ratio of
38499  // deflection to element length)
38500  double unrefinement_tolerance =
38501  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38502 
38503  // Tolerance to add points
38504  double refinement_tolerance =
38505  polygon_pt->polyline_pt(p)->refinement_tolerance();
38506 
38507  // Establish refinement and unrefinement tolerance
38508  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38509  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38510 
38511  // Establish the maximum length constraint
38512  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38513  tmp_polyline_pt->set_maximum_length(maximum_length);
38514 
38515 #ifdef OOMPH_HAS_MPI
38516  // If the mesh is distributed check that the polyline still has
38517  // vertices
38518  if (this->is_mesh_distributed())
38519  {
38520  if (n_vertex >= 2)
38521  {
38522  // Pass the connection information from the old polyline to the
38523  // new one
38524  this->copy_connection_information(polygon_pt->polyline_pt(p),
38525  tmp_curve_section_pt);
38526  } // if (n_vertex >= 2)
38527  } // if (this->is_mesh_distributed())
38528  else
38529 #endif
38530  {
38531  // Pass the connection information from the old polyline to the
38532  // new one
38533  this->copy_connection_information(polygon_pt->polyline_pt(p),
38534  tmp_curve_section_pt);
38535  }
38536 
38537  // Now update the polyline according to the new vertices but first
38538  // check if the object is allowed to delete the representation or
38539  // if it should be done by other object
38540  bool delete_it_on_destructor = false;
38541 
38542  std::set<TriangleMeshCurveSection*>::iterator it =
38543  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38544 
38545  if (it != this->Free_curve_section_pt.end())
38546  {
38547  this->Free_curve_section_pt.erase(it);
38548  delete polygon_pt->curve_section_pt(p);
38549  delete_it_on_destructor = true;
38550  }
38551 
38552  // -------------------------------------------------------
38553  // Copying the new representation
38554  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38555 
38556  // Update the Boundary - Polyline map
38557  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38558 
38559  if (delete_it_on_destructor)
38560  {
38561  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38562  }
38563 
38564 #ifdef OOMPH_HAS_MPI
38565  // --------- Stuff for the sub_boundaries ----- Begin section --------
38566  // Verify if need to deal with sub_boundaries
38567  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38568  {
38569  // Create temporary representations for the boundaries, only to
38570  // create the mesh when calling Triangle
38571 
38572  // Clear all previous stored data
38573  this->Boundary_subpolylines[bound].clear();
38574 
38575  // Create storage for the sub-boundaries
38576  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38577  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38578  {
38579  // Update the polyline according to the sub set of vertices,
38580  TriangleMeshPolyLine* sub_tmp_polyline_pt =
38581  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38582 
38583  // Add the sub-polyline to the container to represent the
38584  // boundary in parts
38585  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38586 
38587  // No need to send the unrefinement/refinement and maximum
38588  // length constraints since these are only temporary
38589  // representations. These polylines can be deleted once the new
38590  // polygons that represent the distributed domain have been
38591  // created
38592 
38593  } // for (isub < nsub_boundaries)
38594 
38595  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38596  // --------- Stuff for the sub_boundaries ----- End section ---------
38597 #endif // OOMPH_HAS_MPI
38598 
38599  // Delete the allocated memory for the geometric object that
38600  // represents the boundary
38601  delete mesh_geom_obj_pt;
38602 
38603  } // for (p < n_polyline)
38604 
38605  // Cleanup the face mesh
38606  for (unsigned p = 0; p < n_polyline; p++)
38607  {
38608  face_mesh_pt[p]->flush_node_storage();
38609  delete face_mesh_pt[p];
38610  }
38611 
38612  return update_was_performed;
38613  }
38614 
38615  //======================================================================
38616  /// Updates the open curve but using the elements area instead
38617  /// of the default refinement and unrefinement methods
38618  //======================================================================
38619  template<class ELEMENT>
38621  TriangleMeshOpenCurve*& open_curve_pt, const Vector<double>& target_area)
38622  {
38623  // Verify if there was a change on the open curve representation
38624  unsigned update_was_performed = false;
38625 
38626  const unsigned nele = this->nelement();
38627 
38628  // - Get the vertices along the boundaries and for each element identify
38629  // its associated target error.
38630  // - Get face mesh representation of each polyline.
38631  // - Get the vertices with the help of face elements.
38632  // - Find the global index in the mesh of the face element
38633  // and use it to get its associated target area.
38634 
38635  // Get the face mesh representation
38636  Vector<Mesh*> face_mesh_pt;
38637  get_face_mesh_representation(open_curve_pt, face_mesh_pt);
38638 
38639  // Create vertices of the polylines by using the vertices of the
38640  // FaceElements
38641  Vector<double> vertex_coord(3); // zeta,x,y
38642  Vector<double> bound_left(1);
38643  Vector<double> bound_right(1);
38644 
38645  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38646 
38647  // Go for each curve section
38648  for (unsigned cs = 0; cs < ncurve_section; cs++)
38649  {
38650  // Get the MeshAsGeomObject representation just once per polyline,
38651  // this object is only used by the
38652  // refine_boundary_constrained_by_target_area() method. We get it
38653  // here to ensure that all processors (in a distributed context)
38654  // get this representation just once, and because an AllToAll MPI
38655  // communication is used in this calling
38656  MeshAsGeomObject* mesh_geom_obj_pt =
38657  new MeshAsGeomObject(face_mesh_pt[cs]);
38658 
38659  // Get the boundary id
38660  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
38661 
38662  // Get the chunk number
38663  const unsigned chunk =
38664  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38665 
38666  /// Use a vector of vector for vertices and target areas to deal
38667  /// with the cases when the boundaries are split by the
38668  /// distribution process. Internal boundaries may be completely or
38669  /// partially overlapped by shared boundaries
38670 
38671  // Loop over the face elements and add their vertices (they are
38672  // automatically sorted because of the set)
38673  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38674 
38675  // Store the non halo elements and the element at the other side of
38676  // the boundary (whatever it be halo or not), the first will be the
38677  // ones from which we will get the vertices (in even position)
38678  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38679 
38680  // Map to store the index of the face element on a boundary
38681  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
38682 
38683  // Map to know the already sorted face elements
38684  std::map<FiniteElement*, bool> face_element_done;
38685 
38686  for (unsigned ef = 0; ef < nface_element; ++ef)
38687  {
38688  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38689 
38690  // Skip the halo elements (not used as base elements, only
38691  // include those elements whose element at the other side of the
38692  // boundary is non halo)
38693 #ifdef OOMPH_HAS_MPI
38694  if (this->is_mesh_distributed())
38695  {
38696  // Only work with non-halo elements
38697  if (ele_face_pt->is_halo())
38698  {
38699  continue;
38700  }
38701  }
38702 #endif
38703 
38704  // Check if not already done
38705  if (!face_element_done[ele_face_pt])
38706  {
38707  // Add the element and look for the element at the other side
38708  // of the boundary to add it immediately after the new added
38709  // element
38710  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38711  // Create the map of the face element with the index
38712  face_element_index_on_boundary[ele_face_pt] = ef;
38713  // Mark the current element as done
38714  face_element_done[ele_face_pt] = true;
38715  // Get the number of nodes
38716  const unsigned nnodes = ele_face_pt->nnode();
38717  // Get the left and right node to look for the elements at the
38718  // other side of the boundary
38719  Node* left_node_pt = ele_face_pt->node_pt(0);
38720  Node* right_node_pt = ele_face_pt->node_pt(nnodes - 1);
38721 #ifdef PARANOID
38722  // Flag to know if the element at the other side of the
38723  // boundary was found
38724  bool found_other_side_face_ele = false;
38725 #endif
38726  for (unsigned iface = 0; iface < nface_element; iface++)
38727  {
38728  // Get the candidate face element
38729  FiniteElement* cele_face_pt =
38730  face_mesh_pt[cs]->finite_element_pt(iface);
38731  // Check if not already done
38732  if (!face_element_done[cele_face_pt])
38733  {
38734  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38735  Node* cright_node_pt = cele_face_pt->node_pt(nnodes - 1);
38736  // Check if the nodes are the same
38737  if ((left_node_pt == cleft_node_pt &&
38738  right_node_pt == cright_node_pt) ||
38739  (left_node_pt == cright_node_pt &&
38740  right_node_pt == cleft_node_pt))
38741  {
38742  // Add the element to the storage
38743  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38744  // ... and mark the element as done
38745  face_element_done[cele_face_pt] = true;
38746  // Create the map of the face element with the index
38747  face_element_index_on_boundary[cele_face_pt] = iface;
38748 #ifdef PARANOID
38749  // Set the flag of found other side face element
38750  found_other_side_face_ele = true;
38751 #endif
38752  break;
38753  }
38754  }
38755  } // (iface < nface_element)
38756 
38757 #ifdef PARANOID
38758  if (!found_other_side_face_ele)
38759  {
38760  std::ostringstream error_message;
38761  error_message
38762  << "The face element at the other side of the boundary (" << bound
38763  << ") was not found!!\n"
38764  << "These are the nodes of the face element:\n"
38765  << "(" << left_node_pt->x(0) << ", " << left_node_pt->x(1) << ") "
38766  << "and (" << right_node_pt->x(0) << "," << right_node_pt->x(1)
38767  << ")\n\n";
38768  throw OomphLibError(
38769  error_message.str(),
38770  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38771  OOMPH_EXCEPTION_LOCATION);
38772  }
38773 #endif
38774  } // if (!face_ele_done[ele_face_pt])
38775 
38776  } // (ef < nface_element)
38777 
38778  // Clear the map of the already done face elements
38779  // This will be used to help sorting the face elements
38780  face_element_done.clear();
38781 
38782  // Set of coordinates that are on the boundary
38783  // The entries are sorted on first entry in vector which stores
38784  // the boundary coordinate so the vertices come out in order!
38785  std::set<Vector<double>> vertex_nodes;
38786 
38787  // Vector to store the vertices, transfer the sorted vertices from the
38788  // set to this vector, --- including the z-value ---
38789  Vector<Vector<double>> tmp_vector_vertex_node;
38790 
38791  // Vector to store the coordinates of the polylines, same as the
38792  // tmp_vector_vertex_node vector (after adding more nodes) but
38793  // --- without the z-value ---, used to re-generate the polylines
38794  Vector<Vector<double>> vector_vertex_node;
38795 
38796 #ifdef OOMPH_HAS_MPI
38797  // Indicates if the set of vertices give rise to a internal
38798  // boundary that will be used as shared boundary or as normal
38799  // internal boundary -- Only used to deal with internal boundaries
38800  // in a distributed scheme
38801  std::vector<bool> internal_to_shared_boundary;
38802 
38803  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38804  // Set of coordinates that are on the boundary (splitted boundary version)
38805  // The first vector is used to allocate the points for each sub-boundary
38806  // Set entries are ordered on first entry in vector which stores
38807  // the boundary coordinate so the vertices come out in order!
38808  Vector<std::set<Vector<double>>> sub_vertex_nodes;
38809 
38810  // Vector to store the vertices, transfer the sorted vertices from the
38811  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38812  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
38813 
38814  // Vector to store the coordinates of the polylines that will represent
38815  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38816  // but --- without the z-value ---, used to generate the sub-polylines
38817  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
38818 
38819  // --------- Stuff to deal with splitted boundaries ----------- End ------
38820 
38821 #endif // #ifdef OOMPH_HAS_MPI
38822 
38823  // Sort the face element, those that have both elements (one at
38824  // each side of the boundary) marked as nonhalo, and those with one
38825  // nonhalo an the other as halo
38826 
38827  // Number of done face elements
38828  unsigned nsorted_face_elements = 0;
38829 
38830 #ifdef OOMPH_HAS_MPI
38831  // Counter for sub_boundaries
38832  unsigned nsub_boundaries = 0;
38833 #endif // #ifdef OOMPH_HAS_MPI
38834 
38835  // Total number of non halo double face element
38836  const unsigned nnon_halo_doubled_face_ele =
38837  non_halo_doubled_face_element_pt.size();
38838 
38839  // Continue until all the face elements have been sorted
38840  // This while is to deal with the cases of splitted boundaries
38841  while (nsorted_face_elements < nnon_halo_doubled_face_ele)
38842  {
38843  // Get and initial face element
38844  FiniteElement* ele_face_pt = 0;
38845  FiniteElement* repeated_ele_face_pt = 0;
38846 #ifdef PARANOID
38847  bool found_initial_face_element = false;
38848 #endif
38849 
38850  // Flag to know if we are working with a face element which the
38851  // face element at the other side of the boundary is also non
38852  // halo
38853  bool both_root_face_elements_are_nonhalo = false;
38854 
38855  unsigned iface = 0;
38856  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface += 2)
38857  {
38858  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38859  // If not done then take it as initial face element
38860  if (!face_element_done[ele_face_pt])
38861  {
38862  // Mark it as done
38863  face_element_done[ele_face_pt] = true;
38864  // Get the other side boundary face element
38865  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface + 1];
38866  // ... also mark as done the repeated face element
38867  face_element_done[repeated_ele_face_pt] = true;
38868 
38869 #ifdef OOMPH_HAS_MPI
38870  if (!repeated_ele_face_pt->is_halo())
38871  {
38872  both_root_face_elements_are_nonhalo = true;
38873  }
38874 #endif // #ifdef OOMPH_HAS_MPI
38875 
38876  // Plus two because internal boundaries have
38877  // two face elements per each edge
38878  nsorted_face_elements += 2;
38879  iface += 2;
38880 #ifdef PARANOID
38881  // And set the flag to true
38882  found_initial_face_element = true;
38883 #endif
38884  break;
38885  }
38886  }
38887 
38888 #ifdef PARANOID
38889  if (!found_initial_face_element)
38890  {
38891  std::ostringstream error_message;
38892  error_message << "Could not find an initial face element for the "
38893  "current segment\n";
38894  throw OomphLibError(error_message.str(),
38895  OOMPH_CURRENT_FUNCTION,
38896  OOMPH_EXCEPTION_LOCATION);
38897  }
38898 #endif
38899 
38900  // Local set of coordinates that are on the boundary Set entries
38901  // are ordered on first entry in vector which stores the boundary
38902  // coordinate so the vertices come out in order
38903  std::set<Vector<double>> local_vertex_nodes;
38904 
38905  // Vector to store the vertices, transfer the sorted vertices from the
38906  // set (local) to this vector (local), --- including the z-value ---
38907  Vector<Vector<double>> local_tmp_vector_vertex_node;
38908 
38909  // Vector to store the target areas, uses the same approach as the
38910  // set for the local_vertex_nodes, ordered on first entry
38911  std::set<Vector<double>> sorted_target_areas;
38912 
38913  // Vector to store the target areas, used to transfer the sorted target
38914  // areas from "sorted_target_areas" set
38915  Vector<double> tmp_sorted_target_areas;
38916 
38917  // ------------------------------------------------------------------
38918  // Add the vertices of the initial face element to the set of local
38919  // sorted vertices
38920  // ------------------------------------------------------------------
38921  const unsigned nnode = ele_face_pt->nnode();
38922  // Add the left-hand node to the set:
38923  // Boundary coordinate
38924  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
38925  vertex_coord[0] = bound_left[0];
38926 
38927  // Actual coordinates
38928  for (unsigned i = 0; i < 2; i++)
38929  {
38930  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
38931  }
38932  local_vertex_nodes.insert(vertex_coord);
38933 
38934  // Add the right-hand node to the set:
38935  // Boundary coordinate
38936  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
38937  bound, bound_right);
38938  vertex_coord[0] = bound_right[0];
38939 
38940  // Actual coordinates
38941  for (unsigned i = 0; i < 2; i++)
38942  {
38943  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
38944  }
38945  local_vertex_nodes.insert(vertex_coord);
38946 
38947  // The initial and final node on the set
38948  Node* first_node_pt = ele_face_pt->node_pt(0);
38949  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
38950 
38951  // -----------------------------------------------------
38952  // Find the global index in the mesh of the face element
38953  // and use it to get its associated target area
38954  // -----------------------------------------------------
38955  // Container to store the zeta value (used as index) and
38956  // the associated target area of the element
38957  Vector<double> zeta_target_area_values(2);
38958 
38959  // Use the minimum zeta value to sort the target areas
38960  // along the boundary
38961  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38962 
38963  // Get the index of the face element on the current boundary
38964  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38965  // Get the "ef"-th element on the boundary
38966  FiniteElement* el_pt = this->boundary_element_pt(bound, ef);
38967  double target_area_face_element = 0.0;
38968 
38969 #ifdef PARANOID
38970  bool found_global_element_index = false;
38971 #endif
38972  for (unsigned eg = 0; eg < nele; eg++)
38973  {
38974  // Get the "eg-th" element
38975  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
38976 
38977  // Compare with the element on the boundary, if equal then
38978  // store the target area
38979  if (el_pt == el_compare_pt)
38980  {
38981  target_area_face_element = target_area[eg];
38982 #ifdef PARANOID
38983  found_global_element_index = true;
38984 #endif
38985  break; // break the for (eg < nele) global element
38986  } // if el_pt == el_compare_pt
38987  } // for nele (on complete mesh)
38988 
38989 #ifdef PARANOID
38990  if (!found_global_element_index)
38991  {
38992  std::ostringstream error_message;
38993  error_message << "The global index for the (" << ef
38994  << ")-th face element "
38995  << "on\nthe (" << bound
38996  << ")-th boundary was not found!!!";
38997  throw OomphLibError(error_message.str(),
38998  OOMPH_CURRENT_FUNCTION,
38999  OOMPH_EXCEPTION_LOCATION);
39000  }
39001 #endif
39002 
39003  // Get the index of the repeated face element on the current boundary
39004  const unsigned ref =
39005  face_element_index_on_boundary[repeated_ele_face_pt];
39006  FiniteElement* rel_pt = this->boundary_element_pt(bound, ref);
39007  double target_area_repeated_face_element = 0.0;
39008 
39009 #ifdef PARANOID
39010  bool found_global_repeated_element_index = false;
39011 #endif
39012  for (unsigned eg = 0; eg < nele; eg++)
39013  {
39014  // Get the "eg-th" element
39015  FiniteElement* el_compare_pt = this->finite_element_pt(eg);
39016 
39017  // Compare with the element on the boundary, if equal then
39018  // store the target area
39019  if (rel_pt == el_compare_pt)
39020  {
39021  target_area_repeated_face_element = target_area[eg];
39022 #ifdef PARANOID
39023  found_global_repeated_element_index = true;
39024 #endif
39025  break; // break the for (eg < nele) global element
39026  } // if rel_pt == el_compare_pt
39027  } // for nele (on complete mesh)
39028 
39029 #ifdef PARANOID
39030  if (!found_global_repeated_element_index)
39031  {
39032  std::ostringstream error_message;
39033  error_message << "The global index for the (" << ref
39034  << ")-th face element "
39035  << "on\nthe (" << bound
39036  << ")-th boundary was not found (repeated "
39037  << "face element)!!!";
39038  throw OomphLibError(error_message.str(),
39039  OOMPH_CURRENT_FUNCTION,
39040  OOMPH_EXCEPTION_LOCATION);
39041  }
39042 #endif
39043 
39044  // Choose the minimum target area from both elements, one at each side
39045  // of the edge on the boundary
39046  zeta_target_area_values[1] =
39047  std::min(target_area_face_element, target_area_repeated_face_element);
39048 
39049  // Add the target areas to the sorted set
39050  sorted_target_areas.insert(zeta_target_area_values);
39051  // ------------------------------------------------------------------
39052 
39053  // Continue iterating if a new face element has been added to the
39054  // list
39055  bool face_element_added = false;
39056 
39057  // While a new face element has been added to the set of sorted
39058  // face elements then re-iterate
39059  do
39060  {
39061  // Start from the next face elements since we have already
39062  // added the previous one as the initial face element (any
39063  // previous face element had to be added on previous
39064  // iterations)
39065  for (unsigned iiface = iface; iiface < nnon_halo_doubled_face_ele;
39066  iiface += 2)
39067  {
39068  face_element_added = false;
39069  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
39070 
39071  // Check that the face element with which we are working has
39072  // the same conditions as the root face element (both faces
39073  // are nonhalo or one face is halo and the other nonhalo)
39074 
39075  // Get the face element at the other side of the boundary
39076  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface + 1];
39077  bool both_face_elements_are_nonhalo = false;
39078 
39079 #ifdef OOMPH_HAS_MPI
39080  if (!repeated_ele_face_pt->is_halo())
39081  {
39082  both_face_elements_are_nonhalo = true;
39083  }
39084 #endif // #ifdef OOMPH_HAS_MPI
39085 
39086  if (!face_element_done[ele_face_pt] &&
39087  (both_face_elements_are_nonhalo ==
39088  both_root_face_elements_are_nonhalo))
39089  {
39090  // Get each individual node to check if they are contiguous
39091  const unsigned nlnode = ele_face_pt->nnode();
39092  Node* left_node_pt = ele_face_pt->node_pt(0);
39093  Node* right_node_pt = ele_face_pt->node_pt(nlnode - 1);
39094 
39095  if (left_node_pt == first_node_pt)
39096  {
39097  first_node_pt = right_node_pt;
39098  face_element_added = true;
39099  }
39100  else if (left_node_pt == last_node_pt)
39101  {
39102  last_node_pt = right_node_pt;
39103  face_element_added = true;
39104  }
39105  else if (right_node_pt == first_node_pt)
39106  {
39107  first_node_pt = left_node_pt;
39108  face_element_added = true;
39109  }
39110  else if (right_node_pt == last_node_pt)
39111  {
39112  last_node_pt = left_node_pt;
39113  face_element_added = true;
39114  }
39115 
39116  if (face_element_added)
39117  {
39118  // Add the left-hand node to the set:
39119  // Boundary coordinate
39120  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
39121  vertex_coord[0] = bound_left[0];
39122 
39123  // Actual coordinates
39124  for (unsigned i = 0; i < 2; i++)
39125  {
39126  vertex_coord[i + 1] = left_node_pt->x(i);
39127  }
39128  local_vertex_nodes.insert(vertex_coord);
39129 
39130  // Add the right-hand nodes to the set:
39131  // Boundary coordinate
39132  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
39133  vertex_coord[0] = bound_right[0];
39134 
39135  // Actual coordinates
39136  for (unsigned i = 0; i < 2; i++)
39137  {
39138  vertex_coord[i + 1] = right_node_pt->x(i);
39139  }
39140  local_vertex_nodes.insert(vertex_coord);
39141 
39142  // Mark as done only if one of its nodes has been
39143  // added to the list
39144  face_element_done[ele_face_pt] = true;
39145  // .. also mark as done the face element at the othe side of
39146  // the boundary
39147  repeated_ele_face_pt =
39148  non_halo_doubled_face_element_pt[iiface + 1];
39149  face_element_done[repeated_ele_face_pt] = true;
39150  // ... and increase the number of sorted face elements
39151  nsorted_face_elements += 2;
39152 
39153  // -----------------------------------------------------
39154  // Find the global index in the mesh of the face element
39155  // and use it to get its associated target area
39156  // -----------------------------------------------------
39157  // Use the minimum zeta value to sort the target areas
39158  // along the boundary
39159  zeta_target_area_values[0] =
39160  std::min(bound_left[0], bound_right[0]);
39161 
39162  // Get the "ef"-th element on the boundary
39163  const unsigned lef =
39164  face_element_index_on_boundary[ele_face_pt];
39165  FiniteElement* lel_pt = this->boundary_element_pt(bound, lef);
39166 
39167 #ifdef PARANOID
39168  found_global_element_index = false;
39169 #endif
39170  for (unsigned eg = 0; eg < nele; eg++)
39171  {
39172  // Get the "eg-th" element
39173  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
39174 
39175  // Compare with the element on the boundary, if equal then
39176  // store the target area
39177  if (lel_pt == lel_compare_pt)
39178  {
39179  target_area_face_element = target_area[eg];
39180 #ifdef PARANOID
39181  found_global_element_index = true;
39182 #endif
39183  break; // break the for (eg < nele) global element
39184  } // if lel_pt == lel_compare_pt
39185  } // for nele (on complete mesh)
39186 
39187 #ifdef PARANOID
39188  if (!found_global_element_index)
39189  {
39190  std::ostringstream error_message;
39191  error_message << "The global index for the (" << lef
39192  << ")-th face element "
39193  << "on\nthe (" << bound
39194  << ")-th boundary was not found!!!";
39195  throw OomphLibError(error_message.str(),
39196  OOMPH_CURRENT_FUNCTION,
39197  OOMPH_EXCEPTION_LOCATION);
39198  }
39199 #endif
39200 
39201  // Get the index of the repeated face element on the boundary
39202  const unsigned rlef =
39203  face_element_index_on_boundary[repeated_ele_face_pt];
39204  FiniteElement* rlel_pt = this->boundary_element_pt(bound, rlef);
39205 
39206 #ifdef PARANOID
39207  found_global_repeated_element_index = false;
39208 #endif
39209  for (unsigned eg = 0; eg < nele; eg++)
39210  {
39211  // Get the "eg-th" element
39212  FiniteElement* lel_compare_pt = this->finite_element_pt(eg);
39213 
39214  // Compare with the element on the boundary, if equal then
39215  // store the target area
39216  if (rlel_pt == lel_compare_pt)
39217  {
39218  target_area_repeated_face_element = target_area[eg];
39219 #ifdef PARANOID
39220  found_global_repeated_element_index = true;
39221 #endif
39222  break; // break the for (eg < nele) global element
39223  } // if rlel_pt == el_compare_pt
39224  } // for nele (on complete mesh)
39225 
39226 #ifdef PARANOID
39227  if (!found_global_repeated_element_index)
39228  {
39229  std::ostringstream error_message;
39230  error_message << "The global index for the (" << rlef
39231  << ")-th face element "
39232  << "on\nthe (" << bound
39233  << ")-th boundary was not found "
39234  << "(repeated face element)!!!";
39235  throw OomphLibError(error_message.str(),
39236  OOMPH_CURRENT_FUNCTION,
39237  OOMPH_EXCEPTION_LOCATION);
39238  }
39239 #endif
39240 
39241  // Choose the minimum target area from both elements, one
39242  // at each side of the edge on the boundary
39243  zeta_target_area_values[1] = std::min(
39244  target_area_face_element, target_area_repeated_face_element);
39245 
39246  // Add the target areas to the sorted set
39247  sorted_target_areas.insert(zeta_target_area_values);
39248 
39249  break;
39250  }
39251 
39252  } // if (!face_element_done[[ele_face_pt])
39253  } // for (iiface<nnon_halo_doubled_face_ele)
39254  } while (face_element_added &&
39255  (nsorted_face_elements < nnon_halo_doubled_face_ele));
39256 
39257  // -------------------------------------------------------------
39258  // At this point we already have a sorted set of nodes and can
39259  // be used to peform the unrefinement and refinement procedures
39260  // -------------------------------------------------------------
39261 
39262  // Get the number of nodes on the list
39263  const unsigned nlocal_nodes = local_vertex_nodes.size();
39264  // Change representation to vector for easy of handling ...
39265  local_tmp_vector_vertex_node.resize(nlocal_nodes);
39266 
39267  // Copy the vertices of the nodes
39268  unsigned counter = 0;
39269  std::set<Vector<double>>::iterator it_vertex;
39270  for (it_vertex = local_vertex_nodes.begin();
39271  it_vertex != local_vertex_nodes.end();
39272  it_vertex++)
39273  {
39274  local_tmp_vector_vertex_node[counter].resize(3);
39275  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39276  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39277  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39278  counter++;
39279  }
39280 
39281  // ... same for the info. related with the target areas (turn
39282  // into vector)
39283  const unsigned ntarget_areas = sorted_target_areas.size();
39284  tmp_sorted_target_areas.resize(ntarget_areas);
39285  counter = 0;
39286  std::set<Vector<double>>::iterator it_area;
39287  for (it_area = sorted_target_areas.begin();
39288  it_area != sorted_target_areas.end();
39289  ++it_area)
39290  {
39291  tmp_sorted_target_areas[counter] = (*it_area)[1];
39292  ++counter;
39293  }
39294 
39295 #ifdef PARANOID
39296  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1))
39297  {
39298  std::ostringstream error_message;
39299  error_message
39300  << "The boundary (" << bound << ") was split during the "
39301  << "distribution process.\n"
39302  << "The problem comes when associating the target areas with the "
39303  << "elements that gave\nrise to the vertex coordinates.\n"
39304  << "The number of local nodes on the 'sub-polyline' ("
39305  << nlocal_nodes << ") is not according with the number of target\n"
39306  << "areas (" << ntarget_areas << ") for that number of nodes.\n"
39307  << "The target areas number must be equal to the number of "
39308  "nodes-1\n";
39309  throw OomphLibError(error_message.str(),
39310  OOMPH_CURRENT_FUNCTION,
39311  OOMPH_EXCEPTION_LOCATION);
39312  }
39313 #endif
39314 
39315  // The unrefinement and refinement process needs to be applied
39316  // from the bottom-left node since the internal open curve could
39317  // lie on the shared boundaries
39318  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] <
39319  local_tmp_vector_vertex_node[0][2])
39320  {
39321  std::reverse(local_tmp_vector_vertex_node.begin(),
39322  local_tmp_vector_vertex_node.end());
39323  std::reverse(tmp_sorted_target_areas.begin(),
39324  tmp_sorted_target_areas.end());
39325  }
39326  else if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] ==
39327  local_tmp_vector_vertex_node[0][2])
39328  {
39329  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][1] <
39330  local_tmp_vector_vertex_node[0][1])
39331  {
39332  std::reverse(local_tmp_vector_vertex_node.begin(),
39333  local_tmp_vector_vertex_node.end());
39334  std::reverse(tmp_sorted_target_areas.begin(),
39335  tmp_sorted_target_areas.end());
39336  }
39337  }
39338 
39339  // ------------------------------------------------------------
39340  // Create the vertices along the boundary using the target
39341  // area to define the distance among them
39342  // ------------------------------------------------------------
39343 
39344  // Tolerance below which the middle point can be deleted
39345  // (ratio of deflection to element length)
39346  double unrefinement_tolerance =
39347  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39348 
39349  // Apply unrefinement
39350  bool unrefinement_applied =
39351  unrefine_boundary_constrained_by_target_area(
39352  bound,
39353  chunk,
39354  local_tmp_vector_vertex_node,
39355  unrefinement_tolerance,
39356  tmp_sorted_target_areas);
39357 
39358  // Tolerance for refinement
39359  double refinement_tolerance =
39360  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39361 
39362  // Apply refinement
39363  bool refinement_applied = refine_boundary_constrained_by_target_area(
39364  mesh_geom_obj_pt,
39365  local_tmp_vector_vertex_node,
39366  refinement_tolerance,
39367  tmp_sorted_target_areas);
39368 
39369  // Clear the local containter to recover the nodes ordered using
39370  // the zeta value
39371  local_vertex_nodes.clear();
39372 
39373  // At the end of each unrefinement/refinement step store the new
39374  // nodes on the set that will give rise to the vertices of the
39375  // new polyline representation
39376  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39377  for (unsigned i = 0; i < nnew_nodes; i++)
39378  {
39379  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39380  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39381  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39382  vertex_nodes.insert(vertex_coord); // Global container
39383  local_vertex_nodes.insert(vertex_coord);
39384  }
39385 
39386  // Update the flag to indicate whether an unrefinement or
39387  // refinement was applied
39388  update_was_performed = (unrefinement_applied || refinement_applied);
39389 
39390 #ifdef OOMPH_HAS_MPI
39391  if (this->is_mesh_distributed())
39392  {
39393  // Add the set of vertices for the boundary, this will help to
39394  // detect if we need to deal with sub_boundaries and
39395  // sub_polylines representations
39396  sub_vertex_nodes.push_back(local_vertex_nodes);
39397  // Increase the counter for sub_boundaries
39398  nsub_boundaries++;
39399 
39400  // Mark if the polyline created by these vertices will be used
39401  // as a shared boundary or as an internal boundary
39402  if (both_root_face_elements_are_nonhalo)
39403  {
39404  internal_to_shared_boundary.push_back(false);
39405  }
39406  else
39407  {
39408  internal_to_shared_boundary.push_back(true);
39409  }
39410  }
39411 #endif
39412 
39413  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39414  // This while is in charge of sorting all the face elements to
39415  // create the new representation of the polyline (also deals
39416  // with the sub-boundary cases)
39417 
39418  // Now turn into vector for ease of handling...
39419  const unsigned npoly_vertex = vertex_nodes.size();
39420  tmp_vector_vertex_node.resize(npoly_vertex);
39421  unsigned count = 0;
39422  for (std::set<Vector<double>>::iterator it = vertex_nodes.begin();
39423  it != vertex_nodes.end();
39424  ++it)
39425  {
39426  tmp_vector_vertex_node[count].resize(3);
39427  tmp_vector_vertex_node[count][0] = (*it)[0];
39428  tmp_vector_vertex_node[count][1] = (*it)[1];
39429  tmp_vector_vertex_node[count][2] = (*it)[2];
39430  ++count;
39431  }
39432 
39433 #ifdef OOMPH_HAS_MPI
39434  // Check that the number of set of vertices marked to be part of a
39435  // shared boundary or of an internal boundaries be the same as the
39436  // total number of sub-boundaries
39437 #ifdef PARANOID
39438  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39439  const unsigned ninternal_to_shared_boundaries =
39440  internal_to_shared_boundary.size();
39441  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39442  {
39443  std::ostringstream error_message;
39444  error_message
39445  << "The number of found sub-boundaries and the number of marked "
39446  << "internal\nboundaries are different\n"
39447  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
39448  << "Number of marked internal boundaries: ("
39449  << ninternal_to_shared_boundaries << ")\n\n";
39450  throw OomphLibError(error_message.str(),
39451  OOMPH_CURRENT_FUNCTION,
39452  OOMPH_EXCEPTION_LOCATION);
39453  }
39454 #endif
39455 
39456  // --------- Stuff for the sub_boundaries ----- Begin section -------
39457 #ifdef PARANOID
39458  if (nsub_boundaries_set != nsub_boundaries)
39459  {
39460  std::ostringstream error_message;
39461  error_message
39462  << "The number of found sub-boundaries and the number of counted\n"
39463  << "sub-boundaries are different:\n"
39464  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
39465  << "Number of counted sub-boundaries: (" << nsub_boundaries
39466  << ")\n\n";
39467  throw OomphLibError(error_message.str(),
39468  OOMPH_CURRENT_FUNCTION,
39469  OOMPH_EXCEPTION_LOCATION);
39470  }
39471 #endif
39472 
39473  // Verify if need to deal with sub_boundaries
39474  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39475  {
39476  // Mark the boundary as been splitted in the partition process
39477  this->Boundary_was_splitted[bound] = true;
39478 
39479  // Resize the vector to store the info. of sub-boundaries
39480  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39481  // Loop over the sub-boundaries
39482  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39483  {
39484  // Turn info. into vector for ease of handling...
39485  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39486  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39487  unsigned subcount = 0;
39488  std::set<Vector<double>>::iterator subit;
39489  for (subit = sub_vertex_nodes[isub].begin();
39490  subit != sub_vertex_nodes[isub].end();
39491  ++subit)
39492  {
39493  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39494  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39495  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39496  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39497  ++subcount;
39498  }
39499  }
39500  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39501  // --------- Stuff for the sub_boundaries ----- End section ----------
39502 #endif // OOMPH_HAS_MPI
39503 
39504  // For further processing the three-dimensional vector has to be
39505  // reduced to a two-dimensional vector
39506  unsigned n_vertex = tmp_vector_vertex_node.size();
39507 
39508  // Resize the vector for vectices
39509  vector_vertex_node.resize(n_vertex);
39510  for (unsigned i = 0; i < n_vertex; i++)
39511  {
39512  vector_vertex_node[i].resize(2);
39513  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
39514  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
39515  }
39516 
39517 #ifdef OOMPH_HAS_MPI
39518  // --------- Stuff for the sub_boundaries ----- Begin section -------
39519  // Verify if need to deal with sub_boundaries
39520  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39521  {
39522  // For further processing the three-dimensional vector has to be
39523  // reduced to a two-dimensional vector
39524  // Resize the vector to store the info. of sub-boundaries
39525  sub_vector_vertex_node.resize(nsub_boundaries);
39526  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39527  {
39528  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
39529  // Resize the vector for vectices
39530  sub_vector_vertex_node[isub].resize(subn_vertex);
39531  for (unsigned i = 0; i < subn_vertex; i++)
39532  {
39533  sub_vector_vertex_node[isub][i].resize(2);
39534  sub_vector_vertex_node[isub][i][0] =
39535  sub_tmp_vector_vertex_node[isub][i][1];
39536  sub_vector_vertex_node[isub][i][1] =
39537  sub_tmp_vector_vertex_node[isub][i][2];
39538  }
39539  }
39540  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39541 
39542  // We already have the info. for the sub-boundaries (if necessary)
39543  // and then we can create the sub-boundaries representations to
39544  // ease the generation of the mesh by Triangle
39545 
39546  // --------- Stuff for the sub_boundaries ----- End section ---------
39547 #endif // OOMPH_HAS_MPI
39548 
39549  // ------------------------------------------------------------------
39550  // Check for contiguousness
39551  // ------------------------------------------------------------------
39552 #ifdef OOMPH_HAS_MPI
39553  // Only perform this checking if the mesh is not distributed When
39554  // the mesh is distributed the polylines continuity is addressed by
39555  // the sort_polylines_helper() method
39556  if (!this->is_mesh_distributed())
39557 #endif
39558  {
39559  if (cs > 0)
39560  {
39561  // Final end point of previous line
39562  Vector<double> final_vertex_of_previous_segment;
39563  unsigned n_prev_vertex =
39564  open_curve_pt->curve_section_pt(cs - 1)->nvertex();
39565  final_vertex_of_previous_segment =
39566  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(
39567  n_prev_vertex - 1);
39568 
39569  unsigned prev_seg_boundary_id =
39570  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
39571 
39572  // Find the error between the final vertex of the previous
39573  // line and the first vertex of the current line
39574  double error = 0.0;
39575  for (unsigned i = 0; i < 2; i++)
39576  {
39577  const double dist = final_vertex_of_previous_segment[i] -
39578  (*vector_vertex_node.begin())[i];
39579  error += dist * dist;
39580  }
39581  error = sqrt(error);
39582 
39583  // If the error is bigger than the tolerance then
39584  // we probably need to reverse, but better check
39585  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39586  {
39587  // Find the error between the final vertex of the previous
39588  // line and the last vertex of the current line
39589  double rev_error = 0.0;
39590  for (unsigned i = 0; i < 2; i++)
39591  {
39592  const double dist = final_vertex_of_previous_segment[i] -
39593  (*--vector_vertex_node.end())[i];
39594  rev_error += dist * dist;
39595  }
39596  rev_error = sqrt(rev_error);
39597 
39598  if (rev_error >
39599  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39600  {
39601  // It could be possible that the first segment be reversed and we
39602  // did not notice it because this check does not apply for the
39603  // first segment. We can verify if the first segment is reversed
39604  // by using the vertex number 1
39605  if (cs == 1)
39606  {
39607  // Initial end point of previous line
39608  Vector<double> initial_vertex_of_previous_segment;
39609 
39610  initial_vertex_of_previous_segment =
39611  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(0);
39612 
39613  unsigned prev_seg_boundary_id =
39614  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
39615 
39616  // Find the error between the initial vertex of the previous
39617  // line and the first vertex of the current line
39618  double error = 0.0;
39619  for (unsigned i = 0; i < 2; i++)
39620  {
39621  const double dist = initial_vertex_of_previous_segment[i] -
39622  (*vector_vertex_node.begin())[i];
39623  error += dist * dist;
39624  }
39625  error = sqrt(error); // Reversed only the previous one
39626 
39627  // If the error is bigger than the tolerance then
39628  // we probably need to reverse, but better check
39629  if (error >
39630  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39631  {
39632  // Find the error between the final vertex of the previous
39633  // line and the last vertex of the current line
39634  double rev_error = 0.0;
39635  for (unsigned i = 0; i < 2; i++)
39636  {
39637  const double dist = initial_vertex_of_previous_segment[i] -
39638  (*--vector_vertex_node.end())[i];
39639  rev_error += dist * dist;
39640  }
39641  rev_error = sqrt(rev_error); // Reversed both the current
39642  // one and the previous one
39643 
39644  if (rev_error >
39645  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39646  {
39647  std::ostringstream error_stream;
39648  error_stream
39649  << "The distance between the first node of the current\n"
39650  << "line segment (boundary " << bound
39651  << ") and either end of "
39652  << "the previous line segment\n"
39653  << "(boundary " << prev_seg_boundary_id
39654  << ") is bigger than"
39655  << " the desired tolerance "
39656  << ToleranceForVertexMismatchInPolygons::Tolerable_error
39657  << ".\n"
39658  << "This suggests that the polylines defining the "
39659  "polygonal\n"
39660  << "representation are not properly ordered.\n"
39661  << "Fail on last vertex of polyline: ("
39662  << prev_seg_boundary_id
39663  << ") and\nfirst vertex of polyline (" << bound
39664  << ").\nThis should have failed when first trying to "
39665  << "construct the\npolygon.\n";
39666  throw OomphLibError(error_stream.str(),
39667  OOMPH_CURRENT_FUNCTION,
39668  OOMPH_EXCEPTION_LOCATION);
39669  }
39670  else
39671  {
39672  // Reverse both
39673  // Reverse the current vector to line up with the previous
39674  // one
39675  std::reverse(vector_vertex_node.begin(),
39676  vector_vertex_node.end());
39677  open_curve_pt->polyline_pt(cs - 1)->reverse();
39678  }
39679  }
39680  else
39681  {
39682  // Reverse the previous one
39683  open_curve_pt->polyline_pt(cs - 1)->reverse();
39684  }
39685 
39686  } // if (cs == 1)
39687  else
39688  {
39689  std::ostringstream error_stream;
39690  error_stream
39691  << "The distance between the first node of the current\n"
39692  << "line segment (boundary " << bound
39693  << ") and either end of "
39694  << "the previous line segment\n"
39695  << "(boundary " << prev_seg_boundary_id
39696  << ") is bigger than the "
39697  << "desired tolerance "
39698  << ToleranceForVertexMismatchInPolygons::Tolerable_error
39699  << ".\n"
39700  << "This suggests that the polylines defining the polygonal\n"
39701  << "representation are not properly ordered.\n"
39702  << "Fail on last vertex of polyline: ("
39703  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
39704  << bound << ").\n"
39705  << "This should have failed when first trying to construct\n"
39706  << "the polygon.\n";
39707  throw OomphLibError(error_stream.str(),
39708  OOMPH_CURRENT_FUNCTION,
39709  OOMPH_EXCEPTION_LOCATION);
39710  }
39711  }
39712  else
39713  {
39714  // Reverse the current vector to line up with the previous one
39715  std::reverse(vector_vertex_node.begin(),
39716  vector_vertex_node.end());
39717  }
39718  }
39719 
39720  } // if (cs > 0)
39721 
39722  } // if (!this->is_mesh_distributed())
39723 
39724  // ---------------------------------------------------------------
39725  // Update the polylines representation
39726  // ---------------------------------------------------------------
39727  // Always update the polylines representation, in a distributed
39728  // mesh it is necessary to update the polyline representation since
39729  // it may no longer have vertices (the boundary may not be part of
39730  // the domain in the current processor)
39731 
39732  // The new number of vertices
39733  n_vertex = vector_vertex_node.size();
39734 
39735  // Update the polyline according to the new vertices
39736  TriangleMeshPolyLine* tmp_polyline_pt =
39737  new TriangleMeshPolyLine(vector_vertex_node, bound);
39738 
39739  // Create a temporal "curve section" version of the recently
39740  // created polyline
39741  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
39742 
39743  // Tolerance below which the middle point can be deleted (ratio of
39744  // deflection to element length)
39745  double unrefinement_tolerance =
39746  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39747 
39748  // Tolerance to add points
39749  double refinement_tolerance =
39750  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39751 
39752  // Establish refinement and unrefinement tolerance
39753  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39754  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39755 
39756  // Establish the maximum length constraint
39757  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39758  tmp_polyline_pt->set_maximum_length(maximum_length);
39759 
39760 #ifdef OOMPH_HAS_MPI
39761  // If the mesh is distributed check that the polyline still has
39762  // vertices
39763  if (this->is_mesh_distributed())
39764  {
39765  if (n_vertex >= 2)
39766  {
39767  // Pass the connection information from the old polyline to
39768  // the new one
39769  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39770  tmp_curve_section_pt);
39771  } // if (n_vertex >= 2)
39772  } // if (this->is_mesh_distributed())
39773  else
39774 #endif
39775  {
39776  // Pass the connection information from the old polyline to the
39777  // new one
39778  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39779  tmp_curve_section_pt);
39780  }
39781 
39782  // Now update the polyline according to the new vertices but first
39783  // check if the object is allowed to delete the representation or
39784  // if it should be done by other object
39785  bool delete_it_on_destructor = false;
39786 
39787  std::set<TriangleMeshCurveSection*>::iterator it =
39788  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39789 
39790  if (it != this->Free_curve_section_pt.end())
39791  {
39792  this->Free_curve_section_pt.erase(it);
39793  delete open_curve_pt->curve_section_pt(cs);
39794  delete_it_on_destructor = true;
39795  }
39796 
39797  // -------------------------------------------------------------
39798  // Copying the new representation
39799  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39800 
39801  // Update the Boundary - Polyline map
39802  this->Boundary_curve_section_pt[bound] =
39803  open_curve_pt->curve_section_pt(cs);
39804 
39805  if (delete_it_on_destructor)
39806  {
39807  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39808  }
39809 
39810 #ifdef OOMPH_HAS_MPI
39811  // If there are not sub-boundaries mark the boundary if need to be
39812  // trated as shared or as internal boundary
39813  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39814  {
39815  // Clear all previous stored data
39816  this->Boundary_marked_as_shared_boundary[bound].clear();
39817 
39818  // .. and store the flag for the boundary
39819  this->Boundary_marked_as_shared_boundary[bound].push_back(
39820  internal_to_shared_boundary[0]);
39821  }
39822  // --------- Stuff for the sub_boundaries ----- Begin section --------
39823  // Verify if need to deal with sub_boundaries
39824  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39825  {
39826  // Create temporary representations for the boundaries, only to
39827  // create the mesh when calling Triangle
39828 
39829  // Clear all previous stored data
39830  this->Boundary_subpolylines[bound].clear();
39831  // Now create storage for the sub-boundaries
39832  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39833 
39834  // Clear all previous stored data
39835  this->Boundary_marked_as_shared_boundary[bound].clear();
39836  // Create storage to mark the internal boundaries as shared
39837  // boundaries
39838  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39839  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39840  {
39841  // Now update the polyline according to the sub set of
39842  // vertices, set the chunk number of the polyline
39843  TriangleMeshPolyLine* sub_tmp_polyline_pt =
39844  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39845 
39846  // Add the sub-polyline to the container to represent the
39847  // boundary in parts
39848  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39849 
39850  // Copy the flag that mark the boundary as internal or as
39851  // shared bound
39852  this->Boundary_marked_as_shared_boundary[bound][isub] =
39853  internal_to_shared_boundary[isub];
39854 
39855  // No need to send the unrefinement/refinement and maximum
39856  // length constraints since these are only temporary
39857  // representations
39858 
39859  // But we certanly we need to pass the connection information
39860  // to the sub-polylines
39861  // Get a curve section representation of the sub-polyline
39862  TriangleMeshCurveSection* tmp_sub_curve_section_pt =
39863  sub_tmp_polyline_pt;
39864  this->copy_connection_information_to_sub_polylines(
39865  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39866 
39867  } // for (isub < nsub_boundaries)
39868 
39869  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39870  // --------- Stuff for the sub_boundaries ----- End section ---------
39871 #endif // OOMPH_HAS_MPI
39872 
39873  // Delete the allocated memory for the geometric object
39874  // that represents the curvilinear boundary
39875  delete mesh_geom_obj_pt;
39876 
39877  } // for (cs < ncurve_section)
39878 
39879  // Cleanup the face mesh
39880  for (unsigned p = 0; p < ncurve_section; p++)
39881  {
39882  face_mesh_pt[p]->flush_node_storage();
39883  delete face_mesh_pt[p];
39884  }
39885 
39886  return update_was_performed;
39887  }
39888 
39889 #ifdef OOMPH_HAS_MPI
39890  //======================================================================
39891  /// Updates the polylines using the elements area as
39892  /// constraint for the number of points along the boundaries
39893  //======================================================================
39894  template<class ELEMENT>
39896  Vector<TriangleMeshPolyLine*>& vector_polyline_pt,
39897  const Vector<double>& target_areas)
39898  {
39899  // Flag to check if there were a change on the shared boundary
39900  // representation
39901  unsigned update_was_performed = false;
39902 
39903  // Go through all the shared boundaries/polylines
39904  const unsigned n_polylines = vector_polyline_pt.size();
39905  for (unsigned pp = 0; pp < n_polylines; pp++)
39906  {
39907  // Get the boundary id of the current polyline
39908  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39909 
39910  // Get the chunk number
39911  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39912 
39913  // Get the face elements that created the shared boundary from the
39914  // bulk shared boundary elements
39915 
39916  // Compute the face elements from the shared boundary elements,
39917  // create an association from the face element with the "bulk"
39918  // elements
39919  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39920 
39921  // The temporary storage for the halo face elements
39922  Vector<FiniteElement*> halo_shared_face_ele_pt;
39923  // The temporary storage for the nonhalo face elements
39924  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39925 
39926  // Get the number of shared boundary elements associated with the
39927  // current shared boundary
39928  const unsigned nshared_bound_ele =
39929  this->nshared_boundary_element(shd_bnd_id);
39930 
39931  // Loop over the elements in the shared boundary to create the face
39932  // elements
39933  for (unsigned e = 0; e < nshared_bound_ele; e++)
39934  {
39935  // Get the shared boundary element
39936  FiniteElement* bulk_ele_pt =
39937  this->shared_boundary_element_pt(shd_bnd_id, e);
39938 
39939  // Get the face index
39940  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39941 
39942  // Before adding the new element we need to ensure that the edge
39943  // that this element represents has not been already added
39944  FiniteElement* face_ele_pt =
39945  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39946 
39947  // Establish the association between the bulk element and the
39948  // face element
39949  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39950 
39951  // Nonhalo element
39952  if (!bulk_ele_pt->is_halo())
39953  {
39954  // Add nonhalo shared face element to the container
39955  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39956  }
39957  else // halo element
39958  {
39959  // Add halo shared face element to the container
39960  halo_shared_face_ele_pt.push_back(face_ele_pt);
39961  }
39962 
39963  } // for (e < nshared_bound_ele)
39964 
39965  // Now we have the face elements, we need to ensure that the halo
39966  // and nonhalo bulk element are sorted one after the other
39967  Vector<Vector<FiniteElement*>> unsorted_shared_bulk_ele_pt;
39968 
39969  // Mark the face elements already used
39970  std::map<FiniteElement*, bool> shared_face_done;
39971 
39972  // Get the number of nonhalo face elements
39973  const unsigned nnonhalo_face_shared_ele =
39974  nonhalo_shared_face_ele_pt.size();
39975 
39976  // Get the number of halo face elements
39977  const unsigned nhalo_face_shared_ele = halo_shared_face_ele_pt.size();
39978 
39979 #ifdef PARANOID
39980  // The number of nonhalo shared face boundary elements must be the
39981  // half of the total number of shared boundary elements
39982  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39983  {
39984  std::ostringstream error_message;
39985  error_message
39986  << "The number of shared boundary elements (" << nshared_bound_ele
39987  << ") is not the double\nof the number of unsorted NONHALO shared "
39988  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39989  << "for the current boundary (" << shd_bnd_id << ")\n\n";
39990  throw OomphLibError(error_message.str(),
39991  OOMPH_CURRENT_FUNCTION,
39992  OOMPH_EXCEPTION_LOCATION);
39993  }
39994 
39995  // The number of halo shared face boundary elements must be the
39996  // half of the total number of shared boundary elements
39997  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39998  {
39999  std::ostringstream error_message;
40000  error_message
40001  << "The number of shared boundary elements (" << nshared_bound_ele
40002  << ") is not the double\nof the number of unsorted HALO shared "
40003  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
40004  << "for the current boundary (" << shd_bnd_id << ")\n\n";
40005  throw OomphLibError(error_message.str(),
40006  OOMPH_CURRENT_FUNCTION,
40007  OOMPH_EXCEPTION_LOCATION);
40008  }
40009 #endif
40010 
40011  // ------------------------------------------------------------------
40012  // Loop over the nonhalo face elements and look for the halo face
40013  // element at the other side of the shared boundary
40014  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40015  {
40016  // Get the inh-th face element
40017  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
40018 
40019  // Get the number of nodes on the face element
40020  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
40021  // Get the first and last node on the element
40022  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
40023  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh - 1);
40024 
40025  // Now find the (halo) face element at the other side of the
40026  // shared boundary
40027  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40028  {
40029  // Get the ih-th face element
40030  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
40031 
40032  // Check that the face element has not been done
40033  if (!shared_face_done[halo_face_ele_pt])
40034  {
40035  // Get the number of nodes on the face element
40036  const unsigned nnodes_h = halo_face_ele_pt->nnode();
40037  // Get the first and last node on the element
40038  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
40039  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h - 1);
40040 
40041  // If the nodes are the same then we have found the (halo)
40042  // face element at the other side of the shared boundary
40043  if (nh_first_node_pt == h_first_node_pt &&
40044  nh_last_node_pt == h_last_node_pt)
40045  {
40046  // Get the BULK elements associated with the face elements
40047  Vector<FiniteElement*> tmp_bulk_element_pt;
40048  // Get the BULK elements associated to the face elements
40049  // (the nonhalo and the halo)
40050  FiniteElement* nonhalo_bulk_ele_pt =
40051  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
40052  FiniteElement* halo_bulk_ele_pt =
40053  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
40054 
40055  // Add the BULK elements to the temporal storage
40056  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
40057  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
40058 
40059  // Store the pair of elements associated to the "edge"
40060  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
40061 
40062  // Mark the face elements as done
40063  shared_face_done[nonhalo_face_ele_pt] = true;
40064  shared_face_done[halo_face_ele_pt] = true;
40065 
40066  // Break the loop for (ih < nhalo_face_shared_ele)
40067  break;
40068  } // if (nh_first_node_pt == h_first_node_pt &&
40069  // nh_last_node_pt == h_last_node_pt)
40070  else if (nh_first_node_pt == h_last_node_pt &&
40071  nh_last_node_pt == h_first_node_pt)
40072  {
40073  // Get the BULK elements associated with the face elements
40074  Vector<FiniteElement*> tmp_bulk_element_pt;
40075  // Get the BULK elements associated to the face elements
40076  // (the nonhalo and the halo)
40077  FiniteElement* nonhalo_bulk_ele_pt =
40078  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
40079  FiniteElement* halo_bulk_ele_pt =
40080  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
40081 
40082  // Add the BULK elements to the temporal storage
40083  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
40084  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
40085 
40086  // Store the pair of elements associated to the "edge"
40087  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
40088 
40089  // Mark the face elements as done
40090  shared_face_done[nonhalo_face_ele_pt] = true;
40091  shared_face_done[halo_face_ele_pt] = true;
40092 
40093  // Break the loop for (ih < nhalo_face_shared_ele)
40094  break;
40095  } // else if (nh_first_node_pt == h_last_node_pt &&
40096  // nh_last_node_pt == h_first_node_pt)
40097 
40098  } // if (face_done[halo_face_ele_pt])
40099 
40100  } // for (ih < nhalo_face_shared_ele)
40101 
40102  } // for (inh < nnonhalo_face_shared_ele)
40103 
40104  // -------------------------------------------------------------
40105  // Now sort the face elements
40106  // -------------------------------------------------------------
40107 
40108  // We already have the shared face elements that make the shared
40109  // boundary (and the bulk elements), now sort them to create a
40110  // contiguous boundary
40111 
40112 #ifdef PARANOID
40113  const unsigned nunsorted_shared_bulk_ele =
40114  unsorted_shared_bulk_ele_pt.size();
40115 
40116  // The number of unsorted shared BULK elements MUST be the same
40117  // as the number of shared_boundary elements divided by two
40118  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
40119  {
40120  std::ostringstream error_message;
40121  error_message
40122  << "The number of shared boundary elements (" << nshared_bound_ele
40123  << ") is not the double\nof the number of unsorted shared bulk "
40124  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
40125  << "for the current boundary (" << shd_bnd_id << ")\n\n";
40126  throw OomphLibError(error_message.str(),
40127  OOMPH_CURRENT_FUNCTION,
40128  OOMPH_EXCEPTION_LOCATION);
40129  }
40130 
40131  // The number of done shared face elements MUST be the same as the
40132  // sum of the nonhalo and halo shared boundary face elements
40133  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
40134  shared_face_done.size())
40135  {
40136  std::ostringstream error_message;
40137  error_message << "The number of DONE shared boundary face elements ("
40138  << shared_face_done.size()
40139  << ") is not the same\n as the sum of"
40140  << "the nonhalo face shared boundary elements ("
40141  << nnonhalo_face_shared_ele
40142  << ")\nand the halo face shared "
40143  << "boundary elements (" << nhalo_face_shared_ele
40144  << ") for the\n/"
40145  << "current boundary (" << shd_bnd_id << ")\n\n";
40146  throw OomphLibError(error_message.str(),
40147  OOMPH_CURRENT_FUNCTION,
40148  OOMPH_EXCEPTION_LOCATION);
40149  }
40150 #endif
40151 
40152  // Clear the already done face elements
40153  shared_face_done.clear();
40154 
40155  // The number of sorted face elements
40156  unsigned nsorted_face_ele = 0;
40157 
40158  // Storing for the sorting nodes extracted from the face
40159  // elements. This are also used to update the polyline
40160  std::list<Node*> sorted_nodes;
40161 
40162  // Storing for the sorted shared face elements
40163  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
40164 
40165  // Get the root face element
40166  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
40167  nsorted_face_ele++;
40168 
40169  // Mark face as done
40170  shared_face_done[root_face_ele_pt] = true;
40171 
40172  // The initial and final node on the list
40173  const unsigned nnodes_root = root_face_ele_pt->nnode();
40174  Node* first_node_pt = root_face_ele_pt->node_pt(0);
40175  Node* last_node_pt = root_face_ele_pt->node_pt(nnodes_root - 1);
40176 
40177  // Push back on the list the new nodes
40178  sorted_nodes.push_back(first_node_pt);
40179  sorted_nodes.push_back(last_node_pt);
40180 
40181  // Store the bulk elements of the current face
40182  sorted_shared_bound_elements_pt.push_back(
40183  unsorted_shared_bulk_ele_pt[0][0]);
40184  sorted_shared_bound_elements_pt.push_back(
40185  unsorted_shared_bulk_ele_pt[0][1]);
40186 
40187  // Sort the face elements
40188  while (nsorted_face_ele < nnonhalo_face_shared_ele)
40189  {
40190  // Flag to indicate when a node was added
40191  bool node_added = false;
40192 
40193  // Start from the next edge since we have already added the
40194  // previous one as the initial face element
40195  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
40196  {
40197  FiniteElement* tmp_shared_face_ele_pt =
40198  nonhalo_shared_face_ele_pt[iface];
40199 
40200  // If face has not been sorted
40201  if (!shared_face_done[tmp_shared_face_ele_pt])
40202  {
40203  // Get the number of nodes for the current face element
40204  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
40205 
40206  // Get each individual node
40207  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
40208  Node* right_node_pt =
40209  tmp_shared_face_ele_pt->node_pt(tmp_nnodes - 1);
40210 
40211  if (left_node_pt == first_node_pt)
40212  {
40213  // Push front the new node
40214  sorted_nodes.push_front(right_node_pt);
40215  first_node_pt = right_node_pt;
40216  node_added = true;
40217 
40218  // Store the elements of the current face element
40219  sorted_shared_bound_elements_pt.push_front(
40220  unsorted_shared_bulk_ele_pt[iface][1]);
40221  sorted_shared_bound_elements_pt.push_front(
40222  unsorted_shared_bulk_ele_pt[iface][0]);
40223  }
40224  else if (left_node_pt == last_node_pt)
40225  {
40226  // Push back the new node
40227  sorted_nodes.push_back(right_node_pt);
40228  last_node_pt = right_node_pt;
40229  node_added = true;
40230 
40231  // Store the elements of the current face element
40232  sorted_shared_bound_elements_pt.push_back(
40233  unsorted_shared_bulk_ele_pt[iface][0]);
40234  sorted_shared_bound_elements_pt.push_back(
40235  unsorted_shared_bulk_ele_pt[iface][1]);
40236  }
40237  else if (right_node_pt == first_node_pt)
40238  {
40239  // Push front the new node
40240  sorted_nodes.push_front(left_node_pt);
40241  first_node_pt = left_node_pt;
40242  node_added = true;
40243 
40244  // Store the elements of the current face element
40245  sorted_shared_bound_elements_pt.push_front(
40246  unsorted_shared_bulk_ele_pt[iface][1]);
40247  sorted_shared_bound_elements_pt.push_front(
40248  unsorted_shared_bulk_ele_pt[iface][0]);
40249  }
40250  else if (right_node_pt == last_node_pt)
40251  {
40252  // Push back the new node
40253  sorted_nodes.push_back(left_node_pt);
40254  last_node_pt = left_node_pt;
40255  node_added = true;
40256 
40257  // Store the elements of the current face element
40258  sorted_shared_bound_elements_pt.push_back(
40259  unsorted_shared_bulk_ele_pt[iface][0]);
40260  sorted_shared_bound_elements_pt.push_back(
40261  unsorted_shared_bulk_ele_pt[iface][1]);
40262  }
40263 
40264  if (node_added)
40265  {
40266  // Mark as done if one of its nodes has been added to the
40267  // list
40268  shared_face_done[tmp_shared_face_ele_pt] = true;
40269  nsorted_face_ele++;
40270 
40271  // Break the for
40272  break;
40273  }
40274 
40275  } // if (!shared_face_done[tmp_shared_face_ele_pt])
40276 
40277  } // for (iface < nnonhalo_face_shared_ele)
40278 
40279  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
40280 
40281  // ----------------------------------------------------------------
40282  // Here we can safely delete the face elements, they are no longer
40283  // required
40284 
40285  // First the nonhalo face elements
40286  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40287  {
40288  delete nonhalo_shared_face_ele_pt[inh];
40289  nonhalo_shared_face_ele_pt[inh] = 0;
40290  } // for (inh < nnonhalo_face_shared_ele)
40291 
40292  // ... then the halo face elements
40293  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40294  {
40295  delete halo_shared_face_ele_pt[ih];
40296  halo_shared_face_ele_pt[ih] = 0;
40297  } // for (inh < nhalo_face_shared_ele)
40298 
40299  // ------------------------------------------------------------------
40300  // At this point we already have a sorted list of nodes, get the
40301  // vertices from them and store them in a vector container
40302 
40303  // Get the number of nodes on the list
40304  const unsigned n_nodes = sorted_nodes.size();
40305 
40306  // The vector to store the vertices
40307  Vector<Vector<double>> polyline_vertices(n_nodes);
40308 
40309  // Copy the vertices from the nodes
40310  unsigned counter = 0;
40311  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40312  it_nodes != sorted_nodes.end();
40313  it_nodes++)
40314  {
40315  polyline_vertices[counter].resize(2);
40316  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40317  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40318  counter++;
40319  }
40320 
40321  // ------------------------------------------------------------------
40322  // Now get the target areas associated to the shared boundary
40323  // elements
40324 
40325  // Copy the sorted elements in a vector
40326  Vector<FiniteElement*> sorted_shared_ele_pt;
40327  for (std::list<FiniteElement*>::iterator it_ele =
40328  sorted_shared_bound_elements_pt.begin();
40329  it_ele != sorted_shared_bound_elements_pt.end();
40330  it_ele++)
40331  {
40332  sorted_shared_ele_pt.push_back((*it_ele));
40333  }
40334 
40335  // Get the number of target areas
40336  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40337  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40338 
40339  // Mark those shared elements already found
40340  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40341 
40342  // Counter for the number of already done shared elements
40343  unsigned count_found_shared_element = 0;
40344 
40345  // Get the target area associated to the shared boundary elements
40346  const unsigned nele = this->nelement();
40347 
40348  // Loop over the elements to find the target areas associated to
40349  // the shared boundary elements
40350  for (unsigned e = 0; e < nele; e++)
40351  {
40352  GeneralisedElement* current_ele_pt = this->element_pt(e);
40353  // Now compare the current element with those in the sorted
40354  // shared element array
40355  for (unsigned s = 0; s < n_shared_target_areas; s++)
40356  {
40357  // Get the element
40358  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40359  // Create the pair element-index to check if done
40360  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40361  std::make_pair(current_shared_ele_pt, s);
40362  if (!shared_ele_done[pair_gen_ele_idx])
40363  {
40364  // Compare with the global element
40365  if (current_ele_pt == current_shared_ele_pt)
40366  {
40367  // Store the target area of the current shared element
40368  sorted_shared_target_areas[s] = target_areas[e];
40369  // Mark the shared element as done
40370  shared_ele_done[pair_gen_ele_idx] = true;
40371  // Increase the number of found elements
40372  count_found_shared_element++;
40373  } // if (current_ele_pt == current_shared_ele_pt)
40374  } // if (!shared_ele_done[current_shared_ele_pt])
40375  } // for (s < nshared_taget_areas)
40376 
40377  // Check if all shared elements have been found
40378  if (count_found_shared_element == n_shared_target_areas)
40379  {
40380  break;
40381  }
40382 
40383  } // for (e < nele)
40384 
40385 #ifdef PARANOID
40386  // Check if the number of found target areas is the same as the
40387  // number of shared target areas
40388  if (count_found_shared_element != n_shared_target_areas)
40389  {
40390  std::ostringstream error_message;
40391  error_message << "The number of found target areas ("
40392  << count_found_shared_element
40393  << ") is different from the "
40394  << "total number\nof target areas ("
40395  << n_shared_target_areas << ") in shared boundary ("
40396  << shd_bnd_id << ")\n\n";
40397  throw OomphLibError(error_message.str(),
40398  OOMPH_CURRENT_FUNCTION,
40399  OOMPH_EXCEPTION_LOCATION);
40400  }
40401 #endif
40402 
40403  // The number of vertices
40404  const unsigned n_vertices = n_nodes;
40405 
40406  // Get the number of segments from the input vector_polyline_pt
40407  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40408  // Get the number of segments from the input vector_polyline_pt to
40409  // ensure that the shared boundary corresponds to the one
40410  // represented by the shared face elements (this has sence when the
40411  // mesh was re-created from re-starting)
40412 
40413  // Check that the number of vertices correspond with the number of
40414  // segments
40415 #ifdef PARANOID
40416  if (n_segments != n_vertices - 1)
40417  {
40418  std::ostringstream error_message;
40419  error_message
40420  << "The number of segments from the current shared polyline "
40421  << "(" << n_segments << ") does not\ncorrespond with the number of "
40422  << "sorted vertices (" << n_vertices - 1
40423  << ") of the current shared\n"
40424  << "boundary\n\n";
40425  throw OomphLibError(error_message.str(),
40426  OOMPH_CURRENT_FUNCTION,
40427  OOMPH_EXCEPTION_LOCATION);
40428  }
40429 
40430  // Check that the number of target areas correspond with the number
40431  // of vertices
40432  if (n_segments != n_shared_target_areas / 2)
40433  {
40434  std::ostringstream error_message;
40435  error_message
40436  << "The number of segments for the current sorting of edges "
40437  << "(" << n_segments << ") is different\nfrom the number of "
40438  << "target areas (" << n_shared_target_areas / 2 << ")\n\n";
40439  throw OomphLibError(error_message.str(),
40440  OOMPH_CURRENT_FUNCTION,
40441  OOMPH_EXCEPTION_LOCATION);
40442  }
40443 #endif
40444 
40445  // ------------------------------------------------------------------
40446  // Get the target areas that are used to perform the unrefinement
40447  // and refinement operation. For each face element on a shared
40448  // polyline there are two bulk elements, a halo and a haloed
40449  // element, each with an associated target area. Review the
40450  // function
40451  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40452  // check how the shared boundaries were created
40453  Vector<double> polyline_target_area(n_segments);
40454  // Loop over the segments in the shared polyline
40455  for (unsigned s = 0; s < n_segments; s++)
40456  {
40457  // Get the minimum of the associated target areas
40458  polyline_target_area[s] =
40459  std::min(sorted_shared_target_areas[s * 2],
40460  sorted_shared_target_areas[(s * 2) + 1]);
40461  }
40462 
40463  // Before going to the unrefinement or refinement process check
40464  // that in all processors where the shared boundary lives start
40465  // from the same vertex.
40466  // Start from the bottom left vertex
40467  if (polyline_vertices[n_vertices - 1][1] < polyline_vertices[0][1])
40468  {
40469  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40470  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40471  }
40472  else if (polyline_vertices[n_vertices - 1][1] == polyline_vertices[0][1])
40473  {
40474  if (polyline_vertices[n_vertices - 1][0] < polyline_vertices[0][0])
40475  {
40476  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40477  std::reverse(polyline_target_area.begin(),
40478  polyline_target_area.end());
40479  }
40480  }
40481 
40482  // ------------------------------------------------------------------
40483  // Apply unrefinement
40484  bool unrefinement_applied = false;
40485  // Apply unefinement if there are more than three nodes at the
40486  // shared boundary
40487  if (n_vertices > 3)
40488  {
40489  unrefinement_applied =
40490  unrefine_shared_boundary_constrained_by_target_area(
40491  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40492  }
40493 
40494  // Apply refinement
40495  bool refinement_applied =
40496  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40497  polyline_target_area);
40498 
40499  // Was unrefinement/refinement applied
40500  update_was_performed |= (unrefinement_applied || refinement_applied);
40501 
40502  // ------------------------------------------------------------------
40503  // Update the polyline representation of the shared boundary
40504 
40505  // The new shared polyline representation
40506  TriangleMeshPolyLine* new_polyline_pt =
40507  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40508 
40509  // Get the curve section representation
40510  TriangleMeshCurveSection* curve_section_pt = vector_polyline_pt[pp];
40511 
40512  // Copy the connection information from the old shared polyline to
40513  // the new one
40514  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40515 
40516  // Now update the polyline according to the new vertices but first
40517  // check if the object is allowed to delete the representation or
40518  // if it should be done by other object
40519  bool delete_it_on_destructor = false;
40520 
40521  // Establish the element as being deleted by the destructor of the
40522  // class
40523  std::set<TriangleMeshCurveSection*>::iterator it =
40524  this->Free_curve_section_pt.find(curve_section_pt);
40525 
40526  if (it != this->Free_curve_section_pt.end())
40527  {
40528  this->Free_curve_section_pt.erase(it);
40529  delete curve_section_pt;
40530  delete_it_on_destructor = true;
40531  }
40532 
40533  // Copy the new representation to the output vector_polyline_pt
40534  vector_polyline_pt[pp] = new_polyline_pt;
40535 
40536  // Get the new curve section representation
40537  TriangleMeshCurveSection* new_curve_section_pt = vector_polyline_pt[pp];
40538 
40539  // Update the Boundary - Polyline map
40540  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40541 
40542  if (delete_it_on_destructor)
40543  {
40544  this->Free_curve_section_pt.insert(new_curve_section_pt);
40545  }
40546 
40547  } // for (pp < npoly)
40548 
40549  return update_was_performed;
40550  }
40551 #endif // #ifdef OOMPH_HAS_MPI
40552 
40553  //=========================================================================
40554  /// Helper function that performs the unrefinement process
40555  /// on the specified boundary by using the provided vertices
40556  /// representation and the associated target area.
40557  //=========================================================================
40558  template<class ELEMENT>
40561  const unsigned& b,
40562  const unsigned& c,
40563  Vector<Vector<double>>& vector_bnd_vertices,
40564  double& unrefinement_tolerance,
40565  Vector<double>& area_constraint)
40566  {
40567  // Store the vertices not allowed for deletion
40568  std::set<Vector<double>> no_delete_vertex;
40569 
40570  // Does the boundary receives connections?
40571  const bool boundary_receive_connections =
40572  this->boundary_connections(b, c, no_delete_vertex);
40573 
40574  // Boolean that indicates whether an actual update of the vertex
40575  // coordinates was performed
40576  bool unrefinement_applied = false;
40577 
40578  // Return inmedately
40579  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40580  {
40581  return unrefinement_applied;
40582  }
40583 
40584  // Strategy to delete nodes: Consider the target area of the
40585  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40586  // if the number of segments to be added is equal to zero for both
40587  // elements then compute the average of both target areas and check
40588  // if the number of segments is still zero, if that holds mark the
40589  // node to be deleted. Before delete the node check whether it is in
40590  // the non_delete_vertex list. Skip the i+1-th node and go for the
40591  // (i+2)-th one, it means, increase the counter for current node by
40592  // two.
40593 
40594  // Number of vertices on the boundary
40595  unsigned n_vertex = vector_bnd_vertices.size();
40596 
40597  // Compute a constant value
40598  const double constant_value = 4.0 / sqrt(3.0);
40599 
40600  if (n_vertex > 2)
40601  {
40602  // Go through all the vertices and delete points when the target area
40603  // indicates zero points along the boundary
40604  for (unsigned i = 1; i < n_vertex - 1; i += 2)
40605  {
40606  if (area_constraint[i - 1] > 0 && area_constraint[i] > 0)
40607  {
40608  const double local_zeta_first = vector_bnd_vertices[i - 1][0];
40609  const double local_zeta_last = vector_bnd_vertices[i + 1][0];
40610  const double local_length_zeta =
40611  std::fabs(local_zeta_last - local_zeta_first);
40612 
40613  const double x1 = vector_bnd_vertices[i - 1][1];
40614  const double y1 = vector_bnd_vertices[i - 1][2];
40615  const double x2 = vector_bnd_vertices[i + 1][1];
40616  const double y2 = vector_bnd_vertices[i + 1][2];
40617  const double local_length =
40618  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
40619 
40620  const double x_m = vector_bnd_vertices[i][1];
40621  const double y_m = vector_bnd_vertices[i][2];
40622 
40623  const double average_area_constraint =
40624  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
40625 
40626  // Compute the length of the the side of an equilateral
40627  // triangle
40628  const double length_side =
40629  sqrt(constant_value * average_area_constraint);
40630 
40631  const double length_side_zeta =
40632  (local_length_zeta * length_side) / local_length;
40633 
40634  // Is the new length greater that the old one
40635  if ((length_side_zeta / local_length_zeta) > 1.0)
40636  {
40637  // If the number of segments is zero then verify the condition for
40638  // deletion of nodes but using the condition in the default
40639  // unrefine_boundary() method. If both conditions are true then
40640  // delete the node
40641  // Maths from
40642  // http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40643  double a_x = vector_bnd_vertices[i - 1][1];
40644  double a_y = vector_bnd_vertices[i - 1][2];
40645  double b_x = vector_bnd_vertices[i][1];
40646  double b_y = vector_bnd_vertices[i][2];
40647  double c_x = vector_bnd_vertices[i + 1][1];
40648  double c_y = vector_bnd_vertices[i + 1][2];
40649 
40650  double a = b_x - a_x;
40651  double b = b_y - a_y;
40652  double c = c_x - a_x;
40653  double d = c_y - a_y;
40654 
40655  double e = a * (a_x + b_x) + b * (a_y + b_y);
40656  double f = c * (a_x + c_x) + d * (a_y + c_y);
40657 
40658  double g = 2.0 * (a * (c_y - b_y) - b * (c_x - b_x));
40659 
40660  bool do_it = false;
40661  if (std::fabs(g) < 1.0e-14)
40662  {
40663  do_it = true;
40664  }
40665  else
40666  {
40667  double p_x = (d * e - b * f) / g;
40668  double p_y = (a * f - c * e) / g;
40669 
40670  double r = sqrt(pow((a_x - p_x), 2) + pow((a_y - p_y), 2));
40671 
40672  double rhalfca_x = 0.5 * (a_x - c_x);
40673  double rhalfca_y = 0.5 * (a_y - c_y);
40674 
40675  double halfca_squared = pow(rhalfca_x, 2) + pow(rhalfca_y, 2);
40676 
40677  double sticky_out_bit =
40678  r - sqrt(std::fabs((r * r) - halfca_squared));
40679 
40680  // If sticky out bit divided by distance between end nodes
40681  // is less than tolerance the boundary is so flat that we
40682  // can safely kill the node
40683  if ((sticky_out_bit / (2.0 * sqrt(halfca_squared))) <
40684  unrefinement_tolerance)
40685  {
40686  do_it = true;
40687  }
40688  }
40689 
40690  // If the vertex was proposed for deletion check if it is
40691  // allowed for being deleted
40692  if (do_it && boundary_receive_connections)
40693  {
40694  // Is the vertex one of the non deletable vertices
40695  for (std::set<Vector<double>>::iterator it =
40696  no_delete_vertex.begin();
40697  it != no_delete_vertex.end();
40698  it++)
40699  {
40700  // Compute the distance between the proposed node to
40701  // delete and the ones that should not be deleted
40702  const double x = (*it)[0];
40703  const double y = (*it)[1];
40704  double error = (x_m - x) * (x_m - x) + (y_m - y) * (y_m - y);
40705  error = sqrt(error);
40706 
40707  if (error <
40708  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40709  {
40710  // Do not delete the vertex
40711  do_it = false;
40712  break;
40713  }
40714  }
40715 
40716  } // if (do_it && boundary_receive_connections)
40717 
40718  // Remove node?
40719  if (do_it)
40720  {
40721  vector_bnd_vertices[i].resize(0);
40722  }
40723  } // if (n_seg == 0)
40724  } // if (area_constraint[i] >= 0)
40725  } // for (i < n_vertex-1)
40726 
40727  // Create a new (temporary) vector for the nodes, so that deleted nodes
40728  // are not stored
40729  Vector<Vector<double>> compact_vector;
40730 
40731  // Compact vector for target areas too
40732  Vector<double> compact_area_constraint;
40733 
40734  // Copy only the non deleted nodes
40735  for (unsigned i = 0; i < n_vertex; i++)
40736  {
40737  // If the entry was not deleted include it in the new vector
40738  if (vector_bnd_vertices[i].size() != 0)
40739  {
40740  compact_vector.push_back(vector_bnd_vertices[i]);
40741  }
40742  }
40743 
40744  // ------------------------------------------------------------------
40745  // Size of the target areas vector
40746  unsigned nsize_target = area_constraint.size();
40747  if (nsize_target == 1)
40748  {
40749  // No node was deleted, just copy the target area
40750  compact_area_constraint.push_back(area_constraint[0]);
40751  }
40752 
40753  // Copy the target areas
40754  for (unsigned i = 1; i < n_vertex; i += 2)
40755  {
40756  // If the entry was not deleted include the target areas of both
40757  // elements sharing the node
40758  if (vector_bnd_vertices[i].size() != 0)
40759  {
40760  compact_area_constraint.push_back(area_constraint[i - 1]);
40761  // To catch the case when working with even number of vertex
40762  if (i < nsize_target)
40763  {
40764  compact_area_constraint.push_back(area_constraint[i]);
40765  }
40766  }
40767  else
40768  {
40769  // If the node was deleted then compute the new target area as the
40770  // average of the target area of the elements sharing the node
40771  double new_area_constraint =
40772  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
40773  compact_area_constraint.push_back(new_area_constraint);
40774  }
40775  }
40776 
40777  // If the size of the compact vector is different from the size of the
40778  // vector before applying the area length constraint then the polyline
40779  // was updated
40780  if (n_vertex != compact_vector.size())
40781  {
40782  unrefinement_applied = true;
40783  }
40784 
40785  // Copy back to the original vector
40786  n_vertex = compact_vector.size();
40787  vector_bnd_vertices.resize(n_vertex);
40788  for (unsigned i = 0; i < n_vertex; i++)
40789  {
40790  vector_bnd_vertices[i].resize(3);
40791  vector_bnd_vertices[i][0] = compact_vector[i][0];
40792  vector_bnd_vertices[i][1] = compact_vector[i][1];
40793  vector_bnd_vertices[i][2] = compact_vector[i][2];
40794  }
40795 
40796  // Copy back to the original vector of target areas
40797  unsigned ntarget_areas = compact_area_constraint.size();
40798  area_constraint.resize(ntarget_areas);
40799  for (unsigned i = 0; i < ntarget_areas; i++)
40800  {
40801  area_constraint[i] = compact_area_constraint[i];
40802  }
40803 
40804  } // if (n_vertex > 2)
40805 
40806  return unrefinement_applied;
40807  }
40808 
40809  //=========================================================================
40810  /// Helper function that performs the refinement process
40811  /// on the specified boundary by using the provided vertices
40812  /// representation and the associated elements target area.
40813  //=========================================================================
40814  template<class ELEMENT>
40817  MeshAsGeomObject* mesh_geom_obj_pt,
40818  Vector<Vector<double>>& vector_bnd_vertices,
40819  double& refinement_tolerance,
40820  Vector<double>& area_constraint)
40821  {
40822  // Boolean that indicates whether an actual update of the vertex
40823  // coordinates was performed
40824  bool refinement_applied = false;
40825 
40826  // Return inmedately
40827  if (!Do_boundary_refinement_constrained_by_target_areas)
40828  {
40829  return refinement_applied;
40830  }
40831 
40832  // Get the total number of current vertices
40833  unsigned n_vertex = vector_bnd_vertices.size();
40834 
40835  // Compute a constant value
40836  const double constant_value = 4.0 / sqrt(3.0);
40837 
40838  if (n_vertex > 1)
40839  {
40840  // Create a new (temporary) vector for the nodes, so that new
40841  // nodes can be stored
40842  Vector<Vector<double>> new_vector;
40843 
40844  // Go through all the vertices and create points according to the
40845  // specified element area
40846  for (unsigned i = 0; i < n_vertex - 1; i++)
40847  {
40848  // Include the first node
40849  new_vector.push_back(vector_bnd_vertices[i]);
40850 
40851  if (area_constraint[i] > 0)
40852  {
40853  double local_zeta_first = vector_bnd_vertices[i][0];
40854  double local_zeta_last = vector_bnd_vertices[i + 1][0];
40855  const double local_length_zeta =
40856  std::fabs(local_zeta_last - local_zeta_first);
40857 
40858  // Check if need to interchange the zeta first and the zeta
40859  // last (to ensure the same order in zeta values in any two
40860  // processors)
40861  if (local_zeta_first > local_zeta_last)
40862  {
40863  const double tmp_zeta = local_zeta_first;
40864  local_zeta_first = local_zeta_last;
40865  local_zeta_last = tmp_zeta;
40866  }
40867 
40868  const double x1 = vector_bnd_vertices[i][1];
40869  const double y1 = vector_bnd_vertices[i][2];
40870  const double x2 = vector_bnd_vertices[i + 1][1];
40871  const double y2 = vector_bnd_vertices[i + 1][2];
40872  const double local_length =
40873  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
40874 
40875  // Compute the length in zeta units
40876  const double length_side = sqrt(constant_value * area_constraint[i]);
40877  const double length_side_zeta =
40878  (local_length_zeta * length_side) / local_length;
40879 
40880  // How many segments should be introduced
40881  const double n_seg_double = length_side_zeta / local_length_zeta;
40882 
40883  // One segment initialy (the original one)
40884  unsigned n_seg = 1;
40885 
40886  // How many more segments to introduce?
40887  n_seg += static_cast<unsigned>(std::floor(1.0 / n_seg_double));
40888 
40889  // Are there segments to introduce? There must be at least one
40890  // segment, the original one
40891  if (n_seg > 0)
40892  {
40893  // The zeta increment
40894  double zeta_increment = (local_length_zeta) / ((double)n_seg);
40895 
40896  Vector<double> zeta(1);
40897  // Create the n_seg segmets between each pair of nodes
40898  for (unsigned s = 1; s < n_seg; s++)
40899  {
40900  // Get the coordinates
40901  zeta[0] = local_zeta_first + zeta_increment * double(s);
40902  Vector<double> vertex(2);
40903  mesh_geom_obj_pt->position(zeta, vertex);
40904 
40905  // Create the new node
40906  Vector<double> new_node(3);
40907  new_node[0] = zeta[0];
40908  new_node[1] = vertex[0];
40909  new_node[2] = vertex[1];
40910 
40911  // Include the new node
40912  new_vector.push_back(new_node);
40913 
40914  } // for (s<=n_seg)
40915 
40916  } // if (n_seg > 0)
40917 
40918  } // if (area_constraint[i] >= 0)
40919 
40920  } // for (i < n_vertex-1)
40921 
40922  // Once finished all the vertices add the last node to the vector
40923  new_vector.push_back(vector_bnd_vertices[n_vertex - 1]);
40924 
40925  // If the new size of the vector (including the added nodes) is
40926  // different from the size of the vector before applying the
40927  // area length constraint then the polyline was updated
40928  n_vertex = new_vector.size();
40929  if (n_vertex != vector_bnd_vertices.size())
40930  {
40931  refinement_applied = true;
40932  }
40933 
40934  // Copy the new representation
40935  vector_bnd_vertices.resize(n_vertex);
40936  for (unsigned i = 0; i < n_vertex; i++)
40937  {
40938  vector_bnd_vertices[i].resize(3);
40939  vector_bnd_vertices[i][0] = new_vector[i][0];
40940  vector_bnd_vertices[i][1] = new_vector[i][1];
40941  vector_bnd_vertices[i][2] = new_vector[i][2];
40942  }
40943 
40944  } // if (n_vertex > 1)
40945 
40946  return refinement_applied;
40947  }
40948 
40949  //======================================================================
40950  /// Helper function that performs the unrefinement process
40951  /// on the specified boundary by using the provided vertices
40952  /// representation and the associated target area.
40953  /// NOTE: This is the version that applies unrefinement to shared
40954  /// boundaries
40955  //======================================================================
40956  template<class ELEMENT>
40959  const unsigned& b,
40960  const unsigned& c,
40961  Vector<Vector<double>>& vector_bnd_vertices,
40962  Vector<double>& area_constraint)
40963  {
40964  // Store the vertices not allowed for deletion
40965  std::set<Vector<double>> no_delete_vertex;
40966 
40967  // Does the boundary receives connections?
40968  const bool boundary_receive_connections =
40969  this->boundary_connections(b, c, no_delete_vertex);
40970 
40971  // Boolean that indicates whether an actual update of the vertex
40972  // coordinates was performed
40973  bool unrefinement_applied = false;
40974 
40975  // Return inmedately
40976  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40977  {
40978  return unrefinement_applied;
40979  }
40980 
40981  // Strategy to delete nodes:
40982 
40983  // Strategy to delete nodes: Consider the target area of the
40984  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40985  // if the number of segments to be added is equal to zero for both
40986  // elements then compute the average of both target areas and check
40987  // if the number of segments is still zero, if that holds mark the
40988  // node to be deleted. Before delete the node check whether it is in
40989  // the non_delete_vertex list. Skip the i+1-th node and go for the
40990  // (i+2)-th one, it means, increase the counter for current node by
40991  // two.
40992 
40993  // Number of vertices on the boundary
40994  unsigned n_vertex = vector_bnd_vertices.size();
40995 
40996  // Compute a constant value
40997  const double constant_value = 4.0 / sqrt(3.0);
40998 
40999  if (n_vertex > 2)
41000  {
41001  // Go through all the vertices and delete points when the target
41002  // area indicates zero points along the boundary
41003  for (unsigned i = 1; i < n_vertex - 1; i += 2)
41004  {
41005  // Is a target area assigned to the left and right element of
41006  // the i-th node
41007  if (area_constraint[i - 1] > 0 && area_constraint[i] > 0)
41008  {
41009  // Get the vertices to the left
41010  const double x1 = vector_bnd_vertices[i - 1][0];
41011  const double y1 = vector_bnd_vertices[i - 1][1];
41012  // ... and to the right of the i-th vertex
41013  const double x2 = vector_bnd_vertices[i + 1][0];
41014  const double y2 = vector_bnd_vertices[i + 1][1];
41015 
41016  // The distance
41017  const double local_length =
41018  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
41019 
41020  // Get the middle vertex
41021  const double x_m = vector_bnd_vertices[i][0];
41022  const double y_m = vector_bnd_vertices[i][1];
41023 
41024  // The average area
41025  const double average_area_constraint =
41026  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
41027 
41028  // Compute the base length of the triangle with
41029  // area_constraint area
41030  const double length_side =
41031  sqrt(constant_value * average_area_constraint);
41032 
41033  // Is the new length greater than the old one
41034  if ((length_side / local_length) > 1.0)
41035  {
41036  bool do_it = true;
41037 
41038  // If the vertex was proposed for deletion check that it is
41039  // allowed for being deleted
41040  if (do_it && boundary_receive_connections)
41041  {
41042  // Is the vertex one of the non deletable vertices
41043  for (std::set<Vector<double>>::iterator it =
41044  no_delete_vertex.begin();
41045  it != no_delete_vertex.end();
41046  it++)
41047  {
41048  // Compute the distance between the proposed node to delete
41049  // and the ones that should not be deleted
41050  const double x = (*it)[0];
41051  const double y = (*it)[1];
41052  double error = (x_m - x) * (x_m - x) + (y_m - y) * (y_m - y);
41053  error = sqrt(error);
41054 
41055  if (error <
41056  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41057  {
41058  // Do not delete the vertex
41059  do_it = false;
41060  break;
41061  }
41062  }
41063 
41064  } // if (do_it && boundary_receive_connections)
41065 
41066  // Remove node?
41067  if (do_it)
41068  {
41069  vector_bnd_vertices[i].resize(0);
41070  }
41071  } // if ((local_length / length_side) <= 1.3)
41072 
41073  } // if (area_constraint[i] >= 0)
41074 
41075  } // for (i < n_vertex-1)
41076 
41077  // Create a new (temporary) vector for the nodes, so that deleted nodes
41078  // are not stored
41079  Vector<Vector<double>> compact_vector;
41080 
41081  // Compact vector for target areas too
41082  Vector<double> compact_area_constraint;
41083 
41084  // Copy only the non deleted nodes
41085  for (unsigned i = 0; i < n_vertex; i++)
41086  {
41087  // If the entry was not deleted include it in the new vector
41088  if (vector_bnd_vertices[i].size() != 0)
41089  {
41090  compact_vector.push_back(vector_bnd_vertices[i]);
41091  }
41092  }
41093 
41094  // ------------------------------------------------------------------
41095  // The number of target areas
41096  unsigned n_area_constraint = area_constraint.size();
41097  if (n_area_constraint == 1)
41098  {
41099  // No node could be deleted then just copy the target area
41100  compact_area_constraint.push_back(area_constraint[0]);
41101  }
41102 
41103  // Copy the target areas
41104  for (unsigned i = 1; i < n_vertex; i += 2)
41105  {
41106  // If the entry was not deleted include the target areas of both
41107  // elements sharing the node
41108  if (vector_bnd_vertices[i].size() != 0)
41109  {
41110  compact_area_constraint.push_back(area_constraint[i - 1]);
41111  // To catch the case when working with even number of vertices
41112  if (i < n_area_constraint)
41113  {
41114  compact_area_constraint.push_back(area_constraint[i]);
41115  }
41116  }
41117  else
41118  {
41119  // If the node was deleted then compute the new target area as the
41120  // average of the target area of the elements sharing the node
41121  const double new_area_constraint =
41122  (area_constraint[i - 1] + area_constraint[i]) / 2.0;
41123  compact_area_constraint.push_back(new_area_constraint);
41124  }
41125  } // for (i < n_vertex)
41126 
41127  // If the size of the compact vector is different from the size of
41128  // the vector before applying the area length constraint then the
41129  // polyline was updated
41130  if (n_vertex != compact_vector.size())
41131  {
41132  unrefinement_applied = true;
41133  }
41134 
41135  // Copy back to the original vector
41136  n_vertex = compact_vector.size();
41137  vector_bnd_vertices.resize(n_vertex);
41138  for (unsigned i = 0; i < n_vertex; i++)
41139  {
41140  vector_bnd_vertices[i].resize(2);
41141  vector_bnd_vertices[i][0] = compact_vector[i][0];
41142  vector_bnd_vertices[i][1] = compact_vector[i][1];
41143  }
41144 
41145  // Copy back to the original vector of target areas
41146  unsigned ntarget_areas = compact_area_constraint.size();
41147  area_constraint.resize(ntarget_areas);
41148  for (unsigned i = 0; i < ntarget_areas; i++)
41149  {
41150  area_constraint[i] = compact_area_constraint[i];
41151  }
41152 
41153  } // if (n_vertex > 2)
41154 
41155  return unrefinement_applied;
41156  }
41157 
41158  //======================================================================
41159  /// Helper function that performs the refinement process
41160  /// on the specified boundary by using the provided vertices
41161  /// representation and the associated elements target area.
41162  /// NOTE: This is the version that applies refinement to shared
41163  /// boundaries
41164  //======================================================================
41165  template<class ELEMENT>
41168  Vector<Vector<double>>& vector_bnd_vertices,
41169  Vector<double>& area_constraint)
41170  {
41171  // Boolean that indicates whether an actual update of the vertex
41172  // coordinates was performed
41173  bool refinement_applied = false;
41174 
41175  // Return inmedately
41176  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
41177  {
41178  return refinement_applied;
41179  }
41180 
41181  // Get the number of segments
41182  unsigned nsegments = vector_bnd_vertices.size() - 1;
41183 
41184  // Create a new (temporary) vector for the nodes, so that new nodes
41185  // can be stored
41186  Vector<Vector<double>> tmp_bnd_vertices;
41187 
41188  // Compute a constant value
41189  const double constant_value = 4.0 / sqrt(3.0);
41190 
41191  for (unsigned s = 0; s < nsegments; s++)
41192  {
41193  Vector<double> left_vertex = vector_bnd_vertices[s];
41194  Vector<double> right_vertex = vector_bnd_vertices[s + 1];
41195 
41196  // Initial and final point of the segment
41197  const double x1 = left_vertex[0];
41198  const double y1 = left_vertex[1];
41199  const double x2 = right_vertex[0];
41200  const double y2 = right_vertex[1];
41201 
41202  // Lenght of the segment
41203  const double segment_length =
41204  sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
41205 
41206  // Compute the distance for the new segments
41207  const double new_segment_length =
41208  sqrt(constant_value * area_constraint[s]);
41209 
41210  // How many segments should be introduced
41211  const double n_seg_double = new_segment_length / segment_length;
41212 
41213  // One segment initialy (the original one)
41214  unsigned nseg = 1;
41215  // How many more segments to introduce?
41216  nseg += static_cast<unsigned>(std::floor(1.0 / n_seg_double));
41217 
41218  // The left vertex must be always included, even though no new vertex
41219  // be added
41220  tmp_bnd_vertices.push_back(left_vertex);
41221 
41222  // Are there segments to introduce? There must be at least one
41223  // segment, the original one
41224  if (nseg > 0)
41225  {
41226  // Create intermediate vertices
41227  double incrementx = (right_vertex[0] - left_vertex[0]) / (double)(nseg);
41228  double incrementy = (right_vertex[1] - left_vertex[1]) / (double)(nseg);
41229  for (unsigned i = 1; i < nseg; i++)
41230  {
41231  Vector<double> tmp_vertex(2);
41232  tmp_vertex[0] = left_vertex[0] + incrementx * i;
41233  tmp_vertex[1] = left_vertex[1] + incrementy * i;
41234  tmp_bnd_vertices.push_back(tmp_vertex);
41235  } // for (i < nseg)
41236 
41237  } // if (nseg > 0)
41238 
41239  } // for (s < nsegments)
41240 
41241  // Add the last vertex
41242  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
41243 
41244  // If the new size of the vector (including the added nodes) is
41245  // different from the size of the vector before applying the
41246  // refinement then the polyline was updated
41247  nsegments = tmp_bnd_vertices.size() - 1;
41248  if (nsegments != vector_bnd_vertices.size() - 1)
41249  {
41250  refinement_applied = true;
41251 
41252  // Copy across
41253  vector_bnd_vertices.resize(nsegments + 1);
41254  for (unsigned i = 0; i < nsegments + 1; i++)
41255  {
41256  vector_bnd_vertices[i].resize(2);
41257  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
41258  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
41259  }
41260  }
41261 
41262  return refinement_applied;
41263  }
41264 
41265  //======================================================================
41266  /// Updates the polylines representation after restart
41267  //======================================================================
41268  template<class ELEMENT>
41270  TriangleMeshPolygon*& polygon_pt)
41271  {
41272  // **********************************************************************
41273  // 1) Collect the elements adjacet to the polyline boundary id and
41274  // update the polyline
41275  // **********************************************************************
41276 
41277  // (1.1) Get the face mesh representation
41278  Vector<Mesh*> face_mesh_pt;
41279  get_face_mesh_representation(polygon_pt, face_mesh_pt);
41280 
41281  // (1.2) Create vertices of the polylines by using the vertices of the
41282  // FaceElements
41283  Vector<double> vertex_coord(3); // zeta,x,y
41284  Vector<double> bound_left(1);
41285  Vector<double> bound_right(1);
41286 
41287  const unsigned n_polyline = polygon_pt->npolyline();
41288 
41289  // Go for each polyline
41290  for (unsigned p = 0; p < n_polyline; p++)
41291  {
41292  // Get the MeshAsGeomObject representation just once per polyline,
41293  // this object is only used by the
41294  // refine_boundary_constrained_by_target_area() method. We get it here
41295  // to ensure that all processors (in a distributed context) get this
41296  // representation just once, and because an AllToAll MPI communication
41297  // is used in this calling
41298  MeshAsGeomObject* mesh_geom_obj_pt =
41299  new MeshAsGeomObject(face_mesh_pt[p]);
41300 
41301  // Set of coordinates that are on the boundary
41302  // Set entries are ordered on first entry in vector which stores
41303  // the boundary coordinate so the vertices come out in order!
41304  std::set<Vector<double>> vertex_nodes;
41305 
41306  // Vector to store the vertices, transfer the sorted vertices from the
41307  // set to this vector, --- including the z-value ---
41308  Vector<Vector<double>> tmp_vector_vertex_node;
41309 
41310  // Vector to store the coordinates of the polylines, same as the
41311  // tmp_vector_vertex_node vector (after adding more nodes) but
41312  // --- without the z-value ---, used to re-generate the polylines
41313  Vector<Vector<double>> vector_vertex_node;
41314 
41315 #ifdef OOMPH_HAS_MPI
41316  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41317  // Set of coordinates that are on the boundary (splitted boundary version)
41318  // The first vector is used to allocate the points for each sub-boundary
41319  // Set entries are ordered on first entry in vector which stores
41320  // the boundary coordinate so the vertices come out in order!
41321  Vector<std::set<Vector<double>>> sub_vertex_nodes;
41322 
41323  // Vector to store the vertices, transfer the sorted vertices from the
41324  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41325  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
41326 
41327  // Vector to store the coordinates of the polylines that will represent
41328  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41329  // but --- without the z-value ---, used to generate the sub-polylines
41330  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
41331  // --------- Stuff to deal with splitted boundaries ----------- End ------
41332 #endif
41333 
41334  // Get the boundary id
41335  unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
41336 
41337  /// Use a vector of vector for vertices and target areas to
41338  /// deal with the cases when the boundaries are split by the
41339  /// distribution process
41340 
41341  // Loop over the face elements (ordered) and add their vertices
41342  const unsigned nface_element = face_mesh_pt[p]->nelement();
41343 
41344  // Store the non halo face elements, the ones from which we will
41345  // get the vertices
41346  Vector<FiniteElement*> non_halo_face_element_pt;
41347  // Map to store the index of the face element on a boundary
41348  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
41349 
41350  for (unsigned ef = 0; ef < nface_element; ++ef)
41351  {
41352  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41353  // Skip the halo elements
41354 #ifdef OOMPH_HAS_MPI
41355  if (this->is_mesh_distributed())
41356  {
41357  // Only work with non-halo elements
41358  if (ele_face_pt->is_halo())
41359  {
41360  continue;
41361  }
41362  }
41363 #endif
41364  // Add the face element to the vector
41365  non_halo_face_element_pt.push_back(ele_face_pt);
41366  face_element_index_on_boundary[ele_face_pt] = ef;
41367  }
41368 
41369  // Get the number of non halo face element
41370  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41371 
41372  // Map to know the already sorted face elements
41373  std::map<FiniteElement*, bool> face_element_done;
41374 
41375  // Number of done face elements
41376  unsigned nsorted_face_elements = 0;
41377 
41378 #ifdef OOMPH_HAS_MPI
41379  // Counter for sub_boundaries
41380  unsigned nsub_boundaries = 0;
41381 #endif // #ifdef OOMPH_HAS_MPI
41382 
41383  // Continue until all the face elements have been sorted
41384  // This while is to deal with the cases of splitted boundaries
41385  while (nsorted_face_elements < nnon_halo_face_element)
41386  {
41387  // Get and initial face element
41388  FiniteElement* ele_face_pt = 0;
41389 #ifdef PARANOID
41390  bool found_initial_face_element = false;
41391 #endif
41392 
41393  unsigned iface = 0;
41394  for (iface = 0; iface < nnon_halo_face_element; iface++)
41395  {
41396  ele_face_pt = non_halo_face_element_pt[iface];
41397  // If not done then take it as initial face element
41398  if (!face_element_done[ele_face_pt])
41399  {
41400 #ifdef PARANOID
41401  found_initial_face_element = true;
41402 #endif
41403  nsorted_face_elements++;
41404  iface++;
41405  break;
41406  }
41407  }
41408 
41409 #ifdef PARANOID
41410  if (!found_initial_face_element)
41411  {
41412  std::ostringstream error_message;
41413  error_message << "Could not find an initial face element for the "
41414  "current segment\n";
41415  // << "----- Possible memory leak -----\n";
41416  throw OomphLibError(
41417  error_message.str(),
41418  "RefineableTriangleMesh::update_polygon_after_restart()",
41419  OOMPH_EXCEPTION_LOCATION);
41420  }
41421 #endif
41422 
41423  // Local set of coordinates that are on the boundary
41424  // Set entries are ordered on first entry in vector which stores
41425  // the boundary coordinate so the vertices come out in order!
41426  std::set<Vector<double>> local_vertex_nodes;
41427 
41428  // Vector to store the vertices, transfer the sorted vertices from the
41429  // set (local) to this vector (local), --- including the z-value ---
41430  Vector<Vector<double>> local_tmp_vector_vertex_node;
41431 
41432  // ------------------------------------------------------------------
41433  // ------------------------------------------------------------------
41434  // -----------------------------------------------------------------
41435  // Add the vertices of the initial face element to the set of local
41436  // sorted vertices
41437  // -----------------------------------------------------------------
41438  unsigned nnode = ele_face_pt->nnode();
41439  // Add the left-hand node to the set:
41440  // Boundary coordinate
41441  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
41442  vertex_coord[0] = bound_left[0];
41443 
41444  // Actual coordinates
41445  for (unsigned i = 0; i < 2; i++)
41446  {
41447  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
41448  }
41449  local_vertex_nodes.insert(vertex_coord);
41450 
41451  // Add the right-hand nodes to the set:
41452  // Boundary coordinate
41453  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
41454  bound, bound_right);
41455  vertex_coord[0] = bound_right[0];
41456 
41457  // Actual coordinates
41458  for (unsigned i = 0; i < 2; i++)
41459  {
41460  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
41461  }
41462  local_vertex_nodes.insert(vertex_coord);
41463 
41464  // The initial and final node on the set
41465  Node* first_node_pt = ele_face_pt->node_pt(0);
41466  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
41467 
41468  // Mark the current face element as done
41469  face_element_done[ele_face_pt] = true;
41470 
41471  // ------------------------------------------------------------------
41472  // ------------------------------------------------------------------
41473  // ------------------------------------------------------------------
41474 
41475  // Continue iterating if a new face element has been added to the
41476  // list
41477  bool face_element_added = false;
41478 
41479  // While a new face element has been added to the set of sorted
41480  // face elements then re-iterate
41481  do
41482  {
41483  // Start from the next face elements since we have already added
41484  // the previous one as the initial face element (any previous face
41485  // element had to be added on previous iterations)
41486  for (unsigned iiface = iface; iiface < nnon_halo_face_element;
41487  iiface++)
41488  {
41489  face_element_added = false;
41490  ele_face_pt = non_halo_face_element_pt[iiface];
41491  if (!face_element_done[ele_face_pt])
41492  {
41493  // Get each individual node to check if they are contiguous
41494  nnode = ele_face_pt->nnode();
41495  Node* left_node_pt = ele_face_pt->node_pt(0);
41496  Node* right_node_pt = ele_face_pt->node_pt(nnode - 1);
41497 
41498  if (left_node_pt == first_node_pt)
41499  {
41500  first_node_pt = right_node_pt;
41501  face_element_added = true;
41502  }
41503  else if (left_node_pt == last_node_pt)
41504  {
41505  last_node_pt = right_node_pt;
41506  face_element_added = true;
41507  }
41508  else if (right_node_pt == first_node_pt)
41509  {
41510  first_node_pt = left_node_pt;
41511  face_element_added = true;
41512  }
41513  else if (right_node_pt == last_node_pt)
41514  {
41515  last_node_pt = left_node_pt;
41516  face_element_added = true;
41517  }
41518 
41519  if (face_element_added)
41520  {
41521  // Add the left-hand node to the set:
41522  // Boundary coordinate
41523  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
41524  vertex_coord[0] = bound_left[0];
41525 
41526  // Actual coordinates
41527  for (unsigned i = 0; i < 2; i++)
41528  {
41529  vertex_coord[i + 1] = left_node_pt->x(i);
41530  }
41531  local_vertex_nodes.insert(vertex_coord);
41532 
41533  // Add the right-hand nodes to the set:
41534  // Boundary coordinate
41535  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
41536  vertex_coord[0] = bound_right[0];
41537 
41538  // Actual coordinates
41539  for (unsigned i = 0; i < 2; i++)
41540  {
41541  vertex_coord[i + 1] = right_node_pt->x(i);
41542  }
41543  local_vertex_nodes.insert(vertex_coord);
41544 
41545  // Mark as done only if one of its nodes has been
41546  // added to the list
41547  face_element_done[ele_face_pt] = true;
41548  nsorted_face_elements++;
41549 
41550  break;
41551  }
41552 
41553  } // if (!edge_done[edge])
41554  } // for (iiedge < nedges)
41555  } while (face_element_added &&
41556  (nsorted_face_elements < nnon_halo_face_element));
41557 
41558  // -----------------------------------------------------------------
41559  // At this point we already have a sorted set of nodes and
41560  // can be used to peform the unrefinement and refinement procedures
41561  // -----------------------------------------------------------------
41562 
41563  // Get the number of nodes on the list
41564  const unsigned nlocal_nodes = local_vertex_nodes.size();
41565  // Change representation to vector for easy of handling ...
41566  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41567 
41568  // Copy the vertices of the nodes
41569  unsigned counter = 0;
41570  std::set<Vector<double>>::iterator it_vertex;
41571  for (it_vertex = local_vertex_nodes.begin();
41572  it_vertex != local_vertex_nodes.end();
41573  it_vertex++)
41574  {
41575  local_tmp_vector_vertex_node[counter].resize(3);
41576  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41577  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41578  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41579  counter++;
41580  }
41581 
41582  // *********************************************************************
41583  // 3) Create the vertices along the boundary using the target area to
41584  // define the distance among them
41585  // *********************************************************************
41586 
41587  // Clear the local containter to recover the nodes ordered using the
41588  // zeta value
41589  local_vertex_nodes.clear();
41590 
41591  // At the end of each unrefinement/refinement step store the new nodes
41592  // on the set that will give rise to the vertices of the new polyline
41593  // representation
41594  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41595  for (unsigned i = 0; i < nnew_nodes; i++)
41596  {
41597  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41598  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41599  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41600  vertex_nodes.insert(vertex_coord); // Global container
41601  local_vertex_nodes.insert(vertex_coord);
41602  }
41603 
41604 #ifdef OOMPH_HAS_MPI
41605  if (this->is_mesh_distributed())
41606  {
41607  // Add the set of vertices for the boundary, this will help to detect
41608  // if we need to deal with sub_boundaries and sub_polylines represen.
41609  sub_vertex_nodes.push_back(local_vertex_nodes);
41610  // Increase the counter for sub_boundaries
41611  nsub_boundaries++;
41612  }
41613 #endif
41614 
41615  } // while(nsorted_face_elements < nnon_halo_face_element)
41616 
41617  // Now turn into vector for ease of handling...
41618  unsigned npoly_vertex = vertex_nodes.size();
41619  tmp_vector_vertex_node.resize(npoly_vertex);
41620  unsigned count = 0;
41621  std::set<Vector<double>>::iterator it;
41622  for (it = vertex_nodes.begin(); it != vertex_nodes.end(); ++it)
41623  {
41624  tmp_vector_vertex_node[count].resize(3);
41625  tmp_vector_vertex_node[count][0] = (*it)[0];
41626  tmp_vector_vertex_node[count][1] = (*it)[1];
41627  tmp_vector_vertex_node[count][2] = (*it)[2];
41628  ++count;
41629  }
41630 
41631 #ifdef OOMPH_HAS_MPI
41632  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41633 #ifdef PARANOID
41634  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41635  if (nsub_boundaries_set != nsub_boundaries)
41636  {
41637  std::ostringstream error_message;
41638  error_message
41639  << "The number of found sub-boundaries and the number of counted\n"
41640  << "sub-boundaries are different:\n"
41641  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
41642  << "Number of counted sub-boundaries: (" << nsub_boundaries << ")\n";
41643  throw OomphLibError(
41644  error_message.str(),
41645  "RefineableTriangleMesh::update_polygon_after_restart()",
41646  OOMPH_EXCEPTION_LOCATION);
41647  }
41648 #endif
41649 
41650  // Verify if need to deal with sub_boundaries
41651  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41652  {
41653  // Mark the boundary as been splitted in the partition process
41654  this->Boundary_was_splitted[bound] = true;
41655  // Resize the vector to store the info. of sub-boundaries
41656  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41657  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41658  {
41659  // Turn info. into vector for ease of handling...
41660  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41661  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41662  unsigned subcount = 0;
41663  std::set<Vector<double>>::iterator subit;
41664  for (subit = sub_vertex_nodes[isub].begin();
41665  subit != sub_vertex_nodes[isub].end();
41666  ++subit)
41667  {
41668  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41669  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41670  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41671  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41672  ++subcount;
41673  }
41674  }
41675  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41676  // --------- Stuff for the sub_boundaries ----- End section ------------
41677 #endif // OOMPH_HAS_MPI
41678 
41679 
41680  // For further processing the three-dimensional vector
41681  // has to be reduced to a two-dimensional vector
41682  unsigned n_vertex = tmp_vector_vertex_node.size();
41683 
41684  // Resize the vector for vectices
41685  vector_vertex_node.resize(n_vertex);
41686  for (unsigned i = 0; i < n_vertex; i++)
41687  {
41688  vector_vertex_node[i].resize(2);
41689  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
41690  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
41691  }
41692 
41693 #ifdef OOMPH_HAS_MPI
41694  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41695  // Verify if need to deal with sub_boundaries
41696  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41697  {
41698  // For further processing the three-dimensional vector
41699  // has to be reduced to a two-dimensional vector
41700  // Resize the vector to store the info. of sub-boundaries
41701  sub_vector_vertex_node.resize(nsub_boundaries);
41702  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41703  {
41704  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
41705  // Resize the vector for vectices
41706  sub_vector_vertex_node[isub].resize(subn_vertex);
41707  for (unsigned i = 0; i < subn_vertex; i++)
41708  {
41709  sub_vector_vertex_node[isub][i].resize(2);
41710  sub_vector_vertex_node[isub][i][0] =
41711  sub_tmp_vector_vertex_node[isub][i][1];
41712  sub_vector_vertex_node[isub][i][1] =
41713  sub_tmp_vector_vertex_node[isub][i][2];
41714  }
41715  }
41716  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41717 
41718  // We already have the info. for the sub-boundaries (if necessary)
41719  // and then we can create the sub-boundaries representations to
41720  // ease the generation of the mesh by Triangle
41721 
41722  // --------- Stuff for the sub_boundaries ----- End section ------------
41723 #endif // OOMPH_HAS_MPI
41724 
41725  // *********************************************************************
41726  // 4) Check for contiguousness
41727  // *********************************************************************
41728 #ifdef OOMPH_HAS_MPI
41729  // Only perform this checking if the mesh is not distributed
41730  // When the mesh is distributed the polylines continuity is
41731  // addressed with the sort_polylines_helper() method
41732  if (!this->is_mesh_distributed())
41733 #endif
41734  {
41735  if (p > 0)
41736  {
41737  // Final end point of previous line
41738  Vector<double> final_vertex_of_previous_segment;
41739  unsigned n_prev_vertex =
41740  polygon_pt->curve_section_pt(p - 1)->nvertex();
41741  final_vertex_of_previous_segment =
41742  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(n_prev_vertex -
41743  1);
41744 
41745  unsigned prev_seg_boundary_id =
41746  polygon_pt->curve_section_pt(p - 1)->boundary_id();
41747 
41748  // Find the error between the final vertex of the previous
41749  // line and the first vertex of the current line
41750  double error = 0.0;
41751  for (unsigned i = 0; i < 2; i++)
41752  {
41753  const double dist = final_vertex_of_previous_segment[i] -
41754  (*vector_vertex_node.begin())[i];
41755  error += dist * dist;
41756  }
41757  error = sqrt(error);
41758 
41759  // If the error is bigger than the tolerance then
41760  // we probably need to reverse, but better check
41761  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41762  {
41763  // Find the error between the final vertex of the previous
41764  // line and the last vertex of the current line
41765  double rev_error = 0.0;
41766  for (unsigned i = 0; i < 2; i++)
41767  {
41768  const double dist = final_vertex_of_previous_segment[i] -
41769  (*--vector_vertex_node.end())[i];
41770  rev_error += dist * dist;
41771  }
41772  rev_error = sqrt(rev_error);
41773 
41774  if (rev_error >
41775  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41776  {
41777  // It could be possible that the first segment be reversed and we
41778  // did not notice it because this check does not apply for the
41779  // first segment. We can verify if the first segment is reversed
41780  // by using the vertex number 1
41781  if (p == 1)
41782  {
41783  // Initial end point of previous line
41784  Vector<double> initial_vertex_of_previous_segment;
41785 
41786  initial_vertex_of_previous_segment =
41787  polygon_pt->polyline_pt(p - 1)->vertex_coordinate(0);
41788 
41789  unsigned prev_seg_boundary_id =
41790  polygon_pt->curve_section_pt(p - 1)->boundary_id();
41791 
41792  // Find the error between the initial vertex of the previous
41793  // line and the first vertex of the current line
41794  double error = 0.0;
41795  for (unsigned i = 0; i < 2; i++)
41796  {
41797  const double dist = initial_vertex_of_previous_segment[i] -
41798  (*vector_vertex_node.begin())[i];
41799  error += dist * dist;
41800  }
41801  error = sqrt(error); // Reversed only the previous one
41802 
41803  // If the error is bigger than the tolerance then
41804  // we probably need to reverse, but better check
41805  if (error >
41806  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41807  {
41808  // Find the error between the final vertex of the previous
41809  // line and the last vertex of the current line
41810  double rev_error = 0.0;
41811  for (unsigned i = 0; i < 2; i++)
41812  {
41813  const double dist = initial_vertex_of_previous_segment[i] -
41814  (*--vector_vertex_node.end())[i];
41815  rev_error += dist * dist;
41816  }
41817  rev_error =
41818  sqrt(rev_error); // Reversed both the current one and
41819  // the previous one
41820 
41821  if (rev_error >
41822  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41823  {
41824  std::ostringstream error_stream;
41825  error_stream
41826  << "The distance between the first node of the current\n"
41827  << "line segment (boundary " << bound
41828  << ") and either end of "
41829  << "the previous line segment\n"
41830  << "(boundary " << prev_seg_boundary_id
41831  << ") is bigger than "
41832  << "the desired tolerance "
41833  << ToleranceForVertexMismatchInPolygons::Tolerable_error
41834  << ".\n"
41835  << "This suggests that the polylines defining the "
41836  "polygonal\n"
41837  << "representation are not properly ordered.\n"
41838  << "Fail on last vertex of polyline: ("
41839  << prev_seg_boundary_id
41840  << ") and\nfirst vertex of polyline (" << bound
41841  << ").\nThis should have failed when first trying to"
41842  << " construct the\npolygon.\n";
41843  throw OomphLibError(
41844  error_stream.str(),
41845  "RefineableTriangleMesh::update_polygon_after_restart()",
41846  OOMPH_EXCEPTION_LOCATION);
41847  }
41848  else
41849  {
41850  // Reverse both
41851  // Reverse the current vector to line up with the previous
41852  // one
41853  std::reverse(vector_vertex_node.begin(),
41854  vector_vertex_node.end());
41855  polygon_pt->polyline_pt(p - 1)->reverse();
41856  }
41857  }
41858  else
41859  {
41860  // Reverse the previous one
41861  polygon_pt->polyline_pt(p - 1)->reverse();
41862  }
41863 
41864  } // if p == 1
41865  else
41866  {
41867  std::ostringstream error_stream;
41868  error_stream
41869  << "The distance between the first node of the current\n"
41870  << "line segment (boundary " << bound
41871  << ") and either end of "
41872  << "the previous line segment\n"
41873  << "(boundary " << prev_seg_boundary_id
41874  << ") is bigger than the "
41875  << "desired tolerance "
41876  << ToleranceForVertexMismatchInPolygons::Tolerable_error
41877  << ".\n"
41878  << "This suggests that the polylines defining the polygonal\n"
41879  << "representation are not properly ordered.\n"
41880  << "Fail on last vertex of polyline: ("
41881  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
41882  << bound << ").\n"
41883  << "This should have failed when first trying to construct "
41884  "the\n"
41885  << "polygon.\n";
41886  throw OomphLibError(
41887  error_stream.str(),
41888  "RefineableTriangleMesh::update_polygon_after_restart()",
41889  OOMPH_EXCEPTION_LOCATION);
41890  }
41891  }
41892  else
41893  {
41894  // Reverse the current vector to line up with the previous one
41895  std::reverse(vector_vertex_node.begin(),
41896  vector_vertex_node.end());
41897  }
41898  } // error
41899  } // p > 0
41900  } // is mesh not distributed
41901 
41902  // *********************************************************************
41903  // 5) Update the polylines representation
41904  // *********************************************************************
41905  // if (applied_area_length_constraint)
41906  // If only applied when there is a change then it keeps the
41907  // previous polyline representation, it means, it does not delete
41908  // the boundaries that are not part of the domain. We must update
41909  // the boundary representation
41910  {
41911  n_vertex = vector_vertex_node.size();
41912 
41913  // Now update the polyline according to the new vertices
41914  // The new one representation
41915  TriangleMeshPolyLine* tmp_polyline_pt =
41916  new TriangleMeshPolyLine(vector_vertex_node, bound);
41917 
41918  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41919  // {
41920  // DEBP(h);
41921  // DEBP(vector_vertex_node[h][0]);
41922  // DEBP(vector_vertex_node[h][1]);
41923  // }
41924 
41925  // Create a temporal "curve section" version of the recently created
41926  // polyline
41927  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
41928 
41929  // Tolerance below which the middle point can be deleted
41930  // (ratio of deflection to element length)
41931  double unrefinement_tolerance =
41932  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41933 
41934  // Tolerance to add points
41935  double refinement_tolerance =
41936  polygon_pt->polyline_pt(p)->refinement_tolerance();
41937 
41938  // Establish refinement and unrefinement tolerance
41939  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
41940  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
41941 
41942  // Establish the maximum length constraint
41943  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41944  tmp_polyline_pt->set_maximum_length(maximum_length);
41945 
41946  if (n_vertex >= 2)
41947  {
41948  // Pass the connection information from the old polyline to the
41949  // new one
41950  this->copy_connection_information(polygon_pt->polyline_pt(p),
41951  tmp_curve_section_pt);
41952  }
41953 
41954  // Now update the polyline according to the new vertices but
41955  // first check if the object is allowed to delete the representation
41956  // or if it should be done by other object
41957  bool delete_it_on_destructor = false;
41958 
41959  std::set<TriangleMeshCurveSection*>::iterator it =
41960  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41961 
41962  if (it != this->Free_curve_section_pt.end())
41963  {
41964  this->Free_curve_section_pt.erase(it);
41965  delete polygon_pt->curve_section_pt(p);
41966  delete_it_on_destructor = true;
41967  }
41968 
41969  // *****************************************************************
41970  // Copying the new representation
41971  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41972 
41973  // Update the Boundary - Polyline map
41974  this->Boundary_curve_section_pt[bound] =
41975  polygon_pt->curve_section_pt(p);
41976 
41977  if (delete_it_on_destructor)
41978  {
41979  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41980  }
41981 
41982 #ifdef OOMPH_HAS_MPI
41983  // --------- Stuff for the sub_boundaries ----- Begin section --------
41984  // Verify if need to deal with sub_boundaries
41985  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41986  {
41987  // Create temporary representations for the boundaries, only to
41988  // create the mesh when calling Triangle
41989  // Clear all previous stored data
41990  this->Boundary_subpolylines[bound].clear();
41991  // Now create storage for the sub-boundaries
41992  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41993  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41994  {
41995  // Now update the polyline according to the sub set of
41996  // vertices, set the chunk number of the polyline
41997  TriangleMeshPolyLine* sub_tmp_polyline_pt =
41998  new TriangleMeshPolyLine(
41999  sub_vector_vertex_node[isub], bound, isub);
42000 
42001  // Add the sub-polyline to the container to represent the boundary
42002  // in parts
42003  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42004 
42005  // No need to send the unrefinement/refinement and maximum
42006  // length constraints since these are only temporary
42007  // representations. These polylines can be deleted once the
42008  // new polygons that represent the distributed domain have
42009  // been created
42010 
42011  } // for (isub < nsub_boundaries)
42012 
42013  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42014  // --------- Stuff for the sub_boundaries ----- End section ---------
42015 #endif // OOMPH_HAS_MPI
42016 
42017  } // update polyline representation
42018 
42019  // Delete the allocated memory for the geometric object that
42020  // represents the curvilinear boundary
42021  delete mesh_geom_obj_pt;
42022 
42023  } // npolyline
42024 
42025  // Cleanup the face mesh
42026  for (unsigned p = 0; p < n_polyline; p++)
42027  {
42028  face_mesh_pt[p]->flush_node_storage();
42029  delete face_mesh_pt[p];
42030  }
42031  }
42032 
42033 
42034  //======================================================================
42035  /// Updates the open curve representation after restart
42036  //======================================================================
42037  template<class ELEMENT>
42039  TriangleMeshOpenCurve*& open_curve_pt)
42040  {
42041  // **********************************************************************
42042  // 1) Get the vertices along the boundaries ids of the polylines and
42043  // update them
42044  // **********************************************************************
42045 
42046  // (1.1) Get the face mesh representation
42047  Vector<Mesh*> face_mesh_pt;
42048  get_face_mesh_representation(open_curve_pt, face_mesh_pt);
42049 
42050  // (1.2) Create vertices of the polylines by using the vertices of the
42051  // FaceElements
42052  Vector<double> vertex_coord(3); // zeta,x,y
42053  Vector<double> bound_left(1);
42054  Vector<double> bound_right(1);
42055 
42056  const unsigned ncurve_section = open_curve_pt->ncurve_section();
42057  // Go for each curve section
42058  for (unsigned cs = 0; cs < ncurve_section; cs++)
42059  {
42060  // Get the MeshAsGeomObject representation just once per polyline,
42061  // this object is only used by the
42062  // refine_boundary_constrained_by_target_area() method. We get it here
42063  // to ensure that all processors (in a distributed context) get this
42064  // representation just once, and because an AllToAll MPI communication
42065  // is used in this calling
42066  MeshAsGeomObject* mesh_geom_obj_pt =
42067  new MeshAsGeomObject(face_mesh_pt[cs]);
42068 
42069  // Get the boundary id
42070  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
42071 
42072  /// Use a vector of vector for vertices and target areas to deal
42073  /// with the cases when the boundaries are split bn the
42074  /// distribution process. Internal boundaries may be completely or
42075  /// partially overlapped by shared boundaries
42076 
42077  // Loop over the face elements and add their vertices (they are
42078  // automatically sorted because of the set)
42079  const unsigned nface_element = face_mesh_pt[cs]->nelement();
42080  // Store the non halo elements and the element at the other side of
42081  // the boundary (whatever it be halo or not), the first will be the
42082  // ones from which we will get the vertices (in even position)
42083  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
42084 
42085  // Map to store the index of the face element on a boundary
42086  std::map<FiniteElement*, unsigned> face_element_index_on_boundary;
42087 
42088  // Map to know the already sorted face elements
42089  std::map<FiniteElement*, bool> face_element_done;
42090 
42091  for (unsigned ef = 0; ef < nface_element; ++ef)
42092  {
42093  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
42094 
42095  // Skip the halo elements (not used as base elements, only
42096  // include those elements which one of its counterparts -- at the
42097  // other side of the boundary -- is non halo)
42098 #ifdef OOMPH_HAS_MPI
42099  if (this->is_mesh_distributed())
42100  {
42101  // Only work with non-halo elements
42102  if (ele_face_pt->is_halo())
42103  {
42104  continue;
42105  }
42106  }
42107 #endif
42108 
42109  // Check if not already done
42110  if (!face_element_done[ele_face_pt])
42111  {
42112  // Add the element and look for the element at the other side
42113  // of the boundary to add it immediately after the new added
42114  // element
42115  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
42116  // Create the map of the face element with the index
42117  face_element_index_on_boundary[ele_face_pt] = ef;
42118  // Mark the current element as done
42119  face_element_done[ele_face_pt] = true;
42120  // Get the number of nodes
42121  const unsigned nnodes = ele_face_pt->nnode();
42122  // Get the left and right node to look for the elements at the
42123  // other side of the boundary
42124  Node* left_node_pt = ele_face_pt->node_pt(0);
42125  Node* right_node_pt = ele_face_pt->node_pt(nnodes - 1);
42126 
42127 #ifdef PARANOID
42128  // Flag to know if the element at the other side of the
42129  // boundary was found
42130  bool found_other_side_face_ele = false;
42131 #endif
42132  for (unsigned iface = 0; iface < nface_element; iface++)
42133  {
42134  // Get the candidate face element
42135  FiniteElement* cele_face_pt =
42136  face_mesh_pt[cs]->finite_element_pt(iface);
42137  // Check if not already done
42138  if (!face_element_done[cele_face_pt])
42139  {
42140  Node* cleft_node_pt = cele_face_pt->node_pt(0);
42141  Node* cright_node_pt = cele_face_pt->node_pt(nnodes - 1);
42142 
42143  // Check if the nodes are the same
42144  if ((left_node_pt == cleft_node_pt &&
42145  right_node_pt == cright_node_pt) ||
42146  (left_node_pt == cright_node_pt &&
42147  right_node_pt == cleft_node_pt))
42148  {
42149  // Add the element to the storage
42150  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
42151  // ... and mark the element as done
42152  face_element_done[cele_face_pt] = true;
42153  // Create the map of the face element with the index
42154  face_element_index_on_boundary[cele_face_pt] = iface;
42155 #ifdef PARANOID
42156  // Set the flag of found other side face element
42157  found_other_side_face_ele = true;
42158 #endif
42159  break;
42160  }
42161  }
42162  } // (iface < nface_element)
42163 
42164 #ifdef PARANOID
42165  if (!found_other_side_face_ele)
42166  {
42167  std::ostringstream error_message;
42168  error_message
42169  << "The face element at the other side of the boundary (" << bound
42170  << ") was not found!!\n"
42171  << "These are the nodes of the face element:\n"
42172  << "(" << left_node_pt->x(0) << ", " << left_node_pt->x(1) << ") "
42173  << "and (" << right_node_pt->x(0) << "," << right_node_pt->x(1)
42174  << ")\n\n";
42175  throw OomphLibError(
42176  error_message.str(),
42177  "RefineableTriangleMesh::update_open_curve_after_restart()",
42178  OOMPH_EXCEPTION_LOCATION);
42179  }
42180 #endif
42181  } // if (!face_ele_done[ele_face_pt])
42182 
42183  } // (ef < nface_element)
42184 
42185  // Clear the map of the already done face elements
42186  // This will now be used to sort the face elements
42187  face_element_done.clear();
42188 
42189  // Set of coordinates that are on the boundary
42190  // The entries are sorted on first entry in vector which stores
42191  // the boundary coordinate so the vertices come out in order!
42192  std::set<Vector<double>> vertex_nodes;
42193 
42194  // Vector to store the vertices, transfer the sorted vertices from the
42195  // set to this vector, --- including the z-value ---
42196  Vector<Vector<double>> tmp_vector_vertex_node;
42197 
42198  // Vector to store the coordinates of the polylines, same as the
42199  // tmp_vector_vertex_node vector (after adding more nodes) but
42200  // --- without the z-value ---, used to re-generate the polylines
42201  Vector<Vector<double>> vector_vertex_node;
42202 
42203 #ifdef OOMPH_HAS_MPI
42204  // Indicates if the set of vertices give rise to a internal
42205  // boundary that will be used as shared boundary or as normal
42206  // internal boundary -- Only used to deal with internal boundaries
42207  // in a distributed scheme
42208  std::vector<bool> internal_to_shared_boundary;
42209 
42210  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
42211  // Set of coordinates that are on the boundary (splitted boundary version)
42212  // The first vector is used to allocate the points for each sub-boundary
42213  // Set entries are ordered on first entry in vector which stores
42214  // the boundary coordinate so the vertices come out in order!
42215  Vector<std::set<Vector<double>>> sub_vertex_nodes;
42216 
42217  // Vector to store the vertices, transfer the sorted vertices from the
42218  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
42219  Vector<Vector<Vector<double>>> sub_tmp_vector_vertex_node;
42220 
42221  // Vector to store the coordinates of the polylines that will represent
42222  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
42223  // but --- without the z-value ---, used to generate the sub-polylines
42224  Vector<Vector<Vector<double>>> sub_vector_vertex_node;
42225 
42226  // --------- Stuff to deal with splitted boundaries ----------- End ------
42227 #endif
42228 
42229  // Sort face elements, separate those with both nonhalo face
42230  // elements from those with one halo and one nonhalo face element
42231 
42232  // Number of done face elements
42233  unsigned nsorted_face_elements = 0;
42234 
42235 #ifdef OOMPH_HAS_MPI
42236  // Counter for sub_boundaries
42237  unsigned nsub_boundaries = 0;
42238 #endif // #ifdef OOMPH_HAS_MPI
42239 
42240  // Total number of non halo double face element
42241  const unsigned nnon_halo_doubled_face_ele =
42242  non_halo_doubled_face_element_pt.size();
42243 
42244  // Continue until all the face elements have been sorted
42245  // This while is to deal with the cases of splitted boundaries
42246  while (nsorted_face_elements < nnon_halo_doubled_face_ele)
42247  {
42248  // Get and initial face element
42249  FiniteElement* ele_face_pt = 0;
42250  FiniteElement* repeated_ele_face_pt = 0;
42251 #ifdef PARANOID
42252  bool found_initial_face_element = false;
42253 #endif
42254 
42255  // Flag to know if we are working with a face element which the
42256  // face element at the other side of the boundary is also non
42257  // halo
42258  bool both_root_face_elements_are_nonhalo = false;
42259 
42260  unsigned iface = 0;
42261  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface += 2)
42262  {
42263  ele_face_pt = non_halo_doubled_face_element_pt[iface];
42264  // If not done then take it as initial face element
42265  if (!face_element_done[ele_face_pt])
42266  {
42267  // Mark it as done
42268  face_element_done[ele_face_pt] = true;
42269  // Get the other side boundary face element
42270  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface + 1];
42271  // ... also mark as done the repeated face element
42272  face_element_done[repeated_ele_face_pt] = true;
42273 
42274 #ifdef OOMPH_HAS_MPI
42275  if (!repeated_ele_face_pt->is_halo())
42276  {
42277  both_root_face_elements_are_nonhalo = true;
42278  }
42279 #endif // #ifdef OOMPH_HAS_MPI
42280 
42281  // Plus two because internal boundaries have
42282  // two face elements per each edge
42283  nsorted_face_elements += 2;
42284  iface += 2;
42285 #ifdef PARANOID
42286  // And set the flag to true
42287  found_initial_face_element = true;
42288 #endif
42289  break;
42290  }
42291  }
42292 
42293 #ifdef PARANOID
42294  if (!found_initial_face_element)
42295  {
42296  std::ostringstream error_message;
42297  error_message << "Could not find an initial face element for the "
42298  "current segment\n";
42299  // << "----- Possible memory leak -----\n";
42300  throw OomphLibError(error_message.str(),
42301  OOMPH_CURRENT_FUNCTION,
42302  OOMPH_EXCEPTION_LOCATION);
42303  }
42304 #endif
42305 
42306  // Local set of coordinates that are on the boundary Set entries
42307  // are ordered on first entry in vector which stores the boundary
42308  // coordinate so the vertices come out in order
42309  std::set<Vector<double>> local_vertex_nodes;
42310 
42311  // Vector to store the vertices, transfer the sorted vertices from the
42312  // set (local) to this vector (local), --- including the z-value ---
42313  Vector<Vector<double>> local_tmp_vector_vertex_node;
42314 
42315  // ------------------------------------------------------------------
42316  // ------------------------------------------------------------------
42317  // Add the vertices of the initial face element to the set of local
42318  // sorted vertices
42319  // ------------------------------------------------------------------
42320  // ------------------------------------------------------------------
42321  const unsigned nnode = ele_face_pt->nnode();
42322  // Add the left-hand node to the set:
42323  // Boundary coordinate
42324  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound, bound_left);
42325  vertex_coord[0] = bound_left[0];
42326 
42327  // Actual coordinates
42328  for (unsigned i = 0; i < 2; i++)
42329  {
42330  vertex_coord[i + 1] = ele_face_pt->node_pt(0)->x(i);
42331  }
42332  local_vertex_nodes.insert(vertex_coord);
42333 
42334  // Add the right-hand node to the set:
42335  // Boundary coordinate
42336  ele_face_pt->node_pt(nnode - 1)->get_coordinates_on_boundary(
42337  bound, bound_right);
42338  vertex_coord[0] = bound_right[0];
42339 
42340  // Actual coordinates
42341  for (unsigned i = 0; i < 2; i++)
42342  {
42343  vertex_coord[i + 1] = ele_face_pt->node_pt(nnode - 1)->x(i);
42344  }
42345  local_vertex_nodes.insert(vertex_coord);
42346 
42347  // The initial and final node on the set
42348  Node* first_node_pt = ele_face_pt->node_pt(0);
42349  Node* last_node_pt = ele_face_pt->node_pt(nnode - 1);
42350 
42351  // Continue iterating if a new face element has been added to the
42352  // list
42353  bool face_element_added = false;
42354 
42355  // While a new face element has been added to the set of sorted
42356  // face elements then re-iterate
42357  do
42358  {
42359  // Start from the next face elements since we have already
42360  // added the previous one as the initial face element (any
42361  // previous face element had to be added on previous
42362  // iterations)
42363  for (unsigned iiface = iface; iiface < nnon_halo_doubled_face_ele;
42364  iiface += 2)
42365  {
42366  face_element_added = false;
42367  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42368 
42369  // Check that the face element with which we are working has
42370  // the same conditions as the root face element (both faces
42371  // are nonhalo or one face is halo and the other nonhalo)
42372 
42373  // Get the face element at the other side of the boundary
42374  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface + 1];
42375  bool both_face_elements_are_nonhalo = false;
42376 
42377 #ifdef OOMPH_HAS_MPI
42378  if (!repeated_ele_face_pt->is_halo())
42379  {
42380  both_face_elements_are_nonhalo = true;
42381  }
42382 #endif // #ifdef OOMPH_HAS_MPI
42383 
42384  if (!face_element_done[ele_face_pt] &&
42385  (both_face_elements_are_nonhalo ==
42386  both_root_face_elements_are_nonhalo))
42387  {
42388  // Get each individual node to check if they are contiguous
42389  const unsigned nlnode = ele_face_pt->nnode();
42390  Node* left_node_pt = ele_face_pt->node_pt(0);
42391  Node* right_node_pt = ele_face_pt->node_pt(nlnode - 1);
42392 
42393  if (left_node_pt == first_node_pt)
42394  {
42395  first_node_pt = right_node_pt;
42396  face_element_added = true;
42397  }
42398  else if (left_node_pt == last_node_pt)
42399  {
42400  last_node_pt = right_node_pt;
42401  face_element_added = true;
42402  }
42403  else if (right_node_pt == first_node_pt)
42404  {
42405  first_node_pt = left_node_pt;
42406  face_element_added = true;
42407  }
42408  else if (right_node_pt == last_node_pt)
42409  {
42410  last_node_pt = left_node_pt;
42411  face_element_added = true;
42412  }
42413 
42414  if (face_element_added)
42415  {
42416  // Add the left-hand node to the set:
42417  // Boundary coordinate
42418  left_node_pt->get_coordinates_on_boundary(bound, bound_left);
42419  vertex_coord[0] = bound_left[0];
42420 
42421  // Actual coordinates
42422  for (unsigned i = 0; i < 2; i++)
42423  {
42424  vertex_coord[i + 1] = left_node_pt->x(i);
42425  }
42426  local_vertex_nodes.insert(vertex_coord);
42427 
42428  // Add the right-hand nodes to the set:
42429  // Boundary coordinate
42430  right_node_pt->get_coordinates_on_boundary(bound, bound_right);
42431  vertex_coord[0] = bound_right[0];
42432 
42433  // Actual coordinates
42434  for (unsigned i = 0; i < 2; i++)
42435  {
42436  vertex_coord[i + 1] = right_node_pt->x(i);
42437  }
42438  local_vertex_nodes.insert(vertex_coord);
42439 
42440  // Mark as done only if one of its nodes has been
42441  // added to the list
42442  face_element_done[ele_face_pt] = true;
42443  // .. also mark as done the face element at the othe side of
42444  // the boundary
42445  repeated_ele_face_pt =
42446  non_halo_doubled_face_element_pt[iiface + 1];
42447  face_element_done[repeated_ele_face_pt] = true;
42448  // ... and increase the number of sorted face elements
42449  nsorted_face_elements += 2;
42450 
42451  break;
42452  }
42453 
42454  } // if (!face_element_done[[ele_face_pt])
42455  } // for (iiface<nnon_halo_doubled_face_ele)
42456  } while (face_element_added &&
42457  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42458 
42459  // -------------------------------------------------------------
42460  // At this point we already have a sorted set of nodes and can
42461  // be used to peform the unrefinement and refinement procedures
42462  // -------------------------------------------------------------
42463 
42464  // Get the number of nodes on the list
42465  const unsigned nlocal_nodes = local_vertex_nodes.size();
42466  // Change representation to vector for easy of handling ...
42467  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42468 
42469  // Copy the vertices of the nodes
42470  unsigned counter = 0;
42471  std::set<Vector<double>>::iterator it_vertex;
42472  for (it_vertex = local_vertex_nodes.begin();
42473  it_vertex != local_vertex_nodes.end();
42474  it_vertex++)
42475  {
42476  local_tmp_vector_vertex_node[counter].resize(3);
42477  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42478  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42479  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42480  counter++;
42481  }
42482 
42483  // The unrefinement and refinement process needs to be applied
42484  // from the bottom-left node since the internal open curve could
42485  // lie on the shared boundaries
42486  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] <
42487  local_tmp_vector_vertex_node[0][2])
42488  {
42489  std::reverse(local_tmp_vector_vertex_node.begin(),
42490  local_tmp_vector_vertex_node.end());
42491  }
42492  else if (local_tmp_vector_vertex_node[nlocal_nodes - 1][2] ==
42493  local_tmp_vector_vertex_node[0][2])
42494  {
42495  if (local_tmp_vector_vertex_node[nlocal_nodes - 1][1] <
42496  local_tmp_vector_vertex_node[0][1])
42497  {
42498  std::reverse(local_tmp_vector_vertex_node.begin(),
42499  local_tmp_vector_vertex_node.end());
42500  }
42501  }
42502 
42503  // ****************************************************************
42504  // 3) Create the vertices along the boundary using the target
42505  // area to define the distance among them
42506  // ****************************************************************
42507 
42508  // Clear the local containter to recover the nodes ordered using
42509  // the zeta value
42510  local_vertex_nodes.clear();
42511 
42512  // At the end of each unrefinement/refinement step store the new
42513  // nodes on the set that will give rise to the vertices of the
42514  // new polyline representation
42515  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42516  for (unsigned i = 0; i < nnew_nodes; i++)
42517  {
42518  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42519  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42520  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42521  vertex_nodes.insert(vertex_coord); // Global container
42522  local_vertex_nodes.insert(vertex_coord);
42523  }
42524 
42525 #ifdef OOMPH_HAS_MPI
42526  if (this->is_mesh_distributed())
42527  {
42528  // Add the set of vertices for the boundary, this will help to
42529  // detect if we need to deal with sub_boundaries and
42530  // sub_polylines representations
42531  sub_vertex_nodes.push_back(local_vertex_nodes);
42532  // Increase the counter for sub_boundaries
42533  nsub_boundaries++;
42534 
42535  // Mark if the polyline created by these vertices will be used
42536  // as a shared boundary or as an internal boundary
42537  if (both_root_face_elements_are_nonhalo)
42538  {
42539  internal_to_shared_boundary.push_back(false);
42540  }
42541  else
42542  {
42543  internal_to_shared_boundary.push_back(true);
42544  }
42545  }
42546 #endif
42547 
42548  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42549  // This while is in charge of sorting all the face elements to
42550  // create the new representation of the polyline (also deals
42551  // with the sub-boundary cases)
42552 
42553  // Now turn into vector for ease of handling...
42554  const unsigned npoly_vertex = vertex_nodes.size();
42555  tmp_vector_vertex_node.resize(npoly_vertex);
42556  unsigned count = 0;
42557  std::set<Vector<double>>::iterator it;
42558  for (it = vertex_nodes.begin(); it != vertex_nodes.end(); ++it)
42559  {
42560  tmp_vector_vertex_node[count].resize(3);
42561  tmp_vector_vertex_node[count][0] = (*it)[0];
42562  tmp_vector_vertex_node[count][1] = (*it)[1];
42563  tmp_vector_vertex_node[count][2] = (*it)[2];
42564  ++count;
42565  }
42566 
42567 #ifdef OOMPH_HAS_MPI
42568  // Check that the number of set of vertices marked to be shared or
42569  // internal boundaries be the same as the total number of
42570  // sub-boundaries
42571 #ifdef PARANOID
42572  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42573  const unsigned ninternal_to_shared_boundaries =
42574  internal_to_shared_boundary.size();
42575  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42576  {
42577  std::ostringstream error_message;
42578  error_message
42579  << "The number of found sub-boundaries and the number of marked "
42580  << "internal\nboundaries are different\n"
42581  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
42582  << "Number of marked internal boundaries: ("
42583  << ninternal_to_shared_boundaries << ")\n\n";
42584  throw OomphLibError(
42585  error_message.str(),
42586  "RefineableTriangleMesh::update_open_curve_after_restart()",
42587  OOMPH_EXCEPTION_LOCATION);
42588  }
42589 #endif
42590 
42591  // --------- Stuff for the sub_boundaries ----- Begin section -------
42592 #ifdef PARANOID
42593  if (nsub_boundaries_set != nsub_boundaries)
42594  {
42595  std::ostringstream error_message;
42596  error_message
42597  << "The number of found sub-boundaries and the number of counted\n"
42598  << "sub-boundaries are different:\n"
42599  << "Number of found sub-boundaries: (" << nsub_boundaries_set << ")\n"
42600  << "Number of counted sub-boundaries: (" << nsub_boundaries
42601  << ")\n\n";
42602  throw OomphLibError(
42603  error_message.str(),
42604  "RefineableTriangleMesh::update_open_curve_after_restart()",
42605  OOMPH_EXCEPTION_LOCATION);
42606  }
42607 #endif
42608 
42609  // Verify if need to deal with sub_boundaries
42610  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42611  {
42612  // Mark the boundary as been splitted in the partition process
42613  this->Boundary_was_splitted[bound] = true;
42614  // Resize the vector to store the info. of sub-boundaries
42615  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42616  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42617  {
42618  // Turn info. into vector for ease of handling...
42619  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42620  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42621  unsigned subcount = 0;
42622  std::set<Vector<double>>::iterator subit;
42623  for (subit = sub_vertex_nodes[isub].begin();
42624  subit != sub_vertex_nodes[isub].end();
42625  ++subit)
42626  {
42627  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42628  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42629  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42630  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42631  ++subcount;
42632  }
42633  }
42634  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42635  // --------- Stuff for the sub_boundaries ----- End section ----------
42636 #endif // OOMPH_HAS_MPI
42637 
42638  // For further processing the three-dimensional vector has to be
42639  // reduced to a two-dimensional vector
42640  unsigned n_vertex = tmp_vector_vertex_node.size();
42641 
42642  // Resize the vector for vectices
42643  vector_vertex_node.resize(n_vertex);
42644  for (unsigned i = 0; i < n_vertex; i++)
42645  {
42646  vector_vertex_node[i].resize(2);
42647  vector_vertex_node[i][0] = tmp_vector_vertex_node[i][1];
42648  vector_vertex_node[i][1] = tmp_vector_vertex_node[i][2];
42649  }
42650 
42651 #ifdef OOMPH_HAS_MPI
42652  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42653  // Verify if need to deal with sub_boundaries
42654  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42655  {
42656  // For further processing the three-dimensional vector
42657  // has to be reduced to a two-dimensional vector
42658  // Resize the vector to store the info. of sub-boundaries
42659  sub_vector_vertex_node.resize(nsub_boundaries);
42660  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42661  {
42662  const unsigned subn_vertex = sub_tmp_vector_vertex_node[isub].size();
42663  // Resize the vector for vectices
42664  sub_vector_vertex_node[isub].resize(subn_vertex);
42665  for (unsigned i = 0; i < subn_vertex; i++)
42666  {
42667  sub_vector_vertex_node[isub][i].resize(2);
42668  sub_vector_vertex_node[isub][i][0] =
42669  sub_tmp_vector_vertex_node[isub][i][1];
42670  sub_vector_vertex_node[isub][i][1] =
42671  sub_tmp_vector_vertex_node[isub][i][2];
42672  }
42673  }
42674  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42675 
42676  // We already have the info. for the sub-boundaries (if necessary) and
42677  // then we can create the sub-boundaries representations to ease the
42678  // generation of the mesh by Triangle
42679 
42680  // --------- Stuff for the sub_boundaries ----- End section ------------
42681 #endif // OOMPH_HAS_MPI
42682 
42683  // *********************************************************************
42684  // 4) Check for contiguousness
42685  // *********************************************************************
42686 #ifdef OOMPH_HAS_MPI
42687  // Only perform this checking if the mesh is not distributed
42688  // When the mesh is distributed the polylines continuity is
42689  // addressed with the sort_polylines_helper() method
42690  if (!this->is_mesh_distributed())
42691 #endif
42692  {
42693  if (cs > 0)
42694  {
42695  // Final end point of previous line
42696  Vector<double> final_vertex_of_previous_segment;
42697  unsigned n_prev_vertex =
42698  open_curve_pt->curve_section_pt(cs - 1)->nvertex();
42699  final_vertex_of_previous_segment =
42700  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(
42701  n_prev_vertex - 1);
42702 
42703  unsigned prev_seg_boundary_id =
42704  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
42705 
42706  // Find the error between the final vertex of the previous
42707  // line and the first vertex of the current line
42708  double error = 0.0;
42709  for (unsigned i = 0; i < 2; i++)
42710  {
42711  const double dist = final_vertex_of_previous_segment[i] -
42712  (*vector_vertex_node.begin())[i];
42713  error += dist * dist;
42714  }
42715  error = sqrt(error);
42716 
42717  // If the error is bigger than the tolerance then
42718  // we probably need to reverse, but better check
42719  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42720  {
42721  // Find the error between the final vertex of the previous
42722  // line and the last vertex of the current line
42723  double rev_error = 0.0;
42724  for (unsigned i = 0; i < 2; i++)
42725  {
42726  const double dist = final_vertex_of_previous_segment[i] -
42727  (*--vector_vertex_node.end())[i];
42728  rev_error += dist * dist;
42729  }
42730  rev_error = sqrt(rev_error);
42731 
42732  if (rev_error >
42733  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42734  {
42735  // It could be possible that the first segment be reversed and we
42736  // did not notice it because this check does not apply for the
42737  // first segment. We can verify if the first segment is reversed
42738  // by using the vertex number 1
42739  if (cs == 1)
42740  {
42741  // Initial end point of previous line
42742  Vector<double> initial_vertex_of_previous_segment;
42743 
42744  initial_vertex_of_previous_segment =
42745  open_curve_pt->polyline_pt(cs - 1)->vertex_coordinate(0);
42746 
42747  unsigned prev_seg_boundary_id =
42748  open_curve_pt->curve_section_pt(cs - 1)->boundary_id();
42749 
42750  // Find the error between the initial vertex of the previous
42751  // line and the first vertex of the current line
42752  double error = 0.0;
42753  for (unsigned i = 0; i < 2; i++)
42754  {
42755  const double dist = initial_vertex_of_previous_segment[i] -
42756  (*vector_vertex_node.begin())[i];
42757  error += dist * dist;
42758  }
42759  error = sqrt(error); // Reversed only the previous one
42760 
42761  // If the error is bigger than the tolerance then
42762  // we probably need to reverse, but better check
42763  if (error >
42764  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42765  {
42766  // Find the error between the final vertex of the previous
42767  // line and the last vertex of the current line
42768  double rev_error = 0.0;
42769  for (unsigned i = 0; i < 2; i++)
42770  {
42771  const double dist = initial_vertex_of_previous_segment[i] -
42772  (*--vector_vertex_node.end())[i];
42773  rev_error += dist * dist;
42774  }
42775  rev_error = sqrt(rev_error); // Reversed both the current
42776  // one and the previous one
42777 
42778  if (rev_error >
42779  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42780  {
42781  std::ostringstream error_stream;
42782  error_stream
42783  << "The distance between the first node of the current\n"
42784  << "line segment (boundary " << bound
42785  << ") and either end of "
42786  << "the previous line segment\n"
42787  << "(boundary " << prev_seg_boundary_id
42788  << ") is bigger than"
42789  << " the desired tolerance "
42790  << ToleranceForVertexMismatchInPolygons::Tolerable_error
42791  << ".\n"
42792  << "This suggests that the polylines defining the "
42793  "polygonal\n"
42794  << "representation are not properly ordered.\n"
42795  << "Fail on last vertex of polyline: ("
42796  << prev_seg_boundary_id
42797  << ") and\nfirst vertex of polyline (" << bound
42798  << ").\nThis should have failed when first trying to "
42799  << "construct the\npolygon.\n";
42800  throw OomphLibError(error_stream.str(),
42801  "RefineableTriangleMesh::update_open_"
42802  "curve_after_restart()",
42803  OOMPH_EXCEPTION_LOCATION);
42804  }
42805  else
42806  {
42807  // Reverse both
42808  // Reverse the current vector to line up with the previous
42809  // one
42810  std::reverse(vector_vertex_node.begin(),
42811  vector_vertex_node.end());
42812  open_curve_pt->polyline_pt(cs - 1)->reverse();
42813  }
42814  }
42815  else
42816  {
42817  // Reverse the previous one
42818  open_curve_pt->polyline_pt(cs - 1)->reverse();
42819  }
42820 
42821  } // if (cs == 1)
42822  else
42823  {
42824  std::ostringstream error_stream;
42825  error_stream
42826  << "The distance between the first node of the current\n"
42827  << "line segment (boundary " << bound
42828  << ") and either end of "
42829  << "the previous line segment\n"
42830  << "(boundary " << prev_seg_boundary_id
42831  << ") is bigger than the "
42832  << "desired tolerance "
42833  << ToleranceForVertexMismatchInPolygons::Tolerable_error
42834  << ".\n"
42835  << "This suggests that the polylines defining the polygonal\n"
42836  << "representation are not properly ordered.\n"
42837  << "Fail on last vertex of polyline: ("
42838  << prev_seg_boundary_id << ") and\nfirst vertex of polyline ("
42839  << bound << ").\n"
42840  << "This should have failed when first trying to construct "
42841  "the\n"
42842  << "polygon.\n";
42843  throw OomphLibError(
42844  error_stream.str(),
42845  "RefineableTriangleMesh::update_open_curve_after_restart()",
42846  OOMPH_EXCEPTION_LOCATION);
42847  }
42848  }
42849  else
42850  {
42851  // Reverse the current vector to line up with the previous one
42852  std::reverse(vector_vertex_node.begin(),
42853  vector_vertex_node.end());
42854  }
42855  } // error
42856  } // (cs > 0)
42857  } // is mesh not distributed
42858 
42859  // DEBP(applied_area_length_constraint);
42860  // DEBP(p);
42861  // getchar();
42862  // *********************************************************************
42863  // 5) Update the polylines representation
42864  // *********************************************************************
42865  // if (applied_area_length_constraint)
42866  // If only applied when there is a change then it keeps the
42867  // previous polyline representation, it means, it does not delete
42868  // the boundaries that are not part of the domain. We must update
42869  // the boundary representation
42870  {
42871  n_vertex = vector_vertex_node.size();
42872 
42873  // Now update the polyline according to the new vertices
42874  // The new one representation
42875  TriangleMeshPolyLine* tmp_polyline_pt =
42876  new TriangleMeshPolyLine(vector_vertex_node, bound);
42877 
42878  // Create a temporal "curve section" version of the recently created
42879  // polyline
42880  TriangleMeshCurveSection* tmp_curve_section_pt = tmp_polyline_pt;
42881 
42882  // Tolerance below which the middle point can be deleted
42883  // (ratio of deflection to element length)
42884  double unrefinement_tolerance =
42885  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42886 
42887  // Tolerance to add points
42888  double refinement_tolerance =
42889  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42890 
42891  // Establish refinement and unrefinement tolerance
42892  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42893  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42894 
42895  // Establish the maximum length constraint
42896  double maximum_length =
42897  open_curve_pt->polyline_pt(cs)->maximum_length();
42898  tmp_polyline_pt->set_maximum_length(maximum_length);
42899 
42900  if (n_vertex >= 2)
42901  {
42902  // Pass the connection information from the old polyline to the
42903  // new one
42904  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42905  tmp_curve_section_pt);
42906  }
42907 
42908  // Now update the polyline according to the new vertices but first
42909  // check if the object is allowed to delete the representation or
42910  // if it should be done by other object
42911  bool delete_it_on_destructor = false;
42912 
42913  std::set<TriangleMeshCurveSection*>::iterator it =
42914  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42915 
42916  if (it != this->Free_curve_section_pt.end())
42917  {
42918  this->Free_curve_section_pt.erase(it);
42919  delete open_curve_pt->curve_section_pt(cs);
42920  delete_it_on_destructor = true;
42921  }
42922 
42923  // *****************************************************************
42924  // Copying the new representation
42925  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42926 
42927  // Update the Boundary - Polyline map
42928  this->Boundary_curve_section_pt[bound] =
42929  open_curve_pt->curve_section_pt(cs);
42930 
42931  if (delete_it_on_destructor)
42932  {
42933  this->Free_curve_section_pt.insert(
42934  open_curve_pt->curve_section_pt(cs));
42935  }
42936 
42937 #ifdef OOMPH_HAS_MPI
42938 
42939  // If there are not sub-boundaries mark the boundary if need to be
42940  // trated as shared or as internal boundary
42941  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42942  {
42943  // Clear all previous stored data
42944  this->Boundary_marked_as_shared_boundary[bound].clear();
42945 
42946  // .. and store the flag for the boundary
42947  this->Boundary_marked_as_shared_boundary[bound].push_back(
42948  internal_to_shared_boundary[0]);
42949  }
42950  // --------- Stuff for the sub_boundaries ----- Begin section --------
42951  // Verify if need to deal with sub_boundaries
42952  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42953  {
42954  // Create temporary representations for the boundaries, only to
42955  // create the mesh when calling Triangle
42956  // Clear all previous stored data
42957  this->Boundary_subpolylines[bound].clear();
42958  // Now create storage for the sub-boundaries
42959  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42960 
42961  // Clear all previous stored data
42962  this->Boundary_marked_as_shared_boundary[bound].clear();
42963  // Create storage to mark the internal boundaries as shared
42964  // boundaries
42965  this->Boundary_marked_as_shared_boundary[bound].resize(
42966  nsub_boundaries);
42967  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42968  {
42969  // Now update the polyline according to the sub set of
42970  // vertices, set the chunk number of the polyline
42971  TriangleMeshPolyLine* sub_tmp_polyline_pt =
42972  new TriangleMeshPolyLine(
42973  sub_vector_vertex_node[isub], bound, isub);
42974 
42975  // Add the sub-polyline to the container to represent the
42976  // boundary in parts
42977  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42978 
42979  // Copy the flag that mark the boundary as internal or as
42980  // shared bound
42981  this->Boundary_marked_as_shared_boundary[bound][isub] =
42982  internal_to_shared_boundary[isub];
42983 
42984  // No need to send the unrefinement/refinement and maximum
42985  // length constraints since these are only temporary
42986  // representations
42987  }
42988 
42989  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42990  // --------- Stuff for the sub_boundaries ----- End section ---------
42991 #endif // OOMPH_HAS_MPI
42992 
42993  } // update polyline representation
42994 
42995  // Delete the allocated memory for the geometric object
42996  // that represents the curvilinear boundary
42997  delete mesh_geom_obj_pt;
42998 
42999  } // npolyline
43000 
43001  // Cleanup the face mesh
43002  for (unsigned p = 0; p < ncurve_section; p++)
43003  {
43004  face_mesh_pt[p]->flush_node_storage();
43005  delete face_mesh_pt[p];
43006  }
43007  }
43008 
43009 #ifdef OOMPH_HAS_MPI
43010  //======================================================================
43011  /// Updates the shared polylines representation after restart
43012  //======================================================================
43013  template<class ELEMENT>
43015  Vector<TriangleMeshPolyLine*>& vector_polyline_pt)
43016  {
43017  // Go through all the shared boundaries/polylines
43018  const unsigned npolylines = vector_polyline_pt.size();
43019  for (unsigned pp = 0; pp < npolylines; pp++)
43020  {
43021  // Get the boundary of the current polyline
43022  const unsigned b = vector_polyline_pt[pp]->boundary_id();
43023 
43024  // Get the edges of the shared boundary elements that create the
43025  // shared boundary and store the shared boundary elements from where
43026  // were created
43027  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
43028  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
43029 
43030  // Store the nodes that define the edges
43031  Vector<Node*> halo_edge_nodes_pt;
43032  Vector<Node*> nonhalo_edge_nodes_pt;
43033 
43034  // Go through the shared boundary elements and store their edges
43035  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
43036  for (unsigned e = 0; e < nshared_bound_ele; e++)
43037  {
43038  // Get the shared boundary element
43039  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
43040 
43041  // Get the corner nodes, the first three nodes
43042  Node* first_node_pt = current_ele_pt->node_pt(0);
43043  Node* second_node_pt = current_ele_pt->node_pt(1);
43044  Node* third_node_pt = current_ele_pt->node_pt(2);
43045 
43046  // Check if the elements is halo
43047  if (!current_ele_pt->is_halo())
43048  {
43049  // Store the edges
43050  nonhalo_edge_nodes_pt.push_back(first_node_pt);
43051  nonhalo_edge_nodes_pt.push_back(second_node_pt);
43052 
43053  nonhalo_edge_nodes_pt.push_back(second_node_pt);
43054  nonhalo_edge_nodes_pt.push_back(third_node_pt);
43055 
43056  nonhalo_edge_nodes_pt.push_back(third_node_pt);
43057  nonhalo_edge_nodes_pt.push_back(first_node_pt);
43058 
43059  // Store the info. of the element used to create these edges
43060  std::pair<Node*, Node*> edge1 =
43061  std::make_pair(first_node_pt, second_node_pt);
43062  nonhalo_edge_element_pt[edge1] = current_ele_pt;
43063 
43064  std::pair<Node*, Node*> edge2 =
43065  std::make_pair(second_node_pt, third_node_pt);
43066  nonhalo_edge_element_pt[edge2] = current_ele_pt;
43067 
43068  std::pair<Node*, Node*> edge3 =
43069  std::make_pair(third_node_pt, first_node_pt);
43070  nonhalo_edge_element_pt[edge3] = current_ele_pt;
43071  }
43072  else
43073  {
43074  // Store the edges
43075  halo_edge_nodes_pt.push_back(first_node_pt);
43076  halo_edge_nodes_pt.push_back(second_node_pt);
43077 
43078  halo_edge_nodes_pt.push_back(second_node_pt);
43079  halo_edge_nodes_pt.push_back(third_node_pt);
43080 
43081  halo_edge_nodes_pt.push_back(third_node_pt);
43082  halo_edge_nodes_pt.push_back(first_node_pt);
43083 
43084  // Store the info. of the element used to create these edges
43085  std::pair<Node*, Node*> edge1 =
43086  std::make_pair(first_node_pt, second_node_pt);
43087  halo_edge_element_pt[edge1] = current_ele_pt;
43088 
43089  std::pair<Node*, Node*> edge2 =
43090  std::make_pair(second_node_pt, third_node_pt);
43091  halo_edge_element_pt[edge2] = current_ele_pt;
43092 
43093  std::pair<Node*, Node*> edge3 =
43094  std::make_pair(third_node_pt, first_node_pt);
43095  halo_edge_element_pt[edge3] = current_ele_pt;
43096  }
43097 
43098  } // for (e < nshared_bound_ele)
43099 
43100  // Filter the edges that give rise to a shared boundary
43101 
43102  // Mark the done edges
43103  std::map<std::pair<Node*, Node*>, bool> edge_done;
43104 
43105  // Storage for the edges shared by the elements
43106  Vector<std::pair<Node*, Node*>> unsorted_edges;
43107 
43108  // Storage for the elements that created the unsorted edges (two
43109  // elements, one at each side of the shared boundary)
43110  Vector<Vector<FiniteElement*>> unsorted_edges_elements_pt;
43111 
43112  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
43113  for (unsigned i = 0; i < nnonhalo_edge_nodes; i += 2)
43114  {
43115  Vector<Node*> currenti_edge(2);
43116  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
43117  currenti_edge[1] = nonhalo_edge_nodes_pt[i + 1];
43118 
43119  // Create the edge (both nodes that make the edge)
43120  std::pair<Node*, Node*> new_edge =
43121  std::make_pair(currenti_edge[0], currenti_edge[1]);
43122 
43123  if (!edge_done[new_edge])
43124  {
43125  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
43126  for (unsigned j = 0; j < nhalo_edge_nodes; j += 2)
43127  {
43128  Vector<Node*> currentj_edge(2);
43129  currentj_edge[0] = halo_edge_nodes_pt[j];
43130  currentj_edge[1] = halo_edge_nodes_pt[j + 1];
43131 
43132  // Comparing pointer of nodes
43133  if (currenti_edge[0] == currentj_edge[0] &&
43134  currenti_edge[1] == currentj_edge[1])
43135  {
43136  // Store the edge in the proper container
43137  unsorted_edges.push_back(new_edge);
43138 
43139  // Get the elements associated with the edges
43140  Vector<FiniteElement*> tmp_edge_element_pt;
43141 
43142  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
43143  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
43144 
43145  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
43146  tmp_edge_element_pt.push_back(halo_ele_pt);
43147 
43148  // Store the elements associated with the edge
43149  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
43150 
43151  // Mark the edge as done
43152  edge_done[new_edge] = true;
43153 
43154  // Break the loop for (j < nedge_node)
43155  break;
43156 
43157  } // equal edge
43158 
43159  // Comparing pointer of nodes (reversed)
43160  else if (currenti_edge[0] == currentj_edge[1] &&
43161  currenti_edge[1] == currentj_edge[0])
43162  {
43163  // Create the edge (both nodes that make the edge)
43164  std::pair<Node*, Node*> new_edge =
43165  std::make_pair(currenti_edge[0], currenti_edge[1]);
43166 
43167  // Store the edge in the proper container
43168  unsorted_edges.push_back(new_edge);
43169 
43170  // Create the (reversed) edge (both nodes that make the edge)
43171  std::pair<Node*, Node*> rev_new_edge =
43172  std::make_pair(currentj_edge[0], currentj_edge[1]);
43173 
43174  // Get the elements associated with the edge
43175  Vector<FiniteElement*> tmp_edge_element_pt;
43176 
43177  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
43178  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
43179 
43180  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
43181  tmp_edge_element_pt.push_back(halo_ele_pt);
43182 
43183  // Store the elements associated with the edge
43184  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
43185 
43186  // Mark the edge as done
43187  edge_done[new_edge] = true;
43188 
43189  // Break the loop for (j < nedge_node)
43190  break;
43191 
43192  } // if (equal edge)
43193 
43194  } // for (j < nhalo_edge_nodes)
43195 
43196  } // if (!edge_done[new_edge])
43197 
43198  } // for (i < nnonhalo_edge_nodes)
43199 
43200  // We already have the edges that make the shared boundary (and the
43201  // elements)
43202  // Sort them to create a contiguous boundary
43203 
43204  // Mark the already sorted edges
43205  std::map<std::pair<Node*, Node*>, bool> edge_sorted;
43206 
43207  const unsigned nunsorted_edges = unsorted_edges.size();
43208 
43209 #ifdef PARANOID
43210  // The number of unsorted edges must be the same as the number of
43211  // shared_boundary element / 2
43212  if (nshared_bound_ele / 2 != nunsorted_edges)
43213  {
43214  std::ostringstream error_message;
43215  error_message
43216  << "The number of shared boundary elements (" << nshared_bound_ele
43217  << ") is not the double\nof the number of unsorted edges ("
43218  << nunsorted_edges << ") for the current boundary (" << b << ")\n\n";
43219  throw OomphLibError(
43220  error_message.str(),
43221  "RefineableTriangleMesh::update_shared_curve_after_restart()",
43222  OOMPH_EXCEPTION_LOCATION);
43223  }
43224 #endif
43225 
43226  unsigned nsorted_edges = 0;
43227 
43228  // Storing for the sorting nodes extracted from the edges, and
43229  // then used to update the polyline
43230  std::list<Node*> sorted_nodes;
43231 
43232  // Storing for the edges elements
43233  std::list<FiniteElement*> sorted_edges_elements_pt;
43234 
43235  // Get the root edge
43236  std::pair<Node*, Node*> edge = unsorted_edges[0];
43237  nsorted_edges++;
43238 
43239  // Mark edge as done
43240  edge_sorted[edge] = true;
43241 
43242  // The initial and final node on the list
43243  Node* first_node_pt = edge.first;
43244  Node* last_node_pt = edge.second;
43245 
43246  // Push back on the list the new edge (nodes)
43247  sorted_nodes.push_back(first_node_pt);
43248  sorted_nodes.push_back(last_node_pt);
43249 
43250  // Store the elements for the current edge
43251  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
43252  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
43253 
43254  // Iterate while the number of sorted edges be less than the number of
43255  // unsorted edges
43256  while (nsorted_edges < nunsorted_edges)
43257  {
43258  // Flag to indicate when a node was added
43259  bool node_added = false;
43260 
43261  // Start from the next edge since we have already added the
43262  // previous one as the initial edge
43263  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
43264  {
43265  edge = unsorted_edges[iedge];
43266 
43267  // If edge not done
43268  if (!edge_sorted[edge])
43269  {
43270  // Get each individual node
43271  Node* left_node_pt = edge.first;
43272  Node* right_node_pt = edge.second;
43273 
43274  if (left_node_pt == first_node_pt)
43275  {
43276  // Push front the new node
43277  sorted_nodes.push_front(right_node_pt);
43278  first_node_pt = right_node_pt;
43279  node_added = true;
43280 
43281  // Store the elements for the current edge
43282  sorted_edges_elements_pt.push_front(
43283  unsorted_edges_elements_pt[iedge][1]);
43284  sorted_edges_elements_pt.push_front(
43285  unsorted_edges_elements_pt[iedge][0]);
43286  }
43287  else if (left_node_pt == last_node_pt)
43288  {
43289  // Push back the new node
43290  sorted_nodes.push_back(right_node_pt);
43291  last_node_pt = right_node_pt;
43292  node_added = true;
43293 
43294  // Store the elements for the current edge
43295  sorted_edges_elements_pt.push_back(
43296  unsorted_edges_elements_pt[iedge][0]);
43297  sorted_edges_elements_pt.push_back(
43298  unsorted_edges_elements_pt[iedge][1]);
43299  }
43300  else if (right_node_pt == first_node_pt)
43301  {
43302  // Push front the new node
43303  sorted_nodes.push_front(left_node_pt);
43304  first_node_pt = left_node_pt;
43305  node_added = true;
43306 
43307  // Store the elements for the current edge
43308  sorted_edges_elements_pt.push_front(
43309  unsorted_edges_elements_pt[iedge][1]);
43310  sorted_edges_elements_pt.push_front(
43311  unsorted_edges_elements_pt[iedge][0]);
43312  }
43313  else if (right_node_pt == last_node_pt)
43314  {
43315  // Push back the new node
43316  sorted_nodes.push_back(left_node_pt);
43317  last_node_pt = left_node_pt;
43318  node_added = true;
43319 
43320  // Store the elements for the current edge
43321  sorted_edges_elements_pt.push_back(
43322  unsorted_edges_elements_pt[iedge][0]);
43323  sorted_edges_elements_pt.push_back(
43324  unsorted_edges_elements_pt[iedge][1]);
43325  }
43326 
43327  if (node_added)
43328  {
43329  // Mark as done only if one of its nodes has been
43330  // added to the list
43331  edge_sorted[edge] = true;
43332  nsorted_edges++;
43333 
43334  // Break the for
43335  break;
43336  }
43337 
43338  } // if (!edge_done[edge])
43339  } // for (iedge < nunsorted_edges)
43340  } // while (nsorted_edges < nunsorted_edges)
43341 
43342  // At this point we already have a sorted list of nodes, get the
43343  // vertices from them and store them in a vector container
43344 
43345  // Get the number of nodes on the list
43346  unsigned nvertex = sorted_nodes.size();
43347  // The vector to store the vertices (assign space)
43348  Vector<Vector<double>> polyline_vertices(nvertex);
43349 
43350  // Copy the vertices of the nodes
43351  unsigned counter = 0;
43352  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43353  it_nodes != sorted_nodes.end();
43354  it_nodes++)
43355  {
43356  polyline_vertices[counter].resize(2);
43357  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43358  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43359  counter++;
43360  }
43361 
43362  // Before going to the unrefinement or refinement process check that
43363  // all processors start from the same vertex. Start from the bottom
43364  // left vertex
43365  if (polyline_vertices[nvertex - 1][1] < polyline_vertices[0][1])
43366  {
43367  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43368  }
43369  else if (polyline_vertices[nvertex - 1][1] == polyline_vertices[0][1])
43370  {
43371  if (polyline_vertices[nvertex - 1][0] < polyline_vertices[0][0])
43372  {
43373  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43374  }
43375  }
43376 
43377  // Create the polyline associated with this edge
43378  TriangleMeshPolyLine* new_polyline_pt =
43379  new TriangleMeshPolyLine(polyline_vertices, b);
43380 
43381  // Get the curve section representation
43382  TriangleMeshCurveSection* curve_section_pt = vector_polyline_pt[pp];
43383 
43384  // Copy the connection information from the old shared polyline
43385  // to the new one
43386  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43387 
43388  // Now update the polyline according to the new vertices but first
43389  // check if the object is allowed to delete the representation
43390  // or if it should be done by other object
43391  bool delete_it_on_destructor = false;
43392 
43393  // Establish the element as being deleted by the destructor of
43394  // the class
43395  std::set<TriangleMeshCurveSection*>::iterator it =
43396  this->Free_curve_section_pt.find(curve_section_pt);
43397 
43398  if (it != this->Free_curve_section_pt.end())
43399  {
43400  this->Free_curve_section_pt.erase(it);
43401  delete curve_section_pt;
43402  delete_it_on_destructor = true;
43403  }
43404 
43405  // Copy the new representation
43406  vector_polyline_pt[pp] = new_polyline_pt;
43407 
43408  // Get the new curve section representation
43409  TriangleMeshCurveSection* new_curve_section_pt = vector_polyline_pt[pp];
43410 
43411  // Update the Boundary - Polyline map
43412  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43413 
43414  if (delete_it_on_destructor)
43415  {
43416  this->Free_curve_section_pt.insert(new_curve_section_pt);
43417  }
43418 
43419  } // for (pp < npoly)
43420  }
43421 
43422  //===================================================================
43423  // Fill the boundary elements structures when dealing with
43424  // shared boundaries that overlap internal boundaries. Document the
43425  // number of elements on the shared boundaries that go to internal
43426  // boundaries
43427  //===================================================================
43428  template<class ELEMENT>
43430  ELEMENT>::fill_boundary_elements_and_nodes_for_internal_boundaries()
43431  {
43432  // Dummy file
43433  std::ofstream some_file;
43434  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43435  }
43436 
43437  //===================================================================
43438  // Fill the boundary elements structures when dealing with
43439  // shared boundaries that overlap internal boundaries
43440  //===================================================================
43441  template<class ELEMENT>
43444  std::ofstream& outfile)
43445  {
43446  // Get the number of processors
43447  const unsigned nproc = this->communicator_pt()->nproc();
43448  // Get the rank of the current processor
43449  unsigned my_rank = this->communicator_pt()->my_rank();
43450 
43451  // Temporal name for the shared boundary overlaps structure
43452  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43453  this->Shared_boundary_overlaps_internal_boundary;
43454 
43455  // Register the internal boundary elements that where found to be
43456  // overlapped by shared boundaries
43457  std::set<unsigned> internal_boundary_overlaped;
43458 
43459  // Document the number of elements and nodes associated to the
43460  // boundaries before filling elements and nodes
43461  if (outfile.is_open())
43462  {
43463  const unsigned nbound = this->nboundary();
43464  outfile << "Number of boundaries: " << nbound << "\n\n";
43465  outfile << "Number of elements and nodes associated to each "
43466  << "boundary before\nfilling elements and nodes\n\n";
43467  for (unsigned i = 0; i < nbound; i++)
43468  {
43469  outfile << "Boundary (" << i << ") Elements ("
43470  << this->nboundary_element(i) << ") "
43471  << "Nodes (" << this->nboundary_node(i) << ")\n";
43472  }
43473  }
43474 
43475  // Storage for the shared boundaries in this processor
43476  std::set<unsigned> shared_boundaries_in_this_processor;
43477 
43478  // Get the shared boundaries that this processor has with other
43479  // processors
43480  for (unsigned iproc = 0; iproc < nproc; iproc++)
43481  {
43482  // Work with other processors only
43483  if (iproc != my_rank)
43484  {
43485  // Get the number of boundaries shared with the "iproc"-th processor
43486  unsigned nshared_boundaries_with_iproc =
43487  this->nshared_boundaries(my_rank, iproc);
43488 
43489  if (nshared_boundaries_with_iproc > 0)
43490  {
43491  // Get the boundaries ids shared with "iproc"-th processor
43492  Vector<unsigned> bound_shared_with_iproc;
43493  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
43494 
43495  // Loop over shared boundaries with "iproc"-th processor
43496  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43497  {
43498  unsigned bnd_id = bound_shared_with_iproc[bs];
43499  shared_boundaries_in_this_processor.insert(bnd_id);
43500  }
43501  }
43502  }
43503  }
43504 
43505  // ------------------------------------------------------------------
43506  // Copy the boundary elements and nodes from the shared boundary to
43507  // the internal boundary it overlaps
43508  // ------------------------------------------------------------------
43509  // Go through the shared boundaries that overlap internal boundaries
43510  for (std::map<unsigned, unsigned>::iterator it =
43511  shd_bnd_over_int_bnd.begin();
43512  it != shd_bnd_over_int_bnd.end();
43513  it++)
43514  {
43515  // The shared boundary id that overlaps with an internal boundary
43516  const unsigned shd_bnd_id = (*it).first;
43517  // The internal boundary overlapped by the shared boundary
43518  const unsigned int_bnd_id = (*it).second;
43519 
43520  // Check if the shared boundary exist in this processor
43521  std::set<unsigned>::iterator it_set =
43522  shared_boundaries_in_this_processor.find(shd_bnd_id);
43523  if (it_set != shared_boundaries_in_this_processor.end())
43524  {
43525  internal_boundary_overlaped.insert(int_bnd_id);
43526 
43527  // -----------------------------------------------------------------
43528  // First work the nodes of the shared boundaries that should be
43529  // added to the internal boundaries
43530  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43531 
43532  // Document the number of nodes that will be passed to the internal
43533  // boundary from the current shared boundary
43534  if (outfile.is_open())
43535  {
43536  outfile << "\nPass info. from shared (" << shd_bnd_id
43537  << ") to internal (" << int_bnd_id << ")\n";
43538  outfile << "Number of shared boundary nodes: " << nbnd_node_shd_bnd
43539  << "\n";
43540  }
43541 
43542  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43543  {
43544  // Get the boundary node
43545  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43546  // Add the node to the internal boundary
43547  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43548  }
43549 
43550  // -----------------------------------------------------------------
43551  // Second work the boundary elements
43552  // Get the number of boundary elements that should be copied to the
43553  // internal boundary
43554  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43555 
43556  // Document the number of elements that will be passed to the
43557  // internal boundary from the current shared boundary
43558  if (outfile.is_open())
43559  {
43560  outfile << "Number of shared boundary elements: " << nbnd_ele_shd_bnd
43561  << "\n\n";
43562  }
43563 
43564  // Go through the boundary elements in the shrared boundary and add
43565  // them to the boundary elements of the internal boundary
43566  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43567  {
43568  // Get the boundary element
43569  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43570  // Add the element to the boundary elements storage of the
43571  // internal boundary
43572  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43573  // Get the face index of the boundary
43574  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43575  // Add the face index to the storage of the boundary
43576  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43577 
43578  } // for (ie < nbnd_ele_shd_bnd)
43579 
43580  // If there are regions we need to fill the storage for regions too
43581  const unsigned nregions = this->nregion();
43582  if (nregions > 1)
43583  {
43584  for (unsigned ir = 0; ir < nregions; ir++)
43585  {
43586  // Get the region attribute
43587  const unsigned region_id =
43588  static_cast<unsigned>(this->Region_attribute[ir]);
43589 
43590  // Loop over all elements on boundaries in region ir
43591  const unsigned nele_ir =
43592  this->nboundary_element_in_region(shd_bnd_id, region_id);
43593  for (unsigned ier = 0; ier < nele_ir; ier++)
43594  {
43595  // Get the boundary element in current region
43596  FiniteElement* bnd_ele_pt =
43597  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43598  // Add the boundary element to the internal boundary in the
43599  // region
43600  this->Boundary_region_element_pt[int_bnd_id][region_id].push_back(
43601  bnd_ele_pt);
43602 
43603  // Get the face index of the boundary
43604  int face_index = this->face_index_at_boundary_in_region(
43605  shd_bnd_id, region_id, ier);
43606  // Add the face index to the storage of the boundary region
43607  this->Face_index_region_at_boundary[int_bnd_id][region_id]
43608  .push_back(face_index);
43609 
43610  } // for (ier < nele_ir)
43611 
43612  } // for (ir < nregions)
43613 
43614  } // if (nregions > 1)
43615 
43616  } // if (the shared boundary appears in the current processor)
43617 
43618  } // for (loop over the shared bound that overlap an internal bound)
43619 
43620  // Document the number of elements and nodes associated to the
43621  // boundaries after filling elements and nodes
43622  if (outfile.is_open())
43623  {
43624  const unsigned nbound = this->nboundary();
43625  outfile << "Number of boundaries: " << nbound << "\n\n";
43626  outfile << "Number of elements and nodes associated to each "
43627  << "boundary after\nfilling elements and nodes\n\n";
43628  for (unsigned i = 0; i < nbound; i++)
43629  {
43630  outfile << "Boundary (" << i << ") Elements ("
43631  << this->nboundary_element(i) << ")"
43632  << " Nodes (" << this->nboundary_node(i) << ")\n";
43633  }
43634  }
43635 
43636  // ------------------------------------------------------------------
43637  // Finally, re-setup the boundary coordinates for the new nodes on
43638  // the overlaped internal boundaries
43639  // ------------------------------------------------------------------
43640  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43641  it != internal_boundary_overlaped.end();
43642  it++)
43643  {
43644  const unsigned overlaped_internal_bnd_id = (*it);
43645 
43646  // Re-setup boundary coordinates
43647  this->template setup_boundary_coordinates<ELEMENT>(
43648  overlaped_internal_bnd_id);
43649  }
43650  }
43651 
43652 #endif // #ifdef OOMPH_HAS_MPI
43653 
43654  //======================================================================
43655  /// Move the boundary nodes onto the boundary defined by the old mesh
43656  //======================================================================
43657  template<class ELEMENT>
43659  RefineableTriangleMesh<ELEMENT>*& new_mesh_pt, const unsigned& b)
43660  {
43661  // Quick return
43662  if (!Boundary_coordinate_exists[b])
43663  {
43664  return;
43665  }
43666 
43667  // Firstly we set the boundary coordinates of the new nodes
43668  // In case the mapping between the geometric object's intrinsic coordinate
43669  // and the arc-length coordinate is nonlinear. This is only an
43670  // approximation, but it will ensure that the nodes that were input to
43671  // triangle will retain exactly the same boundary coordinates and then
43672  // linear interpolation is used between those values for any newly created
43673  // nodes.
43674 
43675  // We need to get the boundary nodes from the boundary face
43676  // elements since the "multi_domain" methods add nodes to the
43677  // "Boundary_node_pt" structure which have no boundary coordinates
43678  // assigned
43679  std::set<Node*> tmp_boundary_node_pt;
43680  const unsigned nboundary_ele = this->nboundary_element(b);
43681  for (unsigned e = 0; e < nboundary_ele; e++)
43682  {
43683  // Get the boundary bulk element
43684  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43685 #ifdef OOMPH_HAS_MPI
43686  // Only work with nonhalo elements if the mesh is distributed
43687  if (!bulk_ele_pt->is_halo())
43688  {
43689 #endif
43690  // Get the face index
43691  int face_index = this->face_index_at_boundary(b, e);
43692  // Create the face element
43693  FiniteElement* face_ele_pt =
43694  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
43695 
43696  // Get the number of nodes on the face element
43697  const unsigned nnodes = face_ele_pt->nnode();
43698  for (unsigned i = 0; i < nnodes; i++)
43699  {
43700  // Get the nodes in the face elements
43701  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43702  // Add the nodes to the set of boundary nodes
43703  tmp_boundary_node_pt.insert(tmp_node_pt);
43704  } // for (i < nnodes)
43705 
43706  // Free the memory allocated for the face element
43707  delete face_ele_pt;
43708  face_ele_pt = 0;
43709 #ifdef OOMPH_HAS_MPI
43710  } // if (!bulk_ele_pt->is_halo())
43711 #endif
43712 
43713  } // for (e < nboundary_ele)
43714 
43715  // Get the number of boundary nodes
43716  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43717 
43718  // Quick return if there are no nodes
43719  if (n_boundary_node == 0)
43720  {
43721 #ifdef OOMPH_HAS_MPI
43722  // Check if we are working with a distributed mesh
43723  if (!this->is_mesh_distributed())
43724  {
43725 #endif
43726  return;
43727 #ifdef OOMPH_HAS_MPI
43728  }
43729  else // The mesh is distributed !!!
43730  {
43731  // Do not forget to participate in the communication
43732  Mesh* face_mesh_pt = new Mesh();
43733  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43734  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43735 
43736  // Delete the allocated memory for the geometric object and face mesh
43737  delete mesh_geom_obj_pt;
43738 
43739  // Flush the nodes from the face mesh to make sure we
43740  // don't delete them (the bulk mesh still needs them!)
43741  face_mesh_pt->flush_node_storage();
43742  delete face_mesh_pt;
43743  return;
43744  }
43745 #endif
43746  } // if (n_boundary_node==0)
43747 
43748  // Create a vector of existing boundary nodes with their boundary
43749  // coordinate as the first entry so that we can use standard sort algorithms
43750  Vector<double> node_coord(3);
43751  Vector<double> b_coord(1);
43752 
43753  Vector<Vector<double>> old_boundary_node(n_boundary_node);
43754  unsigned tmp_counter = 0;
43755  for (std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43756  it_node != tmp_boundary_node_pt.end();
43757  it_node++, tmp_counter++)
43758  {
43759  Node* nod_pt = (*it_node);
43760  nod_pt->get_coordinates_on_boundary(b, b_coord);
43761  node_coord[0] = b_coord[0];
43762  node_coord[1] = nod_pt->x(0);
43763  node_coord[2] = nod_pt->x(1);
43764  old_boundary_node[tmp_counter] = node_coord;
43765  } // for (it_node != tmp_boundary_node_pt.end())
43766 
43767  // Sort the vector
43768  std::sort(old_boundary_node.begin(), old_boundary_node.end());
43769 
43770  // Set up an equivalent ordered vector for the new nodes, based on the
43771  // current coordinate which is the scaled arc-length.
43772  // Also provide storage for the original node index,
43773  // the mapped coordinate and a flag to indicate whether the mapped
43774  // coordinate has been assigned.
43775  // Get the nodes on the boundary but consider to which segment (which
43776  // may appear in a distributed mesh) they belong
43777  Vector<Vector<Node*>> segment_nodes_pt;
43778 
43779 #ifdef OOMPH_HAS_MPI
43780  // Get the number of segments
43781  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43782 #else
43783  // The number of segments is one since the boundary is not split
43784  // over multiple processors
43785  const unsigned nsegments = 1;
43786 #endif // #ifdef OOMPH_HAS_MPI
43787 
43788 #ifdef OOMPH_HAS_MPI
43789  // Get the total number of nodes on the boundary
43790  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43791 
43792  // Check if we are working with a distributed mesh
43793  if (this->is_mesh_distributed())
43794  {
43795  // If that is the case we need to ensure that the new mesh has
43796  // nodes too, if that is not the case then return
43797  // Quick return if there are no nodes
43798  if (n_new_boundary_node == 0)
43799  {
43800  // Do not forget to participate in the communication
43801  Mesh* face_mesh_pt = new Mesh();
43802  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43803  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43804 
43805  // Delete the allocated memory for the geometric object and face mesh
43806  delete mesh_geom_obj_pt;
43807  // Flush the nodes from the face mesh to make sure we
43808  // don't delete them (the bulk mesh still needs them!)
43809  face_mesh_pt->flush_node_storage();
43810  delete face_mesh_pt;
43811  return;
43812  }
43813  }
43814 #endif // #ifdef OOMPH_HAS_MPI
43815 
43816  // Create a vector of boundary nodes that must be moved
43817  Vector<Vector<unsigned>> nodes_to_be_snapped(nsegments);
43818 
43819  // Go through all the segments to assign the snapped zeta coordinates
43820  // for the new nodes
43821  for (unsigned is = 0; is < nsegments; is++)
43822  {
43823 #ifdef OOMPH_HAS_MPI
43824  const unsigned n_new_boundary_segment_node =
43825  new_mesh_pt->nboundary_segment_node(b, is);
43826 #else
43827  const unsigned n_new_boundary_segment_node =
43828  new_mesh_pt->nboundary_node(b);
43829 #endif // #ifdef OOMPH_HAS_MPI
43830 
43831  Vector<Vector<double>> new_boundary_node(n_new_boundary_segment_node);
43832  // There will be six data associated with each node
43833  node_coord.resize(6, 0.0);
43834  for (unsigned n = 0; n < n_new_boundary_segment_node; n++)
43835  {
43836 #ifdef OOMPH_HAS_MPI
43837  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b, is, n);
43838 #else
43839  Node* nod_pt = new_mesh_pt->boundary_node_pt(b, n);
43840 #endif // #ifdef OOMPH_HAS_MPI
43841  nod_pt->get_coordinates_on_boundary(b, b_coord);
43842  node_coord[0] = b_coord[0];
43843  node_coord[1] = nod_pt->x(0);
43844  node_coord[2] = nod_pt->x(1);
43845  node_coord[3] = n;
43846  new_boundary_node[n] = node_coord;
43847  } // for (n < n_new_boundary_segment_node)
43848 
43849  // Sort the new boundary nodes based on their arc-length coordinate
43850  std::sort(new_boundary_node.begin(), new_boundary_node.end());
43851 
43852  // We now have two sets of nodes ordered by a coordinate that acts in the
43853  // same direction and has the same limits.
43854 
43855  // Loop over the vector of new nodes and allocate exactly the same
43856  // coordinate as the old nodes at points of coincidence
43857  unsigned old_index = 0;
43858  for (unsigned n = 0; n < n_new_boundary_segment_node; ++n)
43859  {
43860  // Loop over the set of old nodes and if the x and y coordinates
43861  // coincide with the new node copy accross the new boundary coordinate
43862  for (unsigned m = old_index; m < n_boundary_node; ++m)
43863  {
43864  if ((std::fabs(old_boundary_node[m][1] - new_boundary_node[n][1]) <
43865  1.0e-14) &&
43866  (std::fabs(old_boundary_node[m][2] - new_boundary_node[n][2]) <
43867  1.0e-14))
43868  {
43869  // Store the boundary coordinate from the old mesh
43870  new_boundary_node[n][4] = old_boundary_node[m][0];
43871  // Say that it has been stored
43872  new_boundary_node[n][5] = 1.0;
43873  // For efficiency, we can start the iteration from here next
43874  // time round because both vectors are ordered
43875  old_index = m;
43876  break;
43877  }
43878  }
43879  }
43880 
43881  // Check that the end-points have new boundary coordinates allocated
43882 #ifdef PARANOID
43883  if ((new_boundary_node[0][5] == 0.0) ||
43884  (new_boundary_node[n_new_boundary_segment_node - 1][5] == 0.0))
43885  {
43886  std::ostringstream error_stream;
43887  error_stream
43888  << "New boundary coordinates not found for the first and/or last "
43889  << "nodes\n"
43890  << "on the boundary " << b << ". This should not happen because "
43891  << "these\nlimits should have been setup in the constructor\n";
43892  error_stream
43893  << "The distance between the new and old nodes is probably outside\n"
43894  << "our tolerance.\n";
43895  error_stream.precision(20);
43896  error_stream << "Old boundaries: \n";
43897  error_stream << old_boundary_node[0][1] << " "
43898  << old_boundary_node[0][2] << " : "
43899  << old_boundary_node[n_boundary_node - 1][1] << " "
43900  << old_boundary_node[n_boundary_node - 1][2] << "\n";
43901  error_stream << "New boundaries: \n"
43902  << new_boundary_node[0][1] << " "
43903  << new_boundary_node[0][2] << " : "
43904  << new_boundary_node[n_new_boundary_segment_node - 1][1]
43905  << " "
43906  << new_boundary_node[n_new_boundary_segment_node - 1][2]
43907  << "\n";
43908  OomphLibWarning(error_stream.str(),
43909  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43910  OOMPH_EXCEPTION_LOCATION);
43911  }
43912 #endif
43913 
43914  // This is only true if the boundary is not splitted among the
43915  // processors
43916  if (!this->is_mesh_distributed())
43917  {
43918  // The end points should always be present, so we
43919  // can (and must) always add them in exactly
43920  new_boundary_node[0][4] = new_boundary_node[0][0];
43921 
43922  /// Correct!? Because assigned again below
43923  new_boundary_node[n_new_boundary_segment_node - 1][4] =
43924  new_boundary_node[0][5] = 1.0;
43925 
43926  new_boundary_node[n_new_boundary_segment_node - 1][4] =
43927  new_boundary_node[n_new_boundary_segment_node - 1][0];
43928  new_boundary_node[n_new_boundary_segment_node - 1][5] = 1.0;
43929  }
43930 
43931  // Now loop over the interior nodes again and
43932  // use linear interpolation to fill in any unassigned coordiantes
43933  for (unsigned n = 1; n < n_new_boundary_segment_node - 1; ++n)
43934  {
43935  // If the new boundary coordinate has NOT been allocated
43936  if (new_boundary_node[n][5] == 0.0)
43937  {
43938  // Add its (unsorted) node number to the list
43939  nodes_to_be_snapped[is].push_back(
43940  static_cast<unsigned>(new_boundary_node[n][3]));
43941 
43942  // We assume that the previous nodal value has been assigned
43943  // and read out the old and new boundary coordinates
43944  double zeta_old_low = new_boundary_node[n - 1][0];
43945  double zeta_new_low = new_boundary_node[n - 1][4];
43946 
43947  // Loop over the nodes above the current node until
43948  // we find the next one that has been allocated
43949  for (unsigned m = n + 1; m < n_new_boundary_segment_node; ++m)
43950  {
43951  if (new_boundary_node[m][5] == 1.0)
43952  {
43953  // Read out the old boundary coordinate
43954  double zeta_old_high = new_boundary_node[m][0];
43955  double zeta_new_high = new_boundary_node[m][4];
43956  // Use linear interpolation to assign the new boundary coordinate
43957  double frac = (new_boundary_node[n][0] - zeta_old_low) /
43958  (zeta_old_high - zeta_old_low);
43959  new_boundary_node[n][4] =
43960  zeta_new_low + frac * (zeta_new_high - zeta_new_low);
43961  new_boundary_node[n][5] = 1.0;
43962  break;
43963  }
43964  }
43965  }
43966  }
43967 
43968  // Loop over all the nodes and set the new boundary coordinate
43969  for (unsigned n = 0; n < n_new_boundary_segment_node; ++n)
43970  {
43971  if (new_boundary_node[n][5] == 0)
43972  {
43973  throw OomphLibError(
43974  "New boundary coordinate not assigned\n",
43975  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43976  OOMPH_EXCEPTION_LOCATION);
43977  }
43978 
43979 #ifdef OOMPH_HAS_MPI
43980  // get the old coordinate
43981  new_mesh_pt
43983  b, is, static_cast<unsigned>(new_boundary_node[n][3]))
43984  ->get_coordinates_on_boundary(b, b_coord);
43985  // Set the new coordinate
43986  b_coord[0] = new_boundary_node[n][4];
43987  new_mesh_pt
43989  b, is, static_cast<unsigned>(new_boundary_node[n][3]))
43990  ->set_coordinates_on_boundary(b, b_coord);
43991 #else
43992  // get the old coordinate
43993  new_mesh_pt
43994  ->boundary_node_pt(b, static_cast<unsigned>(new_boundary_node[n][3]))
43995  ->get_coordinates_on_boundary(b, b_coord);
43996  // Set the new coordinate
43997  b_coord[0] = new_boundary_node[n][4];
43998  new_mesh_pt
43999  ->boundary_node_pt(b, static_cast<unsigned>(new_boundary_node[n][3]))
44000  ->set_coordinates_on_boundary(b, b_coord);
44001 #endif // #ifdef OOMPH_HAS_MPI
44002  }
44003 
44004  } // for (is < nsegments)
44005 
44006  Mesh* face_mesh_pt = new Mesh();
44007  create_unsorted_face_mesh_representation(b, face_mesh_pt);
44008 
44009  // Now that the coordinates have been set up we can do the snapping
44010  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
44011 
44012  // Now assign the new nodes positions based on the old meshes
44013  // potentially curvilinear boundary (its geom object incarnation)
44014  Vector<double> new_x(2);
44015 
44016  // Loop over the nodes that need to be snapped
44017  for (unsigned is = 0; is < nsegments; is++)
44018  {
44019  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
44020 
44021  for (unsigned in = 0; in < nnodes_to_snap; in++)
44022  {
44023  // Read out the boundary node number
44024  unsigned n = nodes_to_be_snapped[is][in];
44025 #ifdef OOMPH_HAS_MPI
44026  // Get the boundary coordinate of all new nodes
44027  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b, is, n);
44028 #else
44029  // Get the boundary coordinate of all new nodes
44030  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b, n);
44031 #endif // #ifdef OOMPH_HAS_MPI
44032 
44033  nod_pt->get_coordinates_on_boundary(b, b_coord);
44034  // Let's find boundary coordinates of the new node
44035  mesh_geom_obj_pt->position(b_coord, new_x);
44036 
44037  // Now snap to the boundary
44038  for (unsigned i = 0; i < 2; i++)
44039  {
44040  nod_pt->x(i) = new_x[i];
44041  }
44042  }
44043  }
44044 
44045  // Delete the allocated memory for the geometric object and face mesh
44046  delete mesh_geom_obj_pt;
44047  // Flush the nodes from the face mesh to make sure we
44048  // don't delete them (the bulk mesh still needs them!)
44049  face_mesh_pt->flush_node_storage();
44050  delete face_mesh_pt;
44051 
44052  // Fix up the elements adjacent to the boundary
44053 
44054  // Dummy six node element for sorting out bubble node for
44055  // seven node enriched quadratic triangles
44056  TElement<2, 3> dummy_six_node_element;
44057  for (unsigned j = 0; j < 6; j++)
44058  {
44059  dummy_six_node_element.construct_node(j);
44060  }
44061 
44062  // This should definitely become a triangular element member function
44063  // Loop over elements
44064  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
44065  for (unsigned e = 0; e < n_bound_el; e++)
44066  {
44067  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b, e);
44068 
44069  // Deal with different numbers of nodes separately
44070  unsigned nnod = el_pt->nnode();
44071 
44072  // #ifdef PARANOID
44073  // // Flag to indicate if we successully classified/dealt with the
44074  // element bool success=false;
44075  // #endif
44076 
44077  // Simplex element: Nothing to be done other than error checking
44078  if (nnod == 3)
44079  {
44080 #ifdef PARANOID
44081  // Try to cast to a simplex element
44082  TElement<2, 2>* t_el_pt = dynamic_cast<TElement<2, 2>*>(el_pt);
44083  if (t_el_pt == 0)
44084  {
44085  throw OomphLibError(
44086  "Have a three-noded element that's not a TElement<2,2>",
44087  OOMPH_CURRENT_FUNCTION,
44088  OOMPH_EXCEPTION_LOCATION);
44089  }
44090  // If I get there I must not have thrown :)
44091  // success=true;
44092 #endif
44093  }
44094  // Quadratic element (or enriched quadratic)
44095 
44096  else if ((nnod == 6) || (nnod == 7))
44097  {
44098 #ifdef PARANOID
44099  // Try to cast to a quadratic element
44100  TElement<2, 3>* t_el_pt = dynamic_cast<TElement<2, 3>*>(el_pt);
44101  if (t_el_pt == 0)
44102  {
44103  if (nnod == 6)
44104  {
44105  throw OomphLibError(
44106  "Have a six-noded element that's not a TElement<2,3>",
44107  OOMPH_CURRENT_FUNCTION,
44108  OOMPH_EXCEPTION_LOCATION);
44109  }
44110  else
44111  {
44112  throw OomphLibError(
44113  "Have a seven-noded element that's not a TElement<2,3>",
44114  OOMPH_CURRENT_FUNCTION,
44115  OOMPH_EXCEPTION_LOCATION);
44116  }
44117  }
44118  // If I get there I must not have thrown :)
44119  // success=true;
44120 #endif
44121  // Deal with six noded stuff for all (normal and enriched) elements
44122 
44123  /// ----------------------------------------------------------------
44124  /// Repositioning of mid-side nodes
44125  /// ----------------------------------------------------------------
44126 
44127  // Side between 0 and 1
44128  if (el_pt->node_pt(3)->is_on_boundary(b))
44129  {
44130  // Make sure that the node I'm about to move is NOT on
44131  // a boundary
44132  if (!el_pt->node_pt(5)->is_on_boundary())
44133  {
44134  // Reset the internal nodes
44135  for (unsigned i = 0; i < 2; i++)
44136  {
44137  el_pt->node_pt(5)->x(i) =
44138  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
44139  }
44140  }
44141  // Make sure that the node I'm about to move is NOT on
44142  // a boundary
44143  if (!el_pt->node_pt(4)->is_on_boundary())
44144  {
44145  // Reset the internal nodes
44146  for (unsigned i = 0; i < 2; i++)
44147  {
44148  el_pt->node_pt(4)->x(i) =
44149  0.5 * (el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
44150  }
44151  }
44152  }
44153 
44154  // Side between 1 and 2
44155  if (el_pt->node_pt(4)->is_on_boundary(b))
44156  {
44157  // Make sure that the node I'm about to move is NOT on
44158  // a boundary
44159  if (!el_pt->node_pt(5)->is_on_boundary())
44160  {
44161  // Reset the internal nodes
44162  for (unsigned i = 0; i < 2; i++)
44163  {
44164  el_pt->node_pt(5)->x(i) =
44165  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
44166  }
44167  }
44168  // Make sure that the node I'm about to move is NOT on
44169  // a boundary
44170  if (!el_pt->node_pt(3)->is_on_boundary())
44171  {
44172  // Reset the internal nodes
44173  for (unsigned i = 0; i < 2; i++)
44174  {
44175  el_pt->node_pt(3)->x(i) =
44176  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
44177  }
44178  }
44179  }
44180 
44181  // Side between 0 and 2
44182  if (el_pt->node_pt(5)->is_on_boundary(b))
44183  {
44184  // Make sure that the node I'm about to move is NOT on
44185  // a boundary
44186  if (!el_pt->node_pt(4)->is_on_boundary())
44187  {
44188  // Reset the internal nodes
44189  for (unsigned i = 0; i < 2; i++)
44190  {
44191  el_pt->node_pt(4)->x(i) =
44192  0.5 * (el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
44193  }
44194  }
44195  // Make sure that the node I'm about to move is NOT on
44196  // a boundary
44197  if (!el_pt->node_pt(3)->is_on_boundary())
44198  {
44199  // Reset the internal nodes
44200  for (unsigned i = 0; i < 2; i++)
44201  {
44202  el_pt->node_pt(3)->x(i) =
44203  0.5 * (el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
44204  }
44205  }
44206  }
44207 
44208  // If it's seven noded it's likely to be an enriched one: Deal with
44209  // the central (bubble) node
44210  if (nnod == 7)
44211  {
44212  // Try to cast to an enriched quadratic element
44213  TBubbleEnrichedElement<2, 3>* t_el_pt =
44214  dynamic_cast<TBubbleEnrichedElement<2, 3>*>(el_pt);
44215  if (t_el_pt == 0)
44216  {
44217  throw OomphLibError("Have seven-noded element that's not a "
44218  "TBubbleEnrichedElement<2,3>",
44219  OOMPH_CURRENT_FUNCTION,
44220  OOMPH_EXCEPTION_LOCATION);
44221  }
44222 
44223  // Assign the new non-bubble coordinates to the six noded dummy
44224  // element
44225  for (unsigned j = 0; j < 6; j++)
44226  {
44227  for (unsigned i = 0; i < 2; i++)
44228  {
44229  dummy_six_node_element.node_pt(j)->x(i) = el_pt->node_pt(j)->x(i);
44230  }
44231  }
44232 
44233  // Local coordinate of enriched node
44234  unsigned j_enriched = 6;
44235  Vector<double> s(2);
44236  el_pt->local_coordinate_of_node(j_enriched, s);
44237 
44238  // Get its position from non-enriched element
44239  Vector<double> x(2);
44240  dummy_six_node_element.interpolated_x(s, x);
44241  el_pt->node_pt(j_enriched)->x(0) = x[0];
44242  el_pt->node_pt(j_enriched)->x(1) = x[1];
44243  }
44244  }
44245  // Any other case cannot be dealt with at the moment
44246 
44247  else
44248  {
44249  std::ostringstream error_stream;
44250  error_stream << "Cannot deal with this particular " << nnod
44251  << "-noded element yet.\n"
44252  << "Please implement this yourself.\n";
44253  throw OomphLibError(
44254  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
44255  }
44256  }
44257 
44258  // Cleanup
44259  for (unsigned j = 0; j < 6; j++)
44260  {
44261  delete dummy_six_node_element.node_pt(j);
44262  }
44263  }
44264 
44265 
44266 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
44267 
44268 } // namespace oomph
44269 
44270 #endif
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
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 ...
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...
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 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...
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 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 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....
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...
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 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 ...
void update_shared_curve_after_restart(Vector< TriangleMeshPolyLine * > &vector_polyline_pt)
Updates the shared polylines representation after restart.
void send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
Helper function to send back halo and haloed information.
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...
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 snap_nodes_onto_boundary(RefineableTriangleMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
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 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...
double & max_element_size()
Max element size allowed during adaptation.
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...
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...
void sort_nodes_on_shared_boundaries()
Sort the nodes on shared boundaries so that the processors that share a boundary agree with the order...
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...
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 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 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...
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 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...
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...
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.
double & min_permitted_angle()
Min angle before remesh gets triggered.
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 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...
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...
void update_open_curve_after_restart(TriangleMeshOpenCurve *&open_curve_pt)
Updates the open curve representation after restart.
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 ...
void reset_halo_haloed_scheme()
In charge of. re-establish the halo(ed) scheme on all processors. Sends info. to create halo elements...
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 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....
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...
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....
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...
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 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 ...
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...
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 add_haloed_node_helper(unsigned &iproc, Node *nod_pt)
Helper function to add haloed node.
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 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_...
double & min_element_size()
Min element size allowed during adaptation.
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...
bool update_polygon_using_face_mesh(TriangleMeshPolygon *polygon_pt, const bool &check_only=false)
Helper function that updates the input polygon's PSLG by using the end-points of elements from FaceMe...
void update_polygon_after_restart(TriangleMeshPolygon *&polygon_pt)
Updates the polylines representation after restart.
void add_vertices_for_non_deletion()
Mark the vertices that are not allowed for deletion by the unrefienment/refinement polyline methods....
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.
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 apply_max_length_constraint(Mesh *face_mesh_pt, Vector< Vector< double >> &vector_bnd_vertices, double &max_length_constraint)
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.
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...
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.
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
void enable_use_attributes()
Helper function for enabling the use of attributes.
double element_area() const
Helper function for getting the element area.
void disable_automatic_creation_of_vertices_on_boundaries()
Disables the creation of points (by Triangle) on the outer and internal boundaries.
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
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...
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...
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 create_shared_polylines_connections()
Establish the connections of the polylines previously marked as having connections....
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...
void synchronize_boundary_coordinates(const unsigned &b)
In charge of sinchronize the boundary coordinates for internal boundaries that were split as part of ...
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 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...
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned >> &ntmp_boundary_elements_in_region, Vector< FiniteElement * > &deleted_elements)
Virtual function to perform the reset boundary elements info routines. Generally used after load bala...
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...
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 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 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_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 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 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...
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
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.
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
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...
void dump_distributed_info_for_restart(std::ostream &dump_file)
Used to dump info. related with distributed triangle meshes.
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,...
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...
void read_distributed_info_for_restart(std::istream &restart_file)
Used to read info. related with distributed triangle meshes.
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 ...
void output_boundary_coordinates(const unsigned &b, std::ostream &outfile)
Output the nodes on the boundary and their respective boundary coordinates(into separate tecplot zone...
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...
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 ...
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 ...
////////////////////////////////////////////////////////////////////// //////////////////////////////...
struct oomph::classcomp Bottom_left_sorter
bool operator()(const std::pair< double, double > &lhs, const std::pair< double, double > &rhs) const